Functions
Abstract function declarations
Abstract function declarations are written using DEF(...) or PROC(...). Optionally, parameter lists can be specified using withParams(PARAM(...), ...) and type parameters can be specified using withTypeParams(TYPEVAR(...), ...):
import treehugger.forest._, definitions._, treehuggerDSL._
val tree = DEF("get", IntClass).tree
val tree2 = (DEF("sideEffect", UnitClass) withParams()).tree
val tree3 = (PROC("put") withParams(PARAM("x", IntClass))).tree
object sym {
val A = RootClass.newAliasType("A")
val B = RootClass.newAliasType("B")
}
val tree4 = (DEF("compare", BooleanClass)
withTypeParams(TYPEVAR(sym.A))
withParams(PARAM("a", sym.A) := LIT(0))
withParams(PARAM("b", sym.A) := LIT(0)): Tree)
The above examples print as:
treeToString(tree)
// res0: String = "def get: Int"
treeToString(tree2)
// res1: String = "def sideEffect(): Unit"
treeToString(tree3)
// res2: String = "def put(x: Int)"
treeToString(tree4)
// res3: String = "def compare[A](a: A = 0)(b: A = 0): Boolean"
In genral, for functions with return type:
(DEF("get"|sym, typ)
[withParams(PARAM("x"|sym, typ|"C")[ := arg], ...)]*
[withTypeParams(TYPEVAR(...), ...)]).tree
For procedures:
(PROC("get"|sym)
[withParams(PARAM("x"|sym, typ|"C")[ := arg], ...)]*
[withTypeParams(TYPEVAR(...), ...)]).tree
Function definition
Function definitions are written by appending right-hand side tree after := as follows:
val tree5 = DEF("get", IntClass) := LIT(0)
// tree5: DefDef = DefDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("get"),
// List(),
// List(),
// TypeTree(),
// Literal(Constant(0))
// )
treeToString(tree5)
// res4: String = "def get: Int = 0"
The result type can be omitted using DEF(...) as follows:
val tree6 = DEF("get") := LIT(0)
// tree6: DefDef = DefDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("get"),
// List(),
// List(),
// TypeTree(),
// Literal(Constant(0))
// )
treeToString(tree6)
// res5: String = "def get = 0"
When rhs is a BLOCK(tree, ...) you need to use DEFINFER(...) to differentiate from procedures (PROC was added in 0.4.0).
val tree7 = DEFINFER("get") := BLOCK(LIT(0))
// tree7: DefDef = DefDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("get"),
// List(),
// List(),
// TypeTree(),
// Block(List(), Literal(Constant(0)))
// )
treeToString(tree7)
// res6: String = """def get = {
// 0
// }"""
Procedures
Procedure definitions are written using PROC(...) with BLOCK(tree, ...) for the rhs:
val tree8 = PROC("write") withParams(PARAM("str", StringClass)) := BLOCK(
LIT(0)
)
// tree8: ProcDef = ProcDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("write"),
// List(),
// List(
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("str")), TypeTree()),
// EmptyTree
// )
// )
// ),
// Block(List(), Literal(Constant(0)))
// )
treeToString(tree8)
// res7: String = """def write(str: String) {
// 0
// }"""
Currying
Note withParams(...) clause may be added multiple times, each forming a parameter list:
val tree9 = (DEF("compare")
withTypeParams(TYPEVAR(sym.A))
withParams(PARAM("a", sym.A))
withParams(PARAM("b", sym.A))) := FALSE
// tree9: DefDef = DefDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("compare"),
// List(
// TypeDef(
// Modifiers(0L, TypeName(""), List()),
// TypeName("A"),
// List(),
// EmptyTree
// )
// ),
// List(
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("a")), TypeTree()),
// EmptyTree
// )
// ),
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("b")), TypeTree()),
// EmptyTree
// )
// )
// ),
// TypeTree(),
// Literal(Constant(false))
// )
treeToString(tree9)
// res8: String = "def compare[A](a: A)(b: A) = false"
Default parameters
Similar to VAL(...), PARAM(...) can be followed by := and rhs to specify the default argument:
val tree10 = (DEF("compare")
withTypeParams(TYPEVAR(sym.A))
withParams(PARAM("a", sym.A) := LIT(0))
withParams(PARAM("b", sym.A) := LIT(0))) := FALSE
// tree10: DefDef = DefDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("compare"),
// List(
// TypeDef(
// Modifiers(0L, TypeName(""), List()),
// TypeName("A"),
// List(),
// EmptyTree
// )
// ),
// List(
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("a")), TypeTree()),
// Literal(Constant(0))
// )
// ),
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("b")), TypeTree()),
// Literal(Constant(0))
// )
// )
// ),
// TypeTree(),
// Literal(Constant(false))
// )
treeToString(tree10)
// res9: String = "def compare[A](a: A = 0)(b: A = 0) = false"
By-name parameters
By-name parameters are written using TYPE_BYNAME(typ) as follows:
val tree11 = (PROC("whileLoop")
withParams(PARAM("cond", TYPE_BYNAME(BooleanClass)))
withParams(PARAM("stat", TYPE_BYNAME(UnitClass))): Tree)
// tree11: Tree = ProcDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("whileLoop"),
// List(),
// List(
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("cond")), TypeTree()),
// EmptyTree
// )
// ),
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("stat")), TypeTree()),
// EmptyTree
// )
// )
// ),
// EmptyTree
// )
treeToString(tree11)
// res10: String = "def whileLoop(cond: => Boolean)(stat: => Unit)"
Repeated parameters
Repeated parameters are written using TYPE_*(typ) as follows:
val tree12 = (DEF("sum", IntClass)
withParams(PARAM("args", TYPE_*(IntClass))): Tree)
// tree12: Tree = DefDef(
// Modifiers(0L, TypeName(""), List()),
// TermName("sum"),
// List(),
// List(
// List(
// ValDef(
// Modifiers(8192L, TypeName(""), List()),
// Typed(Ident(TermName("args")), TypeTree()),
// EmptyTree
// )
// )
// ),
// TypeTree(),
// EmptyTree
// )
treeToString(tree12)
// res11: String = "def sum(args: Int*): Int"