From 89ced246b3296fb1e297bd944070d49afd4be098 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sun, 21 Apr 2013 04:22:27 -0700 Subject: Boil out some duplicated parser logic. Our focus today is on packages and package objects. --- .../scala/tools/nsc/ast/parser/Parsers.scala | 224 ++++++++++----------- 1 file changed, 108 insertions(+), 116 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index bd3af5f9a2..1dfb2f3bab 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -30,6 +30,9 @@ trait ParsersCommon extends ScannersCommon { val global : Global import global._ + def newLiteral(const: Any) = Literal(Constant(const)) + def literalUnit = newLiteral(()) + /** This is now an abstract class, only to work around the optimizer: * methods in traits are never inlined. */ @@ -57,7 +60,7 @@ trait ParsersCommon extends ScannersCommon { if (in.token == LPAREN) inParens(body) else { accept(LPAREN) ; alt } - @inline final def inParensOrUnit[T](body: => Tree): Tree = inParensOrError(body, Literal(Constant(()))) + @inline final def inParensOrUnit[T](body: => Tree): Tree = inParensOrError(body, literalUnit) @inline final def inParensOrNil[T](body: => List[T]): List[T] = inParensOrError(body, Nil) @inline final def inBraces[T](body: => T): T = { @@ -71,7 +74,7 @@ trait ParsersCommon extends ScannersCommon { else { accept(LBRACE) ; alt } @inline final def inBracesOrNil[T](body: => List[T]): List[T] = inBracesOrError(body, Nil) - @inline final def inBracesOrUnit[T](body: => Tree): Tree = inBracesOrError(body, Literal(Constant(()))) + @inline final def inBracesOrUnit[T](body: => Tree): Tree = inBracesOrError(body, literalUnit) @inline final def dropAnyBraces[T](body: => T): T = if (in.token == LBRACE) inBraces(body) else body @@ -355,7 +358,7 @@ self => /* If we see anything but the above, fail. */ return None } - Some(makePackaging(0, emptyPkg, newStmts)) + Some(makeEmptyPackage(0, newStmts)) } if (mainModuleName == newTermName(ScriptRunner.defaultScriptMain)) @@ -376,15 +379,13 @@ self => * } * }}} */ - - def emptyPkg = atPos(0, 0, 0) { Ident(nme.EMPTY_PACKAGE_NAME) } def emptyInit = DefDef( NoMods, nme.CONSTRUCTOR, Nil, ListOfNil, TypeTree(), - Block(List(Apply(gen.mkSuperInitCall, Nil)), Literal(Constant(()))) + Block(List(Apply(gen.mkSuperInitCall, Nil)), literalUnit) ) // def main @@ -395,11 +396,11 @@ self => // object Main def moduleName = newTermName(ScriptRunner scriptMain settings) - def moduleBody = Template(List(atPos(o2p(in.offset))(scalaAnyRefConstr)), emptyValDef, List(emptyInit, mainDef)) + def moduleBody = Template(atInPos(scalaAnyRefConstr) :: Nil, emptyValDef, List(emptyInit, mainDef)) def moduleDef = ModuleDef(NoMods, moduleName, moduleBody) // package { ... } - makePackaging(0, emptyPkg, List(moduleDef)) + makeEmptyPackage(0, moduleDef :: Nil) } /* --------------- PLACEHOLDERS ------------------------------------------- */ @@ -529,6 +530,10 @@ self => else syntaxError(in.offset, msg, skipIt) } + def syntaxErrorOrIncompleteAnd[T](msg: String, skipIt: Boolean)(and: T): T = { + syntaxErrorOrIncomplete(msg, skipIt) + and + } def expectedMsg(token: Int): String = token2string(token) + " expected but " +token2string(in.token) + " found." @@ -563,9 +568,9 @@ self => if (!isStatSeqEnd) acceptStatSep() - def errorTypeTree = TypeTree() setType ErrorType setPos o2p(in.offset) - def errorTermTree = Literal(Constant(null)) setPos o2p(in.offset) - def errorPatternTree = Ident(nme.WILDCARD) setPos o2p(in.offset) + def errorTypeTree = setInPos(TypeTree() setType ErrorType) + def errorTermTree = setInPos(newLiteral(null)) + def errorPatternTree = setInPos(Ident(nme.WILDCARD)) /** Check that type parameter is not by name or repeated. */ def checkNotByNameOrVarargs(tpt: Tree) = { @@ -607,6 +612,10 @@ self => } def isDefIntro = isTemplateIntro || isDclIntro + def isTopLevelIntro = in.token match { + case PACKAGE | IMPORT | AT => true + case _ => isTemplateIntro || isModifier + } def isNumericLit: Boolean = in.token match { case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => true @@ -666,6 +675,9 @@ self => def atPos[T <: Tree](pos: Position)(t: T): T = global.atPos(pos)(t) + def atInPos[T <: Tree](t: T): T = atPos(o2p(in.offset))(t) + def setInPos[T <: Tree](t: T): T = t setPos o2p(in.offset) + /** Convert tree to formal parameter list. */ def convertToParams(tree: Tree): List[ValDef] = tree match { case Parens(ts) => ts map convertToParam @@ -886,7 +898,7 @@ self => * }}} */ def compoundType(): Tree = compoundTypeRest( - if (in.token == LBRACE) atPos(o2p(in.offset))(scalaAnyRefConstr) + if (in.token == LBRACE) atInPos(scalaAnyRefConstr) else annotType() ) @@ -947,12 +959,11 @@ self => } /** Assumed (provisionally) to be TermNames. */ - def ident(skipIt: Boolean): Name = + def ident(skipIt: Boolean): Name = ( if (isIdent) rawIdent().encode - else { - syntaxErrorOrIncomplete(expectedMsg(IDENTIFIER), skipIt) - nme.ERROR - } + else syntaxErrorOrIncompleteAnd(expectedMsg(IDENTIFIER), skipIt)(nme.ERROR) + ) + def ident(): Name = ident(skipIt = true) def rawIdent(): Name = try in.name finally in.nextToken() @@ -1078,28 +1089,22 @@ self => * @note The returned tree does not yet have a position */ def literal(isNegated: Boolean = false, inPattern: Boolean = false): Tree = { - def finish(value: Any): Tree = { - val t = Literal(Constant(value)) - in.nextToken() - t - } + def finish(value: Any): Tree = try newLiteral(value) finally in.nextToken() if (in.token == SYMBOLLIT) Apply(scalaDot(nme.Symbol), List(finish(in.strVal))) else if (in.token == INTERPOLATIONID) interpolatedString(inPattern = inPattern) else finish(in.token match { - case CHARLIT => in.charVal - case INTLIT => in.intVal(isNegated).toInt - case LONGLIT => in.intVal(isNegated) - case FLOATLIT => in.floatVal(isNegated).toFloat - case DOUBLELIT => in.floatVal(isNegated) + case CHARLIT => in.charVal + case INTLIT => in.intVal(isNegated).toInt + case LONGLIT => in.intVal(isNegated) + case FLOATLIT => in.floatVal(isNegated).toFloat + case DOUBLELIT => in.floatVal(isNegated) case STRINGLIT | STRINGPART => in.strVal.intern() - case TRUE => true - case FALSE => false - case NULL => null - case _ => - syntaxErrorOrIncomplete("illegal literal", skipIt = true) - null + case TRUE => true + case FALSE => false + case NULL => null + case _ => syntaxErrorOrIncompleteAnd("illegal literal", skipIt = true)(null) }) } @@ -1112,18 +1117,15 @@ self => in.nextToken() while (in.token == STRINGPART) { partsBuf += literal() - exprBuf += { + exprBuf += ( if (inPattern) dropAnyBraces(pattern()) - else { - if (in.token == IDENTIFIER) atPos(in.offset)(Ident(ident())) - else if(in.token == LBRACE) expr() - else if(in.token == THIS) { in.nextToken(); atPos(in.offset)(This(tpnme.EMPTY)) } - else { - syntaxErrorOrIncomplete("error in interpolated string: identifier or block expected", skipIt = true) - EmptyTree - } + else in.token match { + case IDENTIFIER => atPos(in.offset)(Ident(ident())) + case LBRACE => expr() + case THIS => in.nextToken(); atPos(in.offset)(This(tpnme.EMPTY)) + case _ => syntaxErrorOrIncompleteAnd("error in interpolated string: identifier or block expected", skipIt = true)(EmptyTree) } - } + ) } if (in.token == STRINGLIT) partsBuf += literal() @@ -1195,7 +1197,7 @@ self => r } else { accept(LPAREN) - Literal(Constant(true)) + newLiteral(true) } } @@ -1249,7 +1251,7 @@ self => newLinesOpt() val thenp = expr() val elsep = if (in.token == ELSE) { in.nextToken(); expr() } - else Literal(Constant(())) + else literalUnit If(cond, thenp, elsep) } parseIf @@ -1323,7 +1325,7 @@ self => case RETURN => def parseReturn = atPos(in.skipToken()) { - Return(if (isExprIntro) expr() else Literal(Constant(()))) + Return(if (isExprIntro) expr() else literalUnit) } parseReturn case THROW => @@ -1511,8 +1513,7 @@ self => val cpos = r2p(tstart, tstart, in.lastOffset max tstart) makeNew(parents, self, stats, npos, cpos) case _ => - syntaxErrorOrIncomplete("illegal start of simple expression", skipIt = true) - errorTermTree + syntaxErrorOrIncompleteAnd("illegal start of simple expression", skipIt = true)(errorTermTree) } simpleExprRest(t, canApply = canApply) } @@ -1832,8 +1833,7 @@ self => } else { badStart } - syntaxErrorOrIncomplete(msg, skip) - errorPatternTree + syntaxErrorOrIncompleteAnd(msg, skip)(errorPatternTree) } /** {{{ @@ -1849,14 +1849,10 @@ self => * * XXX: Hook for IDE */ - def simplePattern(): Tree = { + def simplePattern(): Tree = ( // simple diagnostics for this entry point - def badStart(): Tree = { - syntaxErrorOrIncomplete("illegal start of simple pattern", skipIt = true) - errorPatternTree - } - simplePattern(badStart) - } + simplePattern(() => syntaxErrorOrIncompleteAnd("illegal start of simple pattern", skipIt = true)(errorPatternTree)) + ) def simplePattern(onError: () => Tree): Tree = { val start = in.offset in.token match { @@ -2526,7 +2522,7 @@ self => */ def constrExpr(vparamss: List[List[ValDef]]): Tree = if (in.token == LBRACE) constrBlock(vparamss) - else Block(List(selfInvocation(vparamss)), Literal(Constant(()))) + else Block(selfInvocation(vparamss) :: Nil, literalUnit) /** {{{ * SelfInvocation ::= this ArgumentExprs {ArgumentExprs} @@ -2556,7 +2552,7 @@ self => else Nil } accept(RBRACE) - Block(stats, Literal(Constant(()))) + Block(stats, literalUnit) } /** {{{ @@ -2579,8 +2575,7 @@ self => case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE => TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds()) case _ => - syntaxErrorOrIncomplete("`=', `>:', or `<:' expected", skipIt = true) - EmptyTree + syntaxErrorOrIncompleteAnd("`=', `>:', or `<:' expected", skipIt = true)(EmptyTree) } } } @@ -2613,8 +2608,7 @@ self => case CASEOBJECT => objectDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on 'case' to 'object', thus take prev*/))) case _ => - syntaxErrorOrIncomplete("expected start of definition", skipIt = true) - EmptyTree + syntaxErrorOrIncompleteAnd("expected start of definition", skipIt = true)(EmptyTree) } } @@ -2676,6 +2670,40 @@ self => } } + /** Create a tree representing a package object, converting + * {{{ + * package object foo { ... } + * }}} + * to + * {{{ + * package foo { + * object `package` { ... } + * } + * }}} + */ + def packageObjectDef(start: Offset): PackageDef = { + val defn = objectDef(in.offset, NoMods) + val module = copyModuleDef(defn)(name = nme.PACKAGEkw) + val pid = atPos(o2p(defn.pos.startOrPoint))(Ident(defn.name)) + + makePackaging(start, pid, module :: Nil) + } + def packageOrPackageObject(start: Offset): Tree = ( + if (in.token == OBJECT) + joinComment(packageObjectDef(start) :: Nil).head + else { + in.flushDoc + makePackaging(start, pkgQualId(), inBracesOrNil(topStatSeq())) + } + ) + // TODO - eliminate this and use "def packageObjectDef" (see call site of this + // method for small elaboration.) + def makePackageObject(start: Int, objDef: ModuleDef): PackageDef = objDef match { + case ModuleDef(mods, name, impl) => + makePackaging( + start, atPos(o2p(objDef.pos.startOrPoint)){ Ident(name) }, List(ModuleDef(mods, nme.PACKAGEkw, impl))) + } + /** {{{ * ClassParents ::= AnnotType {`(' [Exprs] `)'} {with AnnotType} * TraitParents ::= AnnotType {with AnnotType} @@ -2755,14 +2783,14 @@ self => def anyrefParents() = { val caseParents = if (mods.isCase) List(productConstr, serializableConstr) else Nil parents0 ::: caseParents match { - case Nil => List(atPos(o2p(in.offset))(scalaAnyRefConstr)) + case Nil => atInPos(scalaAnyRefConstr) :: Nil case ps => ps } } def anyvalConstructor() = ( // Not a well-formed constructor, has to be finished later - see note // regarding AnyVal constructor in AddInterfaces. - DefDef(NoMods, nme.CONSTRUCTOR, Nil, ListOfNil, TypeTree(), Block(Nil, Literal(Constant(())))) + DefDef(NoMods, nme.CONSTRUCTOR, Nil, ListOfNil, TypeTree(), Block(Nil, literalUnit)) ) val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart @@ -2811,42 +2839,10 @@ self => def makePackaging(start: Int, pkg: Tree, stats: List[Tree]): PackageDef = pkg match { case x: RefTree => atPos(start, pkg.pos.point)(PackageDef(x, stats)) } -/* - pkg match { - case id @ Ident(_) => - PackageDef(id, stats) - case Select(qual, name) => // drop this to flatten packages - makePackaging(start, qual, List(PackageDef(Ident(name), stats))) - } - } -*/ - /** Create a tree representing a package object, converting - * {{{ - * package object foo { ... } - * }}} - * to - * {{{ - * package foo { - * object `package` { ... } - * } - * }}} - */ - def makePackageObject(start: Int, objDef: ModuleDef): PackageDef = objDef match { - case ModuleDef(mods, name, impl) => - makePackaging( - start, atPos(o2p(objDef.pos.startOrPoint)){ Ident(name) }, List(ModuleDef(mods, nme.PACKAGEkw, impl))) - } - - /** {{{ - * Packaging ::= package QualId [nl] `{' TopStatSeq `}' - * }}} - */ - def packaging(start: Int): Tree = { - val pkg = pkgQualId() - val stats = inBracesOrNil(topStatSeq()) - makePackaging(start, pkg, stats) - } + def makeEmptyPackage(start: Int, stats: List[Tree]): PackageDef = ( + makePackaging(start, atPos(start, start, start)(Ident(nme.EMPTY_PACKAGE_NAME)), stats) + ) /** {{{ * TopStatSeq ::= TopStat {semi TopStat} @@ -2862,22 +2858,15 @@ self => while (!isStatSeqEnd) { stats ++= (in.token match { case PACKAGE => - val start = in.skipToken() - if (in.token == OBJECT) - joinComment(List(makePackageObject(start, objectDef(in.offset, NoMods)))) - else { - in.flushDoc - List(packaging(start)) - } + packageOrPackageObject(in.skipToken()) :: Nil case IMPORT => in.flushDoc importClause() case x if x == AT || isTemplateIntro || isModifier => - joinComment(List(topLevelTmplDef)) + joinComment(topLevelTmplDef :: Nil) case _ => - if (!isStatSep) - syntaxErrorOrIncomplete("expected class or object definition", skipIt = true) - Nil + if (isStatSep) Nil + else syntaxErrorOrIncompleteAnd("expected class or object definition", skipIt = true)(Nil) }) acceptStatSepOpt() } @@ -2988,7 +2977,7 @@ self => else List(tmplDef(pos, mods)) in.token match { - case RBRACE | CASE => defs :+ (Literal(Constant(())) setPos o2p(in.offset)) + case RBRACE | CASE => defs :+ setInPos(literalUnit) case _ => defs } } @@ -3038,7 +3027,7 @@ self => * CompilationUnit ::= {package QualId semi} TopStatSeq * }}} */ - def compilationUnit(): Tree = checkNoEscapingPlaceholders { + def compilationUnit(): PackageDef = checkNoEscapingPlaceholders { def topstats(): List[Tree] = { val ts = new ListBuffer[Tree] while (in.token == SEMI) in.nextToken() @@ -3046,6 +3035,9 @@ self => if (in.token == PACKAGE) { in.nextToken() if (in.token == OBJECT) { + // TODO - this next line is supposed to be + // ts += packageObjectDef(start) + // but this broke a scaladoc test (run/diagrams-filtering.scala) somehow. ts ++= joinComment(List(makePackageObject(start, objectDef(in.offset, NoMods)))) if (in.token != EOF) { acceptStatSep() @@ -3074,8 +3066,8 @@ self => resetPackage() topstats() match { - case List(stat @ PackageDef(_, _)) => stat - case stats => + case (stat @ PackageDef(_, _)) :: Nil => stat + case stats => val start = if (stats forall (_ == EmptyTree)) 0 else { @@ -3084,7 +3076,7 @@ self => else 0 } - makePackaging(start, atPos(start, start, start) { Ident(nme.EMPTY_PACKAGE_NAME) }, stats) + makeEmptyPackage(start, stats) } } } -- cgit v1.2.3