@@ -3,34 +3,47 @@ layout: doc-page
3
3
title : " Multi-Stage Programming"
4
4
----
5
5
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.
34
47
35
48
1. A top-level splice must appear in an inline method (turning that method
36
49
into a macro)
@@ -42,6 +55,8 @@ we currently impose the following restrictions on the use of splices.
42
55
43
56
4. A macro method is effectively final and it may override no other method.
44
57
58
+ # # API
59
+
45
60
The framework as discussed so far allows code to be staged, i.e. be prepared
46
61
to be executed at a later stage. To run that code, there is another method
47
62
in class `Expr` called `run`. Note that `$` and `run` both map from `Expr[T]`
@@ -53,3 +68,17 @@ sealed abstract class Expr[T] {
53
68
def show given (toolbox: Toolbox): String // show staged code
54
69
}
55
70
` ` `
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
+ ` ` `
0 commit comments