mr.VVoo
mr.VVoo

Reputation: 2270

How to allow a modifier only once for multiple elements in Xtext Grammar?

I want to create the following DSL

namespace x.y.z
system <NAME> {
    component A { ... }
    component B { ... }
    coordinator component C { ... }
    component D { ... }
}

All component's have the same structure except that one and only one requires a coordinator modifier.

By now I tried two different grammars:

System:
    'system' name=ValidID '{'
        (coordinatorComponent=CoordinatorComponent) & 
        (components+=NonCoordinatorComponent*) & 
        (constraints=ComponentConstraints)?
    '}'
;

ComponentConstraints:
    'constraints' '{}'
;

CoordinatorComponent:
    'coordinator' 'component' {Component}
;

NonCoordinatorComponent:
    'component' {Component};

Component:
    name=ValidID '{'
        features+=Feature*
    '}'
;

and the same one with slight changes

CoordinatorComponent:
    'coordinator' {Component}
;

NonCoordinatorComponent:
    {Component};

Component:
    'component' name=ValidID '{'
        features+=Feature*
    '}'
;

The first one results in an error rule ruleSystem failed predicate: {getUnorderedGroupHelper().canLeave(grammarAccess.getSystemAccess().getUnorderedGroup())}? in the editor when writing the DSL (not the grammar).

The second one works but still I think it is weird because it is not really using a modifier but a whole new type. Is there a better way to define Component in general and using a modifier which MUST be used exactly once within System?

Upvotes: 0

Views: 78

Answers (1)

Christian Dietrich
Christian Dietrich

Reputation: 11868

what about using parser fragments

System:
    'system' name=ValidID '{'
        ((coordinatorComponent=CoordinatorComponent) & 
        (components+=NonCoordinatorComponent*) & 
        (constraints=ComponentConstraints)?)
    '}'
;

ComponentConstraints:
    'constraints' '{}'
;

CoordinatorComponent:
    'coordinator' 'component' Component
;

NonCoordinatorComponent:
    'component' Component;

fragment Component:
    name=ValidID '{'
        features+=Feature*
    '}'
;

Upvotes: 1

Related Questions