aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/parsing/JavaParsers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools/dotc/parsing/JavaParsers.scala')
-rw-r--r--src/dotty/tools/dotc/parsing/JavaParsers.scala887
1 files changed, 887 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/parsing/JavaParsers.scala b/src/dotty/tools/dotc/parsing/JavaParsers.scala
new file mode 100644
index 000000000..095342c48
--- /dev/null
+++ b/src/dotty/tools/dotc/parsing/JavaParsers.scala
@@ -0,0 +1,887 @@
+package dotty.tools
+package dotc
+package parsing
+
+import dotty.tools.dotc.core.Constants.Constant
+import dotty.tools.dotc.core.Flags
+import dotty.tools.dotc.core.Flags.FlagSet
+
+import scala.language.implicitConversions
+
+import JavaTokens._
+import JavaScanners._
+import Parsers._
+import core._
+import Contexts._
+import Names._
+import NameOps._
+import Types._
+import Symbols._
+import ast.Trees._
+import Decorators._
+import StdNames._
+import dotty.tools.dotc.util.SourceFile
+import util.Positions._
+import annotation.switch
+import scala.collection.mutable.ListBuffer
+import scala.reflect.internal.util.Collections._
+
+object JavaParsers {
+
+ import ast.untpd._
+
+ class JavaParser(source: SourceFile)(implicit ctx: Context) extends ParserCommon(source) {
+
+ val definitions = ctx.definitions
+ import definitions._
+
+ val in: JavaScanner = new JavaScanner(source)
+
+ /** The simple name of the package of the currently parsed file */
+ private var thisPackageName: TypeName = tpnme.EMPTY
+
+ /** This is the general parse entry point.
+ * Overridden by ScriptParser
+ */
+ def parse(): Tree = {
+ val t = compilationUnit()
+ accept(EOF)
+ t
+ }
+
+ // -------- error handling ---------------------------------------
+
+ protected def skip(): Unit = {
+ var nparens = 0
+ var nbraces = 0
+ while (true) {
+ in.token match {
+ case EOF =>
+ return
+ case SEMI =>
+ if (nparens == 0 && nbraces == 0) return
+ case RPAREN =>
+ nparens -= 1
+ case RBRACE =>
+ if (nbraces == 0) return
+ nbraces -= 1
+ case LPAREN =>
+ nparens += 1
+ case LBRACE =>
+ nbraces += 1
+ case _ =>
+ }
+ in.nextToken()
+ }
+ }
+
+ def syntaxError(msg: String, skipIt: Boolean): Unit = {
+ syntaxError(in.offset, msg, skipIt)
+ }
+
+ def syntaxError(pos: Int, msg: String, skipIt: Boolean): Unit = {
+ if (pos > lastErrorOffset) {
+ syntaxError(msg, pos)
+ // no more errors on this token.
+ lastErrorOffset = in.offset
+ }
+ if (skipIt)
+ skip()
+ }
+ def errorTypeTree = TypeTree().withType(ErrorType) withPos Position(in.offset)
+
+ // --------- tree building -----------------------------
+
+ def rootId(name: Name) = Select(Ident(nme.ROOTPKG), name)
+ def scalaDot(name: Name) = Select(Ident(nme.scala_), name)
+ def scalaAnnotationDot(name: Name) = Select(scalaDot(nme.annotation), name)
+
+ def javaDot(name: Name): Tree =
+ Select(rootId(nme.java), name)
+
+ def javaLangDot(name: Name): Tree =
+ Select(javaDot(nme.lang), name)
+
+ def javaLangObject(): Tree = javaLangDot(tpnme.Object)
+
+ def arrayOf(tpt: Tree) =
+ AppliedTypeTree(Ident(nme.Array.toTypeName), List(tpt))
+
+ def unimplementedExpr = Ident("???".toTermName)
+
+ def makePackaging(pkg: RefTree, stats: List[Tree]): PackageDef =
+ atPos(pkg.pos) { PackageDef(pkg, stats) }
+
+ def makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef]) = {
+ def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match {
+ case (meth: DefDef) :: rest if meth.name.isConstructorName => (meth, rest)
+ case first :: rest =>
+ val (constr, tail) = pullOutFirstConstr(rest)
+ (constr, first :: tail)
+ case nil => (EmptyTree, nil)
+ }
+ val (constr, stats1) = pullOutFirstConstr(stats)
+ val constr1 = if(constr == EmptyTree) makeConstructor(List(), tparams) else constr.asInstanceOf[DefDef]
+ Template(constr1, parents, EmptyValDef, stats1)
+ }
+
+ def makeSyntheticParam(count: Int, tpt: Tree): ValDef =
+ makeParam(nme.syntheticParamName(count), tpt)
+ def makeParam(name: String, tpt: Tree): ValDef =
+ makeParam(name.toTermName, tpt)
+ def makeParam(name: TermName, tpt: Tree, flags: FlagSet = Flags.Param): ValDef =
+ ValDef(Modifiers(flags | Flags.JavaDefined), name, tpt, EmptyTree)
+
+ def makeConstructor(formals: List[Tree], tparams: List[TypeDef]) = {
+ val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p))
+ DefDef(Modifiers(Flags.JavaDefined), nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree)
+ }
+
+ // ------------- general parsing ---------------------------
+
+ /** skip parent or brace enclosed sequence of things */
+ def skipAhead(): Unit = {
+ var nparens = 0
+ var nbraces = 0
+ do {
+ in.token match {
+ case LPAREN =>
+ nparens += 1
+ case LBRACE =>
+ nbraces += 1
+ case _ =>
+ }
+ in.nextToken()
+ in.token match {
+ case RPAREN =>
+ nparens -= 1
+ case RBRACE =>
+ nbraces -= 1
+ case _ =>
+ }
+ } while (in.token != EOF && (nparens > 0 || nbraces > 0))
+ }
+
+ def skipTo(tokens: Int*): Unit = {
+ while (!(tokens contains in.token) && in.token != EOF) {
+ if (in.token == LBRACE) { skipAhead(); accept(RBRACE) }
+ else if (in.token == LPAREN) { skipAhead(); accept(RPAREN) }
+ else in.nextToken()
+ }
+ }
+
+ /** Consume one token of the specified type, or
+ * signal an error if it is not there.
+ */
+ def accept(token: Int): Int = {
+ val offset = in.offset
+ if (in.token != token) {
+ val offsetToReport = in.offset
+ val msg =
+ tokenString(token) + " expected but " +
+ tokenString(in.token) + " found."
+
+ syntaxError(offsetToReport, msg, skipIt = true)
+ }
+ if (in.token == token) in.nextToken()
+ offset
+ }
+
+ def acceptClosingAngle(): Unit = {
+ val closers: PartialFunction[Int, Int] = {
+ case GTGTGTEQ => GTGTEQ
+ case GTGTGT => GTGT
+ case GTGTEQ => GTEQ
+ case GTGT => GT
+ case GTEQ => EQUALS
+ }
+ if (closers isDefinedAt in.token) in.token = closers(in.token)
+ else accept(GT)
+ }
+
+ def identForType(): TypeName = ident().toTypeName
+ def ident(): Name =
+ if (in.token == IDENTIFIER) {
+ val name = in.name
+ in.nextToken()
+ name
+ } else {
+ accept(IDENTIFIER)
+ nme.ERROR
+ }
+
+ def repsep[T <: Tree](p: () => T, sep: Int): List[T] = {
+ val buf = ListBuffer[T](p())
+ while (in.token == sep) {
+ in.nextToken()
+ buf += p()
+ }
+ buf.toList
+ }
+
+ /** Convert (qual)ident to type identifier
+ */
+ def convertToTypeId(tree: Tree): Tree = convertToTypeName(tree) match {
+ case Some(t) => t withPos tree.pos
+ case _ => tree match {
+ case AppliedTypeTree(_, _) | SelectFromTypeTree(_, _) =>
+ tree
+ case _ =>
+ syntaxError("identifier expected", tree.pos)
+ errorTypeTree
+ }
+ }
+
+ /** Translate names in Select/Ident nodes to type names.
+ */
+ def convertToTypeName(tree: Tree): Option[RefTree] = tree match {
+ case Select(qual, name) => Some(Select(qual, name.toTypeName))
+ case Ident(name) => Some(Ident(name.toTypeName))
+ case _ => None
+ }
+ // -------------------- specific parsing routines ------------------
+
+ def qualId(): RefTree = {
+ var t: RefTree = atPos(in.offset) { Ident(ident()) }
+ while (in.token == DOT) {
+ in.nextToken()
+ t = atPos(in.offset) { Select(t, ident()) }
+ }
+ t
+ }
+
+ def optArrayBrackets(tpt: Tree): Tree =
+ if (in.token == LBRACKET) {
+ val tpt1 = atPos(in.offset) { arrayOf(tpt) }
+ in.nextToken()
+ accept(RBRACKET)
+ optArrayBrackets(tpt1)
+ } else tpt
+
+ def basicType(): Tree =
+ atPos(in.offset) {
+ in.token match {
+ case BYTE => in.nextToken(); TypeTree(ByteType)
+ case SHORT => in.nextToken(); TypeTree(ShortType)
+ case CHAR => in.nextToken(); TypeTree(CharType)
+ case INT => in.nextToken(); TypeTree(IntType)
+ case LONG => in.nextToken(); TypeTree(LongType)
+ case FLOAT => in.nextToken(); TypeTree(FloatType)
+ case DOUBLE => in.nextToken(); TypeTree(DoubleType)
+ case BOOLEAN => in.nextToken(); TypeTree(BooleanType)
+ case _ => syntaxError("illegal start of type", skipIt = true); errorTypeTree
+ }
+ }
+
+ def typ(): Tree =
+ optArrayBrackets {
+ if (in.token == FINAL) in.nextToken()
+ if (in.token == IDENTIFIER) {
+ var t = typeArgs(atPos(in.offset)(Ident(ident())))
+ // typeSelect generates Select nodes is the lhs is an Ident or Select,
+ // SelectFromTypeTree otherwise. See #3567.
+ // Select nodes can be later
+ // converted in the typechecker to SelectFromTypeTree if the class
+ // turns out to be an instance ionner class instead of a static inner class.
+ def typeSelect(t: Tree, name: Name) = t match {
+ case Ident(_) | Select(_, _) => Select(t, name)
+ case _ => SelectFromTypeTree(t, name.toTypeName)
+ }
+ while (in.token == DOT) {
+ in.nextToken()
+ t = typeArgs(atPos(in.offset)(typeSelect(t, ident())))
+ }
+ convertToTypeId(t)
+ } else {
+ basicType()
+ }
+ }
+
+ def typeArgs(t: Tree): Tree = {
+ var wildnum = 0
+ def typeArg(): Tree =
+ if (in.token == QMARK) {
+ val offset = in.offset
+ in.nextToken()
+ val hi = if (in.token == EXTENDS) { in.nextToken() ; typ() } else EmptyTree
+ val lo = if (in.token == SUPER) { in.nextToken() ; typ() } else EmptyTree
+ atPos(offset) {
+ /*
+ TypeDef(
+ Modifiers(Flags.JavaDefined | Flags.Deferred),
+ typeName("_$"+(wildnum += 1)),
+ List(),
+ TypeBoundsTree(lo, hi))
+ */
+ TypeBoundsTree(lo, hi)
+ }
+ } else {
+ typ()
+ }
+ if (in.token == LT) {
+ in.nextToken()
+ val t1 = convertToTypeId(t)
+ val args = repsep(typeArg, COMMA)
+ acceptClosingAngle()
+ atPos(t1.pos) {
+ AppliedTypeTree(t1, args)
+ }
+ } else t
+ }
+
+ def annotations(): List[Tree] = {
+ //var annots = new ListBuffer[Tree]
+ while (in.token == AT) {
+ in.nextToken()
+ annotation()
+ }
+ List() // don't pass on annotations for now
+ }
+
+ /** Annotation ::= TypeName [`(` AnnotationArgument {`,` AnnotationArgument} `)`]
+ */
+ def annotation(): Unit = {
+ qualId()
+ if (in.token == LPAREN) { skipAhead(); accept(RPAREN) }
+ else if (in.token == LBRACE) { skipAhead(); accept(RBRACE) }
+ }
+
+ def modifiers(inInterface: Boolean): Modifiers = {
+ var flags = Flags.JavaDefined
+ // assumed true unless we see public/private/protected
+ var isPackageAccess = true
+ var annots: List[Tree] = Nil
+ def addAnnot(sym: ClassSymbol) = annots :+= New(TypeTree(sym.typeRef))
+
+ while (true) {
+ in.token match {
+ case AT if (in.lookaheadToken != INTERFACE) =>
+ in.nextToken()
+ annotation()
+ case PUBLIC =>
+ isPackageAccess = false
+ in.nextToken()
+ case PROTECTED =>
+ flags |= Flags.Protected
+ in.nextToken()
+ case PRIVATE =>
+ isPackageAccess = false
+ flags |= Flags.Private
+ in.nextToken()
+ case STATIC =>
+ flags |= Flags.Static
+ in.nextToken()
+ case ABSTRACT =>
+ flags |= Flags.Abstract
+ in.nextToken()
+ case FINAL =>
+ flags |= Flags.Final
+ in.nextToken()
+ case DEFAULT =>
+ flags |= Flags.DefaultMethod
+ in.nextToken()
+ case NATIVE =>
+ addAnnot(NativeAnnot)
+ in.nextToken()
+ case TRANSIENT =>
+ addAnnot(TransientAnnot)
+ in.nextToken()
+ case VOLATILE =>
+ addAnnot(VolatileAnnot)
+ in.nextToken()
+ case SYNCHRONIZED | STRICTFP =>
+ in.nextToken()
+ case _ =>
+ val privateWithin: TypeName =
+ if (isPackageAccess && !inInterface) thisPackageName
+ else tpnme.EMPTY
+
+ return Modifiers(flags, privateWithin) withAnnotations annots
+ }
+ }
+ assert(false, "should not be here")
+ throw new RuntimeException
+ }
+
+ def typeParams(flags: FlagSet = Flags.JavaDefined | Flags.PrivateLocal | Flags.Param): List[TypeDef] =
+ if (in.token == LT) {
+ in.nextToken()
+ val tparams = repsep(() => typeParam(flags), COMMA)
+ acceptClosingAngle()
+ tparams
+ } else List()
+
+ def typeParam(flags: FlagSet): TypeDef =
+ atPos(in.offset) {
+ val name = identForType()
+ val hi = if (in.token == EXTENDS) { in.nextToken() ; bound() } else EmptyTree
+ TypeDef(Modifiers(flags), name, Nil, TypeBoundsTree(EmptyTree, hi))
+ }
+
+ def bound(): Tree =
+ atPos(in.offset) {
+ val buf = ListBuffer[Tree](typ())
+ while (in.token == AMP) {
+ in.nextToken()
+ buf += typ()
+ }
+ val ts = buf.toList
+ if (ts.tail.isEmpty) ts.head
+ else ts.reduce(AndTypeTree(_,_))
+ }
+
+ def formalParams(): List[ValDef] = {
+ accept(LPAREN)
+ val vparams = if (in.token == RPAREN) List() else repsep(formalParam, COMMA)
+ accept(RPAREN)
+ vparams
+ }
+
+ def formalParam(): ValDef = {
+ if (in.token == FINAL) in.nextToken()
+ annotations()
+ var t = typ()
+ if (in.token == DOTDOTDOT) {
+ in.nextToken()
+ t = atPos(t.pos) {
+ PostfixOp(t, nme.raw.STAR)
+ }
+ }
+ varDecl(Position(in.offset), Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName, dontAddMutable = true)
+ }
+
+ def optThrows(): Unit = {
+ if (in.token == THROWS) {
+ in.nextToken()
+ repsep(typ, COMMA)
+ }
+ }
+
+ def methodBody(): Tree = {
+ skipAhead()
+ accept(RBRACE) // skip block
+ unimplementedExpr
+ }
+
+ def definesInterface(token: Int) = token == INTERFACE || token == AT
+
+ def termDecl(mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = {
+ val inInterface = definesInterface(parentToken)
+ val tparams = if (in.token == LT) typeParams(Flags.JavaDefined | Flags.Param) else List()
+ val isVoid = in.token == VOID
+ var rtpt =
+ if (isVoid) {
+ in.nextToken()
+ TypeTree(UnitType) withPos Position(in.offset)
+ } else typ()
+ var offset = in.offset
+ val rtptName = rtpt match {
+ case Ident(name) => name
+ case _ => nme.EMPTY
+ }
+ if (in.token == LPAREN && rtptName != nme.EMPTY && !inInterface) {
+ // constructor declaration
+ val vparams = formalParams()
+ optThrows()
+ List {
+ atPos(offset) {
+ DefDef(mods, nme.CONSTRUCTOR, parentTParams, List(vparams), TypeTree(), methodBody())
+ }
+ }
+ } else {
+ var mods1 = mods
+ if (mods is Flags.Abstract) mods1 = mods &~ Flags.Abstract
+ offset = in.offset
+ val name = ident()
+ if (in.token == LPAREN) {
+ // method declaration
+ val vparams = formalParams()
+ if (!isVoid) rtpt = optArrayBrackets(rtpt)
+ optThrows()
+ val bodyOk = !inInterface || (mods is Flags.DefaultMethod)
+ val body =
+ if (bodyOk && in.token == LBRACE) {
+ methodBody()
+ } else {
+ if (parentToken == AT && in.token == DEFAULT) {
+ val annot =
+ atPos(offset) {
+ New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil)
+ }
+ mods1 = mods1 withAnnotations annot :: Nil
+ skipTo(SEMI)
+ accept(SEMI)
+ unimplementedExpr
+ } else {
+ accept(SEMI)
+ EmptyTree
+ }
+ }
+ //if (inInterface) mods1 |= Flags.Deferred
+ List {
+ atPos(offset) {
+ DefDef(mods1 | Flags.Method, name.toTermName, tparams, List(vparams), rtpt, body)
+ }
+ }
+ } else {
+ if (inInterface) mods1 |= Flags.Final | Flags.Static
+ val result = fieldDecls(Position(offset), mods1, rtpt, name)
+ accept(SEMI)
+ result
+ }
+ }
+ }
+
+ /** Parse a sequence of field declarations, separated by commas.
+ * This one is tricky because a comma might also appear in an
+ * initializer. Since we don't parse initializers we don't know
+ * what the comma signifies.
+ * We solve this with a second list buffer `maybe` which contains
+ * potential variable definitions.
+ * Once we have reached the end of the statement, we know whether
+ * these potential definitions are real or not.
+ */
+ def fieldDecls(pos: Position, mods: Modifiers, tpt: Tree, name: Name): List[Tree] = {
+ val buf = ListBuffer[Tree](varDecl(pos, mods, tpt, name.toTermName))
+ val maybe = new ListBuffer[Tree] // potential variable definitions.
+ while (in.token == COMMA) {
+ in.nextToken()
+ if (in.token == IDENTIFIER) { // if there's an ident after the comma ...
+ val name = ident()
+ if (in.token == EQUALS || in.token == SEMI) { // ... followed by a `=` or `;`, we know it's a real variable definition
+ buf ++= maybe
+ buf += varDecl(Position(in.offset), mods, tpt, name.toTermName)
+ maybe.clear()
+ } else if (in.token == COMMA) { // ... if there's a comma after the ident, it could be a real vardef or not.
+ maybe += varDecl(Position(in.offset), mods, tpt, name.toTermName)
+ } else { // ... if there's something else we were still in the initializer of the
+ // previous var def; skip to next comma or semicolon.
+ skipTo(COMMA, SEMI)
+ maybe.clear()
+ }
+ } else { // ... if there's no ident following the comma we were still in the initializer of the
+ // previous var def; skip to next comma or semicolon.
+ skipTo(COMMA, SEMI)
+ maybe.clear()
+ }
+ }
+ if (in.token == SEMI) {
+ buf ++= maybe // every potential vardef that survived until here is real.
+ }
+ buf.toList
+ }
+
+ def varDecl(pos: Position, mods: Modifiers, tpt: Tree, name: TermName, dontAddMutable: Boolean = false): ValDef = {
+ val tpt1 = optArrayBrackets(tpt)
+ if (in.token == EQUALS && !(mods is Flags.Param)) skipTo(COMMA, SEMI)
+ val mods1 = if (mods is Flags.Final) mods &~ Flags.Final else if(dontAddMutable) mods else mods | Flags.Mutable
+ atPos(pos) {
+ ValDef(mods1, name, tpt1, EmptyTree)
+ }
+ }
+
+ def memberDecl(mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match {
+ case CLASS | ENUM | INTERFACE | AT =>
+ typeDecl(if (definesInterface(parentToken)) mods | Flags.Static else mods)
+ case _ =>
+ termDecl(mods, parentToken, parentTParams)
+ }
+
+ def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree =
+ atPos(cdef.pos) {
+ ModuleDef((cdef.mods & (Flags.AccessFlags | Flags.JavaDefined)).toTermFlags, cdef.name.toTermName,
+ makeTemplate(List(), statics, List()))
+ }
+
+ private val wild = Ident(nme.WILDCARD) withPos Position(-1)
+ private val wildList = List(wild) // OPT This list is shared for performance.
+
+ def importCompanionObject(cdef: TypeDef): Tree =
+ atPos(cdef.pos) {
+ Import(Ident(cdef.name.toTermName), wildList)
+ }
+
+ // Importing the companion object members cannot be done uncritically: see
+ // ticket #2377 wherein a class contains two static inner classes, each of which
+ // has a static inner class called "Builder" - this results in an ambiguity error
+ // when each performs the import in the enclosing class's scope.
+ //
+ // To address this I moved the import Companion._ inside the class, as the first
+ // statement. This should work without compromising the enclosing scope, but may (?)
+ // end up suffering from the same issues it does in scala - specifically that this
+ // leaves auxiliary constructors unable to access members of the companion object
+ // as unqualified identifiers.
+ def addCompanionObject(statics: List[Tree], cdef: TypeDef): List[Tree] = {
+ // if there are no statics we can use the original cdef, but we always
+ // create the companion so import A._ is not an error (see ticket #1700)
+ val cdefNew =
+ if (statics.isEmpty) cdef
+ else {
+ val template = cdef.rhs.asInstanceOf[Template]
+ cpy.TypeDef(cdef, cdef.mods, cdef.name,
+ cpy.Template(template, template.constr, template.parents, template.self,
+ importCompanionObject(cdef) :: template.body),
+ cdef.tparams)
+ }
+
+ List(makeCompanionObject(cdefNew, statics), cdefNew)
+ }
+
+ def importDecl(): List[Tree] = {
+ accept(IMPORT)
+ val offset = in.offset
+ val buf = new ListBuffer[Name]
+ def collectIdents() : Int = {
+ if (in.token == ASTERISK) {
+ val starOffset = in.offset
+ in.nextToken()
+ buf += nme.WILDCARD
+ starOffset
+ } else {
+ val nameOffset = in.offset
+ buf += ident()
+ if (in.token == DOT) {
+ in.nextToken()
+ collectIdents()
+ } else nameOffset
+ }
+ }
+ if (in.token == STATIC) in.nextToken()
+ else buf += nme.ROOTPKG
+ val lastnameOffset = collectIdents()
+ accept(SEMI)
+ val names = buf.toList
+ if (names.length < 2) {
+ syntaxError(offset, "illegal import", skipIt = false)
+ List()
+ } else {
+ val qual = ((Ident(names.head): Tree) /: names.tail.init) (Select(_, _))
+ val lastname = names.last
+ val ident = Ident(lastname) withPos Position(lastnameOffset)
+// val selector = lastname match {
+// case nme.WILDCARD => Pair(ident, Ident(null) withPos Position(-1))
+// case _ => Pair(ident, ident)
+// }
+ List(atPos(offset)(Import(qual, List(ident))))
+ }
+ }
+
+ def interfacesOpt() =
+ if (in.token == IMPLEMENTS) {
+ in.nextToken()
+ repsep(typ, COMMA)
+ } else {
+ List()
+ }
+
+ def classDecl(mods: Modifiers): List[Tree] = {
+ accept(CLASS)
+ val offset = in.offset
+ val name = identForType()
+ val tparams = typeParams()
+ val superclass =
+ if (in.token == EXTENDS) {
+ in.nextToken()
+ typ()
+ } else {
+ javaLangObject()
+ }
+ val interfaces = interfacesOpt()
+ val (statics, body) = typeBody(CLASS, name, tparams)
+ addCompanionObject(statics, atPos(offset) {
+ TypeDef(mods, name, makeTemplate(superclass :: interfaces, body, tparams))
+ })
+ }
+
+ def interfaceDecl(mods: Modifiers): List[Tree] = {
+ accept(INTERFACE)
+ val offset = in.offset
+ val name = identForType()
+ val tparams = typeParams()
+ val parents =
+ if (in.token == EXTENDS) {
+ in.nextToken()
+ repsep(typ, COMMA)
+ } else {
+ List(javaLangObject())
+ }
+ val (statics, body) = typeBody(INTERFACE, name, tparams)
+ addCompanionObject(statics, atPos(offset) {
+ TypeDef(mods | Flags.Trait | Flags.Interface | Flags.Abstract,
+ name, tparams,
+ makeTemplate(parents, body, tparams))
+ })
+ }
+
+ def typeBody(leadingToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = {
+ accept(LBRACE)
+ val defs = typeBodyDecls(leadingToken, parentName, parentTParams)
+ accept(RBRACE)
+ defs
+ }
+
+ def typeBodyDecls(parentToken: Int, parentName: Name, parentTParams: List[TypeDef]): (List[Tree], List[Tree]) = {
+ val inInterface = definesInterface(parentToken)
+ val statics = new ListBuffer[Tree]
+ val members = new ListBuffer[Tree]
+ while (in.token != RBRACE && in.token != EOF) {
+ var mods = modifiers(inInterface)
+ if (in.token == LBRACE) {
+ skipAhead() // skip init block, we just assume we have seen only static
+ accept(RBRACE)
+ } else if (in.token == SEMI) {
+ in.nextToken()
+ } else {
+ if (in.token == ENUM || definesInterface(in.token)) mods |= Flags.Static
+ val decls = memberDecl(mods, parentToken, parentTParams)
+ (if ((mods is Flags.Static) || inInterface && !(decls exists (_.isInstanceOf[DefDef])))
+ statics
+ else
+ members) ++= decls
+ }
+ }
+ def forwarders(sdef: Tree): List[Tree] = sdef match {
+ case TypeDef(mods, name, _) if (parentToken == INTERFACE) =>
+ var rhs: Tree = Select(Ident(parentName.toTermName), name)
+ List(TypeDef(Modifiers(Flags.Protected), name, rhs))
+ case _ =>
+ List()
+ }
+ val sdefs = statics.toList
+ val idefs = members.toList ::: (sdefs flatMap forwarders)
+ (sdefs, idefs)
+ }
+ def annotationParents = List(
+ scalaAnnotationDot(tpnme.Annotation),
+ Select(javaLangDot(nme.annotation), tpnme.Annotation),
+ scalaAnnotationDot(tpnme.ClassfileAnnotation)
+ )
+ def annotationDecl(mods: Modifiers): List[Tree] = {
+ accept(AT)
+ accept(INTERFACE)
+ val offset = in.offset
+ val name = identForType()
+ val (statics, body) = typeBody(AT, name, List())
+ val constructorParams = body.collect {
+ case dd: DefDef => makeParam(dd.name, dd.tpt, Flags.PrivateLocalParamAccessor)
+ }
+ val constr = DefDef(Modifiers(Flags.JavaDefined), nme.CONSTRUCTOR,
+ List(), List(constructorParams), TypeTree(), EmptyTree)
+ val body1 = body.filterNot(_.isInstanceOf[DefDef])
+ val templ = makeTemplate(annotationParents, constr :: body1, List())
+ addCompanionObject(statics, atPos(offset) {
+ TypeDef(mods, name, templ)
+ })
+ }
+
+ def enumDecl(mods: Modifiers): List[Tree] = {
+ accept(ENUM)
+ val offset = in.offset
+ val name = identForType()
+ def enumType = Ident(name)
+ val interfaces = interfacesOpt()
+ accept(LBRACE)
+ val buf = new ListBuffer[Tree]
+ def parseEnumConsts(): Unit = {
+ if (in.token != RBRACE && in.token != SEMI && in.token != EOF) {
+ buf += enumConst(enumType)
+ if (in.token == COMMA) {
+ in.nextToken()
+ parseEnumConsts()
+ }
+ }
+ }
+ parseEnumConsts()
+ val consts = buf.toList
+ val (statics, body) =
+ if (in.token == SEMI) {
+ in.nextToken()
+ typeBodyDecls(ENUM, name, List())
+ } else {
+ (List(), List())
+ }
+ val predefs = List(
+ DefDef(
+ Modifiers(Flags.JavaDefined | Flags.Static | Flags.Method), nme.values, List(),
+ ListOfNil,
+ arrayOf(enumType),
+ unimplementedExpr),
+ DefDef(
+ Modifiers(Flags.JavaDefined | Flags.Static | Flags.Method), nme.valueOf, List(),
+ List(List(makeParam("x", TypeTree(StringType)))),
+ enumType,
+ unimplementedExpr))
+ accept(RBRACE)
+ /*
+ val superclazz =
+ AppliedTypeTree(javaLangDot(tpnme.Enum), List(enumType))
+ */
+ val superclazz = Apply(TypeApply(
+ Select(New(javaLangDot(tpnme.Enum)), nme.CONSTRUCTOR), List(enumType)),
+ List(Literal(Constant(null)),Literal(Constant(0))))
+ addCompanionObject(consts ::: statics ::: predefs, atPos(offset) {
+ TypeDef(mods | Flags.Enum, name, List(),
+ makeTemplate(superclazz :: interfaces, body, List()))
+ })
+ }
+
+ def enumConst(enumType: Tree) = {
+ annotations()
+ atPos(in.offset) {
+ val name = ident()
+ if (in.token == LPAREN) {
+ // skip arguments
+ skipAhead()
+ accept(RPAREN)
+ }
+ if (in.token == LBRACE) {
+ // skip classbody
+ skipAhead()
+ accept(RBRACE)
+ }
+ ValDef(Modifiers(Flags.Enum | Flags.Stable | Flags.JavaDefined | Flags.Static), name.toTermName, enumType, unimplementedExpr)
+ }
+ }
+
+ def typeDecl(mods: Modifiers): List[Tree] = in.token match {
+ case ENUM => enumDecl(mods)
+ case INTERFACE => interfaceDecl(mods)
+ case AT => annotationDecl(mods)
+ case CLASS => classDecl(mods)
+ case _ => in.nextToken(); syntaxError("illegal start of type declaration", skipIt = true); List(errorTypeTree)
+ }
+
+ /** CompilationUnit ::= [package QualId semi] TopStatSeq
+ */
+ def compilationUnit(): Tree = {
+ var offset = in.offset
+ val pkg: RefTree =
+ if (in.token == AT || in.token == PACKAGE) {
+ annotations()
+ offset = in.offset
+ accept(PACKAGE)
+ val pkg = qualId()
+ accept(SEMI)
+ pkg
+ } else {
+ Ident(nme.EMPTY_PACKAGE)
+ }
+ thisPackageName = convertToTypeName(pkg) match {
+ case Some(t) => t.name.toTypeName
+ case _ => tpnme.EMPTY
+ }
+ val buf = new ListBuffer[Tree]
+ while (in.token == IMPORT)
+ buf ++= importDecl()
+ while (in.token != EOF && in.token != RBRACE) {
+ while (in.token == SEMI) in.nextToken()
+ if (in.token != EOF)
+ buf ++= typeDecl(modifiers(inInterface = false))
+ }
+ accept(EOF)
+ atPos(offset) {
+ makePackaging(pkg, buf.toList)
+ }
+ }
+ }
+}