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 |