Anthony M. Sloane Matthew Roberts Leonard G. C. Hamey Programming Languages and Verification Research Group Department of Computing Macquarie University @plvmq [email protected] @inkytonik
developers shallow embedding in Scala sub-languages attribute grammars strategic term rewriting abstract state machines pretty-printing Structures structure definition is not under our control immutable trees and graphs with node identity Attribution attributes are first-class values storage is outside the attributed structure memoisation of attribute values is based on node identity 2 / 22
many attributes need to consider nodes in context Rewriting: transforming a structure into another structure it is common to share nodes between or within the trees Problem: if a node is shared between structures, what is its context? 11 / 22
Bundle structure root with the relations defined by reachability child, parent, prev, next, siblings, . . . Bonus: relations become powerful pattern matchers Attribute families Context-dependent attributes are families, indexed by a Tree Equations use the tree relations to access the context 12 / 22
relation between T and U val r : Relation[T,U] = ... a is an attribute on T of type V a(t) applies a to t of type T val a : T => V = attr { case r (p1) => // if (t,u) in r and p1 matches u case r.pair (p0 , p1) => // if (t,u) in r, p0 matches t and p1 matches u } 17 / 22
]) { val depth : Node => Int = attr { case tree.parent (p) => depth (p) + 1 case _ => 0 } } val root : Node = ... val tree = new Tree[Node ,Node] (root) val depthModule = new DepthModule (tree) val n : Node = ... ... depthModule.depth (n) ... 18 / 22
Type Value "," Type Value. Conversion ::= ConvOp Type Value "to" Type. Type Named prev tipe name collect[Vector , (Name , Type)] { case tree.prev.pair (Named (name), tipe : Type) => (name , tipe) } 19 / 22
simplify = bottomup (rule { case Plus (Num (0), r) => r case Plus (l, Num (0)) => l }) User of context-dependent attribute must provide the Tree val m, n : Node = ... val orig = Plus (Plus (Num (0), m), n) val treeOrig = new Tree[Node ,Node] (orig) val dOrig = new DepthModule (treeOrig).depth (m) val simp = rewrite (simplify) (orig) val treeSimp = new Tree[Node ,Node] (simp) val dSimp = new DepthModule (treeSimp).depth (m) 20 / 22
by rewrites rule { case Plus (l, r) => Plus (l, Plus (l, r)) } If context-dependent attribution is to be performed: sharing breaks uniqueness of node identity in the structure solution: the Tree class lazily clones shared sub-structure hence we only clone if context-attribution requires it 21 / 22
structure many attributes need to consider nodes in context Rewriting: transforming a structure into another structure it is common to share nodes between or within the trees Problem: if a node is shared between structures, what is its context? Solution: Trees make node contexts explicit via relations attribute families are defined using Trees first-class relations provide pattern matching support more detail: see our SLE 2014 paper implemented in the upcoming Kiama 2.0 https://bitbucket.org/inkytonik/kiama 22 / 22