Help debugging a scope provider [message #1765920] |
Wed, 14 June 2017 09:32  |
Eclipse User |
|
|
|
I am trying to add a scope provider for a DSL. The DSL code is as follows:
Caste Moose() {
action Sheep (Horse:Int) {
create dog of Moose (2);
var Camel : Int;
Camel := 3;
}
action Pig (Horse:Int) {
Camel := 2;
}
}
The code added to the ScopeProvider class for VarNames is:
if (context instanceof VarName) {
// Work up through containers.
val varsInScope = new ArrayList<VarName>
var currentContainer = reference.eContainer
while (currentContainer !== null) {
switch currentContainer {
ForStatement:
if (currentContainer.newVar !== null)
varsInScope.add(currentContainer.newVar)
WithStatement:
if (currentContainer.newVar !== null)
varsInScope.add(currentContainer.newVar)
Statements: {
val locals = EcoreUtil2.getAllContentsOfType(currentContainer,
LocalVariableDeclaration)
locals.forEach([local | varsInScope.add(local.getVar().name)])
}
CasteDeclaration: {
val globals = EcoreUtil2.getAllContentsOfType(currentContainer,
VarDeclaration)
globals.forEach([global | varsInScope.add(global.getVar().name)])
}
}
currentContainer = currentContainer.eContainer
}
return Scopes.scopeFor(varsInScope)
}
Looking at the Outline view in the runtime Eclipse, I can see correctly that the declarations of Pig and Sheep are in different branches of the common declaration of Moose, and so one should not be reached by a chain of containment from the other. Nonetheless the IDE continues to state that Camel is in scope in Pig, and when asked to "go to declaration" goes to the one inside Sheep. Can anyone help with this? I tried with initializing currentContainer to both reference.eContainer and context.eContainer and the result was the same. Is it possible to produce debug output in a context provider in this way?
|
|
|
|
|
|
|
|
|
|
|
|
Re: Help debugging a scope provider [message #1765969 is a reply to message #1765965] |
Wed, 14 June 2017 11:55   |
Eclipse User |
|
|
|
Entire grammar:
grammar obuaop.Caople with org.eclipse.xtext.common.Terminals
generate caople "http://www.Caople.obuaop"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
Model hidden (WS, ML_COMMENT, SL_COMMENT):
imports=ImportClause?
uses=UsesClause?
caste=CasteDeclaration
;
CasteDeclaration:
CASTE castename=CasteName '(' params=FormalParamList? ')'
(EXTEND parent=[CasteName|ID])?
'{'
observes+=ObserveDeclaration*
vars+=VarDeclaration*
actions+=ActionDeclaration*
init=InitDeclaration?
routine=RoutineDeclaration?
'}'
;
ImportClause:
IMPORT (defPackNames+=ID) (',' defPackNames+=ID)* ';'
;
UsesClause:
USES (importCasteNames+=CasteName) (',' importCasteNames+=CasteName)* ';'
;
ObserveDeclaration:
OBSERVE scope=ScopeType observed=ID IN? castes+=[CasteName] (',' castes+=[CasteName])* ';'
;
VarDeclaration:
state?=STATE? VAR var=VarNameAndType ';'
;
ActionDeclaration:
internal?=INTERNAL? ACTION name=ActionName '(' params=FormalParamList ')' '{' body=Statements '}'
;
InitDeclaration:
INIT '{' body=Statements '}'
;
RoutineDeclaration:
BODY '{' body=Statements '}'
;
Statements:
code+=Statement*
;
Statement:
LocalVariableDeclaration |
PrimaryStatement |
IfStatement |
CaseStatement |
WhileStatement |
ForStatement |
RepeatStatement |
LoopStatement |
WhenStatement |
TillStatement |
WithStatement |
';'
;
LocalVariableDeclaration:
VAR var=VarNameAndType (':=' initial=Expression)? ';'
;
PrimaryStatement:
{Assignment} target=Assignable ":=" val=Expression ';' |
{Call} action=[ActionName] '(' params=ActualParamList ')' ';' |
{Create} CREATE name=AgentName OF caste=[CasteName] '(' params=ActualParamList ')'
(FROM ceIp=Expression)? (AT leeIp=Expression)? |
{Super} SUPER ( params=ActualParamList ) |
{Join} JOIN (caste=[CasteName]) '(' params=ActualParamList ')' |
{Suspend} SUSPEND (caste=[CasteName]) |
{Resume} RESUME (caste=[CasteName]) |
{Quit} QUIT (caste=[CasteName])
;
IfStatement:
IF '(' condition=Expression ')' '{' trueBranch=Statements '}'
(=> ELSE '{' falseBranch=Statements '}' )
;
CaseStatement:
CASE '(' condition=Expression ')' '{'
((matches+=Expression) '->' '{' (bodies+=Statements) '}')+
(ELSE '{' (elseBody=Statements) '}')?
'}'
;
WhileStatement:
WHILE '(' condition=Expression ')' '{' (body=Statements) '}'
;
RepeatStatement:
REPEAT '{' (body=Statements) '}' UNTIL '(' condition=Expression ')'
;
LoopStatement:
LOOP '{' body=Statements '}'
;
ForStatement:
FOR (var=[VarName] | VAR newVar=VarName)
((":=" startValue=ExpAdditive TO endValue=ExpAdditive) |
(IN forList=Expression))
'{' body=Statements '}'
;
WithStatement:
WITH '(' (var=[VarName] | VAR newVar=VarName) '=' (old=Expression) ')' '{' body=Statements '}'
;
WhenStatement:
WHEN EventExpression '{' body=Statements '}'
;
TillStatement:
TILL EventExpression '{' body=Statements '}'
;
EventExpression:
EXIST (agent=VarName) IN (caste=[CasteName]) |
((agent=VarName) | SELF) ':' (action=ActionName) '(' params=ActualParamList? ')'
;
Assignable: {Operation} left=AssField ('[' index=Expression ']')?;
AssField: {Operation} left=AssPrimary ('.' field=[FieldName])?;
AssPrimary: var=[VarName] ;
// Herewith the joy of left factored operators with priority
Expression: ExpBinOr;
ExpBinOr: {Operation} left=ExpBinAnd (ops+='||' rights+=ExpBinAnd)*;
ExpBinAnd: {Operation} left=ExpEquality (ops+='&&' rights+=ExpEquality)*;
ExpEquality: {Operation} left=ExpRelational (ops+=('==' | '!=') rights+=ExpRelational)*;
ExpRelational: {Operation} left=ExpAdditive (ops+=('<' | '>' | '<=' | '=>') rights+=ExpAdditive)*;
ExpAdditive: {Operation} left=ExpMulti (ops+=('+' | '-') rights+=ExpMulti)*;
ExpMulti: {Operation} left=ExpUnary (ops+=("*" | "/" | "%") right+=ExpUnary)*;
ExpUnary: {Operation} op=("!" | "-" | "+")? left=ExpElement ;
ExpElement: {Operation} left=ExpField ('[' index=Expression ']')?;
ExpField: {Operation} left=ExpPrimary ('.' field=[FieldName])?;
ExpPrimary: literal=Literal | var=[VarName] ('#' state=[VarName] ) ;
Literal:
{StringLiteral} string=STRING |
{IntLiteral} int=INT |
{BoolLiteral} bool=BOOL |
{RealLiteral} real=RealLiteral |
{StructLiteral} struct=StructuredLiteral |
{EnumLiteral} enumValue=[EnumValue]
;
RealLiteral returns ecore::EDouble:
INT '.' INT
;
StructuredLiteral:
type=[TypeName] ':' (list=ListLiteral | struct=StructLiteral)
;
ListLiteral:
'[' members+=Literal (',' members+=Literal)* ']'
;
StructLiteral:
'{' fields+=[FieldName] ':' values+=Literal (',' fields+=[FieldName] ':' values+=Literal)* '}'
;
StateExpression:
agent=[VarName] '#' state=[VarName]
;
enum BOOL:
TRUE='true' | TRUE='True' | TRUE='TRUE' |
FALSE='false' | FALSE='False' | FALSE='FALSE'
;
ScopeType:
ONLY | SOME | ALL
;
FormalParamList:
params+=VarNameAndType (',' params+=VarNameAndType)*
;
ActualParamList:
params+=Expression (',' params+=Expression)*
;
VarNameAndType:
name=VarName ':' type=Type
;
FieldNameAndType:
name=FieldName ':' type=Type
;
Type:
TYPE_INTEGER |
TYPE_REAL |
TYPE_BOOL |
TYPE_STRING |
AGENT ('{' agent=[CasteName | ID] '}' ) |
type=[TypeName | ID] |
structDef |
listDef |
enumDef
;
structDef:
STRUCT '{'
((fields+=FieldNameAndType) ';')+
'}'
;
listDef:
LIST '{' elementType=Type '}'
;
enumDef:
ENUM '{' enumValues+=EnumValue ( ',' enumValues+=EnumValue )* '}'
;
// Identifier types for contextual inference
CasteName:
name=ID
;
TypeName:
name=ID
;
EnumValue:
name=ID
;
VarName:
name=ID
;
FieldName:
name=ID
;
ActionName:
name=ID
;
AgentName:
name=ID
;
terminal CASTE : "caste" | "Caste" | "CASTE";
terminal AGENT : "agent" | "Agent" | "AGENT";
terminal EXTEND : "extend" | "Extend" | "EXTEND";
terminal TYPE_INTEGER : "int" | "Int" | "INT";
terminal TYPE_REAL : "real" | "Real" | "REAL";
terminal TYPE_BOOL : "bool" | "Bool" | "BOOL";
terminal TYPE_STRING : "string" | "String" | "STRING";
// terminal TYPE_AGENT : "agent" | "Agent" | "AGENT";
terminal IMPORT : "import" | "Import" | "IMPORT";
terminal USES : "uses" | "Uses" | "USES";
terminal STRUCT : "struct" | "Struct" | "STRUCT";
terminal LIST : "list" | "List" | "LIST";
terminal ENUM : "enum" | "Enum" | "ENUM";
terminal OBSERVE : "observe" | "Observe" | "OBSERVE";
terminal ONLY : "only" | "Only" | "ONLY";
terminal SOME : "some" | "Some" | "SOME";
terminal ALL : "all" | "All" | "ALL";
terminal IN : "in" | "In" | "IN";
terminal STATE : "state" | "State" | "STATE";
terminal VAR : "var" | "Var" | "VAR";
terminal ACTION : "action" | "Action" | "ACTION";
terminal INTERNAL : "internal" | "Internal" | "INTERNAL";
terminal INIT : "init" | "Init" | "INIT";
terminal BODY : "body" | "Body" | "BODY";
terminal IF : "if" | "If" | "IF";
terminal ELSE : "else" | "Else" | "ELSE";
terminal CASE : "case" | "Case" | "CASE";
terminal WHILE : "while" | "While" | "WHILE";
terminal REPEAT : "repeat" | "Repeat" | "REPEAT";
terminal UNTIL : "until" | "Until" | "UNTIL";
terminal LOOP : "loop" | "Loop" | "LOOP";
terminal FOR : "for" | "For" | "FOR";
terminal TO : "to" | "To" | "TO";
terminal WITH : "with" | "With" | "WITH";
terminal WHEN : "when" | "When" | "WHEN";
terminal TILL : "till" | "Till" | "TILL";
terminal EXIST : "exist" | "Exist" | "EXIST";
terminal SELF : "self" | "Self" | "SELF";
terminal CREATE : "create" | "Create" | "CREATE";
terminal OF : "of" | "Of" | "OF" ;
terminal FROM: 'from' | "From" | "FROM" ;
terminal AT: 'at' | "At" | "AT" ;
terminal SUPER: "super" | "Super" | "SUPER";
terminal JOIN: "join" | "Join" | "JOIN" ;
terminal SUSPEND: "suspend" | "Suspend" | "SUSPEND" ;
terminal RESUME: "resume" | "Resume" | "RESUME" ;
terminal QUIT: "quit" | "Quit" | "QUIT" ;
// WS, ID, and INT are defined by the Xtext standard terminals
Scope Provider:
class CaopleScopeProvider extends AbstractCaopleScopeProvider {
def GetScope(EObject context, EReference reference) {
if (context instanceof CasteName) {
// Caste names only come from two places: the uses clause, and the definition
// itself.
val rootElement = EcoreUtil2.getRootContainer(context)
val usesElements = EcoreUtil2.getAllContentsOfType(rootElement, UsesClause)
val usedCasteNames = new ArrayList<CasteName>
usesElements.forEach([UsesClause ue | usedCasteNames.addAll(EcoreUtil2.getAllContentsOfType(ue, CasteName))]);
val casteDefinitions = EcoreUtil2.getAllContentsOfType(rootElement, CasteDeclaration)
casteDefinitions.forEach([CasteDeclaration cd | usedCasteNames.add(cd.castename)]);
return Scopes.scopeFor(usedCasteNames);
}
if (context instanceof VarName) {
// Work up through containers.
val varsInScope = new ArrayList<VarName>
var currentContainer = reference.eContainer
while (currentContainer !== null) {
switch currentContainer {
ForStatement:
if (currentContainer.newVar !== null) varsInScope.add(currentContainer.newVar)
WithStatement:
if (currentContainer.newVar !== null) varsInScope.add(currentContainer.newVar)
Statements: {
val locals = EcoreUtil2.getAllContentsOfType(currentContainer, LocalVariableDeclaration)
locals.forEach([local | varsInScope.add(local.getVar().name)])
}
CasteDeclaration: {
val globals = EcoreUtil2.getAllContentsOfType(currentContainer, VarDeclaration)
globals.forEach([global | varsInScope.add(global.getVar().name)])
}
}
currentContainer = currentContainer.eContainer
}
return Scopes.scopeFor(varsInScope)
}
}
}
|
|
|
Re: Help debugging a scope provider [message #1765975 is a reply to message #1765969] |
Wed, 14 June 2017 12:15   |
Eclipse User |
|
|
|
Hi, the scope provider naming looks bad to me should be
override getScope(EObject context, EReference reference) {
if (...) {
return ....
}
return IScope.NULLSCOPE // or super.getScope(context, reference)
}
then reference you scope looks like
AssPrimary: var=[VarName] ;
=> you actually reference a VarName
AssPrimary: var=[VarName] ;
=> your if/else are wrong
the context is where you are, the reference is where you point to
=> maybe
override getScope(EObject context, EReference reference) {
if (reference.EType == MyDslPackage.Literals.CASTE_NAME) {
// Caste names only come from two places: the uses clause, and the definition
// itself.
val rootElement = EcoreUtil2.getRootContainer(context)
val usesElements = EcoreUtil2.getAllContentsOfType(rootElement, UsesClause)
val usedCasteNames = new ArrayList<CasteName>
usesElements.forEach([UsesClause ue | usedCasteNames.addAll(EcoreUtil2.getAllContentsOfType(ue, CasteName))]);
val casteDefinitions = EcoreUtil2.getAllContentsOfType(rootElement, CasteDeclaration)
casteDefinitions.forEach([CasteDeclaration cd | usedCasteNames.add(cd.castename)]);
return Scopes.scopeFor(usedCasteNames);
}
if (reference == MyDslPackage.Literals.ASS_PRIMARY__VAR) {
// Work up through containers.
val varsInScope = new ArrayList<VarName>
var currentContainer = context.eContainer
while (currentContainer !== null) {
switch currentContainer {
ForStatement:
if (currentContainer.newVar !== null) varsInScope.add(currentContainer.newVar)
WithStatement:
if (currentContainer.newVar !== null) varsInScope.add(currentContainer.newVar)
Statements: {
val locals = EcoreUtil2.getAllContentsOfType(currentContainer, LocalVariableDeclaration)
locals.forEach([local | varsInScope.add(local.getVar().name)])
}
CasteDeclaration: {
val globals = EcoreUtil2.getAllContentsOfType(currentContainer, VarDeclaration)
globals.forEach([global | varsInScope.add(global.getVar().name)])
}
}
currentContainer = currentContainer.eContainer
}
return Scopes.scopeFor(varsInScope)
}
//maybe super.getScope(context, reference)
return IScope.NULLSCOPE
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|