Slide 1

Slide 1 text

INTRODUCTION TO EXPRESSION LANGUAGES WITH XTEXT KARSTEN THOMS

Slide 2

Slide 2 text

EXPRESSIONS Additive + - Multiplicative * / % Boolean && || Relational > < >= <= == != Unary !x Postfix x++ Atomic „Hello“

Slide 3

Slide 3 text

CHALLENGES • Recursion • Precedence • Associativity • Ambiguity • Typing

Slide 4

Slide 4 text

We can embed Xbase in our language!

Slide 5

Slide 5 text

base SHIPPED WITH XTEXT FULL FEATURED EXPRESSION LANGUAGE STRONG TYPED JAVA INTEGRATION EMBEDDABLE PRODUCTION READY

Slide 6

Slide 6 text

But… if Xbase cannot be used?

Slide 7

Slide 7 text

What can we learn or reuse from Xbase?

Slide 8

Slide 8 text

Let’s look at some Xtext grammar patterns for expression languages in Xbase…

Slide 9

Slide 9 text

Language’s meta model usually manually defined

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Every expression rule returns the same expression super type

Slide 12

Slide 12 text

Rules first call the rule with the next higher priority

Slide 13

Slide 13 text

…followed by an optional part starting with a syntactic predicate

Slide 14

Slide 14 text

…followed by an 
 Assigned Action

Slide 15

Slide 15 text

Operators of an expression type listed in a datatype rule

Slide 16

Slide 16 text

Rules for supported Literals like Boolean, String, Number etc.

Slide 17

Slide 17 text

All literals collected by an abstract rule, being the rule with the highest priority

Slide 18

Slide 18 text

2 + 3

Slide 19

Slide 19 text

LEFT RECURSION A rule is left-recursive when the first symbol is non-terminal and refers to the rule itself Expression : Expression '+' Expression | '(' Expression ')' | Number; Number : value = INT; 2 + 3

Slide 20

Slide 20 text

!20 Addition returns Expression: Number ({Sum.left = current} '+' right=Number)*; Number: value = INT; 1 1 EXPRESSIONS Example:

Slide 21

Slide 21 text

!21 Addition returns Expression: Number ({Sum.left = current} '+' right=Number)*; Number: value = INT; 1 2 + 3 Sum 2 3 1 EXPRESSIONS Example: Example: ! left right

Slide 22

Slide 22 text

2 + 3 x 8 ^ 2

Slide 23

Slide 23 text

PRECEDENCE ExprPrioN: ExprPrioM =>({ExprPrioN.someRef = current} ..... )*; ExprPrioM: ExprPrioN =>({ExprPrioM.someRef = current} ..... )*; ExprPrioO: Atomic =>({ExprPrioO.someRef = current} ..... )*; Atomic: {Literal} value=; PriorityN PriorityM Atomic < < PriorityO < Addition Multiplication Literal < < Exponentiation <

Slide 24

Slide 24 text

SYNTACTIC PREDICATES • Expressed by => or -> in front of a grammar element • Give the parser hint to follow certain paths in case of ambiguity
 
 „if you see these tokens, then follow this path“ • Recommended instead of using backtracking

Slide 25

Slide 25 text

DANGLING ELSE To which if element does the else part belong? if (condition1) if (condition2) x = 1 else x = 2 if (condition1) if (condition2) x = 1 else x = 2

Slide 26

Slide 26 text

DANGLING ELSE IfStatement returns Expression: 'if' '(' condition=BoolExpression ')' thenPart=Expression (=>'else' elsePart=Expression)? ; if if expr expr expr condition thenPart condition elsePart

Slide 27

Slide 27 text

TYPES

Slide 28

Slide 28 text

IMPLEMENTING A TYPE SYSTEM 1.What is the Actual Type of an expression ?
 2.What is the Expected Type of an expression ?
 3.Is some type conformant with another type ?

Slide 29

Slide 29 text

IMPLEMENTING A TYPE SYSTEM 1.What is the Actual Type of an expression ?
 2.What is the Expected Type of an expression ?
 3.Is some type conformant with another type ? T getActualType (Expression expr) T getExpectedType (Expression expr) boolean isConformant (T expected, T actual)

Slide 30

Slide 30 text

TYPE VALIDATION class TypeValidator extends AbstractMyDSLValidator { @Inject ITypeComputer typeComputer @Check def void checkType(Expression expr) { val actualType = typeComputer.getActualType(expr) val expectedType = typeComputer.getExpectedType(expr) if (expectedType === null || actualType === null) return; // nothing to check if (!typeComputer.isConformant(expectedType, actualType)) { error("Incompatible types. Expected '" + expectedType.name 
 + "' but was '" + actualType.name + "'" , null, IssueCodes.INCOMPATIBLE_TYPES); } } } class MyDSLRuntimeModule extends AbstractMyDSLRuntimeModule { ... @SingletonBinding(eager=true) def bindTypeValidator () { TypeValidator } }

Slide 31

Slide 31 text

number x; string s; s = "Foo" + x;

Slide 32

Slide 32 text

number x; string s; s = "Foo" + x; Actual: NUMBER

Slide 33

Slide 33 text

number x; string s; s = "Foo" + x; Actual: STRING

Slide 34

Slide 34 text

number x; string s; s = "Foo" + x; Actual: STRING

Slide 35

Slide 35 text

number x; string s; s = "Foo" + x; Actual: STRING

Slide 36

Slide 36 text

number x; string s; s = "Foo" + x; Expected: STRING

Slide 37

Slide 37 text

number x; string s; s = x + 1;

Slide 38

Slide 38 text

number x; string s; s = x + 1; Actual: NUMBER Expected: STRING

Slide 39

Slide 39 text

EXPECTED TYPE • Depends on context • Variable initialisation: type of the declared variable • Assignment: right-hand side must be of type of left-hand side • If condition: boolean • Argument of a method call: type of the corresponding parameter of the method

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

TESTING