aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorOndrej Lhotak <olhotak@uwaterloo.ca>2014-09-04 17:06:02 +0200
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-11-22 20:10:20 +0100
commit03627e71d9fdc4b2211d244cc8fd844d57997357 (patch)
treeb0062570c12f5713c09d0aa2519819c202c1f8cb /src/dotty
parentcc1d36f64d324b972ec3116f93c4f62fafd706bc (diff)
downloaddotty-03627e71d9fdc4b2211d244cc8fd844d57997357.tar.gz
dotty-03627e71d9fdc4b2211d244cc8fd844d57997357.tar.bz2
dotty-03627e71d9fdc4b2211d244cc8fd844d57997357.zip
Initial implementation of Java scanner and parser
Ported from scalac 2.11.x branch SHA 9753f23f9362b25a9f481b11dd8d51187187882a This is mostly a direct port, with few significant dotty-specific changes needed. The two more significant changes are: In dotty, the first constructor of a class is pulled out separately from the other stats in the Template. The keyword detection code (buildKeywordArray) was moved into Tokens so that it can more cleanly be shared by the Scala and Java scanners.
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala9
-rw-r--r--src/dotty/tools/dotc/parsing/JavaParsers.scala887
-rw-r--r--src/dotty/tools/dotc/parsing/JavaScanners.scala537
-rw-r--r--src/dotty/tools/dotc/parsing/JavaTokens.scala92
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala90
-rw-r--r--src/dotty/tools/dotc/parsing/Scanners.scala233
-rw-r--r--src/dotty/tools/dotc/parsing/Tokens.scala143
-rw-r--r--src/dotty/tools/dotc/typer/Checking.scala2
-rw-r--r--src/dotty/tools/dotc/typer/FrontEnd.scala5
9 files changed, 1794 insertions, 204 deletions
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index c966f0d61..0e86a2936 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -356,6 +356,12 @@ object Flags {
/** Symbol is a Java-style varargs method */
final val JavaVarargs = termFlag(37, "<varargs>")
+ /** Symbol is a Java default method */
+ final val DefaultMethod = termFlag(38, "<defaultmethod>")
+
+ /** Symbol is a Java enum */
+ final val Enum = commonFlag(40, "<enum>")
+
// Flags following this one are not pickled
/** Symbol always defines a fresh named type */
@@ -547,6 +553,9 @@ object Flags {
/** A Java interface, potentially with default methods */
final val JavaTrait = allOf(JavaDefined, Trait, NoInits)
+
+ /** A Java interface */
+ final val JavaInterface = allOf(JavaDefined, Trait)
/** A Java companion object */
final val JavaModule = allOf(JavaDefined, Module)
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)
+ }
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/parsing/JavaScanners.scala b/src/dotty/tools/dotc/parsing/JavaScanners.scala
new file mode 100644
index 000000000..faac8e163
--- /dev/null
+++ b/src/dotty/tools/dotc/parsing/JavaScanners.scala
@@ -0,0 +1,537 @@
+package dotty.tools
+package dotc
+package parsing
+
+import core.Names._, core.Contexts._, core.Decorators._, util.Positions._
+import Scanners._
+import util.SourceFile
+import JavaTokens._
+import scala.annotation.{ switch, tailrec }
+import scala.reflect.internal.Chars._
+
+object JavaScanners {
+
+ class JavaScanner(source: SourceFile, override val startFrom: Offset = 0)(implicit ctx: Context) extends ScannerCommon(source)(ctx) {
+
+ def toToken(idx: Int): Token =
+ if (idx >= 0 && idx <= lastKeywordStart) kwArray(idx) else IDENTIFIER
+
+ private class JavaTokenData0 extends TokenData
+
+ /** we need one token lookahead
+ */
+ val next : TokenData = new JavaTokenData0
+ val prev : TokenData = new JavaTokenData0
+
+ // Get next token ------------------------------------------------------------
+
+ def nextToken(): Unit = {
+ if (next.token == EMPTY) {
+ fetchToken()
+ }
+ else {
+ this copyFrom next
+ next.token = EMPTY
+ }
+ }
+
+ def lookaheadToken: Int = {
+ prev copyFrom this
+ nextToken()
+ val t = token
+ next copyFrom this
+ this copyFrom prev
+ t
+ }
+
+ /** read next token
+ */
+ private def fetchToken(): Unit = {
+ offset = charOffset - 1
+ ch match {
+ case ' ' | '\t' | CR | LF | FF =>
+ nextChar()
+ fetchToken()
+ case _ =>
+ (ch: @switch) match {
+ case 'A' | 'B' | 'C' | 'D' | 'E' |
+ 'F' | 'G' | 'H' | 'I' | 'J' |
+ 'K' | 'L' | 'M' | 'N' | 'O' |
+ 'P' | 'Q' | 'R' | 'S' | 'T' |
+ 'U' | 'V' | 'W' | 'X' | 'Y' |
+ 'Z' | '$' | '_' |
+ 'a' | 'b' | 'c' | 'd' | 'e' |
+ 'f' | 'g' | 'h' | 'i' | 'j' |
+ 'k' | 'l' | 'm' | 'n' | 'o' |
+ 'p' | 'q' | 'r' | 's' | 't' |
+ 'u' | 'v' | 'w' | 'x' | 'y' |
+ 'z' =>
+ putChar(ch)
+ nextChar()
+ getIdentRest()
+
+ case '0' =>
+ putChar(ch)
+ nextChar()
+ if (ch == 'x' || ch == 'X') {
+ nextChar()
+ base = 16
+ } else {
+ base = 8
+ }
+ getNumber()
+
+ case '1' | '2' | '3' | '4' |
+ '5' | '6' | '7' | '8' | '9' =>
+ base = 10
+ getNumber()
+
+ case '\"' =>
+ nextChar()
+ while (ch != '\"' && (isUnicodeEscape || ch != CR && ch != LF && ch != SU)) {
+ getlitch()
+ }
+ if (ch == '\"') {
+ token = STRINGLIT
+ setStrVal()
+ nextChar()
+ } else {
+ error("unclosed string literal")
+ }
+
+ case '\'' =>
+ nextChar()
+ getlitch()
+ if (ch == '\'') {
+ nextChar()
+ token = CHARLIT
+ setStrVal()
+ } else {
+ error("unclosed character literal")
+ }
+
+ case '=' =>
+ token = EQUALS
+ nextChar()
+ if (ch == '=') {
+ token = EQEQ
+ nextChar()
+ }
+
+ case '>' =>
+ token = GT
+ nextChar()
+ if (ch == '=') {
+ token = GTEQ
+ nextChar()
+ } else if (ch == '>') {
+ token = GTGT
+ nextChar()
+ if (ch == '=') {
+ token = GTGTEQ
+ nextChar()
+ } else if (ch == '>') {
+ token = GTGTGT
+ nextChar()
+ if (ch == '=') {
+ token = GTGTGTEQ
+ nextChar()
+ }
+ }
+ }
+
+ case '<' =>
+ token = LT
+ nextChar()
+ if (ch == '=') {
+ token = LTEQ
+ nextChar()
+ } else if (ch == '<') {
+ token = LTLT
+ nextChar()
+ if (ch == '=') {
+ token = LTLTEQ
+ nextChar()
+ }
+ }
+
+ case '!' =>
+ token = BANG
+ nextChar()
+ if (ch == '=') {
+ token = BANGEQ
+ nextChar()
+ }
+
+ case '~' =>
+ token = TILDE
+ nextChar()
+
+ case '?' =>
+ token = QMARK
+ nextChar()
+
+ case ':' =>
+ token = COLON
+ nextChar()
+
+ case '@' =>
+ token = AT
+ nextChar()
+
+ case '&' =>
+ token = AMP
+ nextChar()
+ if (ch == '&') {
+ token = AMPAMP
+ nextChar()
+ } else if (ch == '=') {
+ token = AMPEQ
+ nextChar()
+ }
+
+ case '|' =>
+ token = BAR
+ nextChar()
+ if (ch == '|') {
+ token = BARBAR
+ nextChar()
+ } else if (ch == '=') {
+ token = BAREQ
+ nextChar()
+ }
+
+ case '+' =>
+ token = PLUS
+ nextChar()
+ if (ch == '+') {
+ token = PLUSPLUS
+ nextChar()
+ } else if (ch == '=') {
+ token = PLUSEQ
+ nextChar()
+ }
+
+ case '-' =>
+ token = MINUS
+ nextChar()
+ if (ch == '-') {
+ token = MINUSMINUS
+ nextChar()
+ } else if (ch == '=') {
+ token = MINUSEQ
+ nextChar()
+ }
+
+ case '*' =>
+ token = ASTERISK
+ nextChar()
+ if (ch == '=') {
+ token = ASTERISKEQ
+ nextChar()
+ }
+
+ case '/' =>
+ nextChar()
+ if (!skipComment()) {
+ token = SLASH
+ nextChar()
+ if (ch == '=') {
+ token = SLASHEQ
+ nextChar()
+ }
+ } else fetchToken()
+
+ case '^' =>
+ token = HAT
+ nextChar()
+ if (ch == '=') {
+ token = HATEQ
+ nextChar()
+ }
+
+ case '%' =>
+ token = PERCENT
+ nextChar()
+ if (ch == '=') {
+ token = PERCENTEQ
+ nextChar()
+ }
+
+ case '.' =>
+ token = DOT
+ nextChar()
+ if ('0' <= ch && ch <= '9') {
+ putChar('.');
+ getFraction()
+ } else if (ch == '.') {
+ nextChar()
+ if (ch == '.') {
+ nextChar()
+ token = DOTDOTDOT
+ } else error("`.' character expected")
+ }
+
+ case ';' =>
+ token = SEMI
+ nextChar()
+
+ case ',' =>
+ token = COMMA
+ nextChar()
+
+ case '(' =>
+ token = LPAREN
+ nextChar()
+
+ case '{' =>
+ token = LBRACE
+ nextChar()
+
+ case ')' =>
+ token = RPAREN
+ nextChar()
+
+ case '}' =>
+ token = RBRACE
+ nextChar()
+
+ case '[' =>
+ token = LBRACKET
+ nextChar()
+
+ case ']' =>
+ token = RBRACKET
+ nextChar()
+
+ case SU =>
+ if (isAtEnd) token = EOF
+ else {
+ error("illegal character")
+ nextChar()
+ }
+
+ case _ =>
+ if (Character.isUnicodeIdentifierStart(ch)) {
+ putChar(ch)
+ nextChar()
+ getIdentRest()
+ } else {
+ error("illegal character: " + ch.toInt)
+ nextChar()
+ }
+ }
+ }
+ }
+
+ protected def skipComment(): Boolean = {
+ @tailrec def skipLineComment(): Unit = ch match {
+ case CR | LF | SU =>
+ case _ => nextChar(); skipLineComment()
+ }
+ @tailrec def skipJavaComment(): Unit = ch match {
+ case SU => incompleteInputError("unclosed comment")
+ case '*' => nextChar(); if (ch == '/') nextChar() else skipJavaComment()
+ case _ => nextChar(); skipJavaComment()
+ }
+ ch match {
+ case '/' => nextChar(); skipLineComment(); true
+ case '*' => nextChar(); skipJavaComment(); true
+ case _ => false
+ }
+ }
+
+ // Identifiers ---------------------------------------------------------------
+
+ private def getIdentRest(): Unit = {
+ while (true) {
+ (ch: @switch) match {
+ case 'A' | 'B' | 'C' | 'D' | 'E' |
+ 'F' | 'G' | 'H' | 'I' | 'J' |
+ 'K' | 'L' | 'M' | 'N' | 'O' |
+ 'P' | 'Q' | 'R' | 'S' | 'T' |
+ 'U' | 'V' | 'W' | 'X' | 'Y' |
+ 'Z' | '$' |
+ 'a' | 'b' | 'c' | 'd' | 'e' |
+ 'f' | 'g' | 'h' | 'i' | 'j' |
+ 'k' | 'l' | 'm' | 'n' | 'o' |
+ 'p' | 'q' | 'r' | 's' | 't' |
+ 'u' | 'v' | 'w' | 'x' | 'y' |
+ 'z' |
+ '0' | '1' | '2' | '3' | '4' |
+ '5' | '6' | '7' | '8' | '9' =>
+ putChar(ch)
+ nextChar()
+
+ case '_' =>
+ putChar(ch)
+ nextChar()
+ getIdentRest()
+ return
+ case SU =>
+ finishNamed()
+ return
+ case _ =>
+ if (Character.isUnicodeIdentifierPart(ch)) {
+ putChar(ch)
+ nextChar()
+ } else {
+ finishNamed()
+ return
+ }
+ }
+ }
+ }
+
+ // Literals -----------------------------------------------------------------
+
+ /** read next character in character or string literal:
+ */
+ protected def getlitch() =
+ if (ch == '\\') {
+ nextChar()
+ if ('0' <= ch && ch <= '7') {
+ val leadch: Char = ch
+ var oct: Int = digit2int(ch, 8)
+ nextChar()
+ if ('0' <= ch && ch <= '7') {
+ oct = oct * 8 + digit2int(ch, 8)
+ nextChar()
+ if (leadch <= '3' && '0' <= ch && ch <= '7') {
+ oct = oct * 8 + digit2int(ch, 8)
+ nextChar()
+ }
+ }
+ putChar(oct.asInstanceOf[Char])
+ } else {
+ ch match {
+ case 'b' => putChar('\b')
+ case 't' => putChar('\t')
+ case 'n' => putChar('\n')
+ case 'f' => putChar('\f')
+ case 'r' => putChar('\r')
+ case '\"' => putChar('\"')
+ case '\'' => putChar('\'')
+ case '\\' => putChar('\\')
+ case _ =>
+ error("invalid escape character", charOffset - 1)
+ putChar(ch)
+ }
+ nextChar()
+ }
+ } else {
+ putChar(ch)
+ nextChar()
+ }
+
+ /** read fractional part and exponent of floating point number
+ * if one is present.
+ */
+ protected def getFraction(): Unit = {
+ token = DOUBLELIT
+ while ('0' <= ch && ch <= '9') {
+ putChar(ch)
+ nextChar()
+ }
+ if (ch == 'e' || ch == 'E') {
+ val lookahead = lookaheadReader
+ lookahead.nextChar()
+ if (lookahead.ch == '+' || lookahead.ch == '-') {
+ lookahead.nextChar()
+ }
+ if ('0' <= lookahead.ch && lookahead.ch <= '9') {
+ putChar(ch)
+ nextChar()
+ if (ch == '+' || ch == '-') {
+ putChar(ch)
+ nextChar()
+ }
+ while ('0' <= ch && ch <= '9') {
+ putChar(ch)
+ nextChar()
+ }
+ }
+ token = DOUBLELIT
+ }
+ if (ch == 'd' || ch == 'D') {
+ putChar(ch)
+ nextChar()
+ token = DOUBLELIT
+ } else if (ch == 'f' || ch == 'F') {
+ putChar(ch)
+ nextChar()
+ token = FLOATLIT
+ }
+ setStrVal()
+ }
+
+ /** read a number into name and set base
+ */
+ protected def getNumber(): Unit = {
+ while (digit2int(ch, if (base < 10) 10 else base) >= 0) {
+ putChar(ch)
+ nextChar()
+ }
+ token = INTLIT
+ if (base <= 10 && ch == '.') {
+ val lookahead = lookaheadReader
+ lookahead.nextChar()
+ lookahead.ch match {
+ case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
+ '8' | '9' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F' =>
+ putChar(ch)
+ nextChar()
+ return getFraction()
+ case _ =>
+ if (!isIdentifierStart(lookahead.ch)) {
+ putChar(ch)
+ nextChar()
+ return getFraction()
+ }
+ }
+ }
+ if (base <= 10 &&
+ (ch == 'e' || ch == 'E' ||
+ ch == 'f' || ch == 'F' ||
+ ch == 'd' || ch == 'D')) {
+ return getFraction()
+ }
+ setStrVal()
+ if (ch == 'l' || ch == 'L') {
+ nextChar()
+ token = LONGLIT
+ }
+ }
+
+ // Errors -----------------------------------------------------------------
+
+ override def toString() = token match {
+ case IDENTIFIER =>
+ "id(" + name + ")"
+ case CHARLIT =>
+ "char(" + intVal + ")"
+ case INTLIT =>
+ "int(" + intVal + ")"
+ case LONGLIT =>
+ "long(" + intVal + ")"
+ case FLOATLIT =>
+ "float(" + floatVal + ")"
+ case DOUBLELIT =>
+ "double(" + floatVal + ")"
+ case STRINGLIT =>
+ "string(" + name + ")"
+ case SEMI =>
+ ";"
+ case COMMA =>
+ ","
+ case _ =>
+ tokenString(token)
+ }
+
+ /* Initialization: read first char, then first token */
+ nextChar()
+ nextToken()
+ }
+
+ val (lastKeywordStart, kwArray) = buildKeywordArray(keywords)
+}
diff --git a/src/dotty/tools/dotc/parsing/JavaTokens.scala b/src/dotty/tools/dotc/parsing/JavaTokens.scala
new file mode 100644
index 000000000..9530e0516
--- /dev/null
+++ b/src/dotty/tools/dotc/parsing/JavaTokens.scala
@@ -0,0 +1,92 @@
+package dotty.tools
+package dotc
+package parsing
+
+import collection.immutable.BitSet
+
+object JavaTokens extends TokensCommon {
+ final val minToken = EMPTY
+ final val maxToken = DOUBLE
+
+ final val javaOnlyKeywords = tokenRange(INSTANCEOF, ASSERT)
+ final val sharedKeywords = BitSet( IF, FOR, ELSE, THIS, NULL, NEW, SUPER, ABSTRACT, FINAL, PRIVATE, PROTECTED,
+ OVERRIDE, EXTENDS, TRUE, FALSE, CLASS, IMPORT, PACKAGE, DO, THROW, TRY, CATCH, FINALLY, WHILE, RETURN )
+ final val primTypes = tokenRange(VOID, DOUBLE)
+ final val keywords = sharedKeywords | javaOnlyKeywords | primTypes
+
+ /** keywords */
+ final val INSTANCEOF = 101; enter(INSTANCEOF, "instanceof")
+ final val CONST = 102; enter(CONST, "const")
+
+ /** templates */
+ final val INTERFACE = 105; enter(INTERFACE, "interface")
+ final val ENUM = 106; enter(ENUM, "enum")
+ final val IMPLEMENTS = 107; enter(IMPLEMENTS, "implements")
+
+ /** modifiers */
+ final val PUBLIC = 110; enter(PUBLIC, "public")
+ final val DEFAULT = 111; enter(DEFAULT, "default")
+ final val STATIC = 112; enter(STATIC, "static")
+ final val TRANSIENT = 113; enter(TRANSIENT, "transient")
+ final val VOLATILE = 114; enter(VOLATILE, "volatile")
+ final val SYNCHRONIZED = 115; enter(SYNCHRONIZED, "synchronized")
+ final val NATIVE = 116; enter(NATIVE, "native")
+ final val STRICTFP = 117; enter(STRICTFP, "strictfp")
+ final val THROWS = 118; enter(THROWS, "throws")
+
+ /** control structures */
+ final val BREAK = 130; enter(BREAK, "break")
+ final val CONTINUE = 131; enter(CONTINUE, "continue")
+ final val GOTO = 132; enter(GOTO, "goto")
+ final val SWITCH = 133; enter(SWITCH, "switch")
+ final val ASSERT = 134; enter(ASSERT, "assert")
+
+ /** special symbols */
+ final val EQEQ = 140
+ final val BANGEQ = 141
+ final val LT = 142
+ final val GT = 143
+ final val LTEQ = 144
+ final val GTEQ = 145
+ final val BANG = 146
+ final val QMARK = 147
+ final val AMP = 148
+ final val BAR = 149
+ final val PLUS = 150
+ final val MINUS = 151
+ final val ASTERISK = 152
+ final val SLASH = 153
+ final val PERCENT = 154
+ final val HAT = 155
+ final val LTLT = 156
+ final val GTGT = 157
+ final val GTGTGT = 158
+ final val AMPAMP = 159
+ final val BARBAR = 160
+ final val PLUSPLUS = 161
+ final val MINUSMINUS = 162
+ final val TILDE = 163
+ final val DOTDOTDOT = 164
+ final val AMPEQ = 165
+ final val BAREQ = 166
+ final val PLUSEQ = 167
+ final val MINUSEQ = 168
+ final val ASTERISKEQ = 169
+ final val SLASHEQ = 170
+ final val PERCENTEQ = 171
+ final val HATEQ = 172
+ final val LTLTEQ = 173
+ final val GTGTEQ = 174
+ final val GTGTGTEQ = 175
+
+ /** primitive types */
+ final val VOID = 180; enter(VOID, "void")
+ final val BOOLEAN = 181; enter(BOOLEAN, "boolean")
+ final val BYTE = 182; enter(BYTE, "byte")
+ final val SHORT = 183; enter(SHORT, "short")
+ final val CHAR = 184; enter(CHAR, "char")
+ final val INT = 185; enter(INT, "int")
+ final val LONG = 186; enter(LONG, "long")
+ final val FLOAT = 187; enter(FLOAT, "float")
+ final val DOUBLE = 188; enter(DOUBLE, "double")
+}
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index 1b08b7400..e8a6fd815 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -51,9 +51,56 @@ object Parsers {
if (source.isSelfContained) new ScriptParser(source)
else new Parser(source)
- class Parser(val source: SourceFile)(implicit ctx: Context) extends DotClass {
+ abstract class ParserCommon(val source: SourceFile)(implicit ctx: Context) extends DotClass {
- val in = new Scanner(source)
+ val in: ScannerCommon
+
+ /* ------------- POSITIONS ------------------------------------------- */
+
+ def atPos[T <: Positioned](start: Offset, point: Offset, end: Offset)(t: T): T =
+ atPos(Position(start, end, point))(t)
+
+ def atPos[T <: Positioned](start: Offset, point: Offset)(t: T): T =
+ atPos(start, point, in.lastOffset)(t)
+
+ def atPos[T <: Positioned](start: Offset)(t: T): T =
+ atPos(start, start)(t)
+
+ def atPos[T <: Positioned](pos: Position)(t: T): T =
+ if (t.pos.isSourceDerived) t else t.withPos(pos)
+
+ def tokenRange = Position(in.offset, in.lastCharOffset, in.offset)
+
+ def sourcePos(off: Int = in.offset): SourcePosition =
+ source atPos Position(off)
+
+
+ /* ------------- ERROR HANDLING ------------------------------------------- */
+ /** The offset where the last syntax error was reported, or if a skip to a
+ * safepoint occurred afterwards, the offset of the safe point.
+ */
+ protected var lastErrorOffset : Int = -1
+
+ /** Issue an error at given offset if beyond last error offset
+ * and update lastErrorOffset.
+ */
+ def syntaxError(msg: String, offset: Int = in.offset): Unit =
+ if (offset > lastErrorOffset) {
+ syntaxError(msg, Position(offset))
+ lastErrorOffset = in.offset
+ }
+
+ /** Unconditionally issue an error at given position, without
+ * updating lastErrorOffset.
+ */
+ def syntaxError(msg: String, pos: Position): Unit =
+ ctx.error(msg, source atPos pos)
+
+ }
+
+ class Parser(source: SourceFile)(implicit ctx: Context) extends ParserCommon(source) {
+
+ val in: Scanner = new Scanner(source)
val openParens = new ParensCounters
@@ -85,25 +132,6 @@ object Parsers {
def isStatSep: Boolean =
in.token == NEWLINE || in.token == NEWLINES || in.token == SEMI
-/* ------------- POSITIONS ------------------------------------------- */
-
- def atPos[T <: Positioned](start: Offset, point: Offset, end: Offset)(t: T): T =
- atPos(Position(start, end, point))(t)
-
- def atPos[T <: Positioned](start: Offset, point: Offset)(t: T): T =
- atPos(start, point, in.lastOffset)(t)
-
- def atPos[T <: Positioned](start: Offset)(t: T): T =
- atPos(start, start)(t)
-
- def atPos[T <: Positioned](pos: Position)(t: T): T =
- if (t.pos.isSourceDerived) t else t.withPos(pos)
-
- def tokenRange = Position(in.offset, in.lastCharOffset, in.offset)
-
- def sourcePos(off: Int = in.offset): SourcePosition =
- source atPos Position(off)
-
/* ------------- ERROR HANDLING ------------------------------------------- */
/** The offset of the last time when a statement on a new line was definitely
@@ -177,26 +205,6 @@ object Parsers {
def deprecationWarning(msg: String, offset: Int = in.offset) =
ctx.deprecationWarning(msg, source atPos Position(offset))
- /** The offset where the last syntax error was reported, or if a skip to a
- * safepoint occurred afterwards, the offset of the safe point.
- */
- private var lastErrorOffset : Int = -1
-
- /** Issue an error at given offset if beyond last error offset
- * and update lastErrorOffset.
- */
- def syntaxError(msg: String, offset: Int = in.offset): Unit =
- if (offset > lastErrorOffset) {
- syntaxError(msg, Position(offset))
- lastErrorOffset = in.offset
- }
-
- /** Unconditionally issue an error at given position, without
- * updating lastErrorOffset.
- */
- def syntaxError(msg: String, pos: Position): Unit =
- ctx.error(msg, source atPos pos)
-
/** Issue an error at current offset taht input is incomplete */
def incompleteInputError(msg: String) =
ctx.incompleteInputError(msg, source atPos Position(in.offset))
diff --git a/src/dotty/tools/dotc/parsing/Scanners.scala b/src/dotty/tools/dotc/parsing/Scanners.scala
index 4d8fdd10d..5eb8357a4 100644
--- a/src/dotty/tools/dotc/parsing/Scanners.scala
+++ b/src/dotty/tools/dotc/parsing/Scanners.scala
@@ -58,36 +58,136 @@ object Scanners {
}
}
- class Scanner(source: SourceFile, override val startFrom: Offset = 0)(implicit ctx: Context) extends CharArrayReader with TokenData {
-
+ abstract class ScannerCommon(source: SourceFile)(implicit ctx: Context) extends CharArrayReader with TokenData {
val buf = source.content
- var keepComments = false
-
- /** All comments in the reverse order of their position in the source.
- * set only when `keepComments` is true.
- */
- var revComments: List[Comment] = Nil
+ // Errors -----------------------------------------------------------------
/** the last error offset
- */
+ */
var errOffset: Offset = NoOffset
- /** A buffer for comments */
- val commentBuf = new StringBuilder
+
+ /** Generate an error at the given offset */
+ def error(msg: String, off: Offset = offset) = {
+ ctx.error(msg, source atPos Position(off))
+ token = ERROR
+ errOffset = off
+ }
+
+ /** signal an error where the input ended in the middle of a token */
+ def incompleteInputError(msg: String): Unit = {
+ ctx.incompleteInputError(msg, source atPos Position(offset))
+ token = EOF
+ errOffset = offset
+ }
+
+ // Setting token data ----------------------------------------------------
/** A character buffer for literals
- */
+ */
val litBuf = new StringBuilder
/** append Unicode character to "litBuf" buffer
- */
+ */
protected def putChar(c: Char): Unit = litBuf.append(c)
+ /** Return buffer contents and clear */
+ def flushBuf(buf: StringBuilder): String = {
+ val str = buf.toString
+ buf.clear()
+ str
+ }
+
+ /** Clear buffer and set name and token */
+ def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit = {
+ target.name = flushBuf(litBuf).toTermName
+ target.token = idtoken
+ if (idtoken == IDENTIFIER) {
+ val idx = target.name.start
+ target.token = toToken(idx)
+ }
+ }
+ def toToken(idx: Int): Token
+
/** Clear buffer and set string */
- private def setStrVal() =
+ def setStrVal() =
strVal = flushBuf(litBuf)
+ /** Convert current strVal to char value
+ */
+ def charVal: Char = if (strVal.length > 0) strVal.charAt(0) else 0
+
+ /** Convert current strVal, base to long value
+ * This is tricky because of max negative value.
+ */
+ def intVal(negated: Boolean): Long = {
+ if (token == CHARLIT && !negated) {
+ charVal
+ } else {
+ var value: Long = 0
+ val divider = if (base == 10) 1 else 2
+ val limit: Long =
+ if (token == LONGLIT) Long.MaxValue else Int.MaxValue
+ var i = 0
+ val len = strVal.length
+ while (i < len) {
+ val d = digit2int(strVal charAt i, base)
+ if (d < 0) {
+ error("malformed integer number")
+ return 0
+ }
+ if (value < 0 ||
+ limit / (base / divider) < value ||
+ limit - (d / divider) < value * (base / divider) &&
+ !(negated && limit == value * base - 1 + d)) {
+ error("integer number too large")
+ return 0
+ }
+ value = value * base + d
+ i += 1
+ }
+ if (negated) -value else value
+ }
+ }
+
+ def intVal: Long = intVal(false)
+
+ /** Convert current strVal, base to double value
+ */
+ def floatVal(negated: Boolean): Double = {
+ val limit: Double =
+ if (token == DOUBLELIT) Double.MaxValue else Float.MaxValue
+ try {
+ val value: Double = java.lang.Double.valueOf(strVal).doubleValue()
+ if (value > limit)
+ error("floating point number too large")
+ if (negated) -value else value
+ } catch {
+ case _: NumberFormatException =>
+ error("malformed floating point number")
+ 0.0
+ }
+ }
+
+ def floatVal: Double = floatVal(false)
+
+ }
+
+ class Scanner(source: SourceFile, override val startFrom: Offset = 0)(implicit ctx: Context) extends ScannerCommon(source)(ctx) {
+ var keepComments = false
+
+ /** All comments in the reverse order of their position in the source.
+ * set only when `keepComments` is true.
+ */
+ var revComments: List[Comment] = Nil
+
+ /** A buffer for comments */
+ val commentBuf = new StringBuilder
+
+ def toToken(idx: Int): Token =
+ if (idx >= 0 && idx <= lastKeywordStart) kwArray(idx) else IDENTIFIER
+
private class TokenData0 extends TokenData
/** we need one token lookahead and one token history
@@ -818,84 +918,6 @@ object Scanners {
strVal = name.toString
}
}
-
-// Setting token data ----------------------------------------------------
-
- /** Clear buffer and set name and token */
- def finishNamed(idtoken: Token = IDENTIFIER, target: TokenData = this): Unit = {
- target.name = flushBuf(litBuf).toTermName
- target.token = idtoken
- if (idtoken == IDENTIFIER) {
- val idx = target.name.start
- if (idx >= 0 && idx <= lastKeywordStart) target.token = kwArray(idx)
- }
- }
-
- /** Return buffer contents and clear */
- def flushBuf(buf: StringBuilder): String = {
- val str = buf.toString
- buf.clear()
- str
- }
-
- /** Convert current strVal to char value
- */
- def charVal: Char = if (strVal.length > 0) strVal.charAt(0) else 0
-
- /** Convert current strVal, base to long value
- * This is tricky because of max negative value.
- */
- def intVal(negated: Boolean): Long = {
- if (token == CHARLIT && !negated) {
- charVal
- } else {
- var value: Long = 0
- val divider = if (base == 10) 1 else 2
- val limit: Long =
- if (token == LONGLIT) Long.MaxValue else Int.MaxValue
- var i = 0
- val len = strVal.length
- while (i < len) {
- val d = digit2int(strVal charAt i, base)
- if (d < 0) {
- error("malformed integer number")
- return 0
- }
- if (value < 0 ||
- limit / (base / divider) < value ||
- limit - (d / divider) < value * (base / divider) &&
- !(negated && limit == value * base - 1 + d)) {
- error("integer number too large")
- return 0
- }
- value = value * base + d
- i += 1
- }
- if (negated) -value else value
- }
- }
-
- def intVal: Long = intVal(false)
-
- /** Convert current strVal, base to double value
- */
- def floatVal(negated: Boolean): Double = {
- val limit: Double =
- if (token == DOUBLELIT) Double.MaxValue else Float.MaxValue
- try {
- val value: Double = java.lang.Double.valueOf(strVal).doubleValue()
- if (value > limit)
- error("floating point number too large")
- if (negated) -value else value
- } catch {
- case _: NumberFormatException =>
- error("malformed floating point number")
- 0.0
- }
- }
-
- def floatVal: Double = floatVal(false)
-
override def toString =
showTokenDetailed(token) + {
if ((identifierTokens contains token) || (literalTokens contains token)) " " + name
@@ -930,22 +952,6 @@ object Scanners {
nextToken()
}
-// Errors -----------------------------------------------------------------
-
- /** Generate an error at the given offset */
- def error(msg: String, off: Offset = offset) = {
- ctx.error(msg, source atPos Position(off))
- token = ERROR
- errOffset = off
- }
-
- /** signal an error where the input ended in the middle of a token */
- def incompleteInputError(msg: String): Unit = {
- ctx.incompleteInputError(msg, source atPos Position(offset))
- token = EOF
- errOffset = offset
- }
-
/* Initialization: read first char, then first token */
nextChar()
nextToken()
@@ -953,14 +959,5 @@ object Scanners {
// ------------- keyword configuration -----------------------------------
- private def start(tok: Token) = tokenString(tok).toTermName.start
- private def sourceKeywords = keywords.toList.filterNot(kw => tokenString(kw) contains ' ')
-
- private val lastKeywordStart = sourceKeywords.map(start).max
-
- private val kwArray: Array[Token] = {
- val arr = Array.fill(lastKeywordStart + 1)(IDENTIFIER)
- for (kw <- sourceKeywords) arr(start(kw)) = kw
- arr
- }
+ val (lastKeywordStart, kwArray) = buildKeywordArray(keywords)
}
diff --git a/src/dotty/tools/dotc/parsing/Tokens.scala b/src/dotty/tools/dotc/parsing/Tokens.scala
index 09124d0d1..226a3710d 100644
--- a/src/dotty/tools/dotc/parsing/Tokens.scala
+++ b/src/dotty/tools/dotc/parsing/Tokens.scala
@@ -3,11 +3,10 @@ package dotc
package parsing
import collection.immutable.BitSet
+import core.Decorators._
-object Tokens {
-
- final val minToken = EMPTY
- final val maxToken = XMLSTART
+abstract class TokensCommon {
+ val maxToken: Int
type Token = Int
type TokenSet = BitSet
@@ -24,6 +23,7 @@ object Tokens {
val tokenString, debugString = new Array[String](maxToken + 1)
def enter(token: Int, str: String, debugStr: String = ""): Unit = {
+ assert(tokenString(token) == null)
tokenString(token) = str
debugString(token) = if (debugStr.isEmpty) str else debugStr
}
@@ -41,17 +41,12 @@ object Tokens {
final val DOUBLELIT = 7; enter(DOUBLELIT, "double literal")
final val STRINGLIT = 8; enter(STRINGLIT, "string literal")
final val STRINGPART = 9; enter(STRINGPART, "string literal", "string literal part")
- final val INTERPOLATIONID = 10; enter(INTERPOLATIONID, "string interpolator")
- final val SYMBOLLIT = 11; enter(SYMBOLLIT, "symbol literal") // TODO: deprecate
+ //final val INTERPOLATIONID = 10; enter(INTERPOLATIONID, "string interpolator")
+ //final val SYMBOLLIT = 11; enter(SYMBOLLIT, "symbol literal") // TODO: deprecate
/** identifiers */
final val IDENTIFIER = 12; enter(IDENTIFIER, "identifier")
- final val BACKQUOTED_IDENT = 13; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident")
-
- final val identifierTokens = BitSet(IDENTIFIER, BACKQUOTED_IDENT)
-
- def isIdentifier(token : Int) =
- token >= IDENTIFIER && token <= BACKQUOTED_IDENT
+ //final val BACKQUOTED_IDENT = 13; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident")
/** alphabetic keywords */
final val IF = 20; enter(IF, "if")
@@ -60,67 +55,63 @@ object Tokens {
final val THIS = 23; enter(THIS, "this")
final val NULL = 24; enter(NULL, "null")
final val NEW = 25; enter(NEW, "new")
- final val WITH = 26; enter(WITH, "with")
+ //final val WITH = 26; enter(WITH, "with")
final val SUPER = 27; enter(SUPER, "super")
- final val CASE = 28; enter(CASE, "case")
- final val CASECLASS = 29; enter(CASECLASS, "case class")
- final val CASEOBJECT = 30; enter(CASEOBJECT, "case object")
- final val VAL = 31; enter(VAL, "val")
+ //final val CASE = 28; enter(CASE, "case")
+ //final val CASECLASS = 29; enter(CASECLASS, "case class")
+ //final val CASEOBJECT = 30; enter(CASEOBJECT, "case object")
+ //final val VAL = 31; enter(VAL, "val")
final val ABSTRACT = 32; enter(ABSTRACT, "abstract")
final val FINAL = 33; enter(FINAL, "final")
final val PRIVATE = 34; enter(PRIVATE, "private")
final val PROTECTED = 35; enter(PROTECTED, "protected")
final val OVERRIDE = 36; enter(OVERRIDE, "override")
- final val IMPLICIT = 37; enter(IMPLICIT, "implicit")
- final val VAR = 38; enter(VAR, "var")
- final val DEF = 39; enter(DEF, "def")
- final val TYPE = 40; enter(TYPE, "type")
+ //final val IMPLICIT = 37; enter(IMPLICIT, "implicit")
+ //final val VAR = 38; enter(VAR, "var")
+ //final val DEF = 39; enter(DEF, "def")
+ //final val TYPE = 40; enter(TYPE, "type")
final val EXTENDS = 41; enter(EXTENDS, "extends")
final val TRUE = 42; enter(TRUE, "true")
final val FALSE = 43; enter(FALSE, "false")
- final val OBJECT = 44; enter(OBJECT, "object")
+ //final val OBJECT = 44; enter(OBJECT, "object")
final val CLASS = 45; enter(CLASS, "class")
final val IMPORT = 46; enter(IMPORT, "import")
final val PACKAGE = 47; enter(PACKAGE, "package")
- final val YIELD = 48; enter(YIELD, "yield")
+ //final val YIELD = 48; enter(YIELD, "yield")
final val DO = 49; enter(DO, "do")
- final val TRAIT = 50; enter(TRAIT, "trait")
- final val SEALED = 51; enter(SEALED, "sealed")
+ //final val TRAIT = 50; enter(TRAIT, "trait")
+ //final val SEALED = 51; enter(SEALED, "sealed")
final val THROW = 52; enter(THROW, "throw")
final val TRY = 53; enter(TRY, "try")
final val CATCH = 54; enter(CATCH, "catch")
final val FINALLY = 55; enter(FINALLY, "finally")
final val WHILE = 56; enter(WHILE, "while")
final val RETURN = 57; enter(RETURN, "return")
- final val MATCH = 58; enter(MATCH, "match")
- final val LAZY = 59; enter(LAZY, "lazy")
- final val THEN = 60; enter(THEN, "then")
- final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
-
- final val alphaKeywords = tokenRange(IF, FORSOME)
+ //final val MATCH = 58; enter(MATCH, "match")
+ //final val LAZY = 59; enter(LAZY, "lazy")
+ //final val THEN = 60; enter(THEN, "then")
+ //final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
/** special symbols */
final val COMMA = 70; enter(COMMA, "','")
final val SEMI = 71; enter(DOT, "'.'")
final val DOT = 72; enter(SEMI, "';'")
- final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
- final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines")
+ //final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
+ //final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines")
/** special keywords */
- final val USCORE = 73; enter(USCORE, "_")
+ //final val USCORE = 73; enter(USCORE, "_")
final val COLON = 74; enter(COLON, ":")
final val EQUALS = 75; enter(EQUALS, "=")
- final val LARROW = 76; enter(LARROW, "<-")
- final val ARROW = 77; enter(ARROW, "=>")
- final val SUBTYPE = 80; enter(SUBTYPE, "<:")
- final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
- final val HASH = 82; enter(HASH, "#")
+ //final val LARROW = 76; enter(LARROW, "<-")
+ //final val ARROW = 77; enter(ARROW, "=>")
+ //final val SUBTYPE = 80; enter(SUBTYPE, "<:")
+ //final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
+ //final val HASH = 82; enter(HASH, "#")
final val AT = 83; enter(AT, "@")
- final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate
+ //final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate
- final val symbolicKeywords = tokenRange(USCORE, VIEWBOUND)
- final val symbolicTokens = tokenRange(COMMA, VIEWBOUND)
- final val keywords = alphaKeywords | symbolicKeywords
+ val keywords: TokenSet
/** parentheses */
final val LPAREN = 90; enter(LPAREN, "'('")
@@ -133,9 +124,75 @@ object Tokens {
final val firstParen = LPAREN
final val lastParen = RBRACE
+ def buildKeywordArray(keywords: TokenSet) = {
+ def start(tok: Token) = tokenString(tok).toTermName.start
+ def sourceKeywords = keywords.toList.filter { (kw: Token) =>
+ val ts = tokenString(kw)
+ (ts != null) && !ts.contains(' ')
+ }
+
+ val lastKeywordStart = sourceKeywords.map(start).max
+
+ val arr = Array.fill(lastKeywordStart + 1)(IDENTIFIER)
+ for (kw <- sourceKeywords) arr(start(kw)) = kw
+ (lastKeywordStart, arr)
+ }
+}
+
+object Tokens extends TokensCommon {
+ final val minToken = EMPTY
+ final val maxToken = XMLSTART
+
+ final val INTERPOLATIONID = 10; enter(INTERPOLATIONID, "string interpolator")
+ final val SYMBOLLIT = 11; enter(SYMBOLLIT, "symbol literal") // TODO: deprecate
+
+ final val BACKQUOTED_IDENT = 13; enter(BACKQUOTED_IDENT, "identifier", "backquoted ident")
+
+ final val identifierTokens = BitSet(IDENTIFIER, BACKQUOTED_IDENT)
+
+ def isIdentifier(token : Int) =
+ token >= IDENTIFIER && token <= BACKQUOTED_IDENT
+
+ /** alphabetic keywords */
+ final val WITH = 26; enter(WITH, "with")
+ final val CASE = 28; enter(CASE, "case")
+ final val CASECLASS = 29; enter(CASECLASS, "case class")
+ final val CASEOBJECT = 30; enter(CASEOBJECT, "case object")
+ final val VAL = 31; enter(VAL, "val")
+ final val IMPLICIT = 37; enter(IMPLICIT, "implicit")
+ final val VAR = 38; enter(VAR, "var")
+ final val DEF = 39; enter(DEF, "def")
+ final val TYPE = 40; enter(TYPE, "type")
+ final val OBJECT = 44; enter(OBJECT, "object")
+ final val YIELD = 48; enter(YIELD, "yield")
+ final val TRAIT = 50; enter(TRAIT, "trait")
+ final val SEALED = 51; enter(SEALED, "sealed")
+ final val MATCH = 58; enter(MATCH, "match")
+ final val LAZY = 59; enter(LAZY, "lazy")
+ final val THEN = 60; enter(THEN, "then")
+ final val FORSOME = 61; enter(FORSOME, "forSome") // TODO: deprecate
+
+ /** special symbols */
+ final val NEWLINE = 78; enter(NEWLINE, "end of statement", "new line")
+ final val NEWLINES = 79; enter(NEWLINES, "end of statement", "new lines")
+
+ /** special keywords */
+ final val USCORE = 73; enter(USCORE, "_")
+ final val LARROW = 76; enter(LARROW, "<-")
+ final val ARROW = 77; enter(ARROW, "=>")
+ final val SUBTYPE = 80; enter(SUBTYPE, "<:")
+ final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
+ final val HASH = 82; enter(HASH, "#")
+ final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate
+
/** XML mode */
final val XMLSTART = 96; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate
+ final val alphaKeywords = tokenRange(IF, FORSOME)
+ final val symbolicKeywords = tokenRange(USCORE, VIEWBOUND)
+ final val symbolicTokens = tokenRange(COMMA, VIEWBOUND)
+ final val keywords = alphaKeywords | symbolicKeywords
+
final val allTokens = tokenRange(minToken, maxToken)
final val literalTokens = tokenRange(CHARLIT, SYMBOLLIT) | BitSet(TRUE, FALSE, NULL)
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala
index 4466e05ed..a0c43c568 100644
--- a/src/dotty/tools/dotc/typer/Checking.scala
+++ b/src/dotty/tools/dotc/typer/Checking.scala
@@ -182,7 +182,7 @@ trait Checking {
def checkValue(tree: Tree, proto: Type)(implicit ctx: Context): tree.type = {
if (!proto.isInstanceOf[SelectionProto]) {
val sym = tree.tpe.termSymbol
- if ((sym is Package) || (sym is JavaModule)) ctx.error(d"$sym is not a value", tree.pos)
+ if ((sym is Package) || ((sym is JavaModule) && !ctx.compilationUnit.isJava)) ctx.error(d"$sym is not a value", tree.pos)
}
tree
}
diff --git a/src/dotty/tools/dotc/typer/FrontEnd.scala b/src/dotty/tools/dotc/typer/FrontEnd.scala
index 4f3b03fa1..d276792e7 100644
--- a/src/dotty/tools/dotc/typer/FrontEnd.scala
+++ b/src/dotty/tools/dotc/typer/FrontEnd.scala
@@ -4,6 +4,7 @@ package typer
import core._
import Phases._
import Contexts._
+import dotty.tools.dotc.parsing.JavaParsers.JavaParser
import parsing.Parsers.Parser
import config.Printers._
import util.Stats._
@@ -22,7 +23,9 @@ class FrontEnd extends Phase {
def parse(implicit ctx: Context) = monitor("parsing") {
val unit = ctx.compilationUnit
- unit.untpdTree = new Parser(unit.source).parse()
+ unit.untpdTree =
+ if(unit.isJava) new JavaParser(unit.source).parse()
+ else new Parser(unit.source).parse()
typr.println("parsed:\n"+unit.untpdTree.show)
}