terminal NAME : expression ;
EX: 'foo', "\foo", '"', "'"
EX: .
EX: ID
EX: 'a'..'z', 'A'..'Z', '0'..'9'
EX: '/*' -> '*/'
EX: !'a'
EX: '^'?, '\n'*, 'a'+
EX: 'a' . ID
EX: ' ' | '\t' | '\r' | '\n'
EX: 'a' & ID*
grammar org.example.domainmodel.Domainmodel with
org.eclipse.xtext.common.Terminals
generate domainmodel "http://www.example.org/domainmodel/Domainmodel"
Domainmodel :
elements += Type*
;
Type:
DataType | Entity
;
DataType:
'datatype' name = ID
;
Entity:
'entity' name = ID ('extends' superType = [Entity])? '{'
features += Feature*
'}'
;
Feature:
many?='many'? name = ID ':' type = [Type]
;
...
WebAppSetup:
'webapp' (name=ID)? '{'
(global=Global)?
(pages+=Page)+
('actions' definedGlobalAction+=ActionElement)*
'}';
Page:
'page' name=ID ('path' path=STRING)? '{'
('input' input+=InputElement (','input+=InputElement)*)?
('view' view+=ViewElement (','view+=ViewElement)*)?
('action' action+=ActionElement (','action+=ActionElement)*)?
'}';
Global:
'global' '{'
('loaderElement' loader=Loader)?
('input' definedGlobalInputs+=InputElement (','definedGlobalInputs+=InputElement)*)?
('view' definedGlobalViews+=ViewElement (','definedGlobalViews+=ViewElement)*)?
('action' definedGlobalActions+=ActionElement (','definedGlobalActions+=ActionElement)*)?
'}';
Loader: view=ViewElement;
ViewElement: type=ViewType name=ID 'selector =' selector=Selector ;
enum ViewType: ELEMENT ='element';
ActionElement: type=ActionType name=ID 'selector =' selector=Selector ;
enum ActionType: CLICK = 'click' ;
terminal ID: '^'?('a'..'z'|'A'..'Z'|'_'|':') ('a'..'z'|'-'|'A'..'Z'|'_'|'0'..'9'|':')*;
terminal INT returns ecore::EInt: ('-')?('0'..'9')+;
...
class MyGenerator implements IGenerator {
//add extension
@Inject extension anotherGenerator
..
}
class MyDslGenerator implements IGenerator {
override void doGenerate(Resource resource, IFileSystemAccess fsa) {
fsa.generateFile(resource.className+".java", toJavaCode(resource.contents.head as Statemachine))
}
def className(Resource res) {
var name = res.URI.lastSegment
name.substring(0, name.indexOf('.'))
}
def toJavaCode(Statemachine sm) '''
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class «sm.eResource.className» {
public static void main(String[] args) {
new «sm.eResource.className»().run();
}
...
}
def dispatch void infer(Statemachine stm,
IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
// create exactly one Java class per state machine
acceptor.accept(stm.toClass(stm.className)).initializeLater [
// add a field for each service annotated with @Inject
members += stm.services.map[service|
service.toField(service.name, service.type) [
annotations += service.toAnnotation(typeof(Inject))
]
]
// generate a method for each state having an action block
members += stm.states.filter[action!=null].map[state|
state.toMethod('do'+state.name.toFirstUpper, state.newTypeRef(Void::TYPE)) [
visibility = PROTECTED
// Associate the expression with the body of this method.
body = state.action
]
]
// generate a method containing the actual state machine code
members += stm.toMethod("run", newTypeRef(Void::TYPE)) [
// the run method has one parameter : an event source of type Provider
val eventProvider = stm.newTypeRef(typeof(Provider), stm.newTypeRef(typeof(String)))
parameters += stm.toParameter("eventSource", eventProvider)
// generate the body
body = [append('''
boolean executeActions = true;
...
}
@RunWith(XtextRunner.class)
@InjectWith(AppSetupInjectorProvider.class)
public class WebAppSetupModelTest {
@Inject
ParseHelper parseHelper;
/**
* Empty models should result in a null model
*/
@Test
public void testEmptyModel() throws Exception {
StringBuilder modelString = new StringBuilder();
modelString.append("");
WebAppSetup model = parseHelper.parse(modelString);
assertNull("Model is not empty", model);
}
@Test
public void testModelAccept() throws Exception {
StringBuilder modelString = new StringBuilder();
modelString.append("webapp ea { ");
modelString.append(" global {");
modelString.append(" loaderElement element loader selector = #ajax-loader");
modelString.append(" action click next selector = #gotoNext");
modelString.append(" }");
modelString.append("");
modelString.append(" page login path \"/faces/pages/login/login.xhtml\" {");
modelString.append(" input type user selector = #login_input,");
modelString.append(" type password selector = #password ");
modelString.append(" action click login selector = #login_submit ");
modelString.append(" }");
modelString.append("}");
WebAppSetup model = parseHelper.parse(modelString);
assertNotNull("Model is null. ", model);
assertTrue("Expected 'loader' as name for global loader element, but was "
+ model.getGlobal().getLoader().getView().getName(),
model.getGlobal().getLoader().getView().getName().equalsIgnoreCase("loader"));
assertTrue("Expected only one page, but was " + model.getPages().size(), model.getPages().size() == 1);
}
}
docs
examples
->sample
features
->org.xtext.feature
releng
->org.xtext.parent
->org.xtext.product
->org.xtext.repository
->org.xtext.repository.parent
->org.xtext.targetplattform
->org.xtext.updatesite
plugins
->org.xtext.mysql1
->org.xtext.mydsl1.ui
->org.xtext.mysql2
->org.xtext.mydsl2.ui
tests
->org.xtext.mydsl1.tests
->org.xtext.mydsl2.tests