Chromium Code Reviews| 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 polymer_expressions.eval; | 5 library polymer_expressions.eval; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 | 9 |
| 10 @MirrorsUsed(metaTargets: const [Reflectable, ObservableProperty], | 10 @MirrorsUsed(metaTargets: const [Reflectable, ObservableProperty], |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 208 var classMirror = _modelMirror.type; | 208 var classMirror = _modelMirror.type; |
| 209 if (getMemberMirror(classMirror, symbol) != null) { | 209 if (getMemberMirror(classMirror, symbol) != null) { |
| 210 return model; | 210 return model; |
| 211 } | 211 } |
| 212 } | 212 } |
| 213 if (parent != null) { | 213 if (parent != null) { |
| 214 return parent.ownerOf(name); | 214 return parent.ownerOf(name); |
| 215 } | 215 } |
| 216 } | 216 } |
| 217 | 217 |
| 218 bool contains(String name) { | |
| 219 if (_variables.containsKey(name)) { | |
| 220 return true; | |
| 221 } else { | |
| 222 var symbol = new Symbol(name); | |
| 223 var classMirror = _modelMirror.type; | |
| 224 if (getMemberMirror(classMirror, symbol) != null) { | |
| 225 return true; | |
| 226 } | |
| 227 } | |
| 228 if (parent != null) { | |
| 229 return parent.contains(name); | |
| 230 } | |
| 231 return false; | |
| 232 } | |
| 233 } | 218 } |
| 234 | 219 |
| 235 Object _convert(v) { | 220 Object _convert(v) { |
| 236 if (v is Stream) return new StreamBinding(v); | 221 if (v is Stream) return new StreamBinding(v); |
| 237 return v; | 222 return v; |
| 238 } | 223 } |
| 239 | 224 |
| 240 abstract class ExpressionObserver<E extends Expression> implements Expression { | 225 abstract class ExpressionObserver<E extends Expression> implements Expression { |
| 241 final E _expr; | 226 final E _expr; |
| 242 ExpressionObserver _parent; | 227 ExpressionObserver _parent; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 } | 268 } |
| 284 | 269 |
| 285 class Updater extends RecursiveVisitor { | 270 class Updater extends RecursiveVisitor { |
| 286 final Scope scope; | 271 final Scope scope; |
| 287 | 272 |
| 288 Updater(this.scope); | 273 Updater(this.scope); |
| 289 | 274 |
| 290 visitExpression(ExpressionObserver e) { | 275 visitExpression(ExpressionObserver e) { |
| 291 e._observe(scope); | 276 e._observe(scope); |
| 292 } | 277 } |
| 293 | |
| 294 visitInExpression(InObserver c) { | |
| 295 visit(c.right); | |
| 296 visitExpression(c); | |
| 297 } | |
| 298 } | 278 } |
| 299 | 279 |
| 300 class ObserverBuilder extends Visitor { | 280 class ObserverBuilder extends Visitor { |
| 301 final Scope scope; | 281 final Scope scope; |
| 302 final Queue parents = new Queue(); | 282 final Queue parents = new Queue(); |
| 303 | 283 |
| 304 ObserverBuilder(this.scope); | 284 ObserverBuilder(this.scope); |
| 305 | 285 |
| 306 visitEmptyExpression(EmptyExpression e) => new EmptyObserver(e); | 286 visitEmptyExpression(EmptyExpression e) => new EmptyObserver(e); |
| 307 | 287 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 var trueExpr = visit(o.trueExpr); | 362 var trueExpr = visit(o.trueExpr); |
| 383 var falseExpr = visit(o.falseExpr); | 363 var falseExpr = visit(o.falseExpr); |
| 384 var ternary = new TernaryObserver(o, condition, trueExpr, falseExpr); | 364 var ternary = new TernaryObserver(o, condition, trueExpr, falseExpr); |
| 385 condition._parent = ternary; | 365 condition._parent = ternary; |
| 386 trueExpr._parent = ternary; | 366 trueExpr._parent = ternary; |
| 387 falseExpr._parent = ternary; | 367 falseExpr._parent = ternary; |
| 388 return ternary; | 368 return ternary; |
| 389 } | 369 } |
| 390 | 370 |
| 391 visitInExpression(InExpression i) { | 371 visitInExpression(InExpression i) { |
| 392 // don't visit the left. It's an identifier, but we don't want to evaluate | 372 throw "can't eval an in expression"; |
|
Jennifer Messerly
2014/01/31 02:48:50
throw new UnsupportedError?
justinfagnani
2014/03/12 23:21:30
Done.
| |
| 393 // it, we just want to add it to the comprehension object | |
| 394 var left = visit(i.left); | |
| 395 var right = visit(i.right); | |
| 396 var inexpr = new InObserver(i, left, right); | |
| 397 right._parent = inexpr; | |
| 398 return inexpr; | |
| 399 } | 373 } |
| 374 | |
| 375 visitAsExpression(AsExpression i) { | |
| 376 throw "can't eval an as expression"; | |
| 377 } | |
| 378 | |
| 400 } | 379 } |
| 401 | 380 |
| 402 class EmptyObserver extends ExpressionObserver<EmptyExpression> | 381 class EmptyObserver extends ExpressionObserver<EmptyExpression> |
| 403 implements EmptyExpression { | 382 implements EmptyExpression { |
| 404 | 383 |
| 405 EmptyObserver(EmptyExpression value) : super(value); | 384 EmptyObserver(EmptyExpression value) : super(value); |
| 406 | 385 |
| 407 _updateSelf(Scope scope) { | 386 _updateSelf(Scope scope) { |
| 408 _value = scope.model; | 387 _value = scope.model; |
| 409 // TODO(justin): listen for scope.model changes? | 388 // TODO(justin): listen for scope.model changes? |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 669 _invalidate(scope); | 648 _invalidate(scope); |
| 670 } | 649 } |
| 671 }); | 650 }); |
| 672 } | 651 } |
| 673 } | 652 } |
| 674 } | 653 } |
| 675 | 654 |
| 676 accept(Visitor v) => v.visitInvoke(this); | 655 accept(Visitor v) => v.visitInvoke(this); |
| 677 } | 656 } |
| 678 | 657 |
| 679 class InObserver extends ExpressionObserver<InExpression> | |
| 680 implements InExpression { | |
| 681 IdentifierObserver left; | |
| 682 ExpressionObserver right; | |
| 683 | |
| 684 InObserver(Expression expr, this.left, this.right) : super(expr); | |
| 685 | |
| 686 _updateSelf(Scope scope) { | |
| 687 Identifier identifier = left; | |
| 688 var iterable = right._value; | |
| 689 | |
| 690 if (iterable is! Iterable && iterable != null) { | |
| 691 throw new EvalException("right side of 'in' is not an iterator"); | |
| 692 } | |
| 693 | |
| 694 if (iterable is ObservableList) { | |
| 695 _subscription = iterable.listChanges.listen((_) => _invalidate(scope)); | |
| 696 } | |
| 697 | |
| 698 // TODO: make Comprehension observable and update it | |
| 699 _value = new Comprehension(identifier.value, iterable); | |
| 700 } | |
| 701 | |
| 702 accept(Visitor v) => v.visitInExpression(this); | |
| 703 } | |
| 704 | |
| 705 _toBool(v) => (v == null) ? false : v; | 658 _toBool(v) => (v == null) ? false : v; |
| 706 | 659 |
| 707 /** Call a [Function] or a [Method]. */ | 660 /** Call a [Function] or a [Method]. */ |
| 708 // TODO(jmesserly): remove this once dartbug.com/13002 is fixed. | 661 // TODO(jmesserly): remove this once dartbug.com/13002 is fixed. |
| 709 // Just inline `_convert(Function.apply(...))` to the call site. | 662 // Just inline `_convert(Function.apply(...))` to the call site. |
| 710 Object call(Object receiver, List args) { | 663 Object call(Object receiver, List args) { |
| 711 var result; | 664 var result; |
| 712 if (receiver is Method) { | 665 if (receiver is Method) { |
| 713 Method method = receiver; | 666 Method method = receiver; |
| 714 result = method.mirror.invoke(method.symbol, args, null).reflectee; | 667 result = method.mirror.invoke(method.symbol, args, null).reflectee; |
| 715 } else { | 668 } else { |
| 716 result = Function.apply(receiver, args, null); | 669 result = Function.apply(receiver, args, null); |
| 717 } | 670 } |
| 718 return _convert(result); | 671 return _convert(result); |
| 719 } | 672 } |
| 720 | 673 |
| 721 /** | |
| 722 * A comprehension declaration ("a in b"). [identifier] is the loop variable | |
| 723 * that's added to the scope during iteration. [iterable] is the set of | |
| 724 * objects to iterate over. | |
| 725 */ | |
| 726 class Comprehension { | |
| 727 final String identifier; | |
| 728 final Iterable iterable; | |
| 729 | |
| 730 Comprehension(this.identifier, Iterable iterable) | |
| 731 : iterable = (iterable != null) ? iterable : const []; | |
| 732 } | |
| 733 | |
| 734 /** A method on a model object in a [Scope]. */ | 674 /** A method on a model object in a [Scope]. */ |
| 735 class Method { | 675 class Method { |
| 736 final InstanceMirror mirror; | 676 final InstanceMirror mirror; |
| 737 final Symbol symbol; | 677 final Symbol symbol; |
| 738 | 678 |
| 739 Method(this.mirror, this.symbol); | 679 Method(this.mirror, this.symbol); |
| 740 | 680 |
| 741 /** | 681 /** |
| 742 * Support for calling single argument methods like [Filter]s. | 682 * Support for calling single argument methods like [Filter]s. |
| 743 * This does not work for calls that need to pass more than one argument. | 683 * This does not work for calls that need to pass more than one argument. |
| 744 */ | 684 */ |
| 745 call(arg0) => mirror.invoke(symbol, [arg0], null).reflectee; | 685 call(arg0) => mirror.invoke(symbol, [arg0], null).reflectee; |
| 746 } | 686 } |
| 747 | 687 |
| 748 class EvalException implements Exception { | 688 class EvalException implements Exception { |
| 749 final String message; | 689 final String message; |
| 750 EvalException(this.message); | 690 EvalException(this.message); |
| 751 String toString() => "EvalException: $message"; | 691 String toString() => "EvalException: $message"; |
| 752 } | 692 } |
| OLD | NEW |