Save 37% off PRO during our Black Friday Sale! »

Introduction to Expression Languages with Xtext

Introduction to Expression Languages with Xtext

Basics and patterns to create languages with expressions.
Slides from presentation at EclipseCon Europe 2017
https://www.eclipsecon.org/europe2017/session/introduction-expression-languages-xtext

E76754f592fecf0116c53b2bc39ff135?s=128

Karsten Thoms

December 18, 2018
Tweet

Transcript

  1. INTRODUCTION TO EXPRESSION LANGUAGES WITH XTEXT KARSTEN THOMS

  2. EXPRESSIONS Additive + - Multiplicative * / % Boolean &&

    || Relational > < >= <= == != Unary !x Postfix x++ Atomic „Hello“
  3. CHALLENGES • Recursion • Precedence • Associativity • Ambiguity •

    Typing
  4. We can embed Xbase in our language!

  5. base SHIPPED WITH XTEXT FULL FEATURED EXPRESSION LANGUAGE STRONG TYPED

    JAVA INTEGRATION EMBEDDABLE PRODUCTION READY
  6. But… if Xbase cannot be used?

  7. What can we learn or reuse from Xbase?

  8. Let’s look at some Xtext grammar patterns for expression languages

    in Xbase…
  9. Language’s meta model usually manually defined

  10. None
  11. Every expression rule returns the same expression super type

  12. Rules first call the rule with the next higher priority

  13. …followed by an optional part starting with a syntactic predicate

  14. …followed by an 
 Assigned Action

  15. Operators of an expression type listed in a datatype rule

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

  17. All literals collected by an abstract rule, being the rule

    with the highest priority
  18. 2 + 3

  19. 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
  20. !20 Addition returns Expression: Number ({Sum.left = current} '+' right=Number)*;

    Number: value = INT; 1 1 EXPRESSIONS Example:
  21. !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
  22. 2 + 3 x 8 ^ 2

  23. PRECEDENCE ExprPrioN: ExprPrioM =>({ExprPrioN.someRef = current} ..... )*; ExprPrioM: ExprPrioN

    =>({ExprPrioM.someRef = current} ..... )*; ExprPrioO: Atomic =>({ExprPrioO.someRef = current} ..... )*; Atomic: {Literal} value=<TERMINAL>; PriorityN PriorityM Atomic < < PriorityO < Addition Multiplication Literal < < Exponentiation <
  24. 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
  25. 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
  26. DANGLING ELSE IfStatement returns Expression: 'if' '(' condition=BoolExpression ')' thenPart=Expression

    (=>'else' elsePart=Expression)? ; if if expr expr expr condition thenPart condition elsePart
  27. TYPES

  28. 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 ?
  29. 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)
  30. 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 } }
  31. number x; string s; s = "Foo" + x;

  32. number x; string s; s = "Foo" + x; Actual:

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

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

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

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

    STRING
  37. number x; string s; s = x + 1;

  38. number x; string s; s = x + 1; Actual:

    NUMBER Expected: STRING
  39. 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
  40. None
  41. None
  42. None
  43. TESTING