Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Binary literal macro, using string interpolation

  • Loading branch information...
commit 4caf191cc9664e85b213e81e1165b89d336d0252 1 parent eb5495d
@retronym retronym authored
View
7 README.md
@@ -41,4 +41,11 @@ $line1.$read.$iw.$iw.plus(2, $line1.$read.$iw.$iw.plus(3, 4)) = 9
$line1.$read.$iw.$iw.plus(1, $line1.$read.$iw.$iw.plus(2, $line1.$read.$iw.$iw.plus(3, 4))) = 10
res3: Int = 10
+scala> b"102"
+<console>:11: error: exception during macro expansion: invalid binary literal
+ b"102"
+ ^
+scala> b"101010"
+res4: Int = 42
+
```
View
2  build.sbt
@@ -8,7 +8,7 @@ seq(npSettings: _*)
scalaVersion := "2.10.0-SNAPSHOT"
-scalacOptions ++= Seq("-Xmacros", "-unchecked", "-Yvirtpatmat")
+scalacOptions ++= Seq("-Xmacros", "-unchecked", "-Yvirtpatmat", "-Xexperimental")
resolvers += "sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
View
80 src/main/scala/com/github/retronym/macrocosm/Macrocosm.scala
@@ -5,7 +5,7 @@ object Macrocosm {
* @return the tree of `a` after the typer, printed as source code.
*/
def macro desugar(a: Any): String = {
- val util = Util(_context); import util._
+ val util = Util(_context); import util._
val s = show(a: Tree)
stringLit(s)
@@ -25,12 +25,12 @@ object Macrocosm {
* log("".isEmpty) // prints: "".isEmpty = true
* ```
*/
- def macro log(a: Any) = {
+ def macro log[A](a: A): A = {
val util = Util(_context); import util._
val tempValName = newTermName("$value")
Block(
List(
- ValDef(Modifiers(), tempValName, TypeTree(), a),
+ ValDef(Modifiers(), tempValName, TypeTree(), a),
Apply(predefPrint, List(stringLit(show(a) + " = "))),
Apply(predefPrintln, List(Ident(tempValName)))
),
@@ -43,7 +43,7 @@ object Macrocosm {
* as the assertion message.
*/
def macro assert2(c: Boolean) = {
- val util = Util(_context); import util._
+ val util = Util(_context); import util._
val cTree: Tree = c
val pos = c.pos.asInstanceOf[scala.tools.nsc.util.OffsetPosition]
@@ -56,47 +56,90 @@ object Macrocosm {
"i$" + count
}
+ implicit def enrichStringContext(sc: StringContext) = new RichStringContext(sc)
+
+ class RichStringContext(sc: StringContext) {
+ // This is how a non-macro version would be implemented.
+ // def b() = {
+ // val s = sc.parts.mkString
+ // parseBinary(s).getOrElse(sys.error("invalid binary literal: " + s))
+ // }
+
+ /** Binary literal integer
+ *
+ * {{{
+ * scala> b"101010"
+ * res0: Int = 42
+ * }}}
+ */
+ def macro b() = {
+ def parseBinary(s: String): Option[Int] = {
+ var i = s.length - 1
+ var sum = 0
+ var mult = 1
+ while (i >= 0) {
+ s.charAt(i) match {
+ case '1' => sum += mult
+ case '0' =>
+ case x => return None
+ }
+ mult *= 2
+ i -= 1
+ }
+ Some(sum)
+ }
+
+ val i = _this match {
+ // e.g: `c.g.r.m.Macrocosm.enrichStringContext(scala.StringContext.apply("1111"))`
+ case Apply(_, List(Apply(_, List(Literal(Constant(const: String)))))) =>
+ parseBinary(const)
+ case _ =>
+ sys.error("Unexpected tree: " + show(_this))
+ }
+ i.map(x => Literal(Constant(x))).getOrElse(sys.error("invalid binary literal"))
+ }
+ }
/**
* Trace execution on `c`, by printing the values of sub-expressions
* to standard out.
*/
def macro trace(c: Any) = {
- val util = Util(_context); import util._
+ val util = Util(_context); import util._
object tracingTransformer extends Transformer {
//val symTree = mutable.buffer[SymTree]
- override def transform(tree: Tree): Tree = {
+ override def transform(tree: Tree): Tree = {
tree match {
case a @ Apply(qual, args) =>
- val tempValName = newTermName(nextName)
+ val tempValName = newTermName(nextName)
val sub = Apply(transform(qual), args.map(a => transform(a)))
Block(
List(
- ValDef(Modifiers(), tempValName, TypeTree(), sub),
+ ValDef(Modifiers(), tempValName, TypeTree(), sub),
Apply(predefPrint, List(stringLit(show(a) + " = "))),
Apply(predefPrintln, List(Ident(tempValName)))
),
Ident(tempValName)
)
case a @ Select(qual, name) if name.isTermName =>
- val tempValName = newTermName(nextName)
+ val tempValName = newTermName(nextName)
val sub = Select(transform(qual), name)
a.tpe match {
- case MethodType(_, _) | PolyType(_, _) =>
+ case MethodType(_, _) | PolyType(_, _) =>
// qual.meth(...)
// \-------/
// don't trace this part.
sub
- case _ =>
+ case _ =>
Block(
List(
- ValDef(Modifiers(), tempValName, TypeTree(), sub),
+ ValDef(Modifiers(), tempValName, TypeTree(), sub),
Apply(predefPrint, List(stringLit(show(a) + " = "))),
Apply(predefPrintln, List(Ident(tempValName)))
),
Ident(tempValName)
)
- }
+ }
case _ => super.transform(tree)
}
}
@@ -105,7 +148,10 @@ object Macrocosm {
//println("t = " + t)
resetAllAttrs(t)
}
-
+
+ def macro tree(a: Any) = {
+ reify(a)
+ }
import scala.reflect.macro.Context
@@ -113,8 +159,8 @@ object Macrocosm {
class Util[C <: Context with Singleton](val context: C) {
import context._
-
- def id(a: Tree): Tree = a
+
+ def id(a: Tree): Tree = a
// The first version of the trace macro did not call this, which led to NSDNHO
// errors with `trace(1.toString.toString)`.
@@ -130,7 +176,7 @@ object Macrocosm {
global.resetAllAttrs(a.asInstanceOf[global.Tree])
.asInstanceOf[Tree]
}
-
+
def predefAssert: Tree =
predefSelect("assert")
Please sign in to comment.
Something went wrong with that request. Please try again.