Chromium Code Reviews| 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 kernel.interpreter; |
| 5 | 5 |
| 6 import '../ast.dart'; | 6 import '../ast.dart'; |
| 7 | 7 |
| 8 class NotImplemented { | 8 class NotImplemented { |
| 9 String message; | 9 String message; |
| 10 | 10 |
| 11 NotImplemented(this.message); | 11 NotImplemented(this.message); |
| 12 | 12 |
| 13 String toString() => message; | 13 String toString() => message; |
| 14 } | 14 } |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 117 | 117 |
| 118 Value visitVariableSet(VariableSet node, env) { | 118 Value visitVariableSet(VariableSet node, env) { |
| 119 return env.assign(node.variable, eval(node.value, env)); | 119 return env.assign(node.variable, eval(node.value, env)); |
| 120 } | 120 } |
| 121 | 121 |
| 122 Value visitStaticInvocation(StaticInvocation node, env) { | 122 Value visitStaticInvocation(StaticInvocation node, env) { |
| 123 if ('print' == node.name.toString()) { | 123 if ('print' == node.name.toString()) { |
| 124 // Special evaluation of print. | 124 // Special evaluation of print. |
| 125 var res = eval(node.arguments.positional[0], env); | 125 var res = eval(node.arguments.positional[0], env); |
| 126 print(res.value); | 126 print(res.value); |
| 127 return new NullValue(); | 127 return Value.nullInstance; |
| 128 } else { | 128 } else { |
| 129 throw new NotImplemented('Support for statement type ' | 129 throw new NotImplemented('Support for statement type ' |
| 130 '${node.runtimeType} is not implemented'); | 130 '${node.runtimeType} is not implemented'); |
| 131 } | 131 } |
| 132 } | 132 } |
| 133 | 133 |
| 134 Value visitMethodInvocation(MethodInvocation node, env) { | |
| 135 // Currently supports only method invocation with <2 arguments and is used | |
| 136 // to evaluate implemented operators for int, double and String values. | |
| 137 var receiver = eval(node.receiver, env); | |
| 138 if (node.arguments.positional.isNotEmpty) { | |
| 139 var argValue = eval(node.arguments.positional.first, env); | |
| 140 return receiver.callMethod(node.name.name, argValue); | |
|
Kevin Millikin (Google)
2017/03/21 11:55:05
We might choose the name 'invokeMethod' to match '
zhivkag
2017/03/21 12:14:48
Done.
| |
| 141 } else { | |
| 142 return receiver.callMethod(node.name.name); | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 Value visitConstructorInvocation(ConstructorInvocation node, env) => | |
| 147 defaultExpression(node, env); | |
| 148 | |
| 134 Value visitNot(Not node, env) { | 149 Value visitNot(Not node, env) { |
| 135 return new BoolValue(!eval(node.operand, env).asBool); | 150 Value operand = eval(node.operand, env).toBoolean(); |
| 151 return identical(operand, Value.trueInstance) | |
| 152 ? Value.falseInstance | |
| 153 : Value.trueInstance; | |
| 136 } | 154 } |
| 137 | 155 |
| 138 Value visitLogicalExpression(LogicalExpression node, env) { | 156 Value visitLogicalExpression(LogicalExpression node, env) { |
| 139 if ('||' == node.operator) { | 157 if ('||' == node.operator) { |
| 140 bool left = eval(node.left, env).asBool; | 158 BoolValue left = eval(node.left, env).toBoolean(); |
| 141 return left | 159 return identical(left, Value.trueInstance) |
| 142 ? new BoolValue(true) | 160 ? Value.trueInstance |
| 143 : new BoolValue(eval(node.right, env).asBool); | 161 : eval(node.right, env).toBoolean(); |
| 144 } else { | 162 } else { |
| 145 assert('&&' == node.operator); | 163 assert('&&' == node.operator); |
| 146 bool left = eval(node.left, env).asBool; | 164 BoolValue left = eval(node.left, env).toBoolean(); |
| 147 return !left | 165 return identical(left, Value.falseInstance) |
| 148 ? new BoolValue(false) | 166 ? Value.falseInstance |
| 149 : new BoolValue(eval(node.right, env).asBool); | 167 : eval(node.right, env).toBoolean(); |
| 150 } | 168 } |
| 151 } | 169 } |
| 152 | 170 |
| 153 Value visitConditionalExpression(ConditionalExpression node, env) { | 171 Value visitConditionalExpression(ConditionalExpression node, env) { |
| 154 if (eval(node.condition, env).asBool) { | 172 var condition = eval(node.condition, env).toBoolean(); |
| 155 return eval(node.then, env); | 173 return identical(condition, Value.trueInstance) |
| 156 } else { | 174 ? eval(node.then, env) |
| 157 return eval(node.otherwise, env); | 175 : eval(node.otherwise, env); |
| 158 } | |
| 159 } | 176 } |
| 160 | 177 |
| 161 Value visitStringConcatenation(StringConcatenation node, env) { | 178 Value visitStringConcatenation(StringConcatenation node, env) { |
| 162 StringBuffer res = new StringBuffer(); | 179 StringBuffer res = new StringBuffer(); |
| 163 for (Expression e in node.expressions) { | 180 for (Expression e in node.expressions) { |
| 164 res.write(eval(e, env).value); | 181 res.write(eval(e, env).value); |
| 165 } | 182 } |
| 166 return new StringValue(res.toString()); | 183 return new StringValue(res.toString()); |
| 167 } | 184 } |
| 168 | 185 |
| 169 // Evaluation of BasicLiterals. | 186 // Evaluation of BasicLiterals. |
| 170 Value visitStringLiteral(StringLiteral node, env) => | 187 Value visitStringLiteral(StringLiteral node, env) => |
| 171 new StringValue(node.value); | 188 new StringValue(node.value); |
| 172 Value visitIntLiteral(IntLiteral node, env) => new IntValue(node.value); | 189 Value visitIntLiteral(IntLiteral node, env) => new IntValue(node.value); |
| 173 Value visitDoubleLiteral(DoubleLiteral node, env) => | 190 Value visitDoubleLiteral(DoubleLiteral node, env) => |
| 174 new DoubleValue(node.value); | 191 new DoubleValue(node.value); |
| 175 Value visitBoolLiteral(BoolLiteral node, env) => new BoolValue(node.value); | 192 Value visitBoolLiteral(BoolLiteral node, env) => |
| 176 Value visitNullLiteral(NullLiteral node, env) => new NullValue(); | 193 node.value ? Value.trueInstance : Value.falseInstance; |
| 194 Value visitNullLiteral(NullLiteral node, env) => Value.nullInstance; | |
| 177 | 195 |
| 178 Value visitLet(Let node, env) { | 196 Value visitLet(Let node, env) { |
| 179 var value = eval(node.variable.initializer, env); | 197 var value = eval(node.variable.initializer, env); |
| 180 var letEnv = new Environment(env); | 198 var letEnv = new Environment(env); |
| 181 letEnv.expand(node.variable, value); | 199 letEnv.expand(node.variable, value); |
| 182 return eval(node.body, letEnv); | 200 return eval(node.body, letEnv); |
| 183 } | 201 } |
| 184 } | 202 } |
| 185 | 203 |
| 204 class ClassDeclaration { | |
|
Kevin Millikin (Google)
2017/03/21 11:55:05
Hmmm. This isn't the declaration, it's our repres
zhivkag
2017/03/21 12:14:48
Acknowledged.
| |
| 205 static final Map<Reference, ClassDeclaration> _classes = | |
| 206 <Reference, ClassDeclaration>{}; | |
| 207 | |
| 208 Class currentClass; | |
| 209 ClassDeclaration superClass; | |
| 210 // The initializers of static fields are evaluated the first time the field | |
| 211 // is accessed. | |
| 212 List<Value> staticFields = <Value>[]; | |
| 213 List<Procedure> getters = <Procedure>[]; | |
| 214 List<Procedure> setters = <Procedure>[]; | |
| 215 List<Procedure> methods = <Procedure>[]; | |
| 216 | |
| 217 factory ClassDeclaration(Reference classRef) { | |
| 218 if (_classes.containsKey(classRef)) { | |
| 219 return _classes[classRef]; | |
| 220 } | |
| 221 _classes[classRef] = new ClassDeclaration._internal(classRef.asClass); | |
| 222 return _classes[classRef]; | |
| 223 } | |
| 224 | |
| 225 ClassDeclaration._internal(this.currentClass) { | |
| 226 if (currentClass.superclass != null) { | |
| 227 superClass = new ClassDeclaration(currentClass.superclass.reference); | |
| 228 } | |
| 229 // TODO: Populate getters, setters and methods. | |
| 230 } | |
| 231 } | |
| 232 | |
| 186 abstract class Value { | 233 abstract class Value { |
| 187 Object get value; | 234 Object get value; |
| 188 bool get asBool; | 235 |
| 236 static final NullValue nullInstance = const NullValue(); | |
| 237 static final BoolValue trueInstance = const BoolValue(true); | |
| 238 static final BoolValue falseInstance = const BoolValue(false); | |
| 239 | |
| 240 const Value(); | |
| 241 | |
| 242 BoolValue toBoolean() { | |
| 243 return identical(this, Value.trueInstance) | |
| 244 ? Value.trueInstance | |
| 245 : Value.falseInstance; | |
| 246 } | |
| 247 | |
| 248 BoolValue equals(Value other) => | |
| 249 value == other.value ? Value.trueInstance : Value.falseInstance; | |
| 250 | |
| 251 Value callMethod(String name, [Value arg]) { | |
| 252 throw notImplemented(obj: name); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 class ObjectValue extends Value { | |
| 257 List<Value> fields; | |
| 258 ClassDeclaration classDeclaration; | |
| 259 | |
| 260 Object get value => this; | |
| 261 | |
| 262 ObjectValue(Constructor constructor, Environment env) { | |
| 263 // TODO: Init fields and eval initializers, repeat the same with super. | |
| 264 // TODO: Eval the Function body of the constructor, with env expanded with | |
| 265 // {VariableDeclaration("this") => this} | |
| 266 notImplemented(obj: constructor.name); | |
| 267 } | |
| 189 } | 268 } |
| 190 | 269 |
| 191 class StringValue extends Value { | 270 class StringValue extends Value { |
| 192 String value; | 271 final String value; |
| 193 | 272 |
| 194 bool get asBool => false; | 273 static final operators = <String, Function>{ |
| 274 '[]': (StringValue v1, Value v2) => v1[v2], | |
| 275 '==': (StringValue v1, Value v2) => v1.equals(v2) | |
| 276 }; | |
| 195 | 277 |
| 196 StringValue(this.value); | 278 StringValue(this.value); |
| 279 | |
| 280 Value callMethod(String name, [Value arg]) { | |
| 281 if (!operators.containsKey(name)) { | |
| 282 return notImplemented(obj: name); | |
| 283 } | |
| 284 return operators[name](this, arg); | |
| 285 } | |
| 286 | |
| 287 // Operators | |
| 288 Value operator [](Value index) => new StringValue(value[index.value]); | |
| 197 } | 289 } |
| 198 | 290 |
| 199 class IntValue extends Value { | 291 abstract class NumValue extends Value { |
| 200 int value; | 292 num get value; |
| 201 | 293 |
| 202 bool get asBool => false; | 294 NumValue(); |
| 295 | |
| 296 factory NumValue.fromValue(num value) { | |
| 297 if (value is int) { | |
| 298 return new IntValue(value); | |
| 299 } else { | |
| 300 assert(value is double); | |
| 301 return new DoubleValue(value); | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 static final operators = <String, Function>{ | |
| 306 '+': (NumValue v1, Value v2) => v1 + v2, | |
| 307 '-': (NumValue v1, Value v2) => v1 - v2, | |
| 308 '>': (NumValue v1, Value v2) => v1 > v2, | |
| 309 '<': (NumValue v1, Value v2) => v1 < v2, | |
| 310 '==': (NumValue v1, Value v2) => v1.equals(v2), | |
| 311 'unary-': (NumValue v1) => -v1, | |
| 312 }; | |
| 313 | |
| 314 Value callMethod(String name, [Value arg]) { | |
| 315 if (!operators.containsKey(name)) return notImplemented(obj: name); | |
| 316 if (arg == null) return operators[name](this); | |
| 317 return operators[name](this, arg); | |
| 318 } | |
| 319 | |
| 320 // Operators | |
| 321 NumValue operator +(Value other) => | |
| 322 new NumValue.fromValue(value + other.value); | |
| 323 NumValue operator -(Value other) => | |
| 324 new NumValue.fromValue(value - other.value); | |
| 325 NumValue operator -() => new NumValue.fromValue(-value); | |
| 326 | |
| 327 BoolValue operator >(Value other) => | |
| 328 value > other.value ? Value.trueInstance : Value.falseInstance; | |
| 329 BoolValue operator <(Value other) => | |
| 330 value < other.value ? Value.trueInstance : Value.falseInstance; | |
| 331 } | |
| 332 | |
| 333 class IntValue extends NumValue { | |
| 334 final int value; | |
| 203 | 335 |
| 204 IntValue(this.value); | 336 IntValue(this.value); |
| 205 } | 337 } |
| 206 | 338 |
| 207 class DoubleValue extends Value { | 339 class DoubleValue extends NumValue { |
| 208 double value; | 340 final double value; |
| 209 | |
| 210 bool get asBool => false; | |
| 211 | 341 |
| 212 DoubleValue(this.value); | 342 DoubleValue(this.value); |
| 213 } | 343 } |
| 214 | 344 |
| 215 class BoolValue extends Value { | 345 class BoolValue extends Value { |
| 216 bool value; | 346 final bool value; |
| 217 | 347 |
| 218 bool get asBool => value; | 348 const BoolValue(this.value); |
| 219 | |
| 220 BoolValue(this.value); | |
| 221 } | 349 } |
| 222 | 350 |
| 223 class NullValue extends Value { | 351 class NullValue extends Value { |
| 224 Object get value => null; | 352 Object get value => null; |
| 225 bool get asBool => false; | 353 |
| 354 const NullValue(); | |
| 226 } | 355 } |
| 227 | 356 |
| 228 Object error(obj) { | 357 notImplemented({String m, Object obj}) { |
| 229 // TODO: Implement accordingly with support for error handling. | 358 throw new NotImplemented(m ?? 'Evaluation for $obj is not implemented'); |
| 230 throw new ArgumentError(obj); | |
| 231 } | 359 } |
| OLD | NEW |