Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » How to Cross-reference sub-elements ?(Trying to cross reference sub-elements of type declaration)  () 1 Vote
icon5.gif  How to Cross-reference sub-elements ? [message #549525] Tue, 27 July 2010 06:21 Go to next message
Cyril  is currently offline Cyril Friend
Messages: 18
Registered: July 2010
Junior Member
Hello Community friends,

I am new to xtext, please be indulgent and descriptive if you can.

I understood how to reference 'root-level' Type declaration like in the xtext guide example between entity and feature.

I am trying now to upgrade in a similar expample with sub-elements using cross-reference like this:

Grammar :


DomainModel:
	(elements+=AbstractElements)*;
	
AbstractElements :
	Cars | Animal | MyCarDescription | MyPetDescription;

Cars :
 'brand :' name=ID '{'
 	(elements+=CarType)*
 	'}'
 ;
 	
CarType:
 'type ' name=ID;

 Animal :
 'species ' name=ID '{'
 	(elements+=PetName)*
 	'}'
 	;
 	
 PetName :
 	'Pet name :' name=ID;
 	
 MyCarDescription :
 'I own a ' myCar=[Cars] 'of type ' myCarType=[CarType];
 
 MyPetDescription :
 'My Pet is a ' myPet=[Animal]', his/her name is ' myPetName =[PetName];


DSL:
brand : Chrysler {
type Voyager
type Horizon
}

brand : Toyota {
type Hybrid
type Yaris
}

species Dog {
Pet name : Zeus
Pet name : Appolon
}

species Cat {
Pet name : Lilou
Pet name : Zoe
}

I own a Chrysler of type ______

My Pet is a Dog , his/her name is ______


How can I get content assist to offer Voyager or Horizon on the first line ?
Same question for Zeus and Appolon on the second line ?

Please correct my grammar if necessary.

Thanks a lot for your time.
Best regards,

Cyril
Re: How to Cross-reference sub-elements ? [message #549538 is a reply to message #549525] Tue, 27 July 2010 06:57 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Hello Cyril,

welcome to Xtext. The solution for your problem is called "scoping". (see Scoping - especially dclarative scoping in the docs). by default References in Xtext are not aware of their context. in your case at MyCarDescription it shows you all CarTypes for the reference myCarType and not only those that fit myCar.

So what can you do. You have to change YourDsl Scope Provider

Here the sample for MyCarDescription

public class MyDslScopeProvider extends AbstractDeclarativeScopeProvider {
	
	public IScope scope_MyCarDescription_myCarType(MyCarDescription mcd, EReference ref) {
		return Scopes.scopeFor(mcd.getMyCar().getElements());
	}

}


Regards
Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: How to Cross-reference sub-elements ? [message #549822 is a reply to message #549538] Wed, 28 July 2010 06:55 Go to previous messageGo to next message
Cyril  is currently offline Cyril Friend
Messages: 18
Registered: July 2010
Junior Member
Christian,

Thanks a lot. You were very helpfull. It works great.

Best regards,

Cyril
Re: How to Cross-reference sub-elements ? [message #552050 is a reply to message #549822] Tue, 10 August 2010 16:05 Go to previous messageGo to next message
Cyril  is currently offline Cyril Friend
Messages: 18
Registered: July 2010
Junior Member
Hello,

I went further into the above solution and encounter a case when scope is given to the validator but not to content-assist, can you help get around this ?

So I added to my grammar the following :

BrandDescription : 
 'For the car brand ' brandname=[Cars] ', the following colored types exist : '
 	(elements+=ColorCarTypeDefinition)+
 ;
 
 ColorCarTypeDefinition :
 	coloredcartype=[CarType] ' = ' color=ID 	;


then I added to my ScopeProvider :
	// Gives scope to editor validator but not to content-assist, why ?
	public IScope scope_ColorCarTypeDefinition_coloredcartype(ColorCarTypeDefinition colorCarTypeDefinition, EReference ref) {
		return Scopes.scopeFor(((BrandDescription)colorCarTypeDefinition.eContainer()).getBrandname().getElements());	
	}


we can see that when I write :
For the car brand Chrysler , the following colored types exist : 
Voyager = blue
Horizon = red
Hybrid = yellow


That it correctly validates Voyager and Horizon but not Hybrid, that's great!
However content-assist does not work and does not propose 'Voyager and Horizon'. Can you tell me how I can correct my scope provider code in order to solve this.

Thanks a lot for your time

Cyril


[Updated on: Thu, 12 August 2010 15:32]

Report message to a moderator

Re: How to Cross-reference sub-elements ? [message #552200 is a reply to message #552050] Wed, 11 August 2010 08:34 Go to previous messageGo to next message
Meinte Boersma is currently offline Meinte BoersmaFriend
Messages: 434
Registered: July 2009
Location: Leiden, Netherlands
Senior Member
I'm guessing that the parser for the content assist can't know yet that you're inside a ColorCarTypeDefinition and hence doesn't try to call the scoping provider for the coloredcartype reference inside it. (I'm not sure how the + modifier in "(elements+=ColorCarTypeDefinition)+" ensures that the generated parser will expect ColorCarTypeDefinition or whether it pre-emptively invokes the parser rule -if not it might still be "poised" to expect a ';'.) You could verify this by typing 'V' and hitting Ctrl/Cmd-Space.

Simple but unelegant solution: prepend ColorCarTypeDefinition with a token like "def" or something. For more elegant but difficult solutions: the Xtext team is your friend Wink



icon9.gif  Re: How to Cross-reference sub-elements ? [message #552556 is a reply to message #552200] Thu, 12 August 2010 15:48 Go to previous messageGo to next message
Cyril  is currently offline Cyril Friend
Messages: 18
Registered: July 2010
Junior Member
Thanks Meinte for your reply.

>(I'm not sure how the + modifier in "(elements+=ColorCarTypeDefinition)+" ensures that the generated parser will expect ColorCarTypeDefinition

To answer your comment I changed to :
BrandDescription :
'For the car brand ' brandname=[Cars] ', the following colored types exist : '
(elements+=ColorCarTypeDefinition)*

=>NO CHANGE

>You could verify this by typing 'V' and hitting Ctrl/Cmd-Space.
Result is:
V =

>Simple but unelegant solution: prepend ColorCarTypeDefinition with a token like "def" or something.

Could you develop your suggestion ?


If I look at some code for the content-assistant :
package org.xtext.example.mydsl.ui.contentassist;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.*;
import org.eclipse.xtext.common.ui.contentassist.TerminalsProposalProvider;
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor;
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext;

/**
 * Represents a generated, default implementation of interface {@link IProposalProvider}.
 * Methods are dynamically dispatched on the first parameter, i.e., you can override them 
 * with a more concrete subtype. 
 */
public class AbstractMyDslProposalProvider extends TerminalsProposalProvider {
		


...

	public void completeColorCarTypeDefinition_Coloredcartype(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		lookupCrossReference(((CrossReference)assignment.getTerminal()), context, acceptor);
	}
	public void completeColorCarTypeDefinition_Color(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		completeRuleCall(((RuleCall)assignment.getTerminal()), context, acceptor);
	}

...

	public void complete_ColorCarTypeDefinition(EObject model, RuleCall ruleCall, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		// subclasses may override
	}
}


I just started to read about how to customize content assist today in the middle of thousands other things.

If you have any example where I could speed up my training on this, or any other hints, I will greatly appreciate it.

Thanks for your time.

Cyril
Re: How to Cross-reference sub-elements ? [message #552595 is a reply to message #552556] Thu, 12 August 2010 18:14 Go to previous messageGo to next message
Dennis  is currently offline Dennis Friend
Messages: 19
Registered: August 2010
Junior Member
I am having similar issue like yourself. Were you able to resolve? Please see my link at http://www.eclipse.org/forums/index.php?t=msg&goto=55259 3&S=6afef75056c3d9c97d04abff618857d2#msg_552593
Re: How to Cross-reference sub-elements ? [message #552604 is a reply to message #552556] Thu, 12 August 2010 18:41 Go to previous messageGo to next message
Alexander Nittka is currently offline Alexander NittkaFriend
Messages: 1193
Registered: July 2009
Senior Member
Hi,

some remarks:

Please use Debugging (e.g. in order to see whether your scoping functions are called at all). For example in the scoping for ColorCarTypeDefinition the first parameter may not be a ColorCarTypeDefinition but a BrandDescription when invoking code completion. In your case this will very probably cause that no proposals are given. I imagine something like polymorphic dispatch not hitting your method (wrong type), uses the default implementation which comes up with all Cartypes, these however with fully qualified names so that they cannot be proposed as you want to reference them with an ID (which does not contain '.'.

public IScope scope_ColorCarTypeDefinition_coloredcartype(EObject context, EReference ref) {
BrandDescription b=extractBrandDescriptionFromContext(context);
return Scopes.scopeFor(b.getBrandname().getElements());
}


Further: do not use keywords that include white spaces.

MyCarDescription :
'I own a ' myCar=[Cars] 'of type ' myCarType=[CarType];

should be

MyCarDescription :
'I' 'own' 'a' myCar=[Cars] 'of' 'type' myCarType=[CarType];

Keywords with spaces will produce strange errors (e.g. try writing "Voyager = blue" i.e. two spaces before the equals).

Alex
Re: How to Cross-reference sub-elements ? [message #552708 is a reply to message #552604] Fri, 13 August 2010 08:53 Go to previous messageGo to next message
Cyril  is currently offline Cyril Friend
Messages: 18
Registered: July 2010
Junior Member
Wise remarks Alex as usual, thank you !

Most of the time, it gets a little bit technical to read your posts for non xtext pro like myself and I end up guessing around your suggestions.

This time I replaced my scope provider like this :
	public IScope scope_ColorCarTypeDefinition_coloredcartype(EObject context, EReference ref) {
		BrandDescription b=extractBrandDescriptionFromContext(context);
		return Scopes.scopeFor(b.getBrandname().getElements());
		}

	private BrandDescription extractBrandDescriptionFromContext(EObject context) {
		return (BrandDescription) context.eContainer();
	}


Not too sure if that's what you suggested, but I tried to launch in debug, and observed when invoking code completion that it's (as you imagine) filling the EOject context parameter with Types others than ColorCarTypeDefinition.

What you're saying is that the default implementation goes through other parents types (shoud I say econtainers?) of ColorCarTypeDefinition and returns somehow fully qualified names which are not interpreted by content assist (the latter only proposing structure like IDs)
Great, I guess I understand that minor part Smile

This interesting understood point does not however lead me to a hint of solution:
-Should I know and develop more complex Scope Provider code ?

-Is the behavior between validator and content assistant not suppose to work together around the same scoping code ?

Reading Dennis' Tables scopes thread made me feel less lonely on this Wink

Can you still help us with sample solutions ?
(My simple grammar isn't a good base ?)

I would think this is something that comes up quite often for people working with xtext to want content-assist to go through inner scopes.

Since it works for the validator, what do I need to tell content-assist to be inspired identicly ? Wink


On your last remarks "do not use keywords that include white spaces.", I'm not sure I got that part as well.
First of all, the power of content assist is to be used quite often for sentences which are uniques.
Why would we want to ctrl space 3 times with intermediate space bar touches to write "I own a" , when we can do it twice and have content assist put together "I own a " followed by a proposed list of words ?

Nevertheless, I tried :
'I' 'own' 'a' myCar=[Cars] 'of' 'type' myCarType=[CarType];
And Validator or content-assist did not like the last word 'a' or 'type' and the junction with the cross reference.

I did not observe the strange error you mention with two spaces before the equals.

In any cases, thanks so much for your suggestion, I am really eager to get the solution on how to write nice content-assist code; but I am guessing it's not that simple Wink

Thanks for your time.

Cyril
Re: How to Cross-reference sub-elements ? [message #552726 is a reply to message #552708] Fri, 13 August 2010 09:21 Go to previous messageGo to next message
Alexander Nittka is currently offline Alexander NittkaFriend
Messages: 1193
Registered: July 2009
Senior Member
> This time I replaced my scope provider like this :
>
> public IScope scope_ColorCarTypeDefinition_coloredcartype(EObject
> context, EReference ref) {
> BrandDescription b=extractBrandDescriptionFromContext(context);
> return Scopes.scopeFor(b.getBrandname().getElements());
> }
>
> private BrandDescription extractBrandDescriptionFromContext(EObject
> context) {
> return (BrandDescription) context.eContainer();
> }
This is basically the same as you had before. The point of the
extractBrandDescription...method is that it is not sufficient to return
the casted context.eContainer(). What if context is an instance of
BrandDescription already. In this case you should return context instead
of context.eContainer.

> Not too sure if that's what you suggested, but I tried to launch in
> debug, and observed when invoking code completion that it's (as you
> imagine) filling the EOject context parameter with Types others than
> ColorCarTypeDefinition.
See. So you have to react to the different types in different ways.

> What you're saying is that the default implementation goes through other
> parents types (shoud I say econtainers?) of ColorCarTypeDefinition and
> returns somehow fully qualified names which are not interpreted by
> content assist (the latter only proposing structure like IDs) Great, I
> guess I understand that minor part :)
Not quite. The default implementation looks for custom scoping
functions, starting with the most specific context type if it does not
find one, it tries to find a method with the type of the context's
container.
In your orignal implementation (context type ColorCarTypeDefinition) no
matching custom method could be found, so the "DefaultScoping" was
applied creating a scope with fully qualified names.

By changing the context parameter to EObject, you make sure that the
custom scoping function is found but now you have to make sure that the
context element is treated correctly.

An alternative would be to use your original scoping function and

public IScope
scope_ColorCarTypeDefinition_coloredcartype(BrandDescription context,
EReference ref) {
return Scopes.scopeFor(context.getBrandname().getElements());
}

> -Is the behavior between validator and content assistant not suppose to
> work together around the same scoping code ?
They do. But the setup is slightly different. Roughly speaking, the
validation can assume that the model is fully instantiated, code
completion cannot (as you wouldn't hit code completion if everything is
there already). This causes the context types to differ, which you have
to take into account when implementing the scoping methods.

> On your last remarks "do not use keywords that include white spaces.",
> I'm not sure I got that part as well.
The basic problem is if you have a keyword "I own" (with one space), you
cannot write "I own" (with two spaces) in the model.

> First of all, the power of content assist is to be used quite often for
> sentences which are uniques.
> Why would we want to ctrl space 3 times with intermediate space bar
> touches to write "I own a" , when we can do it twice and have content
> assist put together "I own a " followed by a proposed list of words ?

Well, how about writing a template that proposes "I own a
*variableForCar* of type *variableForType*" in one go. The variables are
used to allow further content assists *within* the template proposal.
See the documentation on template proposals in the Xtext documentation
and http://blogs.itemis.de/stundzig/archives/474 (you won't need your
own template variable resolver)

Alex


Need training, onsite consulting or any other kind of help for Xtext?
Go visit http://xtext.itemis.com or send a mail to xtext@itemis.de
Re: How to Cross-reference sub-elements ? [message #552729 is a reply to message #552708] Fri, 13 August 2010 09:36 Go to previous message
Alexander Nittka is currently offline Alexander NittkaFriend
Messages: 1193
Registered: July 2009
Senior Member
> On your last remarks "do not use keywords that include white spaces.",

> Nevertheless, I tried :
> 'I' 'own' 'a' myCar=[Cars] 'of' 'type' myCarType=[CarType];
> And Validator or content-assist did not like the last word 'a' or 'type'
> and the junction with the cross reference.

Of course you have to remove the spaces from *all* keywords in the
grammar. Basically everything placed in single or double quotes is a
keyword (stuff in terminal rules excluded).

I bet type was marked as an error as "type " (with space) is a keyword
in the CarType definition.

Alex


Need training, onsite consulting or any other kind of help for Xtext?
Go visit http://xtext.itemis.com or send a mail to xtext@itemis.de
Previous Topic:Disable XtextBuilder
Next Topic:How to introduce my Terminal Rule NOUNDERSCORE ?
Goto Forum:
  


Current Time: Fri Apr 26 00:33:36 GMT 2024

Powered by FUDForum. Page generated in 0.03615 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top