简体   繁体   中英

Xtext grammar with either reference to instance or literal value

I am trying to model an XML based macros

<macro name="dummy" parameters="elemName elemValue">
    <element name=${elemName} /> <!--reference to parameter elemName-->
    <element name="elem1" />
    <anotherElement name="elem2" value=6 />
    <anotherElement name="elem3" value=${elemValue} />
</macro>

Later this macro will be instantiated:

<dummy elemName="elem0" elemValue=3 />

But before I can model the macro, I trying assign either a value (string / integer) or reference of parameter to the element attributes

This is the Xtext grammar I have got so far

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
import "http://www.eclipse.org/emf/2003/XMLType" as type

Model:
    parameters+=Parameter*
    intParameters+=IntParameter*
    elements+=Element*
    otherElements+=AnotherElement*
    ;

Parameter returns Parameter:
    StringParameter | IntParameter
;

StringParameter returns StringParameter:
    {StringParameter}
    'StringParameter'
    name=EString
    '{'
        ('value' value=EString)?
    '}';
    
IntParameter returns IntParameter:
    {IntParameter}
    'IntParameter'
    name=EString
    '{'
        ('value' value=DECINT)?
    '}';

Element returns Element:
    'Element'
    '{'
        'name' name=[StringParameter|EString]
    '}';
    
AnotherElement returns AnotherElement:
    'AnotherElement'
    '{'
        'value' value=[IntParameter|EString]
    '}';

EString returns ecore::EString:
    STRING | ID;
    
terminal fragment DIGIT: '0'..'9';
terminal DECINT: '0' | ('1'..'9' DIGIT*) | ('-''0'..'9' DIGIT*) ;

The above grammar allows only for references to existing parameters. How can I assign values directly to the elements?

StringParameter test { value "hello" }
IntParameter dummy { value 4 }

Element { name test } // works 
Element { name blah } // ERROR: Couldn't resolve reference to StringParameter 'blah'.   

AnotherElement { value dummy } // works
AnotherElement { value 7 } // ERROR: no viable alternative at input '7'
                           // ERROR: Couldn't resolve reference to IntParameter '7'.

Edit 1: Based on the example in Xtext grammar variable definition/reference , I modified 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:
    parameters+=StringParameter*
    elements+=Element*;

Element returns Element:
    'Element'
    '{'
        'name' value=StringValue
    '}';

StringValue:
    StringLiteral | StringRefParameter;

StringRefParameter:
    ref=[StringParameter|EString];

StringLiteral:
    value=EString;

StringParameter returns StringParameter:
    {StringParameter}
    'StringParameter'
    name=EString
    '{'
        ('value' value=EString)?
    '}';

EString returns ecore::EString:
    STRING | ID;

But the generator fails

1212 [main] INFO  text.xtext.generator.XtextGenerator  - Generating common infrastructure
1237 [main] ERROR mf.mwe2.launch.runtime.Mwe2Launcher  - Problems running workflow org.xtext.example.mydsl.GenerateMyDsl: 
[ERROR]: GeneratorException: (Element: -UNKNOWN-; Reported by: XtextGenerator)
     org.eclipse.xtext.util.RuntimeIOException: java.io.FileNotFoundException: /home/user/ws/org.xtext.example.mydsl/../org.xtext.example.mydsl/src-gen/org/xtext/example/mydsl/parser/antlr/internal/InternalMyDslLexer.java (No such file or directory)

Edit 2: The grammar works for integers

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:
    parameters+=IntParameter*
    elements+=Element*
    ;

Element returns Element:
    'Element'
    '{'
        'name' value=IntValue
    '}';

IntValue:
    ref=[IntParameter] | value=DECINT
;

IntParameter returns IntParameter:
    {IntParameter}
    'IntParameter'
    name=EString
    '{'
        ('value' value=DECINT)?
    '}';

EString returns ecore::EString:
    STRING | ID;
    
terminal fragment DIGIT: '0'..'9';
terminal DECINT: '0' | ('1'..'9' DIGIT*) | ('-''0'..'9' DIGIT*) ;

and the following code is valid

IntParameter dummy { value 4 }

Element { name dummy }
Element { name 5 }

Any ideas how could it work for strings?

By changing StringValue from

StringValue:
    ref=[StringParameter|EString] | value=EString

to

StringValue:
    ref=[StringParameter] | value=EString

works for me. The grammar now looks like:

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:
    stringParameters+=StringParameter*
    elements+=Element*
    ;

Element returns Element:
    'Element'
    '{'
        'name' value=StringValue
    '}';

StringValue:
    ref=[StringParameter] | value=EString
;

StringParameter returns StringParameter:
    {StringParameter}
    'StringParameter'
    name=EString
    '{'
        ('value' value=EString)?
    '}';

EString returns ecore::EString:
    STRING | ID;

And the code is

StringParameter test { value hello }

Element { name "world" }
Element { name test }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM