|
|
Re: Help debugging a scope provider [message #1765931 is a reply to message #1765930] |
Wed, 14 June 2017 13:51 |
|
another point:
var currentContainer = reference.eContainer
while (currentContainer !== null) {
walks up to the root
=> everything i a child of that root
=>
CasteDeclaration: {
val globals = EcoreUtil2.getAllContentsOfType(currentContainer,
VarDeclaration)
globals.forEach([global | varsInScope.add(global.getVar().name)])
will find everything
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
Re: Help debugging a scope provider [message #1765953 is a reply to message #1765951] |
Wed, 14 June 2017 14:55 |
|
what i understand
- caste is the root
- it has vars (the one you are searching for)
- and it has ActionDeclaration. which have vars.
=> caste.getAllContentsOfType will give you the vars it directly has and the vars of its actions
=> camel is a grand child of caste Moose
=> it is visible inside Sheep and inside pig
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
Re: Help debugging a scope provider [message #1765960 is a reply to message #1765953] |
Wed, 14 June 2017 15:26 |
Mark Green Messages: 37 Registered: June 2017 |
Member |
|
|
Quote:- caste is the root
- it has vars (the one you are searching for)
- and it has ActionDeclaration. which have vars.
ActionDeclaration:
internal?=INTERNAL? ACTION name=ActionName '(' params=FormalParamList ')' '{' body=Statements '}'
;
ActionDeclaration has vars, but they are inside the Statements block.
In the context of Statements the DSL VAR keyword matches the rule LocalVariableDeclaration, not VarDeclaration.
Therefore, ActionDeclaration should have no child or grandchild VarDeclarations, only LocalVariableDeclarations (I have confirmed this in the outline).
Therefore the LocalVariableDeclarations inside Action should not be found when getting all VarDeclarations on the Caste, because they are not VarDeclarations, they are LocalVariableDeclarations.
[Updated on: Wed, 14 June 2017 15:30] Report message to a moderator
|
|
|
|
Re: Help debugging a scope provider [message #1765963 is a reply to message #1765961] |
Wed, 14 June 2017 15:44 |
Mark Green Messages: 37 Registered: June 2017 |
Member |
|
|
I haven't ever written super.getScope() myself, is it used internally somewhere?
As for scoping VarNames, my understanding is that the Context object is where in the parse tree the reference was found, is that right? So if a VarName is in say, an assignment statement, it will work out from that assignment looking for LocalVariableDeclarations in surrounding Statements or VarDeclarations in surrounding Castes.
What I am hoping it will do is:
Camel := 3
- VarName Reference Camel
-> In AssPrimary in AssField in Assignable in Assignment in PrimaryStatement Camel := 3
-> In Statements (body of Sheep) which also contains LocalVariableDeclaration Camel which is added to the list
-> In ActionDeclaration
-> In CasteDeclaration Moose which has no VarDeclarations
Therefore Camel in scope because it was found in the Statements.
Camel := 2
- Varname Reference Camel
-> In AssPrimary in AssField in Assignable in Assignment in PrimaryStatement Camel := 2
-> In Statements (body of Pig) which has no LocalVariableDeclarations
-> In ActionDeclaration
-> In CasteDeclaration Moose which has no VarDeclarations
Therefore not in scope because the list of possible variables is empty.
VarName is internally referred to in LocalVariableDeclaration and VarDeclaration but has no reference brackets in those contexts so I presume does not trigger scope checking?
[Updated on: Wed, 14 June 2017 15:47] Report message to a moderator
|
|
|
|
|
Re: Help debugging a scope provider [message #1765969 is a reply to message #1765965] |
Wed, 14 June 2017 15:55 |
Mark Green Messages: 37 Registered: June 2017 |
Member |
|
|
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 16:15 |
|
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
}
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
Re: Help debugging a scope provider [message #1765976 is a reply to message #1765975] |
Wed, 14 June 2017 16:20 |
Mark Green Messages: 37 Registered: June 2017 |
Member |
|
|
Could you explain that about the reference a bit more? "The reference is where you point to" but if we still need to determine what is in scope, how can the parser know what it points to (since it would need to point to something in scope)?
At the moment I don't understand this line
if (reference == MyDslPackage.Literals.ASS_PRIMARY__VAR) {
At all, AssPrimary's Var feature is not a Literal, and why would the reference be equal to this? Would a different variable reference be equal to the same thing? Also this typing should be applied to variables used in any expression not just assignments (although the test was on assignments)
Edit: Also unfortunately the code above did not fix the problem.
[Updated on: Wed, 14 June 2017 16:29] Report message to a moderator
|
|
|
Re: Help debugging a scope provider [message #1765977 is a reply to message #1765976] |
Wed, 14 June 2017 16:32 |
|
xtext derives a ecore metamodel from your grammar.
in my case
generate myDsl "http://www.xtext.org/example/mydsl3/MyDsl"
AssPrimary: var=[VarName] ;
and emf generates contstants for classes, attributes and references
=> package = MyDslPackage (in your case caoplePackage)
inside the inner interface literals are the constants.
the are like <TyoeName>__<refname>
so
ASS_PRIMARY__VAR
or
reference.EType == MyDslPackage.Literals.CASTE_NAME if you want to know what type the name is of (EReference.EType)
when xtext calls scope it says:
here is my context. this the the object in the ast where i am at
and here is the EReference (the xxx=[]) thingy that i am currently scoping
=> you need to file out where you are and what you scope (if else in the scope method)
and then collect the stuff
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
|
Re: Help debugging a scope provider [message #1765987 is a reply to message #1765985] |
Wed, 14 June 2017 17:20 |
|
yes context.eClass() == reference.eContainer is correct if you leave type inhertiance out of the play
EClass is a Prototype of an EObject
it has EAttributes and EReferences that describe values (EAttribute) and complex values/objects (EReference with containmaint=true) and cross references (EReference with containmaint=false)
An EObject and its values are instances of these prototypes
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
|
|
|
|
Re: Help debugging a scope provider [message #1765999 is a reply to message #1765998] |
Wed, 14 June 2017 17:46 |
|
c2 is not a reference
Thing: "t" name=ID "{" children=Child+ "}";
Child: name=ID ("ref" ref=[Child])?
EClass: Thing, Child
EAttribute: Thing__Name, Child__Name
EReference(Containment): Thing__Children
EReference(Non COntainment/Reference): Child__Ref
Child__Ref.eContainer ==Child
Thing__Children.eContainer == Thing
u do use eContainer in 99,9999999999999% only for EObject, not for eAttribtues or EReferences
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
|
|
|
|
|
|
|
|
|
|
|
Re: Help debugging a scope provider [message #1766141 is a reply to message #1766038] |
Fri, 16 June 2017 12:00 |
Mark Green Messages: 37 Registered: June 2017 |
Member |
|
|
Hi:
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]
;
EnumValue:
name=ID
;
VarName:
name=ID
;
ExpPrimary => VarName => ID and ExpPrimary => Literal => EnumValue => ID both end up reducing to ID. Is there a way to tell XText, "if a reference to an EnumValue is not found, then this reference parser rule doesn't match, so try an alternative parser rule, ie a VarName reference?" Because at the moment the parser generates an error whenever a VarName is used in a PrimaryExp context saying that it is a missing EnumValue.
[Updated on: Fri, 16 June 2017 12:00] Report message to a moderator
|
|
|
|
|
|
|
|
|