| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 | 4 |
| 5 library fancy_syntax.eval; | 5 library fancy_syntax.eval; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:mirrors'; | 9 import 'dart:mirrors'; |
| 10 | 10 |
| 11 import 'package:mdv_observe/mdv_observe.dart'; | 11 import 'package:mdv_observe/mdv_observe.dart'; |
| 12 | 12 |
| 13 import 'async.dart'; |
| 13 import 'expression.dart'; | 14 import 'expression.dart'; |
| 14 import 'filter.dart'; | 15 import 'filter.dart'; |
| 15 import 'visitor.dart'; | 16 import 'visitor.dart'; |
| 16 import 'parser.dart'; | 17 import 'parser.dart'; |
| 18 import 'src/mirrors.dart'; |
| 17 | 19 |
| 18 final _BINARY_OPERATORS = { | 20 final _BINARY_OPERATORS = { |
| 19 '+': (a, b) => a + b, | 21 '+': (a, b) => a + b, |
| 20 '-': (a, b) => a - b, | 22 '-': (a, b) => a - b, |
| 21 '*': (a, b) => a * b, | 23 '*': (a, b) => a * b, |
| 22 '/': (a, b) => a / b, | 24 '/': (a, b) => a / b, |
| 23 '==': (a, b) => a == b, | 25 '==': (a, b) => a == b, |
| 24 '!=': (a, b) => a != b, | 26 '!=': (a, b) => a != b, |
| 25 '>': (a, b) => a > b, | 27 '>': (a, b) => a > b, |
| 26 '>=': (a, b) => a >= b, | 28 '>=': (a, b) => a >= b, |
| 27 '<': (a, b) => a < b, | 29 '<': (a, b) => a < b, |
| 28 '<=': (a, b) => a <= b, | 30 '<=': (a, b) => a <= b, |
| 29 '||': (a, b) => a || b, | 31 '||': (a, b) => a || b, |
| 30 '&&': (a, b) => a && b, | 32 '&&': (a, b) => a && b, |
| 31 '|': (a, f) { | 33 '|': (a, f) { |
| 32 if (f is Transformer) return f.forward(a); | 34 if (f is Transformer) return f.forward(a); |
| 33 if (f is Filter) return f(a); | 35 if (f is Filter) return f(a); |
| 34 throw new EvalException("Filters must be a one-argument function."); | 36 throw new EvalException("Filters must be a one-argument function."); |
| 35 } | 37 } |
| 36 }; | 38 }; |
| 37 | 39 |
| 38 final _UNARY_OPERATORS = { | 40 final _UNARY_OPERATORS = { |
| 39 '+': (a) => a, | 41 '+': (a) => a, |
| 40 '-': (a) => -a, | 42 '-': (a) => -a, |
| 41 '!': (a) => !a, | 43 '!': (a) => !a, |
| 42 }; | 44 }; |
| 43 | 45 |
| 46 final _BOOLEAN_OPERATORS = ['!', '||', '&&']; |
| 47 |
| 44 /** | 48 /** |
| 45 * Evaluation [expr] in the context of [scope]. | 49 * Evaluation [expr] in the context of [scope]. |
| 46 */ | 50 */ |
| 47 Object eval(Expression expr, Scope scope) => observe(expr, scope)._value; | 51 Object eval(Expression expr, Scope scope) => observe(expr, scope)._value; |
| 48 | 52 |
| 49 | 53 |
| 50 ExpressionObserver observe(Expression expr, Scope scope) { | 54 ExpressionObserver observe(Expression expr, Scope scope) { |
| 51 var observer = new ObserverBuilder(scope).visit(expr); | 55 var observer = new ObserverBuilder(scope).visit(expr); |
| 52 new Updater(scope).visit(observer); | 56 new Updater(scope).visit(observer); |
| 53 return observer; | 57 return observer; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 : _variables = new ObservableMap.from(variables); | 137 : _variables = new ObservableMap.from(variables); |
| 134 | 138 |
| 135 InstanceMirror get _modelMirror { | 139 InstanceMirror get _modelMirror { |
| 136 if (__modelMirror != null) return __modelMirror; | 140 if (__modelMirror != null) return __modelMirror; |
| 137 __modelMirror = reflect(model); | 141 __modelMirror = reflect(model); |
| 138 return __modelMirror; | 142 return __modelMirror; |
| 139 } | 143 } |
| 140 | 144 |
| 141 Object operator[](String name) { | 145 Object operator[](String name) { |
| 142 if (_variables.containsKey(name)) { | 146 if (_variables.containsKey(name)) { |
| 143 return _variables[name]; | 147 return _convert(_variables[name]); |
| 144 } else if (model != null) { | 148 } else if (model != null) { |
| 145 var symbol = new Symbol(name); | 149 var symbol = new Symbol(name); |
| 146 var classMirror = _modelMirror.type; | 150 var classMirror = _modelMirror.type; |
| 147 if (classMirror.variables.containsKey(symbol) || | 151 var memberMirror = getMemberMirror(classMirror, symbol); |
| 148 classMirror.getters.containsKey(symbol)) { | 152 if (memberMirror is VariableMirror || |
| 149 return _modelMirror.getField(symbol).reflectee; | 153 (memberMirror is MethodMirror && memberMirror.isGetter)) { |
| 150 } else if (classMirror.methods.containsKey(symbol)) { | 154 return _convert(_modelMirror.getField(symbol).reflectee); |
| 155 } else if (memberMirror is MethodMirror) { |
| 151 return new Method(_modelMirror, symbol); | 156 return new Method(_modelMirror, symbol); |
| 152 } | 157 } |
| 153 } | 158 } |
| 154 if (parent != null) { | 159 if (parent != null) { |
| 155 return parent[name]; | 160 return _convert(parent[name]); |
| 156 } else { | 161 } else { |
| 157 throw new EvalException("variable not found: $name in $hashCode"); | 162 throw new EvalException("variable not found: $name in $hashCode"); |
| 158 } | 163 } |
| 159 } | 164 } |
| 160 | 165 |
| 161 Object ownerOf(String name) { | 166 Object ownerOf(String name) { |
| 162 if (_variables.containsKey(name)) { | 167 if (_variables.containsKey(name)) { |
| 163 return _variables; | 168 return _variables; |
| 164 } else { | 169 } else { |
| 165 var symbol = new Symbol(name); | 170 var symbol = new Symbol(name); |
| 166 var classMirror = _modelMirror.type; | 171 var classMirror = _modelMirror.type; |
| 167 if (classMirror.variables.containsKey(symbol) || | 172 if (getMemberMirror(classMirror, symbol) != null) { |
| 168 classMirror.getters.containsKey(symbol) || | |
| 169 classMirror.methods.containsKey(symbol)) { | |
| 170 return model; | 173 return model; |
| 171 } | 174 } |
| 172 } | 175 } |
| 173 if (parent != null) { | 176 if (parent != null) { |
| 174 return parent.ownerOf(name); | 177 return parent.ownerOf(name); |
| 175 } | 178 } |
| 176 } | 179 } |
| 180 |
| 181 bool contains(String name) { |
| 182 if (_variables.containsKey(name)) { |
| 183 return true; |
| 184 } else { |
| 185 var symbol = new Symbol(name); |
| 186 var classMirror = _modelMirror.type; |
| 187 if (getMemberMirror(classMirror, symbol) != null) { |
| 188 return true; |
| 189 } |
| 190 } |
| 191 if (parent != null) { |
| 192 return parent.contains(name); |
| 193 } |
| 194 return false; |
| 195 } |
| 196 |
| 197 String toString() => 'Scope($hashCode $parent)'; |
| 198 } |
| 199 |
| 200 Object _convert(v) { |
| 201 if (v is Stream) return new StreamBinding(v); |
| 202 return v; |
| 177 } | 203 } |
| 178 | 204 |
| 179 abstract class ExpressionObserver<E extends Expression> implements Expression { | 205 abstract class ExpressionObserver<E extends Expression> implements Expression { |
| 180 final E _expr; | 206 final E _expr; |
| 181 ExpressionObserver _parent; | 207 ExpressionObserver _parent; |
| 182 | 208 |
| 183 StreamSubscription _subscription; | 209 StreamSubscription _subscription; |
| 184 Object _value; | 210 Object _value; |
| 185 | 211 |
| 186 StreamController _controller = new StreamController.broadcast(); | 212 StreamController _controller = new StreamController.broadcast(); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 | 435 |
| 410 String get method => _expr.method; | 436 String get method => _expr.method; |
| 411 | 437 |
| 412 _updateSelf(Scope scope) { | 438 _updateSelf(Scope scope) { |
| 413 var args = (arguments == null) | 439 var args = (arguments == null) |
| 414 ? [] | 440 ? [] |
| 415 : arguments.map((a) => a._value) | 441 : arguments.map((a) => a._value) |
| 416 .toList(growable: false); | 442 .toList(growable: false); |
| 417 var receiverValue = receiver._value; | 443 var receiverValue = receiver._value; |
| 418 if (receiverValue == null) { | 444 if (receiverValue == null) { |
| 419 return null; | 445 _value = null; |
| 420 } | 446 } else if (_expr.method == null) { |
| 421 if (_expr.method == null) { | |
| 422 if (_expr.isGetter) { | 447 if (_expr.isGetter) { |
| 423 _value = receiverValue; | 448 _value = receiverValue; |
| 424 } else { | 449 } else { |
| 425 assert(receiverValue is Function); | 450 assert(receiverValue is Function); |
| 426 _value = call(receiverValue, args); | 451 _value = call(receiverValue, args); |
| 427 } | 452 } |
| 428 } else { | 453 } else { |
| 429 // special case [] because we don't need mirrors | 454 // special case [] because we don't need mirrors |
| 430 if (_expr.method == '[]') { | 455 if (_expr.method == '[]') { |
| 431 assert(args.length == 1); | 456 assert(args.length == 1); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 _value = new Comprehension(identifier.value, iterable); | 493 _value = new Comprehension(identifier.value, iterable); |
| 469 } | 494 } |
| 470 | 495 |
| 471 accept(Visitor v) => v.visitInExpression(this); | 496 accept(Visitor v) => v.visitInExpression(this); |
| 472 } | 497 } |
| 473 | 498 |
| 474 _toBool(v) => (v == null) ? false : v; | 499 _toBool(v) => (v == null) ? false : v; |
| 475 | 500 |
| 476 call(dynamic receiver, List args) { | 501 call(dynamic receiver, List args) { |
| 477 if (receiver is Method) { | 502 if (receiver is Method) { |
| 478 return receiver.mirror.invoke(receiver.symbol, args, null).reflectee; | 503 return |
| 504 _convert(receiver.mirror.invoke(receiver.symbol, args, null).reflectee); |
| 479 } else { | 505 } else { |
| 480 return Function.apply(receiver, args, null); | 506 return _convert(Function.apply(receiver, args, null)); |
| 481 } | 507 } |
| 482 } | 508 } |
| 483 | 509 |
| 484 /** | 510 /** |
| 485 * A comprehension declaration ("a in b"). | 511 * A comprehension declaration ("a in b"). |
| 486 */ | 512 */ |
| 487 class Comprehension { | 513 class Comprehension { |
| 488 final String identifier; | 514 final String identifier; |
| 489 final Iterable iterable; | 515 final Iterable iterable; |
| 490 Comprehension(this.identifier, this.iterable); | 516 Comprehension(this.identifier, this.iterable); |
| 491 } | 517 } |
| 492 | 518 |
| 493 /** | 519 /** |
| 494 * A method on a model object in a [Scope]. | 520 * A method on a model object in a [Scope]. |
| 495 */ | 521 */ |
| 496 class Method { //implements _FunctionWrapper { | 522 class Method { //implements _FunctionWrapper { |
| 497 final InstanceMirror mirror; | 523 final InstanceMirror mirror; |
| 498 final Symbol symbol; | 524 final Symbol symbol; |
| 499 | 525 |
| 500 Method(this.mirror, this.symbol); | 526 Method(this.mirror, this.symbol); |
| 501 | 527 |
| 502 dynamic call(List args) => mirror.invoke(symbol, args, null).reflectee; | 528 dynamic call(List args) => mirror.invoke(symbol, args, null).reflectee; |
| 503 } | 529 } |
| 504 | 530 |
| 505 class EvalException implements Exception { | 531 class EvalException implements Exception { |
| 506 final String message; | 532 final String message; |
| 507 EvalException(this.message); | 533 EvalException(this.message); |
| 508 String toString() => "EvalException: $message"; | 534 String toString() => "EvalException: $message"; |
| 509 } | 535 } |
| OLD | NEW |