diff options
Diffstat (limited to 'src/dotty/tools/dotc/parsing/JavaParsers.scala')
-rw-r--r-- | src/dotty/tools/dotc/parsing/JavaParsers.scala | 887 |
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) + } + } + } +} |