Kiama is a Scala library for language processing. It enables convenient analysis and transformation of structured data. The programming styles supported by the library are based on well-known formal language processing paradigms, including attribute grammars, tree rewriting, abstract state machines, and pretty printing.
Kiama is a project of the Programming Languages Research Group in the Department of Computing at Macquarie University and is led by Tony Sloane (inkytonik on GMail and Twitter). Other participants at Macquarie are Dominic Verity, Matthew Roberts and the PLRG group students.
Collaborators on the Kiama project have included the Software Engineering Research Group at the Delft University of Technology in The Netherlands, notably Eelco Visser and Lennart Kats.
A traditional approach to language processing is to represent the data to be processed as a hierarchical structure (a tree). Kiama provides different ways to operate on such trees to carry out typical language processing tasks.
Context-sensitive attribute equations
Attribute equations define properties of tree nodes in terms of constants or the properties of other nodes. In this example, the local and global minima of a binary tree (locmin
and globmin
) are defined using simple local equations. The arrow notation denotes accessing an attribute (property) of a node. The attr
function provides caching and circularity checking to the equations. The parent
field provides access to the parent of a node.
val locmin : Tree ==> Int =
attr {
case Fork (l, r) => (l->locmin) min (r->locmin)
case Leaf (v) => v
}
val globmin : Tree ==> Int =
attr {
case t if t isRoot => t->locmin
case t => t.parent[Tree]->globmin
}
Sometimes it is useful to define attributes using a mutual dependency. With attr
this approach would lead to an error since it would not be possible to calculate the values of such attributes. The circular
function goes further by implementing mutually dependent attributes via an iteration to a fixed point. In this example, we are calculating variable liveness information for a imperative language statements using the standard data flow equations.
val in : Stm ==> Set[Var] =
circular (Set[Var]()) {
case s => uses (s) ++ (out (s) -- defines (s))
}
val out : Stm ==> Set[Var] =
circular (Set[Var]()) {
case s => (s->succ) flatMap (in)
}
Rewrite rules and higher-order rewriting strategies
While attributes provide a way to decorate a tree with information, rewriting is concerned with transforming trees, perhaps for translation or for optimisation. Kiama contains a strategy-based rewriting library heavily inspired by the Stratego program transformation language. In this example, we are implementing an evaluation strategy for lambda calculus, using generic strategies such as innermost rewriting.
val beta =
rule {
case App (Lam (x, t, e1), e2) => Let (x, t, e2, e1)
}
val lambda =
beta + arithop + subsNum + subsVar + subsApp + subsLam + subsOpn
def innermost (s : => Strategy) : Strategy =
all (innermost (s) <* attempt (s <* innermost (s)))
lazy val s : Strategy =
innermost (lambda)
Kiama's pretty-printing library provides a flexible way to describe how you want your output to be produced within constraint of line length. For example, the following describes how to pretty-print the constructs of a simple imperative language, where group
, nest
and line
cooperate to produce nicely indented code that breaks lines at sensible place when needed.
def show (t : ImperativeNode) : Doc =
t match {
case Num (d) => value (d)
case Var (s) => s
case Neg (e) => parens ("-" <> show (e))
case Add (l, r) => showbin (l, "+", r)
case Sub (l, r) => showbin (l, "-", r)
case Mul (l, r) => showbin (l, "*", r)
case Div (l, r) => showbin (l, "/", r)
case Null () => semi
case Seqn (ss) => group (braces (nest (line <> ssep (ss map show, line)) <> line))
case Asgn (v, e) => show (v) <+> "=" <+> show (e) <> semi
case While (e, b) => "while" <+> parens (show (e)) <> group (nest (line <> show (b)))
}
def showbin (l : ImperativeNode, op : String, r : ImperativeNode) : Doc =
parens (show (l) <+> op <+> show (r))
Work on this project has been supported by the following Universities, funding agencies and companies.
Delft University of Technology, The Netherlands
Eindhoven University of Technology, The Netherlands
Netherlands Organization for Scientific Research
YourKit
YourKit is kindly supporting open source projects with its full-featured Java Profiler. YourKit, LLC is the creator of innovative and intelligent tools for profiling Java and .NET applications. Take a look at YourKit's leading software products: YourKit Java Profiler and YourKit .NET Profiler.
CloudBees
CloudBees provides generous support to FOSS projects for continuous builds and other services, for which we are very grateful. Kiama nightly builds are built on a CloudBees Jenkins instance, part of their DEV@cloud service.