Created
September 22, 2015 07:39
-
-
Save svenefftinge/4f8259049088a5c55969 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Part 1 | |
org.xtext.homeautomation | |
// To Be Parsed | |
Device Window can be OPEN, CLOSED | |
Device Heating can be ON, OFF | |
Rule 'Close Window, when heating turned on' | |
when Heating.ON | |
then Window.CLOSED | |
Rule 'Switch off heating, when windows gets opened' | |
when Window.OPEN | |
then Heating.OFF | |
// Grammar | |
Model: | |
declarations+=Declaration* | |
; | |
Declaration : | |
Device | Rule | |
; | |
Device : | |
'Device' name=ID 'can' 'be' | |
(states+=State (',' states+=State)*)? | |
; | |
State : | |
name=ID | |
; | |
Rule: | |
'Rule' description=STRING | |
'when' when=[State|QualifiedName] | |
'then' then=[State|QualifiedName]; | |
QualifiedName : ID ('.' ID)*; | |
// Test | |
@Inject extension ParseHelper<Model> | |
@Inject ValidationTestHelper validator | |
@Inject IGenerator generator | |
@Test def void testSimpleFile() { | |
val model = ''' | |
Device Window can be opened, closed | |
Device Heating can be on, off | |
Rule 'Close the window when the heating is on' | |
when Heating.on | |
then Window.closed | |
Rule 'Turn off heating when window gets opened' | |
when Window.opened | |
then Heating.off | |
'''.parse | |
validator.assertNoErrors(model) | |
val fsa = new InMemoryFileSystemAccess | |
generator.doGenerate(model.eResource, fsa) | |
fsa.allFiles.values.head.toString.contains(''' | |
public static void fire(String event) { | |
if (event.equals("opened")) { | |
System.out.println("Window is now opened!"); | |
} | |
if (event.equals("closed")) { | |
System.out.println("Window is now closed!"); | |
} | |
if (event.equals("on")) { | |
System.out.println("Heating is now on!"); | |
} | |
if (event.equals("off")) { | |
System.out.println("Heating is now off!"); | |
} | |
if (event.equals("on")) { | |
fire("closed"); | |
} | |
if (event.equals("opened")) { | |
fire("off"); | |
} | |
} | |
''') | |
} | |
// Generator | |
/* | |
* generated by Xtext | |
*/ | |
package org.xtext.homeautomation.generator | |
import java.util.Scanner | |
import org.eclipse.emf.ecore.resource.Resource | |
import org.eclipse.xtext.generator.IFileSystemAccess | |
import org.eclipse.xtext.generator.IGenerator | |
import org.xtext.homeautomation.rules.Declaration | |
import org.xtext.homeautomation.rules.Device | |
import org.xtext.homeautomation.rules.Rule | |
/** | |
* Generates code from your model files on save. | |
* | |
* See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation | |
*/ | |
class RulesGenerator implements IGenerator { | |
override void doGenerate(Resource resource, IFileSystemAccess fsa) { | |
val simpleClassName = resource.getURI.trimFileExtension.lastSegment | |
if (resource.contents?.head == null) { | |
return; | |
} | |
val declarations = resource.contents.head.eContents.filter(Declaration) | |
fsa.generateFile(simpleClassName + '.java', ''' | |
public class «simpleClassName» { | |
public static void fire(String event) { | |
«FOR device : declarations.filter(Device)» | |
«FOR state : device.states» | |
if (event.equals("«state.name»")) { | |
System.out.println("«device.name» is now «state.name»!"); | |
} | |
«ENDFOR» | |
«ENDFOR» | |
«FOR rule : declarations.filter(Rule)» | |
if (event.equals("«rule.when.name»")) { | |
fire("«rule.then.name»"); | |
} | |
«ENDFOR» | |
} | |
public static void main(String... args) { | |
try («Scanner.name» scanner = new «Scanner.name»(System.in)) { | |
System.out.println("Welcome home!"); | |
System.out.println("Available commands : "); | |
«FOR device : declarations.filter(Device)» | |
«FOR state : device.states» | |
System.out.println(" «device.name» «state.name»" ); | |
«ENDFOR» | |
«ENDFOR» | |
System.out.println("Have fun!"); | |
while(true) { | |
String command = scanner.next(); | |
«FOR device : declarations.filter(Device)» | |
if (command.equalsIgnoreCase("«device.name»")) { | |
String secondaryCommand = scanner.next(); | |
«FOR state : device.states» | |
if (secondaryCommand.equalsIgnoreCase("«state.name»")) { | |
fire("«state.name»"); | |
} else | |
«ENDFOR» | |
{ | |
System.out.println("«device.name» can only have the following states: «device.states.map[name]. | |
join(',')»."); | |
} | |
} | |
«ENDFOR» | |
if (command.equalsIgnoreCase("bye")) { | |
System.out.println("Ciao!"); | |
break; | |
} | |
} | |
} | |
} | |
} | |
''') | |
} | |
def ruleMethodName(Rule device) { | |
'execute' + device.description.replaceAll('\\W', '_') | |
} | |
} | |
// domain model | |
package com.acme { | |
entity Person { | |
name : String | |
givenName : String | |
op getFullName() : String { | |
if (givenName == null) { | |
return name | |
} else { | |
return givenName + " " + name | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment