Scalameta is a clean-room implementation of a metaprogramming toolkit for Scala, designed to be simple, robust and portable. We are striving for scalameta to become a successor of scala.reflect, the current de facto standard in the Scala ecosystem.
Scalameta provides functionality that's unprecedented in the Scala ecosystem. Our killer feature is abstract syntax trees that capture the code exactly as it is written - with all the original formatting and attention to minor syntactic details.
With scalameta, we are building a community of next-generation tooling for Scala. Codacy's Scala engine, Scalafmt, and Scalafix take advantage of our unique features and deliver user experiences that have been unreachable for the most of the traditional Scala tools.
High-fidelity parsing. Note how the abstract syntax trees in the printout below contain comprehensive information about formatting and comments. This is an exclusive feature of scalameta.
scala> "x + y /* adds x and y */".parse[Term] res0: scala.meta.parsers.Parsed[scala.meta.Term] = x + y /* adds x and y */ scala> "List[ Int ]".parse[Type] res1: scala.meta.parsers.Parsed[scala.meta.Type] = List[ Int ]
Tokens. Scalameta takes even the finest details of Scala code into account. We achieve this by attaching tokens, data structures representing atomic units of Scala syntax, to our abstract syntax trees. Note that the abstract syntax tree in the printout doesn't have the comment per se - it is stored in tokens instead.
scala> val tree = "x + y /* adds x and y */".parse[Term].get tree: scala.meta.Term = x + y /* adds x and y */ scala> tree.syntax res0: String = x + y /* adds x and y */ scala> tree.structure res1: String = Term.ApplyInfix(Term.Name("x"), Term.Name("+"), Nil, List(Term.Name("y"))) scala> tree.tokens.structure res2: String = Tokens(BOF [0..0), x [0..1), [1..2), + [2..3), [3..4), y [4..5), [5..6), /* adds x and y */ [6..24), EOF [24..24))
Dialects. Scalameta is designed from the ground up to be platform-independent. This means that we understand different versions of the base language: Scala 2.10, Scala 2.11 and even Dotty. We also support Sbt build files to make sure we cover as much Scala code as possible.
scala> import scala.meta.dialects.Sbt0137 import scala.meta.dialects.Sbt0137 scala> Sbt0137(""" lazy val root = (project in file(".")). settings(name := "hello") """).parse[Source] res0: scala.meta.parsers.Parsed[scala.meta.Source] = lazy val root = (project in file(".")). settings(name := "hello")
Scala.reflect is notorious for being obscure and user-unfriendly,
but it has its moments.
Quasiquotes have proven to be an amazing productivity booster,
so we implemented them in scalameta, and now they are better than ever.
Note how the precise types for
prevent the programmer from generating invalid code.
Learn more about quasiquotes in
scala> val addition = q"x + y" addition: meta.Term.ApplyInfix = x + y scala> val q"$x + $y" = addition x: scala.meta.Term = x y: scala.meta.Term = y scala> q"$y + $x" res0: meta.Term.ApplyInfix = y + x
Stable releases. Every four to six weeks, we publish major releases (e.g. 1.7.0, 1.8.0, etc). In such releases, we accumulate battle-tested changes that have been merged since the last release and make them available on Maven Central.
Pre-release builds. We automatically publish pre-release builds to our Bintray repository on every merge into master, typically within 10-30 minutes of a merge. In such builds, we publish potentially experimental changes that haven't yet undergone practical testing.
Compatibility. Following a popular convention, we only provide binary and source compatibility between minor versions (e.g. between 1.6.0 and 1.6.1, but not between 1.6.0 and 1.7.0). There are no compatibility guarantees provided for pre-release builds.
To get started with scalameta, add the following to your
// Latest stable version libraryDependencies += "org.scalameta" %% "scalameta" % "1.8.0" // Latest pre-release version resolvers += Resolver.bintrayRepo("scalameta", "maven") libraryDependencies += "org.scalameta" %% "scalameta" % "2.0.0-M2-4-07525e18-20170817-0940"
Next, you'll need to add a single wildcard import to the files where you'll be using scalameta. Unlike with scala.reflect, the metaprogramming library from the standard distribution, no complicated setup is necessary.
To learn more about practical aspects of using scalameta, take a look at our tutorial that is based on a workshop given by Ólafur Pall Geirsson at Scala World 2016: http://scalameta.org/tutorial.
Semantic API. Our first priority is to come up with an API that will provide functionality to perform typechecking, name resolution, implicit inference, etc. It is crucial to fully model the language and achieve feature parity with scala.reflect. Visit #604 to check out our roadmap and provide feedback.
New-style ("inline") macros. As announced at ScalaDays New York City 2016, macros based on scala.reflect are going to be dropped from the future versions of Scala. We are now working on the replacement that is designed to be platform-independent and easy-to-use. You may be interested in visiting https://github.com/scalamacros/scalamacros to check out the state of the art.
Other execution environments. The current version of scalameta can only be run with Scala 2.11, Scala 2.12 or Scala.js. This means that it is very hard or outright impossible to write scalameta-based tools targetting Scala 2.10 (e.g. running in sbt 0.13.x) or Scala Native. Vote for #295 and #772 on our issue tracker if that's important for you.
Semantic Tooling at Twitter (ScalaDays Copenhagen 2017). This talk introduces semantic databases, the cornerstone of the scalameta semantic API, and explains how semantic databases can be used to integrate with Kythe, a language-agnostic ecosystem for developer tools. In this talk, we presented our vision of next-generation semantic tooling for the Scala ecosystem.
Video: coming soon
Metaprogramming 2.0 (ScalaDays Berlin 2016). This talk explains the status of scalameta, demonstrates key features, presents the early adopters and publishes our plans for the future. In Berlin, we provided an extensive story of what's going to happen to compile-time metaprogramming in Scala, featuring a live demo of new-style ("inline") macros that support integration with IntelliJ IDEA.