Can scala macros be used to construct types?
I know it is possible to create types inside the generated function, but is it possible to return them outside?
I need a macro that generates Parser [T] - where both the parser and the T are built from an external grammar written in a simplified grammar description language for library users. T is parsed by AST, which contains mutually nested case classes. These case classes must be generated and visible from the outside.
Grammar:
RootType {
member1: {
member11: TypeB
member12: String
member13: TypeB
}
member2: String
TypeB {
member3: String
}
}
Using:
//Somewhere in my library:
trait ASTNode
def parser: Parser[ASTNode] = macro ... //interpret types from grammar-file
//On the client side:
val input = ... //reads unparsed string from some script-file
val parsed = parse(parser, input)
parsed.member1.member11.member3 //so ASTNode should be replaced with RootType
//case class TypeB and synthetic case class for member1 should be also generated
I am thinking about solutions:
- black box macro (how to determine the type that can be used outside of the generated function?)
- Workaround: macro annotated types with elements generated from my grammar (I don't know how many types I have, so I need to subclass by annotation, is this possible?)
- write a compiler plugin or a separate sbt-task or watch a macroparad
- generating a class at runtime is not an option because I need to check types
source to share
Yes it is possible. You can generate AST including ClassDef
, ModuleDef
etc. No problem, and if you use macros (from macro paradise) they will be visible to external code (in a normal macro def
such as parser
in your desired code they are local). See "Public Type Providers" at http://docs.scala-lang.org/overviews/macros/typeproviders.html and https://github.com/travisbrown/type-provider-examples . The library code will look slightly different:
@Grammar("path/to/file") trait ASTNode // reads grammar, and generates subclasses, parser, etc.
source to share