Model-Driven Software Development - Context-Sensitive Transformation

75
Context-Sensitive Transformation Course IN4308 Master Computer Science Delft University of Technology Eelco Visser http://eelcovisser.org Lecture 8

description

A lecture in the course on Model-Driven Software Development. Topic is context-sensitive transformation.

Transcript of Model-Driven Software Development - Context-Sensitive Transformation

Page 1: Model-Driven Software Development - Context-Sensitive Transformation

Context-Sensitive Transformation

Course IN4308Master Computer Science

Delft University of Technology

Eelco Visserhttp://eelcovisser.org

Lecture 8

Page 2: Model-Driven Software Development - Context-Sensitive Transformation

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

Page 3: Model-Driven Software Development - Context-Sensitive Transformation

Coming up

Lecture 8: Context-sensitive transformation

★ design 2

★ transformation with dynamic rewrite rules

Lecture 9: Static analysis & error checking

★ name resolution, reference resolution

★ type analysis

Lecture 10: Code generation

★ string templates, code generation by model transformation

★ concrete object syntax

Lecture 11: Code generation strategies

★ customization of generated code

Page 4: Model-Driven Software Development - Context-Sensitive Transformation

Outline

Design 2

★ designing a domain-specific language

Context-sensitive transformation

★ global-to-local, local-to-global

Rewriting strategies

★ controlling the application of rules

Dynamic rewrite rules

★ context-sensitive transformation with rewrite rules

Page 5: Model-Driven Software Development - Context-Sensitive Transformation

Design 2Build your own DSL

Page 6: Model-Driven Software Development - Context-Sensitive Transformation

Design 2: Purpose

Design a domain-specific language

Domain analysis

★ find abstractions in an existing programming domain

Language design

★ define a notation and translational semantics

Language implementation

★ build IDE and code generator

Understand tradeoffs in language design

Page 7: Model-Driven Software Development - Context-Sensitive Transformation

Design 2: Ingredients

Syntax definition

★ elegant and efficient notation for a domain

Model transformation

★ reduce rich surface syntax to core language

Static analysis

★ find errors during editing

Code generation

★ generate complete implementation from models

Page 8: Model-Driven Software Development - Context-Sensitive Transformation

Design 2: Considerations

Type system

★ do you catch errors at compile-time (in the IDE)?

Customization

★ can application developers work around lack of coverage?

Native interface

★ how are models integrated with environment?

Modularity

★ can models be broken down into smaller components?

Incremental language processing

Page 9: Model-Driven Software Development - Context-Sensitive Transformation

Design 2: Inductive (bottom-up) design

Finding abstractions

Identify coding patterns

★ are there standard patterns in programs in this domain

Identify commonality

★ code generation templates

Identify variability

★ language constructs

Page 10: Model-Driven Software Development - Context-Sensitive Transformation

Design 2: Examples

Improve existing language

- Software building DSL generating ANT

- XML transformation DSL generating XSLT

Abstract from existing framework/library

- DSL for Vaadin (http://vaadin.com)

- Javascript widget DSL generating JQuery or Dojo

- Game DSL generating Ogre C++

AndroidDSL

- Generate Java for Android applications

- Android & Nexus One phones available for experiments

Page 11: Model-Driven Software Development - Context-Sensitive Transformation

JavaSwulimport javax.swing.*;import java.awt.*; public class Test3 { public static void main(String[] ps) { JFrame frame = frame { title = "Welcome!" content = panel of border layout { center = label { text = "Hello World" } south = panel of grid layout { row = { button { text = "cancel" } button { text = "ok"} } } } }; frame.pack(); frame.setVisible(true); }}

import javax.swing.*;import java.awt.*; public class Test3{ public static void main(String[] ps) { JButton jButton_1; JButton jButton_0; JPanel jPanel_1; JLabel jLabel_0; JPanel jPanel_0; JFrame jFrame_0; jFrame_0 = new JFrame(); jFrame_0.setTitle("Welcome!"); jPanel_0 = new JPanel(); BorderLayout borderLayout_0 = new BorderLayout(); jPanel_0.setLayout(borderLayout_0); jFrame_0.setContentPane(jPanel_0); JFrame frame = jFrame_0; jLabel_0 = new JLabel(); jLabel_0.setText("Hello World"); jPanel_0.add(jLabel_0, BorderLayout.CENTER); jPanel_1 = new JPanel(); GridLayout gridLayout_0 = new GridLayout(1, 2); jButton_0 = new JButton(); jButton_0.setText("cancel"); jButton_1 = new JButton(); jButton_1.setText("ok"); jPanel_1.setLayout(gridLayout_0); jPanel_1.add(jButton_0); jPanel_1.add(jButton_1); jPanel_0.add(jPanel_1, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); }}

Page 12: Model-Driven Software Development - Context-Sensitive Transformation

Vaadin

package com.vaadin.demo.simpleaddressbook;

import com.vaadin.Application;import com.vaadin.data.Property;import com.vaadin.data.Property.ValueChangeEvent;import com.vaadin.data.util.IndexedContainer;import com.vaadin.ui.Button;import com.vaadin.ui.Form;import com.vaadin.ui.HorizontalLayout;import com.vaadin.ui.SplitPanel;import com.vaadin.ui.Table;import com.vaadin.ui.TextField;import com.vaadin.ui.VerticalLayout;import com.vaadin.ui.Window;import com.vaadin.ui.Button.ClickEvent;

public class SimpleAddressBook extends Application {

private static String[] fields = { "First Name", "Last Name", "Company", "Mobile Phone", "Work Phone", "Home Phone", "Work Email",

"Home Email", "Street", "Zip", "City", "State", "Country" };

private static String[] visibleCols = new String[] { "Last Name", "First Name", "Company" };

private Table contactList = new Table(); private Form contactEditor = new Form(); private HorizontalLayout bottomLeftCorner = new HorizontalLayout(); private Button contactRemovalButton; private IndexedContainer addressBookData = createDummyData();

@Override

public void init() { initLayout();

initContactAddRemoveButtons();

initAddressList();

initFilteringControls();

}

private void initLayout() { SplitPanel splitPanel = new SplitPanel( SplitPanel.ORIENTATION_HORIZONTAL);

setMainWindow(new Window("Address Book", splitPanel)); VerticalLayout left = new VerticalLayout(); left.setSizeFull();

left.addComponent(contactList);

contactList.setSizeFull();

left.setExpandRatio(contactList, 1);

splitPanel.addComponent(left);

splitPanel.addComponent(contactEditor);

contactEditor.setSizeFull();

contactEditor.getLayout().setMargin(true); contactEditor.setImmediate(true); bottomLeftCorner.setWidth("100%");

left.addComponent(bottomLeftCorner);

}

private void initContactAddRemoveButtons() { // New item button

bottomLeftCorner.addComponent(new Button("+", new Button.ClickListener() { public void buttonClick(ClickEvent event) { Object id = contactList.addItem();

contactList.setValue(id);

}

}));

// Remove item button

contactRemovalButton = new Button("-", new Button.ClickListener() { public void buttonClick(ClickEvent event) { contactList.removeItem(contactList.getValue());

contactList.select(null); }

});

contactRemovalButton.setVisible(false); bottomLeftCorner.addComponent(contactRemovalButton);

}

private String[] initAddressList() { contactList.setContainerDataSource(addressBookData);

contactList.setVisibleColumns(visibleCols);

contactList.setSelectable(true); contactList.setImmediate(true); contactList.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { Object id = contactList.getValue();

contactEditor.setItemDataSource(id == null ? null : contactList .getItem(id));

contactRemovalButton.setVisible(id != null); }

});

return visibleCols; }

private void initFilteringControls() { for (final String pn : visibleCols) { final TextField sf = new TextField(); bottomLeftCorner.addComponent(sf);

sf.setWidth("100%");

sf.setInputPrompt(pn);

sf.setImmediate(true); bottomLeftCorner.setExpandRatio(sf, 1);

sf.addListener(new Property.ValueChangeListener() { public void valueChange(ValueChangeEvent event) { addressBookData.removeContainerFilters(pn);

if (sf.toString().length() > 0 && !pn.equals(sf.toString())) { addressBookData.addContainerFilter(pn, sf.toString(),

true, false); }

getMainWindow().showNotification(

"" + addressBookData.size() + " matches found");

}

});

}

}

private static IndexedContainer createDummyData() {

String[] fnames = { "Peter", "Alice", "Joshua", "Mike", "Olivia",

"Nina", "Alex", "Rita", "Dan", "Umberto", "Henrik", "Rene",

"Lisa", "Marge" };

String[] lnames = { "Smith", "Gordon", "Simpson", "Brown", "Clavel",

"Simons", "Verne", "Scott", "Allison", "Gates", "Rowling",

"Barks", "Ross", "Schneider", "Tate" };

IndexedContainer ic = new IndexedContainer();

for (String p : fields) { ic.addContainerProperty(p, String.class, "");

}

for (int i = 0; i < 1000; i++) { Object id = ic.addItem();

ic.getContainerProperty(id, "First Name").setValue(

fnames[(int) (fnames.length * Math.random())]); ic.getContainerProperty(id, "Last Name").setValue(

lnames[(int) (lnames.length * Math.random())]); }

return ic; }

}

Page 13: Model-Driven Software Development - Context-Sensitive Transformation

Design 2: Advice

Choosing a domain

- choose a domain that you know or are interested to learn

Agile software development

- identify iterations

- minimize risks

- create working version in first week and evolve

Proposal

- don’t get stuck on it

- choose a domain and go

Page 14: Model-Driven Software Development - Context-Sensitive Transformation

Model Transformation

Page 15: Model-Driven Software Development - Context-Sensitive Transformation

Compilation by Normalization

Page 16: Model-Driven Software Development - Context-Sensitive Transformation

Types of Model Transformation

Reduction to sub-language

★ Normalization

★ Desugaring

★ Optimization

★ Aspect weaving

★ Instrumentation

★ Refactoring

Translation to another language

★ Conversion

★ Migration

★ Compilation

Page 17: Model-Driven Software Development - Context-Sensitive Transformation

Term Rewriting

Page 18: Model-Driven Software Development - Context-Sensitive Transformation

Term Rewriting

Term rewrite rules

★ transform term to term

★ pattern matching

★ variable binding

★ substitution

Rewriting strategy

★ algorithm for applying rewrite rules

Page 19: Model-Driven Software Development - Context-Sensitive Transformation

Term Rewrite Rule

desugar : Property(x, t) -> Property(x, t, [])

label/name

left-hand side pattern

right-hand side patternvariable

Page 20: Model-Driven Software Development - Context-Sensitive Transformation

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

Page 21: Model-Driven Software Development - Context-Sensitive Transformation

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

Page 22: Model-Driven Software Development - Context-Sensitive Transformation

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))

Page 23: Model-Driven Software Development - Context-Sensitive Transformation

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

Page 24: Model-Driven Software Development - Context-Sensitive Transformation

Context-sensitiveTransformation

Page 25: Model-Driven Software Development - Context-Sensitive Transformation

Template Inliningdefine page blog(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ outputPost(p) } } }}define outputPost(pst : Post) { navigate post(pst) { output(pst.name) }}define list() { <ul> elements </ul> }define listitem() { <li> elements </li> }define header() { <h1> elements </h1> }

define page blog ( b : Blog ) { <h1> output(b.name) </h1> <ul> for ( p : Post in b.posts ) { <li> navigate post(p) { output(p.name) } </li> } </ul>}

Page 26: Model-Driven Software Development - Context-Sensitive Transformation

Context-sensitive Transformation

Local-to-local

★ replace term by another term

Local-to-global

★ local term influence terms in other parts of model

Global-to-local

★ global information influences transformation of local terms

Page 27: Model-Driven Software Development - Context-Sensitive Transformation

define page blog(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ outputPost(p) } } }}define outputPost(pst : Post) { navigate post(pst) { output(pst.name) }}define list() { <ul> elements </ul> }define listitem() { <li> elements </li> }define header() { <h1> elements </h1> }

define page blog ( b : Blog ) { <h1> output(b.name) </h1> <ul> for ( p : Post in b.posts ) { <li> navigate post(p) { output(p.name) } </li> } </ul>}

Inlining is Global-to-Local

Page 28: Model-Driven Software Development - Context-Sensitive Transformation

outputPost(p) -> navigate post(p) { output(p.name) }where define outputPost(pst : Post) { navigate post(pst) { output(pst.name) } }

Inlining as Rewrite Problem

(this is not a valid Stratego rewrite rule)

Page 29: Model-Driven Software Development - Context-Sensitive Transformation

Rewrite Rules are Context-free

desugar : Property(x, t) -> Property(x, t, [])

Page 30: Model-Driven Software Development - Context-Sensitive Transformation

Simplification: Parameterless Templates

define page blog(b : Blog) { ... footer()}define footer() { navigate url(http://webdsl.org) { “WebDSL” }}

define page blog ( b : Blog ) { ... container() { navigate url(http://webdsl.org) { “WebDSL” } }}

Page 31: Model-Driven Software Development - Context-Sensitive Transformation

Rewrite in Context

Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*

bound in contextlocal traversal

container needed to replace single call with multiple elements

Page 32: Model-Driven Software Development - Context-Sensitive Transformation

Intermezzo:Rewriting Strategies

Page 33: Model-Driven Software Development - Context-Sensitive Transformation

transformation

is

partial* function from terms to terms

* transformation may fail to apply to a term

Page 34: Model-Driven Software Development - Context-Sensitive Transformation

Defining Transformations: Rules & Strategies

Rewrite rules are basic transformations

★ transform term matching lhs to instantiation of rhs

★ evaluate condition (where clause)

Strategies combine rules into complex transformations

★ select rules to apply

★ select algorithm to apply rules

Strategy combinators

★ composition of custom transformations

Page 35: Model-Driven Software Development - Context-Sensitive Transformation

Strategy Combinators

id★ Identity

fail★ failure

s1 ; s2★ sequential composition

s1 <+ s2★ choice

Page 36: Model-Driven Software Development - Context-Sensitive Transformation

Variables

{x, y : s}★ term variable scope

?t★ match term pattern t

!t★ build term pattern t

t1 := t2★ match term t2 to term (pattern) t1

<s> t★ apply strategy s to term t

Page 37: Model-Driven Software Development - Context-Sensitive Transformation

Rewrite Rules

l : t1 -> t2 where s★ named, scoped rewrite rule

★ all variables in t1, t2, s are in scope of the rule

(t1 -> t2 where s)★ unscoped rewrite rule

★ variables are in scope of enclosing scope

Page 38: Model-Driven Software Development - Context-Sensitive Transformation

Rewrite in Context

Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*

bound in context

Page 39: Model-Driven Software Development - Context-Sensitive Transformation

[ TemplateDef( "footer" , [] , [Navigate(PageRef("webdsl", []), [String("WebDSL")])] ), TemplateDef( "blog" , [Param("b", SimpleType("Blog"))] , [Call("footer")] )]

Inline : [def@TemplateDef(f,[],elem*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem*)))> def1*

f elem*

def1*Call(f)

Page 40: Model-Driven Software Development - Context-Sensitive Transformation

Strategy Definitions

f(x,y|a,b) = s★ x, y are strategy parameters

★ a, b are term parameters

★ s uses all parameters

f(x) = s f = s★ term parameters are optional

★ all parameters are optional

Examples

★ try(s) = s <+ id★ repeat(s) = try(s; repeat(s))

Page 41: Model-Driven Software Development - Context-Sensitive Transformation

Rules with Parameters

Transform all elements of a list

Invert order of elements of a list

Pair elements of two lists

inverse(|ys) : [] -> ys

inverse(|ys) : [x|xs] -> <inverse(|[x|ys])> xs

map(s) : [] -> []

map(s) : [x|xs] -> [<s>x | <map(s)> xs]

zip(s) : ([],[]) -> []

zip(s) : ([x|xs],[y|ys]) -> [<s>(x,y) | <zip(s)>(xs,ys)]

Page 42: Model-Driven Software Development - Context-Sensitive Transformation

Traversal Combinators

all(s)★ apply s to all direct sub-terms (children)

one(s)★ apply s to exactly one sub-term

some(s)★ apply s to at least one sub-term

Page 43: Model-Driven Software Development - Context-Sensitive Transformation

Traversal Strategies

topdown(s) = s; all(topdown(s))★ apply s to all sub-terms in top-down order

bottomup(s) = all(bottomup(s)); s★ apply s to all sub-terms in bottom-up order

oncetd(s) = s <+ one(oncetd(s))★ apply s to one sub-term

alltd(s) = s <+ all(alltd(s))★ apply s to frontier

Page 44: Model-Driven Software Development - Context-Sensitive Transformation

Rewrite in Context: Local Traversal

Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*

local traversal

Page 45: Model-Driven Software Development - Context-Sensitive Transformation

Dynamic Rewrite Rules

Page 46: Model-Driven Software Development - Context-Sensitive Transformation

Rewrite in Context: Not Optimal

requires def before use local traversal for each declaration

Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*

Page 47: Model-Driven Software Development - Context-Sensitive Transformation

Dynamic Rewrite Rules

separate traversal from rule definition (binding closures)

declare-inline : TemplateDef(f,[],elem1*) -> TemplateDef(f,[],elem1*) where rules( InlineTemplate : Call(f) -> Call("container", elem1*) )

inline = alltd(declare-inline); topdown(try(InlineTemplate))

Inline : [def@TemplateDef(f,[],elem1*) | def1*] -> [def | def2*] where def2* := <alltd((Call(f) -> Call("container", elem1*)))> def1*

Page 48: Model-Driven Software Development - Context-Sensitive Transformation

outputPost(p) -> navigate post(p) { output(p.name) }where define outputPost(pst : Post) { navigate post(pst) { output(pst.name) } }

Inlining as Rewrite Problem (Revisited)

(informal)

declare-inline : TemplateDef(f,[],elem1*) -> TemplateDef(f,[],elem1*) where rules( InlineTemplate : Call(f) -> Call("container", elem1*) )

(formal; but not yet complete)

Page 49: Model-Driven Software Development - Context-Sensitive Transformation

Template Parameterdefine page blog(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ outputPost(p) } } }}define outputPost(pst : Post) { navigate post(pst) { output(pst.name) }}define list() { <ul> elements </ul> }define listitem() { <li> elements </li> }define header() { <h1> elements </h1> }

define page blog ( b : Blog ) { <h1> output(b.name) </h1> <ul> for ( p : Post in b.posts ) { <li> navigate post(p) { output(p.name) } </li> } </ul>}

Page 50: Model-Driven Software Development - Context-Sensitive Transformation

declare-inline : def@TemplateDef(mod*,f,param*,elem1*) -> def where rules( InlineTemplate : Call(f, e*, []) -> Call("container", [], elem3*) where elem3* := <substitute> (param*, e*, elem1*) ) substitute : (param*, e*, elem1*) -> elem2* where {| Subst : <zip(bind-arg)> (param*, e*) ; elem2* := <alltd(Subst)> elem1* |} bind-arg : (Param(x, t), e) -> (Param(x, t), e) where rules( Subst : Var(x) -> e )

Inlining Templates with Parameters

Page 51: Model-Driven Software Development - Context-Sensitive Transformation

declare-inline : def@TemplateDef(mod*,f,param*,elem1*) -> def where rules( InlineTemplate : Call(f, e*, elem2*) -> Call("container", [], elem3*) where {| Subst : rules( Subst : Elements() -> Call("container",[],elem2*) ) ; elem3* := <substitute> (param*, e*, elem1*) |} )

define list() { <ul> elements </ul> }

Element Parameters

Page 52: Model-Driven Software Development - Context-Sensitive Transformation

Removing Intermediate Structures

rules // remove containers desugar-container : [Call("container",[], elem1*) | elem2*] -> [elem1*, elem2*] desugar : elem1* -> elem2* where elem2* := <at-suffix(desugar-container)> elem1*

container needed to replace single call with multiple elements

Page 53: Model-Driven Software Development - Context-Sensitive Transformation

Inlining Strategy

module template-inlining

imports libstratego-libimports include/nwlimports desugar

strategies inline-all = desugar-all; alltd(declare-inline); innermost(desugar <+ InlineTemplate)

rules declare-inline : ...

Page 54: Model-Driven Software Development - Context-Sensitive Transformation

module template-inlining

imports libstratego-libimports include/nwlimports desugar

strategies inline-all = desugar-all; alltd(declare-inline); innermost(desugar <+ InlineTemplate)

rules declare-inline : TemplateDef(mod*,f,param*,elem1*) -> TemplateDef(mod*,f,param*,elem1*) where rules( InlineTemplate : Call(f, e*, elem2*) -> Call("container", [], elem3*) where {| Subst : rules( Subst : Elements() -> Call("container", [], elem2*) ) ; elem3* := <substitute> (param*, e*, elem1*) |} ) substitute : (param*, e*, elem1*) -> elem2* where {| Subst : <zip(bind-arg)> (param*, e*) ; elem2* := <alltd(Subst)> elem1* |} bind-arg : (Param(x, t), e) -> (Param(x, t), e) where rules( Subst : Var(x) -> e )

rules // remove containers desugar-container : [Call("container",[], elem1*) | elem2*] -> [elem1*, elem2*] desugar : elem1* -> elem2* where elem2* := <at-suffix(desugar-container)> elem1*

Template Inlining Transformation

Page 55: Model-Driven Software Development - Context-Sensitive Transformation

Free Variable Capture

Page 56: Model-Driven Software Development - Context-Sensitive Transformation

Free Variable Capture in Template Inlining

define page blogfront(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ postInline(p) { par{ "Posted by " outputUser(p.author) } } } } }}define postInline(pst : Post) { header{output(pst.title)} output(pst.text) for(p : Tag in pst.tags) { elements }}

Page 57: Model-Driven Software Development - Context-Sensitive Transformation

define page blogfront(b : Blog) { header{output(b.name)} list{ for(p : Post in b.posts) { listitem{ postInline(p) { par{ "Posted by " outputUser(p.author) } } } } }}define postInline(pst : Post) { header{output(pst.title)} output(pst.text) for(p : Tag in pst.tags) { elements }}

define page blogfront(b : Blog) { <h1> output(b.name) </h1> <ul> for(p : Post in b.posts) { <li> <h1>output(p.title)</h1> output(p.text) for ( p : Tag in p.tags ) { <p> "Posted by " navigate user(p.author) { output(p.author.name) } </p> } </li> } </ul>}

Free Variable Capture in Template Inlining

Page 58: Model-Driven Software Development - Context-Sensitive Transformation

define page blogfront(b : Blog) { for(p : Post in b.posts) { for(p : Tag in p.tags) { output(p.name) "Posted by " navigate user(p.author) { output(p.author.name) } } }}

Free Variable Capture in Template Inlining

define page blogfront(b : Blog) { for(p : Post in b.posts) { postInline(p) { "Posted by " outputUser(p.author) } }}define postInline(pst : Post) { for(p : Tag in pst.tags) { output(p.name) elements }}

Page 59: Model-Driven Software Development - Context-Sensitive Transformation

Avoiding Free Variable Capture

substitute-args : (param*, e*, elem1*) -> elem2* where {| Subst : <zip(bind-arg)> (param*, e*) ; elem2* := <substitute> elem1* |} substitute = alltd(Subst <+ rename-bound) rename-bound : ForElem(x, t, e1, elem1*) -> ForElem(y, t, e2, elem2*) where {| Subst : y := <newname> x ; e2 := <substitute> e1 ; rules( Subst : Var(x) -> Var(y) ) ; elem2* := <substitute> elem1* |}

rename bound variables

Page 60: Model-Driven Software Development - Context-Sensitive Transformation

define page blogfront(b : Blog) { for(p : Post in b.posts) { for(p3 : Tag in p.tags) { output(p3.name) "Posted by " navigate user(p.author) { output(p.author.name) } } }}

Free Variable Capture in Template Inlining

define page blogfront(b : Blog) { for(p : Post in b.posts) { postInline(p) { "Posted by " outputUser(p.author) } }}define postInline(pst : Post) { for(p : Tag in pst.tags) { output(p.name) elements }}

Page 61: Model-Driven Software Development - Context-Sensitive Transformation

Aspect Weaving

Page 62: Model-Driven Software Development - Context-Sensitive Transformation

Aspect Weaving

Aspect definition

★ modular definition of cross cutting concerns

Aspect weaving

★ apply aspects to base program

Applications

★ instrumentation for logging, tracing, debugging, profiling

★ access control, data validation, entity extension

Page 63: Model-Driven Software Development - Context-Sensitive Transformation

Access Control Rulesdefine page post(p : Post) { header{output(p.title)} output(p.text) par{ "Posted by " outputUser(p.author) } navigate editpost(p) { "Edit" }}

rule page editpost(pst : Post) { principal == pst.blog.author}

define page editpost(p : Post) { action save() { return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save() { "Save" } }}

Page 64: Model-Driven Software Development - Context-Sensitive Transformation

Access Control Weavingdefine page post(p : Post) { header{output(p.title)} output(p.text) par{ "Posted by " outputUser(p.author) } navigate editpost(p) { "Edit" }}

rule page editpost(pst : Post) { principal == pst.blog.author}

define page editpost(p : Post) { action save() { return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save() { "Save" } }}

Page 65: Model-Driven Software Development - Context-Sensitive Transformation

Access Control Weaving: Protect Pagedefine page post(p : Post) { header{output(p.title)} output(p.text) par{ "Posted by " outputUser(p.author) } navigate editpost(p) { "Edit" }}

rule page editpost(pst : Post) { principal == pst.blog.author}

define page editpost(p : Post) { action save() { return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save() { "Save" } }}

define page editpost(p : Post) { init { if(!(principal == pst.blog.author)) { return accessdenied() ; } } action save() { return post(p) ; } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save ( ) { "Save" } }}

Page 66: Model-Driven Software Development - Context-Sensitive Transformation

Access Control Weaving: Protect Linkdefine page post(p : Post) { header{output(p.title)} output(p.text) par{ "Posted by " outputUser(p.author) } navigate editpost(p) { "Edit" }}

rule page editpost(pst : Post) { principal == pst.blog.author}

define page editpost(p : Post) { action save() { return post(p); } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save() { "Save" } }}

define page editpost(p : Post) { init { if(!(principal == pst.blog.author)) { return accessdenied() ; } } action save() { return post(p) ; } header{output(p.title)} form{ input(p.url) input(p.title) input(p.text) submit save ( ) { "Save" } }}

define page post ( p : Post ) { header{output(p.title)} output(p.text) par{"Posted by "outputUser(p.author)} if(principal == p.blog.author) { navigate editpost(p) { "Edit" } } }

Page 67: Model-Driven Software Development - Context-Sensitive Transformation

Access Control Weaving: Strategy

weave-ac-rules = alltd(declare-ac-rule); bottomup(try(ProtectPage <+ ProtectNavigate))

Page 68: Model-Driven Software Development - Context-Sensitive Transformation

Access Control Weaving: Protect Navigate

declare-ac-rule : r@Rule([Page()], f, param1*, e) -> r where rules( ProtectNavigate : elem@Navigate(PageRef(f, e*), elem*) -> If(e2,Block([elem]),Block([])) where e2 := <substitute-args> (param1*, e*, e) )

Page 69: Model-Driven Software Development - Context-Sensitive Transformation

Access Control Weaving: Protect Page

declare-ac-rule : r@Rule([Page()], f, param1*, e) -> r where rules( ProtectNavigate : ...

ProtectPage : TemplateDef([Page()], f, param2*, elem*) -> TemplateDef([Page()], f, param2*, [Init([ If(Not(e), Block([ReturnPage(PageRef("accessdenied", []))]), Block([]))]), elem*]) where e2 := <substitute-args> (param1*, <map(param-to-exp)> param2*, e) )

param-to-exp : Param(x, t) -> Var(x)

Page 70: Model-Driven Software Development - Context-Sensitive Transformation

Access Control Weaving: Complete*

weave-ac-rules = alltd(declare-ac-rule); bottomup(try(ProtectPage <+ ProtectNavigate))declare-ac-rule : r@Rule([Page()], f, param1*, e) -> r where rules( ProtectPage : TemplateDef([Page()], f, param2*, elem1*) -> TemplateDef([Page()], f, param2*, [Init([ If(Not(e), Block([ReturnPage(PageRef("accessdenied", []))]), Block([]))]), elem1*]) where e2 := <substitute-args> (param1*, <map(param-to-exp)> param2*, e) ProtectNavigate : elem@Navigate(PageRef(f, e*), elem*) -> If(e2,Block([elem]),Block([])) where e2 := <substitute-args> (param1*, e*, e) )param-to-exp : Param(x, t) -> Var(x)

* complete specification for this limited example; WebDSL AC is more complex

Page 71: Model-Driven Software Development - Context-Sensitive Transformation

Extend Entity

module blog

entity Post { url : String (id) title : String (name) text : WikiText blog : Blog (inverse:posts) author : User blog : Blog}

modular extensibility => more cohesion (?)

module tags

entity Tag { key : String (id) title : String (name) text : WikiText posts : Set<Post> }

extend entity Post { tags : Set<Tag> (inverse:posts)}

Page 72: Model-Driven Software Development - Context-Sensitive Transformation

Extend Entity

module blog

entity Post { url : String (id) title : String (name) text : WikiText blog : Blog (inverse:posts) author : User blog : Blog}

modular extensibility => more cohesion (?)

module tags

entity Tag { key : String (id) title : String (name) text : WikiText posts : Set<Post> }

extend entity Post { tags : Set<Tag> (inverse:posts)}

module woven

entity Post { url : String (id) title : String (name) text : WikiText blog : Blog (inverse:posts) author : User blog : Blog tags : Set<Tag> (inverse:posts)}

entity Tag { key : String (id) title : String (name) text : WikiText posts : Set<Post> }

Page 73: Model-Driven Software Development - Context-Sensitive Transformation

Other Model Transformations

Page 74: Model-Driven Software Development - Context-Sensitive Transformation

Other Applications of Model Transformation

Refactoring

★ behaviour preserving transformation to improve design

★ e.g. extract/inline function/template/entity

Difference detection

★ detect differences between two models

Migration

★ update model to conform to new meta-model

Optimization

★ derive more efficient version

★ e.g. query prefetching

Page 75: Model-Driven Software Development - Context-Sensitive Transformation

Schedule

Case 3

★ Syntax definition & term rewriting

★ Deadline:

Design 2

★ Make a proposal (can be submitted separately)

★ Deadline:

Lab this week

★ Install Spoofax

★ Make Case 3

Next

★ Lecture 9: static analysis