Xbase - Implementing Domain-Specific Languages for Java
1. Implementing Domain-Specific
Languages for Java
Sven Efftinge
Wilhelm Hasselbring
Moritz Eysholdt
Robert von Massow
Jan Köhnlein
Michael Hanus
Sebastian Zarnekow
2. Agenda
• What is Xtext?
• Motivation
• Xbase Architecture
•A Reusable language - What is the Interface?
• Real World Applications
3. grammar org.example.domainmodel.DomainModel
with org.eclipse.xtext.common.Terminals
generate domainmodel
"http://www.example.org/domainmodel/Domainmodel"
example DSL
Domainmodel :
elements += Type*;
Type:
DataType |
datatype String
Entity;
entity Person {
name : String
DataType:
givenName : String
'datatype' name = ID;
address : Address
}
Entity:
entity Address {
'entity' name = ID
street : String
('extends' superType = [Entity])? '{'
zip : String
features += Feature*
city : String
'}';
}
Feature:
object
instance name = ID ':' type = [Type];
grammar
5. Motivation
How to add behavior to your DSL?
• Old: Generation Gap Pattern • Better: Make DSL more
Powerful
• generate abstract class
• designing expression languages
• handwrite concrete subclass is hard
• expression grammar
• type system
• compiler
• expressions are very similar
across DSLs
6. Xbase
A reusable Expression Language
Grammar (Parser, Lexer)
Operator Overloading
Lambda Expressions
Extension Methods
Linker
Control Structures
Arithmetic, Logic
Java Callout / -in
Type System
Interpreter / Compiler
Advanced Editor
Eclipse Workbench Integration
Debugger
Parser Serializer Advanced Editor
Eclipse Platform EMF Antlr
7. Xbase is fun
(this is Xbase embedded into Xtend)
class Movies {
@Test def void sumOfVotesOfTop2() {
val movies = movies.sortBy[-rating].take(2).map[numberOfVotes].reduce[a, b| a + b]
assertEquals(47_229, movies)
}
val movies = new FileReader('data.csv').readLines.map[ line |
val segments = line.split(' ').iterator
return new Movie(
segments.next,
Double::parseDouble(segments.next),
Long::parseLong(segments.next),
)
]
}
1. Read file into List<Movie>
@Data class Movie {
String title
double rating
}
long numberOfVotes
2. Filter/Map/Reduce List
data.csv
A Few Good Men 7.6 68236
Empire Records 6.4 20780
"Rome" 9.2 21278
Witness for the Prosecution 8.4 20202
8. Xbase is fun
(this is Xbase embedded into Xtend)
class Movies {
@Test def void sumOfVotesOfTop2() {
val movies = movies.sortBy[-rating].take(2).map[numberOfVotes].reduce[a, b| a + b]
Method
}
assertEquals(47_229, movies)
Body
val movies = new FileReader('data.csv').readLines.map[ line |
val segments = line.split(' ').iterator
return new Movie(
Field
segments.next,
Double::parseDouble(segments.next),
Initialization
Long::parseLong(segments.next),
)
]
}
@Data class Movie {
String title
double rating
long numberOfVotes
}
data.csv
A Few Good Men 7.6 68236
Empire Records 6.4 20780
"Rome" 9.2 21278
Witness for the Prosecution 8.4 20202
9. Xbase is fun
(this is Xbase embedded into Xtend)
class Movies {
@Test def void sumOfVotesOfTop2() {
val movies = movies.sortBy[-rating].take(2).map[numberOfVotes].reduce[a, b| a + b]
assertEquals(47_229, movies)
}
val movies = new FileReader('data.csv').readLines.map[ line |
val segments = line.split(' ').iterator
return new Movie(
segments.next,
Double::parseDouble(segments.next),
Long::parseLong(segments.next),
)
]
}
@Data class Movie {
String title
double rating
long numberOfVotes
Extension Methods
}
data.csv
A Few Good Men 7.6 68236
Empire Records 6.4 20780
"Rome" 9.2 21278
Witness for the Prosecution 8.4 20202
10. Xbase is fun
(this is Xbase embedded into Xtend)
class Movies {
@Test def void sumOfVotesOfTop2() {
val movies = movies.sortBy[-rating].take(2).map[numberOfVotes].reduce[a, b| a + b]
assertEquals(47_229, movies)
}
val movies = new FileReader('data.csv').readLines.map[ line |
val segments = line.split(' ').iterator
return new Movie(
segments.next,
Double::parseDouble(segments.next),
Long::parseLong(segments.next),
)
]
}
@Data class Movie {
String title
double rating
long numberOfVotes
Lambda Expressions
}
data.csv
A Few Good Men 7.6 68236
Empire Records 6.4 20780
"Rome" 9.2 21278
Witness for the Prosecution 8.4 20202
11. Xbase is fun
(this is Xbase embedded into Xtend)
class Movies {
@Test def void sumOfVotesOfTop2() {
val movies = movies.sortBy[-rating].take(2).map[numberOfVotes].reduce[a, b| a + b]
assertEquals(47_229, movies)
}
val movies = new FileReader('data.csv').readLines.map[ line |
val segments = line.split(' ').iterator
return new Movie(
segments.next,
Double::parseDouble(segments.next),
Long::parseLong(segments.next),
)
]
}
@Data class Movie {
String title
double rating
long numberOfVotes
Type Inference
}
data.csv
A Few Good Men 7.6 68236
Empire Records 6.4 20780
"Rome" 9.2 21278
Witness for the Prosecution 8.4 20202
12. REUSE A LANGUAGE??
How to integrate it? What is the interface?
Grammar (Parser, Lexer)
Linker
Type System
MyLanguage Interpreter / Compiler
Advanced Editor
Eclipse Workbench Integration
Debugger
bad, since this is not an abstraction:
it doesn’t hide complexity from the client
13. REUSE A LANGUAGE??
How to integrate it? What is the interface?
grammar inheritance
Grammar (Parser, Lexer)
Linker
Type System
JvmModel
MyLanguage Interpreter / Compiler
Advanced Editor
Eclipse Integration
Debugger
JvmModelInferrer (M2M transformation)
15. JvmModel Inference
(M2M transformation with trace)
MyLanguage Instance MyLanguage JvmModel (serialized)
package my.social.network;
package my.social.network {
(imports)
import java.util.List public class Person {
private String firstName;
private String lastName;
entity Person { private List<Person> friends;
firstName : String (getter, setter)
lastName : String
public String getFullName() {
friends : List<Person> String _plus = (this.firstName + " ");
return (_plus + this.lastName);
op getFullName() : String { }
return firstName + " " + lastName public List<Person> getSortedFriends() {
} final Function1<Person,String> _function =
new Function1<Person,String>() {
public String apply(final Person it) {
op getSortedFriends() : List<Person> { String _fullName = it.getFullName();
return _fullName;
return friends.sortBy[fullName] }
} };
return IterableExtensions.<Person, String>
} sortBy(this.friends, _function);
} }
}
Syntax, inherited from Xbase Xbase compiler output
16. JvmModel Inference
MyLanguage JvmModel (serialized)
package my.social.network;
Embedding Xbase
(imports)
public class Person {
expressions private String firstName;
private String lastName;
private List<Person> friends;
into Java methods (getter, setter)
gives them a public String getFullName() {
String _plus = (this.firstName + " ");
context!
return (_plus + this.lastName);
}
public List<Person> getSortedFriends() {
final Function1<Person,String> _function =
new Function1<Person,String>() {
public String apply(final Person it) {
String _fullName = it.getFullName();
return _fullName;
}
};
return IterableExtensions.<Person, String>
sortBy(this.friends, _function);
}
}
17. the last slide was really important,
let us go back one more time.
18. JvmModel Inference
MyLanguage JvmModel (serialized)
package my.social.network;
Embedding Xbase
(imports)
public class Person {
expressions private String firstName;
private String lastName;
private List<Person> friends;
into Java methods (getter, setter)
gives them a public String getFullName() {
String _plus = (this.firstName + " ");
context!
return (_plus + this.lastName);
}
public List<Person> getSortedFriends() {
final Function1<Person,String> _function =
new Function1<Person,String>() {
public String apply(final Person it) {
String _fullName = it.getFullName();
return _fullName;
}
};
return IterableExtensions.<Person, String>
sortBy(this.friends, _function);
}
}
19. JvmModel Inference
MyLanguage JvmModel (serialized)
package my.social.network;
(imports)
public class Person {
private String firstName;
context! private String lastName;
private List<Person> friends;
(getter, setter)
...for linking public String getFullName() {
String _plus = (this.firstName + " ");
return (_plus + this.lastName);
(as implemented by scoping) }
•names of method parameters public List<Person> getSortedFriends() {
final Function1<Person,String> _function =
•names of member fields new Function1<Person,String>() {
public String apply(final Person it) {
•names of member methods String _fullName = it.getFullName();
return _fullName;
•names of visible types };
}
return IterableExtensions.<Person, String>
sortBy(this.friends, _function);
}
}
20. JvmModel Inference
MyLanguage JvmModel (serialized)
package my.social.network;
(imports)
context! public class Person {
private String firstName;
private String lastName;
private List<Person> friends;
...for the Type System (getter, setter)
public String getFullName() {
String _plus = (this.firstName + " ");
return (_plus + this.lastName);
• a method’s return type is the }
expected type of an expression public List<Person> getSortedFriends() {
final Function1<Person,String> _function =
• fields, variables and parameters
new Function1<Person,String>() {
public String apply(final Person it) {
String _fullName = it.getFullName();
have types return _fullName;
}
• generated java classes are };
return IterableExtensions.<Person, String>
available as new types sortBy(this.friends, _function);
}
}
21. JvmModel Inference
MyLanguage JvmModel (serialized)
package my.social.network;
(imports)
public class Person {
private String firstName;
private String lastName;
context!
private List<Person> friends;
(getter, setter)
public String getFullName() {
String _plus = (this.firstName + " ");
...for the Compiler }
return (_plus + this.lastName);
public List<Person> getSortedFriends() {
final Function1<Person,String> _function =
• actually, the serialized JvmModel
new Function1<Person,String>() {
public String apply(final Person it) {
String _fullName = it.getFullName();
is the compiler output :) return _fullName;
}
};
return IterableExtensions.<Person, String>
sortBy(this.friends, _function);
}
}
22. Real World Applications
• Learning By Example: 7 Languages For The JVM - http://www.eclipse.org/Xtext/7languages.html
• Build Language
• DSL for Guice
• Template Language
• Scripting Language
• DSL for MongoDB
• HTTP routing language
• Little Tortoise
• Xtend - Java-like GPL that also supports functional programming and has powerful type inference
• http://www.eclipse.org/xtend/
• DESAGN - textually define 3D models of cutting tools (physical tools)
• http://www.eclipsecon.org/europe2012/sessions/desagn-xtext-cutting-edge
• openHAB - open Home Automation Bus - Program the behavior of your house!
• http://code.google.com/p/openhab/
• spray - Generate graphical Eclipse editors for the Graphiti framework
• http://eclipselabs.org/p/spray/
• Jnario - Executable Specifications for Java (Behavior Driven Development, BDD)
• http://jnario.org