问题
I would like to create an incredibly simple DSL using xtext, with the following features:
- It will have two primitive types: Number and String
- Users can define their own classes, which are composed of field declarations
- A field declaration associates a name with a type, where a type can be a class or a primitive
The following is my attempt at a DSL, the class definition and references work fine, but I cannot figure out how to have primitive types. The 'String' and 'Number' literals are not working:
Model:
(classes+=Class)*
(fields+=Field)*;
FieldType: Class | 'String' | 'Number';
Field:
type=[FieldType] name=ID ";";
Class:
"class" name=ID
"{"
(fields+=Field)*
"}";
Here is an example I expect to be valid against the above DSL:
Class SomeClass {
}
// This works!
SomeClass reference;
// This does not, doesn't recognise the "String" literal
String string;
Note that further down the line I will be supporting assignment. Thus my DSL will need to incorporate the concept of number / string literals, such that it supports Number someNumber = 123;
回答1:
Having slept on it, I think the right answer is to change my approach. In the above definition we have
Field:
type=[FieldType] name=ID ";";
This defines a rule called "Field" which is made up of two parts; the "type" and the "name". It is the type part that is presenting the issue. The square brackets denote we are expecting an instance of FieldType
, which is:
FieldType: Class | 'String' | 'Number';
Now, it's clear to see that you can have an instance of class, but semantically there's no way to have an instance of the 'String' or 'Number' Literals.
I believe this to be why my DSL above won't let me declare the primitives. The String/Number "types" simply aren't elements that you can have an instance of.
Thinking further, there are some very important distinctions between the definitions of fields that are primitive vs. those which are instances of a class. For example, you can only invoke methods on instances of a class (in my case I am treating String as a true primitive, so no methods).
Thus, it's probably important to have two different type of declarations, one for PrimitiveField
and one for ObjectField
. A field can be either of these:
Model:
(classes+=Class)*
(fields+=Field)*;
PrimitiveType: 'String' | 'Number' | 'Boolean';
Field:
PrimitiveField | ObjectField
;
PrimitiveField:
type=PrimitiveType name=ID ";"
;
ObjectField:
type=[Class] name=ID ";";
Class:
"class" name=ID
"{"
(fields+=Field)*
(methods+=Method)*
"}";
来源:https://stackoverflow.com/questions/19460519/defining-primitives-within-xtext-grammar