Skip to content

Commit 017d3fc

Browse files
committed
Merge pull request #14 from benhag/args
Added macro for passing all arguments of a method as implicit parameter
2 parents 8e83e38 + ebc1b11 commit 017d3fc

File tree

6 files changed

+113
-0
lines changed

6 files changed

+113
-0
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ The kinds of compilation-time data that `sourcecode` provides are:
7272
you have multiple statements in a `{}` block, `sourcecode.Text` will only
7373
capture the source code for the last expression that gets returned. This
7474
implicit is slightly experimental; be sure to report any bugs you find!
75+
- `sourcecode.Args`: the arguments that where provided to the nearest enclosing
76+
method
7577
- `sourcecode.Name.Machine`, `sourcecode.FullName.Machine` and
7678
`sourcecode.Enclosing.Machine` which are similar to `sourcecode.Name`,
7779
`sourcecode.FullName` and `sourcecode.Enclosing` except they do not filter
@@ -475,6 +477,21 @@ be printed. You can, or course, define your own `log` method in the same way,
475477
customizing it to print or not-print exactly what you want to see via the
476478
implicits that `sourcecode` provides!
477479

480+
`sourcecode.Args` can be used to access all parameters that where provided
481+
to a method:
482+
483+
```scala
484+
def debug(implicit name: sourcecode.Name, args: sourcecode.Args): Unit = {
485+
println(name.value + args.value.map(_.map(a => a.source + "=" + a.value).mkString("(", ", ", ")")).mkString(""))
486+
}
487+
488+
def foo(bar: String, baz: Int)(p: Boolean): Unit = {
489+
debug
490+
}
491+
492+
foo("baz", 42)(true) // foo(bar=baz, baz=42)(p=true)
493+
```
494+
478495
Embedding Domain-Specific Languages
479496
-----------------------------------
480497

sourcecode/shared/src/main/scala-2.10/sourcecode/Compat.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,17 @@ object Compat{
99
.owner
1010
.asInstanceOf[c.Symbol]
1111
}
12+
13+
def enclosingParamList(c: Context): List[List[c.Symbol]] = {
14+
def nearestClassOrMethod(owner: c.Symbol): c.Symbol =
15+
if (owner.isMethod || owner.isClass) owner else nearestClassOrMethod(owner.owner)
16+
17+
val com = nearestClassOrMethod(enclosingOwner(c))
18+
if (com.isClass) {
19+
val pc = com.typeSignature.members.filter(m => m.isMethod && m.asMethod.isPrimaryConstructor)
20+
pc.head.asMethod.paramss
21+
} else {
22+
com.asMethod.paramss
23+
}
24+
}
1225
}

sourcecode/shared/src/main/scala-2.11/sourcecode/Compat.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,13 @@ package sourcecode
33
object Compat{
44
type Context = scala.reflect.macros.blackbox.Context
55
def enclosingOwner(c: Context) = c.internal.enclosingOwner
6+
7+
def enclosingParamList(c: Context): List[List[c.Symbol]] = {
8+
def nearestEnclosingMethod(owner: c.Symbol): c.Symbol =
9+
if (owner.isMethod) owner
10+
else if (owner.isClass) owner.asClass.primaryConstructor
11+
else nearestEnclosingMethod(owner.owner)
12+
13+
nearestEnclosingMethod(enclosingOwner(c)).asMethod.paramLists
14+
}
615
}

sourcecode/shared/src/main/scala/sourcecode/SourceContext.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ object Text{
111111
def apply[T](v: T): Text[T] = macro Impls.text[T]
112112

113113
}
114+
115+
case class Args(value: Seq[Seq[Text[_]]]) extends SourceValue[Seq[Seq[Text[_]]]]
116+
object Args extends SourceCompanion[Seq[Seq[Text[_]]], Args](new Args(_)) {
117+
implicit def generate: Args = macro impl
118+
def impl(c: Compat.Context): c.Expr[Args] = {
119+
import c.universe._
120+
val param = Compat.enclosingParamList(c)
121+
val texts = param.map(_.map(p => c.Expr[Text[_]](q"""sourcecode.Text($p, ${p.name.toString})""")))
122+
val textSeqs = texts.map(s => c.Expr(q"""Seq(..$s)"""))
123+
c.Expr[Args](q"""Seq(..$textSeqs)""")
124+
}
125+
}
126+
114127
object Impls{
115128
def text[T: c.WeakTypeTag](c: Compat.Context)(v: c.Expr[T]): c.Expr[sourcecode.Text[T]] = {
116129
import c.universe._
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package sourcecode
2+
3+
object ArgsTests {
4+
def apply() = {
5+
6+
var args: Seq[Seq[(String, Any)]] = Seq()
7+
8+
def debug(implicit arguments: sourcecode.Args): Unit = args = arguments.value.map(_.map(t => t.source -> t.value))
9+
10+
def foo(p1: String, p2: Long, p3: Boolean)(foo: String, bar: String): Unit = {
11+
debug
12+
}
13+
14+
def bar(p1: String, p2: Long, p3: Boolean)(foo: String, bar: String): Unit = {
15+
val bar = {
16+
debug
17+
"bar"
18+
}
19+
}
20+
21+
def baz: Unit = {
22+
debug
23+
}
24+
25+
def withImplicit(p1: String, p2: Long, p3: Boolean)(implicit foo: String): Unit = {
26+
debug
27+
}
28+
29+
class Foo(p1: String, p2: Long, p3: Boolean)(foo: String, bar: String) {
30+
debug
31+
32+
def this(p1: String, p2: Long) = {
33+
this(p1, p2, false)("foo", "bar")
34+
debug
35+
}
36+
}
37+
38+
new Foo("text", 42, false)("foo", "bar")
39+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "foo", "bar" -> "bar")))
40+
41+
new Foo("text", 42)
42+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42)))
43+
44+
foo("text", 42, false)("foo", "bar")
45+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "foo", "bar" -> "bar")))
46+
47+
bar("text", 42, false)("foo", "bar")
48+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "foo", "bar" -> "bar")))
49+
50+
baz
51+
assert(args == Seq())
52+
53+
withImplicit("text", 42, false)("foo")
54+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "foo")))
55+
56+
implicit val implicitFoo = "bar"
57+
withImplicit("text", 42, false)
58+
assert(args == Seq(Seq("p1" -> "text", "p2" -> 42, "p3" -> false), Seq("foo" -> "bar")))
59+
}
60+
}

sourcecode/shared/src/test/scala/sourcecode/Tests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ object Tests{
2020
Synthetic.run()
2121
ManualImplicit()
2222
TextTests()
23+
ArgsTests()
2324

2425
println("================LogExample================")
2526
logExample()

0 commit comments

Comments
 (0)