Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(548)

Side by Side Diff: pkg/polymer_expressions/lib/eval.dart

Issue 74543003: Split out Index AST node from Invoke (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Split out Getter too Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 new Updater(scope).visit(expr); 75 new Updater(scope).visit(expr);
76 return expr.currentValue; 76 return expr.currentValue;
77 } 77 }
78 78
79 /** 79 /**
80 * Assign [value] to the variable or field referenced by [expr] in the context 80 * Assign [value] to the variable or field referenced by [expr] in the context
81 * of [scope]. 81 * of [scope].
82 * 82 *
83 * [expr] must be an /assignable/ expression, it must not contain 83 * [expr] must be an /assignable/ expression, it must not contain
84 * operators or function invocations, and any index operations must use a 84 * operators or function invocations, and any index operations must use a
85 * literal index. 85 * literal index.
Jennifer Messerly 2013/11/18 20:28:41 out of curiosity, why have the restriction that th
justinfagnani 2013/11/20 03:50:33 No, I was just being conservative at the time and
Jennifer Messerly 2013/11/20 04:04:56 makes sense. yeah, I think we'd eventually want al
86 */ 86 */
87 void assign(Expression expr, Object value, Scope scope) { 87 void assign(Expression expr, Object value, Scope scope) {
88 88
89 notAssignable() => 89 notAssignable() =>
90 throw new EvalException("Expression is not assignable: $expr"); 90 throw new EvalException("Expression is not assignable: $expr");
91 91
92 Expression expression; 92 Expression expression;
93 var property; 93 var property;
94 bool isIndex = false; 94 bool isIndex = false;
95 var filters = <Expression>[]; // reversed order for assignment 95 var filters = <Expression>[]; // reversed order for assignment
96 96
97 while (expr is BinaryOperator) { 97 while (expr is BinaryOperator) {
98 BinaryOperator op = expr; 98 BinaryOperator op = expr;
99 if (op.operator != '|') { 99 if (op.operator != '|') {
100 break; 100 break;
101 } 101 }
102 filters.add(op.right); 102 filters.add(op.right);
103 expr = op.left; 103 expr = op.left;
104 } 104 }
105 105
106 if (expr is Identifier) { 106 if (expr is Identifier) {
107 expression = empty(); 107 expression = empty();
108 Identifier ident = expr; 108 Identifier ident = expr;
109 property = ident.value; 109 property = ident.value;
110 } else if (expr is Index) {
111 if (expr.argument is! Literal) notAssignable();
112 expression = expr.receiver;
113 Literal l = expr.argument;
114 property = l.value;
115 isIndex = true;
116 } else if (expr is Getter) {
117 expression = expr.receiver;
118 property = expr.name;
110 } else if (expr is Invoke) { 119 } else if (expr is Invoke) {
111 Invoke invoke = expr; 120 expression = expr.receiver;
112 expression = invoke.receiver; 121 if (expr.method != null) {
113 if (invoke.method == '[]') { 122 if (expr.arguments != null) notAssignable();
114 if (invoke.arguments[0] is! Literal) notAssignable(); 123 property = expr.method;
115 Literal l = invoke.arguments[0];
116 property = l.value;
117 isIndex = true;
118 } else if (invoke.method != null) {
119 if (invoke.arguments != null) notAssignable();
120 property = invoke.method;
121 } else { 124 } else {
122 notAssignable(); 125 notAssignable();
123 } 126 }
124 } else { 127 } else {
125 notAssignable(); 128 notAssignable();
126 } 129 }
127 130
128 // transform the values backwards through the filters 131 // transform the values backwards through the filters
129 for (var filterExpr in filters) { 132 for (var filterExpr in filters) {
130 var filter = eval(filterExpr, scope); 133 var filter = eval(filterExpr, scope);
(...skipping 20 matching lines...) Expand all
151 * Scopes can be nested by giving them a [parent]. If a name in not found in a 154 * Scopes can be nested by giving them a [parent]. If a name in not found in a
152 * Scope, it will look for it in it's parent. 155 * Scope, it will look for it in it's parent.
153 */ 156 */
154 class Scope { 157 class Scope {
155 final Scope parent; 158 final Scope parent;
156 final Object model; 159 final Object model;
157 // TODO(justinfagnani): disallow adding/removing names 160 // TODO(justinfagnani): disallow adding/removing names
158 final ObservableMap<String, Object> _variables; 161 final ObservableMap<String, Object> _variables;
159 InstanceMirror __modelMirror; 162 InstanceMirror __modelMirror;
160 163
161 Scope({this.model, Map<String, Object> variables: const {}, this.parent}) 164 Scope({this.model, Map<String, Object> variables, this.parent})
162 : _variables = new ObservableMap.from(variables); 165 : _variables = new ObservableMap.from(variables == null ? {} : variables);
163 166
164 InstanceMirror get _modelMirror { 167 InstanceMirror get _modelMirror {
165 if (__modelMirror != null) return __modelMirror; 168 if (__modelMirror != null) return __modelMirror;
166 __modelMirror = reflect(model); 169 __modelMirror = reflect(model);
167 return __modelMirror; 170 return __modelMirror;
168 } 171 }
169 172
170 Object operator[](String name) { 173 Object operator[](String name) {
171 if (name == 'this') { 174 if (name == 'this') {
172 return model; 175 return model;
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 class ObserverBuilder extends Visitor { 300 class ObserverBuilder extends Visitor {
298 final Scope scope; 301 final Scope scope;
299 final Queue parents = new Queue(); 302 final Queue parents = new Queue();
300 303
301 ObserverBuilder(this.scope); 304 ObserverBuilder(this.scope);
302 305
303 visitEmptyExpression(EmptyExpression e) => new EmptyObserver(e); 306 visitEmptyExpression(EmptyExpression e) => new EmptyObserver(e);
304 307
305 visitParenthesizedExpression(ParenthesizedExpression e) => visit(e.child); 308 visitParenthesizedExpression(ParenthesizedExpression e) => visit(e.child);
306 309
310 visitGetter(Getter g) {
311 var receiver = visit(g.receiver);
312 var getter = new GetterObserver(g, receiver);
313 receiver._parent = getter;
314 return getter;
315 }
316
317 visitIndex(Index i) {
318 var receiver = visit(i.receiver);
319 var arg = visit(i.argument);
320 var index = new IndexObserver(i, receiver, arg);
321 receiver._parent = index;
322 arg._parent = index;
323 return index;
324 }
325
307 visitInvoke(Invoke i) { 326 visitInvoke(Invoke i) {
308 var receiver = visit(i.receiver); 327 var receiver = visit(i.receiver);
309 var args = (i.arguments == null) 328 var args = (i.arguments == null)
310 ? null 329 ? null
311 : i.arguments.map(visit).toList(growable: false); 330 : i.arguments.map(visit).toList(growable: false);
312 var invoke = new InvokeObserver(i, receiver, args); 331 var invoke = new InvokeObserver(i, receiver, args);
313 receiver._parent = invoke; 332 receiver._parent = invoke;
314 if (args != null) args.forEach((a) => a._parent = invoke); 333 if (args != null) args.forEach((a) => a._parent = invoke);
315 return invoke; 334 return invoke;
316 } 335 }
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 .listen((_) => _invalidate(scope)); 518 .listen((_) => _invalidate(scope));
500 } 519 }
501 _value = f(left._value, right._value); 520 _value = f(left._value, right._value);
502 } 521 }
503 } 522 }
504 523
505 accept(Visitor v) => v.visitBinaryOperator(this); 524 accept(Visitor v) => v.visitBinaryOperator(this);
506 525
507 } 526 }
508 527
528 class GetterObserver extends ExpressionObserver<Getter> implements Getter {
529 final ExpressionObserver receiver;
530
531 GetterObserver(Expression expr, this.receiver) : super(expr);
532
533 String get name => _expr.name;
534
535 _updateSelf(Scope scope) {
536 var receiverValue = receiver._value;
537 if (receiverValue == null) {
538 _value = null;
539 return;
540 }
541 var mirror = reflect(receiverValue);
542 var symbol = new Symbol(_expr.name);
543 _value = mirror.getField(symbol).reflectee;
544
545 if (receiverValue is Observable) {
546 _subscription = (receiverValue as Observable).changes.listen((changes) {
547 if (changes.any((c) => c is PropertyChangeRecord && c.name == symbol)) {
548 _invalidate(scope);
549 }
550 });
551 }
552 }
553
554 accept(Visitor v) => v.visitGetter(this);
555 }
556
557 class IndexObserver extends ExpressionObserver<Index> implements Index {
558 final ExpressionObserver receiver;
559 final ExpressionObserver argument;
560
561 IndexObserver(Expression expr, this.receiver, this.argument) : super(expr);
562
563 _updateSelf(Scope scope) {
564 var receiverValue = receiver._value;
565 if (receiverValue == null) {
566 _value = null;
567 return;
568 }
569 var key = argument._value;
570 _value = receiverValue[key];
571
572 if (receiverValue is Observable) {
573 _subscription = (receiverValue as Observable).changes.listen((changes) {
574 if (changes.any((c) => c is MapChangeRecord && c.key == key)) {
575 _invalidate(scope);
576 }
577 });
578 }
579 }
580
581 accept(Visitor v) => v.visitIndex(this);
582 }
583
509 class InvokeObserver extends ExpressionObserver<Invoke> implements Invoke { 584 class InvokeObserver extends ExpressionObserver<Invoke> implements Invoke {
510 final ExpressionObserver receiver; 585 final ExpressionObserver receiver;
511 List<ExpressionObserver> arguments; 586 final List<ExpressionObserver> arguments;
512 587
513 InvokeObserver(Expression expr, this.receiver, [this.arguments]) 588 InvokeObserver(Expression expr, this.receiver, this.arguments)
514 : super(expr); 589 : super(expr) {
515 590 assert(arguments != null);
516 bool get isGetter => _expr.isGetter; 591 }
517 592
518 String get method => _expr.method; 593 String get method => _expr.method;
519 594
520 _updateSelf(Scope scope) { 595 _updateSelf(Scope scope) {
521 var args = (arguments == null) 596 var args = arguments.map((a) => a._value).toList();
522 ? []
523 : arguments.map((a) => a._value)
524 .toList(growable: false);
525 var receiverValue = receiver._value; 597 var receiverValue = receiver._value;
526 if (receiverValue == null) { 598 if (receiverValue == null) {
527 _value = null; 599 _value = null;
528 } else if (_expr.method == null) { 600 return;
529 if (_expr.isGetter) { 601 }
530 // getter, but not a top-level identifier 602 if (_expr.method == null) {
531 // TODO(justin): listen to the receiver's owner 603 // top-level function or model method
532 _value = receiverValue; 604 // TODO(justin): listen to model changes to see if the method has
533 } else { 605 // changed? listen to the scope to see if the top-level method has
534 // top-level function or model method 606 // changed?
535 // TODO(justin): listen to model changes to see if the method has 607 assert(receiverValue is Function);
536 // changed? listen to the scope to see if the top-level method has 608 _value = call(receiverValue, args);
537 // changed?
538 assert(receiverValue is Function);
539 _value = call(receiverValue, args);
540 }
541 } else { 609 } else {
542 // special case [] because we don't need mirrors 610 var mirror = reflect(receiverValue);
543 if (_expr.method == '[]') { 611 var symbol = new Symbol(_expr.method);
544 assert(args.length == 1); 612 _value = mirror.invoke(symbol, args, null).reflectee;
545 var key = args[0];
546 _value = receiverValue[key];
547 613
548 if (receiverValue is Observable) { 614 if (receiverValue is Observable) {
549 _subscription = (receiverValue as Observable).changes.listen( 615 _subscription = (receiverValue as Observable).changes.listen(
550 (List<ChangeRecord> changes) { 616 (List<ChangeRecord> changes) {
551 if (changes.any((c) => 617 if (changes.any(
552 c is MapChangeRecord && c.key == key)) { 618 (c) => c is PropertyChangeRecord && c.name == symbol)) {
553 _invalidate(scope); 619 _invalidate(scope);
554 } 620 }
555 }); 621 });
556 }
557 } else {
558 var mirror = reflect(receiverValue);
559 var symbol = new Symbol(_expr.method);
560 _value = (_expr.isGetter)
561 ? mirror.getField(symbol).reflectee
562 : mirror.invoke(symbol, args, null).reflectee;
563
564 if (receiverValue is Observable) {
565 _subscription = (receiverValue as Observable).changes.listen(
566 (List<ChangeRecord> changes) {
567 if (changes.any(
568 (c) => c is PropertyChangeRecord && c.name == symbol)) {
569 _invalidate(scope);
570 }
571 });
572 }
573 } 622 }
574 } 623 }
575 } 624 }
576 625
577 accept(Visitor v) => v.visitInvoke(this); 626 accept(Visitor v) => v.visitInvoke(this);
578 } 627 }
579 628
580 class InObserver extends ExpressionObserver<InExpression> 629 class InObserver extends ExpressionObserver<InExpression>
581 implements InExpression { 630 implements InExpression {
582 IdentifierObserver left; 631 IdentifierObserver left;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 * This does not work for calls that need to pass more than one argument. 693 * This does not work for calls that need to pass more than one argument.
645 */ 694 */
646 call(arg0) => mirror.invoke(symbol, [arg0], null).reflectee; 695 call(arg0) => mirror.invoke(symbol, [arg0], null).reflectee;
647 } 696 }
648 697
649 class EvalException implements Exception { 698 class EvalException implements Exception {
650 final String message; 699 final String message;
651 EvalException(this.message); 700 EvalException(this.message);
652 String toString() => "EvalException: $message"; 701 String toString() => "EvalException: $message";
653 } 702 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698