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"