Home » Modeling » TMF (Xtext) » Xtext IScopeProvider
Xtext IScopeProvider [message #39881] |
Tue, 14 April 2009 05:01  |
Eclipse User |
|
|
|
Hello,
I'm quite new to Xtext, especially to its TMF implementation. I'm
experiencing problems with "scoping" via IScopeProvider.
Here is (relevant part of) my grammar:
Parameter:
name=ID ":" type=[ParameterType];
Predicate:
"predicate" name=ID "("
(parameter+=Parameter ("," parameter+=Parameter)*)?
")" ";";
Argument:
parameter=[Parameter] "=" value=ArgumentValue;
Term:
(isNegated?="not")? definition=[Predicate]
"("
(argument+=Argument ("," argument+=Argument)*)?
")";
(I do not mention rules "invoking" Predicate and Term rules, but they are
defined in the grammar, of course).
Parameter's name is unique in Predicate's definition, but it's not
necessarily unique in the whole model. When specifying a list of Arguments
inside a Term rule only Parameters whichs' name is used only once in the
whole model are offered in autocomplete list. I cannot, naturally,
unambiguously link to those whichs' name is used more than once, when not
using "scoping". So, I guess, I need to implement IScopeProvider offering
only those Parameters defined in Term's definition Predicate. My
implementation is:
public class PSLScopeProvider extends DefaultScopeProvider {
@Override
public IScope getScope(EObject context, EReference reference) {
if (reference == PslPackage.eINSTANCE.getTerm_Argument()) {
if (context instanceof Term) {
return createArgumentScope((Term) context);
}
return IScope.NULLSCOPE;
}
return super.getScope(context, reference);
}
}
This is where i got stuck. When typing a Term rule in my generated DSL
editor, when a cursor is right after "(" parenthesis, list of all
model-wide-only-once-used-name-parameters is offered to me, not my
filtered list of Parameters defined in Terms defintion Predicate (built in
createArgumentScope()), as I expected, is shown.
Please, what am I doing wrong?. I hope my post is clear enough to describe
my problem.
Thanks to everyone.
Karel
|
|
|
Re: Xtext IScopeProvider [message #39975 is a reply to message #39881] |
Tue, 14 April 2009 08:57   |
Eclipse User |
|
|
|
Hi Karel,
you almost figured it out yourself.
Have you tried to use something like this:
public class PSLScopeProvider extends DefaultScopeProvider {
@Override
public IScope getScope(EObject context, EReference reference) {
if (reference == PslPackage.eINSTANCE.getArgument_Parameter()) {
Term term = getContainerWithType(context, Term.class);
if (term != null) {
return createArgumentScope(term);
}
return IScope.NULLSCOPE;
}
return super.getScope(context, reference);
}
}
As Term__Argument is a containment reference, the scope provider will
never get this one as the 'reference'-argument. Argument__Parameter
itself is a cross reference (neither containment nor container) and will
be passed to the scoped provider during the linking of your resource.
Regards,
Sebastian
Karel Smutny schrieb:
> Hello,
>
> I'm quite new to Xtext, especially to its TMF implementation. I'm
> experiencing problems with "scoping" via IScopeProvider.
>
> Here is (relevant part of) my grammar:
>
> Parameter:
> name=ID ":" type=[ParameterType];
>
> Predicate:
> "predicate" name=ID "(" (parameter+=Parameter (","
> parameter+=Parameter)*)?
> ")" ";";
>
> Argument:
> parameter=[Parameter] "=" value=ArgumentValue;
>
> Term:
> (isNegated?="not")? definition=[Predicate]
> "("
> (argument+=Argument ("," argument+=Argument)*)?
> ")";
>
> (I do not mention rules "invoking" Predicate and Term rules, but they
> are defined in the grammar, of course).
>
> Parameter's name is unique in Predicate's definition, but it's not
> necessarily unique in the whole model. When specifying a list of
> Arguments inside a Term rule only Parameters whichs' name is used only
> once in the whole model are offered in autocomplete list. I cannot,
> naturally, unambiguously link to those whichs' name is used more than
> once, when not using "scoping". So, I guess, I need to implement
> IScopeProvider offering only those Parameters defined in Term's
> definition Predicate. My implementation is:
>
> public class PSLScopeProvider extends DefaultScopeProvider {
>
> @Override
> public IScope getScope(EObject context, EReference reference) {
> if (reference == PslPackage.eINSTANCE.getTerm_Argument()) {
> if (context instanceof Term) {
> return createArgumentScope((Term) context);
> }
> return IScope.NULLSCOPE;
> }
> return super.getScope(context, reference);
> }
> }
>
> This is where i got stuck. When typing a Term rule in my generated DSL
> editor, when a cursor is right after "(" parenthesis, list of all
> model-wide-only-once-used-name-parameters is offered to me, not my
> filtered list of Parameters defined in Terms defintion Predicate (built
> in createArgumentScope()), as I expected, is shown.
>
> Please, what am I doing wrong?. I hope my post is clear enough to
> describe my problem.
>
> Thanks to everyone.
> Karel
>
|
|
| | | | |
Re: Xtext IScopeProvider [message #40410 is a reply to message #40346] |
Wed, 15 April 2009 05:18   |
Eclipse User |
|
|
|
Hi Sven,
thanks for your concern. My grammar is quite complicated to be pasted to a
newsgroup post, so I made a simpler one with analogous problem.
Grammar definition:
===================
grammar com.gemoney.cz.Tsl with org.eclipse.xtext.common.Terminals
generate tsl "http://gemoney.com/cz/tsl"
Model:
(dataType+=DataType)*
(functionDef+=FunctionDef)*
(functionCall+=FunctionCall)*
;
DataType:
"type" name=ID ";";
FunctionDef:
"function" name=ID "("
parameter+=Parameter ("," parameter+=Parameter)*
")" "returns" returnType=[DataType] ";";
Parameter:
name=ID ":" type=[DataType];
FunctionCall:
function=[FunctionDef] "("
argument+=Argument ("," argument+=Argument)*
")";
Argument:
parameter=[Parameter] "=" value=Value;
Value:
INTLiteral | FunctionCall;
INTLiteral:
value=INT;
Runtime module:
===============
public class TslRuntimeModule extends
com.gemoney.cz.AbstractTslRuntimeModule {
@Override
public Class<? extends IScopeProvider> bindIScopeProvider() {
return TslScopeProvider.class;
}
}
Scope Provider:
===============
public class TslScopeProvider extends DefaultScopeProvider {
@Override
public IScope getScope(EObject context, EReference reference) {
if (reference == TslPackage.eINSTANCE.getArgument_Parameter()) {
if (context instanceof FunctionCall) {
return createArgumentScope(((FunctionCall) context).getFunction());
}
return IScope.NULLSCOPE;
}
return super.getScope(context, reference);
}
private IScope createArgumentScope(FunctionDef function) {
return new SimpleScope(IScope.NULLSCOPE,
CollectionUtils.map(function.getParameter(), new Function<Parameter,
IScopedElement>() {
public IScopedElement exec(Parameter parameter) {
return ScopedElement.create(parameter.getName(), parameter);
}
}));
}
}
These are my only changes to generated code.
Model:
======
type T1;
type T2;
type T3;
function Q(a : T1, b : T2, c : T3) returns T3;
function P(r : T1, s : T2, t : T3) returns T3;
Q(a = 10, b = P(r = 5, s = 12, t = 43), c = 1)
Inside both Q and P function calls the right set of parameter names is
proposed to me (a, b, c for Q and r, s, t for P function). But all of the
names are underlined with message "cannot resolve reference to 'a'".
Regards,
Karel
|
|
|
Re: Xtext IScopeProvider [message #40442 is a reply to message #40410] |
Wed, 15 April 2009 05:43   |
Eclipse User |
|
|
|
Hi Karel,
I suspect the context to be not an instance of FunctionCall when the
linker uses the scope provider, although a FunctionCall is passed when
code completion is invoked. Instead it is likely to be an Argument.
Please try to not use instanceof but walk up the containment hierarchy
instead:
@Override
public IScope getScope(EObject context, EReference reference) {
if (reference == TslPackage.eINSTANCE.getArgument_Parameter()) {
FunctionCall call = findFunctionCall(context);
if (call != null && call.getFunction()!=null) {
return createArgumentScope(call.getFunction());
}
return IScope.NULLSCOPE;
}
return super.getScope(context, reference);
}
FunctionCall findFunctionCall(EObject context) {
if (context instanceof FunctionCall)
return (FunctionCall)context;
// context instanceof Argument
if (context.eContainer() != null) {
return findFunctionCall(context.eContainer());
}
return null;
}
Be aware of the fact, that you should not walk up the hierarchy to far,
as you are nesting FunctionCalls in each other. Also note, that you
cannot assume call.getFunction() != null as the called function may not
exist.
Regards,
Sebastian
Am 15.04.2009 11:18 Uhr, schrieb Karel Smutny:
> Hi Sven,
>
> thanks for your concern. My grammar is quite complicated to be pasted to
> a newsgroup post, so I made a simpler one with analogous problem.
>
> Grammar definition:
> ===================
>
> grammar com.gemoney.cz.Tsl with org.eclipse.xtext.common.Terminals
> generate tsl "http://gemoney.com/cz/tsl"
>
> Model:
> (dataType+=DataType)*
> (functionDef+=FunctionDef)*
> (functionCall+=FunctionCall)* ;
>
> DataType:
> "type" name=ID ";";
>
> FunctionDef:
> "function" name=ID "("
> parameter+=Parameter ("," parameter+=Parameter)*
> ")" "returns" returnType=[DataType] ";";
> Parameter:
> name=ID ":" type=[DataType];
>
> FunctionCall:
> function=[FunctionDef] "("
> argument+=Argument ("," argument+=Argument)*
> ")";
>
> Argument:
> parameter=[Parameter] "=" value=Value;
>
> Value:
> INTLiteral | FunctionCall;
>
> INTLiteral:
> value=INT;
>
> Runtime module:
> ===============
>
> public class TslRuntimeModule extends
> com.gemoney.cz.AbstractTslRuntimeModule {
>
> @Override
> public Class<? extends IScopeProvider> bindIScopeProvider() {
> return TslScopeProvider.class;
> }
> }
>
> Scope Provider:
> ===============
>
> public class TslScopeProvider extends DefaultScopeProvider {
>
> @Override
> public IScope getScope(EObject context, EReference reference) {
> if (reference == TslPackage.eINSTANCE.getArgument_Parameter()) {
> if (context instanceof FunctionCall) {
> return createArgumentScope(((FunctionCall) context).getFunction());
> }
> return IScope.NULLSCOPE;
> }
> return super.getScope(context, reference);
> }
>
> private IScope createArgumentScope(FunctionDef function) {
> return new SimpleScope(IScope.NULLSCOPE,
> CollectionUtils.map(function.getParameter(), new Function<Parameter,
> IScopedElement>() {
> public IScopedElement exec(Parameter parameter) {
> return ScopedElement.create(parameter.getName(), parameter);
> }
> }));
> }
> }
>
> These are my only changes to generated code.
>
> Model:
> ======
>
> type T1;
> type T2;
> type T3;
>
> function Q(a : T1, b : T2, c : T3) returns T3;
> function P(r : T1, s : T2, t : T3) returns T3;
>
> Q(a = 10, b = P(r = 5, s = 12, t = 43), c = 1)
>
> Inside both Q and P function calls the right set of parameter names is
> proposed to me (a, b, c for Q and r, s, t for P function). But all of
> the names are underlined with message "cannot resolve reference to 'a'".
>
> Regards,
> Karel
>
>
|
|
| | |
Re: Xtext IScopeProvider [message #40534 is a reply to message #40473] |
Wed, 15 April 2009 08:43  |
Eclipse User |
|
|
|
Hi Karel,
getScope is actually called with different arguments depending on the
callee, that's right. However it is definitly ok to return the same
result for different contexts (think about a function
add(a, b) = a + b; add(5,1) == add(4,2)
). We consider the "reference" parameter to be the actual selector,
while the context is often not required on a fine grained level. Many
implementations will walk up the containment hierarchy of the context up
to a certain level and actually use this container as the context to
calculate the result. This assumption is reflected by the
DeclarativeScopeProvider (CVS HEAD), which puts exactly this
functionality into a common base class.
Regards,
Sebastian
Am 15.04.2009 14:03 Uhr, schrieb Karel Smutny:
> This helped, thanks a lot!
>
> Last question: Is that all right the function getScope() is called with
> different arguments (once the context parameter is FunctionCall, another
> time Argument) when it is supposed to return the same result?
>
> Regards,
> Karel.
>
|
|
|
Goto Forum:
Current Time: Mon Jul 21 07:13:20 EDT 2025
Powered by FUDForum. Page generated in 0.08661 seconds
|