Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Content assist question (an other one ...)
Content assist question [message #718940] Thu, 25 August 2011 16:12 Go to next message
Michel Simeon is currently offline Michel SimeonFriend
Messages: 130
Registered: December 2009
Senior Member
Here is a sub-set of my grammar:

grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

import "http://www.eclipse.org/emf/2002/Ecore" as ecore

Model :
('Project Name' '=')? projectName = STRING ';'
(elements += (Entity))*
'end' 'model' ;

Entity:
Commodity | Plan ;

Commodity:
'commodity' name = ID '=' label = STRING ',' 'unit' '=' unit = STRING
',' 'price' '=' price = Value ';' ;

Plan:
'plan' name = ID '=' label = STRING ',' 'unit' '=' unit = STRING ';'
(planItems += PlanItem ';')*
'end' ';' ;

PlanReference : planRef = [Plan|ID] ;

PlanItem:
CommodityPlanItem | PlanPlanItem ;

CommodityPlanItem :
itemRef = [Commodity|ID] commCalcType = CommInPlanType
'[' (values+= Value )+ ']' ;

PlanPlanItem :
itemRef = PlanReference planCalcType = PlanInPlanType
'[' (values+= Value )+ ']' ;

Value returns ecore::EDouble :
SignedInt | FLOAT ;

SignedInt returns ecore::EInt : NegativeINT | INT ;

terminal NegativeINT returns ecore::EInt : '-' ('0'..'9')+ ;

enum CommInPlanType:
cons = 'cons'| prod = 'prod' | avail = 'avail' ;

enum PlanInPlanType:
annual = "annual" | phastot = "phastot"
| phasadd = "phasadd" | phasold = "phasold" ;

terminal FLOAT returns ecore::EDouble :
('-'|'+')? (INT '.' INT+ | '.' INT+ | INT '.') ('e' ('-'|'+') INT+)?;

terminal ID:
('A'..'Z'|'À'..'Ý') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'À'..'ÿ')* ;

My problem is the following:

When I define a plan item and specify the ID of a Commodity, I would expect Ctrl-Space to show only the keywords corresponding to a commodity (prod, cons or avail), but I also get the keywords corresponding to a plan. My understanding is that the parser does not infer the type of PlanItem from the item ID, but from the following keyword.

I know I could solve the problem by changing the grammar by adding keywords to the two PlanItem types:

CommodityPlanItem :
'commItem' itemRef = [Commodity|ID] commCalcType = CommInPlanType
(('[' (values+= Value )+ ']')) ;

PlanPlanItem :
'planItem' itemRef = PlanReference planCalcType = PlanInPlanType
'[' (values+= Value )+ ']' ;

The drawback is that the model files that already exist would not be compatible with the revised version.

Is there a way to handle it through the scope provider ? I tried but could not find my way.

Any help is most welcome

MS

Re: Content assist question [message #719019 is a reply to message #718940] Thu, 25 August 2011 19:50 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14661
Registered: July 2009
Senior Member
Hi,

what about simplyfing the grammar and solve the enum problem with a check + content assist?
the main promlem is that enums are pain in the ass in this relation

PlanItem:
itemRef = [Entity|ID] (commCalcType = CommInPlanType | planCalcType = PlanInPlanType)
'[' (values+= Value )+ ']' ;

enum CommInPlanType:
CommInPlanTypeNull | cons = 'cons'| prod = 'prod' | avail = 'avail' ;

enum PlanInPlanType:
PlanInPlanTypeNull |  annual = "annual" | phastot = "phastot"
| phasadd = "phasadd" | phasold = "phasold" ;


public class MyDslProposalProvider extends AbstractMyDslProposalProvider {
	
	@Override
	public void completeKeyword(Keyword keyword,
			ContentAssistContext context,
			ICompletionProposalAcceptor acceptor) {
		PlanItem item  = (PlanItem) context.getCurrentModel();
		EEnum eenum = getEEnum(keyword);
		if (keyword.getValue().equals("CommInPlanTypeNull") || keyword.getValue().equals("PlanInPlanTypeNull")) {
			return;
		}
		if (eenum == null) {
			super.completeKeyword(keyword, context, acceptor);
		} else {
			if (item.getItemRef() instanceof Commodity) {
				if (MyDslPackage.Literals.COMM_IN_PLAN_TYPE.equals(eenum)) {
					super.completeKeyword(keyword, context, acceptor);
				}
			} else if (item.getItemRef() instanceof Commodity) {
				if (MyDslPackage.Literals.PLAN_IN_PLAN_TYPE.equals(eenum)) {
					super.completeKeyword(keyword, context, acceptor);
				}
			}
		}
	}
	
	EEnum getEEnum(Keyword keyword) {
		if (keyword.eContainer() instanceof EnumLiteralDeclaration) {
			return ((EnumLiteralDeclaration)keyword.eContainer()).getEnumLiteral().getEEnum();
		}
		return null;
	}
	
	

}


public class MyDslJavaValidator extends AbstractMyDslJavaValidator {

	@Check
	public void checkPlanItem(PlanItem item) {
		if (CommInPlanType.COMM_IN_PLAN_TYPE_NULL.equals(item.getCommCalcType()) && PlanInPlanType.PLAN_IN_PLAN_TYPE_NULL.equals(item.getPlanCalcType())) {
			error("please specify a void type", MyDslPackage.Literals.PLAN_ITEM__ITEM_REF);
		}
		if (item.getItemRef() instanceof Plan) {
			if (!CommInPlanType.COMM_IN_PLAN_TYPE_NULL.equals(item.getCommCalcType())) {
				error("keyword " + item.getCommCalcType().getLiteral() + " is not allowed here", MyDslPackage.Literals.PLAN_ITEM__COMM_CALC_TYPE);
			}
		}
		if (item.getItemRef() instanceof Commodity) {
			if (!PlanInPlanType.PLAN_IN_PLAN_TYPE_NULL.equals(item.getPlanCalcType())) {
				error("keyword " + item.getPlanCalcType().getLiteral() + " is not allowed here", MyDslPackage.Literals.PLAN_ITEM__PLAN_CALC_TYPE);
			}
		}
	}

}


~Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Content assist question [message #719024 is a reply to message #719019] Thu, 25 August 2011 20:27 Go to previous messageGo to next message
Michel Simeon is currently offline Michel SimeonFriend
Messages: 130
Registered: December 2009
Senior Member
Thanks Christian for a very comprehensive suggestion. I'll try it out.

I'll also need to find out if and how what you suggest would fit the real DSL, where there are five types of Entity instead of two in the subset. In addition to Commodity and Plan there is also Herd, Script and Table; Herd and Script can be a PlanItem, not Table; HerdPlanItem has a values attribute but no result-type attribute, Script has no attribute at all.

I'll let you know.
Thanks again
Michel

Re: Content assist question [message #719479 is a reply to message #719024] Sat, 27 August 2011 12:30 Go to previous messageGo to next message
Michel Simeon is currently offline Michel SimeonFriend
Messages: 130
Registered: December 2009
Senior Member
Hi Christian.

I am making progress and give some details for the benefit of others that might be interested (the full software, called Mads, is at http://mads.sourceforge.net/). I still have one question.

The full grammar includes five types of Entity, each with a unique ID:

Entity:
Commodity | Plan | Script | Herd | Table;

A plan item can be any entity except Table:

PlanItem :
itemRef = [Entity|ID]
( (commCalcType = CommInPlanType '[' (values+= Value )+ ']' ';') // commodity in plan
| (planCalcType = PlanInPlanType '[' (values+= Value )+ ']' ';') // plan in plan
| ('[' (values+= Value )+ ']' ';') // herd in plan
| ';' // script in plan
);

Only Plan and Commodity have a result-type attribute and a series-of-values attribute, Herd has values, Script has no attribute.

The javaValidator and proposalProvider, derived from your message, are thus more complicated:

public class MyDslProposalProvider extends AbstractMyDslProposalProvider {

@Override
public void completeKeyword(Keyword keyword,
ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
EObject currItem = context.getCurrentModel();

if (currItem instanceof PlanItem) {
String proposal;
PlanItem item = (PlanItem) currItem;
// PlanItem item = (PlanItem) context.getCurrentModel();
EEnum eenum = getEEnum(keyword);
if (keyword.getValue().equals("CommInPlanTypeNull")
|| keyword.getValue().equals("PlanInPlanTypeNull")) {
return;
}
if (eenum == null) {
super.completeKeyword(keyword, context, acceptor);
} else {
if (item.getItemRef() instanceof Commodity) {
if (MyDslPackage.Literals.COMM_IN_PLAN_TYPE.equals(eenum)) {
super.completeKeyword(keyword, context, acceptor);
}
} else if (item.getItemRef() instanceof Plan) {
if (MyDslPackage.Literals.PLAN_IN_PLAN_TYPE.equals(eenum)) {
super.completeKeyword(keyword, context, acceptor);
}
}
}
if (item.getItemRef() instanceof Script) proposal = "script item = ID ; ";
else if (item.getItemRef() instanceof Herd) proposal = "herd item = ID [ series of values ] ; ";
else proposal = "item = ID resType [ series of values ] ; ";
proposal = getValueConverter().toString(proposal, "STRING");
ICompletionProposal completionProposal =
createCompletionProposal(proposal, context);
acceptor.accept(completionProposal);
} else if (currItem instanceof Model) {
super.completeKeyword(keyword, context, acceptor);
}
}
....
}

public class MyDslJavaValidator extends AbstractMyDslJavaValidator {


@Check
public void checkPlanItem(PlanItem item) {
if (item.getItemRef() instanceof Plan) {
if (!CommInPlanType.COMM_IN_PLAN_TYPE_NULL.equals(item.getCommCalcType())) {
error("keyword " + item.getCommCalcType().getLiteral() + " is not allowed here", MyDslPackage.Literals.PLAN_ITEM__COMM_CALC_TYPE);
}
if (PlanInPlanType.PLAN_IN_PLAN_TYPE_NULL.equals(item.getPlanCalcType())) {
error("Calculation type keyword is required for Plan Item", MyDslPackage.Literals.PLAN_ITEM__PLAN_CALC_TYPE);
}
// A plan cannot include itself through nested plans
Plan planRefPlan = (Plan) item.getItemRef();
Plan container = (Plan) item.eContainer(); // containing plan
String containerName = container.getName();
Boolean found = false;
found = scanPlan( planRefPlan, containerName, found);
if (found) {
error("A plan cannot include itself through nested plans",
MyDslPackage.Literals.PLAN_ITEM__ITEM_REF);
}
}
else if (item.getItemRef() instanceof Commodity) {
if (!PlanInPlanType.PLAN_IN_PLAN_TYPE_NULL.equals(item.getPlanCalcType())) {
error("keyword " + item.getPlanCalcType().getLiteral() + " is not allowed here", MyDslPackage.Literals.PLAN_ITEM__PLAN_CALC_TYPE);
}
if (CommInPlanType.COMM_IN_PLAN_TYPE_NULL.equals(item.getCommCalcType())) {
error("Calculation type keyword is required for Commodity Item", MyDslPackage.Literals.PLAN_ITEM__COMM_CALC_TYPE);
}
}
else if ((item.getItemRef() instanceof Herd) || (item.getItemRef() instanceof Script)) {
if (!CommInPlanType.COMM_IN_PLAN_TYPE_NULL.equals(item.getCommCalcType())) {
error("keyword " + item.getCommCalcType().getLiteral() + " is not allowed here", MyDslPackage.Literals.PLAN_ITEM__COMM_CALC_TYPE);
}
if (!PlanInPlanType.PLAN_IN_PLAN_TYPE_NULL.equals(item.getPlanCalcType())) {
error("keyword " + item.getPlanCalcType().getLiteral() + " is not allowed here", MyDslPackage.Literals.PLAN_ITEM__PLAN_CALC_TYPE);
}
if (item.getItemRef() instanceof Script){
if (item.getValues().size()!=0) {
error("Time series of Values is not allowed here", MyDslPackage.Literals.PLAN_ITEM__VALUES);
}
}
}
if (!(item.getItemRef() instanceof Script)){
if (item.getValues().size()==0) {
error("Time series of Values is required here", MyDslPackage.Literals.PLAN_ITEM__VALUES);
}
}
}
private Boolean scanPlan (Plan planRefPlan, String containerName, Boolean found){
// scans items of Plan planRef to see if it includes reference to container
...
return found;
}
}

===============

Now, here is my question:

Given the syntax of PlanItem, I always get ; and [ as part of the list of proposals. Could you help me find out how to control those in the proposals provider.

Thanks again for your assistance.

Michel
Re: Content assist question [message #719480 is a reply to message #719479] Sat, 27 August 2011 12:32 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14661
Registered: July 2009
Senior Member
Hi,

the [ ; are keywords too, do debug into completeKeyword and see what you get Wink

~Christian


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: Content assist question [message #722702 is a reply to message #719480] Tue, 06 September 2011 14:44 Go to previous message
Michel Simeon is currently offline Michel SimeonFriend
Messages: 130
Registered: December 2009
Senior Member
Hi Christian,

I found it difficult to understand what goes on when keyword lists are set and gave up trying to do too much. Eventually I decided to change my syntax slightly - at the expense of not being compatible with the previous version.

Now my grammar is:

PlanItem:
(
('run' scriptRef = [Script|ID] SEMI)
| ( planItemRef = [Entity|ID]
(
commCalcType = CommInPlanType
| planCalcType = PlanInPlanType
| herdCalcType = HerdInPlanType // can only be phased
)
(('[' (values+= Value )+ ']')| (levelvalues=ReadFunc))
SEMI
)
);

On that basis I was able to get what I wanted on the basis of your model.

Now I am trying to deal in a similar way with other parts of my grammar, where again I have alternative proposals of items with different lists of features.

One thing I found odd was the fact that variables such as planCalcType above were always assigned a value by default, even if not set by the model, hence the need to add a dummy value like the PlanInPlanTypeNull you proposed. The main draw-back is that if somewhere else I use the default CA mechanism the this value will show up in the list.

Question to the developpers of XText: would it make sense to have null as default when the variable was not set ?

Cheers to all of you
MS
Previous Topic:Difference between References
Next Topic:How to use @Inject in the Xtend Template
Goto Forum:
  


Current Time: Thu Mar 28 21:57:06 GMT 2024

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

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

Back to the top