Building DSLs with Xtext - Eclipse Modeling Day 2009

Preview:

DESCRIPTION

Slides of Eclipse Modeling Day in New York and Toronto http://wiki.eclipse.org/Eclipse_Modeling_Day Motivation of specific tools with apple corer analogy, Example of domain-specific language (chess notation), introduction to Xtext with demo plus outlook

Citation preview

© itemis AG 2009 – All rights reserved

Building DSLs with Xtext

Eclipse Modeling Day

New York, 16 November 2009

Toronto, 18 November 2009

Heiko Behrens (itemis)

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 toolfor a specific job

A specific toolfor 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

Rd2-c2 ,rook at d2 moves to c2.”

Queen to c7.“”

Check.

Moves in Chess:

!ook at a1 moves to a5.

"ishop at c8 captures knight at h3.

# b1 x c3

$2 - g4

Piece

Piece

Piece

Square

Square

Square

Square

Action

Action

Action

Action

Destination

Destination

Destination

Destination

Rook a1 move a5

Bishop c8 capture h3 Knight

Knight b1 capture c3 Queen

Pawn g2 move g4

SourceDestinationPiece

Move

WhitePlayerBlackPlayer

Game«enum»

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.

Superclass

Subclass Class

ecore meta modelLL(*) Parser editor

Model

Grammar

Generator

Runtime

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';

© itemis AG 2009 – All rights reserved

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

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>

vs.

Entities by Example

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 Customer {

! property name : String

! finder findFixed : name = "John Doe"

}

<entity name="Customer">

<attribute type="String" name="name"/>

<findMethod name="findFixed"> <expression> <equals> <attributeRef attr="name"/> <constant val="John Doe"/> </equals> </expression> <findMethod></entity>

Demo

! Implement simple Entity DSL

! Use prepared Generator

entity

*

*

Model

name: EStringType

SimpleType

Entity

name: EStringmany: EBoolean

Property

types

extends

properties

type

grammar org.xtext.webinar.Entity

! with org.eclipse.xtext.common.Terminals

generate entity

"http://www.xtext.org/webinar/Entity"

Model:

! (elements+=Type)*;

Type:

! SimpleType | Entity;

SimpleType:

! 'type' name=ID;

Entity:

! 'entity' name=ID

('extends' extends=[Entity])? '{'

! ! properties+=Property*

! '}';

Property:

! 'property' name=ID ':'

type=[Type] (many?='[]')?;

entity

*

*

Model

name: EStringType

SimpleType

Entity

name: EStringmany: EBoolean

Property

types

extends

properties

type

grammar org.xtext.webinar.Entity

! with org.eclipse.xtext.common.Terminals

generate entity

"http://www.xtext.org/webinar/Entity"

Model:

! (elements+=Type)*;

Type:

! SimpleType | Entity;

SimpleType:

! 'type' name=ID;

Entity:

! 'entity' name=ID

('extends' extends=[Entity])? '{'

! ! properties+=Property*

! '}';

Property:

! 'property' name=ID ':'

type=[Type] (many?='[]')?;

entity

*

*

Model

name: EStringType

SimpleType

Entity

name: EStringmany: EBoolean

Property

types

extends

properties

type

grammar org.xtext.webinar.Entity

! with org.eclipse.xtext.common.Terminals

generate entity

"http://www.xtext.org/webinar/Entity"

Model:

! (elements+=Type)*;

Type:

! SimpleType | Entity;

SimpleType:

! 'type' name=ID;

Entity:

! 'entity' name=ID

('extends' extends=[Entity])? '{'

! ! properties+=Property*

! '}';

Property:

! 'property' name=ID ':'

type=[Type] (many?='[]')?;

entity

*

*

Model

name: EStringType

SimpleType

Entity

name: EStringmany: EBoolean

Property

types

extends

properties

type

grammar org.xtext.webinar.Entity

! with org.eclipse.xtext.common.Terminals

generate entity

"http://www.xtext.org/webinar/Entity"

Model:

! (elements+=Type)*;

Type:

! SimpleType | Entity;

SimpleType:

! 'type' name=ID;

Entity:

! 'entity' name=ID

('extends' extends=[Entity])? '{'

! ! properties+=Property*

! '}';

Property:

! 'property' name=ID ':'

type=[Type] (many?='[]')?;

entity

*

*

Model

name: EStringType

SimpleType

Entity

name: EStringmany: EBoolean

Property

types

extends

properties

type

grammar org.xtext.webinar.Entity

! with org.eclipse.xtext.common.Terminals

generate entity

"http://www.xtext.org/webinar/Entity"

Model:

! (elements+=Type)*;

Type:

! SimpleType | Entity;

SimpleType:

! 'type' name=ID;

Entity:

! 'entity' name=ID

('extends' extends=[Entity])? '{'

! ! properties+=Property*

! '}';

Property:

! 'property' name=ID ':'

type=[Type] (many?='[]')?;

entity

*

*

Model

name: EStringType

SimpleType

Entity

name: EStringmany: EBoolean

Property

types

extends

properties

type

grammar org.xtext.webinar.Entity

! with org.eclipse.xtext.common.Terminals

generate entity

"http://www.xtext.org/webinar/Entity"

Model:

! (elements+=Type)*;

Type:

! SimpleType | Entity;

SimpleType:

! 'type' name=ID;

Entity:

! 'entity' name=ID

('extends' extends=[Entity])? '{'

! ! properties+=Property*

! '}';

Property:

! 'property' name=ID ':'

type=[Type] (many?='[]')?;

entity

*

*

Model

name: EStringType

SimpleType

Entity

name: EStringmany: EBoolean

Property

types

extends

properties

type

grammar org.xtext.webinar.Entity

! with org.eclipse.xtext.common.Terminals

generate entity

"http://www.xtext.org/webinar/Entity"

Model:

! (elements+=Type)*;

Type:

! SimpleType | Entity;

SimpleType:

! 'type' name=ID;

Entity:

! 'entity' name=ID

('extends' extends=[Entity])? '{'

! ! properties+=Property*

! '}';

Property:

! 'property' name=ID ':'

type=[Type] (many?='[]')?;

my WritePimp

Whitespace-Aware

Languages

Incremental Generation

Conclusion

Abstraction

Use a DSL to develop your tools

SupportNewsgroupCommunity ForumProfessional Support

@HBehrenshttp://HeikoBehrens.net

Heiko.Behrens@itemis.dehttp://www.xing.com/profile/Heiko_Behrenshttp://www.linkedin.com/in/HeikoBehrens

twitterblog

mailxinglinkedin

www.xtext.org@XtexttwitterThe Committer Team

JanKöhnlein

DennisHübner

MoritzEysholdt

PeterFriese

MichaelClay

PatrickSchönbach

KnutWannheden

SebastianZarnekow

HeikoBehrens

Sven Efftinge

Recommended