Skip to main content

Tree Examples

This document lists examples of how Scala source code maps to Scalameta tree nodes.

Top level (meta.Source, meta.Pkg, meta.Pkg.Object)​

"package a".parse[Source].get.structure

Source(stats = List(Pkg(ref = Term.Name("a"), stats = Nil)))

Declarations (meta.Decl)​

"val a: Int".parse[Stat].get.structure

Decl.Val(
mods = Nil,
pats = List(Pat.Var(name = Term.Name("a"))),
decltpe = Type.Name("Int")
)
DeclExamples
Decl.Valval a: Int
Decl.Varvar a: Int
Decl.Defdef f: Int
Decl.Typetype T

Definitions (meta.Defn)​

"val a = 1".parse[Stat].get.structure

Defn.Val(
mods = Nil,
pats = List(Pat.Var(name = Term.Name("a"))),
decltpe = None,
rhs = Lit.Int(value = 1)
)
DefnExamples
Defn.Valval a = 1
Defn.Varvar a = 1
Defn.Defdef f = 1
Defn.Macrodef f = macro impl
Defn.Typetype T = Int
Defn.Classclass A
Defn.Traittrait A
Defn.Objectobject A
Defn.Enumenum A (Scala 3)
Defn.EnumCasecase A1 extends A (Scala 3)
Defn.RepeatedEnumCasecase A1, A2 (Scala 3)
Defn.Givengiven A as C[T] (Scala 3)
Defn.GivenAliasgiven C[T] = A (Scala 3)
Defn.ExtensionGroupextension (b: B) def a = 1 (Scala 3)

Terms (meta.Term)​

"1 + 1".parse[Term].get.structure

Term.ApplyInfix(
lhs = Lit.Int(value = 1),
op = Term.Name("+"),
targs = Nil,
args = List(Lit.Int(value = 1))
)
RefExamples
Term.Thisthis, a.this
Term.Supersuper, a.super, super[a], a.super[b]
Term.Namea
Term.Selecta.b
Term.ApplyUnary!a, ~a, -a, a
TermExamples
Term.Applyf(42)
Term.ApplyTypeimplicitly[Ordering[Int]]
Term.ApplyInfixa + a
Term.Assigna = 1
Term.Returnreturn a
Term.Throwthrow e
Term.Ascribea: Int
Term.Annotate(x: @annot)
Term.Tuple(1, 1)
Term.Block{ f1(); f2() }
Term.Ifif (p) t else f
Term.Matchx match { case _ => }
Term.Trytry f catch { case _ => }
Term.TryWithHandlertry f catch (h)
Term.Function(a, b) => a + b
Term.PartialFunction{ case _ => }
Term.Whilewhile(p){ f() }
Term.Dodo { f() } while(p)
Term.Forfor{x <- xs} f(x)
Term.ForYieldfor{x <- xs} yield f(x)
Term.Newnew A
Term.NewAnonymousnew A { }
Term.Placeholder_
Term.Etaf _
Term.Repeatedf(x: _*)
Term.Paramx: Int in def f(x: Int)
Term.Interpolates"Hello $name"
Term.Xml<h1>Hello {name}</h1>
Term.ApplyUsingmethod(using c) (Scala 3)
Term.EndMarkerend if (Scala 3)
Term.QuotedMacroExpr'{ 'ax } (Scala 3)
Term.QuotedMacroType'[ Map[Int, String] ] (Scala 3)
Term.SplicedMacroExpr${ env } (Scala 3)
Term.ContextFunctionExecutionContext ?=> T (Scala 3)
Term.PolyFunction[T] => (t: T) => t (Scala 3)

Types (meta.Type)​

"A with B".parse[Type].get.structure

Type.With(lhs = Type.Name("A"), rhs = Type.Name("B"))
RefExamples
Type.NameB
Type.Selecta.B
Type.Projecta#B
Type.Singletona.type
TypeExamples
Type.ApplyF[T]
Type.ApplyInfixK Map V
Type.FunctionA => B
Type.Tuple(A, B)
Type.WithA with B
Type.AndA & B (Scala 3)
Type.Or A | B (Scala 3)
Type.RefineA { def f: Int }
Type.ExistentialA forSome { type T }
Type.AnnotateT @annot
Type.Lambda[T] => (T, T) (only for supported dialects)
Type.Method(x: T): T (only for supported dialects)
Type.Placeholder_ in T[_]
Type.BoundsT >: Lower <: Upper in def F[T >: Lower <: Upper] = 1
Type.ByName=>T in def f(x: => T) = x
Type.RepeatedT* in def f(x: T*): Unit
Type.Vart in case _: List[t] =>
Type.ParamX in trait A[X]
Type.PolyFunction[T] => (t: T) => t (Scala 3)
Type.ContextFunctionExecutionContext ?=> T (Scala 3)
Type.Matchtype T = match { case A => B} (Scala 3)

Patterns (meta.Pat) and Cases (meta.Case)​

"_: A | _: B".parse[Pat].get.structure

Pat.Alternative(
Pat.Typed(Pat.Wildcard(), Type.Name("A")),
Pat.Typed(Pat.Wildcard(), Type.Name("B"))
)
PatExamples
Lit"literal"
Pat.Wildcard_
Pat.SeqWildcard_* in case List(xs @ _*) =>
Pat.Vara in case a =>
Pat.Binda @ A()
Pat.Alternative1 | 2
Pat.Tuple(a, b)
Pat.ExtractA(a, b)
Pat.ExtractInfixa E b
Pat.Interpolater"Hello (.+)$name"
Pat.Xml<h1>Hello, World!</h1>
Pat.Typeda: Int
Term.Selecta.b
Term.Macrocase 'c => 1 (Scala 3)
Term.Givencase ctx as given Context (Scala 3)
"case a => ()".parse[Case].get.structure

Case(Pat.Var(Term.Name("a")), None, Lit.Unit(()))
CaseExamples
Casecase a if p => f()
TypeCasecase A[t] => F[t] (Scala 3)

Name (meta.Name)​

meta.Name.Anonymous()

"class B { }".parse[Source].get.structure

Source(
stats = List(
Defn.Class(
mods = Nil,
name = Type.Name("B"),
tparams = Nil,
ctor = Ctor.Primary(
mods = Nil,
name = Name.Anonymous(),
paramss = Nil
),
templ = Template(
early = Nil,
inits = Nil,
self = Self(
name = Name.Anonymous(),
decltpe = None
),
stats = Nil
)
)
)
)

meta.name.Indeterminate()

Is it a type, or is it a term? Indeterminate.

"import a.b".parse[Source].get.structure

Source(
stats = List(
Import(
importers = List(
Importer(
ref = Term.Name("a"),
importees = List(
Importee.Name(
name = Name.Indeterminate(
value = b
)
)
)
)
)
)
)
)

Literals (meta.Lit)​

"null".parse[Term].get.structure

Lit.Null()
LitExample
Nullnull
Booleantrue
Unit()
Int1
Double1.0
Float1.0F
Long1L
Byte(no available syntax)
Short(no available syntax)
Char'a'
Symbol'a
String"A"

Coments (meta.Tree.Comments)​

Starting with v4.14.3, scalameta allows both parsing some comments and attaching them to trees.

"""|/*
| * leading comment 1
| */
|// leading comment
|null /* trailing comment 1 */ // trailing comment 2
|// unattached comment
|""".stripMargin.parse[Term].get.structure

/*
* leading comment 1
*/
// leading comment 2
Lit.Null() /* trailing comment 1 */ // trailing comment 2

Constructing trees with comments​

To create a tree with comments, instead of the standard apply method, use createWithComments which appends two additional parameters:


Lit.Null.createWithComments(
begComment = Some(Tree.Comments(List(
Tree.Comment(List(Lit.String("/*\n * leading comment 1\n */"))),
Tree.Comment(List(Lit.String("// leading comment 2")))
))),
endComment = Some(Tree.Comments(List(
Tree.Comment(List(Lit.String("/* trailing comment 1 */"))),
Tree.Comment(List(Lit.String("// trailing comment 2")))
)))
)
Term.Name.createWithComments(
"identifier",
begComment = Some(Tree.Comments(List(
Tree.Comment(List(Lit.String("/* comment */")))
))),
endComment = None // default
)

In addition, the trees now also provide copyWithComments instance methods, which work similarly.

Parsing trees with comments​

The scalameta parser will attach the following comments to a parsed tree:

  • any comment tokens which follow the tree until the first newline or non-trivial (non-space and non-comment) token
  • any comment tokens which precede the tree if they are themselves preceded by a newline or if the first non-trivial token before them is neither an identifier nor a closing delimiter (because then that comment would be attached to the tree ending in that token)

This means, for instance, that a comment following punctuation (say, a comma or a an equals or a colon) would be attached to the next tree rather than the preceding (because punctuation is not included in that previous tree):

foo: // fewer braces call; leading for `bar`
bar, // first argument comment; leading for `baz`
baz // second argument; trailing for `baz
)

foo /* fewer braces call; trailing for `foo` */:
bar /* first argument comment; trailing for `bar` */,
baz
)

Keep in mind that after parsing, multiple trees might refer to the same exact comments. In the example below, // some comment will be accessible both from Term.Name("bar") and from Defn.Val("foo", ...).

val foo = bar // some comment

Showing trees with comments​

The .structure and .syntax methods will only output a comment associated with a tree if

  • the tree is not parsed (say, created manually), or
  • its parent is not set (also a likely case with manually generated trees), or
  • the parent does not contain the same comment
    • if it does, the comment will simply be attributed to the parent