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 Scanners.Offset
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.reporting.diagnostic.messages.IdentifierExpected
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(UnspecifiedErrorType) withPos Position(in.offset)
// --------- tree building -----------------------------
def scalaAnnotationDot(name: Name) = Select(scalaDot(nme.annotation), name)
def javaDot(name: Name): Tree =
Select(rootDot(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 makeTemplate(parents: List[Tree], stats: List[Tree], tparams: List[TypeDef], needsDummyConstr: Boolean) = {
def pullOutFirstConstr(stats: List[Tree]): (Tree, List[Tree]) = stats match {
case (meth: DefDef) :: rest if meth.name == CONSTRUCTOR => (meth, rest)
case first :: rest =>
val (constr, tail) = pullOutFirstConstr(rest)
(constr, first :: tail)
case nil => (EmptyTree, nil)
}
var (constr1, stats1) = pullOutFirstConstr(stats)
if (constr1 == EmptyTree) constr1 = makeConstructor(List(), tparams)
// A dummy first constructor is needed for Java classes so that the real constructors see the
// import of the companion object. The constructor has parameter of type Unit so no Java code
// can call it.
if (needsDummyConstr) {
stats1 = constr1 :: stats1
constr1 = makeConstructor(List(scalaDot(tpnme.Unit)), tparams, Flags.JavaDefined | Flags.PrivateLocal)
}
Template(constr1.asInstanceOf[DefDef], parents, EmptyValDef, stats1)
}
def makeSyntheticParam(count: Int, tpt: Tree): ValDef =
makeParam(nme.syntheticParamName(count), tpt)
def makeParam(name: TermName, tpt: Tree): ValDef =
ValDef(name, tpt, EmptyTree).withMods(Modifiers(Flags.JavaDefined | Flags.ParamAccessor))
def makeConstructor(formals: List[Tree], tparams: List[TypeDef], flags: FlagSet = Flags.JavaDefined) = {
val vparams = mapWithIndex(formals)((p, i) => makeSyntheticParam(i + 1, p))
DefDef(nme.CONSTRUCTOR, tparams, List(vparams), TypeTree(), EmptyTree).withMods(Modifiers(flags))
}
// ------------- 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.
*
* @return The offset at the start of the token to accept
*/
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(_, _) | Select(_, _) =>
tree
case _ =>
syntaxError(IdentifierExpected(tree.show), 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(t.pos.start, in.offset) { Select(t, ident()) }
}
t
}
def optArrayBrackets(tpt: Tree): Tree =
if (in.token == LBRACKET) {
val tpt1 = atPos(tpt.pos.start, 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 if the lhs is an Ident or Select,
// For other nodes it always assumes that the selected item is a type.
def typeSelect(t: Tree, name: Name) = t match {
case Ident(_) | Select(_, _) => Select(t, name)
case _ => Select(t, name.toTypeName)
}
while (in.token == DOT) {
in.nextToken()
t = typeArgs(atPos(t.pos.start, 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.start) {
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 :+= atPos(in.offset) {
in.nextToken()
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.JavaStatic
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)
case TRANSIENT =>
addAnnot(TransientAnnot)
case VOLATILE =>
addAnnot(VolatileAnnot)
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(name, TypeBoundsTree(EmptyTree, hi)).withMods(Modifiers(flags))
}
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 = {
val start = in.offset
if (in.token == FINAL) in.nextToken()
annotations()
var t = typ()
if (in.token == DOTDOTDOT) {
in.nextToken()
t = atPos(t.pos.start) {
PostfixOp(t, nme.raw.STAR)
}
}
atPos(start, in.offset) {
varDecl(Modifiers(Flags.JavaDefined | Flags.Param), t, ident().toTermName)
}
}
def optThrows(): Unit = {
if (in.token == THROWS) {
in.nextToken()
repsep(typ, COMMA)
}
}
def methodBody(): Tree = atPos(in.offset) {
skipAhead()
accept(RBRACE) // skip block
unimplementedExpr
}
def definesInterface(token: Int) = token == INTERFACE || token == AT
def termDecl(start: Offset, 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)
atPos(in.offset) {
in.nextToken()
TypeTree(UnitType)
}
else typ()
var nameOffset = 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(start) {
DefDef(nme.CONSTRUCTOR, parentTParams,
List(vparams), TypeTree(), methodBody()).withMods(mods)
}
}
} else {
var mods1 = mods
if (mods is Flags.Abstract) mods1 = mods &~ Flags.Abstract
nameOffset = 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(nameOffset) {
New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil)
}
mods1 = mods1 withAddedAnnotation annot
val unimplemented = unimplementedExpr
skipTo(SEMI)
accept(SEMI)
unimplemented
} else {
accept(SEMI)
EmptyTree
}
}
//if (inInterface) mods1 |= Flags.Deferred
List {
atPos(start, nameOffset) {
DefDef(name.toTermName, tparams, List(vparams), rtpt, body).withMods(mods1 | Flags.Method)
}
}
} else {
if (inInterface) mods1 |= Flags.Final | Flags.JavaStatic
val result = fieldDecls(start, nameOffset, 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(start: Offset, firstNameOffset: Offset, mods: Modifiers, tpt: Tree, name: Name): List[Tree] = {
val buf = ListBuffer[Tree](
atPos(start, firstNameOffset) { varDecl(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 nextNameOffset = in.offset
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 += atPos(start, nextNameOffset) { varDecl(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 += atPos(start, nextNameOffset) { varDecl(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(mods: Modifiers, tpt: Tree, name: TermName): ValDef = {
val tpt1 = optArrayBrackets(tpt)
if (in.token == EQUALS && !(mods is Flags.Param)) skipTo(COMMA, SEMI)
val mods1 = if (mods is Flags.Final) mods else mods | Flags.Mutable
ValDef(name, tpt1, if (mods is Flags.Param) EmptyTree else unimplementedExpr).withMods(mods1)
}
def memberDecl(start: Offset, mods: Modifiers, parentToken: Int, parentTParams: List[TypeDef]): List[Tree] = in.token match {
case CLASS | ENUM | INTERFACE | AT =>
typeDecl(start, if (definesInterface(parentToken)) mods | Flags.JavaStatic else mods)
case _ =>
termDecl(start, mods, parentToken, parentTParams)
}
def makeCompanionObject(cdef: TypeDef, statics: List[Tree]): Tree =
atPos(cdef.pos) {
assert(cdef.pos.exists)
ModuleDef(cdef.name.toTermName,
makeTemplate(List(), statics, List(), false)).withMods((cdef.mods & (Flags.AccessFlags | Flags.JavaDefined)).toTermFlags)
}
def importCompanionObject(cdef: TypeDef): Tree =
Import(Ident(cdef.name.toTermName).withPos(NoPosition), Ident(nme.WILDCARD) :: Nil)
// 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.name,
cpy.Template(template)(template.constr, template.parents, template.self,
importCompanionObject(cdef) :: template.body)).withMods(cdef.mods)
}
List(makeCompanionObject(cdefNew, statics), cdefNew)
}
def importDecl(): List[Tree] = {
val start = in.offset
accept(IMPORT)
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(start, "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)
// }
val imp = atPos(start) { Import(qual, List(ident)) }
imp :: Nil
}
}
def interfacesOpt() =
if (in.token == IMPLEMENTS) {
in.nextToken()
repsep(typ, COMMA)
} else {
List()
}
def classDecl(start: Offset, mods: Modifiers): List[Tree] = {
accept(CLASS)
val nameOffset = 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)
val cls = atPos(start, nameOffset) {
TypeDef(name, makeTemplate(superclass :: interfaces, body, tparams, true)).withMods(mods)
}
addCompanionObject(statics, cls)
}
def interfaceDecl(start: Offset, mods: Modifiers): List[Tree] = {
accept(INTERFACE)
val nameOffset = 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)
val iface = atPos(start, nameOffset) {
TypeDef(
name,
makeTemplate(parents, body, tparams, false)).withMods(mods | Flags.Trait | Flags.JavaInterface | Flags.Abstract)
}
addCompanionObject(statics, iface)
}
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) {
val start = in.offset
var mods = atPos(start) { 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.JavaStatic
val decls = memberDecl(start, mods, parentToken, parentTParams)
(if ((mods is Flags.JavaStatic) || inInterface && !(decls exists (_.isInstanceOf[DefDef])))
statics
else
members) ++= decls
}
}
def forwarders(sdef: Tree): List[Tree] = sdef match {
case TypeDef(name, _) if (parentToken == INTERFACE) =>
var rhs: Tree = Select(Ident(parentName.toTermName), name)
List(TypeDef(name, rhs).withMods(Modifiers(Flags.Protected)))
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(start: Offset, mods: Modifiers): List[Tree] = {
accept(AT)
accept(INTERFACE)
val nameOffset = in.offset
val name = identForType()
val (statics, body) = typeBody(AT, name, List())
val constructorParams = body.collect {
case dd: DefDef => makeParam(dd.name, dd.tpt)
}
val constr = DefDef(nme.CONSTRUCTOR,
List(), List(constructorParams), TypeTree(), EmptyTree).withMods(Modifiers(Flags.JavaDefined))
val body1 = body.filterNot(_.isInstanceOf[DefDef])
val templ = makeTemplate(annotationParents, constr :: body1, List(), false)
val annot = atPos(start, nameOffset) {
TypeDef(name, templ).withMods(mods | Flags.Abstract)
}
addCompanionObject(statics, annot)
}
def enumDecl(start: Offset, mods: Modifiers): List[Tree] = {
accept(ENUM)
val nameOffset = 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(
nme.values, List(),
ListOfNil,
arrayOf(enumType),
unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method)),
DefDef(
nme.valueOf, List(),
List(List(makeParam("x".toTermName, TypeTree(StringType)))),
enumType,
unimplementedExpr).withMods(Modifiers(Flags.JavaDefined | Flags.JavaStatic | Flags.Method)))
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))))
val enum = atPos(start, nameOffset) {
TypeDef(name,
makeTemplate(superclazz :: interfaces, body, List(), true)).withMods(mods | Flags.Enum)
}
addCompanionObject(consts ::: statics ::: predefs, enum)
}
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(name.toTermName, enumType, unimplementedExpr).withMods(Modifiers(Flags.Enum | Flags.Stable | Flags.JavaDefined | Flags.JavaStatic))
}
}
def typeDecl(start: Offset, mods: Modifiers): List[Tree] = in.token match {
case ENUM => enumDecl(start, mods)
case INTERFACE => interfaceDecl(start, mods)
case AT => annotationDecl(start, mods)
case CLASS => classDecl(start, mods)
case _ => in.nextToken(); syntaxError("illegal start of type declaration", skipIt = true); List(errorTypeTree)
}
/** CompilationUnit ::= [package QualId semi] TopStatSeq
*/
def compilationUnit(): Tree = {
val start = in.offset
val pkg: RefTree =
if (in.token == AT || in.token == PACKAGE) {
annotations()
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) {
val start = in.offset
val mods = atPos(start) { modifiers(inInterface = false) }
buf ++= typeDecl(start, mods)
}
}
val unit = atPos(start) { PackageDef(pkg, buf.toList) }
accept(EOF)
unit
}
}
}