Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » About cross references & scoping
About cross references & scoping [message #1005813] Mon, 28 January 2013 15:15 Go to next message
thomas klutsch is currently offline thomas klutsch
Messages: 1
Registered: January 2013
Junior Member
Hi there!

I just signed up here as a person that is by now totally desperate! I've searched what felt like the entire internet for answers to what I think is a quite a simple question about xtext, but have yet to succeed. This is my last hope to find an answer Sad

So what is it about: It's about cross references and scoping in xtext.

Okay so in my grammar, there are some cross-references, like:

SomeRule:
name = [SomeOtherRule];

But this doesn't always work in the generated language. It works in most cases, but sometimes, I get messages "couldn't resolve reference to SomeOtherRule x".

I've read everything what is written about scoping in the Xtext documentation. Maybe I'm just plain stupid, but that didn't help me AT ALL, as it just comes up with all kinds of different interfaces and classes and buzzwords, but it does not explain how the default scoping behaviour actually works in practice.

Aside from that I found a few blog entries where people have written stuff about the scoping. But that didn't help me either.

So then I tried to experiment with little self-created grammar examples to find out when exactly a cross-references works and when not. But I just don't get the rules behind the mechanism. For me it's just magic.

I spend hours to try to come up with an example, but because I don't understand it yet, I fail to do so. The only thing I can do is give you my entire concrete grammer where the problem occurs - without me understanding it. This is quite some code, and surely some things may not be relevant to the example I'll give you. But I don't know which are and which are not, and if it would change something semantically if I try to simplify it. So, don't get a heart attack, you won't need to think through all of this, but for the sake of completeness, I'll post everything

(by the way this grammar tries to implement the QVT Relations Language)

TopLevel:
	(transformations+=Transformation)*;

Transformation:
	'transformation' name=ID
	'('
	modelDeclarations+=ModelDeclaration (',' modelDeclarations+=ModelDeclaration)*
	')'
	('extends' superTransformation=[Transformation])?
	'{'
	(keyDeclarations+=KeyDeclaration)*
	(relations+=Relation | functions+=Function)*
	'}';

ModelDeclaration:
	name=ID ':'
	metaModelIds+=MetaModelId
	|
	('{' metaModelIds+=MetaModelId (',' metaModelIds+=MetaModelId)* '}');

MetaModelId:
	name=ID;

KeyDeclaration:
	'key' classId=ClassId
	'{'
	keyProperties+=KeyProperty (',' keyProperties+=KeyProperty)*
	'}'
	';';

ClassId:
	name=ID;

KeyProperty:
	PrimitiveKeyProperty | OppositeKeyProperty;

PrimitiveKeyProperty:
	name=ID;

OppositeKeyProperty:
	'opposite'
	'('
	classId=ClassId '.' name=ID
	')';

Relation:
	('top')? 'relation' name=ID
	('overrides' superRelation=[Relation])?
	'{'
	(variableDeclarations+=VariableDeclaration)*
	(domains+=Domain)+
	(whenStatement=WhenStatement)?
	(whereStatement=WhereStatement)?
	'}';

VariableDeclaration:
	name+=VariableName (',' name+=VariableName)* ':' type=TypeCS ';';

VariableName:
	name=ID;

TypeCS:
	name=ID;

Domain:
	PrimitiveTypeDomain | ComplexDomain;

PrimitiveTypeDomain:
	'primitive' 'domain' name=VariableName ':' type=TypeCS ';';

ComplexDomain:
	('checkonly' | 'enforce')? 'domain'
	modelId=[ModelDeclaration]
	template=Template
	('default_values' '{' (assignmentExpressions+=AssignmentExpression)+ '}')?
	';';

AssignmentExpression:
	name=ID '=' oclExpression=OclExpressionCS ';';

Template:
	(name=VariableName)? ':' classId=ClassId
	'{'
	(propertyTemplateList=PropertyTemplateList)?
	'}'
	('{' oclExpression=OclExpressionCS '}')?;

PropertyTemplateList:
	propertyTemplates+=PropertyTemplate (',' propertyTemplates+=PropertyTemplate)*;

PropertyTemplate:
	PrimitivePropertyTemplate | OppositePropertyTemplate;

PrimitivePropertyTemplate:
	name=ID '=' oclExpression=OclExpressionCS;

OppositePropertyTemplate:
	'opposite'
	'('
	classId=ClassId '.' name=ID
	')'
	'=' oclExpression=OclExpressionCS;

WhenStatement:
	{WhenStatement}
	'when'
	'{'
	(oclExpressions+=OclExpressionCS ';')*
	'}';

WhereStatement:
	{WhereStatement}
	'where'
	'{'
	(oclExpressions+=OclExpressionCS ';')*
	'}';

Function:
	'function' name=ID
	'('
	(parameters+=ParameterDeclaration (',' parameters+=ParameterDeclaration)*)?
	')'
	':' type=TypeCS
	(';' | '{' oclExpression=OclExpressionCS '}');

ParameterDeclaration:
	name=VariableName ':' type=TypeCS;

OclExpressionCS:
	concatenatedOclExpressions+=ConcatenatedOclExpression
	('=' concatenatedOclExpressions+=ConcatenatedOclExpression)?;

ConcatenatedOclExpression:
	oclExpressionTerms+=OclExpressionTerm ('+' oclExpressionTerms+=OclExpressionTerm)*;

OclExpressionTerm:
	'(' OclExpressionCS ')' | Template | IfExpCS | VariableExpCS | CallExpCS | LiteralExpCS;

IfExpCS:
	'if' ifOclExpression=OclExpressionCS
	'then' thenOclExpression=OclExpressionCS
	'else' elseOclExpression=OclExpressionCS
	'endif';

VariableExpCS:
	name=[VariableName];

CallExpCS:
	PropertyCallExpCS | CodeCallExp;

PropertyCallExpCS:
	name=[VariableName] '.' properties+=Property ('.' properties+=Property)*;

Property:
	name=ID;

CodeCallExp:
	name=[CallableCode]
	'('
	(parameters+=CodeCallExpParameter)? (',' parameters+=CodeCallExpParameter)*
	')';

CallableCode:
	Relation | Function;

CodeCallExpParameter:
	name=[VariableName];

LiteralExpCS:
	StringLiteralExp | IntLiteralExp | FloatLiteralExp;

StringLiteralExp:
	name=STRING;

IntLiteralExp:
	name=INT;

FloatLiteralExp:
	name=FLOAT;

terminal FLOAT returns ecore::EFloat:
	('0'..'9')+ '.' ('0'..'9')+;
	


Ok still there? Wink So, now here's a snippet of some example code where a problem with the scope arises:

transformation <...> {

	<...>

	top relation ClassToTable {

		cn, prefix:String;

		checkonly domain uml c:Class {
			namespace = p:Package {},
			kind = 'Persistent',
			name = cn
		};

		enforce domain rdbms t:Table {
			schema = s:Schema {},
			name = cn,
			column = cl:Column {
				name = cn + '_tid',
				type = 'NUMBER'
			},
			theKey = k:Key {
				name = cn + '_pk',
				column = cl ####### ERROR ########
			}
		};

		when {
			PackageToSchema (p, s); ####### ERROR ########
		}
		where {
			prefix = '';
			AttributeToColumn (c, t, prefix); ####### OKAY ####### 
		}
	}

        <...>

}


I get errors "couldn't resolve reference to VariableName <x>" at the lines marked with ####### ERROR ########. So the VariableNames p, s and cl are not visible at those points.

However, it seems there's no problem with the variables c, t and prefix (See line marked with ####### OKAY ####### )

And THAT'S what I don't get. Whatever mechanism I think of that xtext might be using, these two incidents seem to be contradictory. Because regarding the hierarchy of the rule's relations, I don't really see a difference?!


...Puh, thanks so much for those of you who have read up to here! I would be so thankful if anyone can explain to me why exactly the references to c, t, and prefix are visible in the where-block, but the references to p and s in the when-block are not.

In one sentence, what I need to understand ist:

What is the default scope of a feature? where can it be references, where not?

Thanks again, Regards Thomas



Re: About cross references & scoping [message #1005862 is a reply to message #1005813] Tue, 29 January 2013 01:12 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian Dietrich
Messages: 6141
Registered: July 2009
Senior Member
Hi,

without having a look at your code

(1) xtext by default builds QualifiedNames <ancestorname>.....<Parentname>.<name>
(2) these names are automatically resolved in the context of their relation
(3) xxxx=[YYYY] is short for xxxx=[YYYY|ID]
so a . is not allowed in the reference
(4)you can overcome this by:
(a) giving the things simple names (IQualifiedNameProvider)
(b) allow qualified names in the rule
xxxx=[YYYY|FQN].... FQN: ID ("." ID)*;

you can use crtl+shift+F3 to see the names of your things

Re: About cross references & scoping [message #1006113 is a reply to message #1005813] Tue, 29 January 2013 19:12 Go to previous message
Ian McDevitt is currently offline Ian McDevitt
Messages: 65
Registered: December 2012
Location: Belfast
Member
I'm trying to solve something similar as I thought I understood the cross referencing and saw it working as I expected, until I tried getting my locally defined variables in one module to refer to properties of another class module. Then I got the same error.

Having a quick look at your code, it would seem that the line
column = cl

should work with a cross ref of ID since there is no dot in cl.

The grammar is large so it's hard to tell which rule that is running but if the error is saying VariableName then it must be one that contains
name=[VariableName];


However I think you may mean
name=[VariableDeclaration];

since VariableName is just an ID which is a terminal or token rather than a type that can be referenced. your cross ref needs to be to another type.

The OKAY ones c, t and prefix must work because they are actually just IDs (haven't been declared as a variable).

I expect I'll be posting my own problem in a day or two when I've shrunk it down to a simple example, so I hope anyone reading this will spare me some advice too. It is a problem of QualifiedNames where I can reference items in another module as Class.item but not as instance.item. Once I run out of ideas I'll post it up.
Ian
Previous Topic:Outline tree provider and view
Next Topic:Cross reference customisation
Goto Forum:
  


Current Time: Tue Jul 29 11:06:41 EDT 2014

Powered by FUDForum. Page generated in 0.01981 seconds