going to mars with groovy domain-specific languages

162
Groovy Domain Specific Languages Guillaume Laforge Groovy Project Manager SpringSource / VMware @glaforge 1

Upload: guillaume-laforge

Post on 17-May-2015

17.868 views

Category:

Technology


2 download

DESCRIPTION

Practical example of implementing and evolving a simple DSL in Groovy, to drive a robot rover on the planet Mars.

TRANSCRIPT

Page 1: Going to Mars with Groovy Domain-Specific Languages

GroovyDomainSpecificLanguages

Guillaume LaforgeGroovy Project ManagerSpringSource / VMware

@glaforge

1

Page 2: Going to Mars with Groovy Domain-Specific Languages

ГИЙОМЛАФОРЖ

Page 3: Going to Mars with Groovy Domain-Specific Languages

Guillaume Laforge

• Groovy Project Manager at VMware

• Initiator of the Grails framework

• Creator of the Gaelyk and Caelyf toolkits

• Co-author of Groovy in Action

• Follow me on...

• My blog: http://glaforge.appspot.com

• Twitter: @glaforge

• Google+: http://gplus.to/glaforge3

Page 4: Going to Mars with Groovy Domain-Specific Languages

IntroductionDefinition, Examples, Goals, Pros & Cons

4

Page 5: Going to Mars with Groovy Domain-Specific Languages

Domain-Specific Languages

• Wikipedia definition

A Domain-Specific Language is a programming language or executable specification language that offers, through appropriate notations and abstractions, expressive power focused on, and usually restricted to, a particular problem domain.

• In contrast to General Purprose Languages

• Also known as: fluent / human interfaces, language oriented programming, little or mini languages, macros, business natural languages...

5

{ }

Page 6: Going to Mars with Groovy Domain-Specific Languages

Technical examples

<?xml version="1.0"?><xsl:stylesheetversion="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml"/> <xsl:template match="*"> <xsl:element name="{name()}"> <xsl:for-each select="@*"> <xsl:element name="{name()}"> <xsl:value-of select="."/> </xsl:element> </xsl:for-each> <xsl:apply-templates select="*|text()"/> </xsl:element> </xsl:template> </xsl:stylesheet>

<?xml version="1.0"?><GTK-Interface><widget> <class>GtkWindow</class> <name>HelloWindow</name> <border_width>5</border_width> <Signal> <name>destroy</name> <handler>gtk_main_quit</handler> </Signal> <title>Hello</title> <type>GTK_WINDOW_TOPLEVEL</type> <position>GTK_WIN_POS_NONE</position> <allow_shrink>True</allow_shrink> <allow_grow>True</allow_grow> <auto_shrink>False</auto_shrink> <widget> <class>GtkButton</class> <name>Hello World</name> <can_focus>True</can_focus> <label>Hello World</label> </widget></widget></GTK-Interface>

# Poll this site first each cycle.poll pop.provider.net proto pop3 user "jsmith" with pass "secret1" is "smith" here user jones with pass "secret2" is "jjones" here with options keep

# Poll this site second, unless Lord Voldemort zaps us first.poll billywig.hogwarts.com with proto imap: user harry_potter with pass "floo" is harry_potter here

# Poll this site third in the cycle. # Password will be fetched from ~/.netrcpoll mailhost.net with proto imap: user esr is esr here

Glade XSLT

fetchmail

Regex"x.z?z{1,3}y"

SQLSELECT * FROM TABLEWHERE NAME LIKE '%SMI'ORDER BY NAME

Page 7: Going to Mars with Groovy Domain-Specific Languages

Antimalaria drug resistance simulation

HR skills representationInsurance policy risk calculation engine

Market data feeds analysis Loan acceptance rules engine

Nuclear safety simulations

Page 8: Going to Mars with Groovy Domain-Specific Languages

Goals of DSLs

• Use a more expressive language than a general-purpose one

• Share a common metaphor of understanding between developers and subject matter experts

• Have domain experts help with the design of the business logic of an application

• Avoid cluttering business code with too much boilerplate technical code thanks to a clean separation

• Let business rules have their own lifecycle

8

Page 9: Going to Mars with Groovy Domain-Specific Languages

Pros and cons

Pros• Domain experts can help, validate,

modify, and often develop DSL programs

• Somewhat self-documenting

• Enhance quality, productivity, reliability, maintainability, portability, reusability

• Safety; as long as the language constructs are safe, any DSL sentence can be considered safe

Cons• Learning cost vs. limited applicability

• Cost of designing, implementing & maintaining DSLs as well as tools/IDEs

• Attaining proper scope

• Trade-offs between domain specificity and general purpose language constructs

• Efficiency cost

• Proliferation of similar non-standard DSLs

9

Page 10: Going to Mars with Groovy Domain-Specific Languages

Groovy provides...

• A flexible and malleable syntax

• scripts, native syntax constructs (list, map, ranges), closures, less punctuation...

• Compile-time and runtime meta-programming

• metaclasses, AST transformations

• also operator overloading

• The ability to easily integrate into Java / Spring apps

• also security and safety

10

Page 11: Going to Mars with Groovy Domain-Specific Languages

Let’s get started!

11

Page 12: Going to Mars with Groovy Domain-Specific Languages
Page 13: Going to Mars with Groovy Domain-Specific Languages

Your mission: build a DSL for a Mars robot

Page 14: Going to Mars with Groovy Domain-Specific Languages

We need a robot!

14

class!Robot!{}

Page 15: Going to Mars with Groovy Domain-Specific Languages

It should move...

15

class!Robot!{!!!!void)move()!{}}

Page 16: Going to Mars with Groovy Domain-Specific Languages

..in a direction!

16

class!Robot!{!!!!void)move(String!dir)!{}}

Page 17: Going to Mars with Groovy Domain-Specific Languages

More explicit direction

17

class!Robot!{!!!!void)move(Direction!dir)!{}}

enum!Direction!{!!!!left,!right,!forward,!backward}

Page 18: Going to Mars with Groovy Domain-Specific Languages

Now how can we control it?

18

import)static)mars.Direction.*;import)mars.Robot;

public)class)Command!{))))public)static)void)main(String[]!args)!{!!!!!!!!Robot!robot!=)new!Robot();!!!!!!!!robot.move(left);!!!!}}

Page 19: Going to Mars with Groovy Domain-Specific Languages

Now how can we control it?

18

import)static)mars.Direction.*;import)mars.Robot;

public)class)Command!{))))public)static)void)main(String[]!args)!{!!!!!!!!Robot!robot!=)new!Robot();!!!!!!!!robot.move(left);!!!!}} Syntactical

noise!

Page 20: Going to Mars with Groovy Domain-Specific Languages

Now how can we control it?

18

import)static)mars.Direction.*;import)mars.Robot;

public)class)Command!{))))public)static)void)main(String[]!args)!{!!!!!!!!Robot!robot!=)new!Robot();!!!!!!!!robot.move(left);!!!!}} Syntactical

noise!

))))))))))))))))))))))))))))))—)))))))))))))))))—

——————————————————————))))————————————————————————————————————————))))))))—————))))))))))))))))))))—))))))))))))))))))—))))——))))——

Page 21: Going to Mars with Groovy Domain-Specific Languages

Scripts vs ClassesOptional semicolons & parens

19

import)static)mars.Direction.*import)mars.Robot

!!!!!!!!def))!robot!=)new!Robot()!!!!!!!!robot.move!left

Page 22: Going to Mars with Groovy Domain-Specific Languages

Scripts vs ClassesOptional semicolons & parens

19

import)static)mars.Direction.*import)mars.Robot

!!!!!!!!def))!robot!=)new!Robot()!!!!!!!!robot.move!left

Optional typing

Page 23: Going to Mars with Groovy Domain-Specific Languages

Scripts vs ClassesOptional semicolons & parens

19

import)static)mars.Direction.*import)mars.Robot

!!!!!!!!def))!robot!=)new!Robot()!!!!!!!!robot.move!left

But I don’t want to compile a script for

every command!

Optional typing

Page 24: Going to Mars with Groovy Domain-Specific Languages

Integration

Page 25: Going to Mars with Groovy Domain-Specific Languages

GroovyShell to the rescue

21

Page 26: Going to Mars with Groovy Domain-Specific Languages

GroovyShell to the rescue

21

def$shell%=$new%GroovyShell()shell.evaluate(%%%%new%File("command.groovy"))

Page 27: Going to Mars with Groovy Domain-Specific Languages

GroovyShell to the rescue

21

def$shell%=$new%GroovyShell()shell.evaluate(%%%%new%File("command.groovy"))

integration.groovy

Page 28: Going to Mars with Groovy Domain-Specific Languages

GroovyShell to the rescue

21

import$static$mars.Direction.*import$mars.Robot

def$robot%=$new%Robot()robot.move%left

def$shell%=$new%GroovyShell()shell.evaluate(%%%%new%File("command.groovy"))

integration.groovy

Page 29: Going to Mars with Groovy Domain-Specific Languages

GroovyShell to the rescue

21

import$static$mars.Direction.*import$mars.Robot

def$robot%=$new%Robot()robot.move%left

def$shell%=$new%GroovyShell()shell.evaluate(%%%%new%File("command.groovy"))

integration.groovy

command.groovy

Page 30: Going to Mars with Groovy Domain-Specific Languages

Integration mechanisms

• Different solutions available:

• Groovy’s own mechanisms

• GroovyScriptEngine, Eval,GroovyClassLoader, GroovyShell

• Java 6: javax.script.* / JSR-223

• Groovy provides a JSR-223 implementation

• Spring’s lang namespace

• Groovy provides the highest level of flexibility and customization, but JSR-223 is a standard...

22

Page 31: Going to Mars with Groovy Domain-Specific Languages

Integration mechanisms

• Different solutions available:

• Groovy’s own mechanisms

• GroovyScriptEngine, Eval,GroovyClassLoader, GroovyShell

• Java 6: javax.script.* / JSR-223

• Groovy provides a JSR-223 implementation

• Spring’s lang namespace

• Groovy provides the highest level of flexibility and customization, but JSR-223 is a standard...

22

Page 32: Going to Mars with Groovy Domain-Specific Languages

What’s wrong with our DSL?

23

import)static)mars.Direction.*import)mars.Robot

def)robot!=)new!Robot()robot.move!left

Page 33: Going to Mars with Groovy Domain-Specific Languages

What’s wrong with our DSL?

23

import)static)mars.Direction.*import)mars.Robot

def)robot!=)new!Robot()robot.move!left

Can’t we hide those imports?

Page 34: Going to Mars with Groovy Domain-Specific Languages

What’s wrong with our DSL?

23

import)static)mars.Direction.*import)mars.Robot

def)robot!=)new!Robot()robot.move!left

Can’t we hide those imports?

Can’t we inject the robot?

Page 35: Going to Mars with Groovy Domain-Specific Languages

What’s wrong with our DSL?

23

import)static)mars.Direction.*import)mars.Robot

def)robot!=)new!Robot()robot.move!left

Can’t we hide those imports?

Can’t we inject the robot?Do we really need to

repeat ‘robot’?

Page 36: Going to Mars with Groovy Domain-Specific Languages

I’m sorry Dave,you can’t do that!

Page 37: Going to Mars with Groovy Domain-Specific Languages

I’m sorry Dave,you can’t do that!

Page 38: Going to Mars with Groovy Domain-Specific Languages

What we really want is...

25

!move!left!

Page 39: Going to Mars with Groovy Domain-Specific Languages

Let’s inject a robot!

• We can pass data in / out of scripts through the Binding

• it’s basically just like a map of variable name keys and their associated values

26

Page 40: Going to Mars with Groovy Domain-Specific Languages

Let’s inject a robot!

• We can pass data in / out of scripts through the Binding

• it’s basically just like a map of variable name keys and their associated values

26

def)binding!=)new!Binding([!!!!robot:!new!Robot()])def)shell!=)new!GroovyShell(binding)shell.evaluate(!!!!new!File("command.groovy"))

Page 41: Going to Mars with Groovy Domain-Specific Languages

Let’s inject a robot!

• We can pass data in / out of scripts through the Binding

• it’s basically just like a map of variable name keys and their associated values

26

def)binding!=)new!Binding([!!!!robot:!new!Robot()])def)shell!=)new!GroovyShell(binding)shell.evaluate(!!!!new!File("command.groovy"))

integration.groovy

Page 42: Going to Mars with Groovy Domain-Specific Languages

Better?

27

import)static)mars.Direction.*

robot.move!left

Page 43: Going to Mars with Groovy Domain-Specific Languages

Better?

27

import)static)mars.Direction.*

robot.move!left

Robot import removed

Page 44: Going to Mars with Groovy Domain-Specific Languages

Better?

27

import)static)mars.Direction.*

robot.move!left

Robot import removed

Robot injected,no ‘new’ needed

Page 45: Going to Mars with Groovy Domain-Specific Languages

How to inject the direction?

• Using the binding...

28

def)binding!=)new!Binding([!!!!robot:!new!Robot(),!!!!left:!!!!!Direction.left,!!!!right:!!!!Direction.right,!!!!backward:!Direction.backward,!!!!forward:!!Direction.forward])def)shell!=)new!GroovyShell(binding)shell.evaluate(!!!!new!File("command.groovy"))

Page 46: Going to Mars with Groovy Domain-Specific Languages

How to inject the direction?

• Using the binding...

28

def)binding!=)new!Binding([!!!!robot:!new!Robot(),!!!!left:!!!!!Direction.left,!!!!right:!!!!Direction.right,!!!!backward:!Direction.backward,!!!!forward:!!Direction.forward])def)shell!=)new!GroovyShell(binding)shell.evaluate(!!!!new!File("command.groovy"))

Fragile in case of new directions!

Page 47: Going to Mars with Groovy Domain-Specific Languages

How to inject the direction?

• Using the binding...

29

def)binding!=)new!Binding([!!!!robot:!new!Robot(),!!!!*:!Direction.values()!!!!!!!!!!!!.collectEntries!{!!!!!!!!!!!!!!!![(it.name()):!it]!!!!!!!!!!!!}])def)shell!=)new!GroovyShell(binding)shell.evaluate(!!!!new!File("command.groovy"))

Page 48: Going to Mars with Groovy Domain-Specific Languages

How to inject the direction?

• Using compiler customizers...

• Let’s have a look at them

30

Page 49: Going to Mars with Groovy Domain-Specific Languages

Compilation customizers

• Ability to apply some customization to the Groovy compilation process

• Three available customizers

• ImportCustomizer: add transparent imports

• ASTTransformationCustomizer: injects an AST transform

• SecureASTCustomizer: restrict the groovy language to an allowed subset

• But you can implement your own

31

Page 50: Going to Mars with Groovy Domain-Specific Languages

Imports customizer

32

new!GroovyShell(new!Binding([robot:!new)Robot()]))!!!!.evaluate("import!static!Direction.*\n"!+!!!!!!!!!!!!!!"robot.move!left")

Page 51: Going to Mars with Groovy Domain-Specific Languages

Imports customizer

32

new!GroovyShell(new!Binding([robot:!new)Robot()]))!!!!.evaluate("import!static!Direction.*\n"!+!!!!!!!!!!!!!!"robot.move!left")

Cheat with string concatenation? Bad!

Page 52: Going to Mars with Groovy Domain-Specific Languages

Imports customizer

32

new!GroovyShell(new!Binding([robot:!new)Robot()]))!!!!.evaluate("import!static!Direction.*\n"!+!!!!!!!!!!!!!!"robot.move!left")

Page 53: Going to Mars with Groovy Domain-Specific Languages

Imports customizer

33

def!configuration!=!new!CompilerConfiguration()!def!imports!=!new!ImportCustomizer()imports.addStaticStar(mars.Direction.name)configuration.addCompilationCustomizers(imports)!!

new!GroovyShell(new!Binding([robot:!new)Robot()]),!!!!!!!!!!!!!!!!!!!!!!!!!configuration)!!!!.evaluate("robot.move!left")!!!!!!

Page 54: Going to Mars with Groovy Domain-Specific Languages

AST transformation customizer

34

def!configuration!=!new!CompilerConfiguration()!def!imports!=!new!ImportCustomizer()imports.addStaticStar(mars.Direction.name)configuration.addCompilationCustomizers(imports,!!!!!!!!!!!!!new!ASTTransformationCustomizer(Log))!new!GroovyShell(new!Binding([robot:!new)Robot()]),!!!!!!!!!!!!!!!!!!!!!!!!!configuration)!!!!.evaluate("robot.move!left"!+!"\n"!!!!!!!!!!!!!!"log.info!‘Robot!moved’")!!!!!!!!!!!

Page 55: Going to Mars with Groovy Domain-Specific Languages

AST transformation customizer

34

def!configuration!=!new!CompilerConfiguration()!def!imports!=!new!ImportCustomizer()imports.addStaticStar(mars.Direction.name)configuration.addCompilationCustomizers(imports,!!!!!!!!!!!!!new!ASTTransformationCustomizer(Log))!new!GroovyShell(new!Binding([robot:!new)Robot()]),!!!!!!!!!!!!!!!!!!!!!!!!!configuration)!!!!.evaluate("robot.move!left"!+!"\n"!!!!!!!!!!!!!!"log.info!‘Robot!moved’")!!!!!!!!!!!

@Log injects a logger in scripts and classes

Page 56: Going to Mars with Groovy Domain-Specific Languages

Secure the onboard trajectory calculator

Page 57: Going to Mars with Groovy Domain-Specific Languages

Secure AST customizer

• Let’s setup our environment

• an import customizer to import java.lang.Math.*

• prepare a secure AST customizer

36

def%imports%=%new%ImportCustomizer().addStaticStars('java.lang.Math')def%secure%=%new%SecureASTCustomizer()

Idea: Secure the rocket’s onboard trajectory calculation system by allowing only math expressions to be evaluated by the calculator

Page 58: Going to Mars with Groovy Domain-Specific Languages

Secure AST customizer

37

...secure.with!{//!disallow!closure!creationclosuresAllowed!=!false!//!disallow!method!definitionsmethodDefinitionAllowed!=!false!

!//!empty!white!list!=>!forbid!importsimportsWhitelist!=![]!staticImportsWhitelist!=![]//!only!allow!the!java.lang.Math.*!static!importstaticStarImportsWhitelist!=!['java.lang.Math']

...

Page 59: Going to Mars with Groovy Domain-Specific Languages

Secure AST customizer

37

...secure.with!{//!disallow!closure!creationclosuresAllowed!=!false!//!disallow!method!definitionsmethodDefinitionAllowed!=!false!

!//!empty!white!list!=>!forbid!importsimportsWhitelist!=![]!staticImportsWhitelist!=![]//!only!allow!the!java.lang.Math.*!static!importstaticStarImportsWhitelist!=!['java.lang.Math']

...

Disallow closures and methods

Page 60: Going to Mars with Groovy Domain-Specific Languages

Secure AST customizer

37

...secure.with!{//!disallow!closure!creationclosuresAllowed!=!false!//!disallow!method!definitionsmethodDefinitionAllowed!=!false!

!//!empty!white!list!=>!forbid!importsimportsWhitelist!=![]!staticImportsWhitelist!=![]//!only!allow!the!java.lang.Math.*!static!importstaticStarImportsWhitelist!=!['java.lang.Math']

...

Disallow closures and methods

Black / white listimports

Page 61: Going to Mars with Groovy Domain-Specific Languages

Secure AST customizer

38

...//%language%tokens%allowedtokensWhitelist%=%[

PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,%COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,%COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL

]%

//%types%allowed%to%be%used%(including%primitive%types)constantTypesClassesWhiteList%=%[

Integer,%Float,%Long,%Double,%BigDecimal,%Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE

]%

//%classes%who%are%allowed%to%be%receivers%of%method%callsreceiversClassesWhiteList%=%[%

Math,%Integer,%Float,%Double,%Long,%BigDecimal%]}...

Page 62: Going to Mars with Groovy Domain-Specific Languages

Secure AST customizer

38

...//%language%tokens%allowedtokensWhitelist%=%[

PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,%COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,%COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL

]%

//%types%allowed%to%be%used%(including%primitive%types)constantTypesClassesWhiteList%=%[

Integer,%Float,%Long,%Double,%BigDecimal,%Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE

]%

//%classes%who%are%allowed%to%be%receivers%of%method%callsreceiversClassesWhiteList%=%[%

Math,%Integer,%Float,%Double,%Long,%BigDecimal%]}...

You can build a subset of the Groovy syntax!

Page 63: Going to Mars with Groovy Domain-Specific Languages

Secure AST customizer

38

...//%language%tokens%allowedtokensWhitelist%=%[

PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,%COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,%COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL

]%

//%types%allowed%to%be%used%(including%primitive%types)constantTypesClassesWhiteList%=%[

Integer,%Float,%Long,%Double,%BigDecimal,%Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE

]%

//%classes%who%are%allowed%to%be%receivers%of%method%callsreceiversClassesWhiteList%=%[%

Math,%Integer,%Float,%Double,%Long,%BigDecimal%]}...

You can build a subset of the Groovy syntax!

Black / white list usage of classes

Page 64: Going to Mars with Groovy Domain-Specific Languages

Secure AST customizer

• Ready to evaluate our flight equations!

• But the following would have failed:

39

shell.evaluate%'System.exit(0)'

def%config%=%new%CompilerConfiguration()config.addCompilationCustomizers(imports,%secure)

def%shell%=%new%GroovyShell(config)%shell.evaluate%'cos%PI/3'

Page 65: Going to Mars with Groovy Domain-Specific Languages

Back to our robot...

40

robot.move)left

Page 66: Going to Mars with Groovy Domain-Specific Languages

Back to our robot...

40

robot.move)left

Still need to get rid of the robot prefix!

Page 67: Going to Mars with Groovy Domain-Specific Languages

Can we remove it?

Page 68: Going to Mars with Groovy Domain-Specific Languages

Can we remove it?

да !

Page 69: Going to Mars with Groovy Domain-Specific Languages

How to remove the ‘robot’?

• Instead of calling the move() method on the robot instance, we should be able to call the move() method directly from within the script

• Two approaches:

42

• Inject a ‘move’ closure in the binding with a method pointer

• Use a base script class with a ‘move’ method delegating to the robot

Page 70: Going to Mars with Groovy Domain-Specific Languages

Inject a closure in the binding

43

def$robot%=%new%Robot()binding%=$new%Binding([%%%%robot:%robot,%%%%*:%Direction.values()%%%%%%%%%%%%.collectEntries%{%%%%%%%%%%%%%%%%[(it.name()):%it]%%%%%%%%%%%%},

%%%%move:%robot.&move])

Page 71: Going to Mars with Groovy Domain-Specific Languages

Inject a closure in the binding

43

def$robot%=%new%Robot()binding%=$new%Binding([%%%%robot:%robot,%%%%*:%Direction.values()%%%%%%%%%%%%.collectEntries%{%%%%%%%%%%%%%%%%[(it.name()):%it]%%%%%%%%%%%%},

%%%%move:%robot.&move])

Method pointer (a closure) on robot’s move instance method

Page 72: Going to Mars with Groovy Domain-Specific Languages

Define a base script class

44

abstract)class!RobotBaseScriptClass!!!!!!!!!!extends!Script!{!!!!void!move(Direction!dir)!{!!!!!!!!def)robot!=!this.binding.robot!!!!!!!!robot.move!dir!!!!}}

Page 73: Going to Mars with Groovy Domain-Specific Languages

Define a base script class

44

abstract)class!RobotBaseScriptClass!!!!!!!!!!extends!Script!{!!!!void!move(Direction!dir)!{!!!!!!!!def)robot!=!this.binding.robot!!!!!!!!robot.move!dir!!!!}}

The move() method is now at the script level

Page 74: Going to Mars with Groovy Domain-Specific Languages

Define a base script class

44

abstract)class!RobotBaseScriptClass!!!!!!!!!!extends!Script!{!!!!void!move(Direction!dir)!{!!!!!!!!def)robot!=!this.binding.robot!!!!!!!!robot.move!dir!!!!}}

The move() method is now at the script level

Access the robot through the script’s binding

Page 75: Going to Mars with Groovy Domain-Specific Languages

Configure the base script class

45

def)conf)=)new)CompilerConfiguration()conf.scriptBaseClass)=)RobotBaseScriptClass

Page 76: Going to Mars with Groovy Domain-Specific Languages

Configure the base script class

45

def)conf)=)new)CompilerConfiguration()conf.scriptBaseClass)=)RobotBaseScriptClass

Scripts evaluated with this configuration will inherit from that class

Page 77: Going to Mars with Groovy Domain-Specific Languages

Ready for lift off!

%%move%left

Page 78: Going to Mars with Groovy Domain-Specific Languages

Beep, beep...yes but how do you define the speed?

...beep...

Page 79: Going to Mars with Groovy Domain-Specific Languages

Oh no!

Page 80: Going to Mars with Groovy Domain-Specific Languages

What we could do now is...

49

move!left,!at:!3.km/h

Page 81: Going to Mars with Groovy Domain-Specific Languages

What we could do now is...

49

move!left,!at:!3.km/h

Mix of named and normal parameters

Page 82: Going to Mars with Groovy Domain-Specific Languages

What we could do now is...

49

move!left,!at:!3.km/h

How to add a km property to numbers?

Mix of named and normal parameters

Page 83: Going to Mars with Groovy Domain-Specific Languages

Adding properties to numbers

• We need to:

• define units, distance and speed

• have a nice notation for them

• that’s where we add properties to numbers!

50

Page 84: Going to Mars with Groovy Domain-Specific Languages

Unit enum and Distance class

51

enum$DistanceUnit%{%%%%centimeter%('cm',%%%%0.01),%%%%meter%%%%%%(%'m',%%%%1),%%%%%kilometer%%('km',%1000)%%%%%%%%%String%abbreviation%%%%double%multiplier%%%%%%%%Unit(String%abbr,%double%mult)%{%%%%%%%%this.abbreviation%=%abbr%%%%%%%%this.multiplier%=%mult%%%%%}

%%%%String%toString()%{%abbreviation%}%}

Page 85: Going to Mars with Groovy Domain-Specific Languages

Unit enum and Distance class

51

enum$DistanceUnit%{%%%%centimeter%('cm',%%%%0.01),%%%%meter%%%%%%(%'m',%%%%1),%%%%%kilometer%%('km',%1000)%%%%%%%%%String%abbreviation%%%%double%multiplier%%%%%%%%Unit(String%abbr,%double%mult)%{%%%%%%%%this.abbreviation%=%abbr%%%%%%%%this.multiplier%=%mult%%%%%}

%%%%String%toString()%{%abbreviation%}%}

@TupleConstructor%class%Distance%{%%%%double%amount%%%%%DistanceUnit%unit

%%%%String%toString()%{%%%%%%%%%"$amount%$unit"%%%%%}%}

Page 86: Going to Mars with Groovy Domain-Specific Languages

Different techniques

• To add dynamic methods or properties, there are several approaches at your disposal:

• ExpandoMetaClass

• custom MetaClass

• Categories

• Let’s have a look at the ExpandoMetaClass

52

Page 87: Going to Mars with Groovy Domain-Specific Languages

Using ExpandoMetaClass

53

Number.metaClass.getCm%=%{%f>%%%%%new%Distance(delegate,%Unit.centimeter)%}Number.metaClass.getM%=%{%f>%%%%%new%Distance(delegate,%Unit.meter)%}Number.metaClass.getKm%=%{%f>%%%%%new%Distance(delegate,%Unit.kilometer)%}

Page 88: Going to Mars with Groovy Domain-Specific Languages

Using ExpandoMetaClass

53

Number.metaClass.getCm%=%{%f>%%%%%new%Distance(delegate,%Unit.centimeter)%}Number.metaClass.getM%=%{%f>%%%%%new%Distance(delegate,%Unit.meter)%}Number.metaClass.getKm%=%{%f>%%%%%new%Distance(delegate,%Unit.kilometer)%}

Add that to integration.groovy

Page 89: Going to Mars with Groovy Domain-Specific Languages

Using ExpandoMetaClass

53

Number.metaClass.getCm%=%{%f>%%%%%new%Distance(delegate,%Unit.centimeter)%}Number.metaClass.getM%=%{%f>%%%%%new%Distance(delegate,%Unit.meter)%}Number.metaClass.getKm%=%{%f>%%%%%new%Distance(delegate,%Unit.kilometer)%}

Add that to integration.groovy

‘delegate’ is the current number

Page 90: Going to Mars with Groovy Domain-Specific Languages

Using ExpandoMetaClass

53

Number.metaClass.getCm%=%{%f>%%%%%new%Distance(delegate,%Unit.centimeter)%}Number.metaClass.getM%=%{%f>%%%%%new%Distance(delegate,%Unit.meter)%}Number.metaClass.getKm%=%{%f>%%%%%new%Distance(delegate,%Unit.kilometer)%}

40.cm!3.5.m4.km

Add that to integration.groovy

‘delegate’ is the current number

Usage in your DSLs

Page 91: Going to Mars with Groovy Domain-Specific Languages

Distance okay, but speed?

• For distance, we just added a property access after the number, but we now need to divide (‘div’) by the time

54

2.km/h

Page 92: Going to Mars with Groovy Domain-Specific Languages

Distance okay, but speed?

• For distance, we just added a property access after the number, but we now need to divide (‘div’) by the time

54

2.km/h

The div() method on Distance

Page 93: Going to Mars with Groovy Domain-Specific Languages

Distance okay, but speed?

• For distance, we just added a property access after the number, but we now need to divide (‘div’) by the time

54

2.km/h

The div() method on Distance

An h duration instance in the binding

Page 94: Going to Mars with Groovy Domain-Specific Languages

First, let’s look at time

55

enum$TimeUnit%{%%%%hour%%%%%%('h',%%%3600),%%%%minute%%%%('min',%%%60),%%%%%kilometer%('s',%%%%%%1)%%%%%%%%%String%abbreviation%%%%double%multiplier%%%%%%%%TimeUnit(String%abbr,%double%mult)%{%%%%%%%%this.abbreviation%=%abbr%%%%%%%%this.multiplier%=%mult%%%%%}

%%%%String%toString()%{%abbreviation%}%}

Page 95: Going to Mars with Groovy Domain-Specific Languages

First, let’s look at time

55

enum$TimeUnit%{%%%%hour%%%%%%('h',%%%3600),%%%%minute%%%%('min',%%%60),%%%%%kilometer%('s',%%%%%%1)%%%%%%%%%String%abbreviation%%%%double%multiplier%%%%%%%%TimeUnit(String%abbr,%double%mult)%{%%%%%%%%this.abbreviation%=%abbr%%%%%%%%this.multiplier%=%mult%%%%%}

%%%%String%toString()%{%abbreviation%}%}

@TupleConstructor%class%Duration%{%%%%double%amount%%%%%TimeUnit%unit

%%%%String%toString()%{%%%%%%%%%"$amount%$unit"%%%%%}%}

Page 96: Going to Mars with Groovy Domain-Specific Languages

Inject the ‘h’ hour constant in the binding

56

def)binding!=)new!Binding([!!!!robot:!new!Robot(),!!!!*:!Direction.values()!!!!!!!!!!!!.collectEntries!{!!!!!!!!!!!!!!!![(it.name()):!it]!!!!!!!!!!!!},

!!!!h:!new!Duration(1,!TimeUnit.hour)])

Page 97: Going to Mars with Groovy Domain-Specific Languages

Now at (light!) speed

57

@TupleConstructor)class)Speed){))))Distance)distance))))Duration)duration

))))String)toString()){)))))))))"$distance/$duration")))))})}

Page 98: Going to Mars with Groovy Domain-Specific Languages

Operator overloading

• Currency amounts

• 15.euros + 10.dollars

• Distance handling

• 10.km - 10.m

• Workflow, concurrency

• taskA | taskB & taskC

• Credit an account• account << 10.dollars

account += 10.dollarsaccount.credit 10.dollars

58

a%+%b%%//%a.plus(b)a%f%b%%//%a.minus(b)a%*%b%%//%a.multiply(b)a%/%b%%//%a.div(b)a%%%b%%//%a.modulo(b)a%**%b%//%a.power(b)a%|%b%%//%a.or(b)a%&%b%%//%a.and(b)a%^%b%%//%a.xor(b)a[b]%%%//%a.getAt(b)a%<<%b%//%a.leftShift(b)a%>>%b%//%a.rightShift(b)+a%%%%%//%a.unaryPlus()fa%%%%%//%a.unaryMinus()~a%%%%%//%a.bitwiseNegate()

Page 99: Going to Mars with Groovy Domain-Specific Languages

Operator overloading

• Update the Distance class with a div() method following the naming convetion for operators

59

class%Distance%{%%%%...%%%%Speed%div(Duration%t)%{%%%%%%%%new%Speed(this,%t)%%%%}%%%%...}

Page 100: Going to Mars with Groovy Domain-Specific Languages

Operator overloading

• Update the Distance class with a div() method following the naming convetion for operators

59

class%Distance%{%%%%...%%%%Speed%div(Duration%t)%{%%%%%%%%new%Speed(this,%t)%%%%}%%%%...} Optional return

Page 101: Going to Mars with Groovy Domain-Specific Languages

Equivalence of notation

• Those two notations are actually equivalent:

60

2.km/h

2.getKm().div(h)

Page 102: Going to Mars with Groovy Domain-Specific Languages

Equivalence of notation

• Those two notations are actually equivalent:

60

2.km/h

2.getKm().div(h)

⇔ This one might be slightly more verbose!

Page 103: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

61

Page 104: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

61

Normal parameter

Page 105: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

61

Namedparameter

Normal parameter

Page 106: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

Will call:def!take(Map!m,!Direction!q)

61

Namedparameter

Normal parameter

Page 107: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

Will call:def!take(Map!m,!Direction!q)

61

Namedparameter

Normal parameter

All named parameters go into the map argument

Page 108: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

Will call:def!take(Map!m,!Direction!q)

61

Namedparameter

Normal parameter

All named parameters go into the map argument

Positional parameters come afterwards

Page 109: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

62

Page 110: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

62

Can we get rid of the comma?

Page 111: Going to Mars with Groovy Domain-Specific Languages

Named parameters usage

move!left,!at:!3.km/h

62

Can we get rid of the comma?

What about the colon too?

Page 112: Going to Mars with Groovy Domain-Specific Languages

Command chains

• A grammar improvement in Groovy 1.8 allowing you to drop dots & parens when chaining method calls

• an extended version of top-level statements like println

• Less dots, less parens allow you to

• write more readable business rules

• in almost plain English sentences

• (or any language, of course)

63

Page 113: Going to Mars with Groovy Domain-Specific Languages

Command chains

%move%left%%at%3.km/h%

64

Page 114: Going to Mars with Groovy Domain-Specific Languages

Command chains

%move%left%%at%3.km/h%

Alternation of method names

64

Page 115: Going to Mars with Groovy Domain-Specific Languages

Command chains

%move%left%%at%3.km/h%

Alternation of method names

and parameters(even named ones)

64

Page 116: Going to Mars with Groovy Domain-Specific Languages

Command chains

%move%left%%at%3.km/h%

64

Page 117: Going to Mars with Groovy Domain-Specific Languages

Command chains

%move%left%%at%3.km/h%%%%%%(%%%%).%%(%%%%%%)

Equivalent to:

64

Page 118: Going to Mars with Groovy Domain-Specific Languages

Look Ma!

No parens,

no dots!

Page 119: Going to Mars with Groovy Domain-Specific Languages

Command chains//%Java%fluent%API%approachclass%Robot%{%%%%...$$$$def%move(Direction%dir)%{%%%%%%%%this.dir%=%dir%%%%%%%%return%this%%%%}

%%%%def%at(Speed%speed)%{%%%%%%%%this.speed%=%speed%%%%%%%%return%this%%%%}%%%%...}

66

Page 120: Going to Mars with Groovy Domain-Specific Languages

Command chains

def)move(Direction)dir)){))))[at:){)Speed)speed)F>))))))))))))...))))))))}]))))}]}

67

Page 121: Going to Mars with Groovy Domain-Specific Languages

Command chains

def)move(Direction)dir)){))))[at:){)Speed)speed)F>))))))))))))...))))))))}]))))}]}

67

Nested maps and closures

Page 122: Going to Mars with Groovy Domain-Specific Languages

Command chains

def)move(Direction)dir)){))))[at:){)Speed)speed)F>))))))))))))...))))))))}]))))}]}

67

move%left%at%3.km/hUsage in your DSLs

Nested maps and closures

Page 123: Going to Mars with Groovy Domain-Specific Languages

Command chains

68

Page 124: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)

68

Page 125: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

68

Page 126: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuation

68

Page 127: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

68

Page 128: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structures

68

Page 129: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

68

Page 130: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parens

68

Page 131: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parensselect%all%%unique()%from%names

68

Page 132: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parensselect%all%%unique()%from%names

//%possible%with%an%odd%number%of%terms

68

Page 133: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parensselect%all%%unique()%from%names

//%possible%with%an%odd%number%of%termsdeploy%left%%arm

68

Page 134: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parensselect%all%%unique()%from%names

//%possible%with%an%odd%number%of%termsdeploy%left%%arm

%%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%)

68

Page 135: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parensselect%all%%unique()%from%names

//%possible%with%an%odd%number%of%termsdeploy%left%%arm

%%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%)

%%%%%(%%%%%%%%%%%).%%%%%%(%%%%)

68

Page 136: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parensselect%all%%unique()%from%names

//%possible%with%an%odd%number%of%termsdeploy%left%%arm

%%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%)

%%%%%(%%%%%%%%%%%).%%%%%%(%%%%)

%%%%%(%%).%%%%(%%).%%%%(%%)

68

Page 137: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parensselect%all%%unique()%from%names

//%possible%with%an%odd%number%of%termsdeploy%left%%arm

%%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%)

%%%%%(%%%%%%%%%%%).%%%%%%(%%%%)

%%%%%(%%).%%%%(%%).%%%%(%%)

%%%%%%(%%%).%%%%%%%%.%%%%(%%%%%)

68

Page 138: Going to Mars with Groovy Domain-Specific Languages

Command chains//%methods%with%multiple%arguments%(commas)take%coffee%%with%sugar,%milk%%and%liquor

//%leverage%namedfargs%as%punctuationcheck%that:%vodka%%tastes%good

//%closure%parameters%for%new%control%structuresgiven%{}%%when%{}%%then%{}

//%zerofarg%methods%require%parensselect%all%%unique()%from%names

//%possible%with%an%odd%number%of%termsdeploy%left%%arm

%%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%)

%%%%%(%%%%%%%%%%%).%%%%%%(%%%%)

%%%%%(%%).%%%%(%%).%%%%(%%)

%%%%%%(%%%).%%%%%%%%.%%%%(%%%%%)

%%%%%%(%%%%).

68

Page 139: Going to Mars with Groovy Domain-Specific Languages

Final result

69

Page 140: Going to Mars with Groovy Domain-Specific Languages

Final result

69

move!forward!at!3.km/h

Page 141: Going to Mars with Groovy Domain-Specific Languages

move forward at 3.km/h

Page 142: Going to Mars with Groovy Domain-Specific Languages

move forward at 3.km/h Yes! We did it!

Page 143: Going to Mars with Groovy Domain-Specific Languages

What about security and safety?

Page 144: Going to Mars with Groovy Domain-Specific Languages

Security and safetyJVM Security ManagersSecureASTCustomizer

SandboxingControlling scripts execution

72

Page 145: Going to Mars with Groovy Domain-Specific Languages

Play it safe in a sandbox

Page 146: Going to Mars with Groovy Domain-Specific Languages

Playing it safe...

• You have to think carefully about what DSL users are allowed to do with your DSL

• Forbid things which are not allowed

• leverage the JVM’s Security Managers

• this might have an impact on performance

• use a Secure AST compilation customizer

• not so easy to think about all possible cases

• avoid long running scripts with *Interrupt transformations

74

Page 147: Going to Mars with Groovy Domain-Specific Languages

Security Managers

• Groovy is just a language leaving on the JVM, so you have access to the usual Security Managers mechanism

• Nothing Groovy specific here

• Please check the documentation on Security Managers and how to design policy files

75

Page 148: Going to Mars with Groovy Domain-Specific Languages

SecureASTCustomizer

76

def!secure!=!new!SecureASTCustomizer()secure.with!{

//!disallow!closure!creation!!!closuresAllowed!=!false!

//!disallow!method!definitions!!!methodDefinitionAllowed!=!false!

//!empty!white!list!=>!forbid!certain!imports!!!importsWhitelist!=![...]!!!!staticImportsWhitelist!=![...]

//!only!allow!some!static!import!!!staticStarImportsWhitelist!=![...]

//!language!tokens!allowed!!!!tokensWhitelist!=![...]

//!types!allowed!to!be!used!!!constantTypesClassesWhiteList!=![...]

//!classes!who!are!allowed!to!be!receivers!of!method!calls!!!receiversClassesWhiteList!=![...]}def!config!=!new!CompilerConfiguration()config.addCompilationCustomizers(secure)def!shell!=!new!GroovyShell(config)

Page 149: Going to Mars with Groovy Domain-Specific Languages

Controlling code execution

• Your application may run user’s code

• what if the code runs in infinite loops or for too long?

• what if the code consumes too many resources?

• 3 new transforms at your rescue

• @ThreadInterrupt: adds Thread#isInterrupted checks so your executing thread stops when interrupted

• @TimedInterrupt: adds checks in method and closure bodies to verify it’s run longer than expected

• @ConditionalInterrupt: adds checks with your own conditional logic to break out from the user code

77

Page 150: Going to Mars with Groovy Domain-Specific Languages

@ThreadInterrupt

78

@ThreadInterruptimport%groovy.transform.ThreadInterrupt%%while%(true)%{

%%%%//%Any%extraterestrial%around?}

Page 151: Going to Mars with Groovy Domain-Specific Languages

@ThreadInterrupt

78

@ThreadInterruptimport%groovy.transform.ThreadInterrupt%%while%(true)%{

%%%%//%Any%extraterestrial%around?}

%

%%%%if%(Thread.currentThread.isInterrupted())%%%%%%%%throw$new%InterruptedException(){ }

Page 152: Going to Mars with Groovy Domain-Specific Languages

@TimedInterrupt

• InterruptedException thrown when checks indicate code ran longer than desired

79

@TimedInterrupt(10)import!groovy.transform.TimedInterrupt!!while!(true)!{!!!!move!left!!!!//!circle!forever}

Page 153: Going to Mars with Groovy Domain-Specific Languages

@ConditionalInterrupt

• Specify your own condition to be inserted at the start of method and closure bodies

• check for available resources, number of times run, etc.

• Leverages closure annotation parameters from Groovy 1.8

80

@ConditionalInterrupt({$battery.level$<$O.1$})import%groovy.transform.ConditionalInterrupt

100.times%{%%%%%%%%move%forward%at%10.km/h}

Page 154: Going to Mars with Groovy Domain-Specific Languages

Using compilation customizers

• In our previous three examples, the usage of the interrupts were explicit, and users had to type them

• if they want to deplete the battery of your robot, they won’t use interrupts, so you have to impose interrupts yourself

• With compilation customizers you can inject those interrupts thanks to the ASTTransformationCustomizer

81

Page 155: Going to Mars with Groovy Domain-Specific Languages

What have we learnt?

82

Page 156: Going to Mars with Groovy Domain-Specific Languages

Groovy Power!™

• A flexible and malleable syntax

• scripts vs classes, optional typing, colons and parens

• Groovy offers useful dynamic features for DSLs

• operator overloading, ExpandoMetaClass

• Can write almost plain natural language sentences

• for readable, concise and expressive DSLs

• Groovy DSLs are easy to integrate, and can be secured to run safely in your own sandbox

83

Page 157: Going to Mars with Groovy Domain-Specific Languages

Groovy Power!™

• A flexible and malleable syntax

• scripts vs classes, optional typing, colons and parens

• Groovy offers useful dynamic features for DSLs

• operator overloading, ExpandoMetaClass

• Can write almost plain natural language sentences

• for readable, concise and expressive DSLs

• Groovy DSLs are easy to integrate, and can be secured to run safely in your own sandbox

83

Groovy is a great fit for

DSLs!

Page 158: Going to Mars with Groovy Domain-Specific Languages

And there’s more!

• We haven’t dived into...

• How to implement your own control structures with the help of closures

• How to create Groovy « builders »

• How to hijack the Groovy syntax to develop our own language extensions with AST Transformations

• Source preprocessing for custom syntax

• How to use the other dynamic metaprogramming techniques available

• How to improve error reporting with customizers

• IDE support with DSL descriptors (GDSL and DSLD)

84

Page 160: Going to Mars with Groovy Domain-Specific Languages

Questions & Answers

86

Got questions, really?

Page 161: Going to Mars with Groovy Domain-Specific Languages

Questions & Answers

86

Got questions, really?

I might have answers!

Page 162: Going to Mars with Groovy Domain-Specific Languages

Image credits• Pills: http://www.we-ew.com/wp-content/uploads/2011/01/plan-b-pills.jpg• Chains: http://2.bp.blogspot.com/-GXDVqUYSCa0/TVdBsON4tdI/AAAAAAAAAW4/EgJOUmAxB28/s1600/breaking-chains5_copy9611.jpg• Russian flag: http://good-wallpapers.com/pictures/4794/Russian%20Flag.jpg• Space odissey: http://dearjesus.files.wordpress.com/2010/04/2001_a_space_odyssey_1.jpg• HAL red: http://2.bp.blogspot.com/-yjsyPxUFicY/TcazwAltOaI/AAAAAAAAAho/GVT7wGhnrUM/s1600/2001-a-space-odyssey-HAL.jpg• Back in time: http://4.bp.blogspot.com/-Pt44Dk9J2EM/TrQx9YNmVcI/AAAAAAAAAk4/ivWw9Lja05k/s1600/clocky.jpg• USSR Space posters: http://www.flickr.com/photos/justinvg• Russian General: http://rickrozoff.files.wordpress.com/2012/02/general-nikolai-makarov.jpg• Rocket: http://blog.al.com/breaking/2009/03/soyuz_launch.jpg• Progress capsule: http://www.spacedaily.com/images/progress-ocean-desk-1024.jpg• Buran: http://www.buran.fr/mriya-antonov/Photos//050-Exhibition%20au%20Bourget%20avec%20Bourane-Airshow%20with%20Buran%20at%20Le%20Bourget-1134884.jpg• Man in space: http://vintagespace.files.wordpress.com/2010/11/voskhod-2_leonov.jpg• Sputnik 2: http://launiusr.files.wordpress.com/2010/06/sputnik2.jpg• Lunakod: http://www.astr.ua.edu/keel/space/lunakhod_moscow.jpg• Sandbox: http://www.turnbacktogod.com/wp-content/uploads/2008/09/sandbox.jpg• Repair: http://www.oneangels.com/wp-content/uploads/2012/03/repair1.jpg• Mars rover: http://wallpapers.free-review.net/wallpapers/49/Mars_rover%2C_Mars_-_03.jpg• Mars rover 2: http://www.universetoday.com/wp-content/uploads/2011/06/551038main_pia14156-43_946-710.jpg• Thumb: http://www.wpclipart.com/sign_language/thumbs_up_large.png.html• Night sky: http://www.aplf-planetariums.info/galeries/ciel_profond/2004-07-01-Voie_Lactee_Scorpion-Jean-Luc_PUGLIESI.jpg• Obama yes we can: http://www.dessinemoiunboulon.net/wp-content/uploads/2009/01/obama-yes-we-can_04-nov-08.jpg• Hook: http://winningware.com/blog/wp-content/uploads/2009/12/FishHookXSmall.jpg• HP 48 GX: http://calculators.torensma.net/files/images/hewlett-packard_hp-48g.jpg• Omer: http://www.irmin.com/wallpaper/TV/Homer%20Simpson%20Oh%20No.jpg• Cadenat: http://acsgsecurite.com/upl/site/cadenat.png

87