Home » Modeling » TMF (Xtext) » [Xtext] Signature based crosslinks
[Xtext] Signature based crosslinks [message #780396] |
Tue, 17 January 2012 18:03 |
|
Hi all,
crosslinks in Xtext are name based, by default. However, in my DSL, I
want to implement a feature similar to method overloading in Java, for
which I need a more complicated crosslink resolving. I call it
"signature based crosslink", as I need to evaluate the signature of a
method.
Example grammar snippet:
-----------------------------------
MethodDeclaration: "def" name=ID "("
(parameters+=Parameter ("," parameters+=Parameter )*)?
")";
Parameter: type=ID name=ID;
....
MethodCall: "call" method=[MethodDeclaration] "("
(argument+=Argument ("," argument+=Argument )*)?
")";
Argument: type=ID;
-----------------------------------
Crosslinks are working out of the box, but only if all methods have
unique names. However, if methods can be overloaded, resolving becomes a
problem. E.g., in
def foo()
def foo(int i)
call foo(int)
call foo should be linked to foo(int i) rather then foo().
My question is how to solve that problem with Xtext (I'm using Xtext
1.0, maybe there exist different solutions for Xtext 2.0?).
I have already tried to implement custom scoping or
IQualifiedNameProvider. However I run into cycles when trying to
retrieve the name of the method used in the MethodCall (Cyclic
resolution of lazy links).
Actually, I have a workaround I'm not happy with. It doesn't make use of
Xtext's crosslink feature: instead of a crosslink, a simple ID is used
in MethodCall. Then, a new field method is added to the generated ecore
element "MethodCall", and this field is set manually after parsing the
code. That is
MethodCall: "call" methodName=ID "(" argument+=Argument
("," argument+=Argument )* ")";
// field "MethodDeclaration method" added in post processing step
// and set in separate resolution step
However, in that case I need a separate resolution step when reading a
model, and I have duplicate code in the binding and in the proposal
provider (for "emulating" the crosslink behaviour), and the crosslinks
are not navigable in the editor.
Is it possible to add a custom resolution/binding step to the Xtext
parser, in order to "fix" crosslinks? The example above is rather
simple, in the real example I have to resolve the type of the arguments
first of course, which makes the whole resolution rather complicated.
Cheers,
Jens
|
|
|
Re: [Xtext] Signature based crosslinks [message #780425 is a reply to message #780396] |
Tue, 17 January 2012 20:31 |
|
Hi Jens,
the qualified name has just to include the parameters, then methods with the same name but different signature are handled differently. The scope for MethodCall_method would have to take the Arguments into account.
Kind regards,
~Karsten
Need professional support for Xtext, EMF, Eclipse IDE?
Go to: http://devhub.karakun.com
Twitter : @kthoms
Blog : www.karsten-thoms.de
|
|
|
Re: [Xtext] Signature based crosslinks [message #780448 is a reply to message #780396] |
Tue, 17 January 2012 23:33 |
Sebastian Zarnekow Messages: 3118 Registered: July 2009 |
Senior Member |
|
|
Hi Jens,
please dive into the Xbase scoping implementation to learn how we handle
overloaded methods there. BestMatchingFeatureScope could serve as a starter.
Regards,
Sebastian
--
Need professional support for Eclipse Modeling?
Go visit: http://xtext.itemis.com
Am 17.01.12 19:03, schrieb Jens v.P.:
> Hi all,
>
> crosslinks in Xtext are name based, by default. However, in my DSL, I
> want to implement a feature similar to method overloading in Java, for
> which I need a more complicated crosslink resolving. I call it
> "signature based crosslink", as I need to evaluate the signature of a
> method.
>
> Example grammar snippet:
> -----------------------------------
> MethodDeclaration: "def" name=ID "("
> (parameters+=Parameter ("," parameters+=Parameter )*)?
> ")";
> Parameter: type=ID name=ID;
>
> ....
>
> MethodCall: "call" method=[MethodDeclaration] "("
> (argument+=Argument ("," argument+=Argument )*)?
> ")";
> Argument: type=ID;
> -----------------------------------
>
> Crosslinks are working out of the box, but only if all methods have
> unique names. However, if methods can be overloaded, resolving becomes a
> problem. E.g., in
>
> def foo()
> def foo(int i)
> call foo(int)
>
> call foo should be linked to foo(int i) rather then foo().
>
> My question is how to solve that problem with Xtext (I'm using Xtext
> 1.0, maybe there exist different solutions for Xtext 2.0?).
>
> I have already tried to implement custom scoping or
> IQualifiedNameProvider. However I run into cycles when trying to
> retrieve the name of the method used in the MethodCall (Cyclic
> resolution of lazy links).
>
> Actually, I have a workaround I'm not happy with. It doesn't make use of
> Xtext's crosslink feature: instead of a crosslink, a simple ID is used
> in MethodCall. Then, a new field method is added to the generated ecore
> element "MethodCall", and this field is set manually after parsing the
> code. That is
>
> MethodCall: "call" methodName=ID "(" argument+=Argument
> ("," argument+=Argument )* ")";
> // field "MethodDeclaration method" added in post processing step
> // and set in separate resolution step
>
> However, in that case I need a separate resolution step when reading a
> model, and I have duplicate code in the binding and in the proposal
> provider (for "emulating" the crosslink behaviour), and the crosslinks
> are not navigable in the editor.
>
> Is it possible to add a custom resolution/binding step to the Xtext
> parser, in order to "fix" crosslinks? The example above is rather
> simple, in the real example I have to resolve the type of the arguments
> first of course, which makes the whole resolution rather complicated.
>
> Cheers,
> Jens
|
|
|
Re: [Xtext] Signature based crosslinks [message #780472 is a reply to message #780425] |
Wed, 18 January 2012 07:52 |
|
Thank you, Karsten! My error in reasoning was to assume that the scoping
provider has to handle the name of the method. However, this is
magically done by Xtext, all I have to care about are the parameters as
you described.
Here's a brief description of the solution for interested readers:
Problem:
Crosslinks have to take other circumstances into account
besides the referencing name. Most popular example:
Overloaded methods must take into account number and types
of arguments and parameters respectively.
Solution:
Custom scope provider only collects possible link targets which
match the additional circumstances. The actual name is handled
later on.
Example:
Assume you want to allow a kind of method overloading. For keeping the
example small, only the number of arguments and parameters are to be
matched.
Grammar snippet:
-------------------------------------------------------------------
MethodDeclaration: "def" name=ID "("
(parameters+=Parameter ("," parameters+=Parameter )*)?
")";
Parameter: type=ID name=ID;
MethodCall: "call" method=[MethodDeclaration] "("
(argument+=Argument ("," argument+=Argument )*)?
")";
Argument: type=ID;
-------------------------------------------------------------------
Scope provider snippet:
-------------------------------------------------------------------
public class MyScopeProvider extends AbstractDeclarativeScopeProvider {
IScope scope_MethodCall_method(MethodCall methodCall, EReference ref) {
int numberOfArguments = methodCall.getArguments().size();
List<EObject> matchingMethods = new ArrayList<EObject>();
for (MethodDeclaration methodDeclaration: getAllMethods()) {
if (methodDeclaration.getParameters().size() == numberOfArguments) {
matchingMethods.add(methodDeclaration);
}
}
return Scopes.scopeFor(matchingMethods);
}
}
-------------------------------------------------------------------
Of course, in a real application, getAllMethods() and the matching
expression (here the comparison of paremeter size and number of
arguments) will be more complicated.
Sample program/model:
-------------------------------------------------------------------
def foo()
def foo(type1 p1)
call foo()
call foo(x)
-------------------------------------------------------------------
foo() call will be correctly bound to def foo(), and foo(x) to foo(type1
p1).
Cheers,
Jens
|
|
|
Goto Forum:
Current Time: Thu Apr 25 14:41:17 GMT 2024
Powered by FUDForum. Page generated in 0.07243 seconds
|