From c73f30922f246a7f2afae8e9e52acce2fdbf4d8d Mon Sep 17 00:00:00 2001 From: Denys Shabalin Date: Wed, 5 Feb 2014 16:07:44 +0100 Subject: Add support for a more straightforward alternative to import selectors --- .../scala/tools/reflect/quasiquotes/Reifiers.scala | 2 + src/reflect/scala/reflect/api/BuildUtils.scala | 6 + .../scala/reflect/internal/BuildUtils.scala | 142 ++++++++++++++++++++- .../scala/reflect/internal/FreshNames.scala | 8 +- src/reflect/scala/reflect/internal/StdNames.scala | 35 ++--- 5 files changed, 172 insertions(+), 21 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 2eb50d5993..017e966f63 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -192,6 +192,8 @@ trait Reifiers { self: Quasiquotes => reifyBuildCall(nme.SyntacticIdent, name, isBackquoted) case SyntacticEmptyTypeTree() => reifyBuildCall(nme.SyntacticEmptyTypeTree) + case SyntacticImport(expr, selectors) => + reifyBuildCall(nme.SyntacticImport, expr, selectors) case Q(Placeholder(Hole(tree, DotDot))) => mirrorBuildCall(nme.SyntacticBlock, tree) case Q(other) => diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index f2932792dd..ec20a89a10 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -290,5 +290,11 @@ private[reflect] trait BuildUtils { self: Universe => def apply(name: Name, isBackquoted: Boolean = false): Ident def unapply(tree: Ident): Option[(Name, Boolean)] } + + val SyntacticImport: SyntacticImportExtractor + trait SyntacticImportExtractor { + def apply(expr: Tree, selectors: List[Tree]): Import + def unapply(imp: Import): Some[(Tree, List[Tree])] + } } } diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 9281367138..3c64754e62 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -143,7 +143,7 @@ trait BuildUtils { self: SymbolTable => def RefTree(qual: Tree, sym: Symbol) = self.RefTree(qual, sym.name) setSymbol sym - def freshTermName(prefix: String): TermName = self.freshTermName(prefix) + def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX): TermName = self.freshTermName(prefix) def freshTypeName(prefix: String): TypeName = self.freshTypeName(prefix) @@ -769,6 +769,146 @@ trait BuildUtils { self: SymbolTable => } def unapply(tree: Ident): Some[(Name, Boolean)] = Some((tree.name, tree.hasAttachment[BackquotedIdentifierAttachment.type])) } + + /** Facade over Imports and ImportSelectors that lets to structurally + * deconstruct/reconstruct them. + * + * Selectors are represented in the following way: + * 1. q"import foo._" <==> q"import foo.${pq"_"}" + * 2. q"import foo.bar" <==> q"import foo.${pq"bar"}" + * 3. q"import foo.{bar => baz}" <==> q"import foo.${pq"bar -> baz"}" + * 4. q"import foo.{bar => _}" <==> q"import foo.${pq"bar -> _"}" + * + * All names in selectors are TermNames despite the fact ImportSelector + * can theoretically contain TypeNames too (but they never do in practice.) + */ + object SyntacticImport extends SyntacticImportExtractor { + // construct/deconstruct {_} import selector + private object WildcardSelector { + def apply(offset: Int): ImportSelector = ImportSelector(nme.WILDCARD, offset, null, -1) + def unapply(sel: ImportSelector): Option[Int] = sel match { + case ImportSelector(nme.WILDCARD, offset, null, -1) => Some(offset) + case _ => None + } + } + + // construct/deconstruct {foo} import selector + private object NameSelector { + def apply(name: TermName, offset: Int): ImportSelector = ImportSelector(name, offset, name, offset) + def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match { + case ImportSelector(name1, offset1, name2, offset2) if name1 == name2 && offset1 == offset2 => + Some((name1.toTermName, offset1)) + case _ => + None + } + } + + // construct/deconstruct {foo => bar} import selector + private object RenameSelector { + def apply(name1: TermName, offset1: Int, name2: TermName, offset2: Int): ImportSelector = + ImportSelector(name1, offset1, name2, offset2) + def unapply(sel: ImportSelector): Option[(TermName, Int, TermName, Int)] = sel match { + case ImportSelector(_, _, null | nme.WILDCARD, _) => + None + case ImportSelector(name1, offset1, name2, offset2) if name1 != name2 => + Some((name1.toTermName, offset1, name2.toTermName, offset2)) + case _ => + None + } + } + + // construct/deconstruct {foo => _} import selector + private object UnimportSelector { + def apply(name: TermName, offset: Int): ImportSelector = + ImportSelector(name, offset, nme.WILDCARD, -1) + def unapply(sel: ImportSelector): Option[(TermName, Int)] = sel match { + case ImportSelector(name, offset, nme.WILDCARD, _) => Some((name.toTermName, offset)) + case _ => None + } + } + + // represent {_} import selector as pq"_" + private object WildcardSelectorRepr { + def apply(pos: Position): Tree = atPos(pos)(self.Ident(nme.WILDCARD)) + def unapply(tree: Tree): Option[Position] = tree match { + case self.Ident(nme.WILDCARD) => Some(tree.pos) + case _ => None + } + } + + // represent {foo} import selector as pq"foo" + private object NameSelectorRepr { + def apply(name: TermName, pos: Position): Tree = atPos(pos)(Bind(name, WildcardSelectorRepr(pos))) + def unapply(tree: Tree): Option[(TermName, Position)] = tree match { + case Bind(name, WildcardSelectorRepr(_)) => Some((name.toTermName, tree.pos)) + case _ => None + } + } + + // pq"left -> right" + private object Arrow { + def apply(left: Tree, right: Tree): Apply = + Apply(self.Ident(nme.MINGT), left :: right :: Nil) + def unapply(tree: Apply): Option[(Tree, Tree)] = tree match { + case Apply(self.Ident(nme.MINGT), left :: right :: Nil) => Some((left, right)) + case _ => None + } + } + + // represent {foo => bar} import selector as pq"foo -> bar" + private object RenameSelectorRepr { + def apply(name1: TermName, pos1: Position, name2: TermName, pos2: Position): Tree = { + val left = NameSelectorRepr(name1, pos1) + val right = NameSelectorRepr(name2, pos2) + atPos(wrappingPos(left :: right :: Nil))(Arrow(left, right)) + } + def unapply(tree: Tree): Option[(TermName, Position, TermName, Position)] = tree match { + case Arrow(NameSelectorRepr(name1, pos1), NameSelectorRepr(name2, pos2)) => + Some((name1.toTermName, pos1, name2.toTermName, pos2)) + case _ => + None + } + } + + // represent {foo => _} import selector as pq"foo -> _" + private object UnimportSelectorRepr { + def apply(name: TermName, pos: Position): Tree = + atPos(pos)(Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(pos))) + def unapply(tree: Tree): Option[(TermName, Position)] = tree match { + case Arrow(NameSelectorRepr(name, pos), WildcardSelectorRepr(_)) => + Some((name, pos)) + case _ => + None + } + } + + private def derivedPos(t: Tree, offset: Int): Position = + if (t.pos == NoPosition) NoPosition else t.pos.withPoint(offset) + + private def derivedOffset(pos: Position): Int = + if (pos == NoPosition) -1 else pos.point + + def apply(expr: Tree, selectors: List[Tree]): Import = { + val importSelectors = selectors.map { + case WildcardSelectorRepr(pos) => WildcardSelector(derivedOffset(pos)) + case NameSelectorRepr(name, pos) => NameSelector(name, derivedOffset(pos)) + case RenameSelectorRepr(name1, pos1, name2, pos2) => RenameSelector(name1, derivedOffset(pos1), name2, derivedOffset(pos2)) + case UnimportSelectorRepr(name, pos) => UnimportSelector(name, derivedOffset(pos)) + case tree => throw new IllegalArgumentException(s"${showRaw(tree)} doesn't correspond to import selector") + } + Import(expr, importSelectors) + } + + def unapply(imp: Import): Some[(Tree, List[Tree])] = { + val selectors = imp.selectors.map { + case WildcardSelector(offset) => WildcardSelectorRepr(derivedPos(imp, offset)) + case NameSelector(name, offset) => NameSelectorRepr(name, derivedPos(imp, offset)) + case RenameSelector(name1, offset1, name2, offset2) => RenameSelectorRepr(name1, derivedPos(imp, offset1), name2, derivedPos(imp, offset2)) + case UnimportSelector(name, offset) => UnimportSelectorRepr(name, derivedPos(imp, offset)) + } + Some((imp.expr, selectors)) + } + } } val build: BuildImpl = new BuildImpl diff --git a/src/reflect/scala/reflect/internal/FreshNames.scala b/src/reflect/scala/reflect/internal/FreshNames.scala index 1de8d425ad..7e9a568266 100644 --- a/src/reflect/scala/reflect/internal/FreshNames.scala +++ b/src/reflect/scala/reflect/internal/FreshNames.scala @@ -8,7 +8,7 @@ package internal import scala.reflect.internal.util.FreshNameCreator -trait FreshNames { self: Names => +trait FreshNames { self: Names with StdNames => // SI-6879 Keeps track of counters that are supposed to be globally unique // as opposed to traditional freshers that are unique to compilation units. val globalFreshNameCreator = new FreshNameCreator @@ -17,8 +17,8 @@ trait FreshNames { self: Names => def currentFreshNameCreator: FreshNameCreator // create fresh term/type name using implicit fresh name creator - 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)) + def freshTermName(prefix: String = nme.FRESH_TERM_NAME_PREFIX)(implicit creator: FreshNameCreator): TermName = newTermName(creator.newName(prefix)) + def freshTypeName(prefix: String)(implicit creator: FreshNameCreator): TypeName = newTypeName(creator.newName(prefix)) // Extractor that matches names which were generated by some // FreshNameCreator with known prefix. Extracts user-specified @@ -36,4 +36,4 @@ trait FreshNames { self: Names => else Some(NameTransformer.decode(sname.replaceFirst(quotedCreatorPrefix, "").replaceAll("\\d*$", ""))) } } -} \ No newline at end of file +} diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 7c979e7bdc..679186f938 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -295,22 +295,23 @@ trait StdNames { protected implicit def createNameType(name: String): TermName = newTermNameCached(name) /** Base strings from which synthetic names are derived. */ - val BITMAP_PREFIX = "bitmap$" - val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$" - val DEFAULT_GETTER_STRING = "$default$" - val DEFAULT_GETTER_INIT_STRING = NameTransformer.encode("") + DEFAULT_GETTER_STRING - val DO_WHILE_PREFIX = "doWhile$" - val EVIDENCE_PARAM_PREFIX = "evidence$" - val EXCEPTION_RESULT_PREFIX = "exceptionResult" - val EXPAND_SEPARATOR_STRING = "$$" - val INTERPRETER_IMPORT_WRAPPER = "$iw" - val LOCALDUMMY_PREFIX = "") + DEFAULT_GETTER_STRING + val DO_WHILE_PREFIX = "doWhile$" + val EVIDENCE_PARAM_PREFIX = "evidence$" + val EXCEPTION_RESULT_PREFIX = "exceptionResult" + val EXPAND_SEPARATOR_STRING = "$$" + val FRESH_TERM_NAME_PREFIX = "x$" + val INTERPRETER_IMPORT_WRAPPER = "$iw" + val LOCALDUMMY_PREFIX = ">>") val LT = encode("<") val MINUS = encode("-") + val MINGT = encode("->") val MOD = encode("%") val MUL = encode("*") val NE = encode("!=") -- cgit v1.2.3