@@ -30,6 +30,8 @@ import java.lang.reflect.Method
30
30
class Interpreter (implicit ctx : Context ) {
31
31
import tpd ._
32
32
33
+ type Env = Map [Symbol , Object ]
34
+
33
35
private [this ] val classLoader = {
34
36
val urls = ctx.settings.classpath.value.split(':' ).map(cp => java.nio.file.Paths .get(cp).toUri.toURL)
35
37
new URLClassLoader (urls, getClass.getClassLoader)
@@ -40,7 +42,7 @@ class Interpreter(implicit ctx: Context) {
40
42
*/
41
43
def interpretTree [T ](tree : Tree )(implicit ct : ClassTag [T ]): Option [T ] = {
42
44
try {
43
- interpretTreeImpl(tree) match {
45
+ interpretTreeImpl(tree, Map .empty ) match {
44
46
case obj : T => Some (obj)
45
47
case obj =>
46
48
// TODO upgrade to a full type tag check or something similar
@@ -57,52 +59,76 @@ class Interpreter(implicit ctx: Context) {
57
59
/** Returns the interpreted result of interpreting the code represented by the tree.
58
60
* Returns the result of the interpreted tree.
59
61
*
60
- * If some error is encountered while interpreting a ctx.error is emited and a StopInterpretation is thrown.
62
+ * If some error is encountered while interpreting a ctx.error is emitted and a StopInterpretation is thrown.
61
63
*/
62
- private def interpretTreeImpl (tree : Tree ): Object = { // TODO add environment
64
+ private def interpretTreeImpl (tree : Tree , env : Env ): Object = {
65
+ ctx.debuglog(
66
+ s """ Interpreting:
67
+ | ${tree.show}
68
+ | $env
69
+ """ .stripMargin)
70
+
63
71
implicit val pos : Position = tree.pos
72
+
64
73
tree match {
65
74
case Quoted (quotedTree) => RawQuoted (quotedTree)
66
75
67
- case Literal (Constant (c)) => c.asInstanceOf [AnyRef ]
76
+ case Literal (Constant (c)) => c.asInstanceOf [Object ]
68
77
69
78
case Apply (fn, args) if fn.symbol.isConstructor =>
70
79
val clazz = loadClass(fn.symbol.owner.symbol.fullName)
71
80
val paramClasses = paramsSig(fn.symbol)
72
- val interpretedArgs = args.map(arg => interpretTreeImpl(arg))
81
+ val interpretedArgs = args.map(arg => interpretTreeImpl(arg, env ))
73
82
val constructor = getConstructor(clazz, paramClasses)
74
83
interpreted(constructor.newInstance(interpretedArgs : _* ))
75
84
76
85
case _ : RefTree | _ : Apply if tree.symbol.isStatic =>
77
86
val clazz = loadClass(tree.symbol.owner.companionModule.fullName)
78
87
val paramClasses = paramsSig(tree.symbol)
79
-
80
88
val interpretedArgs = Array .newBuilder[Object ]
81
89
def interpretArgs (tree : Tree ): Unit = tree match {
82
90
case Apply (fn, args) =>
83
91
interpretArgs(fn)
84
- args.foreach(arg => interpretedArgs += interpretTreeImpl(arg))
92
+ args.foreach(arg => interpretedArgs += interpretTreeImpl(arg, env ))
85
93
case _ =>
86
94
}
87
95
interpretArgs(tree)
88
96
89
97
val method = getMethod(clazz, tree.symbol.name, paramClasses)
90
98
interpreted(method.invoke(null , interpretedArgs.result(): _* ))
91
99
92
- // case tree: RefTree if tree.symbol.is(Module) => // TODO
93
- // case Block(stats, expr) => // TODO evaluate bindings add environment
94
- // case ValDef(_, _, rhs) => // TODO evaluate bindings add environment
100
+ case tree : Ident if env.contains(tree.symbol) =>
101
+ env(tree.symbol)
102
+
103
+ case Block (stats, expr) =>
104
+ val env2 = stats.foldLeft(env)((acc, x) => interpretStat(x, acc))
105
+ interpretTreeImpl(expr, env2)
106
+
107
+ case tree : NamedArg =>
108
+ interpretTreeImpl(tree.arg, env)
95
109
96
110
case Inlined (_, bindings, expansion) =>
97
- assert(bindings.isEmpty) // TODO evaluate bindings and add environment
98
- interpretTreeImpl(expansion)
111
+ val env2 = bindings.foldLeft(env)((acc, x) => interpretStat(x, acc))
112
+ interpretTreeImpl(expansion, env2)
113
+
99
114
case _ =>
100
115
// TODO Add more precise descriptions of why it could not be interpreted.
101
116
// This should be done after the full interpreter is implemented.
102
- throw new StopInterpretation (s " Could not interpret ${tree.show}" , tree.pos)
117
+ throw new StopInterpretation (s " Could not interpret ${tree.show}\n ${tree} " , tree.pos)
103
118
}
104
119
}
105
120
121
+ /** Interprets the statement and returns the updated environment */
122
+ private def interpretStat (stat : Tree , env : Env ): Env = stat match {
123
+ case tree : ValDef =>
124
+ val obj = interpretTreeImpl(tree.rhs, env)
125
+ env.updated(tree.symbol, obj)
126
+
127
+ case _ =>
128
+ interpretTreeImpl(stat, env)
129
+ env
130
+ }
131
+
106
132
private def loadClass (name : Name )(implicit pos : Position ): Class [_] = {
107
133
try classLoader.loadClass(name.toString)
108
134
catch {
@@ -135,7 +161,7 @@ class Interpreter(implicit ctx: Context) {
135
161
catch {
136
162
case ex : RuntimeException =>
137
163
val sw = new StringWriter ()
138
- sw.write(" A runtime exception occurred while interpreting" )
164
+ sw.write(" A runtime exception occurred while interpreting\n " )
139
165
sw.write(ex.getMessage)
140
166
sw.write(" \n " )
141
167
ex.printStackTrace(new PrintWriter (sw))
0 commit comments