diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-09-11 00:25:07 -0700 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-09-11 00:25:07 -0700 |
commit | 6c78a2800c2cd8fe709a290c3575e578ceb35eb0 (patch) | |
tree | c47cf7d5bd816d30349ef1ad9057b79750582262 /src/compiler/scala/tools | |
parent | 71dc4c0e162e880048388b2dc82de528d7c9c497 (diff) | |
parent | cdac66f750acb6fbf000215b8534f27f51da00a3 (diff) | |
download | scala-6c78a2800c2cd8fe709a290c3575e578ceb35eb0.tar.gz scala-6c78a2800c2cd8fe709a290c3575e578ceb35eb0.tar.bz2 scala-6c78a2800c2cd8fe709a290c3575e578ceb35eb0.zip |
Merge pull request #2910 from densh/topic/quasiquote-improvement-final
Various bugfixes and improvements for the quasiquotes
Diffstat (limited to 'src/compiler/scala/tools')
8 files changed, 225 insertions, 199 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index ad1977b9aa..7122e864a4 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -264,42 +264,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { mkNew(Nil, emptyValDef, stats1, NoPosition, NoPosition) } - /** Create positioned tree representing an object creation <new parents { stats } - * @param npos the position of the new - * @param cpos the position of the anonymous class starting with parents - */ - def mkNew(parents: List[Tree], self: ValDef, stats: List[Tree], - npos: Position, cpos: Position): Tree = - if (parents.isEmpty) - mkNew(List(scalaAnyRefConstr), self, stats, npos, cpos) - else if (parents.tail.isEmpty && stats.isEmpty) { - // `Parsers.template` no longer differentiates tpts and their argss - // e.g. `C()` will be represented as a single tree Apply(Ident(C), Nil) - // instead of parents = Ident(C), argss = Nil as before - // this change works great for things that are actually templates - // but in this degenerate case we need to perform postprocessing - val app = treeInfo.dissectApplied(parents.head) - atPos(npos union cpos) { New(app.callee, app.argss) } - } else { - val x = tpnme.ANON_CLASS_NAME - atPos(npos union cpos) { - Block( - List( - atPos(cpos) { - ClassDef( - Modifiers(FINAL), x, Nil, - mkTemplate(parents, self, NoMods, ListOfNil, stats, cpos.focus)) - }), - atPos(npos) { - New( - Ident(x) setPos npos.focus, - Nil) - } - ) - } - } - def mkSyntheticParam(pname: TermName) = ValDef(Modifiers(PARAM | SYNTHETIC), pname, TypeTree(), EmptyTree) - } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 6a09f9f07c..52aa11cb40 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1445,7 +1445,7 @@ self => // The case still missed is unparenthesized single argument, like "x: Int => x + 1", which // may be impossible to distinguish from a self-type and so remains an error. (See #1564) def lhsIsTypedParamList() = t match { - case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true + case Parens(xs) if xs.forall(isTypedParam) => true case _ => false } if (in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)) { @@ -1458,6 +1458,8 @@ self => parseOther } + def isTypedParam(t: Tree) = t.isInstanceOf[Typed] + /** {{{ * Expr ::= implicit Id => Expr * }}} @@ -2704,8 +2706,7 @@ self => syntaxError("classes are not allowed to be virtual", skipIt = false) } val template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss, tstart) - if (isInterface(mods1, template.body)) mods1 |= Flags.INTERFACE - val result = ClassDef(mods1, name, tparams, template) + val result = gen.mkClassDef(mods1, name, tparams, template) // Context bounds generate implicit parameters (part of the template) with types // from tparams: we need to ensure these don't overlap if (!classContextBounds.isEmpty) @@ -2796,17 +2797,7 @@ self => // @S: pre template body cannot stub like post body can! val (self, body) = templateBody(isPre = true) if (in.token == WITH && (self eq emptyValDef)) { - val earlyDefs: List[Tree] = body flatMap { - case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred => - List(copyValDef(vdef)(mods = mods | Flags.PRESUPER)) - case tdef @ TypeDef(mods, name, tparams, rhs) => - deprecationWarning(tdef.pos.point, "early type members are deprecated. Move them to the regular body: the semantics are the same.") - List(treeCopy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs)) - case stat if !stat.isEmpty => - syntaxError(stat.pos, "only concrete field definitions allowed in early object initialization section", skipIt = false) - List() - case _ => List() - } + val earlyDefs: List[Tree] = body.map(ensureEarlyDef).filter(_.nonEmpty) in.nextToken() val parents = templateParents() val (self1, body1) = templateBodyOpt(parenMeansSyntaxError = false) @@ -2821,8 +2812,18 @@ self => } } - def isInterface(mods: Modifiers, body: List[Tree]): Boolean = - mods.isTrait && (body forall treeInfo.isInterfaceMember) + def ensureEarlyDef(tree: Tree): Tree = tree match { + case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred => + copyValDef(vdef)(mods = mods | Flags.PRESUPER) + case tdef @ TypeDef(mods, name, tparams, rhs) => + deprecationWarning(tdef.pos.point, "early type members are deprecated. Move them to the regular body: the semantics are the same.") + treeCopy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs) + case stat if !stat.isEmpty => + syntaxError(stat.pos, "only concrete field definitions allowed in early object initialization section", skipIt = false) + EmptyTree + case _ => + EmptyTree + } /** {{{ * ClassTemplateOpt ::= `extends' ClassTemplate | [[`extends'] TemplateBody] @@ -2831,7 +2832,7 @@ self => * }}} */ def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = { - val (parents0, self, body) = ( + val (parents, self, body) = ( if (in.token == EXTENDS || in.token == SUBTYPE && mods.isTrait) { in.nextToken() template() @@ -2842,26 +2843,21 @@ self => (List(), self, body) } ) - def anyrefParents() = { - val caseParents = if (mods.isCase) List(productConstr, serializableConstr) else Nil - parents0 ::: caseParents match { - case Nil => atInPos(scalaAnyRefConstr) :: Nil - case ps => ps - } - } def anyvalConstructor() = ( // Not a well-formed constructor, has to be finished later - see note // regarding AnyVal constructor in AddInterfaces. DefDef(NoMods, nme.CONSTRUCTOR, Nil, ListOfNil, TypeTree(), Block(Nil, literalUnit)) ) - val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart + val parentPos = o2p(in.offset) + val tstart1 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart - atPos(tstart0) { + atPos(tstart1) { // Exclude only the 9 primitives plus AnyVal. if (inScalaRootPackage && ScalaValueClassNames.contains(name)) - Template(parents0, self, anyvalConstructor :: body) + Template(parents, self, anyvalConstructor :: body) else - gen.mkTemplate(anyrefParents(), self, constrMods, vparamss, body, o2p(tstart)) + gen.mkTemplate(gen.mkParents(mods, parents, parentPos), + self, constrMods, vparamss, body, o2p(tstart)) } } @@ -3012,19 +3008,23 @@ self => def refineStatSeq(): List[Tree] = checkNoEscapingPlaceholders { val stats = new ListBuffer[Tree] while (!isStatSeqEnd) { - if (isDclIntro) { // don't IDE hook - stats ++= joinComment(defOrDcl(in.offset, NoMods)) - } else if (!isStatSep) { - syntaxErrorOrIncomplete( - "illegal start of declaration"+ - (if (inFunReturnType) " (possible cause: missing `=' in front of current method body)" - else ""), skipIt = true) - } + stats ++= refineStat() if (in.token != RBRACE) acceptStatSep() } stats.toList } + def refineStat(): List[Tree] = + if (isDclIntro) { // don't IDE hook + joinComment(defOrDcl(in.offset, NoMods)) + } else if (!isStatSep) { + syntaxErrorOrIncomplete( + "illegal start of declaration"+ + (if (inFunReturnType) " (possible cause: missing `=' in front of current method body)" + else ""), skipIt = true) + Nil + } else Nil + /** overridable IDE hook for local definitions of blockStatSeq * Here's an idea how to fill in start and end positions. def localDef : List[Tree] = { diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index ed694023d7..28e3217449 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -229,11 +229,7 @@ abstract class TreeBuilder { } /** Create block of statements `stats` */ - def makeBlock(stats: List[Tree]): Tree = - if (stats.isEmpty) Literal(Constant(())) - else if (!stats.last.isTerm) Block(stats, Literal(Constant(()))) - else if (stats.length == 1) stats.head - else Block(stats.init, stats.last) + def makeBlock(stats: List[Tree]): Tree = gen.mkBlock(stats) def makeFilter(tree: Tree, condition: Tree, scrutineeName: String): Tree = { val cases = List( @@ -520,8 +516,7 @@ abstract class TreeBuilder { } /** Create a tree representing the function type (argtpes) => restpe */ - def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = - AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe)) + def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = gen.mkFunctionTypeTree(argtpes, restpe) /** Append implicit parameter section if `contextBounds` nonempty */ def addEvidenceParams(owner: Name, vparamss: List[List[ValDef]], contextBounds: List[Tree]): List[List[ValDef]] = { diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index cbe4f69d25..2ec7e97ac5 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -174,7 +174,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { omittables ++= outerCandidatesForElision val bodyOfOuterAccessor: Map[Symbol, DefDef] = - defBuf collect { case dd: DefDef if outerCandidatesForElision(dd.symbol) => dd.symbol -> dd } toMap + defBuf.collect { case dd: DefDef if outerCandidatesForElision(dd.symbol) => dd.symbol -> dd }.toMap // no point traversing further once omittables is empty, all candidates ruled out already. object detectUsages extends Traverser { diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index 18a806e5ff..19888fa8d2 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -50,6 +50,10 @@ trait Parsers { self: Quasiquotes => def entryPoint: QuasiquoteParser => Tree class QuasiquoteParser(source0: SourceFile) extends SourceFileParser(source0) { + def isHole: Boolean = isIdent && isHole(in.name) + + def isHole(name: Name): Boolean = holeMap.contains(name) + override val treeBuilder = new ParserTreeBuilder { // q"(..$xs)" override def makeTupleTerm(trees: List[Tree], flattenUnary: Boolean): Tree = @@ -61,9 +65,13 @@ trait Parsers { self: Quasiquotes => // q"{ $x }" override def makeBlock(stats: List[Tree]): Tree = stats match { - case (head @ Ident(name)) :: Nil if holeMap.contains(name) => Block(Nil, head) + case (head @ Ident(name)) :: Nil if isHole(name) => Block(Nil, head) case _ => super.makeBlock(stats) } + + // tq"$a => $b" + override def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = + AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), argtpes :+ restpe) } import treeBuilder.{global => _, _} @@ -79,7 +87,10 @@ trait Parsers { self: Quasiquotes => } else super.caseClause() - def isHole: Boolean = isIdent && holeMap.contains(in.name) + override def caseBlock(): Tree = super.caseBlock() match { + case Block(Nil, expr) => expr + case other => other + } override def isAnnotation: Boolean = super.isAnnotation || (isHole && lookingAhead { isAnnotation }) @@ -105,13 +116,30 @@ trait Parsers { self: Quasiquotes => case AT => in.nextToken() annot :: readAnnots(annot) - case _ if isHole && lookingAhead { in.token == AT || isModifier || isDefIntro || isIdent} => + case _ if isHole && lookingAhead { isAnnotation || isModifier || isDefIntro || isIdent || isStatSep || in.token == LPAREN } => val ann = Apply(Select(New(Ident(tpnme.QUASIQUOTE_MODS)), nme.CONSTRUCTOR), List(Literal(Constant(in.name.toString)))) in.nextToken() ann :: readAnnots(annot) case _ => Nil } + + override def refineStat(): List[Tree] = + if (isHole && !isDclIntro) { + val result = ValDef(NoMods, in.name, Ident(tpnme.QUASIQUOTE_REFINE_STAT), EmptyTree) :: Nil + in.nextToken() + result + } else super.refineStat() + + override def ensureEarlyDef(tree: Tree) = tree match { + case Ident(name: TermName) if isHole(name) => ValDef(NoMods | Flag.PRESUPER, name, Ident(tpnme.QUASIQUOTE_EARLY_DEF), EmptyTree) + case _ => super.ensureEarlyDef(tree) + } + + override def isTypedParam(tree: Tree) = super.isTypedParam(tree) || (tree match { + case Ident(name) if isHole(name) => true + case _ => false + }) } } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala index b3ac1e293a..e20d98c0f1 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala @@ -92,10 +92,9 @@ trait Placeholders { self: Quasiquotes => } } - object AnnotPlaceholder { - def unapply(tree: Tree): Option[(Tree, Location, Cardinality, List[Tree])] = tree match { - case Apply(Select(New(Placeholder(tree, loc, card)), nme.CONSTRUCTOR), args) => Some(tree, loc, card, args) - case _ => None + object AnnotPlaceholder extends HolePlaceholder { + def matching = { + case Apply(Select(New(Ident(name)), nme.CONSTRUCTOR), Nil) => name } } @@ -113,6 +112,13 @@ trait Placeholders { self: Quasiquotes => } } + object FunctionTypePlaceholder { + def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match { + case AppliedTypeTree(Ident(tpnme.QUASIQUOTE_FUNCTION), args :+ res) => Some((args, res)) + case _ => None + } + } + object SymbolPlaceholder { def unapply(scrutinee: Any): Option[Tree] = scrutinee match { case Placeholder(tree, SymbolLocation, _) => Some(tree) @@ -127,9 +133,16 @@ trait Placeholders { self: Quasiquotes => } } - object ClassPlaceholder { - def unapply(tree: Tree): Option[Tree] = tree match { - case ClassDef(_, _, _, _) => Some(tree) + object RefineStatPlaceholder { + def unapply(tree: Tree): Option[(Tree, Location, Cardinality)] = tree match { + case ValDef(_, Placeholder(tree, location, card), Ident(tpnme.QUASIQUOTE_REFINE_STAT), _) => Some((tree, location, card)) + case _ => None + } + } + + object EarlyDefPlaceholder { + def unapply(tree: Tree): Option[(Tree, Location, Cardinality)] = tree match { + case ValDef(_, Placeholder(tree, location, card), Ident(tpnme.QUASIQUOTE_EARLY_DEF), _) => Some((tree, location, card)) case _ => None } } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala index ee99a5e280..1305e25240 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala @@ -41,11 +41,11 @@ abstract class Quasiquotes extends Parsers lazy val universeTypes = new definitions.UniverseDependentTypes(universe) def expandQuasiquote = { - debug(s"\ncode to parse=\n$code\n") + debug(s"\ncode to parse:\n$code\n") val tree = parse(code) - debug(s"parsed tree\n=${tree}\n=${showRaw(tree)}\n") + debug(s"parsed:\n${showRaw(tree)}\n$tree\n") val reified = reify(tree) - debug(s"reified tree\n=${reified}\n=${showRaw(reified)}\n") + debug(s"reified tree:\n$reified\n") reified } } diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 900237b00d..af4e34536c 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -7,7 +7,10 @@ import scala.reflect.internal.Flags._ trait Reifiers { self: Quasiquotes => import global._ - import global.build.SyntacticClassDef + import global.build.{SyntacticClassDef, SyntacticTraitDef, SyntacticModuleDef, + SyntacticDefDef, SyntacticValDef, SyntacticVarDef, + SyntacticBlock, SyntacticApplied, SyntacticTypeApplied, + SyntacticFunction, SyntacticNew} import global.treeInfo._ import global.definitions._ import Cardinality._ @@ -35,13 +38,9 @@ trait Reifiers { self: Quasiquotes => reified } - override def reifyTree(tree: Tree): Tree = { - val reified = - reifyTreePlaceholder(tree) orElse - reifyTreeSyntactically(tree) - //println(s"reified ${showRaw(tree)} as $reified") - reified - } + override def reifyTree(tree: Tree): Tree = + reifyTreePlaceholder(tree) orElse + reifyTreeSyntactically(tree) def reifyTreePlaceholder(tree: Tree): Tree = tree match { case Placeholder(tree, TreeLocation(_), _) if isReifyingExpressions => tree @@ -49,11 +48,49 @@ trait Reifiers { self: Quasiquotes => case Placeholder(tree, _, card @ Dot()) => c.abort(tree.pos, s"Can't $action with $card here") case TuplePlaceholder(args) => reifyTuple(args) case TupleTypePlaceholder(args) => reifyTupleType(args) + case FunctionTypePlaceholder(argtpes, restpe) => reifyFunctionType(argtpes, restpe) case CasePlaceholder(tree, location, _) => reifyCase(tree, location) - case ClassPlaceholder(tree) => reifyClass(tree) + case RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree) + case EarlyDefPlaceholder(tree, _, _) => reifyEarlyDef(tree) case _ => EmptyTree } + override def reifyTreeSyntactically(tree: Tree) = tree match { + case SyntacticTraitDef(mods, name, tparams, earlyDefs, parents, selfdef, body) => + reifyBuildCall(nme.SyntacticTraitDef, mods, name, tparams, earlyDefs, parents, selfdef, body) + 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 SyntacticNew(earlyDefs, parents, selfdef, body) => + 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) => + reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs) + case SyntacticVarDef(mods, name, tpt, rhs) => + reifyBuildCall(nme.SyntacticVarDef, mods, name, tpt, rhs) + case SyntacticApplied(fun, argss) if argss.length > 1 => + reifyBuildCall(nme.SyntacticApplied, fun, argss) + case SyntacticApplied(fun, argss @ (_ :+ (_ :+ Placeholder(_, _, DotDotDot)))) => + reifyBuildCall(nme.SyntacticApplied, fun, argss) + case SyntacticTypeApplied(fun, targs) if targs.nonEmpty => + reifyBuildCall(nme.SyntacticTypeApplied, fun, targs) + case SyntacticFunction(args, body) => + reifyBuildCall(nme.SyntacticFunction, args, body) + case Block(stats, last) => + reifyBuildCall(nme.SyntacticBlock, stats :+ last) + // parser emits trees with scala package symbol to ensure + // that some names hygienically point to various scala package + // members; we need to preserve this symbol to preserve + // correctness of the trees produced by quasiquotes + case Select(id @ Ident(nme.scala_), name) if id.symbol == ScalaPackage => + reifyBuildCall(nme.ScalaDot, name) + case _ => + super.reifyTreeSyntactically(tree) + } + override def reifyName(name: Name): Tree = name match { case Placeholder(tree, location, _) => if (holesHaveTypes && !(location.tpe <:< nameType)) c.abort(tree.pos, s"$nameType expected but ${location.tpe} found") @@ -70,26 +107,30 @@ trait Reifiers { self: Quasiquotes => def reifyTuple(args: List[Tree]) = args match { case Nil => reify(Literal(Constant(()))) case List(hole @ Placeholder(_, _, NoDot)) => reify(hole) - case List(Placeholder(_, _, _)) => reifyBuildCall(nme.TupleN, args) + case List(Placeholder(_, _, _)) => reifyBuildCall(nme.SyntacticTuple, args) // in a case we only have one element tuple without // any cardinality annotations this means that this is // just an expression wrapped in parentheses case List(other) => reify(other) - case _ => reifyBuildCall(nme.TupleN, args) + case _ => reifyBuildCall(nme.SyntacticTuple, args) } def reifyTupleType(args: List[Tree]) = args match { case Nil => reify(Select(Ident(nme.scala_), tpnme.Unit)) case List(hole @ Placeholder(_, _, NoDot)) => reify(hole) - case List(Placeholder(_, _, _)) => reifyBuildCall(nme.TupleTypeN, args) + case List(Placeholder(_, _, _)) => reifyBuildCall(nme.SyntacticTupleType, args) case List(other) => reify(other) - case _ => reifyBuildCall(nme.TupleTypeN, args) + case _ => reifyBuildCall(nme.SyntacticTupleType, args) } - def reifyClass(tree: Tree) = { - val SyntacticClassDef(mods, name, tparams, constrmods, argss, parents, selfval, body) = tree - reifyBuildCall(nme.SyntacticClassDef, mods, name, tparams, constrmods, argss, parents, selfval, body) - } + def reifyFunctionType(argtpes: List[Tree], restpe: Tree) = + reifyBuildCall(nme.SyntacticFunctionType, argtpes, restpe) + + def reifyRefineStat(tree: Tree) = tree + + def reifyEarlyDef(tree: Tree) = tree + + def reifyAnnotation(tree: Tree) = tree /** Splits list into a list of groups where subsequent elements are considered * similar by the corresponding function. @@ -143,15 +184,33 @@ trait Reifiers { self: Quasiquotes => override def reifyList(xs: List[Any]): Tree = reifyMultiCardinalityList(xs) { case Placeholder(tree, _, DotDot) => tree case CasePlaceholder(tree, _, DotDot) => tree + case RefineStatPlaceholder(tree, _, DotDot) => reifyRefineStat(tree) + case EarlyDefPlaceholder(tree, _, DotDot) => reifyEarlyDef(tree) case List(Placeholder(tree, _, DotDotDot)) => tree } { reify(_) } - def reifyAnnotList(annots: List[Tree]): Tree + def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) { + case AnnotPlaceholder(tree, _, DotDot) => reifyAnnotation(tree) + } { + case AnnotPlaceholder(tree, UnknownLocation | TreeLocation(_), NoDot) => reifyAnnotation(tree) + case other => reify(other) + } - def ensureNoExplicitFlags(m: Modifiers, pos: Position) = - if ((m.flags & ExplicitFlags) != 0L) c.abort(pos, s"Can't $action modifiers together with flags, consider merging flags into modifiers") + // These are explicit flags except those that are used + // 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 + + 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) + c.abort(pos, s"Can't $action modifiers together with flags, consider merging flags into modifiers") + } override def mirrorSelect(name: String): Tree = Select(universe, TermName(name)) @@ -167,19 +226,10 @@ trait Reifiers { self: Quasiquotes => def isReifyingExpressions = true override def reifyTreeSyntactically(tree: Tree): Tree = tree match { - case Block(stats, p @ Placeholder(_, _, _)) => reifyBuildCall(nme.Block, stats :+ p) - case Apply(f, List(Placeholder(argss, _, DotDotDot))) => reifyCallWithArgss(f, argss) - case RefTree(qual, SymbolPlaceholder(tree)) => mirrorBuildCall(nme.RefTree, reify(qual), tree) - case _ => super.reifyTreeSyntactically(tree) - } - - def reifyCallWithArgss(f: Tree, argss: Tree) = { - val f1 = reifyTree(f) - val foldLeftF1 = Apply(TypeApply(Select(argss, nme.foldLeft), List(Select(u, tpnme.Tree))), List(f1)) - val uDotApply = Function( - List(gen.mkSyntheticParam(nme.x_1), gen.mkSyntheticParam(nme.x_2)), - Apply(Select(u, nme.Apply), List(Ident(nme.x_1), Ident(nme.x_2)))) - Apply(foldLeftF1, List(uDotApply)) + case RefTree(qual, SymbolPlaceholder(tree)) => + mirrorBuildCall(nme.RefTree, reify(qual), tree) + case _ => + super.reifyTreeSyntactically(tree) } override def reifyMultiCardinalityList[T](xs: List[T])(fill: PartialFunction[T, Tree])(fallback: T => Tree): Tree = xs match { @@ -193,61 +243,47 @@ trait Reifiers { self: Quasiquotes => tail.foldLeft[Tree](reifyGroup(head)) { (tree, lst) => Apply(Select(tree, nme.PLUSPLUS), List(reifyGroup(lst))) } } - override def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) { - case AnnotPlaceholder(tree, _, DotDot, args) => - val x: TermName = c.freshName() - val xToAnnotationCtor = Function( - List(ValDef(Modifiers(PARAM), x, TypeTree(), EmptyTree)), - mirrorBuildCall(nme.mkAnnotationCtor, Ident(x), reify(args))) - Apply(Select(tree, nme.map), List(xToAnnotationCtor)) - } { - case AnnotPlaceholder(tree, _: TreeLocation, _, args) => - mirrorBuildCall(nme.mkAnnotationCtor, tree, reify(args)) - case other => reify(other) - } - - override def reifyModifiers(m: Modifiers) = { - val (modsPlaceholders, annots) = m.annotations.partition { - case ModsPlaceholder(_, _, _) => true - case _ => false - } - val (mods, flags) = modsPlaceholders.map { - case ModsPlaceholder(tree, location, card) => (tree, location) - }.partition { case (tree, location) => - location match { - case ModsLocation => true - case FlagsLocation => false - case _ => c.abort(tree.pos, s"$flagsType or $modsType expected but ${tree.tpe} found") + override def reifyModifiers(m: Modifiers) = + if (m == NoMods) super.reifyModifiers(m) + else { + val (modsPlaceholders, annots) = m.annotations.partition { + case ModsPlaceholder(_, _, _) => true + case _ => false + } + val (mods, flags) = modsPlaceholders.map { + case ModsPlaceholder(tree, location, card) => (tree, location) + }.partition { case (tree, location) => + location match { + case ModsLocation => true + case FlagsLocation => false + case _ => c.abort(tree.pos, s"$flagsType or $modsType expected but ${tree.tpe} found") + } + } + mods match { + case (tree, _) :: Nil => + if (flags.nonEmpty) c.abort(flags(0)._1.pos, "Can't splice flags together with modifiers, consider merging flags into modifiers") + if (annots.nonEmpty) c.abort(tree.pos, "Can't splice modifiers together with annotations, consider merging annotations into modifiers") + ensureNoExplicitFlags(m, tree.pos) + tree + case _ :: (second, _) :: Nil => + c.abort(second.pos, "Can't splice multiple modifiers, consider merging them into a single modifiers instance") + case _ => + val baseFlags = reifyFlags(m.flags) + val reifiedFlags = flags.foldLeft[Tree](baseFlags) { case (flag, (tree, _)) => Apply(Select(flag, nme.OR), List(tree)) } + mirrorFactoryCall(nme.Modifiers, reifiedFlags, reify(m.privateWithin), reifyAnnotList(annots)) } } - mods match { - case (tree, _) :: Nil => - if (flags.nonEmpty) c.abort(flags(0)._1.pos, "Can't splice flags together with modifiers, consider merging flags into modifiers") - if (annots.nonEmpty) c.abort(tree.pos, "Can't splice modifiers together with annotations, consider merging annotations into modifiers") - ensureNoExplicitFlags(m, tree.pos) - tree - case _ :: (second, _) :: Nil => - c.abort(second.pos, "Can't splice multiple modifiers, consider merging them into a single modifiers instance") - case _ => - val baseFlags = reifyBuildCall(nme.flagsFromBits, m.flags) - val reifiedFlags = flags.foldLeft[Tree](baseFlags) { case (flag, (tree, _)) => Apply(Select(flag, nme.OR), List(tree)) } - mirrorFactoryCall(nme.Modifiers, reifiedFlags, reify(m.privateWithin), reifyAnnotList(annots)) - } - } + + override def reifyRefineStat(tree: Tree) = mirrorBuildCall(nme.mkRefineStat, tree) + + override def reifyEarlyDef(tree: Tree) = mirrorBuildCall(nme.mkEarlyDef, tree) + + override def reifyAnnotation(tree: Tree) = mirrorBuildCall(nme.mkAnnotation, tree) } class UnapplyReifier extends Reifier { def isReifyingExpressions = false - override def reifyTreeSyntactically(tree: Tree): Tree = tree match { - case treeInfo.Applied(fun, Nil, argss) if fun != tree && !tree.isInstanceOf[AppliedTypeTree] => - reifyBuildCall(nme.Applied, fun, argss) - case treeInfo.Applied(fun, targs, argss) if fun != tree & !tree.isInstanceOf[AppliedTypeTree] => - mirrorBuildCall(nme.Applied, reifyBuildCall(nme.TypeApplied, fun, targs), reifyList(argss)) - case _ => - super.reifyTreeSyntactically(tree) - } - override def scalaFactoryCall(name: String, args: Tree*): Tree = call("scala." + name, args: _*) @@ -261,30 +297,20 @@ trait Reifiers { self: Quasiquotes => mkList(xs.map(fallback)) } - override def reifyAnnotList(annots: List[Tree]): Tree = reifyMultiCardinalityList(annots) { - case AnnotPlaceholder(tree, _, DotDot, Nil) => tree - } { - case AnnotPlaceholder(tree, _, NoDot, Nil) => tree - case AnnotPlaceholder(tree, _, NoDot, args) => - val selectCONSTRUCTOR = Apply(Select(u, nme.Select), List(Apply(Select(u, nme.New), List(tree)), Select(Select(u, nme.nmeNme), nme.nmeCONSTRUCTOR))) - Apply(Select(u, nme.Apply), List(selectCONSTRUCTOR, reify(args))) - case other => - reify(other) - } - - override def reifyModifiers(m: Modifiers) = { - val mods = m.annotations.collect { case ModsPlaceholder(tree, _, _) => tree } - mods match { - case tree :: Nil => - if (m.annotations.length != 1) c.abort(tree.pos, "Can't extract modifiers together with annotations, consider extracting just modifiers") - ensureNoExplicitFlags(m, tree.pos) - tree - case _ :: second :: rest => - c.abort(second.pos, "Can't extract multiple modifiers together, consider extracting a single modifiers instance") - case Nil => - mirrorFactoryCall(nme.Modifiers, reifyBuildCall(nme.FlagsAsBits, m.flags), - reify(m.privateWithin), reifyAnnotList(m.annotations)) + override def reifyModifiers(m: Modifiers) = + if (m == NoMods) super.reifyModifiers(m) + else { + val mods = m.annotations.collect { case ModsPlaceholder(tree, _, _) => tree } + mods match { + case tree :: Nil => + if (m.annotations.length != 1) c.abort(tree.pos, "Can't extract modifiers together with annotations, consider extracting just modifiers") + ensureNoExplicitFlags(m, tree.pos) + tree + case _ :: second :: rest => + c.abort(second.pos, "Can't extract multiple modifiers together, consider extracting a single modifiers instance") + case Nil => + mirrorFactoryCall(nme.Modifiers, reifyFlags(m.flags), reify(m.privateWithin), reifyAnnotList(m.annotations)) + } } - } } -}
\ No newline at end of file +} |