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