From c676ec25a321f9fd23de83bf02ed8d6c15ba7e62 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Thu, 19 Sep 2013 14:52:54 +0200 Subject: refactor out common logic between various statSeq-s in parser Partial functions are left outside of the call to statSeq to allow re-use and overriding capabilities for quasiquotes. --- .../scala/tools/nsc/ast/parser/Parsers.scala | 66 ++++++++++------------ 1 file changed, 31 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 34f3fcce9f..efc630f27a 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2902,6 +2902,18 @@ self => makePackaging(start, atPos(start, start, start)(Ident(nme.EMPTY_PACKAGE_NAME)), stats) ) + def statSeq(stat: PartialFunction[Int, List[Tree]], errorMsg: String = "illegal start of definition"): List[Tree] = { + val stats = new ListBuffer[Tree] + def default(tok: Int) = + if (isStatSep) Nil + else syntaxErrorOrIncompleteAnd(errorMsg, skipIt = true)(Nil) + while (!isStatSeqEnd) { + stats ++= stat.applyOrElse(in.token, default) + acceptStatSepOpt() + } + stats.toList + } + /** {{{ * TopStatSeq ::= TopStat {semi TopStat} * TopStat ::= Annotations Modifiers TmplDef @@ -2911,24 +2923,15 @@ self => * | * }}} */ - def topStatSeq(): List[Tree] = { - val stats = new ListBuffer[Tree] - while (!isStatSeqEnd) { - stats ++= (in.token match { - case PACKAGE => - packageOrPackageObject(in.skipToken()) :: Nil - case IMPORT => - in.flushDoc - importClause() - case x if isAnnotation || isTemplateIntro || isModifier => - joinComment(topLevelTmplDef :: Nil) - case _ => - if (isStatSep) Nil - else syntaxErrorOrIncompleteAnd("expected class or object definition", skipIt = true)(Nil) - }) - acceptStatSepOpt() - } - stats.toList + def topStatSeq(): List[Tree] = statSeq(topStat, errorMsg = "expected class or object definition") + def topStat: PartialFunction[Int, List[Tree]] = { + case PACKAGE => + packageOrPackageObject(in.skipToken()) :: Nil + case IMPORT => + in.flushDoc + importClause() + case _ if isAnnotation || isTemplateIntro || isModifier => + joinComment(topLevelTmplDef :: Nil) } /** {{{ @@ -2972,23 +2975,16 @@ self => * | * }}} */ - def templateStats(): List[Tree] = { - val stats = new ListBuffer[Tree] - while (!isStatSeqEnd) { - if (in.token == IMPORT) { - in.flushDoc - stats ++= importClause() - } else if (isDefIntro || isModifier || isAnnotation) { - stats ++= joinComment(nonLocalDefOrDcl) - } else if (isExprIntro) { - in.flushDoc - stats += statement(InTemplate) - } else if (!isStatSep) { - syntaxErrorOrIncomplete("illegal start of definition", skipIt = true) - } - acceptStatSepOpt() - } - stats.toList + def templateStats(): List[Tree] = statSeq(templateStat) + def templateStat: PartialFunction[Int, List[Tree]] = { + case IMPORT => + in.flushDoc + importClause() + case _ if isDefIntro || isModifier || isAnnotation => + joinComment(nonLocalDefOrDcl) + case _ if isExprIntro => + in.flushDoc + statement(InTemplate) :: Nil } /** {{{ -- cgit v1.2.3 From d7aae49f8ff7ccc6c1a588fc116e8c37fdb9e849 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 20 Sep 2013 13:28:42 +0200 Subject: refactor out range position utility constructors This will help to re-use same logic for creating range positions even if atPos isn't used to assign position to the tree. --- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index efc630f27a..b1fcb67a9f 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -302,6 +302,8 @@ self => def freshTypeName(prefix: String): TypeName def o2p(offset: Int): Position def r2p(start: Int, mid: Int, end: Int): Position + def r2p(start: Int, mid: Int): Position = r2p(start, mid, in.lastOffset max start) + def r2p(offset: Int): Position = r2p(offset, offset) /** whether a non-continuable syntax error has been seen */ private var lastErrorOffset : Int = -1 @@ -699,8 +701,8 @@ self => /* ---------- TREE CONSTRUCTION ------------------------------------------- */ - def atPos[T <: Tree](offset: Int)(t: T): T = atPos(r2p(offset, offset, in.lastOffset max offset))(t) - def atPos[T <: Tree](start: Int, point: Int)(t: T): T = atPos(r2p(start, point, in.lastOffset max start))(t) + def atPos[T <: Tree](offset: Int)(t: T): T = atPos(r2p(offset))(t) + def atPos[T <: Tree](start: Int, point: Int)(t: T): T = atPos(r2p(start, point))(t) def atPos[T <: Tree](start: Int, point: Int, end: Int)(t: T): T = atPos(r2p(start, point, end))(t) def atPos[T <: Tree](pos: Position)(t: T): T = global.atPos(pos)(t) -- cgit v1.2.3 From 3a148cd0cd404751095cd1c5aca09ad8923c51ab Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 20 Sep 2013 13:32:38 +0200 Subject: SI-6841 SI-6657 add support for packages into quasiquotes and toolbox In order to implement this a new parser entry point `parseStatsOrPackages` that augments current parseStats with ability to parse "package name { ... }" syntax. --- .../scala/reflect/macros/contexts/Parsers.scala | 2 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 12 +++--- .../scala/tools/reflect/ToolBoxFactory.scala | 2 +- .../scala/tools/reflect/quasiquotes/Parsers.scala | 9 +++- .../tools/reflect/quasiquotes/Placeholders.scala | 7 +++ .../scala/tools/reflect/quasiquotes/Reifiers.scala | 19 +++++--- src/reflect/scala/reflect/api/BuildUtils.scala | 16 ++++++- .../scala/reflect/internal/BuildUtils.scala | 29 ++++++++++++- src/reflect/scala/reflect/internal/StdNames.scala | 17 +++++--- src/reflect/scala/reflect/internal/TreeGen.scala | 6 +++ .../neg/quasiquotes-syntax-error-position.check | 4 +- test/files/run/toolbox_parse_package.check | 8 ++++ test/files/run/toolbox_parse_package.scala | 9 ++++ .../quasiquotes/DefinitionConstructionProps.scala | 50 ++++++++++++++++++++++ .../DefinitionDeconstructionProps.scala | 24 +++++++++++ 15 files changed, 187 insertions(+), 27 deletions(-) create mode 100644 test/files/run/toolbox_parse_package.check create mode 100644 test/files/run/toolbox_parse_package.scala (limited to 'src') diff --git a/src/compiler/scala/reflect/macros/contexts/Parsers.scala b/src/compiler/scala/reflect/macros/contexts/Parsers.scala index ae6488b5a8..88cfea8157 100644 --- a/src/compiler/scala/reflect/macros/contexts/Parsers.scala +++ b/src/compiler/scala/reflect/macros/contexts/Parsers.scala @@ -11,7 +11,7 @@ trait Parsers { val sreporter = new StoreReporter() val unit = new CompilationUnit(newSourceFile(code, "")) { override def reporter = sreporter } val parser = newUnitParser(unit) - val tree = gen.mkTreeOrBlock(parser.parseStats()) + val tree = gen.mkTreeOrBlock(parser.parseStatsOrPackages()) sreporter.infos.foreach { case sreporter.Info(pos, msg, sreporter.ERROR) => throw ParseException(pos, msg) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index b1fcb67a9f..508453d5b2 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -346,9 +346,10 @@ self => */ def parse(): Tree = parseRule(_.parseStartRule()) - /** This is alternative entry point for repl, script runner, toolbox and quasiquotes. + /** These are alternative entry points for repl, script runner, toolbox and parsing in macros. */ def parseStats(): List[Tree] = parseRule(_.templateStats()) + def parseStatsOrPackages(): List[Tree] = parseRule(_.templateOrTopStatSeq()) /** This is the parse entry point for code which is not self-contained, e.g. * a script which is a series of template statements. They will be @@ -2743,10 +2744,9 @@ self => */ def packageObjectDef(start: Offset): PackageDef = { val defn = objectDef(in.offset, NoMods) - val module = copyModuleDef(defn)(name = nme.PACKAGEkw) - val pid = atPos(o2p(defn.pos.start))(Ident(defn.name)) - - makePackaging(start, pid, module :: Nil) + val pidPos = o2p(defn.pos.startOrPoint) + val pkgPos = r2p(start, pidPos.point) + gen.mkPackageObject(defn, pidPos, pkgPos) } def packageOrPackageObject(start: Offset): Tree = ( if (in.token == OBJECT) @@ -2989,6 +2989,8 @@ self => statement(InTemplate) :: Nil } + def templateOrTopStatSeq(): List[Tree] = statSeq(templateStat.orElse(topStat)) + /** {{{ * RefineStatSeq ::= RefineStat {semi RefineStat} * RefineStat ::= Dcl diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index fdc2613810..9e5a97270d 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -280,7 +280,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => def parse(code: String): Tree = { reporter.reset() - val tree = gen.mkTreeOrBlock(newUnitParser(code, "").parseStats()) + val tree = gen.mkTreeOrBlock(newUnitParser(code, "").parseStatsOrPackages()) throwIfErrors() tree } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 5a1a25cfa1..7abf8b9964 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -140,11 +140,18 @@ trait Parsers { self: Quasiquotes => case Ident(name) if isHole(name) => true case _ => false }) + + override def topStat = super.topStat.orElse { + case _ if isHole => + val stats = ValDef(NoMods, in.name, Ident(tpnme.QUASIQUOTE_PACKAGE_STAT), EmptyTree) :: Nil + in.nextToken() + stats + } } } object TermParser extends Parser { - def entryPoint = { parser => gen.mkTreeOrBlock(parser.templateStats()) } + def entryPoint = { parser => gen.mkTreeOrBlock(parser.templateOrTopStatSeq()) } } object TypeParser extends Parser { diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala index c2b219ee31..d74350cad8 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala @@ -146,4 +146,11 @@ trait Placeholders { self: Quasiquotes => case _ => None } } + + object PackageStatPlaceholder { + def unapply(tree: Tree): Option[(Tree, Location, Cardinality)] = tree match { + case ValDef(NoMods, Placeholder(tree, location, card), Ident(tpnme.QUASIQUOTE_PACKAGE_STAT), EmptyTree) => Some((tree, location, card)) + case _ => None + } + } } \ No newline at end of file diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 18999e8267..6f5bf88549 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -7,10 +7,8 @@ import scala.reflect.internal.Flags._ trait Reifiers { self: Quasiquotes => import global._ - import global.build.{SyntacticClassDef, SyntacticTraitDef, SyntacticModuleDef, - SyntacticDefDef, SyntacticValDef, SyntacticVarDef, - SyntacticBlock, SyntacticApplied, SyntacticTypeApplied, - SyntacticFunction, SyntacticNew, SyntacticAssign} + import global.build.{Select => _, Ident => _, _} + import global.treeInfo._ import global.definitions._ import Cardinality._ import universeTypes._ @@ -51,6 +49,7 @@ trait Reifiers { self: Quasiquotes => case CasePlaceholder(tree, location, _) => reifyCase(tree, location) case RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree) case EarlyDefPlaceholder(tree, _, _) => reifyEarlyDef(tree) + case PackageStatPlaceholder(tree, _, _) => reifyPackageStat(tree) case _ => EmptyTree } @@ -60,8 +59,10 @@ trait Reifiers { self: Quasiquotes => case SyntacticClassDef(mods, name, tparams, constrmods, vparamss, earlyDefs, parents, selfdef, body) => reifyBuildCall(nme.SyntacticClassDef, mods, name, tparams, constrmods, vparamss, earlyDefs, parents, selfdef, body) - case SyntacticModuleDef(mods, name, earlyDefs, parents, selfdef, body) => - reifyBuildCall(nme.SyntacticModuleDef, mods, name, earlyDefs, parents, selfdef, body) + case SyntacticPackageObjectDef(name, earlyDefs, parents, selfdef, body) => + reifyBuildCall(nme.SyntacticPackageObjectDef, name, earlyDefs, parents, selfdef, body) + case SyntacticObjectDef(mods, name, earlyDefs, parents, selfdef, body) => + reifyBuildCall(nme.SyntacticObjectDef, mods, name, earlyDefs, parents, selfdef, body) case SyntacticNew(earlyDefs, parents, selfdef, body) => reifyBuildCall(nme.SyntacticNew, earlyDefs, parents, selfdef, body) case SyntacticDefDef(mods, name, tparams, vparamss, tpt, rhs) => @@ -131,6 +132,8 @@ trait Reifiers { self: Quasiquotes => def reifyAnnotation(tree: Tree) = tree + def reifyPackageStat(tree: Tree) = tree + /** Splits list into a list of groups where subsequent elements are considered * similar by the corresponding function. * @@ -185,6 +188,8 @@ trait Reifiers { self: Quasiquotes => case CasePlaceholder(tree, _, DotDot) => tree case RefineStatPlaceholder(tree, _, DotDot) => reifyRefineStat(tree) case EarlyDefPlaceholder(tree, _, DotDot) => reifyEarlyDef(tree) + case PackageStatPlaceholder(tree, _, DotDot) => reifyPackageStat(tree) + case List(Placeholder(tree, _, DotDotDot)) => tree } { reify(_) @@ -280,6 +285,8 @@ trait Reifiers { self: Quasiquotes => override def reifyEarlyDef(tree: Tree) = mirrorBuildCall(nme.mkEarlyDef, tree) override def reifyAnnotation(tree: Tree) = mirrorBuildCall(nme.mkAnnotation, tree) + + override def reifyPackageStat(tree: Tree) = mirrorBuildCall(nme.mkPackageStat, tree) } class UnapplyReifier extends Reifier { diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 551c27bf9c..df126bed45 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -80,6 +80,10 @@ private[reflect] trait BuildUtils { self: Universe => def mkRefineStat(stats: List[Tree]): List[Tree] + def mkPackageStat(stat: Tree): Tree + + def mkPackageStat(stats: List[Tree]): List[Tree] + def mkEarlyDef(defn: Tree): Tree def mkEarlyDef(defns: List[Tree]): List[Tree] @@ -133,14 +137,22 @@ private[reflect] trait BuildUtils { self: Universe => List[Tree], List[Tree], ValDef, List[Tree])] } - val SyntacticModuleDef: SyntacticModuleDefExtractor + val SyntacticObjectDef: SyntacticObjectDefExtractor - trait SyntacticModuleDefExtractor { + trait SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] } + val SyntacticPackageObjectDef: SyntacticPackageObjectDefExtractor + + trait SyntacticPackageObjectDefExtractor { + def apply(name: TermName, earlyDefs: List[Tree], + parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree + def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] + } + val SyntacticTuple: SyntacticTupleExtractor val SyntacticTupleType: SyntacticTupleExtractor diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 951efd90ed..a09715ec7c 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -98,6 +98,18 @@ trait BuildUtils { self: SymbolTable => def mkRefineStat(stats: List[Tree]): List[Tree] = stats.map(mkRefineStat) + def mkPackageStat(stat: Tree): Tree = { + stat match { + case cd: ClassDef => + case md: ModuleDef => + case pd: PackageDef => + case _ => throw new IllegalArgumentException(s"not legal package stat: $stat") + } + stat + } + + def mkPackageStat(stats: List[Tree]): List[Tree] = stats.map(mkPackageStat) + object ScalaDot extends ScalaDotExtractor { def apply(name: Name): Tree = gen.scalaDot(name) def unapply(tree: Tree): Option[Name] = tree match { @@ -110,7 +122,7 @@ trait BuildUtils { self: SymbolTable => case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred => copyValDef(vdef)(mods = mods | PRESUPER) case tdef @ TypeDef(mods, _, _, _) => - copyTypeDef(tdef)(mods = mods | PRESUPER) + copyTypeDef(tdef)(mods = mods | PRESUPER) case _ => throw new IllegalArgumentException(s"not legal early def: $defn") } @@ -244,7 +256,7 @@ trait BuildUtils { self: SymbolTable => } } - object SyntacticModuleDef extends SyntacticModuleDefExtractor { + object SyntacticObjectDef extends SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], parents: List[Tree], selfdef: ValDef, body: List[Tree]) = ModuleDef(mods, name, gen.mkTemplate(parents, selfdef, NoMods, Nil, earlyDefs ::: body)) @@ -257,6 +269,19 @@ trait BuildUtils { self: SymbolTable => } } + object SyntacticPackageObjectDef extends SyntacticPackageObjectDefExtractor { + def apply(name: TermName, earlyDefs: List[Tree], + parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree = + gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfdef, body)) + + def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { + case PackageDef(Ident(name: TermName), List(SyntacticObjectDef(NoMods, nme.PACKAGEkw, earlyDefs, parents, selfdef, body))) => + Some((name, earlyDefs, parents, selfdef, body)) + case _ => + None + } + } + private trait ScalaMemberRef { val symbols: Seq[Symbol] def result(name: Name): Option[Symbol] = diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index af26253802..7cfe194fd1 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -247,11 +247,12 @@ trait StdNames { final val Quasiquote: NameType = "Quasiquote" // quasiquote-specific names - final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$" - final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" - final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$" - final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$" - final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$" + final val QUASIQUOTE_MODS: NameType = "$quasiquote$mods$" + final val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" + final val QUASIQUOTE_FUNCTION: NameType = "$quasiquote$function$" + final val QUASIQUOTE_REFINE_STAT: NameType = "$quasiquote$refine$stat$" + final val QUASIQUOTE_EARLY_DEF: NameType = "$quasiquote$early$def$" + final val QUASIQUOTE_PACKAGE_STAT: NameType = "$quasiquote$package$stat$" // Annotation simple names, used in Namer final val BeanPropertyAnnot: NameType = "BeanProperty" @@ -587,8 +588,9 @@ trait StdNames { val SyntacticClassDef: NameType = "SyntacticClassDef" val SyntacticDefDef: NameType = "SyntacticDefDef" val SyntacticFunction: NameType = "SyntacticFunction" - val SyntacticFunctionType: NameType= "SyntacticFunctionType" - val SyntacticModuleDef: NameType = "SyntacticModuleDef" + val SyntacticFunctionType: NameType = "SyntacticFunctionType" + val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef" + val SyntacticObjectDef: NameType = "SyntacticObjectDef" val SyntacticNew: NameType = "SyntacticNew" val SyntacticTraitDef: NameType = "SyntacticTraitDef" val SyntacticTuple: NameType = "SyntacticTuple" @@ -683,6 +685,7 @@ trait StdNames { val mkAnnotation: NameType = "mkAnnotation" val mkRefineStat: NameType = "mkRefineStat" val mkEarlyDef: NameType = "mkEarlyDef" + val mkPackageStat: NameType = "mkPackageStat" val ne: NameType = "ne" val newArray: NameType = "newArray" val newFreeTerm: NameType = "newFreeTerm" diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index 720d8bfe4a..cf7c729a6a 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -448,4 +448,10 @@ abstract class TreeGen extends macros.TreeBuilder { case _ => Assign(lhs, rhs) } + + def mkPackageObject(defn: ModuleDef, pidPos: Position = NoPosition, pkgPos: Position = NoPosition) = { + val module = copyModuleDef(defn)(name = nme.PACKAGEkw) + val pid = atPos(pidPos)(Ident(defn.name)) + atPos(pkgPos)(PackageDef(pid, module :: Nil)) + } } diff --git a/test/files/neg/quasiquotes-syntax-error-position.check b/test/files/neg/quasiquotes-syntax-error-position.check index 3bd813b1bb..25e5b8d75a 100644 --- a/test/files/neg/quasiquotes-syntax-error-position.check +++ b/test/files/neg/quasiquotes-syntax-error-position.check @@ -10,9 +10,9 @@ quasiquotes-syntax-error-position.scala:7: error: '}' expected but end of quote quasiquotes-syntax-error-position.scala:8: error: '.' expected but splicee found. q"import $t $t" ^ -quasiquotes-syntax-error-position.scala:9: error: illegal start of definition +quasiquotes-syntax-error-position.scala:9: error: '{' expected but end of quote found. q"package p" - ^ + ^ quasiquotes-syntax-error-position.scala:10: error: ';' expected but '@' found. q"foo@$a" ^ diff --git a/test/files/run/toolbox_parse_package.check b/test/files/run/toolbox_parse_package.check new file mode 100644 index 0000000000..46465980a0 --- /dev/null +++ b/test/files/run/toolbox_parse_package.check @@ -0,0 +1,8 @@ +package foo { + object bar extends scala.AnyRef { + def () = { + super.(); + () + } + } +} diff --git a/test/files/run/toolbox_parse_package.scala b/test/files/run/toolbox_parse_package.scala new file mode 100644 index 0000000000..62412a50d7 --- /dev/null +++ b/test/files/run/toolbox_parse_package.scala @@ -0,0 +1,9 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{universe => ru} +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.ToolBox + +object Test extends App { + val toolbox = cm.mkToolBox() + println(toolbox.parse("package foo { object bar }")) +} \ No newline at end of file diff --git a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala index ced479aef5..e8ddb4b72a 100644 --- a/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/DefinitionConstructionProps.scala @@ -13,6 +13,7 @@ object DefinitionConstructionProps with TraitConstruction with TypeDefConstruction with ValDefConstruction + with PackageConstruction trait ClassConstruction { self: QuasiquoteProperties => val anyRef = ScalaDot(TypeName("AnyRef")) @@ -292,4 +293,53 @@ trait MethodConstruction { self: QuasiquoteProperties => val a = q"new Foo(a)(b)" assertEqAst(q"@$a def foo", "@Foo(a)(b) def foo") } +} + +trait PackageConstruction { self: QuasiquoteProperties => + property("splice select into package name") = test { + val name = q"foo.bar" + assertEqAst(q"package $name { }", "package foo.bar { }") + } + + property("splce name into package name") = test{ + val name = TermName("bippy") + assertEqAst(q"package $name { }", "package bippy { }") + } + + property("splice members into package body") = test { + val members = q"class C" :: q"object O" :: Nil + assertEqAst(q"package foo { ..$members }", "package foo { class C; object O }") + } + + property("splice illegal members into package body") = test { + val f = q"def f" + assertThrows[IllegalArgumentException] { q"package foo { $f }" } + val v = q"val v = 0" + assertThrows[IllegalArgumentException] { q"package foo { $v }" } + val expr = q"x + 1" + assertThrows[IllegalArgumentException] { q"package foo { $expr }" } + } + + property("splice name into package object") = test { + val foo = TermName("foo") + assertEqAst(q"package object $foo", "package object foo") + } + + property("splice parents into package object") = test { + val parents = tq"a" :: tq"b" :: Nil + assertEqAst(q"package object foo extends ..$parents", + "package object foo extends a with b") + } + + property("splice members into package object") = test { + val members = q"def foo" :: q"val x = 1" :: Nil + assertEqAst(q"package object foo { ..$members }", + "package object foo { def foo; val x = 1 }") + } + + property("splice early def into package object") = test { + val edefs = q"val x = 1" :: q"type I = Int" :: Nil + assertEqAst(q"package object foo extends { ..$edefs } with Any", + "package object foo extends { val x = 1; type I = Int } with Any") + } } \ No newline at end of file diff --git a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala index fdfbfe871c..993ef899b0 100644 --- a/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/DefinitionDeconstructionProps.scala @@ -13,6 +13,7 @@ object DefinitionDeconstructionProps with ObjectDeconstruction with ModsDeconstruction with ValVarDeconstruction + with PackageDeconstruction trait TraitDeconstruction { self: QuasiquoteProperties => property("exhaustive trait matcher") = test { @@ -144,4 +145,27 @@ trait ValVarDeconstruction { self: QuasiquoteProperties => matches("var x = 1") assertThrows[MatchError] { matches("val x = 1") } } +} + +trait PackageDeconstruction { self: QuasiquoteProperties => + property("exhaustive package matcher") = test { + def matches(line: String) { val q"package $name { ..$body }" = parse(line) } + matches("package foo { }") + matches("package foo { class C }") + matches("package foo.bar { }") + matches("package bippy.bongo { object A; object B }") + matches("package bippy { package bongo { object O } }") + } + + property("exhaustive package object matcher") = test { + def matches(line: String) { + val q"package object $name extends { ..$early } with ..$parents { $self => ..$body }" = parse(line) + } + matches("package object foo") + matches("package object foo { def baz }") + matches("package object foo { self => }") + matches("package object foo extends mammy with daddy { def baz }") + matches("package object foo extends { val early = 1 } with daddy") + assertThrows[MatchError] { matches("object foo") } + } } \ No newline at end of file -- cgit v1.2.3 From 60603f2524bf7c06c6f73eefb1cc30b6df7c392d Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Tue, 24 Sep 2013 17:09:50 +0200 Subject: minor changes due to typos --- src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala | 4 ++-- test/files/scalacheck/quasiquotes/ArbitraryTreesAndNames.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 6f5bf88549..d205ebece7 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -206,13 +206,13 @@ trait Reifiers { self: Quasiquotes => // to overload the same tree for two different concepts: // - MUTABLE that is used to override ValDef for vars // - TRAIT that is used to override ClassDef for traits - val nonoverloadedExplicitFlags = ExplicitFlags & ~MUTABLE & ~TRAIT + val nonOverloadedExplicitFlags = ExplicitFlags & ~MUTABLE & ~TRAIT def ensureNoExplicitFlags(m: Modifiers, pos: Position) = { // Traits automatically have ABSTRACT flag assigned to // them so in that case it's not an explicit flag val flags = if (m.isTrait) m.flags & ~ABSTRACT else m.flags - if ((flags & nonoverloadedExplicitFlags) != 0L) + if ((flags & nonOverloadedExplicitFlags) != 0L) c.abort(pos, s"Can't $action modifiers together with flags, consider merging flags into modifiers") } diff --git a/test/files/scalacheck/quasiquotes/ArbitraryTreesAndNames.scala b/test/files/scalacheck/quasiquotes/ArbitraryTreesAndNames.scala index 23b6a5fbdb..4118d92076 100644 --- a/test/files/scalacheck/quasiquotes/ArbitraryTreesAndNames.scala +++ b/test/files/scalacheck/quasiquotes/ArbitraryTreesAndNames.scala @@ -257,7 +257,7 @@ trait ArbitraryTreesAndNames { /* These are marker types that allow to write tests that * depend specificly on Trees that are terms or types. - * They are transperantly tranformed to trees through + * They are transparently tranformed to trees through * implicit conversions and liftables for quasiquotes. */ -- cgit v1.2.3 From debdd2f316934c417c7d9865ea0f2ea503e51b63 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Thu, 26 Sep 2013 18:41:02 +0200 Subject: use regular macro expansion logic for unapply quasiquotes Previously due to limited support for expansion in apply position quasiquotes had to use a compiler hook for deconstruction. Now with recent changes in pattern matcher it's possible to remove that special case. --- .../scala/tools/nsc/typechecker/Typers.scala | 3 +- .../scala/tools/reflect/quasiquotes/Holes.scala | 2 +- .../tools/reflect/quasiquotes/Placeholders.scala | 14 ++++++-- .../tools/reflect/quasiquotes/Quasiquotes.scala | 6 ++-- .../scala/tools/reflect/quasiquotes/Reifiers.scala | 40 ++++++++++++++++++++-- src/reflect/scala/reflect/api/Quasiquotes.scala | 2 +- test/files/scalacheck/quasiquotes/ErrorProps.scala | 5 +-- 7 files changed, 57 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 7bf342f475..3cd937313f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3274,8 +3274,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // SI-7877 `isTerm` needed to exclude `class T[A] { def unapply(..) }; ... case T[X] =>` case HasUnapply(unapply) if mode.inPatternMode && fun.isTerm => - if (unapply == QuasiquoteClass_api_unapply) macroExpandUnapply(this, tree, fun, unapply, args, mode, pt) - else doTypedUnapply(tree, fun0, fun, args, mode, pt) + doTypedUnapply(tree, fun0, fun, args, mode, pt) case _ => if (treeInfo.isMacroApplication(tree)) duplErrorTree(MacroTooManyArgumentListsError(tree, fun.symbol)) diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala index dd849f2bca..f92c9aa845 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Holes.scala @@ -154,7 +154,7 @@ trait Holes { self: Quasiquotes => object Hole { def apply(splicee: Tree, holeCard: Cardinality): Hole = { - if (splicee.tpe == null) return new Hole(splicee, UnknownLocation, holeCard) + if (method == nme.unapply) return new Hole(splicee, UnknownLocation, holeCard) val (spliceeCard, elementTpe) = parseCardinality(splicee.tpe) def cantSplice() = { val holeCardMsg = if (holeCard != NoDot) s" with $holeCard" else "" diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala index d74350cad8..c31d1fcd12 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala @@ -32,10 +32,17 @@ trait Placeholders { self: Quasiquotes => def appendHole(tree: Tree, cardinality: Cardinality) = { val placeholderName = c.freshName(TermName(nme.QUASIQUOTE_PREFIX + sessionSuffix)) sb.append(placeholderName) - holeMap(placeholderName) = Hole(tree, cardinality) + val holeTree = if (method == nme.unapply) Bind(placeholderName, Ident(nme.WILDCARD)) else tree + holeMap(placeholderName) = Hole(holeTree, cardinality) } - foreach2(args, parts.init) { case (tree, (p, pos)) => + val iargs = method match { + case nme.apply => args + case nme.unapply => List.fill(parts.length - 1)(EmptyTree) + case _ => global.abort("unreachable") + } + + foreach2(iargs, parts.init) { case (tree, (p, pos)) => val (part, cardinality) = parseDots(p) appendPart(part, pos) appendHole(tree, cardinality) @@ -47,7 +54,7 @@ trait Placeholders { self: Quasiquotes => } class HoleMap { - private val underlying = mutable.ListMap[String, Hole]() + private var underlying = immutable.SortedMap[String, Hole]() private val accessed = mutable.Set[String]() def unused: Set[Name] = (underlying.keys.toSet -- accessed).map(TermName(_)) def contains(key: Name) = underlying.contains(key.toString) @@ -64,6 +71,7 @@ trait Placeholders { self: Quasiquotes => accessed += s underlying.get(s) } + def toList = underlying.toList } // Step 2: Transform vanilla Scala AST into an AST with holes diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala index 1305e25240..fb0ad3bbb0 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala @@ -14,8 +14,9 @@ abstract class Quasiquotes extends Parsers def debug(msg: String): Unit = if (settings.Yquasiquotedebug.value) println(msg) - lazy val (universe: Tree, args, parts, parse, reify) = c.macroApplication match { + lazy val (universe: Tree, args, parts, parse, reify, method) = c.macroApplication match { case Apply(Select(Select(Apply(Select(universe0, _), List(Apply(_, parts0))), interpolator0), method0), args0) => + debug(s"\nparse prefix:\nuniverse=$universe0\nparts=$parts0\ninterpolator=$interpolator0\nmethod=$method0\nargs=$args0\n") val parts1 = parts0.map { case lit @ Literal(Constant(s: String)) => s -> lit.pos case part => c.abort(part.pos, "Quasiquotes can only be used with literal strings") @@ -32,7 +33,7 @@ abstract class Quasiquotes extends Parsers case nme.pq => PatternParser.parse(_) case other => global.abort(s"Unknown quasiquote flavor: $other") } - (universe0, args0, parts1, parse0, reify0) + (universe0, args0, parts1, parse0, reify0, method0) case _ => global.abort(s"Couldn't parse call prefix tree ${c.macroApplication}.") } @@ -41,6 +42,7 @@ abstract class Quasiquotes extends Parsers lazy val universeTypes = new definitions.UniverseDependentTypes(universe) def expandQuasiquote = { + debug(s"\nmacro application:\n${c.macroApplication}\n") debug(s"\ncode to parse:\n$code\n") val tree = parse(code) debug(s"parsed:\n${showRaw(tree)}\n$tree\n") diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index d205ebece7..9f1a3ce257 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -7,7 +7,7 @@ import scala.reflect.internal.Flags._ trait Reifiers { self: Quasiquotes => import global._ - import global.build.{Select => _, Ident => _, _} + import global.build.{Select => _, Ident => _, TypeTree => _, _} import global.treeInfo._ import global.definitions._ import Cardinality._ @@ -27,12 +27,48 @@ trait Reifiers { self: Quasiquotes => def action = if (isReifyingExpressions) "splice" else "extract" def holesHaveTypes = isReifyingExpressions + def wrap(tree: Tree) = + if (isReifyingExpressions) tree + else { + val freevars = holeMap.toList.map { case (name, _) => Ident(name) } + val isVarPattern = tree match { case Bind(name, Ident(nme.WILDCARD)) => true case _ => false } + val cases = + if(isVarPattern) { + val Ident(name) :: Nil = freevars + // cq"$name: $treeType => $SomeModule($name)" :: Nil + CaseDef(Bind(name, Typed(Ident(nme.WILDCARD), TypeTree(treeType))), + EmptyTree, Apply(Ident(SomeModule), List(Ident(name)))) :: Nil + } else { + val (succ, fail) = freevars match { + case Nil => + // (q"true", q"false") + (Literal(Constant(true)), Literal(Constant(false))) + case head :: Nil => + // (q"$SomeModule($head)", q"$NoneModule") + (Apply(Ident(SomeModule), List(head)), Ident(NoneModule)) + case vars => + // (q"$SomeModule((..$vars))", q"$NoneModule") + (Apply(Ident(SomeModule), List(SyntacticTuple(vars))), Ident(NoneModule)) + } + // cq"$tree => $succ" :: cq"_ => $fail" :: Nil + CaseDef(tree, EmptyTree, succ) :: CaseDef(Ident(nme.WILDCARD), EmptyTree, fail) :: Nil + } + // q"new { def unapply(tree: $AnyClass) = tree match { case ..$cases } }.unapply(..$args)" + Apply( + Select( + SyntacticNew(Nil, Nil, noSelfType, List( + DefDef(NoMods, nme.unapply, Nil, List(List(ValDef(NoMods, nme.tree, TypeTree(AnyClass.toType), EmptyTree))), TypeTree(), + Match(Ident(nme.tree), cases)))), + nme.unapply), + args) + } + def reifyFillingHoles(tree: Tree): Tree = { val reified = reifyTree(tree) holeMap.unused.foreach { hole => c.abort(holeMap(hole).tree.pos, s"Don't know how to $action here") } - reified + wrap(reified) } override def reifyTree(tree: Tree): Tree = diff --git a/src/reflect/scala/reflect/api/Quasiquotes.scala b/src/reflect/scala/reflect/api/Quasiquotes.scala index 08d3274ca5..8e993af382 100644 --- a/src/reflect/scala/reflect/api/Quasiquotes.scala +++ b/src/reflect/scala/reflect/api/Quasiquotes.scala @@ -8,7 +8,7 @@ trait Quasiquotes { self: Universe => implicit class Quasiquote(ctx: StringContext) { protected trait api { def apply(args: Any*): Any = macro ??? - def unapply(subpatterns: Any*): Option[Any] = macro ??? + def unapply(scrutinee: Any): Any = macro ??? } object q extends api object tq extends api diff --git a/test/files/scalacheck/quasiquotes/ErrorProps.scala b/test/files/scalacheck/quasiquotes/ErrorProps.scala index b9e69e0e88..b0a7641577 100644 --- a/test/files/scalacheck/quasiquotes/ErrorProps.scala +++ b/test/files/scalacheck/quasiquotes/ErrorProps.scala @@ -41,10 +41,7 @@ object ErrorProps extends QuasiquoteProperties("errors") { property("@..$first @$rest def foo") = fails( "Can't extract with .. here", """ - val a = annot("a") - val b = annot("b") - val c = annot("c") - val q"@..$first @$rest def foo" = q"@$a @$b @$c def foo" + q"@a @b @c def foo" match { case q"@..$first @$rest def foo" => } """) property("only literal string arguments") = fails( -- cgit v1.2.3 From d36989d1ec1de3b5b75de41415c852b087974bc7 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 27 Sep 2013 17:22:03 +0200 Subject: advanced fresh name reification During parsing some names are generated artificially using freshTermName & freshTypeName (e.g. `x$1`). Such names should be reified in a different way because they are assumed to be always fresh and non-overlapping with the environment. So `x$1` should reify down to equivalent of `freshTermName("x$")` rather than `TermName("x$1")`. But this is not enough. One name can be used more than once in a tree. E.g. `q"_ + 1"` desugars into `q"x$1 => x$1 + 1"`. So we need to ensure that every place where `x$1` is used gets the same fresh name. Hence the need for `withFreshTermName` that lets q"_ + 1" quasiquote desugare into equivalent of `withFreshTermName("x$") { freshx => q"$freshx => $freshx + 1" }`. For pattern quasiquotes it's a bit different. Due to the fact that end-result must be a pattern we need to represent fresh names as patterns too. A natural way to express that something is fresh is to represent it as a free variable (e.g. any name will do in that place). But due to possible use of the same name in multiple places we need to make sure that all such places have the same values by adding a sequence of guards to the pattern. Previously such names were reified naively and it could have caused name collision problems and inability to properly much on trees that contain such names. --- .../scala/tools/reflect/quasiquotes/Parsers.scala | 19 +++++++- .../tools/reflect/quasiquotes/Quasiquotes.scala | 8 +++- .../scala/tools/reflect/quasiquotes/Reifiers.scala | 55 ++++++++++++++++++++-- src/reflect/scala/reflect/api/BuildUtils.scala | 4 ++ .../scala/reflect/internal/BuildUtils.scala | 13 +++++ src/reflect/scala/reflect/internal/StdNames.scala | 1 + .../quasiquotes/TermConstructionProps.scala | 10 +++- .../quasiquotes/TermDeconstructionProps.scala | 24 +++++++++- 8 files changed, 126 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 7abf8b9964..ae610098dd 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -6,13 +6,14 @@ import scala.tools.nsc.ast.parser.Tokens._ import scala.compat.Platform.EOL import scala.reflect.internal.util.{BatchSourceFile, SourceFile} import scala.collection.mutable.ListBuffer +import scala.util.Try /** Builds upon the vanilla Scala parser and teams up together with Placeholders.scala to emulate holes. * A principled solution to splicing into Scala syntax would be a parser that natively supports holes. * Unfortunately, that's outside of our reach in Scala 2.11, so we have to emulate. */ trait Parsers { self: Quasiquotes => - import global._ + import global.{Try => _, _} abstract class Parser extends { val global: self.global.type = self.global @@ -54,7 +55,13 @@ trait Parsers { self: Quasiquotes => def isHole(name: Name): Boolean = holeMap.contains(name) + override def freshTermName(prefix: String): TermName = unit.freshTermName(nme.QUASIQUOTE_PREFIX + prefix) + override def freshTypeName(prefix: String): TypeName = unit.freshTypeName(nme.QUASIQUOTE_PREFIX + prefix) + override val treeBuilder = new ParserTreeBuilder { + override def freshTermName(prefix: String): TermName = parser.freshTermName(prefix) + override def freshTypeName(prefix: String): TypeName = parser.freshTypeName(prefix) + // q"(..$xs)" override def makeTupleTerm(trees: List[Tree], flattenUnary: Boolean): Tree = Apply(Ident(nme.QUASIQUOTE_TUPLE), trees) @@ -168,4 +175,14 @@ trait Parsers { self: Quasiquotes => parser.treeBuilder.patvarTransformer.transform(pat) } } + + object FreshName { + def unapply(name: Name): Option[String] = + name.toString.split("\\$") match { + case Array(qq, left, right) if qq + "$" == nme.QUASIQUOTE_PREFIX && Try(right.toInt).isSuccess => + Some(left + "$") + case _ => + None + } + } } \ No newline at end of file diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala index fb0ad3bbb0..9e98dcbc8b 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala @@ -47,7 +47,13 @@ abstract class Quasiquotes extends Parsers val tree = parse(code) debug(s"parsed:\n${showRaw(tree)}\n$tree\n") val reified = reify(tree) - debug(s"reified tree:\n$reified\n") + val sreified = + reified + .toString + .replace("scala.reflect.runtime.`package`.universe.build.", "") + .replace("scala.reflect.runtime.`package`.universe.", "") + .replace("scala.collection.immutable.", "") + debug(s"reified tree:\n$sreified\n") reified } } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 9f1a3ce257..642c882d5c 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -27,9 +27,40 @@ trait Reifiers { self: Quasiquotes => def action = if (isReifyingExpressions) "splice" else "extract" def holesHaveTypes = isReifyingExpressions + /** Map that stores freshly generated names linked to the corresponding names in the reified tree. + * This information is used to reify names created by calls to freshTermName and freshTypeName. + */ + var nameMap = collection.mutable.HashMap.empty[Name, Set[TermName]].withDefault { _ => Set() } + + /** Wraps expressions into: + * a sequence of nested withFreshTermName/withFreshTypeName calls which are required + * to force regeneration of randomly generated names on every evaluation of quasiquote. + * + * Wraps patterns into: + * a call into anonymous class' unapply method required by unapply macro expansion: + * + * new { + * def unapply(tree) = tree match { + * case pattern if guard => Some(result) + * case _ => None + * } + * }.unapply() + * + * where pattern corresponds to reified tree and guard represents conjunction of equalities + * which check that pairs of names in nameMap.values are equal between each other. + */ def wrap(tree: Tree) = - if (isReifyingExpressions) tree - else { + if (isReifyingExpressions) { + nameMap.foldLeft(tree) { + case (t, (origname, names)) => + assert(names.size == 1) + val FreshName(prefix) = origname + val ctor = TermName("withFresh" + (if (origname.isTermName) "TermName" else "TypeName")) + // q"$u.build.$ctor($prefix) { ${names.head} => $t }" + Apply(Apply(Select(Select(u, nme.build), ctor), List(Literal(Constant(prefix)))), + List(Function(List(ValDef(Modifiers(PARAM), names.head, TypeTree(), EmptyTree)), t))) + } + } else { val freevars = holeMap.toList.map { case (name, _) => Ident(name) } val isVarPattern = tree match { case Bind(name, Ident(nme.WILDCARD)) => true case _ => false } val cases = @@ -50,8 +81,18 @@ trait Reifiers { self: Quasiquotes => // (q"$SomeModule((..$vars))", q"$NoneModule") (Apply(Ident(SomeModule), List(SyntacticTuple(vars))), Ident(NoneModule)) } - // cq"$tree => $succ" :: cq"_ => $fail" :: Nil - CaseDef(tree, EmptyTree, succ) :: CaseDef(Ident(nme.WILDCARD), EmptyTree, fail) :: Nil + val guard = + nameMap.collect { case (_, nameset) if nameset.size >= 2 => + nameset.toList.sliding(2).map { case List(n1, n2) => + // q"$n1 == $n2" + Apply(Select(Ident(n1), nme.EQ), List(Ident(n2))) + } + }.flatten.reduceOption[Tree] { (l, r) => + // q"$l && $r" + Apply(Select(l, nme.ZAND), List(r)) + }.getOrElse { EmptyTree } + // cq"$tree if $guard => $succ" :: cq"_ => $fail" :: Nil + CaseDef(tree, guard, succ) :: CaseDef(Ident(nme.WILDCARD), EmptyTree, fail) :: Nil } // q"new { def unapply(tree: $AnyClass) = tree match { case ..$cases } }.unapply(..$args)" Apply( @@ -131,6 +172,12 @@ trait Reifiers { self: Quasiquotes => case Placeholder(tree, location, _) => if (holesHaveTypes && !(location.tpe <:< nameType)) c.abort(tree.pos, s"$nameType expected but ${location.tpe} found") tree + case FreshName(prefix) if prefix != nme.QUASIQUOTE_NAME_PREFIX => + def fresh() = c.freshName[TermName](nme.QUASIQUOTE_NAME_PREFIX) + def introduceName() = { val n = fresh(); nameMap(name) += n; n} + def result(n: Name) = if (isReifyingExpressions) Ident(n) else Bind(n, Ident(nme.WILDCARD)) + if (isReifyingPatterns) result(introduceName()) + else result(nameMap.get(name).map { _.head }.getOrElse { introduceName() }) case _ => super.reifyName(name) } diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index df126bed45..0dad78112b 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -90,6 +90,10 @@ private[reflect] trait BuildUtils { self: Universe => def RefTree(qual: Tree, sym: Symbol): Tree + def withFreshTermName[T](prefix: String)(f: TermName => T): T + + def withFreshTypeName[T](prefix: String)(f: TypeName => T): T + val ScalaDot: ScalaDotExtractor trait ScalaDotExtractor { diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index a09715ec7c..3e04811f4d 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -131,6 +131,19 @@ trait BuildUtils { self: SymbolTable => def RefTree(qual: Tree, sym: Symbol) = self.RefTree(qual, sym.name) setSymbol sym + def withFreshTermName[T](prefix: String)(f: TermName => T): T = f(TermName(freshName(prefix))) + + def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(TypeName(freshName(prefix))) + + object freshName { + private val counters = collection.mutable.HashMap[String, Int]() withDefaultValue 0 + def apply(prefix: String): String = { + val safePrefix = prefix.replaceAll("""[<>]""", """\$""") + counters(safePrefix) += 1 + safePrefix + counters(safePrefix) + } + } + object FlagsRepr extends FlagsReprExtractor { def apply(bits: Long): FlagSet = bits def unapply(flags: Long): Some[Long] = Some(flags) diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 7cfe194fd1..5cc3f911a4 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -320,6 +320,7 @@ trait StdNames { val REIFY_FREE_VALUE_SUFFIX: NameType = "$value" val REIFY_SYMDEF_PREFIX: NameType = "symdef$" val QUASIQUOTE_PREFIX: String = "qq$" + val QUASIQUOTE_NAME_PREFIX: String = "nn$" val QUASIQUOTE_FILE: String = "" val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" val QUASIQUOTE_CASE: NameType = "$quasiquote$case$" diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala index 753ad1aa59..9284903623 100644 --- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala @@ -7,7 +7,6 @@ import scala.reflect.runtime.universe._ import Flag._ object TermConstructionProps extends QuasiquoteProperties("term construction") { - property("splice single tree return tree itself") = forAll { (t: Tree) => q"$t" ≈ t } @@ -191,4 +190,13 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") { val assignx = q"x = 1" assertEqAst(q"f($assignx)", "f(x = 1)") } + + property("fresh names are regenerated at each evaluation") = test { + def plusOne = q"{ _ + 1 }" + assert(!(plusOne ≈ plusOne)) + def whileTrue = q"while(true) false" + assert(!(whileTrue ≈ whileTrue)) + def withEvidence = q"def foo[T: X]" + assert(!(withEvidence ≈ withEvidence)) + } } diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala index 22d4b1ce4f..ff105f7fba 100644 --- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala @@ -88,7 +88,7 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction matches("new foo with bar") matches("new foo with bar { body }") matches("new { anonymous }") - matches("new { val early = 1} with Parent[Int] { body }") + matches("new { val early = 1 } with Parent[Int] { body }") matches("new Foo { selfie => }") } @@ -111,4 +111,26 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction assert(left ≈ q"foo(bar)") assert(value ≈ q"baz") } + + property("deconstruct while loop") = test { + val q"while($cond) $body" = parse("while(cond) body") + assert(cond ≈ q"cond") + assert(body ≈ q"body") + } + + property("deconstruct do while loop") = test { + val q"do $body while($cond)" = parse("do body while(cond)") + assert(cond ≈ q"cond") + assert(body ≈ q"body") + } + + property("deconstruct anonymous function with placeholders") = test { + val q"{ $f(_) }" = q"{ foo(_) }" + assert(f ≈ q"foo") + val q"{ _.$member }" = q"{ _.foo }" + assert(member ≈ TermName("foo")) + val q"{ _ + $x }" = q"{ _ + x }" + assert(x ≈ q"x") + val q"{ _ * _ }" = q"{ _ * _ }" + } } -- cgit v1.2.3 From 9aa5a27042abae1e0ed585863678bc3a6fcf63a4 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Mon, 30 Sep 2013 17:25:44 +0200 Subject: make q"f(..$xs)" deconstruction symmetrical to q"f[..$xs]" --- src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala | 3 +++ src/reflect/scala/reflect/api/BuildUtils.scala | 7 +++++++ src/reflect/scala/reflect/internal/BuildUtils.scala | 9 +++++++++ src/reflect/scala/reflect/internal/StdNames.scala | 1 + test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala | 5 ++--- 5 files changed, 22 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 642c882d5c..b397940803 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -150,6 +150,9 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticVarDef, mods, name, tpt, rhs) case SyntacticAssign(lhs, rhs) => reifyBuildCall(nme.SyntacticAssign, lhs, rhs) + case SyntacticApplied(fun, List(args)) + if args.forall { case Placeholder(_, _, DotDotDot) => false case _ => true } => + reifyBuildCall(nme.SyntacticApply, fun, args) case SyntacticApplied(fun, argss) if argss.nonEmpty => reifyBuildCall(nme.SyntacticApplied, fun, argss) case SyntacticTypeApplied(fun, targs) if targs.nonEmpty => diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 0dad78112b..fc5d228417 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -122,6 +122,13 @@ private[reflect] trait BuildUtils { self: Universe => def unapply(tree: Tree): Some[(Tree, List[List[Tree]])] } + val SyntacticApply: SyntacticApplyExtractor + + trait SyntacticApplyExtractor { + def apply(tree: Tree, args: List[Tree]): Tree + def unapply(tree: Tree): Some[(Tree, List[Tree])] + } + val SyntacticClassDef: SyntacticClassDefExtractor trait SyntacticClassDefExtractor { diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 3e04811f4d..28f353593a 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -173,6 +173,15 @@ trait BuildUtils { self: SymbolTable => } } + object SyntacticApply extends SyntacticApplyExtractor { + def apply(tree: Tree, args: List[Tree]): Tree = SyntacticApplied(tree, List(args)) + + def unapply(tree: Tree): Some[(Tree, List[Tree])] = tree match { + case Apply(fun, args) => Some((fun, args)) + case other => Some((other, Nil)) + } + } + private object UnCtor { def unapply(tree: Tree): Option[(Modifiers, List[List[ValDef]], List[Tree])] = tree match { case DefDef(mods, nme.MIXIN_CONSTRUCTOR, _, _, _, Block(lvdefs, _)) => diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 5cc3f911a4..8a0e1e4768 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -584,6 +584,7 @@ trait StdNames { val Select: NameType = "Select" val SelectFromTypeTree: NameType = "SelectFromTypeTree" val SyntacticApplied: NameType = "SyntacticApplied" + val SyntacticApply: NameType = "SyntacticApply" val SyntacticAssign: NameType = "SyntacticAssign" val SyntacticBlock: NameType = "SyntacticBlock" val SyntacticClassDef: NameType = "SyntacticClassDef" diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala index ff105f7fba..f37e4d9975 100644 --- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala +++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala @@ -8,9 +8,8 @@ import Flag._ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction") { property("f(..x) = f") = test { - assertThrows[MatchError] { - val q"f(..$argss)" = q"f" - } + val q"f(..$args)" = q"f" + assert(args ≈ Nil) } property("f(x)") = forAll { (x: Tree) => -- cgit v1.2.3 From 0fd119d527dbe75b841b47e868bfcc09990714f0 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Tue, 1 Oct 2013 16:47:20 +0200 Subject: better name for isCaseDefStart As it was pointed out by @paulp current isCaseDefStart method's name doesn't really correspond to one of it's primary usages: checking if the block within case has reached it's end. --- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 12 ++++++------ src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 508453d5b2..032c0c34b3 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -635,8 +635,6 @@ self => def isAnnotation: Boolean = in.token == AT - def isCaseDefStart: Boolean = in.token == CASE - def isLocalModifier: Boolean = in.token match { case ABSTRACT | FINAL | SEALED | IMPLICIT | LAZY => true case _ => false @@ -687,6 +685,8 @@ self => def isStatSeqEnd = in.token == RBRACE || in.token == EOF + def isCaseDefEnd = in.token == RBRACE || in.token == CASE + def isStatSep(token: Int): Boolean = token == NEWLINE || token == NEWLINES || token == SEMI @@ -1329,7 +1329,7 @@ self => in.nextToken() if (in.token != LBRACE) catchFromExpr() else inBracesOrNil { - if (isCaseDefStart) caseClauses() + if (in.token == CASE) caseClauses() else catchFromExpr() } } @@ -1640,7 +1640,7 @@ self => */ def blockExpr(): Tree = atPos(in.offset) { inBraces { - if (isCaseDefStart) Match(EmptyTree, caseClauses()) + if (in.token == CASE) Match(EmptyTree, caseClauses()) else block() } } @@ -3057,14 +3057,14 @@ self => */ def blockStatSeq(): List[Tree] = checkNoEscapingPlaceholders { val stats = new ListBuffer[Tree] - while (!isStatSeqEnd && !isCaseDefStart) { + while (!isStatSeqEnd && !isCaseDefEnd) { if (in.token == IMPORT) { stats ++= importClause() acceptStatSepOpt() } else if (isExprIntro) { stats += statement(InBlock) - if (in.token != RBRACE && !isCaseDefStart) acceptStatSep() + if (!isCaseDefEnd) acceptStatSep() } else if (isDefIntro || isLocalModifier || isAnnotation) { if (in.token == IMPLICIT) { diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index ae610098dd..bd85aa9cdc 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -101,7 +101,7 @@ trait Parsers { self: Quasiquotes => override def isAnnotation: Boolean = super.isAnnotation || (isHole && lookingAhead { isAnnotation }) - override def isCaseDefStart: Boolean = super.isCaseDefStart || (in.token == EOF) + override def isCaseDefEnd: Boolean = super.isCaseDefEnd || (in.token == EOF) override def isModifier: Boolean = super.isModifier || (isHole && lookingAhead { isModifier }) -- cgit v1.2.3 From f6d0fbf9d5376727f70bc35eb511ee8d0624e7c7 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 20 Sep 2013 14:16:26 +0200 Subject: fix minor regression in quasiquote reification emptyValDef should always be reified as emptyValDef. After the the introduction of SyntacticValDef this ceased to be true. --- src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index b397940803..3d1ecf95b2 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -144,7 +144,7 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticNew, earlyDefs, parents, selfdef, body) case SyntacticDefDef(mods, name, tparams, vparamss, tpt, rhs) => reifyBuildCall(nme.SyntacticDefDef, mods, name, tparams, vparamss, tpt, rhs) - case SyntacticValDef(mods, name, tpt, rhs) => + case SyntacticValDef(mods, name, tpt, rhs) if tree != noSelfType => reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs) case SyntacticVarDef(mods, name, tpt, rhs) => reifyBuildCall(nme.SyntacticVarDef, mods, name, tpt, rhs) -- cgit v1.2.3 From ed86ab0a83f08e742545cf6ef40818f520c7844f Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Tue, 1 Oct 2013 16:54:54 +0200 Subject: rename selfdef into selfType For sake of consistency with noSelfType. --- src/reflect/scala/reflect/api/BuildUtils.scala | 10 ++--- .../scala/reflect/internal/BuildUtils.scala | 44 +++++++++++----------- 2 files changed, 27 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index fc5d228417..28551b1dcd 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -134,7 +134,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticClassDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], constrMods: Modifiers, vparamss: List[List[ValDef]], earlyDefs: List[Tree], - parents: List[Tree], selfdef: ValDef, body: List[Tree]): ClassDef + parents: List[Tree], selfType: ValDef, body: List[Tree]): ClassDef def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]], List[Tree], List[Tree], ValDef, List[Tree])] } @@ -143,7 +143,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticTraitDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], - earlyDefs: List[Tree], parents: List[Tree], selfdef: ValDef, body: List[Tree]): ClassDef + earlyDefs: List[Tree], parents: List[Tree], selfType: ValDef, body: List[Tree]): ClassDef def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], List[Tree], List[Tree], ValDef, List[Tree])] } @@ -152,7 +152,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree + parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] } @@ -160,7 +160,7 @@ private[reflect] trait BuildUtils { self: Universe => trait SyntacticPackageObjectDefExtractor { def apply(name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree + parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] } @@ -182,7 +182,7 @@ private[reflect] trait BuildUtils { self: Universe => val SyntacticNew: SyntacticNewExtractor trait SyntacticNewExtractor { - def apply(earlyDefs: List[Tree], parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree + def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree def unapply(tree: Tree): Option[(List[Tree], List[Tree], ValDef, List[Tree])] } diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 28f353593a..b46408624c 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -194,9 +194,9 @@ trait BuildUtils { self: SymbolTable => private object UnMkTemplate { def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = { - val Template(parents, selfdef, tbody) = templ + val Template(parents, selfType, tbody) = templ def result(ctorMods: Modifiers, vparamss: List[List[ValDef]], edefs: List[Tree], body: List[Tree]) = - Some((parents, selfdef, ctorMods, vparamss, edefs, body)) + Some((parents, selfType, ctorMods, vparamss, edefs, body)) def indexOfCtor(trees: List[Tree]) = trees.indexWhere { case UnCtor(_, _, _) => true ; case _ => false } @@ -236,7 +236,7 @@ trait BuildUtils { self: SymbolTable => object SyntacticClassDef extends SyntacticClassDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], constrMods: Modifiers, vparamss: List[List[ValDef]], earlyDefs: List[Tree], - parents: List[Tree], selfdef: ValDef, body: List[Tree]): ClassDef = { + parents: List[Tree], selfType: ValDef, body: List[Tree]): ClassDef = { val extraFlags = PARAMACCESSOR | (if (mods.isCase) CASEACCESSOR else 0L) val vparamss0 = vparamss.map { _.map { vd => copyValDef(vd)(mods = (vd.mods | extraFlags) & (~DEFERRED)) } } val tparams0 = mkTparams(tparams) @@ -247,15 +247,15 @@ trait BuildUtils { self: SymbolTable => } else parents ) val body0 = earlyDefs ::: body - val templ = gen.mkTemplate(parents0, selfdef, constrMods, vparamss0, body0) + val templ = gen.mkTemplate(parents0, selfType, constrMods, vparamss0, body0) gen.mkClassDef(mods, name, tparams0, templ) } def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], Modifiers, List[List[ValDef]], List[Tree], List[Tree], ValDef, List[Tree])] = tree match { - case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfdef, ctorMods, vparamss, earlyDefs, body)) + case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfType, ctorMods, vparamss, earlyDefs, body)) if !ctorMods.isTrait && !ctorMods.hasFlag(JAVA) => - Some((mods, name, tparams, ctorMods, vparamss, earlyDefs, parents, selfdef, body)) + Some((mods, name, tparams, ctorMods, vparamss, earlyDefs, parents, selfType, body)) case _ => None } @@ -263,29 +263,29 @@ trait BuildUtils { self: SymbolTable => object SyntacticTraitDef extends SyntacticTraitDefExtractor { def apply(mods: Modifiers, name: TypeName, tparams: List[TypeDef], earlyDefs: List[Tree], - parents: List[Tree], selfdef: ValDef, body: List[Tree]): ClassDef = { + parents: List[Tree], selfType: ValDef, body: List[Tree]): ClassDef = { val mods0 = mods | TRAIT | ABSTRACT - val templ = gen.mkTemplate(parents, selfdef, Modifiers(TRAIT), Nil, earlyDefs ::: body) + val templ = gen.mkTemplate(parents, selfType, Modifiers(TRAIT), Nil, earlyDefs ::: body) gen.mkClassDef(mods0, name, mkTparams(tparams), templ) } def unapply(tree: Tree): Option[(Modifiers, TypeName, List[TypeDef], List[Tree], List[Tree], ValDef, List[Tree])] = tree match { - case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfdef, ctorMods, vparamss, earlyDefs, body)) + case ClassDef(mods, name, tparams, UnMkTemplate(parents, selfType, ctorMods, vparamss, earlyDefs, body)) if mods.isTrait => - Some((mods, name, tparams, earlyDefs, parents, selfdef, body)) + Some((mods, name, tparams, earlyDefs, parents, selfType, body)) case _ => None } } object SyntacticObjectDef extends SyntacticObjectDefExtractor { def apply(mods: Modifiers, name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfdef: ValDef, body: List[Tree]) = - ModuleDef(mods, name, gen.mkTemplate(parents, selfdef, NoMods, Nil, earlyDefs ::: body)) + parents: List[Tree], selfType: ValDef, body: List[Tree]) = + ModuleDef(mods, name, gen.mkTemplate(parents, selfType, NoMods, Nil, earlyDefs ::: body)) def unapply(tree: Tree): Option[(Modifiers, TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { - case ModuleDef(mods, name, UnMkTemplate(parents, selfdef, _, _, earlyDefs, body)) => - Some((mods, name, earlyDefs, parents, selfdef, body)) + case ModuleDef(mods, name, UnMkTemplate(parents, selfType, _, _, earlyDefs, body)) => + Some((mods, name, earlyDefs, parents, selfType, body)) case _ => None } @@ -293,12 +293,12 @@ trait BuildUtils { self: SymbolTable => object SyntacticPackageObjectDef extends SyntacticPackageObjectDefExtractor { def apply(name: TermName, earlyDefs: List[Tree], - parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree = - gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfdef, body)) + parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree = + gen.mkPackageObject(SyntacticObjectDef(NoMods, name, earlyDefs, parents, selfType, body)) def unapply(tree: Tree): Option[(TermName, List[Tree], List[Tree], ValDef, List[Tree])] = tree match { - case PackageDef(Ident(name: TermName), List(SyntacticObjectDef(NoMods, nme.PACKAGEkw, earlyDefs, parents, selfdef, body))) => - Some((name, earlyDefs, parents, selfdef, body)) + case PackageDef(Ident(name: TermName), List(SyntacticObjectDef(NoMods, nme.PACKAGEkw, earlyDefs, parents, selfType, body))) => + Some((name, earlyDefs, parents, selfType, body)) case _ => None } @@ -406,15 +406,15 @@ trait BuildUtils { self: SymbolTable => } object SyntacticNew extends SyntacticNewExtractor { - def apply(earlyDefs: List[Tree], parents: List[Tree], selfdef: ValDef, body: List[Tree]): Tree = - gen.mkNew(parents, selfdef, earlyDefs ::: body, NoPosition, NoPosition) + def apply(earlyDefs: List[Tree], parents: List[Tree], selfType: ValDef, body: List[Tree]): Tree = + gen.mkNew(parents, selfType, earlyDefs ::: body, NoPosition, NoPosition) def unapply(tree: Tree): Option[(List[Tree], List[Tree], ValDef, List[Tree])] = tree match { case SyntacticApplied(Select(New(SyntacticTypeApplied(ident, targs)), nme.CONSTRUCTOR), argss) => Some((Nil, SyntacticApplied(SyntacticTypeApplied(ident, targs), argss) :: Nil, noSelfType, Nil)) - case SyntacticBlock(SyntacticClassDef(_, tpnme.ANON_CLASS_NAME, Nil, _, ListOfNil, earlyDefs, parents, selfdef, body) :: + case SyntacticBlock(SyntacticClassDef(_, tpnme.ANON_CLASS_NAME, Nil, _, ListOfNil, earlyDefs, parents, selfType, body) :: Apply(Select(New(Ident(tpnme.ANON_CLASS_NAME)), nme.CONSTRUCTOR), Nil) :: Nil) => - Some((earlyDefs, parents, selfdef, body)) + Some((earlyDefs, parents, selfType, body)) case _ => None } -- cgit v1.2.3 From 3692acaa40c8edcf4a5e7f4fcfa29ef090385df2 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Wed, 2 Oct 2013 13:25:07 +0200 Subject: move fresh name creator into scala.reflect.internal.util --- .../scala/tools/nsc/CompilationUnits.scala | 5 ++- .../scala/tools/nsc/ast/parser/Parsers.scala | 5 ++- .../scala/tools/nsc/util/FreshNameCreator.scala | 40 ---------------------- .../scala/reflect/internal/BuildUtils.scala | 13 ++----- .../reflect/internal/util/FreshNameCreator.scala | 31 +++++++++++++++++ 5 files changed, 38 insertions(+), 56 deletions(-) delete mode 100644 src/compiler/scala/tools/nsc/util/FreshNameCreator.scala create mode 100644 src/reflect/scala/reflect/internal/util/FreshNameCreator.scala (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 1de5c1f626..59ac123fe6 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -5,8 +5,7 @@ package scala.tools.nsc -import util.FreshNameCreator -import scala.reflect.internal.util.{ SourceFile, NoSourceFile } +import scala.reflect.internal.util.{ SourceFile, NoSourceFile, FreshNameCreator } import scala.collection.mutable import scala.collection.mutable.{ LinkedHashSet, ListBuffer } import scala.tools.nsc.reporters.Reporter @@ -27,7 +26,7 @@ trait CompilationUnits { global: Global => class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { self => /** the fresh name creator */ - val fresh: FreshNameCreator = new FreshNameCreator.Default + val fresh: FreshNameCreator = new FreshNameCreator def freshTermName(prefix: String): TermName = newTermName(fresh.newName(prefix)) def freshTypeName(prefix: String): TypeName = newTypeName(fresh.newName(prefix)) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 032c0c34b3..6f5d9f289b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -13,9 +13,8 @@ import scala.collection.{ mutable, immutable } import mutable.{ ListBuffer, StringBuilder } import scala.reflect.internal.{ ModifierFlags => Flags } import scala.reflect.internal.Chars.{ isScalaLetter } -import scala.reflect.internal.util.{ SourceFile, Position } +import scala.reflect.internal.util.{ SourceFile, Position, FreshNameCreator } import Tokens._ -import util.FreshNameCreator /** Historical note: JavaParsers started life as a direct copy of Parsers * but at a time when that Parsers had been replaced by a different one. @@ -164,7 +163,7 @@ self => val in = newScanner() in.init() - private val globalFresh = new FreshNameCreator.Default + private val globalFresh = new FreshNameCreator def unit = global.currentUnit def freshName(prefix: String): Name = freshTermName(prefix) diff --git a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala deleted file mode 100644 index e877c990f0..0000000000 --- a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala +++ /dev/null @@ -1,40 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2013 LAMP/EPFL - * @author Martin Odersky - */ - -package scala.tools.nsc -package util - -import scala.collection.mutable - -trait FreshNameCreator { - /** Do not call before after type checking ends. - * PP: I think that directive needs to lose a word somewhere. - */ - def newName(): String - def newName(prefix: String): String -} - -object FreshNameCreator { - class Default extends FreshNameCreator { - protected var counter = 0 - protected val counters = mutable.HashMap[String, Int]() withDefaultValue 0 - - /** - * Create a fresh name with the given prefix. It is guaranteed - * that the returned name has never been returned by a previous - * call to this function (provided the prefix does not end in a digit). - */ - def newName(prefix: String): String = { - val safePrefix = prefix.replaceAll("""[<>]""", """\$""") - counters(safePrefix) += 1 - - safePrefix + counters(safePrefix) - } - def newName(): String = { - counter += 1 - "$" + counter + "$" - } - } -} diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index b46408624c..39dfe60ecf 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -131,18 +131,11 @@ trait BuildUtils { self: SymbolTable => def RefTree(qual: Tree, sym: Symbol) = self.RefTree(qual, sym.name) setSymbol sym - def withFreshTermName[T](prefix: String)(f: TermName => T): T = f(TermName(freshName(prefix))) + def withFreshTermName[T](prefix: String)(f: TermName => T): T = f(TermName(freshNameCreator.newName(prefix))) - def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(TypeName(freshName(prefix))) + def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(TypeName(freshNameCreator.newName(prefix))) - object freshName { - private val counters = collection.mutable.HashMap[String, Int]() withDefaultValue 0 - def apply(prefix: String): String = { - val safePrefix = prefix.replaceAll("""[<>]""", """\$""") - counters(safePrefix) += 1 - safePrefix + counters(safePrefix) - } - } + private val freshNameCreator = new util.FreshNameCreator object FlagsRepr extends FlagsReprExtractor { def apply(bits: Long): FlagSet = bits diff --git a/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala b/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala new file mode 100644 index 0000000000..8fe4a715f3 --- /dev/null +++ b/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala @@ -0,0 +1,31 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2013 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.reflect.internal +package util + +import scala.collection.mutable + +class FreshNameCreator { + protected var counter = 0 + protected val counters = mutable.HashMap[String, Int]() withDefaultValue 0 + + /** + * Create a fresh name with the given prefix. It is guaranteed + * that the returned name has never been returned by a previous + * call to this function (provided the prefix does not end in a digit). + */ + def newName(prefix: String): String = { + val safePrefix = prefix.replaceAll("""[<>]""", """\$""") + counters(safePrefix) += 1 + + safePrefix + counters(safePrefix) + } + + def newName(): String = { + counter += 1 + "$" + counter + "$" + } +} -- cgit v1.2.3 From 27fca0fc3fecef10ece59a4c28282301ce2cd961 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Thu, 10 Oct 2013 12:56:37 +0200 Subject: decrease duplication of fresh* function definitions This commit extracts out freshTermName and freshTypeName to the top-level with implicit fresh name creator argument. This will let to refactor out more methods out of tree builder into treegen that are dependent on fresh name generator. We also save quite a bit of boilerplate by not having to redefined fresh functions all over the place. --- .../scala/tools/nsc/CompilationUnits.scala | 7 ++-- src/compiler/scala/tools/nsc/Global.scala | 5 ++- .../scala/tools/nsc/ast/parser/Parsers.scala | 46 ++++++++-------------- .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 29 ++++---------- .../tools/nsc/typechecker/NamesDefaults.scala | 2 +- .../tools/nsc/typechecker/PatternTypers.scala | 2 +- .../scala/tools/reflect/quasiquotes/Parsers.scala | 10 ++--- .../scala/reflect/internal/BuildUtils.scala | 6 +-- .../scala/reflect/internal/SymbolTable.scala | 4 ++ 9 files changed, 44 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 59ac123fe6..df5952a4cf 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -26,10 +26,9 @@ trait CompilationUnits { global: Global => class CompilationUnit(val source: SourceFile) extends CompilationUnitContextApi { self => /** the fresh name creator */ - val fresh: FreshNameCreator = new FreshNameCreator - - def freshTermName(prefix: String): TermName = newTermName(fresh.newName(prefix)) - def freshTypeName(prefix: String): TypeName = newTypeName(fresh.newName(prefix)) + implicit val fresh: FreshNameCreator = new FreshNameCreator + def freshTermName(prefix: String = "x$") = global.freshTermName(prefix) + def freshTypeName(prefix: String) = global.freshTypeName(prefix) /** the content of the compilation unit in tree form */ var body: Tree = EmptyTree diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 1cd3e0ec4b..46456093eb 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -110,9 +110,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) } /** A spare instance of TreeBuilder left for backwards compatibility. */ - lazy val treeBuilder: TreeBuilder { val global: Global.this.type } = new UnitTreeBuilder { + lazy val treeBuilder: TreeBuilder { val global: Global.this.type } = new TreeBuilder { val global: Global.this.type = Global.this; - val unit = currentUnit + def unit = currentUnit + def source = currentUnit.source } /** Fold constants */ diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 6f5d9f289b..2b6bf657b3 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -40,9 +40,6 @@ trait ParsersCommon extends ScannersCommon { self => */ abstract class ParserCommon { val in: ScannerCommon - def freshName(prefix: String): Name - def freshTermName(prefix: String): TermName - def freshTypeName(prefix: String): TypeName def deprecationWarning(off: Int, msg: String): Unit def accept(token: Int): Int @@ -163,15 +160,7 @@ self => val in = newScanner() in.init() - private val globalFresh = new FreshNameCreator - def unit = global.currentUnit - def freshName(prefix: String): Name = freshTermName(prefix) - def freshTermName(prefix: String): TermName = newTermName(globalFresh.newName(prefix)) - def freshTypeName(prefix: String): TypeName = newTypeName(globalFresh.newName(prefix)) - - def o2p(offset: Int): Position = Position.offset(source, offset) - def r2p(start: Int, mid: Int, end: Int): Position = rangePos(source, start, mid, end) // suppress warnings; silent abort on errors def warning(offset: Int, msg: String) {} @@ -224,9 +213,6 @@ self => override def newScanner() = new UnitScanner(unit, patches) - override def freshTermName(prefix: String): TermName = unit.freshTermName(prefix) - override def freshTypeName(prefix: String): TypeName = unit.freshTypeName(prefix) - override def warning(offset: Int, msg: String) { unit.warning(o2p(offset), msg) } @@ -294,25 +280,26 @@ self => abstract class Parser extends ParserCommon { parser => val in: Scanner - def unit: CompilationUnit - def freshName(prefix: String): Name - def freshTermName(prefix: String): TermName - def freshTypeName(prefix: String): TypeName - def o2p(offset: Int): Position - def r2p(start: Int, mid: Int, end: Int): Position - def r2p(start: Int, mid: Int): Position = r2p(start, mid, in.lastOffset max start) - def r2p(offset: Int): Position = r2p(offset, offset) - - /** whether a non-continuable syntax error has been seen */ - private var lastErrorOffset : Int = -1 + def source: SourceFile - class ParserTreeBuilder extends UnitTreeBuilder { + class ParserTreeBuilder extends TreeBuilder { val global: self.global.type = self.global def unit = parser.unit + def source = parser.source } val treeBuilder = new ParserTreeBuilder - import treeBuilder.{global => _, unit => _, _} + import treeBuilder.{global => _, unit => _, source => _, fresh => _, _} + + implicit def fresh: FreshNameCreator = unit.fresh + + def o2p(offset: Int): Position = Position.offset(source, offset) + def r2p(start: Int, mid: Int, end: Int): Position = rangePos(source, start, mid, end) + def r2p(start: Int, mid: Int): Position = r2p(start, mid, in.lastOffset max start) + def r2p(offset: Int): Position = r2p(offset, offset) + + /** whether a non-continuable syntax error has been seen */ + private var lastErrorOffset : Int = -1 /** The types of the context bounds of type parameters of the surrounding class */ @@ -1162,7 +1149,7 @@ self => /** Consume a USCORE and create a fresh synthetic placeholder param. */ private def freshPlaceholder(): Tree = { val start = in.offset - val pname = freshName("x$") + val pname = freshTermName() in.nextToken() val id = atPos(start)(Ident(pname)) val param = atPos(id.pos.focus)(gen.mkSyntheticParam(pname.toTermName)) @@ -2247,7 +2234,7 @@ self => } } val nameOffset = in.offset - // TODO AM: freshName(o2p(in.skipToken()), "_$$"), will need to update test suite + // TODO AM: freshTermName(o2p(in.skipToken()), "_$$"), will need to update test suite val pname: TypeName = wildcardOrIdent().toTypeName val param = atPos(start, nameOffset) { val tparams = typeParamClauseOpt(pname, null) // @M TODO null --> no higher-order context bounds for now @@ -2459,7 +2446,6 @@ self => EmptyTree } def mkDefs(p: Tree, tp: Tree, rhs: Tree): List[Tree] = { - //Console.println("DEBUG: p = "+p.toString()); // DEBUG val trees = makePatDef(newmods, if (tp.isEmpty) p diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 59abf99844..28d5aefc2b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -8,24 +8,21 @@ package ast.parser import symtab.Flags._ import scala.collection.mutable.ListBuffer -import scala.reflect.internal.util.Position +import scala.reflect.internal.util.{Position, SourceFile, FreshNameCreator} /** Methods for building trees, used in the parser. All the trees * returned by this class must be untyped. */ abstract class TreeBuilder { - val global: Global import global._ - def freshName(): Name = freshName("x$") - def freshTermName(): TermName = freshTermName("x$") + def unit: CompilationUnit + def source: SourceFile - def freshName(prefix: String): Name - def freshTermName(prefix: String): TermName - def freshTypeName(prefix: String): TypeName - def o2p(offset: Int): Position - def r2p(start: Int, point: Int, end: Int): Position + implicit def fresh: FreshNameCreator = unit.fresh + def o2p(offset: Int): Position = Position.offset(source, offset) + def r2p(start: Int, mid: Int, end: Int): Position = rangePos(source, start, mid, end) def rootScalaDot(name: Name) = gen.rootScalaDot(name) def scalaDot(name: Name) = gen.scalaDot(name) @@ -325,7 +322,7 @@ abstract class TreeBuilder { /* If `pat` is not yet a `Bind` wrap it in one with a fresh name */ def makeBind(pat: Tree): Tree = pat match { case Bind(_, _) => pat - case _ => Bind(freshName(), pat) setPos pat.pos + case _ => Bind(freshTermName(), pat) setPos pat.pos } /* A reference to the name bound in Bind `pat`. */ @@ -416,7 +413,7 @@ abstract class TreeBuilder { * } */ def makeCatchFromExpr(catchExpr: Tree): CaseDef = { - val binder = freshTermName("x") + val binder = freshTermName() val pat = Bind(binder, Typed(Ident(nme.WILDCARD), Ident(tpnme.Throwable))) val catchDef = ValDef(Modifiers(ARTIFACT), freshTermName("catchExpr"), TypeTree(), catchExpr) val catchFn = Ident(catchDef.name) @@ -520,13 +517,3 @@ abstract class TreeBuilder { } } } - -abstract class UnitTreeBuilder extends TreeBuilder { - import global._ - def unit: CompilationUnit - def freshName(prefix: String): Name = freshTermName(prefix) - def freshTermName(prefix: String): TermName = unit.freshTermName(prefix) - def freshTypeName(prefix: String): TypeName = unit.freshTypeName(prefix) - def o2p(offset: Int): Position = Position.offset(unit.source, offset) - def r2p(start: Int, mid: Int, end: Int): Position = rangePos(unit.source, start, mid, end) -} diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index dea4c46e79..03aad71165 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -289,7 +289,7 @@ trait NamesDefaults { self: Analyzer => arg.tpe } ).widen // have to widen or types inferred from literal defaults will be singletons - val s = context.owner.newValue(unit.freshTermName("x$"), arg.pos, newFlags = ARTIFACT) setInfo { + val s = context.owner.newValue(unit.freshTermName(), arg.pos, newFlags = ARTIFACT) setInfo { val tp = if (byName) functionType(Nil, argTpe) else argTpe uncheckedBounds(tp) } diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala index f3e8ac64f4..f69b8a9697 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala @@ -281,7 +281,7 @@ trait PatternTypers { else TypeBounds.lower(tpSym.tpeHK) ) // origin must be the type param so we can deskolemize - val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?"+tpSym.name), tpSym, bounds) + val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?" + tpSym.name), tpSym, bounds) skolemBuffer += skolem logResult(s"Created gadt skolem $skolem: ${skolem.tpe_*} to stand in for $tpSym")(skolem.tpe_*) case tp1 => tp1 diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index bd85aa9cdc..983978db7e 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -4,7 +4,7 @@ package quasiquotes import scala.tools.nsc.ast.parser.{Parsers => ScalaParser} import scala.tools.nsc.ast.parser.Tokens._ import scala.compat.Platform.EOL -import scala.reflect.internal.util.{BatchSourceFile, SourceFile} +import scala.reflect.internal.util.{BatchSourceFile, SourceFile, FreshNameCreator} import scala.collection.mutable.ListBuffer import scala.util.Try @@ -55,12 +55,12 @@ trait Parsers { self: Quasiquotes => def isHole(name: Name): Boolean = holeMap.contains(name) - override def freshTermName(prefix: String): TermName = unit.freshTermName(nme.QUASIQUOTE_PREFIX + prefix) - override def freshTypeName(prefix: String): TypeName = unit.freshTypeName(nme.QUASIQUOTE_PREFIX + prefix) + override implicit def fresh = new FreshNameCreator { + override def newName(prefix: String) = super.newName(nme.QUASIQUOTE_PREFIX + prefix) + } override val treeBuilder = new ParserTreeBuilder { - override def freshTermName(prefix: String): TermName = parser.freshTermName(prefix) - override def freshTypeName(prefix: String): TypeName = parser.freshTypeName(prefix) + override implicit def fresh = parser.fresh // q"(..$xs)" override def makeTupleTerm(trees: List[Tree], flattenUnary: Boolean): Tree = diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 39dfe60ecf..46119ae802 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -131,11 +131,11 @@ trait BuildUtils { self: SymbolTable => def RefTree(qual: Tree, sym: Symbol) = self.RefTree(qual, sym.name) setSymbol sym - def withFreshTermName[T](prefix: String)(f: TermName => T): T = f(TermName(freshNameCreator.newName(prefix))) + def withFreshTermName[T](prefix: String)(f: TermName => T): T = f(freshTermName(prefix)) - def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(TypeName(freshNameCreator.newName(prefix))) + def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(freshTypeName(prefix)) - private val freshNameCreator = new util.FreshNameCreator + private implicit val fresh = new FreshNameCreator object FlagsRepr extends FlagsReprExtractor { def apply(bits: Long): FlagSet = bits diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index a6f9dfc164..0e9c866ace 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -370,6 +370,10 @@ abstract class SymbolTable extends macros.Universe * Adds the `sm` String interpolator to a [[scala.StringContext]]. */ implicit val StringContextStripMarginOps: StringContext => StringContextStripMarginOps = util.StringContextStripMarginOps + + // fresh name creation + def freshTermName(prefix: String = "x$")(implicit creator: FreshNameCreator): TermName = newTermName(creator.newName(prefix)) + def freshTypeName(prefix: String)(implicit creator: FreshNameCreator): TypeName = newTypeName(creator.newName(prefix)) } object SymbolTableStats { -- cgit v1.2.3 From 68a6b57df2534d8b96cee8b3f4ab68159029779a Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 11 Oct 2013 15:51:17 +0200 Subject: eliminate isCaseDefEnd override by moving the logic into stock parser --- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 2 +- src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala | 2 -- test/files/neg/xmltruncated6.check | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 2b6bf657b3..b2570d64e3 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -671,7 +671,7 @@ self => def isStatSeqEnd = in.token == RBRACE || in.token == EOF - def isCaseDefEnd = in.token == RBRACE || in.token == CASE + def isCaseDefEnd = in.token == RBRACE || in.token == CASE || in.token == EOF def isStatSep(token: Int): Boolean = token == NEWLINE || token == NEWLINES || token == SEMI diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 983978db7e..71e9274d37 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -101,8 +101,6 @@ trait Parsers { self: Quasiquotes => override def isAnnotation: Boolean = super.isAnnotation || (isHole && lookingAhead { isAnnotation }) - override def isCaseDefEnd: Boolean = super.isCaseDefEnd || (in.token == EOF) - override def isModifier: Boolean = super.isModifier || (isHole && lookingAhead { isModifier }) override def isLocalModifier: Boolean = super.isLocalModifier || (isHole && lookingAhead { isLocalModifier }) diff --git a/test/files/neg/xmltruncated6.check b/test/files/neg/xmltruncated6.check index 6123114560..f638f2f090 100644 --- a/test/files/neg/xmltruncated6.check +++ b/test/files/neg/xmltruncated6.check @@ -1,4 +1,4 @@ -xmltruncated6.scala:2: error: ';' expected but eof found. +xmltruncated6.scala:2: error: in XML literal: expected end of Scala block val stuff = { "no closing brace" ^ one error found -- cgit v1.2.3 From 0a16caa5881b312f5cd3817fd4036436ed1d58b5 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 11 Oct 2013 15:55:46 +0200 Subject: use NameTransformer.encode for fresh name prefix sanitization --- src/reflect/scala/reflect/internal/util/FreshNameCreator.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala b/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala index 8fe4a715f3..c8347cfeaa 100644 --- a/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala +++ b/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala @@ -7,6 +7,7 @@ package scala.reflect.internal package util import scala.collection.mutable +import scala.reflect.NameTransformer class FreshNameCreator { protected var counter = 0 @@ -18,9 +19,8 @@ class FreshNameCreator { * call to this function (provided the prefix does not end in a digit). */ def newName(prefix: String): String = { - val safePrefix = prefix.replaceAll("""[<>]""", """\$""") + val safePrefix = NameTransformer.encode(prefix) counters(safePrefix) += 1 - safePrefix + counters(safePrefix) } -- cgit v1.2.3 From cf58d7c88c35c41f749298de5b0de09fca72df1b Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 11 Oct 2013 17:40:35 +0200 Subject: re-wire fresh name creator to currentUnit.fresh at compile-time --- src/compiler/scala/tools/nsc/Global.scala | 1 + src/reflect/scala/reflect/internal/BuildUtils.scala | 2 +- src/reflect/scala/reflect/internal/SymbolTable.scala | 1 + src/reflect/scala/reflect/runtime/JavaUniverse.scala | 2 ++ test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala | 2 ++ 5 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 46456093eb..1c5354502b 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1050,6 +1050,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def currentRun: Run = curRun def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile + def currentFreshNameCreator = currentUnit.fresh def isGlobalInitialized = ( definitions.isDefinitionsInitialized diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 46119ae802..fc6b26db3f 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -135,7 +135,7 @@ trait BuildUtils { self: SymbolTable => def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(freshTypeName(prefix)) - private implicit val fresh = new FreshNameCreator + private implicit def fresh: FreshNameCreator = self.currentFreshNameCreator object FlagsRepr extends FlagsReprExtractor { def apply(bits: Long): FlagSet = bits diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index 0e9c866ace..8f954e4095 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -372,6 +372,7 @@ abstract class SymbolTable extends macros.Universe implicit val StringContextStripMarginOps: StringContext => StringContextStripMarginOps = util.StringContextStripMarginOps // fresh name creation + def currentFreshNameCreator: FreshNameCreator def freshTermName(prefix: String = "x$")(implicit creator: FreshNameCreator): TermName = newTermName(creator.newName(prefix)) def freshTypeName(prefix: String)(implicit creator: FreshNameCreator): TypeName = newTypeName(creator.newName(prefix)) } diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index 06a7db6289..9d37edbacd 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -21,6 +21,8 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S def newStrictTreeCopier: TreeCopier = new StrictTreeCopier def newLazyTreeCopier: TreeCopier = new LazyTreeCopier + val currentFreshNameCreator = new reflect.internal.util.FreshNameCreator + // can't put this in runtime.Trees since that's mixed with Global in ReflectGlobal, which has the definition from internal.Trees object treeInfo extends { val global: JavaUniverse.this.type = JavaUniverse.this diff --git a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala index 285e87e3b2..a3699a4eeb 100644 --- a/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala +++ b/test/junit/scala/tools/nsc/symtab/SymbolTableForUnitTesting.scala @@ -85,5 +85,7 @@ class SymbolTableForUnitTesting extends SymbolTable { } lazy val treeInfo: scala.reflect.internal.TreeInfo{val global: SymbolTableForUnitTesting.this.type} = ??? + val currentFreshNameCreator = new reflect.internal.util.FreshNameCreator + phase = SomePhase } -- cgit v1.2.3 From 68e9e267e63f13ce2e99843df989a1306f91cd19 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 11 Oct 2013 20:25:26 +0200 Subject: use concurrent hash map with atomic integers This should ensure that concurrent access to the fresh name creator is properly synchronized. --- src/compiler/scala/reflect/macros/contexts/Names.scala | 4 ++-- .../scala/reflect/internal/util/FreshNameCreator.scala | 14 +++++--------- test/files/run/macro-abort-fresh.check | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/reflect/macros/contexts/Names.scala b/src/compiler/scala/reflect/macros/contexts/Names.scala index e535754a98..c2f14cf0f1 100644 --- a/src/compiler/scala/reflect/macros/contexts/Names.scala +++ b/src/compiler/scala/reflect/macros/contexts/Names.scala @@ -4,7 +4,7 @@ package contexts trait Names { self: Context => - lazy val freshNameCreator = callsiteTyper.context.unit.fresh + def freshNameCreator = callsiteTyper.context.unit.fresh def fresh(): String = freshName() @@ -16,7 +16,7 @@ trait Names { freshName[NameType](name) def freshName(): String = - freshNameCreator.newName() + freshName("fresh$") def freshName(name: String): String = freshNameCreator.newName(name) diff --git a/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala b/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala index c8347cfeaa..3e54de8e1e 100644 --- a/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala +++ b/src/reflect/scala/reflect/internal/util/FreshNameCreator.scala @@ -6,12 +6,13 @@ package scala.reflect.internal package util +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.atomic.AtomicLong import scala.collection.mutable import scala.reflect.NameTransformer class FreshNameCreator { - protected var counter = 0 - protected val counters = mutable.HashMap[String, Int]() withDefaultValue 0 + protected val counters = new ConcurrentHashMap[String, AtomicLong]() /** * Create a fresh name with the given prefix. It is guaranteed @@ -20,12 +21,7 @@ class FreshNameCreator { */ def newName(prefix: String): String = { val safePrefix = NameTransformer.encode(prefix) - counters(safePrefix) += 1 - safePrefix + counters(safePrefix) - } - - def newName(): String = { - counter += 1 - "$" + counter + "$" + counters.putIfAbsent(safePrefix, new AtomicLong(0)); + safePrefix + counters.get(safePrefix).incrementAndGet(); } } diff --git a/test/files/run/macro-abort-fresh.check b/test/files/run/macro-abort-fresh.check index 87491f6e48..9fddee57d4 100644 --- a/test/files/run/macro-abort-fresh.check +++ b/test/files/run/macro-abort-fresh.check @@ -1,4 +1,4 @@ -$1$ +fresh$1 qwe1 qwe2 reflective compilation has failed: -- cgit v1.2.3 From 489ea4ac1c1932ed6943ea215e1494eb1e3dff84 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 18 Oct 2013 14:56:10 +0200 Subject: use more descriptive types instead of ints in the parser and scanner --- .../scala/tools/nsc/ast/parser/Parsers.scala | 117 +++++++++++---------- .../scala/tools/nsc/ast/parser/Scanners.scala | 50 ++++----- 2 files changed, 85 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index b2570d64e3..1d5f35b7d6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -40,8 +40,8 @@ trait ParsersCommon extends ScannersCommon { self => */ abstract class ParserCommon { val in: ScannerCommon - def deprecationWarning(off: Int, msg: String): Unit - def accept(token: Int): Int + def deprecationWarning(off: Offset, msg: String): Unit + def accept(token: Token): Int /** Methods inParensOrError and similar take a second argument which, should * the next token not be the expected opener (e.g. LPAREN) will be returned @@ -163,10 +163,10 @@ self => def unit = global.currentUnit // suppress warnings; silent abort on errors - def warning(offset: Int, msg: String) {} - def deprecationWarning(offset: Int, msg: String) {} + def warning(offset: Offset, msg: String) {} + def deprecationWarning(offset: Offset, msg: String) {} - def syntaxError(offset: Int, msg: String): Unit = throw new MalformedInput(offset, msg) + def syntaxError(offset: Offset, msg: String): Unit = throw new MalformedInput(offset, msg) def incompleteInputError(msg: String): Unit = throw new MalformedInput(source.content.length - 1, msg) object symbXMLBuilder extends SymbolicXMLBuilder(this, preserveWS = true) { // DEBUG choices @@ -213,11 +213,11 @@ self => override def newScanner() = new UnitScanner(unit, patches) - override def warning(offset: Int, msg: String) { + override def warning(offset: Offset, msg: String) { unit.warning(o2p(offset), msg) } - override def deprecationWarning(offset: Int, msg: String) { + override def deprecationWarning(offset: Offset, msg: String) { unit.deprecationWarning(o2p(offset), msg) } @@ -235,7 +235,7 @@ self => for ((offset, msg) <- syntaxErrors) unit.error(o2p(offset), msg) - override def syntaxError(offset: Int, msg: String) { + override def syntaxError(offset: Offset, msg: String) { if (smartParsing) syntaxErrors += ((offset, msg)) else unit.error(o2p(offset), msg) } @@ -259,9 +259,10 @@ self => } } - final val Local = 0 - final val InBlock = 1 - final val InTemplate = 2 + type Location = Int + final val Local: Location = 0 + final val InBlock: Location = 1 + final val InTemplate: Location = 2 // These symbols may not yet be loaded (e.g. in the ide) so don't go // through definitions to obtain the names. @@ -293,10 +294,10 @@ self => implicit def fresh: FreshNameCreator = unit.fresh - def o2p(offset: Int): Position = Position.offset(source, offset) - def r2p(start: Int, mid: Int, end: Int): Position = rangePos(source, start, mid, end) - def r2p(start: Int, mid: Int): Position = r2p(start, mid, in.lastOffset max start) - def r2p(offset: Int): Position = r2p(offset, offset) + def o2p(offset: Offset): Position = Position.offset(source, offset) + def r2p(start: Offset, mid: Offset, end: Offset): Position = rangePos(source, start, mid, end) + def r2p(start: Offset, mid: Offset): Position = r2p(start, mid, in.lastOffset max start) + def r2p(offset: Offset): Position = r2p(offset, offset) /** whether a non-continuable syntax error has been seen */ private var lastErrorOffset : Int = -1 @@ -496,7 +497,7 @@ self => finally inFunReturnType = saved } - protected def skip(targetToken: Int) { + protected def skip(targetToken: Token) { var nparens = 0 var nbraces = 0 while (true) { @@ -524,17 +525,17 @@ self => in.nextToken() } } - def warning(offset: Int, msg: String): Unit + def warning(offset: Offset, msg: String): Unit def incompleteInputError(msg: String): Unit private def syntaxError(pos: Position, msg: String, skipIt: Boolean) { syntaxError(pos pointOrElse in.offset, msg, skipIt) } - def syntaxError(offset: Int, msg: String): Unit + def syntaxError(offset: Offset, msg: String): Unit def syntaxError(msg: String, skipIt: Boolean) { syntaxError(in.offset, msg, skipIt) } - def syntaxError(offset: Int, msg: String, skipIt: Boolean) { + def syntaxError(offset: Offset, msg: String, skipIt: Boolean) { if (offset > lastErrorOffset) { syntaxError(offset, msg) // no more errors on this token. @@ -558,10 +559,10 @@ self => } def expectedMsgTemplate(exp: String, fnd: String) = s"$exp expected but $fnd found." - def expectedMsg(token: Int): String = expectedMsgTemplate(token2string(token), token2string(in.token)) + def expectedMsg(token: Token): String = expectedMsgTemplate(token2string(token), token2string(in.token)) /** Consume one token of the specified type, or signal an error if it is not there. */ - def accept(token: Int): Int = { + def accept(token: Token): Offset = { val offset = in.offset if (in.token != token) { syntaxErrorOrIncomplete(expectedMsg(token), skipIt = false) @@ -647,14 +648,14 @@ self => def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT - def isLiteralToken(token: Int) = token match { + def isLiteralToken(token: Token) = token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | INTERPOLATIONID | SYMBOLLIT | TRUE | FALSE | NULL => true case _ => false } def isLiteral = isLiteralToken(in.token) - def isExprIntroToken(token: Int): Boolean = isLiteralToken(token) || (token match { + def isExprIntroToken(token: Token): Boolean = isLiteralToken(token) || (token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE | DO | RETURN | THROW | LPAREN | LBRACE | XMLSTART => true @@ -663,7 +664,7 @@ self => def isExprIntro: Boolean = isExprIntroToken(in.token) - def isTypeIntroToken(token: Int): Boolean = token match { + def isTypeIntroToken(token: Token): Boolean = token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER | USCORE | LPAREN | AT => true case _ => false @@ -673,7 +674,7 @@ self => def isCaseDefEnd = in.token == RBRACE || in.token == CASE || in.token == EOF - def isStatSep(token: Int): Boolean = + def isStatSep(token: Token): Boolean = token == NEWLINE || token == NEWLINES || token == SEMI def isStatSep: Boolean = isStatSep(in.token) @@ -688,10 +689,10 @@ self => /* ---------- TREE CONSTRUCTION ------------------------------------------- */ - def atPos[T <: Tree](offset: Int)(t: T): T = atPos(r2p(offset))(t) - def atPos[T <: Tree](start: Int, point: Int)(t: T): T = atPos(r2p(start, point))(t) - def atPos[T <: Tree](start: Int, point: Int, end: Int)(t: T): T = atPos(r2p(start, point, end))(t) - def atPos[T <: Tree](pos: Position)(t: T): T = global.atPos(pos)(t) + def atPos[T <: Tree](offset: Offset)(t: T): T = atPos(r2p(offset))(t) + def atPos[T <: Tree](start: Offset, point: Offset)(t: T): T = atPos(r2p(start, point))(t) + def atPos[T <: Tree](start: Offset, point: Offset, end: Offset)(t: T): T = atPos(r2p(start, point, end))(t) + 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) @@ -729,7 +730,7 @@ self => } /** {{{ part { `sep` part } }}},or if sepFirst is true, {{{ { `sep` part } }}}. */ - final def tokenSeparated[T](separator: Int, sepFirst: Boolean, part: => T): List[T] = { + final def tokenSeparated[T](separator: Token, sepFirst: Boolean, part: => T): List[T] = { val ts = new ListBuffer[T] if (!sepFirst) ts += part @@ -772,7 +773,7 @@ self => } } - def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = + def checkAssoc(offset: Offset, op: Name, leftAssoc: Boolean) = if (treeInfo.isLeftAssoc(op) != leftAssoc) syntaxError( offset, "left- and right-associative operators with same precedence may not be mixed", skipIt = false) @@ -812,7 +813,7 @@ self => def argType(): Tree def functionArgType(): Tree - private def tupleInfixType(start: Int) = { + private def tupleInfixType(start: Offset) = { in.nextToken() if (in.token == RPAREN) { in.nextToken() @@ -1049,7 +1050,7 @@ self => t } - def selectors(t: Tree, typeOK: Boolean, dotOffset: Int): Tree = + def selectors(t: Tree, typeOK: Boolean, dotOffset: Offset): Tree = if (typeOK && in.token == TYPE) { in.nextToken() atPos(t.pos.start, dotOffset) { SingletonTypeTree(t) } @@ -1107,7 +1108,7 @@ self => * | null * }}} */ - def literal(isNegated: Boolean = false, inPattern: Boolean = false, start: Int = in.offset): Tree = atPos(start) { + def literal(isNegated: Boolean = false, inPattern: Boolean = false, start: Offset = in.offset): Tree = atPos(start) { def finish(value: Any): Tree = try newLiteral(value) finally in.nextToken() if (in.token == SYMBOLLIT) Apply(scalaDot(nme.Symbol), List(finish(in.strVal))) @@ -1204,12 +1205,12 @@ self => in.nextToken() } - def newLineOptWhenFollowedBy(token: Int) { + def newLineOptWhenFollowedBy(token: Offset) { // note: next is defined here because current == NEWLINE if (in.token == NEWLINE && in.next.token == token) newLineOpt() } - def newLineOptWhenFollowing(p: Int => Boolean) { + def newLineOptWhenFollowing(p: Token => Boolean) { // note: next is defined here because current == NEWLINE if (in.token == NEWLINE && p(in.next.token)) newLineOpt() } @@ -1224,7 +1225,7 @@ self => if (in.token == COLON) { in.nextToken(); typ() } else TypeTree() - def typeOrInfixType(location: Int): Tree = + def typeOrInfixType(location: Location): Tree = if (location == Local) typ() else startInfixType() @@ -1235,7 +1236,7 @@ self => * WildcardType ::= `_' TypeBounds * }}} */ - def wildcardType(start: Int) = { + def wildcardType(start: Offset) = { val pname = freshTypeName("_$") val t = atPos(start)(Ident(pname)) val bounds = typeBounds() @@ -1261,7 +1262,7 @@ self => /* hook for IDE, unlike expression can be stubbed * don't use for any tree that can be inspected in the parser! */ - def statement(location: Int): Tree = expr(location) // !!! still needed? + def statement(location: Location): Tree = expr(location) // !!! still needed? /** {{{ * Expr ::= (Bindings | [`implicit'] Id | `_') `=>' Expr @@ -1288,9 +1289,9 @@ self => */ def expr(): Tree = expr(Local) - def expr(location: Int): Tree = withPlaceholders(expr0(location), isAny = false) + def expr(location: Location): Tree = withPlaceholders(expr0(location), isAny = false) - def expr0(location: Int): Tree = (in.token: @scala.annotation.switch) match { + def expr0(location: Location): Tree = (in.token: @scala.annotation.switch) match { case IF => def parseIf = atPos(in.skipToken()) { val cond = condExpr() @@ -1448,7 +1449,7 @@ self => * }}} */ - def implicitClosure(start: Int, location: Int): Tree = { + def implicitClosure(start: Offset, location: Location): Tree = { val param0 = convertToParam { atPos(in.offset) { Ident(ident()) match { @@ -1712,7 +1713,7 @@ self => while (in.token == IF) enums += makeFilter(in.offset, guard()) } - def makeFilter(start: Int, tree: Tree) = Filter(r2p(start, tree.pos.point, tree.pos.end), tree) + def makeFilter(start: Offset, tree: Tree) = Filter(r2p(start, tree.pos.point, tree.pos.end), tree) /* -------- PATTERNS ------------------------------------------- */ @@ -2276,7 +2277,7 @@ self => t setPos o2p(in.offset) } - def bound(tok: Int): Tree = if (in.token == tok) { in.nextToken(); typ() } else EmptyTree + def bound(tok: Token): Tree = if (in.token == tok) { in.nextToken(); typ() } else EmptyTree /* -------- DEFS ------------------------------------------- */ @@ -2395,7 +2396,7 @@ self => * | type [nl] TypeDcl * }}} */ - def defOrDcl(pos: Int, mods: Modifiers): List[Tree] = { + def defOrDcl(pos: Offset, mods: Modifiers): List[Tree] = { if (mods.isLazy && in.token != VAL) syntaxError("lazy not allowed here. Only vals can be lazy", skipIt = false) in.token match { @@ -2524,7 +2525,7 @@ self => } } - def funDefRest(start: Int, nameOffset: Int, mods: Modifiers, name: Name): Tree = { + def funDefRest(start: Offset, nameOffset: Offset, mods: Modifiers, name: Name): Tree = { val result = atPos(start, if (name.toTermName == nme.ERROR) start else nameOffset) { var newmods = mods // contextBoundBuf is for context bounded type parameters of the form @@ -2607,7 +2608,7 @@ self => * TypeDcl ::= type Id [TypeParamClause] TypeBounds * }}} */ - def typeDefOrDcl(start: Int, mods: Modifiers): Tree = { + def typeDefOrDcl(start: Offset, mods: Modifiers): Tree = { in.nextToken() newLinesOpt() atPos(start, in.offset) { @@ -2640,7 +2641,7 @@ self => * | [override] trait TraitDef * }}} */ - def tmplDef(pos: Int, mods: Modifiers): Tree = { + def tmplDef(pos: Offset, mods: Modifiers): Tree = { if (mods.isLazy) syntaxError("classes cannot be lazy", skipIt = false) in.token match { case TRAIT => @@ -2664,7 +2665,7 @@ self => * TraitDef ::= Id [TypeParamClause] RequiresTypeOpt TraitTemplateOpt * }}} */ - def classDef(start: Int, mods: Modifiers): ClassDef = { + def classDef(start: Offset, mods: Modifiers): ClassDef = { in.nextToken() val nameOffset = in.offset val name = identForType() @@ -2704,7 +2705,7 @@ self => * ObjectDef ::= Id ClassTemplateOpt * }}} */ - def objectDef(start: Int, mods: Modifiers): ModuleDef = { + def objectDef(start: Offset, mods: Modifiers): ModuleDef = { in.nextToken() val nameOffset = in.offset val name = ident() @@ -2743,7 +2744,7 @@ self => ) // 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 { + def makePackageObject(start: Offset, objDef: ModuleDef): PackageDef = objDef match { case ModuleDef(mods, name, impl) => makePackaging( start, atPos(o2p(objDef.pos.start)){ Ident(name) }, List(ModuleDef(mods, nme.PACKAGEkw, impl))) @@ -2818,7 +2819,7 @@ self => * TraitExtends ::= `extends' | `<:' * }}} */ - def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = { + def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Offset): Template = { val (parents, self, body) = ( if (in.token == EXTENDS || in.token == SUBTYPE && mods.isTrait) { in.nextToken() @@ -2881,17 +2882,17 @@ self => /* -------- STATSEQS ------------------------------------------- */ /** Create a tree representing a packaging. */ - def makePackaging(start: Int, pkg: Tree, stats: List[Tree]): PackageDef = pkg match { + def makePackaging(start: Offset, pkg: Tree, stats: List[Tree]): PackageDef = pkg match { case x: RefTree => atPos(start, pkg.pos.point)(PackageDef(x, stats)) } - def makeEmptyPackage(start: Int, stats: List[Tree]): PackageDef = ( + def makeEmptyPackage(start: Offset, stats: List[Tree]): PackageDef = ( makePackaging(start, atPos(start, start, start)(Ident(nme.EMPTY_PACKAGE_NAME)), stats) ) - def statSeq(stat: PartialFunction[Int, List[Tree]], errorMsg: String = "illegal start of definition"): List[Tree] = { + def statSeq(stat: PartialFunction[Token, List[Tree]], errorMsg: String = "illegal start of definition"): List[Tree] = { val stats = new ListBuffer[Tree] - def default(tok: Int) = + def default(tok: Token) = if (isStatSep) Nil else syntaxErrorOrIncompleteAnd(errorMsg, skipIt = true)(Nil) while (!isStatSeqEnd) { @@ -2911,7 +2912,7 @@ self => * }}} */ def topStatSeq(): List[Tree] = statSeq(topStat, errorMsg = "expected class or object definition") - def topStat: PartialFunction[Int, List[Tree]] = { + def topStat: PartialFunction[Token, List[Tree]] = { case PACKAGE => packageOrPackageObject(in.skipToken()) :: Nil case IMPORT => @@ -2963,7 +2964,7 @@ self => * }}} */ def templateStats(): List[Tree] = statSeq(templateStat) - def templateStat: PartialFunction[Int, List[Tree]] = { + def templateStat: PartialFunction[Token, List[Tree]] = { case IMPORT => in.flushDoc importClause() diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 6957f85689..b12be1a056 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -21,19 +21,24 @@ trait ScannersCommon { val global : Global import global._ + /** Offset into source character array */ + type Offset = Int + + type Token = Int + trait CommonTokenData { - def token: Int + def token: Token def name: TermName } trait ScannerCommon extends CommonTokenData { // things to fill in, in addition to buf, decodeUni which come from CharArrayReader - def error (off: Int, msg: String): Unit - def incompleteInputError(off: Int, msg: String): Unit - def deprecationWarning(off: Int, msg: String): Unit + def error(off: Offset, msg: String): Unit + def incompleteInputError(off: Offset, msg: String): Unit + def deprecationWarning(off: Offset, msg: String): Unit } - def createKeywordArray(keywords: Seq[(Name, Int)], defaultToken: Int): (Int, Array[Int]) = { + def createKeywordArray(keywords: Seq[(Name, Token)], defaultToken: Token): (Token, Array[Token]) = { val names = keywords sortBy (_._1.start) map { case (k, v) => (k.start, v) } val low = names.head._1 val high = names.last._1 @@ -48,13 +53,10 @@ trait Scanners extends ScannersCommon { val global : Global import global._ - /** Offset into source character array */ - type Offset = Int - trait TokenData extends CommonTokenData { /** the next token */ - var token: Int = EMPTY + var token: Token = EMPTY /** the offset of the first character of the current token */ var offset: Offset = 0 @@ -169,7 +171,7 @@ trait Scanners extends ScannersCommon { def isAtEnd = charOffset >= buf.length - def resume(lastCode: Int) = { + def resume(lastCode: Token) = { token = lastCode if (next.token != EMPTY && !reporter.hasErrors) syntaxError("unexpected end of input: possible missing '}' in XML block") @@ -194,7 +196,7 @@ trait Scanners extends ScannersCommon { protected def emitIdentifierDeprecationWarnings = true /** Clear buffer and set name and token */ - private def finishNamed(idtoken: Int = IDENTIFIER) { + private def finishNamed(idtoken: Token = IDENTIFIER) { name = newTermName(cbuf.toString) cbuf.clear() token = idtoken @@ -225,7 +227,7 @@ trait Scanners extends ScannersCommon { * (the STRINGLIT appears twice in succession on the stack iff the * expression is a multiline string literal). */ - var sepRegions: List[Int] = List() + var sepRegions: List[Token] = List() // Get next token ------------------------------------------------------------ @@ -583,7 +585,7 @@ trait Scanners extends ScannersCommon { } /** Can token start a statement? */ - def inFirstOfStat(token: Int) = token match { + def inFirstOfStat(token: Token) = token match { case EOF | CATCH | ELSE | EXTENDS | FINALLY | FORSOME | MATCH | WITH | YIELD | COMMA | SEMI | NEWLINE | NEWLINES | DOT | COLON | EQUALS | ARROW | LARROW | SUBTYPE | VIEWBOUND | SUPERTYPE | HASH | RPAREN | RBRACKET | RBRACE | LBRACKET => @@ -593,7 +595,7 @@ trait Scanners extends ScannersCommon { } /** Can token end a statement? */ - def inLastOfStat(token: Int) = token match { + def inLastOfStat(token: Token) = token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | IDENTIFIER | BACKQUOTED_IDENT | THIS | NULL | TRUE | FALSE | RETURN | USCORE | TYPE | XMLSTART | RPAREN | RBRACKET | RBRACE => @@ -1122,7 +1124,7 @@ trait Scanners extends ScannersCommon { def applyBracePatch(): Boolean = false /** overridden in UnitScanners */ - def parenBalance(token: Int) = 0 + def parenBalance(token: Token) = 0 /** overridden in UnitScanners */ def healBraces(): List[BracePatch] = List() @@ -1137,7 +1139,7 @@ trait Scanners extends ScannersCommon { // ------------- keyword configuration ----------------------------------- - private val allKeywords = List[(Name, Int)]( + private val allKeywords = List[(Name, Token)]( nme.ABSTRACTkw -> ABSTRACT, nme.CASEkw -> CASE, nme.CATCHkw -> CATCH, @@ -1191,8 +1193,8 @@ trait Scanners extends ScannersCommon { nme.MACROkw -> IDENTIFIER, nme.THENkw -> IDENTIFIER) - private var kwOffset: Int = -1 - private val kwArray: Array[Int] = { + private var kwOffset: Offset = -1 + private val kwArray: Array[Token] = { val (offset, arr) = createKeywordArray(allKeywords, IDENTIFIER) kwOffset = offset arr @@ -1203,7 +1205,7 @@ trait Scanners extends ScannersCommon { // Token representation ---------------------------------------------------- /** Returns the string representation of given token. */ - def token2string(token: Int): String = (token: @switch) match { + def token2string(token: Token): String = (token: @switch) match { case IDENTIFIER | BACKQUOTED_IDENT => "identifier" case CHARLIT => "character literal" case INTLIT => "integer literal" @@ -1234,7 +1236,7 @@ trait Scanners extends ScannersCommon { } } - class MalformedInput(val offset: Int, val msg: String) extends Exception + class MalformedInput(val offset: Offset, val msg: String) extends Exception /** A scanner for a given source file not necessarily attached to a compilation unit. * Useful for looking inside source files that aren not currently compiled to see what's there @@ -1262,7 +1264,7 @@ trait Scanners extends ScannersCommon { lazy val parensAnalyzer = new ParensAnalyzer(unit, List()) - override def parenBalance(token: Int) = parensAnalyzer.balance(token) + override def parenBalance(token: Token) = parensAnalyzer.balance(token) override def healBraces(): List[BracePatch] = { var patches: List[BracePatch] = List() @@ -1412,7 +1414,7 @@ trait Scanners extends ScannersCommon { var tabSeen = false - def line(offset: Int): Int = { + def line(offset: Offset): Int = { def findLine(lo: Int, hi: Int): Int = { val mid = (lo + hi) / 2 if (offset < lineStart(mid)) findLine(lo, mid - 1) @@ -1423,7 +1425,7 @@ trait Scanners extends ScannersCommon { else findLine(0, lineStart.length - 1) } - def column(offset: Int): Int = { + def column(offset: Offset): Int = { var col = 0 var i = offset - 1 while (i >= 0 && buf(i) != CR && buf(i) != LF) { @@ -1485,6 +1487,6 @@ trait Scanners extends ScannersCommon { // when skimming through the source file trying to heal braces override def emitIdentifierDeprecationWarnings = false - override def error(offset: Int, msg: String) {} + override def error(offset: Offset, msg: String) {} } } -- cgit v1.2.3 From d3e04daa658170ffc58f2e1ea3da0f4d55f001a7 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 18 Oct 2013 14:57:16 +0200 Subject: annotate return type of the implicit fresh name creator --- src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 71e9274d37..0b5ade0b4c 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -55,12 +55,12 @@ trait Parsers { self: Quasiquotes => def isHole(name: Name): Boolean = holeMap.contains(name) - override implicit def fresh = new FreshNameCreator { + override implicit def fresh: FreshNameCreator = new FreshNameCreator { override def newName(prefix: String) = super.newName(nme.QUASIQUOTE_PREFIX + prefix) } override val treeBuilder = new ParserTreeBuilder { - override implicit def fresh = parser.fresh + override implicit def fresh: FreshNameCreator = parser.fresh // q"(..$xs)" override def makeTupleTerm(trees: List[Tree], flattenUnary: Boolean): Tree = -- cgit v1.2.3