Scalameta

Scalameta

  • Trees
  • SemanticDB
  • GitHub

›Trees

Trees

  • Guide
  • trees/quasiquotes
  • trees/examples
  • Scastie Playground
  • Scalameta AST Explorer
  • Scaladoc

SemanticDB

  • Guide
  • Specification

Community

  • Built with Scalameta
  • Presentations

trees/examples

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
← trees/quasiquotesScastie Playground →
  • Top level (meta.Source, meta.Pkg, meta.Pkg.Object)
  • Declarations (meta.Decl)
  • Definitions (meta.Defn)
  • Terms (meta.Term)
  • Types (meta.Type)
  • Patterns (meta.Pat) and Cases (meta.Case)
  • Name (meta.Name)
  • Literals (meta.Lit)
  • Coments (meta.Tree.Comments)
    • Constructing trees with comments
    • Parsing trees with comments
    • Showing trees with comments
Scalameta
Scalameta Docs
Trees GuideQuasiquotesSemanticDB
Scalameta Projects
Metals: language serverScalafmt: code formatterScalafix: linting and refactoring toolMUnit: testing libraryMDoc: documentation toolMetabrowse: online code browser
Community
GitHub
Copyright © 2025 Scalameta