Home » Modeling » TMF (Xtext) » [Xtext] Scoping Provider Implementation
| | | |
Re: [Xtext] Scoping Provider Implementation [message #48253 is a reply to message #48193] |
Thu, 04 June 2009 21:24 |
Sebastian Zarnekow Messages: 3118 Registered: July 2009 |
Senior Member |
|
|
Hi Derek,
when you are tackling this recursive problem with the help of the lazy
linker (which is the default), you should not have to deal with the
linking order. That means, you may call any getter of your model as you
want.
When I read your post, my first idea was something like this (note: this
is mostly pseudocode, but I hope you'll get the idea):
IScope methodThatCalculatesTheScopeForYAndX(..) {
ClassDef clazz = getClassDefFromContext(..); // should be C
return recursiveComputeContent(clazz);
}
IScope recursiveComputeScope(ClassDef clazz) {
if (clazz == null)
return IScope.NullScope;
IScope result = new Scope(clazz.getAllFields(),
recursiveComputeScope(clazz.getSuperclass());
return result;
}
In production environments, I would track the clazzes, that have already
been visited to avoid infinite recursion due to cyclic inheritance.
Hope that helps,
Sebastian
Am 04.06.2009 21:27 Uhr, schrieb Derek Palma:
> Thanks for your help Knut.
>
> Just to be sure I am understanding your point, it seems you are
> recommend ingI go to the root of the model and access the elemens which
> are not currently getting their scopes resolved in order to avoid the
> recursion? I am looking at the problem as a general traversal problem
> since the hierarchy can be of abitrary depth, so I am thinking I need to
> either approach it bottom-up (like I started), or top-down (maybe close
> to what you are proposing).
>
> Assuming I have
> class A { int x 1; int y = 2; }
> class B extends A { int y = 10; }
> class C extends B { String z = y + x; }
>
> B.z needs to be 11.
>
> I just want to make sure I am thinking about Xtext/Scoping correctly in
> tackling this. To avoid recursion I presume I have to do something to
> access the model without calling gets on the objects. I still don't see
> how this can be possible unless the recursion traverses to the root and
> then resolves everything top down.
>
> Derek
>
> "Knut Wannheden" <knut.wannheden@paranor.ch> wrote in message
> news:44c26338deeea07f63523f898013971c$1@www.eclipse.org...
>> Hi Derek,
>>
>> I think the problem is that when you execute
>> classDef.getSuperClasses().get(i) the linker is called recursively to
>> retrieve the scope for the very context object and reference you
>> currently compute the scope for.
>>
>> So assuming you have a Model object yet another level up the
>> containment hierarchy you should probably write something like:
>>
>> Model model = (Model) context.eContainer().eContainer();
>> List<ClassDef> elements = model.getClassDefs().subList(0,
>> model.getClassDefs().indexOf(context));
>>
>> Regards,
>>
>> --knut
>>
>>
>
|
|
|
Re: [Xtext] Scoping Provider Implementation [message #48283 is a reply to message #48253] |
Fri, 05 June 2009 05:58 |
Derek Palma Messages: 141 Registered: July 2009 |
Senior Member |
|
|
Hi Sebastian,
Since the exact code required for the implementation is not obvious to me
let me first make sure I understand the idea you are proposing.
First, it seems you are implying all getter calls are resolved with
recursion which is what would be expected. So the implementation requires
that you perform a scope resolution when you reference something and get an
IScope back. From this you can build your current scope which was deferred
while the scopes closer to the root of the model are being created.
So the traversal would be something like the following based on my current
understanding:
Since this example does not include nested class declarations, we can assume
all classes are at file scope. This is the same as the default.
For class member scoping, lets assume C is processed first and its members
must be resolved. Our grammar would have something inside a ClassDef like
((memberefs+=MemberDef) | (memberDefs+=MemberDefs)*
MemberRef :
memberRef=[MemberDef];
So we would have:
C should contain: { memberDefs=[z], memberRefs[y,x] }
The problem is to resolve memberRefs for a ClassDef recursively. Taking your
example and making it more concrete
IScope recursiveComputeScope(ClassDef clazz) {
if (clazz == null)
return IScope.NullScope;
IScope result = new Scope(clazz.getMemberDefs() /* is a list of
MemberDef references */,
recursiveComputeScope(clazz.getSuperclasses() /* is a list of
ClassDef references */);
return result;
}
At this point I am not sure what is really generated. Specifically what are
the IScopes which must be generated. My guess is:
IScope{ outer = C, elements = [A.x, B.y] } where outer is a ClassDef and
elements are MemberDefs.
IScope{ outer = B, elements = [A.x ] }
IScope{ outer = A, elements = [] }
Your feedback is appreciated.
Thanks
Derek
"Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
news:h09e33$nk7$1@build.eclipse.org...
> Hi Derek,
>
> when you are tackling this recursive problem with the help of the lazy
> linker (which is the default), you should not have to deal with the
> linking order. That means, you may call any getter of your model as you
> want.
>
> When I read your post, my first idea was something like this (note: this
> is mostly pseudocode, but I hope you'll get the idea):
>
> IScope methodThatCalculatesTheScopeForYAndX(..) {
> ClassDef clazz = getClassDefFromContext(..); // should be C
> return recursiveComputeContent(clazz);
> }
>
> IScope recursiveComputeScope(ClassDef clazz) {
> if (clazz == null)
> return IScope.NullScope;
> IScope result = new Scope(clazz.getAllFields(),
> recursiveComputeScope(clazz.getSuperclass());
> return result;
> }
>
> In production environments, I would track the clazzes, that have already
> been visited to avoid infinite recursion due to cyclic inheritance.
>
> Hope that helps,
> Sebastian
>
> Am 04.06.2009 21:27 Uhr, schrieb Derek Palma:
>> Thanks for your help Knut.
>>
>> Just to be sure I am understanding your point, it seems you are
>> recommend ingI go to the root of the model and access the elemens which
>> are not currently getting their scopes resolved in order to avoid the
>> recursion? I am looking at the problem as a general traversal problem
>> since the hierarchy can be of abitrary depth, so I am thinking I need to
>> either approach it bottom-up (like I started), or top-down (maybe close
>> to what you are proposing).
>>
>> Assuming I have
>> class A { int x 1; int y = 2; }
>> class B extends A { int y = 10; }
>> class C extends B { String z = y + x; }
>>
>> B.z needs to be 11.
>>
>> I just want to make sure I am thinking about Xtext/Scoping correctly in
>> tackling this. To avoid recursion I presume I have to do something to
>> access the model without calling gets on the objects. I still don't see
>> how this can be possible unless the recursion traverses to the root and
>> then resolves everything top down.
>>
>> Derek
>>
>> "Knut Wannheden" <knut.wannheden@paranor.ch> wrote in message
>> news:44c26338deeea07f63523f898013971c$1@www.eclipse.org...
>>> Hi Derek,
>>>
>>> I think the problem is that when you execute
>>> classDef.getSuperClasses().get(i) the linker is called recursively to
>>> retrieve the scope for the very context object and reference you
>>> currently compute the scope for.
>>>
>>> So assuming you have a Model object yet another level up the
>>> containment hierarchy you should probably write something like:
>>>
>>> Model model = (Model) context.eContainer().eContainer();
>>> List<ClassDef> elements = model.getClassDefs().subList(0,
>>> model.getClassDefs().indexOf(context));
>>>
>>> Regards,
>>>
>>> --knut
>>>
>>>
>>
>
|
|
|
Re: [Xtext] Scoping Provider Implementation [message #48342 is a reply to message #48283] |
Fri, 05 June 2009 09:08 |
Sebastian Zarnekow Messages: 3118 Registered: July 2009 |
Senior Member |
|
|
Hi Derek,
Yes, I imply that calls do ClassDef.getSupertypes() are resolved
correctly, when you try to create a scope for visible members.
Let me describe the controlflow, when the model is linked:
First of all, the frameworks traverses your model and tries to create
proxy EObjects for any element, that is referenced by a non-containment
EReference, aka CrossReference. Now, you may savely assume, that your
model is linked from the EMF point of view.
Afterwards, the open editor will check these proxy-crosslinks. That is,
it tries to resolve any proxy in its current model. Therefore we decode
the information in the proxy URI to retrieve the "real" linked object.
When the textual representation (most probably the name) of the linked
object has been calculated, all reachable objects have to be identified.
That's where scopes come into play. What information is available at
this point?
Example:
Resource R_A:
Model M1 {
referencedModel: R_B/M2
ClassDef A extends B,
ClassDef B extends Z,
ClassDef C
}
Resource R_B:
Model M2 {
ClassDef A,
ClassDef Z
}
Let's assume, you have an EObject A - the current 'context' - of type
ClassDef with a structural feature 'supertypes', which has the
eReferenceType ClassDef.
To find all visible (linkable) ClassDefs, we have to create a scope (or
more precisely a scope hierachy).
The most concrete, innermost scope will contain all ClassDefs that are
contained in the current model / the actual resource. It's outer scope
will contain all ClassDefs of the referenced resource. This way, we
create the following scope for the current context 'A' to resolve the
feature 'supertypes':
Scope M1 {
A, B, C
} -outer->
Scope M2 {
A, Z
} -outer->
NullScope
When the supertype of 'A' will be resolved, the linker will iterate the
content of the scope and stop as soon as it finds a scoped element whose
name matches the calculated textual representation ('B' in our example).
All this will be done basically on demand, lazy and with respect to
infinite recursion.
Now, let's dive a little deeper into the linking of MemberDefs.
We want to link a MemberRef to a MemberDef. Visible MemberDefs are
declared in the Class of the MemberRef itself or one of its
superclasses. That means, we have to create a hierachy of scopes along
the inheritance tree of ClassDefs. Therefore we need to navigate to our
supertypes and collect their declared MemberDefs. The clue is, that you
may implement it as straightforward as it sounds.
Pseudocode to create a scope for MemberRefs:
ClassDef owner = getContainerOfType(memberRef, ClassDef.class);
Scope result = createScopeContainingMemberDefs(owner);
return result;
with:
Scope createScopeContainingMemberDefs(ClassDef classDef) {
if (classDef == null)
return NullScope;
List<MemberDefs> allMembers = classDef.getAllMemberDefs();
Scope outer = createScopeContainingMemberDefs(
classDef.getSuperclass()); **
Scope result = new Scope(allMembers, outer);
return result;
}
>>> class A { int x 1; int y = 2; }
>>> class B extends A { int y = 10; }
>>> class C extends B { String z = y + x; }
Taking your example model, this will lead to the following scope, when
you try to resolve the 'y' in C { String z = y + x; }
Scope //MemberDefs of C
{
z
} -outer->
Scope // MemberDefs of B
{
y
} -outer->
Scope // MemberDefs of A
{
x,
y
} -outer->
NullScope
When you iterate the scope's content, you will get C.z, B.y, A.x.
Note: A.y will not be returned as it is hidden by B.y
** That's the point when the previously described scope for supertypes
may be created on demand. This does not interfere with the linking of
MemberRefs or other types.
Hope that clarifies things a bit. Please don't hesitate to ask for more
details, if anything remains unclear to you.
- Sebastian
Am 05.06.2009 7:58 Uhr, schrieb Derek Palma:
> Hi Sebastian,
>
> Since the exact code required for the implementation is not obvious to
> me let me first make sure I understand the idea you are proposing.
>
> First, it seems you are implying all getter calls are resolved with
> recursion which is what would be expected. So the implementation
> requires that you perform a scope resolution when you reference
> something and get an IScope back. From this you can build your current
> scope which was deferred while the scopes closer to the root of the
> model are being created.
>
> So the traversal would be something like the following based on my
> current understanding:
>
> Since this example does not include nested class declarations, we can
> assume all classes are at file scope. This is the same as the default.
>
> For class member scoping, lets assume C is processed first and its
> members must be resolved. Our grammar would have something inside a
> ClassDef like
> ((memberefs+=MemberDef) | (memberDefs+=MemberDefs)*
>
> MemberRef :
> memberRef=[MemberDef];
>
> So we would have:
> C should contain: { memberDefs=[z], memberRefs[y,x] }
>
> The problem is to resolve memberRefs for a ClassDef recursively. Taking
> your example and making it more concrete
>
> IScope recursiveComputeScope(ClassDef clazz) {
> if (clazz == null)
> return IScope.NullScope;
>
> IScope result = new Scope(clazz.getMemberDefs() /* is a list of
> MemberDef references */,
> recursiveComputeScope(clazz.getSuperclasses() /* is a list of ClassDef
> references */);
>
> return result;
> }
>
> At this point I am not sure what is really generated. Specifically what
> are the IScopes which must be generated. My guess is:
>
> IScope{ outer = C, elements = [A.x, B.y] } where outer is a ClassDef and
> elements are MemberDefs.
> IScope{ outer = B, elements = [A.x ] }
> IScope{ outer = A, elements = [] }
>
> Your feedback is appreciated.
> Thanks
> Derek
>
>
>
>
>
> "Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
> news:h09e33$nk7$1@build.eclipse.org...
>> Hi Derek,
>>
>> when you are tackling this recursive problem with the help of the lazy
>> linker (which is the default), you should not have to deal with the
>> linking order. That means, you may call any getter of your model as
>> you want.
>>
>> When I read your post, my first idea was something like this (note:
>> this is mostly pseudocode, but I hope you'll get the idea):
>>
>> IScope methodThatCalculatesTheScopeForYAndX(..) {
>> ClassDef clazz = getClassDefFromContext(..); // should be C
>> return recursiveComputeContent(clazz);
>> }
>>
>> IScope recursiveComputeScope(ClassDef clazz) {
>> if (clazz == null)
>> return IScope.NullScope;
>> IScope result = new Scope(clazz.getAllFields(),
>> recursiveComputeScope(clazz.getSuperclass());
>> return result;
>> }
>>
>> In production environments, I would track the clazzes, that have
>> already been visited to avoid infinite recursion due to cyclic
>> inheritance.
>>
>> Hope that helps,
>> Sebastian
>>
>> Am 04.06.2009 21:27 Uhr, schrieb Derek Palma:
>>> Thanks for your help Knut.
>>>
>>> Just to be sure I am understanding your point, it seems you are
>>> recommend ingI go to the root of the model and access the elemens which
>>> are not currently getting their scopes resolved in order to avoid the
>>> recursion? I am looking at the problem as a general traversal problem
>>> since the hierarchy can be of abitrary depth, so I am thinking I need to
>>> either approach it bottom-up (like I started), or top-down (maybe close
>>> to what you are proposing).
>>>
>>> Assuming I have
>>> class A { int x 1; int y = 2; }
>>> class B extends A { int y = 10; }
>>> class C extends B { String z = y + x; }
>>>
>>> B.z needs to be 11.
>>>
>>> I just want to make sure I am thinking about Xtext/Scoping correctly in
>>> tackling this. To avoid recursion I presume I have to do something to
>>> access the model without calling gets on the objects. I still don't see
>>> how this can be possible unless the recursion traverses to the root and
>>> then resolves everything top down.
>>>
>>> Derek
>>>
>>> "Knut Wannheden" <knut.wannheden@paranor.ch> wrote in message
>>> news:44c26338deeea07f63523f898013971c$1@www.eclipse.org...
>>>> Hi Derek,
>>>>
>>>> I think the problem is that when you execute
>>>> classDef.getSuperClasses().get(i) the linker is called recursively to
>>>> retrieve the scope for the very context object and reference you
>>>> currently compute the scope for.
>>>>
>>>> So assuming you have a Model object yet another level up the
>>>> containment hierarchy you should probably write something like:
>>>>
>>>> Model model = (Model) context.eContainer().eContainer();
>>>> List<ClassDef> elements = model.getClassDefs().subList(0,
>>>> model.getClassDefs().indexOf(context));
>>>>
>>>> Regards,
>>>>
>>>> --knut
>>>>
>>>>
>>>
>>
>
|
|
|
Re: [Xtext] Scoping Provider Implementation [message #49335 is a reply to message #48342] |
Mon, 08 June 2009 19:36 |
Derek Palma Messages: 141 Registered: July 2009 |
Senior Member |
|
|
Hi Sebastian,
Thanks very much! This information was very helpful. I have the basic
functions working now. However, I hit a few issues I wanted to mention.
1) Class multi inhertitance. With more than one super class you can't just
use the super class's scope as the outer. When I have more than one super
class I will just merge the scopes of all superclasses into one. So for this
case I will be returning a single scope instead of a scope hierarchy.
2) Nested class member access.
class A {
class B {
class C {
int x;
} c;
} b;
int y = b.c.x;
}
For this my grammar has an array of MemberRefs (like
memberRefs+=[MemberDef]). When I process scope resolution I am not sure how
to know the current index I am asked to resolve. I don't really know if it
is A's scope, b's (B's) scope, or c's (C's) scope. Other than using a
grammar that has instead of an array of memberRefs, a unique named variable
for each index (like memberRef1, memberRef2, ...) so the getScope will have
an EReference with the name sent to the unique name, how can I know which
index is being resolved?
3) Sometime I notice that the red underlines in the DSL editor are left in
the text even after the error indicator in the left margin is removed. If I
restart Eclipse it does not redraw the error indicator. Could the editor be
getting out of sync with me and not remembering to remove the errors once
the references are resolved? I am concerned if I could be causing this
problem or not. With M6 I did notice that the Xtext editor does this too but
I could never duplicate it and restarting eclipse always proved there was
not really a syntax error. I recently have switched to RC3 and have not done
much xtext editing.
Thanks for your help
Derek
"Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
news:h0anal$90v$1@build.eclipse.org...
> Hi Derek,
>
> Yes, I imply that calls do ClassDef.getSupertypes() are resolved
> correctly, when you try to create a scope for visible members.
>
> Let me describe the controlflow, when the model is linked:
>
> First of all, the frameworks traverses your model and tries to create
> proxy EObjects for any element, that is referenced by a non-containment
> EReference, aka CrossReference. Now, you may savely assume, that your
> model is linked from the EMF point of view.
>
> Afterwards, the open editor will check these proxy-crosslinks. That is, it
> tries to resolve any proxy in its current model. Therefore we decode the
> information in the proxy URI to retrieve the "real" linked object.
> When the textual representation (most probably the name) of the linked
> object has been calculated, all reachable objects have to be identified.
> That's where scopes come into play. What information is available at this
> point?
>
> Example:
>
> Resource R_A:
> Model M1 {
> referencedModel: R_B/M2
> ClassDef A extends B,
> ClassDef B extends Z,
> ClassDef C
> }
>
> Resource R_B:
> Model M2 {
> ClassDef A,
> ClassDef Z
> }
>
> Let's assume, you have an EObject A - the current 'context' - of type
> ClassDef with a structural feature 'supertypes', which has the
> eReferenceType ClassDef.
> To find all visible (linkable) ClassDefs, we have to create a scope (or
> more precisely a scope hierachy).
> The most concrete, innermost scope will contain all ClassDefs that are
> contained in the current model / the actual resource. It's outer scope
> will contain all ClassDefs of the referenced resource. This way, we create
> the following scope for the current context 'A' to resolve the feature
> 'supertypes':
>
> Scope M1 {
> A, B, C
> } -outer->
> Scope M2 {
> A, Z
> } -outer->
> NullScope
>
> When the supertype of 'A' will be resolved, the linker will iterate the
> content of the scope and stop as soon as it finds a scoped element whose
> name matches the calculated textual representation ('B' in our example).
> All this will be done basically on demand, lazy and with respect to
> infinite recursion.
>
> Now, let's dive a little deeper into the linking of MemberDefs.
>
> We want to link a MemberRef to a MemberDef. Visible MemberDefs are
> declared in the Class of the MemberRef itself or one of its superclasses.
> That means, we have to create a hierachy of scopes along the inheritance
> tree of ClassDefs. Therefore we need to navigate to our supertypes and
> collect their declared MemberDefs. The clue is, that you may implement it
> as straightforward as it sounds.
>
> Pseudocode to create a scope for MemberRefs:
>
> ClassDef owner = getContainerOfType(memberRef, ClassDef.class);
> Scope result = createScopeContainingMemberDefs(owner);
> return result;
>
> with:
>
> Scope createScopeContainingMemberDefs(ClassDef classDef) {
> if (classDef == null)
> return NullScope;
>
> List<MemberDefs> allMembers = classDef.getAllMemberDefs();
> Scope outer = createScopeContainingMemberDefs(
> classDef.getSuperclass()); **
> Scope result = new Scope(allMembers, outer);
> return result;
> }
>
> >>> class A { int x 1; int y = 2; }
> >>> class B extends A { int y = 10; }
> >>> class C extends B { String z = y + x; }
>
> Taking your example model, this will lead to the following scope, when you
> try to resolve the 'y' in C { String z = y + x; }
>
> Scope //MemberDefs of C
> {
> z
> } -outer->
> Scope // MemberDefs of B
> {
> y
> } -outer->
> Scope // MemberDefs of A
> {
> x,
> y
> } -outer->
> NullScope
>
> When you iterate the scope's content, you will get C.z, B.y, A.x.
> Note: A.y will not be returned as it is hidden by B.y
>
> ** That's the point when the previously described scope for supertypes may
> be created on demand. This does not interfere with the linking of
> MemberRefs or other types.
>
> Hope that clarifies things a bit. Please don't hesitate to ask for more
> details, if anything remains unclear to you.
>
> - Sebastian
>
> Am 05.06.2009 7:58 Uhr, schrieb Derek Palma:
>> Hi Sebastian,
>>
>> Since the exact code required for the implementation is not obvious to
>> me let me first make sure I understand the idea you are proposing.
>>
>> First, it seems you are implying all getter calls are resolved with
>> recursion which is what would be expected. So the implementation
>> requires that you perform a scope resolution when you reference
>> something and get an IScope back. From this you can build your current
>> scope which was deferred while the scopes closer to the root of the
>> model are being created.
>>
>> So the traversal would be something like the following based on my
>> current understanding:
>>
>> Since this example does not include nested class declarations, we can
>> assume all classes are at file scope. This is the same as the default.
>>
>> For class member scoping, lets assume C is processed first and its
>> members must be resolved. Our grammar would have something inside a
>> ClassDef like
>> ((memberefs+=MemberDef) | (memberDefs+=MemberDefs)*
>>
>> MemberRef :
>> memberRef=[MemberDef];
>>
>> So we would have:
>> C should contain: { memberDefs=[z], memberRefs[y,x] }
>>
>> The problem is to resolve memberRefs for a ClassDef recursively. Taking
>> your example and making it more concrete
>>
>> IScope recursiveComputeScope(ClassDef clazz) {
>> if (clazz == null)
>> return IScope.NullScope;
>>
>> IScope result = new Scope(clazz.getMemberDefs() /* is a list of
>> MemberDef references */,
>> recursiveComputeScope(clazz.getSuperclasses() /* is a list of ClassDef
>> references */);
>>
>> return result;
>> }
>>
>> At this point I am not sure what is really generated. Specifically what
>> are the IScopes which must be generated. My guess is:
>>
>> IScope{ outer = C, elements = [A.x, B.y] } where outer is a ClassDef and
>> elements are MemberDefs.
>> IScope{ outer = B, elements = [A.x ] }
>> IScope{ outer = A, elements = [] }
>>
>> Your feedback is appreciated.
>> Thanks
>> Derek
>>
>>
>>
>>
>>
>> "Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
>> news:h09e33$nk7$1@build.eclipse.org...
>>> Hi Derek,
>>>
>>> when you are tackling this recursive problem with the help of the lazy
>>> linker (which is the default), you should not have to deal with the
>>> linking order. That means, you may call any getter of your model as
>>> you want.
>>>
>>> When I read your post, my first idea was something like this (note:
>>> this is mostly pseudocode, but I hope you'll get the idea):
>>>
>>> IScope methodThatCalculatesTheScopeForYAndX(..) {
>>> ClassDef clazz = getClassDefFromContext(..); // should be C
>>> return recursiveComputeContent(clazz);
>>> }
>>>
>>> IScope recursiveComputeScope(ClassDef clazz) {
>>> if (clazz == null)
>>> return IScope.NullScope;
>>> IScope result = new Scope(clazz.getAllFields(),
>>> recursiveComputeScope(clazz.getSuperclass());
>>> return result;
>>> }
>>>
>>> In production environments, I would track the clazzes, that have
>>> already been visited to avoid infinite recursion due to cyclic
>>> inheritance.
>>>
>>> Hope that helps,
>>> Sebastian
>>>
>>> Am 04.06.2009 21:27 Uhr, schrieb Derek Palma:
>>>> Thanks for your help Knut.
>>>>
>>>> Just to be sure I am understanding your point, it seems you are
>>>> recommend ingI go to the root of the model and access the elemens which
>>>> are not currently getting their scopes resolved in order to avoid the
>>>> recursion? I am looking at the problem as a general traversal problem
>>>> since the hierarchy can be of abitrary depth, so I am thinking I need
>>>> to
>>>> either approach it bottom-up (like I started), or top-down (maybe close
>>>> to what you are proposing).
>>>>
>>>> Assuming I have
>>>> class A { int x 1; int y = 2; }
>>>> class B extends A { int y = 10; }
>>>> class C extends B { String z = y + x; }
>>>>
>>>> B.z needs to be 11.
>>>>
>>>> I just want to make sure I am thinking about Xtext/Scoping correctly in
>>>> tackling this. To avoid recursion I presume I have to do something to
>>>> access the model without calling gets on the objects. I still don't see
>>>> how this can be possible unless the recursion traverses to the root and
>>>> then resolves everything top down.
>>>>
>>>> Derek
>>>>
>>>> "Knut Wannheden" <knut.wannheden@paranor.ch> wrote in message
>>>> news:44c26338deeea07f63523f898013971c$1@www.eclipse.org...
>>>>> Hi Derek,
>>>>>
>>>>> I think the problem is that when you execute
>>>>> classDef.getSuperClasses().get(i) the linker is called recursively to
>>>>> retrieve the scope for the very context object and reference you
>>>>> currently compute the scope for.
>>>>>
>>>>> So assuming you have a Model object yet another level up the
>>>>> containment hierarchy you should probably write something like:
>>>>>
>>>>> Model model = (Model) context.eContainer().eContainer();
>>>>> List<ClassDef> elements = model.getClassDefs().subList(0,
>>>>> model.getClassDefs().indexOf(context));
>>>>>
>>>>> Regards,
>>>>>
>>>>> --knut
>>>>>
>>>>>
>>>>
>>>
>>
>
|
|
| |
Re: [Xtext] Scoping Provider Implementation [message #49546 is a reply to message #49335] |
Tue, 09 June 2009 08:19 |
Sebastian Zarnekow Messages: 3118 Registered: July 2009 |
Senior Member |
|
|
Hi Derek,
plase find my comments below.
Am 08.06.2009 21:36 Uhr, schrieb Derek Palma:
> Hi Sebastian,
>
> Thanks very much! This information was very helpful. I have the basic
> functions working now. However, I hit a few issues I wanted to mention.
>
> 1) Class multi inhertitance. With more than one super class you can't
> just use the super class's scope as the outer. When I have more than one
> super class I will just merge the scopes of all superclasses into one.
> So for this case I will be returning a single scope instead of a scope
> hierarchy.
Sounds reasonable :-)
>
> 2) Nested class member access.
> class A {
> class B {
> class C {
> int x;
> } c;
> } b;
>
> int y = b.c.x;
> }
> For this my grammar has an array of MemberRefs (like
> memberRefs+=[MemberDef]). When I process scope resolution I am not sure
> how to know the current index I am asked to resolve. I don't really know
> if it is A's scope, b's (B's) scope, or c's (C's) scope. Other than
> using a grammar that has instead of an array of memberRefs, a unique
> named variable for each index (like memberRef1, memberRef2, ...) so the
> getScope will have an EReference with the name sent to the unique name,
> how can I know which index is being resolved?
>
Sorry, I didn't get it. Can you please provide your grammar or at least
the relevant parts of it?
This is, what I understood: You are refering to the expression "b.c.x"
and by "index" you mean "b" or "c" or "x"?
I'ld model this expression in a way, that will produce the following
semantic model:
ChainedMemberRef (
target: ChainedMemberRef (
target: MemberRef (
member: b
)
member: c
)
member: x
)
This way, you'll get a kind of a binary tree instead of a list, thus
there will be no need to compute the current index. Have a look into
Actions to write a grammar that produces this kind of structure.
Sample:
MemberDef: name = ID '=' value = MemberRef;
MemberRef:
member=[MemberDef]
({ChainedMemberRef.target=current} '.' member=[MemberDef])*;
> 3) Sometime I notice that the red underlines in the DSL editor are left
> in the text even after the error indicator in the left margin is
> removed. If I restart Eclipse it does not redraw the error indicator.
> Could the editor be getting out of sync with me and not remembering to
> remove the errors once the references are resolved? I am concerned if I
> could be causing this problem or not. With M6 I did notice that the
> Xtext editor does this too but I could never duplicate it and restarting
> eclipse always proved there was not really a syntax error. I recently
> have switched to RC3 and have not done much xtext editing.
This sound like a bug. Please file a bugzilla and describe briefly how
to reproduce the problem.
Regards,
Sebastian
>
> Thanks for your help
> Derek
>
>
> "Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
> news:h0anal$90v$1@build.eclipse.org...
>> Hi Derek,
>>
>> Yes, I imply that calls do ClassDef.getSupertypes() are resolved
>> correctly, when you try to create a scope for visible members.
>>
>> Let me describe the controlflow, when the model is linked:
>>
>> First of all, the frameworks traverses your model and tries to create
>> proxy EObjects for any element, that is referenced by a
>> non-containment EReference, aka CrossReference. Now, you may savely
>> assume, that your model is linked from the EMF point of view.
>>
>> Afterwards, the open editor will check these proxy-crosslinks. That
>> is, it tries to resolve any proxy in its current model. Therefore we
>> decode the information in the proxy URI to retrieve the "real" linked
>> object.
>> When the textual representation (most probably the name) of the linked
>> object has been calculated, all reachable objects have to be
>> identified. That's where scopes come into play. What information is
>> available at this point?
>>
>> Example:
>>
>> Resource R_A:
>> Model M1 {
>> referencedModel: R_B/M2
>> ClassDef A extends B,
>> ClassDef B extends Z,
>> ClassDef C
>> }
>>
>> Resource R_B:
>> Model M2 {
>> ClassDef A,
>> ClassDef Z
>> }
>>
>> Let's assume, you have an EObject A - the current 'context' - of type
>> ClassDef with a structural feature 'supertypes', which has the
>> eReferenceType ClassDef.
>> To find all visible (linkable) ClassDefs, we have to create a scope
>> (or more precisely a scope hierachy).
>> The most concrete, innermost scope will contain all ClassDefs that are
>> contained in the current model / the actual resource. It's outer scope
>> will contain all ClassDefs of the referenced resource. This way, we
>> create the following scope for the current context 'A' to resolve the
>> feature 'supertypes':
>>
>> Scope M1 {
>> A, B, C
>> } -outer->
>> Scope M2 {
>> A, Z
>> } -outer->
>> NullScope
>>
>> When the supertype of 'A' will be resolved, the linker will iterate
>> the content of the scope and stop as soon as it finds a scoped element
>> whose name matches the calculated textual representation ('B' in our
>> example). All this will be done basically on demand, lazy and with
>> respect to infinite recursion.
>>
>> Now, let's dive a little deeper into the linking of MemberDefs.
>>
>> We want to link a MemberRef to a MemberDef. Visible MemberDefs are
>> declared in the Class of the MemberRef itself or one of its
>> superclasses. That means, we have to create a hierachy of scopes along
>> the inheritance tree of ClassDefs. Therefore we need to navigate to
>> our supertypes and collect their declared MemberDefs. The clue is,
>> that you may implement it as straightforward as it sounds.
>>
>> Pseudocode to create a scope for MemberRefs:
>>
>> ClassDef owner = getContainerOfType(memberRef, ClassDef.class);
>> Scope result = createScopeContainingMemberDefs(owner);
>> return result;
>>
>> with:
>>
>> Scope createScopeContainingMemberDefs(ClassDef classDef) {
>> if (classDef == null)
>> return NullScope;
>>
>> List<MemberDefs> allMembers = classDef.getAllMemberDefs();
>> Scope outer = createScopeContainingMemberDefs(
>> classDef.getSuperclass()); **
>> Scope result = new Scope(allMembers, outer);
>> return result;
>> }
>>
>> >>> class A { int x 1; int y = 2; }
>> >>> class B extends A { int y = 10; }
>> >>> class C extends B { String z = y + x; }
>>
>> Taking your example model, this will lead to the following scope, when
>> you try to resolve the 'y' in C { String z = y + x; }
>>
>> Scope //MemberDefs of C
>> {
>> z
>> } -outer->
>> Scope // MemberDefs of B
>> {
>> y
>> } -outer->
>> Scope // MemberDefs of A
>> {
>> x,
>> y
>> } -outer->
>> NullScope
>>
>> When you iterate the scope's content, you will get C.z, B.y, A.x.
>> Note: A.y will not be returned as it is hidden by B.y
>>
>> ** That's the point when the previously described scope for supertypes
>> may be created on demand. This does not interfere with the linking of
>> MemberRefs or other types.
>>
>> Hope that clarifies things a bit. Please don't hesitate to ask for
>> more details, if anything remains unclear to you.
>>
>> - Sebastian
>>
>> Am 05.06.2009 7:58 Uhr, schrieb Derek Palma:
>>> Hi Sebastian,
>>>
>>> Since the exact code required for the implementation is not obvious to
>>> me let me first make sure I understand the idea you are proposing.
>>>
>>> First, it seems you are implying all getter calls are resolved with
>>> recursion which is what would be expected. So the implementation
>>> requires that you perform a scope resolution when you reference
>>> something and get an IScope back. From this you can build your current
>>> scope which was deferred while the scopes closer to the root of the
>>> model are being created.
>>>
>>> So the traversal would be something like the following based on my
>>> current understanding:
>>>
>>> Since this example does not include nested class declarations, we can
>>> assume all classes are at file scope. This is the same as the default.
>>>
>>> For class member scoping, lets assume C is processed first and its
>>> members must be resolved. Our grammar would have something inside a
>>> ClassDef like
>>> ((memberefs+=MemberDef) | (memberDefs+=MemberDefs)*
>>>
>>> MemberRef :
>>> memberRef=[MemberDef];
>>>
>>> So we would have:
>>> C should contain: { memberDefs=[z], memberRefs[y,x] }
>>>
>>> The problem is to resolve memberRefs for a ClassDef recursively. Taking
>>> your example and making it more concrete
>>>
>>> IScope recursiveComputeScope(ClassDef clazz) {
>>> if (clazz == null)
>>> return IScope.NullScope;
>>>
>>> IScope result = new Scope(clazz.getMemberDefs() /* is a list of
>>> MemberDef references */,
>>> recursiveComputeScope(clazz.getSuperclasses() /* is a list of ClassDef
>>> references */);
>>>
>>> return result;
>>> }
>>>
>>> At this point I am not sure what is really generated. Specifically what
>>> are the IScopes which must be generated. My guess is:
>>>
>>> IScope{ outer = C, elements = [A.x, B.y] } where outer is a ClassDef and
>>> elements are MemberDefs.
>>> IScope{ outer = B, elements = [A.x ] }
>>> IScope{ outer = A, elements = [] }
>>>
>>> Your feedback is appreciated.
>>> Thanks
>>> Derek
>>>
>>>
>>>
>>>
>>>
>>> "Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
>>> news:h09e33$nk7$1@build.eclipse.org...
>>>> Hi Derek,
>>>>
>>>> when you are tackling this recursive problem with the help of the lazy
>>>> linker (which is the default), you should not have to deal with the
>>>> linking order. That means, you may call any getter of your model as
>>>> you want.
>>>>
>>>> When I read your post, my first idea was something like this (note:
>>>> this is mostly pseudocode, but I hope you'll get the idea):
>>>>
>>>> IScope methodThatCalculatesTheScopeForYAndX(..) {
>>>> ClassDef clazz = getClassDefFromContext(..); // should be C
>>>> return recursiveComputeContent(clazz);
>>>> }
>>>>
>>>> IScope recursiveComputeScope(ClassDef clazz) {
>>>> if (clazz == null)
>>>> return IScope.NullScope;
>>>> IScope result = new Scope(clazz.getAllFields(),
>>>> recursiveComputeScope(clazz.getSuperclass());
>>>> return result;
>>>> }
>>>>
>>>> In production environments, I would track the clazzes, that have
>>>> already been visited to avoid infinite recursion due to cyclic
>>>> inheritance.
>>>>
>>>> Hope that helps,
>>>> Sebastian
>>>>
>>>> Am 04.06.2009 21:27 Uhr, schrieb Derek Palma:
>>>>> Thanks for your help Knut.
>>>>>
>>>>> Just to be sure I am understanding your point, it seems you are
>>>>> recommend ingI go to the root of the model and access the elemens
>>>>> which
>>>>> are not currently getting their scopes resolved in order to avoid the
>>>>> recursion? I am looking at the problem as a general traversal problem
>>>>> since the hierarchy can be of abitrary depth, so I am thinking I
>>>>> need to
>>>>> either approach it bottom-up (like I started), or top-down (maybe
>>>>> close
>>>>> to what you are proposing).
>>>>>
>>>>> Assuming I have
>>>>> class A { int x 1; int y = 2; }
>>>>> class B extends A { int y = 10; }
>>>>> class C extends B { String z = y + x; }
>>>>>
>>>>> B.z needs to be 11.
>>>>>
>>>>> I just want to make sure I am thinking about Xtext/Scoping
>>>>> correctly in
>>>>> tackling this. To avoid recursion I presume I have to do something to
>>>>> access the model without calling gets on the objects. I still don't
>>>>> see
>>>>> how this can be possible unless the recursion traverses to the root
>>>>> and
>>>>> then resolves everything top down.
>>>>>
>>>>> Derek
>>>>>
>>>>> "Knut Wannheden" <knut.wannheden@paranor.ch> wrote in message
>>>>> news:44c26338deeea07f63523f898013971c$1@www.eclipse.org...
>>>>>> Hi Derek,
>>>>>>
>>>>>> I think the problem is that when you execute
>>>>>> classDef.getSuperClasses().get(i) the linker is called recursively to
>>>>>> retrieve the scope for the very context object and reference you
>>>>>> currently compute the scope for.
>>>>>>
>>>>>> So assuming you have a Model object yet another level up the
>>>>>> containment hierarchy you should probably write something like:
>>>>>>
>>>>>> Model model = (Model) context.eContainer().eContainer();
>>>>>> List<ClassDef> elements = model.getClassDefs().subList(0,
>>>>>> model.getClassDefs().indexOf(context));
>>>>>>
>>>>>> Regards,
>>>>>>
>>>>>> --knut
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
|
|
|
Re: [Xtext] Scoping Provider Implementation [message #49788 is a reply to message #49546] |
Wed, 10 June 2009 13:20 |
Derek Palma Messages: 141 Registered: July 2009 |
Senior Member |
|
|
Hi,
I tried the using actions instead of lists. Here is my approach and current
thinking in more detail.
Use the following example:
class A {
class Nested1 {
class Nested2 {
class Nested3 {
Integer z;
} nested;
Integer y;
} nested2;
Integer x;
} nested1;
nested1. nested2. nested3. z = 10;
}
The grammar excerpt for the rule in question:
MemberRef:
baseMemberRef=[MemberDef] ({ChainedMemberRef.target=current} '.'
nestedMemberRef=[MemberDef])*;
I am able to resolve baseMemberRef because I assume it is the first member
ref in the sequence (i.e. the nested1 of nested1.nested2.nested3.z) but for
this I ended up using the same approach I used for non nested members so I
made no progress. I do see getScope calls for nestedMemberRef. However, I
searched everywhere in the context for the name of the member (nested1,
nested2, nested3, z) and could not find it. I looked at the Xtext code which
calls getScope and it seems to have the string in the AST node but I never
see it passed to getScope in any way. I presume there is some way to know
the name of the reference for this action rule or my previous approach with
lists but I certainly need some help to find it.
My assumption is that to resolve a nested member ref I need to have the
following input somehow:
1) member ref name (nested1, nested2, nested3, ...)
2) ability to get the definition of the class containing the member
definition. I seem to be able to get the definition of A already but not
sure how if I will be able to start from A or the definition of the nested
class when I resolve the inner members.
Thanks for your patience.
Derek
"Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
news:h0l5tr$khs$1@build.eclipse.org...
> Hi Derek,
>
> plase find my comments below.
>
> Am 08.06.2009 21:36 Uhr, schrieb Derek Palma:
>> Hi Sebastian,
>>
>> Thanks very much! This information was very helpful. I have the basic
>> functions working now. However, I hit a few issues I wanted to mention.
>>
>> 1) Class multi inhertitance. With more than one super class you can't
>> just use the super class's scope as the outer. When I have more than one
>> super class I will just merge the scopes of all superclasses into one.
>> So for this case I will be returning a single scope instead of a scope
>> hierarchy.
>
> Sounds reasonable :-)
>
>>
>> 2) Nested class member access.
>> class A {
>> class B {
>> class C {
>> int x;
>> } c;
>> } b;
>>
>> int y = b.c.x;
>> }
>> For this my grammar has an array of MemberRefs (like
>> memberRefs+=[MemberDef]). When I process scope resolution I am not sure
>> how to know the current index I am asked to resolve. I don't really know
>> if it is A's scope, b's (B's) scope, or c's (C's) scope. Other than
>> using a grammar that has instead of an array of memberRefs, a unique
>> named variable for each index (like memberRef1, memberRef2, ...) so the
>> getScope will have an EReference with the name sent to the unique name,
>> how can I know which index is being resolved?
>>
>
> Sorry, I didn't get it. Can you please provide your grammar or at least
> the relevant parts of it?
> This is, what I understood: You are refering to the expression "b.c.x" and
> by "index" you mean "b" or "c" or "x"?
>
> I'ld model this expression in a way, that will produce the following
> semantic model:
>
> ChainedMemberRef (
> target: ChainedMemberRef (
> target: MemberRef (
> member: b
> )
> member: c
> )
> member: x
> )
>
> This way, you'll get a kind of a binary tree instead of a list, thus there
> will be no need to compute the current index. Have a look into Actions to
> write a grammar that produces this kind of structure.
>
> Sample:
>
> MemberDef: name = ID '=' value = MemberRef;
> MemberRef:
> member=[MemberDef]
> ({ChainedMemberRef.target=current} '.' member=[MemberDef])*;
>
>> 3) Sometime I notice that the red underlines in the DSL editor are left
>> in the text even after the error indicator in the left margin is
>> removed. If I restart Eclipse it does not redraw the error indicator.
>> Could the editor be getting out of sync with me and not remembering to
>> remove the errors once the references are resolved? I am concerned if I
>> could be causing this problem or not. With M6 I did notice that the
>> Xtext editor does this too but I could never duplicate it and restarting
>> eclipse always proved there was not really a syntax error. I recently
>> have switched to RC3 and have not done much xtext editing.
>
> This sound like a bug. Please file a bugzilla and describe briefly how to
> reproduce the problem.
>
> Regards,
> Sebastian
>
>>
>> Thanks for your help
>> Derek
>>
>>
>> "Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
>> news:h0anal$90v$1@build.eclipse.org...
>>> Hi Derek,
>>>
>>> Yes, I imply that calls do ClassDef.getSupertypes() are resolved
>>> correctly, when you try to create a scope for visible members.
>>>
>>> Let me describe the controlflow, when the model is linked:
>>>
>>> First of all, the frameworks traverses your model and tries to create
>>> proxy EObjects for any element, that is referenced by a
>>> non-containment EReference, aka CrossReference. Now, you may savely
>>> assume, that your model is linked from the EMF point of view.
>>>
>>> Afterwards, the open editor will check these proxy-crosslinks. That
>>> is, it tries to resolve any proxy in its current model. Therefore we
>>> decode the information in the proxy URI to retrieve the "real" linked
>>> object.
>>> When the textual representation (most probably the name) of the linked
>>> object has been calculated, all reachable objects have to be
>>> identified. That's where scopes come into play. What information is
>>> available at this point?
>>>
>>> Example:
>>>
>>> Resource R_A:
>>> Model M1 {
>>> referencedModel: R_B/M2
>>> ClassDef A extends B,
>>> ClassDef B extends Z,
>>> ClassDef C
>>> }
>>>
>>> Resource R_B:
>>> Model M2 {
>>> ClassDef A,
>>> ClassDef Z
>>> }
>>>
>>> Let's assume, you have an EObject A - the current 'context' - of type
>>> ClassDef with a structural feature 'supertypes', which has the
>>> eReferenceType ClassDef.
>>> To find all visible (linkable) ClassDefs, we have to create a scope
>>> (or more precisely a scope hierachy).
>>> The most concrete, innermost scope will contain all ClassDefs that are
>>> contained in the current model / the actual resource. It's outer scope
>>> will contain all ClassDefs of the referenced resource. This way, we
>>> create the following scope for the current context 'A' to resolve the
>>> feature 'supertypes':
>>>
>>> Scope M1 {
>>> A, B, C
>>> } -outer->
>>> Scope M2 {
>>> A, Z
>>> } -outer->
>>> NullScope
>>>
>>> When the supertype of 'A' will be resolved, the linker will iterate
>>> the content of the scope and stop as soon as it finds a scoped element
>>> whose name matches the calculated textual representation ('B' in our
>>> example). All this will be done basically on demand, lazy and with
>>> respect to infinite recursion.
>>>
>>> Now, let's dive a little deeper into the linking of MemberDefs.
>>>
>>> We want to link a MemberRef to a MemberDef. Visible MemberDefs are
>>> declared in the Class of the MemberRef itself or one of its
>>> superclasses. That means, we have to create a hierachy of scopes along
>>> the inheritance tree of ClassDefs. Therefore we need to navigate to
>>> our supertypes and collect their declared MemberDefs. The clue is,
>>> that you may implement it as straightforward as it sounds.
>>>
>>> Pseudocode to create a scope for MemberRefs:
>>>
>>> ClassDef owner = getContainerOfType(memberRef, ClassDef.class);
>>> Scope result = createScopeContainingMemberDefs(owner);
>>> return result;
>>>
>>> with:
>>>
>>> Scope createScopeContainingMemberDefs(ClassDef classDef) {
>>> if (classDef == null)
>>> return NullScope;
>>>
>>> List<MemberDefs> allMembers = classDef.getAllMemberDefs();
>>> Scope outer = createScopeContainingMemberDefs(
>>> classDef.getSuperclass()); **
>>> Scope result = new Scope(allMembers, outer);
>>> return result;
>>> }
>>>
>>> >>> class A { int x 1; int y = 2; }
>>> >>> class B extends A { int y = 10; }
>>> >>> class C extends B { String z = y + x; }
>>>
>>> Taking your example model, this will lead to the following scope, when
>>> you try to resolve the 'y' in C { String z = y + x; }
>>>
>>> Scope //MemberDefs of C
>>> {
>>> z
>>> } -outer->
>>> Scope // MemberDefs of B
>>> {
>>> y
>>> } -outer->
>>> Scope // MemberDefs of A
>>> {
>>> x,
>>> y
>>> } -outer->
>>> NullScope
>>>
>>> When you iterate the scope's content, you will get C.z, B.y, A.x.
>>> Note: A.y will not be returned as it is hidden by B.y
>>>
>>> ** That's the point when the previously described scope for supertypes
>>> may be created on demand. This does not interfere with the linking of
>>> MemberRefs or other types.
>>>
>>> Hope that clarifies things a bit. Please don't hesitate to ask for
>>> more details, if anything remains unclear to you.
>>>
>>> - Sebastian
>>>
>>> Am 05.06.2009 7:58 Uhr, schrieb Derek Palma:
>>>> Hi Sebastian,
>>>>
>>>> Since the exact code required for the implementation is not obvious to
>>>> me let me first make sure I understand the idea you are proposing.
>>>>
>>>> First, it seems you are implying all getter calls are resolved with
>>>> recursion which is what would be expected. So the implementation
>>>> requires that you perform a scope resolution when you reference
>>>> something and get an IScope back. From this you can build your current
>>>> scope which was deferred while the scopes closer to the root of the
>>>> model are being created.
>>>>
>>>> So the traversal would be something like the following based on my
>>>> current understanding:
>>>>
>>>> Since this example does not include nested class declarations, we can
>>>> assume all classes are at file scope. This is the same as the default.
>>>>
>>>> For class member scoping, lets assume C is processed first and its
>>>> members must be resolved. Our grammar would have something inside a
>>>> ClassDef like
>>>> ((memberefs+=MemberDef) | (memberDefs+=MemberDefs)*
>>>>
>>>> MemberRef :
>>>> memberRef=[MemberDef];
>>>>
>>>> So we would have:
>>>> C should contain: { memberDefs=[z], memberRefs[y,x] }
>>>>
>>>> The problem is to resolve memberRefs for a ClassDef recursively. Taking
>>>> your example and making it more concrete
>>>>
>>>> IScope recursiveComputeScope(ClassDef clazz) {
>>>> if (clazz == null)
>>>> return IScope.NullScope;
>>>>
>>>> IScope result = new Scope(clazz.getMemberDefs() /* is a list of
>>>> MemberDef references */,
>>>> recursiveComputeScope(clazz.getSuperclasses() /* is a list of ClassDef
>>>> references */);
>>>>
>>>> return result;
>>>> }
>>>>
>>>> At this point I am not sure what is really generated. Specifically what
>>>> are the IScopes which must be generated. My guess is:
>>>>
>>>> IScope{ outer = C, elements = [A.x, B.y] } where outer is a ClassDef
>>>> and
>>>> elements are MemberDefs.
>>>> IScope{ outer = B, elements = [A.x ] }
>>>> IScope{ outer = A, elements = [] }
>>>>
>>>> Your feedback is appreciated.
>>>> Thanks
>>>> Derek
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> "Sebastian Zarnekow" <Sebastian.Zarnekow@itemis.de> wrote in message
>>>> news:h09e33$nk7$1@build.eclipse.org...
>>>>> Hi Derek,
>>>>>
>>>>> when you are tackling this recursive problem with the help of the lazy
>>>>> linker (which is the default), you should not have to deal with the
>>>>> linking order. That means, you may call any getter of your model as
>>>>> you want.
>>>>>
>>>>> When I read your post, my first idea was something like this (note:
>>>>> this is mostly pseudocode, but I hope you'll get the idea):
>>>>>
>>>>> IScope methodThatCalculatesTheScopeForYAndX(..) {
>>>>> ClassDef clazz = getClassDefFromContext(..); // should be C
>>>>> return recursiveComputeContent(clazz);
>>>>> }
>>>>>
>>>>> IScope recursiveComputeScope(ClassDef clazz) {
>>>>> if (clazz == null)
>>>>> return IScope.NullScope;
>>>>> IScope result = new Scope(clazz.getAllFields(),
>>>>> recursiveComputeScope(clazz.getSuperclass());
>>>>> return result;
>>>>> }
>>>>>
>>>>> In production environments, I would track the clazzes, that have
>>>>> already been visited to avoid infinite recursion due to cyclic
>>>>> inheritance.
>>>>>
>>>>> Hope that helps,
>>>>> Sebastian
>>>>>
>>>>> Am 04.06.2009 21:27 Uhr, schrieb Derek Palma:
>>>>>> Thanks for your help Knut.
>>>>>>
>>>>>> Just to be sure I am understanding your point, it seems you are
>>>>>> recommend ingI go to the root of the model and access the elemens
>>>>>> which
>>>>>> are not currently getting their scopes resolved in order to avoid the
>>>>>> recursion? I am looking at the problem as a general traversal problem
>>>>>> since the hierarchy can be of abitrary depth, so I am thinking I
>>>>>> need to
>>>>>> either approach it bottom-up (like I started), or top-down (maybe
>>>>>> close
>>>>>> to what you are proposing).
>>>>>>
>>>>>> Assuming I have
>>>>>> class A { int x 1; int y = 2; }
>>>>>> class B extends A { int y = 10; }
>>>>>> class C extends B { String z = y + x; }
>>>>>>
>>>>>> B.z needs to be 11.
>>>>>>
>>>>>> I just want to make sure I am thinking about Xtext/Scoping
>>>>>> correctly in
>>>>>> tackling this. To avoid recursion I presume I have to do something to
>>>>>> access the model without calling gets on the objects. I still don't
>>>>>> see
>>>>>> how this can be possible unless the recursion traverses to the root
>>>>>> and
>>>>>> then resolves everything top down.
>>>>>>
>>>>>> Derek
>>>>>>
>>>>>> "Knut Wannheden" <knut.wannheden@paranor.ch> wrote in message
>>>>>> news:44c26338deeea07f63523f898013971c$1@www.eclipse.org...
>>>>>>> Hi Derek,
>>>>>>>
>>>>>>> I think the problem is that when you execute
>>>>>>> classDef.getSuperClasses().get(i) the linker is called recursively
>>>>>>> to
>>>>>>> retrieve the scope for the very context object and reference you
>>>>>>> currently compute the scope for.
>>>>>>>
>>>>>>> So assuming you have a Model object yet another level up the
>>>>>>> containment hierarchy you should probably write something like:
>>>>>>>
>>>>>>> Model model = (Model) context.eContainer().eContainer();
>>>>>>> List<ClassDef> elements = model.getClassDefs().subList(0,
>>>>>>> model.getClassDefs().indexOf(context));
>>>>>>>
>>>>>>> Regards,
>>>>>>>
>>>>>>> --knut
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
|
|
| |
Re: [Xtext] Scoping Provider Implementation [message #50460 is a reply to message #49944] |
Thu, 11 June 2009 17:17 |
Derek Palma Messages: 141 Registered: July 2009 |
Senior Member |
|
|
Thanks for your patience!
I still don't understand how to use the context to control the set of all
possible elements. Here are the few examples I am considering based on my
nested example.
class A {
class Nested1 {
class Nested2 {
class Nested3 {
Integer z;
} nested;
Integer y;
} nested2;
Integer x;
} nested1;
nested1. nested2. nested3. z = 10;
}
The valid possibilities for for the LHS of the asignment are:
nested1.nested2.nested3-> { z }
nested1.nested2 -> { nested3.z, y}
nested1 -> { nested2.y, nested2.nested3.z, x}
Somehow I need to know which case I am asked to resolve so I return the
correct set. I still cannot see how to use the context (e.g. what to look
for) so I can know which set to return. Can you tell me exactly what you
would look at to deterimne this? I.e. what would be used inside
target.nestedMemberRef?
As you can see my big assumption is that I need to know whether resolving
nested1, nested1.nested2, or nested1.nested2.nested3. I changed my code so
it returns union of all sets, which allows resolution to occur, but will
allow undesired combinations to be used (nested1.z).
thanks
Derek
Just one clarification. It looks like
"Sven Efftinge" <sven.efftinge@itemis.de> wrote in message
news:h0qbr9$l3m$1@build.eclipse.org...
> Derek Palma schrieb:
>> I am able to resolve baseMemberRef because I assume it is the first
>> member ref in the sequence (i.e. the nested1 of
>> nested1.nested2.nested3.z) but for this I ended up using the same
>> approach I used for non nested members so I made no progress. I do see
>> getScope calls for nestedMemberRef. However, I searched everywhere in the
>> context for the name of the member (nested1, nested2, nested3, z) and
>> could not find it. I looked at the Xtext code which calls getScope and it
>> seems to have the string in the AST node but I never see it passed to
>> getScope in any way. I presume there is some way to know the name of the
>> reference for this action rule or my previous approach with lists but I
>> certainly need some help to find it.
>
> The scopes are not responsible to filter based on the concrete text at
> hand.
> They should return all possible elements. The filtering based on the text
> is the responsibility of the ILinkingService.
>
> So given your grammar rule, a scope for 'nestedMemberRef' should be
> computed by using target.baseMemberRef (or target.nestedMemeberRef).
> Maybe you should rewrite the rule like so:
>
> MemberRef:
> memberRef=[MemberDef] ({MemberRef.target=current} '.'
> memberRef=[MemberDef])*;
>
> So you don't need to differentiate between base and nested member refs.
>
> Sven
|
|
|
Re: [Xtext] Scoping Provider Implementation [message #50488 is a reply to message #50460] |
Thu, 11 June 2009 19:07 |
Sebastian Zarnekow Messages: 3118 Registered: July 2009 |
Senior Member |
|
|
Hi Derek,
I created a very small example, to illustrate what I previously tried to
explain:
This is my model:
class TopLevel {
attribute1 = "Value";
attribute2 = attribute1;
attribute2_error = attribute2.attribute1; // error
attribute3 = A.B2.C.attr_C;
class A {
attr_A = "A";
class B1 {
attr_B = "B1";
class C {
attr_C = "C";
}
}
class B2 {
attr_B = "B2";
class C {
attr_C = "C";
}
}
}
}
The grammar:
grammar org.xtext.example.Scoping with org.eclipse.xtext.common.Terminals
generate scoping "http://www.xtext.org/example/Scoping"
Owner:
'class' name=ID '{'
members+=Member*
'}';
Member:
Owner | Attribute;
Attribute:
name = ID ( '=' value = Value )? ';';
Value:
SimpleValue | ReferenceValue;
SimpleValue:
value = STRING;
ReferenceValue:
value = [Member] ('.' {NestedReferenceValue.owner=current} value =
[Member])*;
And the scope provider. I didn't customize anything else.
/*
* generated by Xtext
*/
package org.xtext.example.scoping;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.xtext.scoping.IScope;
import org.eclipse.xtext.scoping.IScopedElement;
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvi der;
import org.eclipse.xtext.scoping.impl.ScopedElement;
import org.eclipse.xtext.scoping.impl.SimpleScope;
/**
* This class contains custom scoping description.
*
* see : http://wiki.eclipse.org/Xtext/Documentation#Scoping
* on how and when to use it
*
*/
public class ScopingScopeProvider extends AbstractDeclarativeScopeProvider {
public IScope scope_ReferenceValue_value(ReferenceValue context,
EReference reference) {
Owner owner = org.eclipse.xtext.EcoreUtil2.getContainerOfType(context,
Owner.class);
return createScope(owner.getMembers());
}
public IScope scope_ReferenceValue_value(NestedReferenceValue context,
EReference reference) {
Member member = context.getOwner().getValue();
if (member instanceof Owner)
return createScope(((Owner) member).getMembers());
return IScope.NULLSCOPE;
}
private IScope createScope(List<Member> members) {
// can be written more functional with google collections
List<IScopedElement> elements = new
ArrayList<IScopedElement>(members.size());
for(Member member: members) {
elements.add(ScopedElement.create(member.getName(), member));
}
return new SimpleScope(elements);
}
}
I can send you this sample project as a zip. Please drop me a mail, if
you like.
Hope that helps,
Sebastian
Am 11.06.2009 19:17 Uhr, schrieb Derek Palma:
> Thanks for your patience!
>
> I still don't understand how to use the context to control the set of
> all possible elements. Here are the few examples I am considering based
> on my nested example.
>
> class A {
> class Nested1 {
> class Nested2 {
> class Nested3 {
> Integer z;
> } nested;
> Integer y;
> } nested2;
> Integer x;
> } nested1;
>
> nested1. nested2. nested3. z = 10;
> }
>
> The valid possibilities for for the LHS of the asignment are:
>
> nested1.nested2.nested3-> { z }
> nested1.nested2 -> { nested3.z, y}
> nested1 -> { nested2.y, nested2.nested3.z, x}
>
> Somehow I need to know which case I am asked to resolve so I return the
> correct set. I still cannot see how to use the context (e.g. what to
> look for) so I can know which set to return. Can you tell me exactly
> what you would look at to deterimne this? I.e. what would be used inside
> target.nestedMemberRef?
>
> As you can see my big assumption is that I need to know whether
> resolving nested1, nested1.nested2, or nested1.nested2.nested3. I
> changed my code so it returns union of all sets, which allows resolution
> to occur, but will allow undesired combinations to be used (nested1.z).
>
> thanks
> Derek
>
>
> Just one clarification. It looks like
> "Sven Efftinge" <sven.efftinge@itemis.de> wrote in message
> news:h0qbr9$l3m$1@build.eclipse.org...
>> Derek Palma schrieb:
>>> I am able to resolve baseMemberRef because I assume it is the first
>>> member ref in the sequence (i.e. the nested1 of
>>> nested1.nested2.nested3.z) but for this I ended up using the same
>>> approach I used for non nested members so I made no progress. I do
>>> see getScope calls for nestedMemberRef. However, I searched
>>> everywhere in the context for the name of the member (nested1,
>>> nested2, nested3, z) and could not find it. I looked at the Xtext
>>> code which calls getScope and it seems to have the string in the AST
>>> node but I never see it passed to getScope in any way. I presume
>>> there is some way to know the name of the reference for this action
>>> rule or my previous approach with lists but I certainly need some
>>> help to find it.
>>
>> The scopes are not responsible to filter based on the concrete text at
>> hand.
>> They should return all possible elements. The filtering based on the
>> text is the responsibility of the ILinkingService.
>>
>> So given your grammar rule, a scope for 'nestedMemberRef' should be
>> computed by using target.baseMemberRef (or target.nestedMemeberRef).
>> Maybe you should rewrite the rule like so:
>>
>> MemberRef:
>> memberRef=[MemberDef] ({MemberRef.target=current} '.'
>> memberRef=[MemberDef])*;
>>
>> So you don't need to differentiate between base and nested member refs.
>>
>> Sven
>
|
|
|
Re: [Xtext] Scoping Provider Implementation [message #50516 is a reply to message #50488] |
Thu, 11 June 2009 19:12 |
Sebastian Zarnekow Messages: 3118 Registered: July 2009 |
Senior Member |
|
|
Actually there was a small bug in the last rule of the grammar. Please
replace it with
ReferenceValue:
value = [Member] ({NestedReferenceValue.owner=current} '.' value =
[Member])*;
This minor change will help the content assistant to calculate more
reasonable proposals.
Regards,
Sebastian
Am 11.06.2009 21:07 Uhr, schrieb Sebastian Zarnekow:
> Hi Derek,
>
> I created a very small example, to illustrate what I previously tried to
> explain:
>
> This is my model:
>
> class TopLevel {
>
> attribute1 = "Value";
> attribute2 = attribute1;
> attribute2_error = attribute2.attribute1; // error
> attribute3 = A.B2.C.attr_C;
> class A {
> attr_A = "A";
> class B1 {
> attr_B = "B1";
> class C {
> attr_C = "C";
> }
> }
>
> class B2 {
> attr_B = "B2";
> class C {
> attr_C = "C";
> }
> }
> }
> }
>
> The grammar:
>
> grammar org.xtext.example.Scoping with org.eclipse.xtext.common.Terminals
>
> generate scoping "http://www.xtext.org/example/Scoping"
>
> Owner:
> 'class' name=ID '{'
> members+=Member*
> '}';
>
> Member:
> Owner | Attribute;
>
> Attribute:
> name = ID ( '=' value = Value )? ';';
>
> Value:
> SimpleValue | ReferenceValue;
>
> SimpleValue:
> value = STRING;
>
> ReferenceValue:
> value = [Member] ('.' {NestedReferenceValue.owner=current} value =
> [Member])*;
>
>
> And the scope provider. I didn't customize anything else.
>
> /*
> * generated by Xtext
> */
> package org.xtext.example.scoping;
>
> import java.util.ArrayList;
> import java.util.List;
>
> import org.eclipse.emf.ecore.EReference;
> import org.eclipse.xtext.scoping.IScope;
> import org.eclipse.xtext.scoping.IScopedElement;
> import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvi der;
> import org.eclipse.xtext.scoping.impl.ScopedElement;
> import org.eclipse.xtext.scoping.impl.SimpleScope;
>
> /**
> * This class contains custom scoping description.
> *
> * see : http://wiki.eclipse.org/Xtext/Documentation#Scoping
> * on how and when to use it
> *
> */
> public class ScopingScopeProvider extends
> AbstractDeclarativeScopeProvider {
>
> public IScope scope_ReferenceValue_value(ReferenceValue context,
> EReference reference) {
> Owner owner = org.eclipse.xtext.EcoreUtil2.getContainerOfType(context,
> Owner.class);
> return createScope(owner.getMembers());
> }
>
> public IScope scope_ReferenceValue_value(NestedReferenceValue context,
> EReference reference) {
> Member member = context.getOwner().getValue();
> if (member instanceof Owner)
> return createScope(((Owner) member).getMembers());
> return IScope.NULLSCOPE;
> }
>
> private IScope createScope(List<Member> members) {
> // can be written more functional with google collections
> List<IScopedElement> elements = new
> ArrayList<IScopedElement>(members.size());
> for(Member member: members) {
> elements.add(ScopedElement.create(member.getName(), member));
> }
> return new SimpleScope(elements);
> }
>
> }
>
> I can send you this sample project as a zip. Please drop me a mail, if
> you like.
>
> Hope that helps,
> Sebastian
>
> Am 11.06.2009 19:17 Uhr, schrieb Derek Palma:
>> Thanks for your patience!
>>
>> I still don't understand how to use the context to control the set of
>> all possible elements. Here are the few examples I am considering based
>> on my nested example.
>>
>> class A {
>> class Nested1 {
>> class Nested2 {
>> class Nested3 {
>> Integer z;
>> } nested;
>> Integer y;
>> } nested2;
>> Integer x;
>> } nested1;
>>
>> nested1. nested2. nested3. z = 10;
>> }
>>
>> The valid possibilities for for the LHS of the asignment are:
>>
>> nested1.nested2.nested3-> { z }
>> nested1.nested2 -> { nested3.z, y}
>> nested1 -> { nested2.y, nested2.nested3.z, x}
>>
>> Somehow I need to know which case I am asked to resolve so I return the
>> correct set. I still cannot see how to use the context (e.g. what to
>> look for) so I can know which set to return. Can you tell me exactly
>> what you would look at to deterimne this? I.e. what would be used inside
>> target.nestedMemberRef?
>>
>> As you can see my big assumption is that I need to know whether
>> resolving nested1, nested1.nested2, or nested1.nested2.nested3. I
>> changed my code so it returns union of all sets, which allows resolution
>> to occur, but will allow undesired combinations to be used (nested1.z).
>>
>> thanks
>> Derek
>>
>>
>> Just one clarification. It looks like
>> "Sven Efftinge" <sven.efftinge@itemis.de> wrote in message
>> news:h0qbr9$l3m$1@build.eclipse.org...
>>> Derek Palma schrieb:
>>>> I am able to resolve baseMemberRef because I assume it is the first
>>>> member ref in the sequence (i.e. the nested1 of
>>>> nested1.nested2.nested3.z) but for this I ended up using the same
>>>> approach I used for non nested members so I made no progress. I do
>>>> see getScope calls for nestedMemberRef. However, I searched
>>>> everywhere in the context for the name of the member (nested1,
>>>> nested2, nested3, z) and could not find it. I looked at the Xtext
>>>> code which calls getScope and it seems to have the string in the AST
>>>> node but I never see it passed to getScope in any way. I presume
>>>> there is some way to know the name of the reference for this action
>>>> rule or my previous approach with lists but I certainly need some
>>>> help to find it.
>>>
>>> The scopes are not responsible to filter based on the concrete text at
>>> hand.
>>> They should return all possible elements. The filtering based on the
>>> text is the responsibility of the ILinkingService.
>>>
>>> So given your grammar rule, a scope for 'nestedMemberRef' should be
>>> computed by using target.baseMemberRef (or target.nestedMemeberRef).
>>> Maybe you should rewrite the rule like so:
>>>
>>> MemberRef:
>>> memberRef=[MemberDef] ({MemberRef.target=current} '.'
>>> memberRef=[MemberDef])*;
>>>
>>> So you don't need to differentiate between base and nested member refs.
>>>
>>> Sven
>>
>
|
|
|
Goto Forum:
Current Time: Sun Dec 22 05:59:48 GMT 2024
Powered by FUDForum. Page generated in 0.04894 seconds
|