diff options
author | Den Shabalin <den.shabalin@gmail.com> | 2013-09-05 13:27:54 +0200 |
---|---|---|
committer | Den Shabalin <den.shabalin@gmail.com> | 2013-09-05 14:39:12 +0200 |
commit | 800f5acd0d7117bf953829da7c6d955e61e63bdc (patch) | |
tree | f7a28dbe2888cb6a2ba39a751c6dd24a296979d5 /src | |
parent | 1585b52b6cbf2e2985ef3a02009466e56baf6e74 (diff) | |
download | scala-800f5acd0d7117bf953829da7c6d955e61e63bdc.tar.gz scala-800f5acd0d7117bf953829da7c6d955e61e63bdc.tar.bz2 scala-800f5acd0d7117bf953829da7c6d955e61e63bdc.zip |
add support for function type splicing and extraction
Diffstat (limited to 'src')
8 files changed, 50 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index ed7c0d1a0a..28e3217449 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -516,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/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala index fe0809c869..868eccebcd 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala @@ -64,6 +64,10 @@ trait Parsers { self: Quasiquotes => case (head @ Ident(name)) :: Nil if holeMap.contains(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 => _, _} diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala index 5d7edcd75e..f0886b5735 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala @@ -113,6 +113,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) diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index a817afe741..9789801fac 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -45,6 +45,7 @@ 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 RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree) case _ => EmptyTree @@ -104,6 +105,9 @@ trait Reifiers { self: Quasiquotes => case _ => reifyBuildCall(nme.TupleTypeN, args) } + def reifyFunctionType(argtpes: List[Tree], restpe: Tree) = + reifyBuildCall(nme.SyntacticFunctionType, argtpes, restpe) + def reifyRefineStat(tree: Tree) = tree /** Splits list into a list of groups where subsequent elements are considered diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index a0a47fe23c..a74d3c137d 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -132,5 +132,12 @@ private[reflect] trait BuildUtils { self: Universe => def apply(stats: List[Tree]): Tree def unapply(tree: Tree): Option[List[Tree]] } + + val SyntacticFunctionType: SyntacticFunctionTypeExtractor + + trait SyntacticFunctionTypeExtractor { + def apply(argtpes: List[Tree], restpe: Tree): Tree + def unapply(tree: Tree): Option[(List[Tree], Tree)] + } } } diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index abe9e39067..e2894c5b94 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -5,7 +5,7 @@ package internal import Flags._ trait BuildUtils { self: SymbolTable => - import definitions.{TupleClass, MaxTupleArity, ScalaPackage, UnitClass} + import definitions.{TupleClass, FunctionClass, MaxTupleArity, MaxFunctionArity, ScalaPackage, UnitClass} class BuildImpl extends BuildApi { @@ -200,6 +200,26 @@ trait BuildUtils { self: SymbolTable => } } + object SyntacticFunctionType extends SyntacticFunctionTypeExtractor { + def apply(argtpes: List[Tree], restpe: Tree): Tree = { + require(argtpes.length <= MaxFunctionArity + 1, s"Function types with arity bigger than $MaxFunctionArity aren't supported") + gen.mkFunctionTypeTree(argtpes, restpe) + } + + def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match { + case AppliedTypeTree(id: Ident, args @ (argtpes :+ restpe)) + if args.length - 1 <= MaxFunctionArity && id.symbol == FunctionClass(args.length - 1) => + Some((argtpes, restpe)) + case AppliedTypeTree(Select(pack, fun), args @ (argtpes :+ restpe)) + if args.length - 1 <= MaxFunctionArity && pack.symbol == ScalaPackage && fun == FunctionClass(args.length - 1).name => + Some((argtpes, restpe)) + case AppliedTypeTree(Select(Select(Ident(nme.ROOTPKG), nme.scala_), fun), args @ (argtpes :+ restpe)) + if args.length - 1 <= MaxFunctionArity && fun == FunctionClass(args.length - 1).name => + Some((argtpes, restpe)) + case _ => None + } + } + object SyntacticBlock extends SyntacticBlockExtractor { def apply(stats: List[Tree]): Tree = gen.mkBlock(stats) diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 0b1f444772..f4662296e2 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -249,6 +249,7 @@ trait StdNames { // 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$" // Annotation simple names, used in Namer @@ -590,6 +591,7 @@ trait StdNames { val SyntacticApplied: NameType = "SyntacticApplied" val SyntacticBlock: NameType = "SyntacticBlock" val SyntacticClassDef: NameType = "SyntacticClassDef" + val SyntacticFunctionType: NameType= "SyntacticFunctionType" val SyntacticTypeApplied: NameType = "SyntacticTypeApplied" val This: NameType = "This" val ThisType: NameType = "ThisType" diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index 9623cc31f6..648c921eb7 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -415,6 +415,10 @@ abstract class TreeGen extends macros.TreeBuilder { } } + /** Create a tree representing the function type (argtpes) => restpe */ + def mkFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = + AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe)) + /** Create block of statements `stats` */ def mkBlock(stats: List[Tree]): Tree = if (stats.isEmpty) Literal(Constant(())) |