Skip to content

Commit bf408ca

Browse files
committed
wip
1 parent 036809f commit bf408ca

File tree

3 files changed

+105
-109
lines changed

3 files changed

+105
-109
lines changed

docs/docs/reference/metaprogramming/macros.md

Lines changed: 34 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -487,95 +487,54 @@ the code it runs produces one.
487487

488488
### Example Expansion
489489

490-
Assume an `Array` class with an inline `map` method that forwards to a macro
491-
implementation.
490+
TODO
491+
492+
Assume we have two methods, one `map` that takes an `Expr[Array[T]]` and a
493+
function `f` and one `sum` that performs a sum by delegating to `map`.
492494

493495
```scala
494-
class Array[T] {
495-
inline def map[U](f: T => U): Array[U] = ${ Macros.mapImpl[T, U]('[U], 'this, 'f) }
496+
object Macros {
497+
def map[T](arr: Expr[Array[T]], f: Expr[T] => Expr[Unit])(implicit t: Type[T]): Expr[Unit] = '{
498+
var i: Int = 0
499+
while (i < ($arr).length) {
500+
val element: $t = ($arr)(i)
501+
${f('element)}
502+
i += 1
496503
}
497-
```
498-
499-
Here’s the definition of the `mapImpl` macro, which takes quoted types and
500-
expressions to a quoted expression:
504+
}
501505

502-
```scala
503-
object Macros {
506+
def sum(arr: Expr[Array[Int]]): Expr[Int] = '{
507+
var sum = 0
508+
${ map(arr, x => '{sum += $x}) }
509+
sum
510+
}
504511

505-
def mapImpl[T, U](u: Type[U], arr: Expr[Array[T]], op: Expr[T => U]): Expr[Array[U]] = '{
506-
var i = 0
507-
val xs = $arr
508-
var len = xs.length
509-
val ys = new Array[$u](len)
510-
while (i < len) {
511-
ys(i) = ${ op('{ xs(i) }) }
512-
i += 1
513-
}
514-
ys
515-
}
516-
}
512+
inline def sum_m(arr: Array[Int]): Int = ${sum('arr)}
513+
}
517514
```
518515

519-
Here’s an application of `map` and how it rewrites to optimized code:
516+
A call to `sum_m(Array(1,2,3))` will first inline `sum`:
520517

521518
```scala
522-
genSeq[Int]().map(x => x + 1)
519+
var sum = 0
520+
${ _root_.Macros.map(arr, x => '{sum += $x}) }
521+
sum
523522
```
524-
==> (inline)
525-
```scala
526-
val _this: Seq[Int] = genSeq[Int]()
527-
val f: Int => Int = x => x + 1
528-
${ _root_.Macros.mapImpl[Int, Int]('[Int], '_this, 'f) }
529-
```
530-
==> (splice)
531-
```scala
532-
val _this: Seq[Int] = genSeq[Int]()
533-
val f: Int => Int = x => x + 1
534523

535-
{
536-
var i = 0
537-
val xs = ${ '_this }
538-
var len = xs.length
539-
val ys = new Array[${ '[Int] }](len)
540-
while (i < len) {
541-
ys(i) = ${ ('f)('{ xs(i) }) }
542-
i += 1
543-
}
544-
ys
545-
}
546-
```
547-
==> (expand and splice inside quotes)
548-
```scala
549-
val _this: Seq[Int] = genSeq[Int]()
550-
val f: Int => Int = x => x + 1
524+
then it will splice:
551525

552-
{
553-
var i = 0
554-
val xs = _this
555-
var len = xs.length
556-
val ys = new Array[Int](len)
557-
while (i < len) {
558-
ys(i) = xs(i) + 1
559-
i += 1
560-
}
561-
ys
562-
}
563-
```
564-
==> (elim dead code)
565526
```scala
566-
val _this: Seq[Int] = genSeq[Int]()
527+
var sum = 0
528+
var i: Int = 0
567529

568-
{
569-
var i = 0
570-
val xs = _this
571-
var len = xs.length
572-
val ys = new Array[Int](len)
573-
while (i < len) {
574-
ys(i) = xs(i) + 1
575-
i += 1
576-
}
577-
ys
578-
}
530+
while (i < ($arr).length) {
531+
val element: $t = ($arr)(i)
532+
${f('element)}
533+
i += 1
534+
}
535+
536+
${ _root_.Macros.map(arr, x => '{sum += $x}) }
537+
sum
579538
```
580539

581540
### Relationship with Whitebox Inline

docs/docs/reference/metaprogramming/staging.md

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,47 @@ layout: doc-page
33
title: "Multi-Stage Programming"
44
----
55

6-
The framework expresses at the same time compile-time meta-programming
7-
and staging. The phase in which code is run is determined by the
8-
difference between the number of splice scopes and quote scopes in
9-
which it is embedded.
10-
11-
- If there are more splices than quotes, the code is run at
12-
"compile-time" i.e. as a macro. In the general case, this means
13-
running an interpreter that evaluates the code, which is
14-
represented as a typed abstract syntax tree. The interpreter can
15-
fall back to reflective calls when evaluating an application of a
16-
previously compiled method. If the splice excess is more than one,
17-
it would mean that a macro’s implementation code (as opposed to the
18-
code it expands to) invokes other macros. If macros are realized by
19-
interpretation, this would lead to towers of interpreters, where
20-
the first interpreter would itself interpret an interpreter code
21-
that possibly interprets another interpreter and so on.
22-
23-
- If the number of splices equals the number of quotes, the code is
24-
compiled and run as usual.
25-
26-
- If the number of quotes exceeds the number of splices, the code is
27-
staged. That is, it produces a typed abstract syntax tree or type
28-
structure at run-time. A quote excess of more than one corresponds
29-
to multi-staged programming.
30-
31-
Providing an interpreter for the full language is quite difficult, and
32-
it is even more difficult to make that interpreter run efficiently. So
33-
we currently impose the following restrictions on the use of splices.
6+
The framework expresses at the same time compile-time meta-programming and
7+
multi-staging programming. We can think of compile-time meta-programming as a
8+
two stage compilation process: one that we write the code in top-level splices,
9+
that will be used for code generation (macros) and one that will perform all
10+
necessecary evaluations at compile-time and an object program that we will run
11+
as usual. What if we could synthesize code at runtime and offer one extra stage
12+
to the programmer? Then we can have a value of type `Expr[T]` at runtime that we
13+
can essentially treat as a typed-syntax tree that we can either _show_ as a
14+
string (pretty-print) or compile and run. If the number of quotes exceeds the
15+
number of splices more than one (effectively handling at run-time values of type
16+
`Expr[Expr[T]]`, `Expr[Expr[Expr[T]]]`, ... we talk about Multi-Stage
17+
Programming).
18+
19+
The motivation behind this _paradigm_ is to let runtime information affect or
20+
guide code-generation.
21+
22+
Intuition: The phase in which code is run is determined by the difference
23+
between the number of splice scopes and quote scopes in which it is embedded.
24+
25+
- If there are more splices than quotes, the code is run at "compile-time" i.e.
26+
as a macro. In the general case, this means running an interpreter that
27+
evaluates the code, which is represented as a typed abstract syntax tree. The
28+
interpreter can fall back to reflective calls when evaluating an application
29+
of a previously compiled method. If the splice excess is more than one, it
30+
would mean that a macro’s implementation code (as opposed to the code it
31+
expands to) invokes other macros. If macros are realized by interpretation,
32+
this would lead to towers of interpreters, where the first interpreter would
33+
itself interpret an interpreter code that possibly interprets another
34+
interpreter and so on.
35+
36+
- If the number of splices equals the number of quotes, the code is compiled
37+
and run as usual.
38+
39+
- If the number of quotes exceeds the number of splices, the code is staged.
40+
That is, it produces a typed abstract syntax tree or type structure at
41+
run-time. A quote excess of more than one corresponds to multi-staged
42+
programming.
43+
44+
Providing an interpreter for the full language is quite difficult, and it is
45+
even more difficult to make that interpreter run efficiently. So we currently
46+
impose the following restrictions on the use of splices.
3447

3548
1. A top-level splice must appear in an inline method (turning that method
3649
into a macro)
@@ -42,6 +55,8 @@ we currently impose the following restrictions on the use of splices.
4255

4356
4. A macro method is effectively final and it may override no other method.
4457

58+
## API
59+
4560
The framework as discussed so far allows code to be staged, i.e. be prepared
4661
to be executed at a later stage. To run that code, there is another method
4762
in class `Expr` called `run`. Note that `$` and `run` both map from `Expr[T]`
@@ -53,3 +68,17 @@ sealed abstract class Expr[T] {
5368
def show given (toolbox: Toolbox): String // show staged code
5469
}
5570
```
71+
72+
## Example
73+
74+
TODO
75+
sbt:dotty> dotr -classpath out -with-compiler Test
76+
77+
```scala
78+
// staging
79+
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make(getClass.getClassLoader)
80+
val sum_s = '{ (arr: Array[Int]) => ${sum('arr)}}
81+
println(sum_s.show)
82+
83+
sum_s.run.apply(Array(1, 2, 3)) // Returns 6
84+
```

docs/sidebar.yml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,20 @@ sidebar:
6767
url: docs/reference/contextual/inferable-by-name-parameters.html
6868
- title: Relationship with Scala 2 Implicits
6969
url: docs/reference/contextual/relationship-implicits.html
70+
- title: Metaprogramming
71+
subsection:
72+
- title: Overview
73+
url: docs/reference/metaprogramming/toc.html
74+
- title: Inline
75+
url: docs/reference/metaprogramming/inline.html
76+
- title: Macros
77+
url: docs/reference/metaprogramming/macros.html
78+
- title: Staging
79+
url: docs/reference/metaprogramming/staging.html
80+
- title: TASTy Reflection
81+
url: docs/reference/metaprogramming/tasty-reflect.html
82+
- title: TASTy Inspection
83+
url: docs/reference/metaprogramming/tasty-inspect.html
7084
- title: Other New Features
7185
subsection:
7286
- title: Trait Parameters
@@ -75,12 +89,6 @@ sidebar:
7589
url: docs/reference/other-new-features/creator-applications.html
7690
- title: Export Clauses
7791
url: docs/reference/other-new-features/export.html
78-
- title: Inlining by Rewriting
79-
url: docs/reference/other-new-features/inline.html
80-
- title: Meta Programming
81-
url: docs/reference/other-new-features/principled-meta-programming.html
82-
- title: TASTy Reflect
83-
url: docs/reference/other-new-features/tasty-reflect.html
8492
- title: Opaque Type Aliases
8593
url: docs/reference/other-new-features/opaques.html
8694
- title: Parameter Untupling

0 commit comments

Comments
 (0)