OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 library kernerl.interpreter; | 4 library kernerl.interpreter; |
5 | 5 |
6 import 'dart:collection'; | |
7 import '../ast.dart'; | 6 import '../ast.dart'; |
8 | 7 |
9 class NotImplemented { | 8 class NotImplemented { |
10 String message; | 9 String message; |
11 | 10 |
12 NotImplemented(this.message); | 11 NotImplemented(this.message); |
13 | 12 |
14 String toString() => message; | 13 String toString() => message; |
15 } | 14 } |
16 | 15 |
17 class Interpreter { | 16 class Interpreter { |
18 Program program; | 17 Program program; |
| 18 Evaluator evaluator = new Evaluator(); |
19 | 19 |
20 Interpreter(this.program); | 20 Interpreter(this.program); |
21 | 21 |
22 void evalProgram() { | 22 void run() { |
23 assert(program.libraries.isEmpty); | 23 assert(program.libraries.isEmpty); |
24 Procedure mainMethod = program.mainMethod; | 24 Procedure mainMethod = program.mainMethod; |
25 Statement statementBlock = mainMethod.function.body; | 25 Statement statementBlock = mainMethod.function.body; |
26 // Evaluate only statement with one expression, ExpressionStatement, which | 26 // Executes only ExpressionStatements and VariableDeclarations in the top |
27 // is StaticInvocation of the method print. | 27 // BlockStatement. |
28 if (statementBlock is Block) { | 28 if (statementBlock is Block) { |
29 Statement statement = statementBlock.statements.first; | 29 var env = new Environment.empty(); |
30 if (statement is ExpressionStatement) { | 30 |
31 statement.expression.accept1(new ExpressionEval1(), | 31 for (Statement s in statementBlock.statements) { |
32 new ExpressionState(new HashMap<String, Object>())); | 32 if (s is ExpressionStatement) { |
| 33 evaluator.eval(s.expression, env); |
| 34 } else if (s is VariableDeclaration) { |
| 35 var value = evaluator.eval(s.initializer ?? new NullLiteral(), env); |
| 36 env.expand(s, value); |
| 37 } else { |
| 38 throw new NotImplemented('Evaluation for statement type ' |
| 39 '${s.runtimeType} is not implemented.'); |
| 40 } |
33 } | 41 } |
34 } else { | 42 } else { |
35 throw new NotImplemented('Evaluation for statement type ' | 43 throw new NotImplemented('Evaluation for statement type ' |
36 '${statementBlock.runtimeType} is not implemented'); | 44 '${statementBlock.runtimeType} is not implemented.'); |
37 } | 45 } |
38 } | 46 } |
39 } | 47 } |
40 | 48 |
41 class InvalidExpressionError { | 49 class InvalidExpressionError { |
42 InvalidExpression expression; | 50 InvalidExpression expression; |
43 | 51 |
44 InvalidExpressionError(this.expression); | 52 InvalidExpressionError(this.expression); |
45 | 53 |
46 String toString() => 'Invalid expression at ' | 54 String toString() => |
47 '${expression.location.toString()}'; | 55 'Invalid expression at ${expression.location.toString()}'; |
48 } | 56 } |
49 | 57 |
50 class ExpressionState { | 58 class Binding { |
51 Map<String, Object> environment; | 59 final VariableDeclaration variable; |
| 60 Value value; |
52 | 61 |
53 ExpressionState(this.environment); | 62 Binding(this.variable, this.value); |
54 } | 63 } |
55 | 64 |
56 class ExpressionEval1 extends ExpressionVisitor1<Object> { | 65 class Environment { |
57 @override | 66 final List<Binding> bindings = <Binding>[]; |
58 Object defaultExpression(Expression node, arg) { | 67 final Environment parent; |
| 68 |
| 69 Environment.empty() : parent = null; |
| 70 Environment(this.parent); |
| 71 |
| 72 bool contains(VariableDeclaration variable) { |
| 73 for (Binding b in bindings.reversed) { |
| 74 if (identical(b.variable, variable)) return true; |
| 75 } |
| 76 return parent?.contains(variable) ?? false; |
| 77 } |
| 78 |
| 79 Binding lookupBinding(VariableDeclaration variable) { |
| 80 assert(contains(variable)); |
| 81 for (Binding b in bindings) { |
| 82 if (identical(b.variable, variable)) return b; |
| 83 } |
| 84 return parent.lookupBinding(variable); |
| 85 } |
| 86 |
| 87 Value lookup(VariableDeclaration variable) { |
| 88 return lookupBinding(variable).value; |
| 89 } |
| 90 |
| 91 void assign(VariableDeclaration variable, Value value) { |
| 92 assert(contains(variable)); |
| 93 lookupBinding(variable).value = value; |
| 94 } |
| 95 |
| 96 void expand(VariableDeclaration variable, Value value) { |
| 97 assert(!contains(variable)); |
| 98 bindings.add(new Binding(variable, value)); |
| 99 } |
| 100 } |
| 101 |
| 102 class Evaluator extends ExpressionVisitor1<Value> { |
| 103 Value eval(Expression expr, Environment env) => expr.accept1(this, env); |
| 104 |
| 105 Value defaultExpression(Expression node, env) { |
59 throw new NotImplemented('Evaluation for expressions of type ' | 106 throw new NotImplemented('Evaluation for expressions of type ' |
60 '${node.runtimeType} is not implemented.'); | 107 '${node.runtimeType} is not implemented.'); |
61 } | 108 } |
62 | 109 |
63 Object visitInvalidExpression1(InvalidExpression node, arg) => | 110 Value visitInvalidExpression1(InvalidExpression node, env) { |
64 throw new InvalidExpressionError(node); | 111 throw new InvalidExpressionError(node); |
| 112 } |
65 | 113 |
66 Object visitStaticInvocation(StaticInvocation node, arg) { | 114 Value visitVariableGet(VariableGet node, env) { |
| 115 return env.lookup(node.variable); |
| 116 } |
| 117 |
| 118 Value visitVariableSet(VariableSet node, env) { |
| 119 return env.assign(node.variable, eval(node.value, env)); |
| 120 } |
| 121 |
| 122 Value visitStaticInvocation(StaticInvocation node, env) { |
67 if ('print' == node.name.toString()) { | 123 if ('print' == node.name.toString()) { |
68 // Special evaluation of print. | 124 // Special evaluation of print. |
69 var res = node.arguments.positional[0].accept1(this, arg); | 125 var res = eval(node.arguments.positional[0], env); |
70 print(res); | 126 print(res.value); |
| 127 return new NullValue(); |
71 } else { | 128 } else { |
72 throw new NotImplemented('Support for statement type ' | 129 throw new NotImplemented('Support for statement type ' |
73 '${node.runtimeType} is not implemented'); | 130 '${node.runtimeType} is not implemented'); |
74 } | 131 } |
75 } | 132 } |
76 | 133 |
| 134 Value visitNot(Not node, env) { |
| 135 return new BoolValue(!eval(node.operand, env).asBool); |
| 136 } |
| 137 |
| 138 Value visitLogicalExpression(LogicalExpression node, env) { |
| 139 if ('||' == node.operator) { |
| 140 bool left = eval(node.left, env).asBool; |
| 141 return left |
| 142 ? new BoolValue(true) |
| 143 : new BoolValue(eval(node.right, env).asBool); |
| 144 } else { |
| 145 assert('&&' == node.operator); |
| 146 bool left = eval(node.left, env).asBool; |
| 147 return !left |
| 148 ? new BoolValue(false) |
| 149 : new BoolValue(eval(node.right, env).asBool); |
| 150 } |
| 151 } |
| 152 |
| 153 Value visitConditionalExpression(ConditionalExpression node, env) { |
| 154 if (eval(node.condition, env).asBool) { |
| 155 return eval(node.then, env); |
| 156 } else { |
| 157 return eval(node.otherwise, env); |
| 158 } |
| 159 } |
| 160 |
| 161 Value visitStringConcatenation(StringConcatenation node, env) { |
| 162 StringBuffer res = new StringBuffer(); |
| 163 for (Expression e in node.expressions) { |
| 164 res.write(eval(e, env).value); |
| 165 } |
| 166 return new StringValue(res.toString()); |
| 167 } |
| 168 |
77 // Evaluation of BasicLiterals. | 169 // Evaluation of BasicLiterals. |
78 Object visitStringLiteral(StringLiteral node, arg) => node.value; | 170 Value visitStringLiteral(StringLiteral node, env) => |
79 Object visitIntLiteral(IntLiteral node, arg) => node.value; | 171 new StringValue(node.value); |
80 Object visitDoubleLiteral(DoubleLiteral node, arg) => node.value; | 172 Value visitIntLiteral(IntLiteral node, env) => new IntValue(node.value); |
81 Object visitBoolLiteral(BoolLiteral node, arg) => node.value; | 173 Value visitDoubleLiteral(DoubleLiteral node, env) => |
82 Object visitNullLiteral(NullLiteral node, arg) => node.value; | 174 new DoubleValue(node.value); |
| 175 Value visitBoolLiteral(BoolLiteral node, env) => new BoolValue(node.value); |
| 176 Value visitNullLiteral(NullLiteral node, env) => new NullValue(); |
| 177 |
| 178 Value visitLet(Let node, env) { |
| 179 var value = eval(node.variable.initializer, env); |
| 180 var letEnv = new Environment(env); |
| 181 letEnv.expand(node.variable, value); |
| 182 return eval(node.body, letEnv); |
| 183 } |
83 } | 184 } |
| 185 |
| 186 abstract class Value { |
| 187 Object get value; |
| 188 bool get asBool; |
| 189 } |
| 190 |
| 191 class StringValue extends Value { |
| 192 String value; |
| 193 |
| 194 bool get asBool => false; |
| 195 |
| 196 StringValue(this.value); |
| 197 } |
| 198 |
| 199 class IntValue extends Value { |
| 200 int value; |
| 201 |
| 202 bool get asBool => false; |
| 203 |
| 204 IntValue(this.value); |
| 205 } |
| 206 |
| 207 class DoubleValue extends Value { |
| 208 double value; |
| 209 |
| 210 bool get asBool => false; |
| 211 |
| 212 DoubleValue(this.value); |
| 213 } |
| 214 |
| 215 class BoolValue extends Value { |
| 216 bool value; |
| 217 |
| 218 bool get asBool => value; |
| 219 |
| 220 BoolValue(this.value); |
| 221 } |
| 222 |
| 223 class NullValue extends Value { |
| 224 Object get value => null; |
| 225 bool get asBool => false; |
| 226 } |
| 227 |
| 228 Object error(obj) { |
| 229 // TODO: Implement accordingly with support for error handling. |
| 230 throw new ArgumentError(obj); |
| 231 } |
OLD | NEW |