Classes
Class definitions
Class definitions are written using CLASSDEF(...):
import treehugger.forest._, definitions._, treehuggerDSL._
val tree = (CLASSDEF("C"): Tree)
// tree: Tree = ClassDef(
// Modifiers(0L, TypeName(""), List()),
// Modifiers(0L, TypeName(""), List()),
// TypeName("C"),
// List(),
// List(),
// Template(
// List(),
// ValDef(Modifiers(4L, TypeName(""), List()), Ident(TermName("_")), EmptyTree),
// List()
// )
// )
treeToString(tree)
// res0: String = "class C"
val tree2 = CLASSDEF("C") := BLOCK(
VAL("x") := LIT(0)
)
// tree2: ClassDef = ClassDef(
// Modifiers(0L, TypeName(""), List()),
// Modifiers(0L, TypeName(""), List()),
// TypeName("C"),
// List(),
// List(),
// Template(
// List(),
// ValDef(Modifiers(4L, TypeName(""), List()), Ident(TermName("_")), EmptyTree),
// List(
// ValDef(
// Modifiers(0L, TypeName(""), List()),
// Ident(TermName("x")),
// Literal(Constant(0))
// )
// )
// )
// )
treeToString(tree2)
// res1: String = """class C {
// val x = 0
// }"""
The general form of the first example is:
CLASSDEF(sym|"C").empty
As with value and function names, CLASSDEF can accept either a symbol or a String.
Constructor parameters
Primary constructor parameters are written using withParams(...) similar to function definitions. Except, it could use VAL(...) and VAR(...) in addition to PARAM(...):
val tree3 = (CLASSDEF("C")
withParams(PARAM("x", IntClass),
VAL("y", StringClass),
VAR("z", TYPE_LIST(StringClass))) := BLOCK(
DEF("hi") := LIT("hi")
))
// tree3: ClassDef = ClassDef(
// Modifiers(0L, TypeName(""), List()),
// Modifiers(0L, TypeName(""), List()),
// TypeName("C"),
// List(),
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("x")), TypeTree()),
// EmptyTree
// ),
// ValDef(
// Modifiers(0L, TypeName(""), List()),
// Typed(Ident(TermName("y")), TypeTree()),
// EmptyTree
// ),
// ValDef(
// Modifiers(4096L, TypeName(""), List()),
// Typed(Ident(TermName("z")), TypeTree()),
// EmptyTree
// )
// ),
// Template(
// List(),
// ValDef(Modifiers(4L, TypeName(""), List()), Ident(TermName("_")), EmptyTree),
// List(
// DefDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("hi"),
// List(),
// List(),
// TypeTree(),
// Literal(Constant("hi"))
// )
// )
// )
// )
treeToString(tree3)
// res2: String = """class C(x: Int, val y: String, var z: List[String]) {
// def hi = "hi"
// }"""
Constructor definitions
Auxiliary constructors are defined using DEFTHIS := BLOCK(stat, ...). Optionally, DEFTHIS may take withParams(...):
val tree4 = (CLASSDEF("C")
withParams(PARAM("s", StringClass)) := BLOCK(
DEFTHIS withParams(PARAM("x", IntClass)) := BLOCK(
THIS APPLY(REF("x") TOSTRING)
)
))
// tree4: ClassDef = ClassDef(
// Modifiers(0L, TypeName(""), List()),
// Modifiers(0L, TypeName(""), List()),
// TypeName("C"),
// List(),
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("s")), TypeTree()),
// EmptyTree
// )
// ),
// Template(
// List(),
// ValDef(Modifiers(4L, TypeName(""), List()), Ident(TermName("_")), EmptyTree),
// List(
// DefDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("_$this"),
// List(),
// List(
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("x")), TypeTree()),
// EmptyTree
// )
// )
// ),
// TypeTree(),
// Block(
// List(),
// Apply(
// This(TypeName("")),
// List(Select(Ident(TermName("x")), TermName("toString")))
// )
// )
// )
// )
// )
// )
treeToString(tree4)
// res3: String = """class C(s: String) {
// def this(x: Int) = {
// this(x.toString)
// }
// }"""
Extending classes
To define classes by extending super classes use withParents(tree|typ|"T"):
scala> val tree5 = CLASSDEF("C") withParents("B") := BLOCK(
DEF("x") := LIT(0)
)
scala> treeToString(tree5)
Self type annotations
To define self type annotations use withSelf(sym|"self", [typ1, ...]):
val tree6 = CLASSDEF("C") withSelf("self", "T1", "T2") := BLOCK(
VAL("x") := REF("self")
)
// tree6: ClassDef = ClassDef(
// Modifiers(0L, TypeName(""), List()),
// Modifiers(0L, TypeName(""), List()),
// TypeName("C"),
// List(),
// List(),
// Template(
// List(),
// ValDef(
// Modifiers(0L, TypeName(""), List()),
// Typed(Ident(TermName("self")), TypeTree()),
// EmptyTree
// ),
// List(
// ValDef(
// Modifiers(0L, TypeName(""), List()),
// Ident(TermName("x")),
// Ident(TermName("self"))
// )
// )
// )
// )
treeToString(tree6)
// res4: String = """class C { self: T1 with T2 =>
// val x = self
// }"""
Early denifitions
To define field values before supertype constructor is called add early definitions using withEarlyDefs(tree, ...):
val tree7 = CLASSDEF("C") withEarlyDefs(
VAL("name") := LIT("Bob")
) withParents("B") := BLOCK(
LIT(0)
)
// tree7: ClassDef = ClassDef(
// Modifiers(0L, TypeName(""), List()),
// Modifiers(0L, TypeName(""), List()),
// TypeName("C"),
// List(),
// List(),
// Template(
// List(
// Block(
// List(),
// ValDef(
// Modifiers(0L, TypeName(""), List()),
// Ident(TermName("name")),
// Literal(Constant("Bob"))
// )
// ),
// TypeTree()
// ),
// ValDef(Modifiers(4L, TypeName(""), List()), Ident(TermName("_")), EmptyTree),
// List(Literal(Constant(0)))
// )
// )
treeToString(tree7)
// res5: String = """class C extends {
// val name = "Bob"
// } with B {
// 0
// }"""