Building DSLs with Xtext

                                         Eclipse Modeling Day

                                         New York, 16 November 2009
                                         Toronto, 18 November 2009


                                         Heiko Behrens (itemis)




© itemis AG 2009 – All rights reserved
FOUNDATION
 MEMBER TM
Model-Driven Software Development
            with DSLs
Suppose...
You’d want to core an apple...
... for your kids.
?
Right tool for the job?
Your trusty swiss army knife!
Suppose...
You’d want to core a few more apples...
... for an apple cake.
Still the best tool for the job?
Better use this one.
and this one:
... a DSL is ...
A specific tool
for a specific job
A specific tool
for a specific job
Domain-Specific Language (DSL)
A DSL is a formal, processable language
  targeting at a specific viewpoint or
     aspect of a software system.
Its semantics, flexibility and notation is
 designed in order to support working
with that viewpoint as good as possible.
Rd2-c2
“ Queen to c7.
               Check.”




  “ Rd2-c2 ,
                      ”
rook at d2 moves to c2.
Moves in Chess:
!ook at a1 moves to a5.
    P
    iece           S   q uare      A
                                   ction
                                           De   stin ation


"ishop at c8 captures knight at h3.
    P
    iece            S   q uare   ion
                                           Action
                                                             D
                                                             es tinat


# b1 x c3
Piece S   qua re ction stination
              AD      e


$2 - g4
                      ation
S A D
quar
    e   ction e  stin
Rook     a1    move      a5
              Bishop   c8   capture    h3   Knight
              Knight   b1   capture    c3   Queen
               Pawn    g2    move      g4


    Game                     Move
                         Source                      «enum»
WhitePlayer
                       * Destination                  Piece
BlackPlayer
                         Piece
"ishop at c8 captures knight at h3

           " c8 x h3
Model (textfile)
White: "Mayfield"
Black: "Trinks"

pawn at e2 moves to e4
pawn at f7 moves to g5

K b1 - c3
f7 - f5

queen at d1 moves to h5
// 1-0
Xtext is a complete environment
for development of textual
 - programming languages and
 - domain-specific languages.
It is implemented in Java and is
based on Eclipse, EMF, and Antlr.
ar
Model




                                    m
                                   m
                               ra
                               G
                           Generator



        Runtime
                  Superclass




                  Subclass              Class




 LL(*) Parser   ecore meta model                editor
Grammar (similar to EBNF)
 Game:
 !   "White:" whitePlayer=STRING
 !   "Black:" blackPlayer=STRING
 !   (moves+=Move)+;
 !

 Move:
 !   AlgebraicMove | SpokenMove;

 AlgebraicMove:
 !   (piece=Piece)? source=Square (captures?='x'|'-') dest=Square;
 !

 SpokenMove:
 !   piece=Piece 'at' source=Square
 !   (captures?='captures' capturedPiece=Piece 'at' | 'moves to')
 !   dest=Square;
 !

 terminal Square:
 !   ('a'..'h')('1'..'8');
 !

 enum Piece:
 !   pawn    =   'P'   |   pawn     =   'pawn'     |
 !   knight =    'N'   |   knight   =   'knight'   |
 !   bishop =    'B'   |   bishop   =   'bishop'   |
 !   rook    =   'R'   |   rook     =   'rook'     |
 !   queen =     'Q'   |   queen    =   'queen'    |
 !   king    =   'K'   |   king     =   'king';
Demo
• Model         File within Editor + Custom View
• Xtext        Grammar for writing simple chess games
• Derived          meta model
• Java     program that works with textual models
• Xpand-based                generator




© itemis AG 2009 – All rights reserved                  31
Real World DSLs
Regular Expressions
[-+]?[0-9]*.?[0-9]+
Complex Event Processing
from FlightBookings F, CarBookings C, HotelBookings H
  matching [24 hours: F, C, H ]
  on F.name = C.name = H.name
  select F.name, true bookingWithCar,
  into TripleBookings

from FlightBookings F, CarBookings C, HotelBookings H
  matching [24 hours: F, !C, H ]
  on F.name = C.name = H.name
  select F.name, false bookingWithCar
  into TripleBookings

from TripleBookings
  where prev(bookingWithCar) and not bookingWithCar
  select name
  into LostCustomers
internal DSL
 (with Java)
Mailer.mail()
.to(“you@gmail.com”)
.from(“me@gmail.com”)
.subject(“Writing DSLs in Java”)
.body(“...”)
.send();
ANT
<project name="MyProject" default="dist" basedir=".">
  <property name="src" location="src"/>
  <property name="build" location="build"/>
  <property name="dist" location="dist"/>
  <target name="init">
    <mkdir dir="${build}"/>
  </target>
  <target name="compile" depends="init">
    <javac srcdir="${src}" destdir="${build}"/>
  </target>
  <target name="dist" depends="compile">
    <mkdir dir="${dist}/lib"/>
    <jar jarfile="${dist}/lib/MyProject.jar"
         basedir="${build}"/>
  </target>
  <target name="clean">
    <delete dir="${build}"/>
    <delete dir="${dist}"/>
  </target>
</project>
ANT
      ?
<project name="MyProject" default="dist" basedir=".">
  <property name="src" location="src"/>
  <property name="build" location="build"/>
  <property name="dist" location="dist"/>
  <target name="init">
    <mkdir dir="${build}"/>
  </target>
  <target name="compile" depends="init">
    <javac srcdir="${src}" destdir="${build}"/>
  </target>
  <target name="dist" depends="compile">
    <mkdir dir="${dist}/lib"/>
    <jar jarfile="${dist}/lib/MyProject.jar"
         basedir="${build}"/>
  </target>
  <target name="clean">
    <delete dir="${build}"/>
    <delete dir="${dist}"/>
  </target>
</project>
Entities by Example




        vs.
package templates;

import java.util.*;
import java.io.Serializable;
import javax.persistence.*;

@SuppressWarnings("serial")
@Entity
public class Customer implements Serializable {
!    private Long id;
!    private String name;
!    private Address address;
!    private Set<Order> orders = new HashSet<Order>();
!    // No-arg constructor
!    public Customer() {
!    }
!    @Id
!    public Long getId() {
!    !    return id;
!    }
!    public void setId(Long id) {
!    !    this.id = id;
!    }
!    public String getName() {
!    !    return name;
!    }
!    public void setName(String name) {
!    !    this.name = name;
!    }
!    public Address getAddress() {
!    !    return address;
!    }
!    public void setAddress(Address address) {
!    !    this.address = address;
!    }
!    @OneToMany
!    public Collection<Order> getOrders() {
!    !    return orders;
!    }
!    public void setOrders(Set<Order> orders) {
!    !    this.orders = orders;
!    }
}
package templates;

import java.io.Serializable;
import java.util.*;
import javax.persistence.*;

@SuppressWarnings("serial")
@Entity
public class Customer implements Serializable {
!    private Long id;
!    private String name;
!    private Address address;
!    private Set<Order> orders = new HashSet<Order>();
!    // No-arg constructor
!    public Customer() {
!    }
!    @Id
!    public Long getId() {
!    !    return id;
!    }
!    public void setId(Long id) {
!    !    this.id = id;
!    }
!    public String getName() {
!    !    return name;
!    }
!    public void setName(String name) {
!    !    this.name = name;
!    }
!    public Address getAddress() {
!    !    return address;
!    }
!    public void setAddress(Address address) {
!    !    this.address = address;
!    }
!    @OneToMany
!    public Collection<Order> getOrders() {
!    !    return orders;
!    }
!    public void setOrders(Set<Order> orders) {
!    !    this.orders = orders;
!    }
}
entity Customer {
! property name : String
! property address : Address
! property orders : Order[]
}




   POJOs            DAOs
The Finder Method
<entity name="Customer">
 <attribute type="String" name="name"/>
 <findMethod name="findFixed">
  <expression>
   <equals>
    <attributeRef attr="name"/>
    <constant val="John Doe"/>
   </equals>
  </expression>
 <findMethod>
</entity>



entity Customer {
! property name : String
! finder findFixed : name = "John Doe"
}
Demo

! Implement simple Entity DSL
! Use prepared Generator
grammar org.xtext.webinar.Entity
!   with org.eclipse.xtext.common.Terminals
                                              entity
generate entity
  "http://www.xtext.org/webinar/Entity"                         Model

Model:
                                                                  types
!   (elements+=Type)*;
                                                               *
Type:                                                         Type
                                                         name: EString
!   SimpleType | Entity;

SimpleType:
!   'type' name=ID;
                                                   SimpleType             Entity
Entity:                                                                              extends
!   'entity' name=ID
     ('extends' extends=[Entity])? '{'
                                                                  properties
!   !    properties+=Property*                                              *
!   '}';                                                               Property
                                                                    name: EString
                                                           type     many: EBoolean
Property:
!   'property' name=ID ':'
     type=[Type] (many?='[]')?;
grammar org.xtext.webinar.Entity
!   with org.eclipse.xtext.common.Terminals
                                              entity
generate entity
  "http://www.xtext.org/webinar/Entity"                         Model

Model:
                                                                  types
!   (elements+=Type)*;
                                                               *
Type:                                                         Type
                                                         name: EString
!   SimpleType | Entity;

SimpleType:
!   'type' name=ID;
                                                   SimpleType             Entity
Entity:                                                                              extends
!   'entity' name=ID
     ('extends' extends=[Entity])? '{'
                                                                  properties
!   !    properties+=Property*                                              *
!   '}';                                                               Property
                                                                    name: EString
                                                           type     many: EBoolean
Property:
!   'property' name=ID ':'
     type=[Type] (many?='[]')?;
grammar org.xtext.webinar.Entity
!   with org.eclipse.xtext.common.Terminals
                                              entity
generate entity
  "http://www.xtext.org/webinar/Entity"                         Model

Model:
                                                                  types
!   (elements+=Type)*;
                                                               *
Type:                                                         Type
                                                         name: EString
!   SimpleType | Entity;

SimpleType:
!   'type' name=ID;
                                                   SimpleType             Entity
Entity:                                                                              extends
!   'entity' name=ID
     ('extends' extends=[Entity])? '{'
                                                                  properties
!   !    properties+=Property*                                              *
!   '}';                                                               Property
                                                                    name: EString
                                                           type     many: EBoolean
Property:
!   'property' name=ID ':'
     type=[Type] (many?='[]')?;
grammar org.xtext.webinar.Entity
!   with org.eclipse.xtext.common.Terminals
                                              entity
generate entity
  "http://www.xtext.org/webinar/Entity"                         Model

Model:
                                                                  types
!   (elements+=Type)*;
                                                               *
Type:                                                         Type
                                                         name: EString
!   SimpleType | Entity;

SimpleType:
!   'type' name=ID;
                                                   SimpleType             Entity
Entity:                                                                              extends
!   'entity' name=ID
     ('extends' extends=[Entity])? '{'
                                                                  properties
!   !    properties+=Property*                                              *
!   '}';                                                               Property
                                                                    name: EString
                                                           type     many: EBoolean
Property:
!   'property' name=ID ':'
     type=[Type] (many?='[]')?;
grammar org.xtext.webinar.Entity
!   with org.eclipse.xtext.common.Terminals
                                              entity
generate entity
  "http://www.xtext.org/webinar/Entity"                         Model

Model:
                                                                  types
!   (elements+=Type)*;
                                                               *
Type:                                                         Type
                                                         name: EString
!   SimpleType | Entity;

SimpleType:
!   'type' name=ID;
                                                   SimpleType             Entity
Entity:                                                                              extends
!   'entity' name=ID
     ('extends' extends=[Entity])? '{'
                                                                  properties
!   !    properties+=Property*                                              *
!   '}';                                                               Property
                                                                    name: EString
                                                           type     many: EBoolean
Property:
!   'property' name=ID ':'
     type=[Type] (many?='[]')?;
grammar org.xtext.webinar.Entity
!   with org.eclipse.xtext.common.Terminals
                                              entity
generate entity
  "http://www.xtext.org/webinar/Entity"                         Model

Model:
                                                                  types
!   (elements+=Type)*;
                                                               *
Type:                                                         Type
                                                         name: EString
!   SimpleType | Entity;

SimpleType:
!   'type' name=ID;
                                                   SimpleType             Entity
Entity:                                                                              extends
!   'entity' name=ID
     ('extends' extends=[Entity])? '{'
                                                                  properties
!   !    properties+=Property*                                              *
!   '}';                                                               Property
                                                                    name: EString
                                                           type     many: EBoolean
Property:
!   'property' name=ID ':'
     type=[Type] (many?='[]')?;
grammar org.xtext.webinar.Entity
!   with org.eclipse.xtext.common.Terminals
                                              entity
generate entity
  "http://www.xtext.org/webinar/Entity"                         Model

Model:
                                                                  types
!   (elements+=Type)*;
                                                               *
Type:                                                         Type
                                                         name: EString
!   SimpleType | Entity;

SimpleType:
!   'type' name=ID;
                                                   SimpleType             Entity
Entity:                                                                              extends
!   'entity' name=ID
     ('extends' extends=[Entity])? '{'
                                                                  properties
!   !    properties+=Property*                                              *
!   '}';                                                               Property
                                                                    name: EString
                                                           type     many: EBoolean
Property:
!   'property' name=ID ':'
     type=[Type] (many?='[]')?;
Pimp
 my Write
Whitespace-Aware
  Languages
Incremental
Generation
Conclusion
Abstraction
Use a DSL to develop your tools
Support
Newsgroup
Community Forum
Professional Support
twitter @HBehrens
blog http://HeikoBehrens.net

mail       Heiko.Behrens@itemis.de
xing       http://www.xing.com/profile/Heiko_Behrens
linkedin   http://www.linkedin.com/in/HeikoBehrens




                                                                                            www.xtext.org
                 The Committer Team                                                         twitter @Xtext




 Heiko      Michael    Sven       Moritz    Peter     Dennis     Jan        Patrick     Knut      Sebastian
Behrens      Clay     Efftinge   Eysholdt   Friese    Hübner   Köhnlein   Schönbach   Wannheden   Zarnekow

Building DSLs with Xtext - Eclipse Modeling Day 2009

  • 1.
    Building DSLs withXtext Eclipse Modeling Day New York, 16 November 2009 Toronto, 18 November 2009 Heiko Behrens (itemis) © itemis AG 2009 – All rights reserved
  • 2.
  • 4.
  • 6.
  • 7.
    You’d want tocore an apple...
  • 8.
  • 9.
  • 10.
    Your trusty swissarmy knife!
  • 11.
  • 12.
    You’d want tocore a few more apples...
  • 13.
    ... for anapple cake.
  • 14.
    Still the besttool for the job?
  • 15.
  • 16.
  • 17.
    ... a DSLis ...
  • 18.
    A specific tool fora specific job
  • 19.
    A specific tool fora specific job
  • 20.
    Domain-Specific Language (DSL) ADSL is a formal, processable language targeting at a specific viewpoint or aspect of a software system. Its semantics, flexibility and notation is designed in order to support working with that viewpoint as good as possible.
  • 21.
  • 22.
    “ Queen toc7. Check.” “ Rd2-c2 , ” rook at d2 moves to c2.
  • 23.
    Moves in Chess: !ookat a1 moves to a5. P iece S q uare A ction De stin ation "ishop at c8 captures knight at h3. P iece S q uare ion Action D es tinat # b1 x c3 Piece S qua re ction stination AD e $2 - g4 ation S A D quar e ction e stin
  • 24.
    Rook a1 move a5 Bishop c8 capture h3 Knight Knight b1 capture c3 Queen Pawn g2 move g4 Game Move Source «enum» WhitePlayer * Destination Piece BlackPlayer Piece
  • 25.
    "ishop at c8captures knight at h3 " c8 x h3
  • 26.
    Model (textfile) White: "Mayfield" Black:"Trinks" pawn at e2 moves to e4 pawn at f7 moves to g5 K b1 - c3 f7 - f5 queen at d1 moves to h5 // 1-0
  • 28.
    Xtext is acomplete environment for development of textual - programming languages and - domain-specific languages. It is implemented in Java and is based on Eclipse, EMF, and Antlr.
  • 29.
    ar Model m m ra G Generator Runtime Superclass Subclass Class LL(*) Parser ecore meta model editor
  • 30.
    Grammar (similar toEBNF) Game: ! "White:" whitePlayer=STRING ! "Black:" blackPlayer=STRING ! (moves+=Move)+; ! Move: ! AlgebraicMove | SpokenMove; AlgebraicMove: ! (piece=Piece)? source=Square (captures?='x'|'-') dest=Square; ! SpokenMove: ! piece=Piece 'at' source=Square ! (captures?='captures' capturedPiece=Piece 'at' | 'moves to') ! dest=Square; ! terminal Square: ! ('a'..'h')('1'..'8'); ! enum Piece: ! pawn = 'P' | pawn = 'pawn' | ! knight = 'N' | knight = 'knight' | ! bishop = 'B' | bishop = 'bishop' | ! rook = 'R' | rook = 'rook' | ! queen = 'Q' | queen = 'queen' | ! king = 'K' | king = 'king';
  • 31.
    Demo • Model File within Editor + Custom View • Xtext Grammar for writing simple chess games • Derived meta model • Java program that works with textual models • Xpand-based generator © itemis AG 2009 – All rights reserved 31
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
    from FlightBookings F,CarBookings C, HotelBookings H matching [24 hours: F, C, H ] on F.name = C.name = H.name select F.name, true bookingWithCar, into TripleBookings from FlightBookings F, CarBookings C, HotelBookings H matching [24 hours: F, !C, H ] on F.name = C.name = H.name select F.name, false bookingWithCar into TripleBookings from TripleBookings where prev(bookingWithCar) and not bookingWithCar select name into LostCustomers
  • 37.
  • 38.
  • 39.
  • 40.
    <project name="MyProject" default="dist"basedir="."> <property name="src" location="src"/> <property name="build" location="build"/> <property name="dist" location="dist"/> <target name="init"> <mkdir dir="${build}"/> </target> <target name="compile" depends="init"> <javac srcdir="${src}" destdir="${build}"/> </target> <target name="dist" depends="compile"> <mkdir dir="${dist}/lib"/> <jar jarfile="${dist}/lib/MyProject.jar" basedir="${build}"/> </target> <target name="clean"> <delete dir="${build}"/> <delete dir="${dist}"/> </target> </project>
  • 41.
  • 42.
    <project name="MyProject" default="dist"basedir="."> <property name="src" location="src"/> <property name="build" location="build"/> <property name="dist" location="dist"/> <target name="init"> <mkdir dir="${build}"/> </target> <target name="compile" depends="init"> <javac srcdir="${src}" destdir="${build}"/> </target> <target name="dist" depends="compile"> <mkdir dir="${dist}/lib"/> <jar jarfile="${dist}/lib/MyProject.jar" basedir="${build}"/> </target> <target name="clean"> <delete dir="${build}"/> <delete dir="${dist}"/> </target> </project>
  • 43.
  • 44.
    package templates; import java.util.*; importjava.io.Serializable; import javax.persistence.*; @SuppressWarnings("serial") @Entity public class Customer implements Serializable { ! private Long id; ! private String name; ! private Address address; ! private Set<Order> orders = new HashSet<Order>(); ! // No-arg constructor ! public Customer() { ! } ! @Id ! public Long getId() { ! ! return id; ! } ! public void setId(Long id) { ! ! this.id = id; ! } ! public String getName() { ! ! return name; ! } ! public void setName(String name) { ! ! this.name = name; ! } ! public Address getAddress() { ! ! return address; ! } ! public void setAddress(Address address) { ! ! this.address = address; ! } ! @OneToMany ! public Collection<Order> getOrders() { ! ! return orders; ! } ! public void setOrders(Set<Order> orders) { ! ! this.orders = orders; ! } }
  • 45.
    package templates; import java.io.Serializable; importjava.util.*; import javax.persistence.*; @SuppressWarnings("serial") @Entity public class Customer implements Serializable { ! private Long id; ! private String name; ! private Address address; ! private Set<Order> orders = new HashSet<Order>(); ! // No-arg constructor ! public Customer() { ! } ! @Id ! public Long getId() { ! ! return id; ! } ! public void setId(Long id) { ! ! this.id = id; ! } ! public String getName() { ! ! return name; ! } ! public void setName(String name) { ! ! this.name = name; ! } ! public Address getAddress() { ! ! return address; ! } ! public void setAddress(Address address) { ! ! this.address = address; ! } ! @OneToMany ! public Collection<Order> getOrders() { ! ! return orders; ! } ! public void setOrders(Set<Order> orders) { ! ! this.orders = orders; ! } }
  • 46.
    entity Customer { !property name : String ! property address : Address ! property orders : Order[] } POJOs DAOs
  • 47.
  • 48.
    <entity name="Customer"> <attributetype="String" name="name"/> <findMethod name="findFixed"> <expression> <equals> <attributeRef attr="name"/> <constant val="John Doe"/> </equals> </expression> <findMethod> </entity> entity Customer { ! property name : String ! finder findFixed : name = "John Doe" }
  • 49.
    Demo ! Implement simpleEntity DSL ! Use prepared Generator
  • 50.
    grammar org.xtext.webinar.Entity ! with org.eclipse.xtext.common.Terminals entity generate entity "http://www.xtext.org/webinar/Entity" Model Model: types ! (elements+=Type)*; * Type: Type name: EString ! SimpleType | Entity; SimpleType: ! 'type' name=ID; SimpleType Entity Entity: extends ! 'entity' name=ID ('extends' extends=[Entity])? '{' properties ! ! properties+=Property* * ! '}'; Property name: EString type many: EBoolean Property: ! 'property' name=ID ':' type=[Type] (many?='[]')?;
  • 51.
    grammar org.xtext.webinar.Entity ! with org.eclipse.xtext.common.Terminals entity generate entity "http://www.xtext.org/webinar/Entity" Model Model: types ! (elements+=Type)*; * Type: Type name: EString ! SimpleType | Entity; SimpleType: ! 'type' name=ID; SimpleType Entity Entity: extends ! 'entity' name=ID ('extends' extends=[Entity])? '{' properties ! ! properties+=Property* * ! '}'; Property name: EString type many: EBoolean Property: ! 'property' name=ID ':' type=[Type] (many?='[]')?;
  • 52.
    grammar org.xtext.webinar.Entity ! with org.eclipse.xtext.common.Terminals entity generate entity "http://www.xtext.org/webinar/Entity" Model Model: types ! (elements+=Type)*; * Type: Type name: EString ! SimpleType | Entity; SimpleType: ! 'type' name=ID; SimpleType Entity Entity: extends ! 'entity' name=ID ('extends' extends=[Entity])? '{' properties ! ! properties+=Property* * ! '}'; Property name: EString type many: EBoolean Property: ! 'property' name=ID ':' type=[Type] (many?='[]')?;
  • 53.
    grammar org.xtext.webinar.Entity ! with org.eclipse.xtext.common.Terminals entity generate entity "http://www.xtext.org/webinar/Entity" Model Model: types ! (elements+=Type)*; * Type: Type name: EString ! SimpleType | Entity; SimpleType: ! 'type' name=ID; SimpleType Entity Entity: extends ! 'entity' name=ID ('extends' extends=[Entity])? '{' properties ! ! properties+=Property* * ! '}'; Property name: EString type many: EBoolean Property: ! 'property' name=ID ':' type=[Type] (many?='[]')?;
  • 54.
    grammar org.xtext.webinar.Entity ! with org.eclipse.xtext.common.Terminals entity generate entity "http://www.xtext.org/webinar/Entity" Model Model: types ! (elements+=Type)*; * Type: Type name: EString ! SimpleType | Entity; SimpleType: ! 'type' name=ID; SimpleType Entity Entity: extends ! 'entity' name=ID ('extends' extends=[Entity])? '{' properties ! ! properties+=Property* * ! '}'; Property name: EString type many: EBoolean Property: ! 'property' name=ID ':' type=[Type] (many?='[]')?;
  • 55.
    grammar org.xtext.webinar.Entity ! with org.eclipse.xtext.common.Terminals entity generate entity "http://www.xtext.org/webinar/Entity" Model Model: types ! (elements+=Type)*; * Type: Type name: EString ! SimpleType | Entity; SimpleType: ! 'type' name=ID; SimpleType Entity Entity: extends ! 'entity' name=ID ('extends' extends=[Entity])? '{' properties ! ! properties+=Property* * ! '}'; Property name: EString type many: EBoolean Property: ! 'property' name=ID ':' type=[Type] (many?='[]')?;
  • 56.
    grammar org.xtext.webinar.Entity ! with org.eclipse.xtext.common.Terminals entity generate entity "http://www.xtext.org/webinar/Entity" Model Model: types ! (elements+=Type)*; * Type: Type name: EString ! SimpleType | Entity; SimpleType: ! 'type' name=ID; SimpleType Entity Entity: extends ! 'entity' name=ID ('extends' extends=[Entity])? '{' properties ! ! properties+=Property* * ! '}'; Property name: EString type many: EBoolean Property: ! 'property' name=ID ':' type=[Type] (many?='[]')?;
  • 57.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
    Use a DSLto develop your tools
  • 64.
  • 65.
    twitter @HBehrens blog http://HeikoBehrens.net mail Heiko.Behrens@itemis.de xing http://www.xing.com/profile/Heiko_Behrens linkedin http://www.linkedin.com/in/HeikoBehrens www.xtext.org The Committer Team twitter @Xtext Heiko Michael Sven Moritz Peter Dennis Jan Patrick Knut Sebastian Behrens Clay Efftinge Eysholdt Friese Hübner Köhnlein Schönbach Wannheden Zarnekow