Showing posts with label xtext. Show all posts
Showing posts with label xtext. Show all posts

Friday, January 23, 2015

XtextDay and EclipseCon San Francisco 2015

In case you've missed it, we are organizing a so called XtextDay co-located with EclipseCon 2015. The program is already online for a couple of weeks:

Sebastian and I will start the day talking about the newest developments (e.g. Intellij IDEA support, web editor support, incremental standalone builders, etc.). After that we will hear how Xtext languages are used to design REST APIs. In the afternoon we have in-depth sessions on Xbase, performance and scoping, and after the coffee break we will learn how a silicon valley company use Xtext to build a commercial product for designing systems on a chip (IoT). The full program details can be found here. But that's not all..

Additional Xtext content at EclipseCon

Although it's possible to register only for the XtextDay, I recommend to book the whole EclipseCon conference as it is not only an awesome community event where you will find many new friends, but in addition to the XtextDay, there is some Xtext-related content there as well. It starts with a beginner's tutorial on Monday, which is a good preparation for the technically deeper talks following. In addition to the XtextDay and the tutorial we have:

So quite some content in addition to XtextDay. If you consider using Xtext for something or you are already using it, then you should definitely come and join the sessions, discussions and party! :-)

Monday, October 01, 2012

Current Development and Future Plans for Xtext and Xtend

It has been a couple of weeks now since we released Xtext and Xtend with Eclipse Juno. Time for an update on what we are doing and where we want to go. In the following I describe the main new topics the team is working on. In addition to what is described below there is of course also a lot of maintenance work we are doing, i.e. fixing bugs and improving the core framework. Also we are doing some awesome work for customers, which I’m not allowed to talk about (But, yes, you can hire us. Even the whole team!).

Editors For Other Platforms

We are experimenting with support for other IDE-platforms than Eclipse. The first platform we are looking at right now is the web, more concrete Orion. Other platforms we want to look at are Netbeans, Xcode, Visual Studio and IntelliJ. Also basic configuration settings for TextMate and the like could be something we will be looking at.
Which one do you think is most interesting?
This part of our work is funded by Zukunftsprogramm Wirtschaft


Improved Type System

The type system and linking for Xbase-based languages (Xtend falls into this class) is currently redeveloped. Although the existing one does a decent job it has some architectural flaws which makes it too slow when working with bigger files. The new one is fast and it can do even more and cooler things. Type inference, for instance, now uses control flow analysis. That is you can write the following:
val myMap = newHashMap
myMap.put(23, new StringBuilder)
myMap.put(42, "some string")
// myMap is of type Map<Integer, CharSequence> by now
There are some other new features, which are possible with the new typesystem and even more importantly it will fix the outstanding typing bugs and be a solid foundation for future improvements. I'm sure there will be a blog post about the details in the next couple of weeks.

Formatting

Xtend gets a new formatter. I’m already using it on a daily basis and must say that it works very well. Especially with a language like Xtend which is syntactically much more flexible than Java, you need to look into language idioms to make sure a formatter does what you expect. There will also be a preference page to adjust formatting settings, but it won’t have as many options as the Java formatter in the beginning. Would be nice to have some more beta testers and feedback. What kind of options do you want to see?
Although we are implementing the formatting for Xtend now, we plan to have a new or at least an improved API for all Xtext languages. And of course the formatting for the expression goes into Xbase.

Active Annotations

Active Annotations allow you to participate in the translation step from Xtend to Java source code. It’s a bit like Java’s annotation processing but much more flexible and less complicated to integrate at the same time. You basically declare an annotation and implement a processing method, where you define how to translate annotated Xtend code to Java. I'll write a separate blog post on this.
Also Sebastian is giving a sneak-preview on Active Annotations tomorrow at JavaOne and the feature will play an important role in the session Web Development with GWT and Xtend Olli and I are giving at EclipseCon in a couple of weeks.

Release Plans

Currently the overhauled type system has highest priority and we are targeting a release as soon as it is done. We hope to have it in December this year. That release will contain the formatting and might have an @Beta-flagged prototype for Active Annotations included. We plan to have a prototype for Xtext & Orion later this year as well, maybe the team can even give a so demo during their EclipseCon talk.

Additional Topics

I want to make contributing simpler. The idea is to provide a one click download, which materialises a working IDE, workspace and target platform on your box. The git repository should already be connected with our gerrit instance. Also we want to start writing breaking and ignored unit tests for defects so potential contributors can easily reproduce a problem and see how our test framework works. Let's see if we can make contributing and fixing bugs simple and fun.
Another topic is to provide an alternative for debugging Xbase-languages. Currently they work through JSR-045 which is great as long as you run your code in a standard JVM. Unfortunately JSR-045 isn't supported by Android's Dalvik-VM or GWT's new SuperDevMode. We need to come up with a solution for this as well.
Finally I want to mention that there is now a package for "Java and DSL Developers" on the Eclipse download page. It doesn't have a neat welcome page so far but it's a one-stop-shopping for people who want to get started with Xtend or Xtext (or both).

Monday, May 07, 2012

Martin Fowler's State Machine DSL with Xtext 2.3


In his book on domain-specific languages, Martin Fowler introduces a small example along which he shows different techniques to implement a domain-specific language. The example goes like this:

Imagine you work for a company specialized on developing and installing systems for secret compartments and you have many customers with very different mechanisms. Mrs. H for instance wants to have a secret panel in her bedroom, which can only be opened after the door has been closed, the second drawer in her chest has been opened and the bedside light was turned on. Also the panel should be closed and locked immediately after someone opens the door - no matter in what state the system is in that case.

Martin proposes the following script as an appropriate definition of Mrs. H's secret compartment system:

events
  doorClosed
  drawOpened
  lightOn   
  reset doorOpened
  panelClosed
end

commands
  unlockPanel
  lockPanel
  lockDoor
  unlockDoor
end

state idle
  actions {unlockDoor lockPanel}
  doorClosed => active
end

state active
  drawOpened => waitingForLight
  lightOn    => waitingForDraw
end

state waitingForLight
  lightOn => unlockedPanel
end

state waitingForDraw
  drawOpened => unlockedPanel
end

state unlockedPanel
  actions {unlockPanel lockDoor}
  panelClosed => idle
end

The script starts with two sections which declare the events and the commands. After that the different states are declared. Some of them execute declared commands as a side effect (the actions block). Also they contain declarations of transitions, i.e. to what state the system switches when a certain event is fired.

As I have already implemented this language with previous versions of Xtext, I'd like to make it a bit more interesting this time. Let's replace the more or less useless declaration of commands with the possibility to write and call real code!

events
  doorClosed
  drawOpened
  lightOn   
  reset doorOpened
  panelClosed
end

state idle
  do { 
    println("opened the door.")
    println("locked the panel.")
  }
  doorClosed => active
end

state active
  drawOpened => waitingForLight
  lightOn    => waitingForDraw
end

state waitingForLight
  lightOn => unlockedPanel
end

state waitingForDraw
  drawOpened => unlockedPanel
end

state unlockedPanel
  do { 
    println("opened the panel.")
    println("locked the door.")
  }
  panelClosed => idle
end

As you can see the main change is that you are now able to call Java libraries right from within your state machine. I want these expressions to be statically typed (incl. full support for Java generics) and to keep the code as readable and dense as the rest of the DSL we need to have type inference like in Scala. Feature-wise everything should be supported, from for-loops to conditional logic, from the typical literals to more advanced concepts like lambda expressions (it's 2012 after all). 

But how would we talk to a door resp. panel service in order to open and close them? We could use static methods, but that's bad design since then the application is hardly testable and you cannot easily switch the concrete implementations behind these services. So let's use dependency injection. 
To support that I added a services block to the language where you list all required services. Now we can use these services within the action code :

events
  doorClosed
  drawOpened
  lightOn   
  reset doorOpened
  panelClosed
end

services
  DoorService door
  PanelService panel
end

state idle
  do { 
    door.open
    panel.close
  }
  doorClosed => active
end

state active
  drawOpened => waitingForLight
  lightOn    => waitingForDraw
end

state waitingForLight
  lightOn => unlockedPanel
end

state waitingForDraw
  drawOpened => unlockedPanel
end

state unlockedPanel
  do { 
    door.close
    panel.open
  }
  panelClosed => idle
end

Our language would now be very testable and should integrate nicely with any Java project. 

How Do I Implement Such A Language In Xtext?

To get a full implementation of this DSL, including not only a parser, linker, unparser, etc. but also a compiler generating readable and executable Java code as well as having nice integration in Eclipse, you need to create a fresh Xtext project, using the wizard and define the following grammar:

grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Statemachine :
  {Statemachine}
  ('events' 
    events+=Event+ 
  'end')?
  ('services'
    services+=Service*
  'end')?
  states+=State*;

Service :
  type=JvmTypeReference name=ID;

Event:
  resetEvent?='reset'name=ID;

State:
  'state' name=ID
    ('do' action=XBlockExpression)?
    transitions+=Transition*
  'end';

Transition:
  event=[Event] '=>' state=[State];

I don't want to go into a detailed explanation of the grammar language, since that is explained in the documentation. But note, that in order to be able to write full Java types in the service declaration we refer to a library grammar rule (JvmTypeReference). The same applies for the expressions: The library grammar 'org.eclipse.xtext.xbase.Xbase' predefines the full expressions and all we have to do here is to import the grammar in the first line and call the rule XBlockExpression within the rule State.

Now that we have defined the syntax of our language, we need to tell how it is translated to Java. For that matter we write some code, which creates a Java DOM out of the state machine DOM produced by the parser. To make this very readable and concise Xtext comes with an internal DSL implemented in the programming language Xtend. The actual code looks like this:

 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;
         String currentState = "«stm.states.head.name»";
         String lastEvent = null;
         while (true) {
           «FOR state : stm.states»
             if (currentState.equals("«state.name»")) {
               «IF state.action != null»
                 if (executeActions) {
                   do«state.name.toFirstUpper»();
                   executeActions = false;
                 }
               «ENDIF»
               System.out.println("Your are now in state '«state.name»'. Waiting for [«
                 state.transitions.map[event.name].join(', '].");
               lastEvent = eventSource.get();
               «FOR t : state.transitions»
                 if ("«t.event.name»".equals(lastEvent)) {
                   currentState = "«t.state.name»";
                   executeActions = true;
                 }
               «ENDFOR»
             }
           «ENDFOR»
           «FOR resetEvent : stm.events.filter[resetEvent]»
             if ("«resetEvent.name»".equals(lastEvent)) {
               System.out.println("Resetting state machine.");
               currentState = "«stm.states.head.name»";
               executeActions = true;
             }
           «ENDFOR»
           
         }
       ''')]
     ]
   ]
 }


That's all you need. With just the grammar and the Xtend code above you have implemented the full language! I've pushed the full project to github.
This is what the Java code generated for Mrs. H's controller looks like.

What Do You Get?

As already mentioned the expressions are feature complete and statically typed. The compiler can be run from any Java process (e.g. ant, maven, gradle, command line). Also the tooling is just like you would expect: content assist, coloring, hovers, refactorings, dead code analysis and even debugging work out of the box:


Content Assist For Expressions

Call-Hierarchy Integrated in JDT
Content Assist For Types

Dead Code Analysis






Thursday, February 23, 2012

EclipseCon 2012 and Xtext

In case you didn't recognize this year's EclipseCon has a whole track on DSLs, covering a lot of interesting sessions around Xtext. There are many technical sessions, success stories, and even a full tutorial.

Here are the technical talks given by the core committers of Xtext and EMF:

And just in case you need some inspiration, there are a lot of sessions talking about stuff which was built with Xtext:


Finally there are some more general sessions like:

Xtext core committers, that is Jan, Moritz, Sebastian, Ed and me, will be at the conference all days and be happy to discuss all kinds of topics with you. We'll have a booth where you can always find someone to talks to and most likely we'll also have a BOF session at one of the evenings.

So if you are in any case interested in Xtext and/or domain specific languages, EclipseCon 2012 is the conference to go to. It's only in five weeks, so you should register now!

And by the way there are many, many other interesting sessions going on there.

I'm looking forward to a fun community meet-up! :-)

Tuesday, November 01, 2011

Build Your Own JVM Language!

Xtext has already simplified development of domain-specific languages a lot. From a simple grammar definition you not only get a full language infrastructure but also powerful Eclipse-based tool support.
Now it's getting even better.

Today we release Xtext 2.1, which comes with surprisingly easy to use support for defining little languages targeting the JVM (Java Virtual Machine). You only need to define two files:
  • the grammar
  • a mapping to Java concepts
The first one is not new. It's still the same concise and readable grammar language we always had in Xtext.

The second script is the big deal: it allows you to map your language concepts to any number of Java types, fields and methods. By doing that you implicitly tell the framework what it needs to know to provide you with a fully working IDE including an incremental compiler!

We have written a nice little tutorial explaining the five steps needed to get a language like the following:

import java.util.List

package my.model {

    entity Person {
        name: String
        firstName: String
        friends: List<Person>
        address : Address

        op getFullName() : String {
            return firstName + " " + name;
        }
        
        op getFriendsSortedByFullName() : List<Person> {
            return friends.sortBy( f | f.fullName);
        }
    }
    
    entity Address {
        street: String
        zip: String
        city: String
    }
}

As you can see, it supports all kinds of advanced features such as Java generics and full expressions even including closures. But you not only get a working parser, linker and compiler but a fully-working high-end Eclipse plug-in on top! The screencast demos the resulting language and IDE and briefly shows how that can be built. Be creative and have fun!

Thursday, October 20, 2011

Xtend - Type-safe Groovy-style Builder API

In this post I want to focus on two cool language features which are both interesting for themselves but even more so in combination.

The Implicit Variable 'it'

If you name your variable 'it' all its members are accessible without qualifying them with the variable reference (just like 'this').

Example:

def appendFoo(StringBuilder it) {
  append('foo')
}

Also note that variables with the name 'it' are the only ones which can be overridden in lexical scopes. So you could for instance write the following, where the lambda expressions argument shadows the outer variable it.

def foo(List<String> it) {
  foreach[ it | toUpperCase ]
}

Sugar For Lambdas With One Argument

Many languages have special syntactic sugar for lambdas with just one argument. So does Xtend. The usual syntax for a closure with one argument is :

  [Type arg | expression-using-arg ]

But as lambdas with one argument are a common case, you can leave out the paramter declaration as in :

  [expression-using-it]

And of course the name of the single argument will be 'it'.

Closures As Last Arguments

We added another feature, which is common in many other popular languages: If you invoke a method where the last argument is a closure you can place the closure after the actual method invocation.

Example:

  newArrayList('a','b','c').foreach [ toUpperCase ]

Groovy-style Builder Syntax

Using these three language enhancements in combination allows for defining statically-typed groovy-style builder APIs. Check the screencast to see it in action.

Interesting? See xtend-lang.org for more cool features.

Monday, August 15, 2011

Riding the Waterfall


Did you know we are working on a research project called “Xbase”? It’s a two year project which is going to end in May 2012. So far we are absolutely in time with everything we had written down in the project plan two years ago. We've developed Xbase itself and Xtend on top of it. Next up in the plan is a textual language for EMF Ecore files as well as a validation language. Both are based on and leveraging Xbase. Also in the plan is support for debugging for Xbase-based languages, evaluating the usefulness of Xbase in the context of web-development and extensive documentation. So here are the details for the next couple of months:
Xcore
Ed already blogged about it: It’s going to be the primary syntax to design Ecore models and it will not only come with decent tooling to define the structural elements of an Ecore model. It will allow you to express behavior of EOperations and derived EStructuralFeatures using Xbase. It’s still in a very early state but we’ll have something cool to show at EclipseCon Europe (as long as the talk gets accepted that is ;-))
Validation language
The validation language is developed together with our friends from Paranor. It will focus on a declarative description of compiler issues, including the messages and severities and will automatically allow language users to change the severities on a per project level.
Debugging
Developing with DSLs includes debugging them. We want to allow debugging any Xbase-based DSL right within the Java debugger. The idea is that you can debug through the underlying Java but at the same time (i.e. during the same debugging session) you can also step over the original DSL code. This might be best explained with the small prototype I created a couple of weeks ago.
Evaluation in the context of web development
To proof the relevance of Xbase and Xtext we have put this evaluation task into the project plan. The idea is to write a small web application framework, which might not be as general as something like Spring Roo or the Play! Framework but is much more concrete than the domain model example we ship. Think of it as a comprehensive real world application of Xtext 2.0. The project plan states that this is going to be open-sourced :-)
Extensive Documentation (The Xtext book)
The Xbase project plan says we are going to work a couple of months on extensive documentation. The best form would be a printed book. So that’s what we want to do.
Maintenance
We have just added Xbase to the already relatively large Xtext project. We’ve also added Xtend, a statically typed programming language, and plan to have a couple of other new components as well. But we cannot just throw stuff in all the time. We need to make sure that the overall quality is improved steadily and this gets harder as the framework grows. The good thing is, that we won’t do (we can’t since we published API) big changes to the core framework as we did in previous years. But still there’s enough to do and even the further improvement of the runtime and the editor parts of Xbase, Xtend and Xtext itself is written down in the project plan. Isn't waterfall planning a great thing? ;-)
BTW: Xtext 2.0.1 and Xtext 2.1.0
A service release has been available for two weeks now and the 2.1 release is planned for mid October. It will contain a lot of bugfixes, a more stable version of the reimplemented serializer, and more performance improvements (we are still working on that). It will also come with one or the other enhancement. It’s best to check bugzilla to find out about the details. We use the SR2 flag for it.

Monday, June 06, 2011

Upcoming Eclipse Democamps Featuring Xtext

Have you yet checked whether there is an Eclipse DemoCamp for Indigo near your place?

There is a lot of Xtext coverage in DemoCamps in Europe and one in the US this month. So if you want to learn about Xtext 2.0 and its new features, you should consider to come to one of the following events.

June 7thFrankfurt, GermanyXtext 2.0 (with me)
June 11thKrakow, PolandXtext Demo (Marcin Lewandowski)
June 14thBonn, GermanyXtext 2.0 (Jan Koehnlein)
June 17thVienna, AustriaXtext 2.0 (Sebastian Zarnekow)
June 20thMunich, GermanyXtext 2.0 (Sebastian and me)
APPlause (built with Xtext) (Peter Friese)
June 20thSan Jose, USAXtext 2.0 (Moritz Eysholdt)
June 21stDresden, GermanyXtext 2.0 (Jan Koehnlein)
June 21stDarmstadt, GermanyAPPlause (built with Xtext) (Marcus Ficner)
June 28thHamburg, GermanyXtext 2.0 (me)
June 28thAmsterdam, NetherlandsXtext 2.0 (Christophe Bouhier)
June 29thBerlin, GermanyAPPlause (built with Xtext) (Heiko Behrens)

In addition to that Sebastian and I are giving a talk at Jazoon in Zurich, Switzerland on June 21st. I'm looking forward to see many of you at one of these events!

Friday, June 03, 2011

5 simple steps to Fowler's DSL with Xtext 2.0

You might have read (about) the book Domain-Specific Languages written by Martin Fowler. As the name suggests it is about these little useful programming languages you can built very easily with Xtext. Unfortunately Martin decided to use more low level technology in order to explain how to implement such a language. So if you don't want to spend hours of hours dealing with complex low level technology just to end up with a parser but nothing else, here are the five steps needed to get a fully working implementation for the DSL he uses throughout the book (Mrs Grant's Controller). It doesn't get simpler.

Below you can find a detailed description. For those of you who prefer to just sit and watch, here are three screencasts I've recorded around this example.



Creating the project and defining the language



Defining the code generator and see its integration



Features, Features, Features



1) Download Eclipse and Install Xtext

For many people this is the hardest part. But believe me things have improved and it is now quite easy to get a working Eclipse distribution including the latest milestone of Xtext 2.0. :-)

Download an Eclipse Classic distribution for your platform from here :  
    http://www.eclipse.org/downloads/index-developer.php

Unzip and start Eclipse, choose Help -> Install New Software... and use the update site
    http://download.itemis.com/updates/milestones
in order to install the Xtext SDK feature

2) Use the Xtext project wizard

Select New -> Project..., and within the dialog choose Xtext Project. You can stick with the defaults on the next page, but make sure you choose the Experimental Features configuration in order to get the latest and greatest features, such as rename refactoring.

You should use the experimental features

3) Define the grammar

The Xtext grammar file is automatically opened. Just copy and paste the following grammar definition for Martin's statemachine DSL in.


grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate statemachine "http://www.xtext.org/example/secretcompartments/Statemachine"

Statemachine :
     {Statemachine}
     ('events' 
          events+=Event+ 
     'end')?
     ('resetEvents' 
          resetEvents+=[Event]+ 
     'end')?
     ('commands' 
          commands+=Command+ 
     'end')?
     states+=State*
;

Event:
     name=ID code=ID
;

Command:
     name=ID code=ID
;

State:
     'state' name=ID
          ('actions' '{' actions+=[Command]+ '}')?
          transitions+=Transition*
     'end'
;

Transition:
     event=[Event] '=>' state=[State]
;


4) Run the generator

Now you need to run the generator which creates the parser and a couple of other parts of the language infrastructure. To do so right click into the editor and choose 
   Run As -> Generate Xtext Artifacts

5) Define the code generator

A DSL isn't worth much if you are not able to execute it somehow. Xtext has already provided you with a stub for a code generator written in our cool new template language Xtend (Xtend as well as the grammar language are also implemented with Xtext of course). 
To get a working implementation which produces a Java implementation of a defined statemachine, just copy the following into the file MyDslGenerator.xtend

package org.xtext.example.mydsl.generator

import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.IGenerator
import org.eclipse.xtext.generator.IFileSystemAccess
import org.xtext.example.mydsl.statemachine.Statemachine
import org.xtext.example.mydsl.statemachine.Event
import org.xtext.example.mydsl.statemachine.Command
import org.xtext.example.mydsl.statemachine.State

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();
}
«FOR c : sm.commands»
«c.declareCommand»
«ENDFOR»
protected void run() {
boolean executeActions = true;
String currentState = "«sm.states.head.name»";
String lastEvent = null;
while (true) {
«FOR state : sm.states»
«state.generateCode»
«ENDFOR»
«FOR resetEvent : sm.resetEvents»
if ("«resetEvent.name»".equals(lastEvent)) {
System.out.println("Resetting state machine.");
currentState = "«sm.states.head.name»";
executeActions = true;
}
«ENDFOR»
}
}
private String receiveEvent() {
System.out.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
return br.readLine();
} catch (IOException ioe) {
System.out.println("Problem reading input");
return "";
}
}
}
'''
def declareCommand(Command command) '''
protected void do«command.name.toFirstUpper»() {
System.out.println("Executing command «command.name» («command.code»)");
}
'''
def generateCode(State state) '''
if (currentState.equals("«state.name»")) {
if (executeActions) {
«FOR c : state.actions»
do«c.name.toFirstUpper»();
«ENDFOR»
executeActions = false;
}
System.out.println("Your are now in state '«state.name»'. Possible events are [«
state.transitions.map(t | t.event.name).join(', '].");
lastEvent = receiveEvent();
«FOR t : state.transitions»
if ("«t.event.name»".equals(lastEvent)) {
currentState = "«t.state.name»";
executeActions = true;
}
«ENDFOR»
}
'''
}