Skip to content

Instantly share code, notes, and snippets.

@xeno-by
Created April 29, 2013 13:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xeno-by/5481456 to your computer and use it in GitHub Desktop.
Save xeno-by/5481456 to your computer and use it in GitHub Desktop.
import scala.reflect.macros.Context
import language.experimental.macros
object Macros {
implicit class StringContextExtension(ctx: StringContext) {
object split {
def unapply(dummy: Any): Any = macro impl
}
}
def impl(c: Context)(dummy: c.Expr[Any]): c.Expr[Any] = {
import c.universe._
val Apply(Select(Select(Apply(_, List(Apply(_, statics))), _), _), List(dummy)) = c.macroApplication
val nsplicees = statics.length - 1
if (nsplicees <= 1) c.abort(c.enclosingPosition, "split needs more than one splicee")
def mkPart(i: Int) = {
if (statics.mkString.contains("into ints: ")) {
Apply(Select(Ident(newTermName("scrut")), newTermName("$div")), List(Literal(Constant(nsplicees))))
} else if (statics.mkString.contains("into strings: ")) {
val sscrut = Select(Ident(newTermName("scrut")), newTermName("toString"))
val substring = Select(sscrut, newTermName("substring"))
val length = Select(sscrut, newTermName("length"))
val onenth = Apply(Select(length, newTermName("$div")), List(Literal(Constant(nsplicees))))
val lo = Apply(Select(onenth, "$times"), List(Literal(Constant(i))))
val hi = Apply(Select(lo, "$plus"), List(Literal(Constant(onenth))))
Apply(substring, List(lo, hi))
} else {
???
}
}
val scrutinee = ValDef(NoMods, newTermName("scrut"), TypeTree(), dummy)
val partDefs = 1.to(nsplicees).map(i => ValDef(NoMods, newTermName("part" + i), TypeTree(), mkPart(i))).toList
val partRefs = partDefs.map(partDef => Ident(partDef.name))
val result = Apply(Ident(newTermName("Some")), List(Apply(Ident("Tuple" + nsplicees), partRefs)))
c.Expr[Any](Block(scrutinee +: partDefs, result))
}
}
import Macros._
object Test extends App {
42 match {
case split"into ints: $x and $y" => println((x, y, x.getClass, y.getClass))
case _ => println("fail")
}
// 42 match {
// case split"into strings: $x and $y" => println((x, y, x.getClass, y.getClass))
// case _ => println("fail")
// }
}
15:03 ~/Projects/210x/sandbox (2.10.x)$ scalac Macros.scala && scalac Test.scala
{
val scrut: Int = <unapply-selector>;
val part1: Int = scrut./(2);
val part2: Int = scrut./(2);
scala.Some.apply[(Int, Int)](scala.Tuple2.apply[Int, Int](part1, part2))
}
Block[1](List(ValDef[2](Modifiers(), newTermName("scrut"), TypeTree[3](), Ident[3](newTermName("<unapply-selector>")#20755)), ValDef[2](Modifiers(), newTermName("part1"), TypeTree[3](), Apply[3](Select[4](Ident[5](newTermName("scrut")#20758), newTermName("$div")#17275), List(Literal[6](Constant(2))))), ValDef[2](Modifiers(), newTermName("part2"), TypeTree[3](), Apply[3](Select[4](Ident[5](newTermName("scrut")#20758), newTermName("$div")#17275), List(Literal[6](Constant(2)))))), Apply[1](TypeApply[7](Select[8](Select[9](Ident[10](scala#20), scala.Some#1309), newTermName("apply")#20794), List(TypeTree[11]())), List(Apply[11](TypeApply[12](Select[13](Select[14](Ident[10](scala#20), scala.Tuple2#1513), newTermName("apply")#19908), List(TypeTree[3](), TypeTree[3]())), List(Ident[3](newTermName("part1")#20759), Ident[3](newTermName("part2")#20760))))))
[1] TypeRef(ThisType(scala#21), scala.Some#1308, List(TypeRef(ThisType(scala#21), scala.Tuple2#1512, List(TypeRef(ThisType(scala#21), scala.Int#849, List()), TypeRef(ThisType(scala#21), scala.Int#849, List())))))
[2] NoType
[3] TypeRef(ThisType(scala#21), scala.Int#849, List())
[4] MethodType(List(newTermName("x")#17276), TypeRef(ThisType(scala#21), scala.Int#849, List()))
[5] SingleType(NoPrefix, newTermName("scrut")#20758)
[6] ConstantType(Constant(2))
[7] MethodType(List(newTermName("x")#20886), TypeRef(ThisType(scala#21), scala.Some#1308, List(TypeRef(ThisType(scala#21), scala.Tuple2#1512, List(TypeRef(ThisType(scala#21), scala.Int#849, List()), TypeRef(ThisType(scala#21), scala.Int#849, List()))))))
[8] PolyType(List(newTypeName("A")#20795), MethodType(List(newTermName("x")#20796), TypeRef(ThisType(scala#21), scala.Some#1308, List(TypeRef(NoPrefix, newTypeName("A")#20795, List())))))
[9] SingleType(SingleType(ThisType(<root>#2), scala#20), scala.Some#1309)
[10] SingleType(ThisType(<root>#2), scala#20)
[11] TypeRef(ThisType(scala#21), scala.Tuple2#1512, List(TypeRef(ThisType(scala#21), scala.Int#849, List()), TypeRef(ThisType(scala#21), scala.Int#849, List())))
[12] MethodType(List(newTermName("_1")#20884, newTermName("_2")#20885), TypeRef(ThisType(scala#21), scala.Tuple2#1512, List(TypeRef(ThisType(scala#21), scala.Int#849, List()), TypeRef(ThisType(scala#21), scala.Int#849, List()))))
[13] PolyType(List(newTypeName("T1")#19909, newTypeName("T2")#19910), MethodType(List(newTermName("_1")#19911, newTermName("_2")#19912), TypeRef(ThisType(scala#21), scala.Tuple2#1512, List(TypeRef(NoPrefix, newTypeName("T1")#19909, List()), TypeRef(NoPrefix, newTypeName("T2")#19910, List())))))
[14] SingleType(SingleType(ThisType(<root>#2), scala#20), scala.Tuple2#1513)
error:
while compiling: Test.scala
during phase: typer
library version: version 2.10.2-20130425-053916-403ba8938f
compiler version: version 2.10.2-20130425-053916-403ba8938f
reconstructed args: -language:experimental.macros
last tree to typer: Block
symbol: null
symbol definition: null
tpe: Some[(Int, Int)]
symbol owners:
context owners: value <local Test> -> object Test -> package <empty>
== Enclosing template or block ==
Template( // val <local Test>: <notype> in object Test
"App" // parents
ValDef(
private
"_"
<tpt>
<empty>
)
// 2 statements
DefDef( // def <init>(): Test.type in object Test
<method>
"<init>"
[]
List(Nil)
<tpt> // tree.tpe=Test.type
Block( // tree.tpe=Unit
Apply( // def <init>(): Object in class Object, tree.tpe=Object
Test.super."<init>" // def <init>(): Object in class Object, tree.tpe=()Object
Nil
)
()
)
)
Match(
42
// 2 cases
CaseDef(
Apply(
StringContext("into ints: ", " and ", "")."split"
// 2 arguments
Bind(
"x"
"_"
)
Bind(
"y"
"_"
)
)
Apply(
"println"
Apply(
"scala"."Tuple4"
// 4 arguments
"x"
"y"
"x"."getClass"
"y"."getClass"
)
)
)
CaseDef(
"_"
Apply(
"println"
"fail"
)
)
)
)
== Expanded type of tree ==
TypeRef(
TypeSymbol(
final case class Some[+A <: <?>] extends Option[A] with Product with Serializable
)
args = List(
TypeRef(
TypeSymbol(
case class Tuple2[+T1 <: <?>, +T2 <: <?>] extends Product2[T1,T2] with Product with Serializable
)
args = List(
TypeRef(TypeSymbol(final abstract class Int extends AnyVal))
TypeRef(TypeSymbol(final abstract class Int extends AnyVal))
)
)
)
)
uncaught exception during compilation: java.lang.NullPointerException
error: java.lang.NullPointerException
at scala.tools.nsc.typechecker.Infer$class.extractorFormalTypes(Infer.scala:93)
at scala.tools.nsc.Global$$anon$1.extractorFormalTypes(Global.scala:493)
at scala.tools.nsc.typechecker.Typers$Typer.doTypedUnapply(Typers.scala:3483)
at scala.tools.nsc.typechecker.Typers$Typer.doTypedApply(Typers.scala:3417)
at scala.tools.nsc.typechecker.Typers$Typer.normalTypedApply$1(Typers.scala:4583)
at scala.tools.nsc.typechecker.Typers$Typer.typedApply$1(Typers.scala:4615)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5520)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5598)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$119$$anonfun$apply$43.apply(Typers.scala:5712)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$119$$anonfun$apply$43.apply(Typers.scala:5712)
at scala.tools.nsc.typechecker.Contexts$Context.withImplicitsDisabledAllowEnrichment(Contexts.scala:232)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$119.apply(Typers.scala:5712)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$119.apply(Typers.scala:5712)
at scala.tools.nsc.typechecker.TypeDiagnostics$class.typingInPattern(TypeDiagnostics.scala:72)
at scala.tools.nsc.Global$$anon$1.typingInPattern(Global.scala:493)
at scala.tools.nsc.typechecker.Typers$Typer.typedPattern(Typers.scala:5712)
at scala.tools.nsc.typechecker.Typers$Typer.typedCase(Typers.scala:2446)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$typedCases$1.apply(Typers.scala:2492)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$typedCases$1.apply(Typers.scala:2491)
at scala.collection.immutable.List.loop$1(List.scala:170)
at scala.collection.immutable.List.mapConserve(List.scala:186)
at scala.tools.nsc.typechecker.Typers$Typer.typedCases(Typers.scala:2491)
at scala.tools.nsc.typechecker.Typers$Typer.typedMatch(Typers.scala:2504)
at scala.tools.nsc.typechecker.Typers$Typer.typedVirtualizedMatch$1(Typers.scala:4319)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5532)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5598)
at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedStat$1(Typers.scala:2917)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3021)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3021)
at scala.collection.immutable.List.loop$1(List.scala:170)
at scala.collection.immutable.List.mapConserve(List.scala:186)
at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3021)
at scala.tools.nsc.typechecker.Typers$Typer.typedTemplate(Typers.scala:1910)
at scala.tools.nsc.typechecker.Typers$Typer.typedModuleDef(Typers.scala:1791)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5540)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5598)
at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedStat$1(Typers.scala:2917)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3021)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3021)
at scala.collection.immutable.List.loop$1(List.scala:170)
at scala.collection.immutable.List.mapConserve(List.scala:186)
at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3021)
at scala.tools.nsc.typechecker.Typers$Typer.typedPackageDef$1(Typers.scala:5257)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5543)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5598)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5655)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3.apply(Analyzer.scala:99)
at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:464)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3$$anonfun$run$1.apply(Analyzer.scala:91)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3$$anonfun$run$1.apply(Analyzer.scala:91)
at scala.collection.Iterator$class.foreach(Iterator.scala:727)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1157)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3.run(Analyzer.scala:91)
at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1583)
at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1557)
at scala.tools.nsc.Global$Run.compileSources(Global.scala:1553)
at scala.tools.nsc.Global$Run.compile(Global.scala:1662)
at scala.tools.nsc.Driver.doCompile(Driver.scala:33)
at scala.tools.nsc.Main$.doCompile(Main.scala:79)
at scala.tools.nsc.Driver.process(Driver.scala:54)
at scala.tools.nsc.Driver.main(Driver.scala:67)
at scala.tools.nsc.Main.main(Main.scala)
Exception in thread "main" java.lang.NullPointerException
at scala.tools.nsc.typechecker.Infer$class.extractorFormalTypes(Infer.scala:93)
at scala.tools.nsc.Global$$anon$1.extractorFormalTypes(Global.scala:493)
at scala.tools.nsc.typechecker.Typers$Typer.doTypedUnapply(Typers.scala:3483)
at scala.tools.nsc.typechecker.Typers$Typer.doTypedApply(Typers.scala:3417)
at scala.tools.nsc.typechecker.Typers$Typer.normalTypedApply$1(Typers.scala:4583)
at scala.tools.nsc.typechecker.Typers$Typer.typedApply$1(Typers.scala:4615)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5520)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5598)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$119$$anonfun$apply$43.apply(Typers.scala:5712)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$119$$anonfun$apply$43.apply(Typers.scala:5712)
at scala.tools.nsc.typechecker.Contexts$Context.withImplicitsDisabledAllowEnrichment(Contexts.scala:232)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$119.apply(Typers.scala:5712)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$119.apply(Typers.scala:5712)
at scala.tools.nsc.typechecker.TypeDiagnostics$class.typingInPattern(TypeDiagnostics.scala:72)
at scala.tools.nsc.Global$$anon$1.typingInPattern(Global.scala:493)
at scala.tools.nsc.typechecker.Typers$Typer.typedPattern(Typers.scala:5712)
at scala.tools.nsc.typechecker.Typers$Typer.typedCase(Typers.scala:2446)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$typedCases$1.apply(Typers.scala:2492)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$typedCases$1.apply(Typers.scala:2491)
at scala.collection.immutable.List.loop$1(List.scala:170)
at scala.collection.immutable.List.mapConserve(List.scala:186)
at scala.tools.nsc.typechecker.Typers$Typer.typedCases(Typers.scala:2491)
at scala.tools.nsc.typechecker.Typers$Typer.typedMatch(Typers.scala:2504)
at scala.tools.nsc.typechecker.Typers$Typer.typedVirtualizedMatch$1(Typers.scala:4319)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5532)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5598)
at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedStat$1(Typers.scala:2917)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3021)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3021)
at scala.collection.immutable.List.loop$1(List.scala:170)
at scala.collection.immutable.List.mapConserve(List.scala:186)
at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3021)
at scala.tools.nsc.typechecker.Typers$Typer.typedTemplate(Typers.scala:1910)
at scala.tools.nsc.typechecker.Typers$Typer.typedModuleDef(Typers.scala:1791)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5540)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5598)
at scala.tools.nsc.typechecker.Typers$Typer.scala$tools$nsc$typechecker$Typers$Typer$$typedStat$1(Typers.scala:2917)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3021)
at scala.tools.nsc.typechecker.Typers$Typer$$anonfun$60.apply(Typers.scala:3021)
at scala.collection.immutable.List.loop$1(List.scala:170)
at scala.collection.immutable.List.mapConserve(List.scala:186)
at scala.tools.nsc.typechecker.Typers$Typer.typedStats(Typers.scala:3021)
at scala.tools.nsc.typechecker.Typers$Typer.typedPackageDef$1(Typers.scala:5257)
at scala.tools.nsc.typechecker.Typers$Typer.typed1(Typers.scala:5543)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5598)
at scala.tools.nsc.typechecker.Typers$Typer.typed(Typers.scala:5655)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3.apply(Analyzer.scala:99)
at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:464)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3$$anonfun$run$1.apply(Analyzer.scala:91)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3$$anonfun$run$1.apply(Analyzer.scala:91)
at scala.collection.Iterator$class.foreach(Iterator.scala:727)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1157)
at scala.tools.nsc.typechecker.Analyzer$typerFactory$$anon$3.run(Analyzer.scala:91)
at scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1583)
at scala.tools.nsc.Global$Run.compileUnits(Global.scala:1557)
at scala.tools.nsc.Global$Run.compileSources(Global.scala:1553)
at scala.tools.nsc.Global$Run.compile(Global.scala:1662)
at scala.tools.nsc.Driver.doCompile(Driver.scala:33)
at scala.tools.nsc.Main$.doCompile(Main.scala:79)
at scala.tools.nsc.Driver.process(Driver.scala:54)
at scala.tools.nsc.Driver.main(Driver.scala:67)
at scala.tools.nsc.Main.main(Main.scala)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment