model-driven software development - pretty-printing, editor services, term rewriting
DESCRIPTION
Model-Driven Software Development, Pretty-Printing, Editor Services, Term RewritingTRANSCRIPT
Pretty-PrintingEditor ServicesTerm Rewriting
Course IN4308Master Computer Science
Delft University of Technology
Eelco Visserhttp://eelcovisser.org
Lecture 7
Outline
Pretty-printing
★ from abstract syntax to concrete syntax
Editor services
★ defining the behavior of editors
Term rewriting
★ transforming abstract syntax
Pretty-Printing
While( BinOp(Var("x"), "<", IntLit("3")), Block( [Assign( Var("x") , BinOp(Var("x"), "+", IntLit("1")) )] ))
while ( (x < 3) ){ x := (x + 1) ;}
Pretty-Printing: Abstract to Concrete Syntax
Syntax Definition
Parse Table Signature Pretty-Print Table
TransformParse Pretty-Print
entity User { name :: String pw :: Secret}def output(u : User) {
@Entityclass User { String _user; public User getUser() { return _user; }syntax definition is basis of language definition
Syntax of Statements
module statementsexports sorts Statement context-free syntax Exp ":=" Exp ";" -> Statement {cons("Assign")} Exp ";" -> Statement {cons("ExpStat")} "return" PageRef ";" -> Statement {cons("ReturnPage")} "{" Statement* "}" -> Block {cons("Block")} Block -> Statement
sorts VarDecl context-free syntax "var" ID ":" Type -> VarDecl {cons("VarDecl")} "var" ID ":" Type ":=" Exp -> VarDecl {cons("VarDeclInit")} VarDecl ";" -> Statement {cons("Stat")} "var" -> ID {reject} context-free syntax "for" "(" ID ":" Type "in" Exp ")" Block -> Statement {cons("For")} "while" "(" Exp ")" Block -> Statement {cons("While")} "if" "(" Exp ")" Block "else" Block -> Statement {cons("If")}
Pretty-Print Table
mapping constructors to text
context-free syntax Exp ":=" Exp ";" -> Statement {cons("Assign")} "{" Statement* "}" -> Block {cons("Block")} Block -> Statement "while" "(" Exp ")" Block -> Statement {cons("While")}
[ ... Assign -- H[ _1 KW[":="] _2 KW[";"] ],
Block -- V[ V is=2[ KW["{"] _1] KW["}"]],
Block.1:iter-star -- _1,
While -- V[ H[KW["while"] KW["("] _1 KW[")"]] _2], ...]
Formatting with Box Expressions
context-free syntax Exp ":=" Exp ";" -> Statement {cons("Assign")} "{" Statement* "}" -> Block {cons("Block")} Block -> Statement "while" "(" Exp ")" Block -> Statement {cons("While")}
[ ... Assign -- H[ _1 KW[":="] _2 KW[";"] ],
Block -- V[ V is=2[ KW["{"] _1] KW["}"]],
Block.1:iter-star -- _1,
While -- V[ H[KW["while"] KW["("] _1 KW[")"]] _2], ...]
While( BinOp(Var("x"), "<", IntLit("3")), Block( [Assign( Var("x") , BinOp(Var("x"), "+", IntLit("1")) )] ))
while ( (x < 3) ){ x := (x + 1) ;}
Pretty-Printing: Term to Box to Text
V[H[KW["while"] KW["("] ... KW[")"]] V[V is=2[KW["{"] ... ] KW["}"]]]
Generated Pretty-Print Table
[ ... Assign -- _1 KW[":="] _2 KW[";"], ExpStat -- _1 KW[";"], ReturnPage -- KW["return"] _1 KW[";"], Block -- KW["{"] _1] KW["}"], Block.1:iter-star -- _1, VarDecl -- KW["var"] _1 KW[":"] _2, VarDeclInit -- KW["var"] _1 KW[":"] _2 KW[":="] _3, Stat -- _1 KW[";"], For -- KW["for"] KW["("] _1 KW[":"] _2 KW["in"] _3 KW[")"] _4, While -- KW["while"] KW["("] _1 KW[")"] _2], If -- KW["if"] KW["("] _1 KW[")"] _2 KW["else"] _3, ...]
Pretty-Print Table with Box Markup
[ ... Assign -- H[_1 KW[":="] _2 KW[";"]], ExpStat -- H hs=0[_1 KW[";"]], ReturnPage -- H hs=0 [KW["return"] _1 KW[";"]], Block -- V [V is=2 [KW["{"] _1] KW["}"]], Block.1:iter-star -- _1, VarDecl -- H [KW["var"] _1 KW[":"] _2], VarDeclInit -- H [KW["var"] _1 KW[":"] _2 KW[":="] _3], Stat -- H hs=0 [_1 KW[";"]], For -- V[H[KW["for"] KW["("] _1 KW[":"] _2 KW["in"] _3 KW[")"]] _4], While -- V[H[KW["while"] KW["("] _1 KW[")"]] _2], If -- V [ V is=2[ H[KW["if"] KW["("] _1 KW[")"]] _2] V is=2[ KW["else"] _3]], ...]
Presentational
Editor Services
Editor Services
Syntax highlighting
★ token coloring
Code folding
★ folding & unfolding code fragments
Outline view
★ table of contents
Syntax properties
★ bracket matching, indentation
Syntax completion
★ match on syntactic triggers & replace with template
module nwl.main
imports nwl-Builders nwl-Colorer nwl-Folding nwl-Outliner nwl-References nwl-Syntax nwl-Completions
language General properties name : nwl id : nwl extends : Root description : "Spoofax/IMP-generated editor for the nwl language" url : http://strategoxt.org extensions : nwl table : include/nwl.tbl start symbols : Start
Editor Services Composition
Syntax Definition
Default Syntax Highlighting
Default Code Folding
DefaultOutline View
Editor
Custom Syntax Highlighting
CustomCode Folding
CustomOutline View+ + +
module nwl-Foldingimports nwl-Folding.generatedfolding Element.CallElems Element.Call Element.ForElem Element.ForAllElem
module nwl-Folding.generatedfolding Default folding Start.Module Definition.Entity Property.Property Definition.TemplateDef Element.CallArgs PageRef.PageRef Element.Action
Code Folding
Outline View
module nwl-Outliner.generatedoutliner Default outliner Start.Module Definition.Entity Property.Property Definition.TemplateDef Element.CallArgs Exp.MethodCall Element.CallElems Element.Call Element.ForElem Element.ForAllElem PageRef.PageRef Element.Action Statement.For Statement.While Statement.If Element.Submit Element.XmlElem
module nwl-Colorer.generated colorer Default, token-based highlighting keyword : 127 0 85 bold identifier : default string : blue number : darkgreen var : 255 0 100 italic operator : 0 0 128 layout : 100 100 0 italic colorer System colors darkred = 128 0 0 red = 255 0 0 darkgreen = 0 128 0 green = 0 255 0 darkblue = 0 0 128 blue = 0 0 255 cyan = 0 255 255 magenta = 255 0 255 yellow = 255 255 0 white = 255 255 255 black = 0 0 0 gray = 128 128 128 grey = gray orange = 255 165 0 pink = 255 105 180 brown = 139 69 19 default = _
Default Syntax Highlighting
Custom Syntax Highlighting
module nwl-Colorerimports nwl-Colorer.generatedcolorer Element : darkgreen
Syntax Properties
module nwl-Syntax.generatedlanguage Syntax properties (static defaults) // Comment constructs: line comment : "//" block comment : "/*" * "*/" // Fences (used for matching, // inserting, indenting brackets): fences : [ ] ( ) { } // Automatic indent hints // (indent after these tokens): indent after : "=" ":" // Regular expression for identifiers: identifier lexical : "[A-Za-z0-9_]+"
BuildersSemantic Editor Services
Builders: Analysis & Transformation Services
module nwl-Buildersbuilders provider: include/nwl.ctree
observer: editor-analyze
builder : "Generate Java code" = generate-java (openeditor) (realtime)
builder : "Show ATerm (selection)" = generate-aterm (openeditor) (realtime) (meta) builder : "Normalize (selection)" = show-normalized (openeditor) (realtime) (meta)
builder : "Normalize Pretty (selection)" = show-normalized-pp (openeditor) (realtime) (meta)
Term Rewriting
Term Rewriting
Term rewrite rules
★ transform term to term
★ pattern matching
★ variable binding
★ substitution
Rewriting strategy
★ algorithm for applying rewrite rules
Grammar to Signature
module nwlsignature constructors Entity : ID * List(Property) -> Definition Property : ID * Type * List(Annotation) -> Property Property : ID * Type -> Property
context-free syntax "entity" ID "{" Property* "}" -> Definition {cons("Entity")} ID ":" Type -> Property {cons("Property")} ID ":" Type "(" {Annotation ","}* ")" -> Property {cons("Property")}
Desugaring: Syntactic Normalization
Entity("Blog", [ Property("url", SimpleType("String"), [Id()]) , Property("name", SimpleType("String"), [Name()]) , Property("posts", SetType(SimpleType("Post"))) , Property("author", SimpleType("User")) ])
Entity("Blog", [ Property("url", SimpleType("String"), [Id()]) , Property("name", SimpleType("String"), [Name()]) , Property("posts", SetType(SimpleType("Post")), []) , Property("author", SimpleType("User"), []) ])
Term Rewriting in Stratego
module desugar
imports include/nwl
rules
desugar : Property(x, t) -> Property(x, t, [])
strategies
desugar-all = innermost(desugar)
import signature
strategy
rewrite rule
Term Rewrite Rule
desugar : Property(x, t) -> Property(x, t, [])
label/name
left-hand side pattern
right-hand side patternvariable
Rewrite Rule Application
Property("author", SimpleType("User"))
desugar : Property(x, t) -> Property(x, t, [])
pattern matching
variablebinding
Property("author", SimpleType("User"), [])
pattern instantiation substitution
Rewrite Strategy
desugar-all = innermost(desugar)
strategy definitiongeneric strategy
strategy instantiation
innermost(s) apply transformation s exhaustively to all sub-terms of subject term in bottom-up order
More Syntactic Normalizations
rules
desugar : CallArgs(x, e*) -> Call(x, e*, []) desugar : CallElems(x, elem*) -> Call(x, [], elem*) desugar : Call(x) -> Call(x, [], []) desugar : Property(x, t) -> Property(x, t, [])
Generic Representation for Binary Operators
signature constructors BinOp : Exp * Op * Exp -> Exp
rules
desugar : Lt(e1, e2) -> BinOp(e1, "<", e2)
desugar : Plus(e1, e2) -> BinOp(e1, "+", e2) desugar : Times(e1, e2) -> BinOp(e1, "*", e2)
desugar : UnaryMinus(e) -> BinOp(IntLit("0"), "-", e)
Assign( Var("x"), BinOp( Var("a") , "+" , BinOp( BinOp(Var("b"), "+", IntLit("3")) , "/" , Var("c") ) ))
Assign( Var("x"), Plus( Var("a") , Div(Times(Var("b"), IntLit("3")), Var("c")) ))
x := a + b * 3 / c;
parse
desugar
Applying Transformation in Editor
Binding Transformation to Editor Service
rules show-desugared : (selected, position, ast, path, project-path) -> (filename, result-string) with filename := <guarantee-extension(|"aterm")> path; result-string := <desugar-all; pp-aterm-box; box2text-string(|120)> selected
module nwl-Buildersbuilders builder : "Desugar (selection)" = show-desugared (openeditor) (realtime) (meta)
Stratego interface
editor interfacebehavior
transformation
standard calling convention for builders
Constant Folding
y := a + (3 * 5 - 17);
Assign( Var("y"), BinOp(Var("a"), "+", IntLit("25")))
Assign( Var("y"), Plus( Var("a") , Minus(Times(IntLit("3"), IntLit("5")), IntLit("17")) ))
y := (a + 25);
desugar + eval
parse
pretty-print
Constant Folding Rules
strategies
eval-all = innermost(desugar + eval)
rules eval : BinOp(IntLit(x), "+", IntLit(y)) -> IntLit(<addS>(x, y)) eval : BinOp(IntLit(x), "-", IntLit(y)) -> IntLit(<subtS>(x, y)) eval : BinOp(IntLit(x), "*", IntLit(y)) -> IntLit(<mulS>(x, y)) eval : BinOp(IntLit(x), "/", IntLit(y)) -> IntLit(<divS>(x, y))
Conditional Rewrite Rules
eval : BinOp(IntLit(x), "+", IntLit(y)) -> IntLit(<addS>(x, y))
eval : BinOp(IntLit(x), "+", IntLit(y)) -> IntLit(z) where z := <addS>(x, y)condition
match apply transformation
bound in condition
For to While
action foo() { for(p : Post in b.posts) { p.title := "foo"; }}
action foo ( ) { var i : Int := 0; var c : Set<Post> := b.posts; var l : Int := c.length(); while (i < l) { var p : Post := c[i]; p.title := "foo" ; i := i + 1; }}
specification (by example)
For to While: Transformation Schema
for(x : t in e) bvar i : Int := 0;var c : Set<t> := e;var l : Int := c.length();while (i < l) { var x : t := c[i]; b i := i + 1;}
abstraction of example
For to While: Rewrite Rule
normalize : For(x, t, e, b) -> Block([ Stat(VarDeclInit(i, SimpleType("Int"), IntLit("0"))), Stat(VarDeclInit(c, SimpleType(t), e)), Stat(VarDeclInit(l, SimpleType("Int"), MethodCall(Var(c), "length", []))), While(BinOp(Var(i), "<", Var(l)), Block([ Stat(VarDeclInit(x, t, IndexAccess(Var(c), Var(i)))), b, Assign(Var(i), BinOp(Var(i), "+", IntLit("1"))) ])) ]) where i := <newname> "i"; c := <newname> "c"; l := <newname> "l"
For to While: Result
action foo() { for(p : Post in b.posts) { p.title := "foo"; }}
action foo ( ) { var i : Int := 0; var c : Set<Post> := b.posts; var l : Int := c.length(); while (i < l) { var p : Post := c[i]; p.title := "foo" ; i := i + 1; }}
action foo ( ) { { var i0 : Int := 0; var c0 : Set<Post> := b.posts; var l0 : Int := c0.length(); while ( (i0 < l0) ) { var p : Post := c0[i0]; p.title := "foo" ; i0 := (i0 + 1) ; } }}
specification by example
result
Normalization Strategy
strategies normalize-all = innermost(desugar + normalize)
rules normalize : For(x, t, e, b) -> Block([ Stat(VarDecl(... ])
normalize : [Block(stat1*) | stat2*] -> <conc> (stat1*, stat2*)
(is that a correct transformation?)
For to While: Final Result
action foo() { for(p : Post in b.posts) { p.title := "foo"; }}
action foo ( ) { var i : Int := 0; var c : Set<Post> := b.posts; var l : Int := c.length(); while (i < l) { var p : Post := c[i]; p.title := "foo" ; i := i + 1; }}
action foo ( ) { var i0 : Int := 0; var c0 : Set<Post> := b.posts; var l0 : Int := c0.length(); while ( (i0 < l0) ) { var p : Post := c0[i0]; p.title := "foo" ; i0 := (i0 + 1) ; }}
specification by example
result
Normalization Strategy
strategies normalize-all = innermost(desugar + normalize)
rules normalize : For(x, t, e, b) -> Block([ Stat(VarDecl(... ])
normalize : Block([Block(stat*)]) -> Block(stat*)
Schedule
Lab this week
★ Design 1: deadline is April 1
★ Design 2: what DSL will you design?
Cases
★ Case 2: web abstractions
★ Deadline Case 2: April 8
★ Case 3:
Next
★ Lecture 8: code generation