Skip to content

Instantly share code, notes, and snippets.

@spoenemann
Last active October 21, 2021 15:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spoenemann/51efd467bf50a137ee44 to your computer and use it in GitHub Desktop.
Save spoenemann/51efd467bf50a137ee44 to your computer and use it in GitHub Desktop.
vJUG Demo
Device Window can be OPEN, CLOSED
Device Heating can be ON, OFF
Rule 'Close the window when heating is turned on'
when Heating.ON
then Window.CLOSED
Rule 'Switch off heating when the window is opened'
when Window.OPEN
then Heating.OFF
grammar org.xtext.example.home.HomeAutomation with org.eclipse.xtext.common.Terminals
generate homeAutomation "http://www.xtext.org/example/home/HomeAutomation"
//--- Model Example
// Device Window can be OPEN, CLOSED
// Device Heating can be ON, OFF
//
// Rule 'Close the window when heating is turned on'
// when Heating.ON
// then Window.CLOSED
//
// Rule 'Switch off heating when the window is 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)*;
package org.xtext.example.home.generator
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.AbstractGenerator
import org.eclipse.xtext.generator.IFileSystemAccess2
import org.eclipse.xtext.generator.IGeneratorContext
import org.xtext.example.home.homeAutomation.Device
import org.xtext.example.home.homeAutomation.Model
class HomeAutomationGenerator extends AbstractGenerator {
override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
val model = resource.contents.head as Model
val devices = model.declarations.filter(Device)
fsa.generateFile('overview.txt', '''
«devices.size» devices named «devices.map[name].sort.join(', '
''')
}
}
package org.xtext.example.home.tests
import com.google.inject.Inject
import org.eclipse.xtext.generator.IGenerator2
import org.eclipse.xtext.generator.InMemoryFileSystemAccess
import org.eclipse.xtext.junit4.InjectWith
import org.eclipse.xtext.junit4.XtextRunner
import org.eclipse.xtext.junit4.util.ParseHelper
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.xtext.example.home.homeAutomation.Model
@RunWith(XtextRunner)
@InjectWith(HomeAutomationInjectorProvider)
class HomeAutomationGeneratorTest {
@Inject extension ParseHelper<Model>
@Inject IGenerator2 generator
@Test def void testDeviceOverview() {
val model = '''
Device Window can be OPEN, CLOSED
Device Heating can be ON, OFF
Rule 'Close the window when heating is turned on'
when Heating.ON
then Window.CLOSED
Rule 'Switch off heating when the window is opened'
when Window.OPEN
then Heating.OFF
'''.parse
val fsa = new InMemoryFileSystemAccess
generator.doGenerate(model.eResource, fsa, null)
val generatorResult = fsa.allFiles.values.head
Assert.assertNotNull(generatorResult)
Assert.assertEquals('''
2 devices named Heating, Window
'''.toString, generatorResult.toString)
}
}
package org.xtext.example.home.tests
import com.google.inject.Inject
import org.eclipse.xtext.junit4.InjectWith
import org.eclipse.xtext.junit4.XtextRunner
import org.eclipse.xtext.junit4.util.ParseHelper
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.xtext.example.home.homeAutomation.Device
import org.xtext.example.home.homeAutomation.Model
import org.xtext.example.home.homeAutomation.Rule
@RunWith(XtextRunner)
@InjectWith(HomeAutomationInjectorProvider)
class HomeAutomationParsingTest{
@Inject extension ParseHelper<Model> parseHelper
@Test
def void loadModel() {
val model = '''
Device Window can be OPEN, CLOSED
Device Heating can be ON, OFF
Rule 'Close the window when heating is turned on'
when Heating.ON
then Window.CLOSED
Rule 'Switch off heating when the window is opened'
when Window.OPEN
then Heating.OFF
'''.parse
Assert.assertNotNull(model)
Assert.assertEquals(2, model.declarations.filter(Device).size)
Assert.assertEquals(2, model.declarations.filter(Rule).size)
}
}
package org.xtext.example.home.tests
import com.google.inject.Inject
import org.eclipse.xtext.junit4.InjectWith
import org.eclipse.xtext.junit4.XtextRunner
import org.eclipse.xtext.junit4.util.ParseHelper
import org.eclipse.xtext.junit4.validation.ValidationTestHelper
import org.junit.Test
import org.junit.runner.RunWith
import org.xtext.example.home.homeAutomation.Model
import org.xtext.example.home.homeAutomation.Rule
import org.xtext.example.home.homeAutomation.HomeAutomationPackage
@RunWith(XtextRunner)
@InjectWith(HomeAutomationInjectorProvider)
class HomeAutomationValidationTest {
@Inject extension ParseHelper<Model>
@Inject ValidationTestHelper validator
@Test def void testSameDevice() {
val model = '''
Device Window can be OPEN, CLOSED
Rule 'This rule contradicts itself'
when Window.OPEN
then Window.CLOSED
'''.parse
val rule = model.declarations.filter(Rule).head
validator.assertError(model, rule.eClass, null, "same device")
}
}
package org.xtext.example.home.validation
import org.eclipse.xtext.validation.Check
import org.xtext.example.home.homeAutomation.Rule
class HomeAutomationValidator extends AbstractHomeAutomationValidator {
@Check
def checkSameDevice(Rule rule) {
if (rule.when != null && rule.then != null) {
if (rule.when.eContainer == rule.then.eContainer)
error("The 'when' and 'then' parts of a rule must not point to the same device.", null)
}
}
}
@svenefftinge
Copy link

package com.acme {

    entity Person {
        firstName : String
        name : String
        age : int

        op getFullName() : String {
            if (firstName == null) {
                return name;
            } else {
                return firstName + " " + name;
            }
        }
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment