xtext - Couldn't resolve reference to

2019-08-18 05:51发布

问题:

I have the following grammar:

Model: prog+=Program*;

Program: g=Greeting  de+=DataEntry* s+=Statement*;

Greeting: 'Hello' t=ProgPara '!';

ProgPara: 'PROGRAM'  pname=Progname ';';

Progname : name=ID;

DataEntry:  a=INT v=Varname ';';   

Varname : name = ID;

Statement: (c=CopyStmt|m=MoveStmt) ';';

CopyStmt: 'COPY' 'TO' qname=[IndexVarname|ID] ;

IndexVarname : (Indexname|Varname);   

Indexname : '(' name = ID ')';

MoveStmt: 'MOVE' 'TO' p=[PrVarName|ID];

PrVarName : (Varname|Progname);

But it throws error for:

PrVarName : (Varname|Progname);

So i modified the grammar to have as below:

PrVarName : (v=Varname|Progname);

I updated the Scope provider as below:

override getScope(EObject context, EReference reference) {
    if (context instanceof CopyStmt) {
        if (reference.featureID == TestDslPackage.COPY_STMT__QNAME) {
            val rootElement = EcoreUtil2.getRootContainer(context);
            val candidates1 = EcoreUtil2.getAllContentsOfType(rootElement, Indexname);
            val candidates2 = EcoreUtil2.getAllContentsOfType(rootElement, Varname);
            val candidates = candidates1 + candidates2;

            return Scopes.scopeFor(candidates);
        }
    } else if (context instanceof MoveStmt) {
        if (reference.featureID == TestDslPackage.MOVE_STMT__P) {
            val rootElement = EcoreUtil2.getRootContainer(context);
            val candidates1 = EcoreUtil2.getAllContentsOfType(rootElement, Progname);
            val candidates2 = EcoreUtil2.getAllContentsOfType(rootElement, Varname);
            val candidates = candidates1 + candidates2;

            return Scopes.scopeFor(candidates);
        }
    }       
}

Once the grammar was built and i ran the below test case, it is throwing error in the MOVE statement saying "Couldn't resolve reference to PrVarName 'test1'."

Hello PROGRAM test;!

1 test1;
2 test2;
3 test3;

COPY TO test2;
MOVE TO test1;

Looks like i cannot use Varname in two different cross references. But there is a very valid need for it. How do I achieve this?

Thanks in advance.

回答1:

PrVarName : p=(Progname|Varname);

is bad cause it changes the type hierarchy. Progname and Varname are no longer subtypes of PrVarName. By reverting the change and introducing a common Named supertype you can resolve this

Model:
    prog+=Program*;

Program:
    g=Greeting de+=DataEntry* s+=Statement*;

Greeting:
    'Hello' t=ProgPara '!';

ProgPara:
    'PROGRAM' pname=Progname ';';

DataEntry:
    a=INT (v=Varname | in=Indexname) ';';

Statement:
    (c=CopyStmt | m=MoveStmt) ';';

CopyStmt:
    'COPY' 'TO' qname=[IndexVarname|ID];

MoveStmt:
    'MOVE' 'TO' p=[PrVarName|ID];

PrVarName:
    Progname | Varname;

IndexVarname:
    (Indexname | Varname);

Named:Progname|Indexname|Varname;   

Progname:
    {Progname} name=ID; 

Indexname:
    {Indexname}'(' name=ID ')';

Varname:
    {Varame}name=ID;