Skip to content

Commit f86bcc5

Browse files
committed
Add environment to the interpreter
1 parent 82d36bd commit f86bcc5

File tree

4 files changed

+45
-14
lines changed

4 files changed

+45
-14
lines changed

compiler/src/dotty/tools/dotc/interpreter/Interpreter.scala

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import java.lang.reflect.Method
3030
class Interpreter(implicit ctx: Context) {
3131
import tpd._
3232

33+
type Env = Map[Symbol, Object]
34+
3335
private[this] val classLoader = {
3436
val urls = ctx.settings.classpath.value.split(':').map(cp => java.nio.file.Paths.get(cp).toUri.toURL)
3537
new URLClassLoader(urls, getClass.getClassLoader)
@@ -40,7 +42,7 @@ class Interpreter(implicit ctx: Context) {
4042
*/
4143
def interpretTree[T](tree: Tree)(implicit ct: ClassTag[T]): Option[T] = {
4244
try {
43-
interpretTreeImpl(tree) match {
45+
interpretTreeImpl(tree, Map.empty) match {
4446
case obj: T => Some(obj)
4547
case obj =>
4648
// TODO upgrade to a full type tag check or something similar
@@ -57,52 +59,76 @@ class Interpreter(implicit ctx: Context) {
5759
/** Returns the interpreted result of interpreting the code represented by the tree.
5860
* Returns the result of the interpreted tree.
5961
*
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.
6163
*/
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+
6371
implicit val pos: Position = tree.pos
72+
6473
tree match {
6574
case Quoted(quotedTree) => RawQuoted(quotedTree)
6675

67-
case Literal(Constant(c)) => c.asInstanceOf[AnyRef]
76+
case Literal(Constant(c)) => c.asInstanceOf[Object]
6877

6978
case Apply(fn, args) if fn.symbol.isConstructor =>
7079
val clazz = loadClass(fn.symbol.owner.symbol.fullName)
7180
val paramClasses = paramsSig(fn.symbol)
72-
val interpretedArgs = args.map(arg => interpretTreeImpl(arg))
81+
val interpretedArgs = args.map(arg => interpretTreeImpl(arg, env))
7382
val constructor = getConstructor(clazz, paramClasses)
7483
interpreted(constructor.newInstance(interpretedArgs: _*))
7584

7685
case _: RefTree | _: Apply if tree.symbol.isStatic =>
7786
val clazz = loadClass(tree.symbol.owner.companionModule.fullName)
7887
val paramClasses = paramsSig(tree.symbol)
79-
8088
val interpretedArgs = Array.newBuilder[Object]
8189
def interpretArgs(tree: Tree): Unit = tree match {
8290
case Apply(fn, args) =>
8391
interpretArgs(fn)
84-
args.foreach(arg => interpretedArgs += interpretTreeImpl(arg))
92+
args.foreach(arg => interpretedArgs += interpretTreeImpl(arg, env))
8593
case _ =>
8694
}
8795
interpretArgs(tree)
8896

8997
val method = getMethod(clazz, tree.symbol.name, paramClasses)
9098
interpreted(method.invoke(null, interpretedArgs.result(): _*))
9199

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)
95109

96110
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+
99114
case _ =>
100115
// TODO Add more precise descriptions of why it could not be interpreted.
101116
// 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)
103118
}
104119
}
105120

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+
106132
private def loadClass(name: Name)(implicit pos: Position): Class[_] = {
107133
try classLoader.loadClass(name.toString)
108134
catch {
@@ -135,7 +161,7 @@ class Interpreter(implicit ctx: Context) {
135161
catch {
136162
case ex: RuntimeException =>
137163
val sw = new StringWriter()
138-
sw.write("A runtime exception occurred while interpreting")
164+
sw.write("A runtime exception occurred while interpreting\n")
139165
sw.write(ex.getMessage)
140166
sw.write("\n")
141167
ex.printStackTrace(new PrintWriter(sw))

tests/run/quote-and-splice.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
4
44
3
55
5
6+
9
67
1.0
78
5.0
89
25.0

tests/run/quote-and-splice/Macros_1.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ object Macros {
1414
inline def macro4(i: Int)(j: Int) = ~ macro4Impl('(i))('(j))
1515
def macro4Impl(i: Expr[Int])(j: Expr[Int]) = '{ ~i + ~j }
1616

17+
inline def macro5(i: Int, j: Int) = ~ macro5Impl(j = '(j), i = '(i))
18+
def macro5Impl(i: Expr[Int], j: Expr[Int]) = '{ ~i + ~j }
19+
1720
inline def power(inline n: Int, x: Double) = ~powerCode(n, '(x))
1821

1922
def powerCode(n: Int, x: Expr[Double]): Expr[Double] =

tests/run/quote-and-splice/Test_2.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ object Test {
77
println(macro2(false))
88
println(macro3(1))
99
println(macro4(2)(3))
10+
println(macro5(4, 5))
1011
println(power(0, 5))
1112
println(power(1, 5))
1213
println(power(2, 5))

0 commit comments

Comments
 (0)