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

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

Issue 173003006: Use smoke in polymer and polymer_expressions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 10 months 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 @unused.MirrorsUsed(
11 override: 'polymer_expressions.eval') 11 metaTargets: const [Reflectable, ObservableProperty],
12 import 'dart:mirrors'; 12 override: 'smoke.mirrors')
13 import 'dart:mirrors' as unused;
blois 2014/02/20 17:29:25 just show MirrorsUsed?
Jennifer Messerly 2014/02/20 21:15:41 yeah, unused is sort of odd since it is actually u
Siggi Cherem (dart-lang) 2014/02/21 03:55:13 good idea. Done.
13 14
14 import 'package:observe/observe.dart'; 15 import 'package:observe/observe.dart';
16 import 'package:smoke/smoke.dart' as smoke;
15 17
16 import 'async.dart'; 18 import 'async.dart';
17 import 'expression.dart'; 19 import 'expression.dart';
18 import 'filter.dart'; 20 import 'filter.dart';
19 import 'visitor.dart'; 21 import 'visitor.dart';
20 import 'src/mirrors.dart'; 22
23 _unused() => unused.MirrorSystem; // to prevent analyzer warnings
blois 2014/02/20 17:29:25 Should this be removed as well?
Siggi Cherem (dart-lang) 2014/02/21 03:55:13 yeah, I fixed it elsewhere, but forgot to do so he
21 24
22 final _BINARY_OPERATORS = { 25 final _BINARY_OPERATORS = {
23 '+': (a, b) => a + b, 26 '+': (a, b) => a + b,
24 '-': (a, b) => a - b, 27 '-': (a, b) => a - b,
25 '*': (a, b) => a * b, 28 '*': (a, b) => a * b,
26 '/': (a, b) => a / b, 29 '/': (a, b) => a / b,
27 '==': (a, b) => a == b, 30 '==': (a, b) => a == b,
28 '!=': (a, b) => a != b, 31 '!=': (a, b) => a != b,
29 '>': (a, b) => a > b, 32 '>': (a, b) => a > b,
30 '>=': (a, b) => a >= b, 33 '>=': (a, b) => a >= b,
31 '<': (a, b) => a < b, 34 '<': (a, b) => a < b,
32 '<=': (a, b) => a <= b, 35 '<=': (a, b) => a <= b,
33 '||': (a, b) => a || b, 36 '||': (a, b) => a || b,
34 '&&': (a, b) => a && b, 37 '&&': (a, b) => a && b,
35 '|': (a, f) { 38 '|': (a, f) {
36 if (f is Transformer) return f.forward(a); 39 if (f is Transformer) return f.forward(a);
37 if (f is Filter) return f(a); 40 if (f is Filter) return f(a);
38 throw new EvalException("Filters must be a one-argument function."); 41 // TODO(sigmund): uncomment the throw statement. Because of
42 // dartbug.com/13002 smoke gives us an f that is not comparable to Filter.
43 // throw new EvalException("Filters must be a one-argument function.");
44 return f(a);
Siggi Cherem (dart-lang) 2014/02/21 03:55:13 BTW - I removed this workaround and instead hid th
39 } 45 }
40 }; 46 };
41 47
42 final _UNARY_OPERATORS = { 48 final _UNARY_OPERATORS = {
43 '+': (a) => a, 49 '+': (a) => a,
44 '-': (a) => -a, 50 '-': (a) => -a,
45 '!': (a) => !a, 51 '!': (a) => !a,
46 }; 52 };
47 53
48 final _BOOLEAN_OPERATORS = ['!', '||', '&&']; 54 final _BOOLEAN_OPERATORS = ['!', '||', '&&'];
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 throw new EvalException("filter must implement Transformer: $filterExpr"); 141 throw new EvalException("filter must implement Transformer: $filterExpr");
136 } 142 }
137 value = filter.reverse(value); 143 value = filter.reverse(value);
138 } 144 }
139 // make the assignment 145 // make the assignment
140 var o = eval(expression, scope); 146 var o = eval(expression, scope);
141 if (o == null) throw new EvalException("Can't assign to null: $expression"); 147 if (o == null) throw new EvalException("Can't assign to null: $expression");
142 if (isIndex) { 148 if (isIndex) {
143 o[property] = value; 149 o[property] = value;
144 } else { 150 } else {
145 reflect(o).setField(new Symbol(property), value); 151 smoke.write(o, smoke.nameToSymbol(property), value);
146 } 152 }
147 } 153 }
148 154
149 /** 155 /**
150 * A mapping of names to objects. Scopes contain a set of named [variables] and 156 * A mapping of names to objects. Scopes contain a set of named [variables] and
151 * a single [model] object (which can be thought of as the "this" reference). 157 * a single [model] object (which can be thought of as the "this" reference).
152 * Names are currently looked up in [variables] first, then the [model]. 158 * Names are currently looked up in [variables] first, then the [model].
153 * 159 *
154 * Scopes can be nested by giving them a [parent]. If a name in not found in a 160 * Scopes can be nested by giving them a [parent]. If a name in not found in a
155 * Scope, it will look for it in it's parent. 161 * Scope, it will look for it in it's parent.
156 */ 162 */
157 class Scope { 163 class Scope {
158 final Scope parent; 164 final Scope parent;
159 final Object model; 165 final Object model;
160 // TODO(justinfagnani): disallow adding/removing names 166 // TODO(justinfagnani): disallow adding/removing names
161 final ObservableMap<String, Object> _variables; 167 final ObservableMap<String, Object> _variables;
162 InstanceMirror __modelMirror;
163 168
164 Scope({this.model, Map<String, Object> variables, this.parent}) 169 Scope({this.model, Map<String, Object> variables, this.parent})
165 : _variables = new ObservableMap.from(variables == null ? {} : variables); 170 : _variables = new ObservableMap.from(variables == null ? {} : variables);
166 171
167 InstanceMirror get _modelMirror {
168 if (__modelMirror != null) return __modelMirror;
169 __modelMirror = reflect(model);
170 return __modelMirror;
171 }
172
173 Object operator[](String name) { 172 Object operator[](String name) {
174 if (name == 'this') { 173 if (name == 'this') {
175 return model; 174 return model;
176 } else if (_variables.containsKey(name)) { 175 } else if (_variables.containsKey(name)) {
177 return _convert(_variables[name]); 176 return _convert(_variables[name]);
178 } else if (model != null) { 177 } else {
179 var symbol = new Symbol(name); 178 var symbol = smoke.nameToSymbol(name);
180 var classMirror = _modelMirror.type; 179 if (model != null && smoke.hasGetter(model.runtimeType, symbol)) {
181 var memberMirror = getMemberMirror(classMirror, symbol); 180 return _convert(smoke.read(model, symbol));
182 // TODO(jmesserly): simplify once dartbug.com/13002 is fixed.
183 // This can just be "if memberMirror != null" and delete the Method class.
184 if (memberMirror is VariableMirror ||
185 (memberMirror is MethodMirror && memberMirror.isGetter)) {
186 return _convert(_modelMirror.getField(symbol).reflectee);
187 } else if (memberMirror is MethodMirror) {
188 return new Method(_modelMirror, symbol);
189 } 181 }
190 } 182 }
191 if (parent != null) { 183 if (parent != null) {
192 return _convert(parent[name]); 184 return _convert(parent[name]);
193 } else { 185 } else {
194 throw new EvalException("variable '$name' not found"); 186 throw new EvalException("variable '$name' not found");
195 } 187 }
196 } 188 }
197 189
198 Object ownerOf(String name) { 190 Object ownerOf(String name) {
199 if (name == 'this') { 191 if (name == 'this') {
200 // we could return the Scope if it were Observable, but since assigning 192 // we could return the Scope if it were Observable, but since assigning
201 // a model to a template destroys and recreates the instance, it doesn't 193 // a model to a template destroys and recreates the instance, it doesn't
202 // seem neccessary 194 // seem neccessary
203 return null; 195 return null;
204 } else if (_variables.containsKey(name)) { 196 } else if (_variables.containsKey(name)) {
205 return _variables; 197 return _variables;
206 } else { 198 } else if (smoke.hasGetter(model.runtimeType, smoke.nameToSymbol(name))) {
207 var symbol = new Symbol(name); 199 return model;
208 var classMirror = _modelMirror.type;
209 if (getMemberMirror(classMirror, symbol) != null) {
210 return model;
211 }
212 } 200 }
213 if (parent != null) { 201 if (parent != null) {
214 return parent.ownerOf(name); 202 return parent.ownerOf(name);
215 } 203 }
216 } 204 }
217 205
218 bool contains(String name) { 206 bool contains(String name) {
219 if (_variables.containsKey(name)) { 207 if (_variables.containsKey(name) ||
208 smoke.hasGetter(model.runtimeType, smoke.nameToSymbol(name))) {
220 return true; 209 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 } 210 }
228 if (parent != null) { 211 if (parent != null) {
229 return parent.contains(name); 212 return parent.contains(name);
230 } 213 }
231 return false; 214 return false;
232 } 215 }
233 } 216 }
234 217
235 Object _convert(v) { 218 Object _convert(v) {
236 if (v is Stream) return new StreamBinding(v); 219 if (v is Stream) return new StreamBinding(v);
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 456
474 IdentifierObserver(Identifier value) : super(value); 457 IdentifierObserver(Identifier value) : super(value);
475 458
476 String get value => _expr.value; 459 String get value => _expr.value;
477 460
478 _updateSelf(Scope scope) { 461 _updateSelf(Scope scope) {
479 _value = scope[value]; 462 _value = scope[value];
480 463
481 var owner = scope.ownerOf(value); 464 var owner = scope.ownerOf(value);
482 if (owner is Observable) { 465 if (owner is Observable) {
483 var symbol = new Symbol(value); 466 var symbol = smoke.nameToSymbol(value);
484 _subscription = (owner as Observable).changes.listen((changes) { 467 _subscription = (owner as Observable).changes.listen((changes) {
485 if (changes.any( 468 if (changes.any(
486 (c) => c is PropertyChangeRecord && c.name == symbol)) { 469 (c) => c is PropertyChangeRecord && c.name == symbol)) {
487 _invalidate(scope); 470 _invalidate(scope);
488 } 471 }
489 }); 472 });
490 } 473 }
491 } 474 }
492 475
493 accept(Visitor v) => v.visitIdentifier(this); 476 accept(Visitor v) => v.visitIdentifier(this);
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 GetterObserver(Expression expr, this.receiver) : super(expr); 566 GetterObserver(Expression expr, this.receiver) : super(expr);
584 567
585 String get name => _expr.name; 568 String get name => _expr.name;
586 569
587 _updateSelf(Scope scope) { 570 _updateSelf(Scope scope) {
588 var receiverValue = receiver._value; 571 var receiverValue = receiver._value;
589 if (receiverValue == null) { 572 if (receiverValue == null) {
590 _value = null; 573 _value = null;
591 return; 574 return;
592 } 575 }
593 var mirror = reflect(receiverValue); 576 var symbol = smoke.nameToSymbol(_expr.name);
594 var symbol = new Symbol(_expr.name); 577 _value = smoke.read(receiverValue, symbol);
595 _value = mirror.getField(symbol).reflectee;
596 578
597 if (receiverValue is Observable) { 579 if (receiverValue is Observable) {
598 _subscription = (receiverValue as Observable).changes.listen((changes) { 580 _subscription = (receiverValue as Observable).changes.listen((changes) {
599 if (changes.any((c) => c is PropertyChangeRecord && c.name == symbol)) { 581 if (changes.any((c) => c is PropertyChangeRecord && c.name == symbol)) {
600 _invalidate(scope); 582 _invalidate(scope);
601 } 583 }
602 }); 584 });
603 } 585 }
604 } 586 }
605 587
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 if (receiverValue == null) { 632 if (receiverValue == null) {
651 _value = null; 633 _value = null;
652 return; 634 return;
653 } 635 }
654 if (_expr.method == null) { 636 if (_expr.method == null) {
655 // top-level function or model method 637 // top-level function or model method
656 // TODO(justin): listen to model changes to see if the method has 638 // TODO(justin): listen to model changes to see if the method has
657 // changed? listen to the scope to see if the top-level method has 639 // changed? listen to the scope to see if the top-level method has
658 // changed? 640 // changed?
659 assert(receiverValue is Function); 641 assert(receiverValue is Function);
660 _value = call(receiverValue, args); 642 _value = _convert(Function.apply(receiverValue, args));
661 } else { 643 } else {
662 var mirror = reflect(receiverValue); 644 var symbol = smoke.nameToSymbol(_expr.method);
663 var symbol = new Symbol(_expr.method); 645 _value = smoke.invoke(receiverValue, symbol, args);
664 _value = mirror.invoke(symbol, args, null).reflectee;
665 646
666 if (receiverValue is Observable) { 647 if (receiverValue is Observable) {
667 _subscription = (receiverValue as Observable).changes.listen( 648 _subscription = (receiverValue as Observable).changes.listen(
668 (List<ChangeRecord> changes) { 649 (List<ChangeRecord> changes) {
669 if (changes.any( 650 if (changes.any(
670 (c) => c is PropertyChangeRecord && c.name == symbol)) { 651 (c) => c is PropertyChangeRecord && c.name == symbol)) {
671 _invalidate(scope); 652 _invalidate(scope);
672 } 653 }
673 }); 654 });
674 } 655 }
(...skipping 24 matching lines...) Expand all
699 680
700 // TODO: make Comprehension observable and update it 681 // TODO: make Comprehension observable and update it
701 _value = new Comprehension(identifier.value, iterable); 682 _value = new Comprehension(identifier.value, iterable);
702 } 683 }
703 684
704 accept(Visitor v) => v.visitInExpression(this); 685 accept(Visitor v) => v.visitInExpression(this);
705 } 686 }
706 687
707 _toBool(v) => (v == null) ? false : v; 688 _toBool(v) => (v == null) ? false : v;
708 689
709 /** Call a [Function] or a [Method]. */
710 // TODO(jmesserly): remove this once dartbug.com/13002 is fixed.
711 // Just inline `_convert(Function.apply(...))` to the call site.
712 Object call(Object receiver, List args) {
713 var result;
714 if (receiver is Method) {
715 Method method = receiver;
716 result = method.mirror.invoke(method.symbol, args, null).reflectee;
717 } else {
718 result = Function.apply(receiver, args, null);
719 }
720 return _convert(result);
721 }
722
723 /** 690 /**
724 * A comprehension declaration ("a in b"). [identifier] is the loop variable 691 * A comprehension declaration ("a in b"). [identifier] is the loop variable
725 * that's added to the scope during iteration. [iterable] is the set of 692 * that's added to the scope during iteration. [iterable] is the set of
726 * objects to iterate over. 693 * objects to iterate over.
727 */ 694 */
728 class Comprehension { 695 class Comprehension {
729 final String identifier; 696 final String identifier;
730 final Iterable iterable; 697 final Iterable iterable;
731 698
732 Comprehension(this.identifier, Iterable iterable) 699 Comprehension(this.identifier, Iterable iterable)
733 : iterable = (iterable != null) ? iterable : const []; 700 : iterable = (iterable != null) ? iterable : const [];
734 } 701 }
735 702
736 /** A method on a model object in a [Scope]. */
737 class Method {
738 final InstanceMirror mirror;
739 final Symbol symbol;
740
741 Method(this.mirror, this.symbol);
742
743 /**
744 * Support for calling single argument methods like [Filter]s.
745 * This does not work for calls that need to pass more than one argument.
746 */
747 call(arg0) => mirror.invoke(symbol, [arg0], null).reflectee;
748 }
749
750 class EvalException implements Exception { 703 class EvalException implements Exception {
751 final String message; 704 final String message;
752 EvalException(this.message); 705 EvalException(this.message);
753 String toString() => "EvalException: $message"; 706 String toString() => "EvalException: $message";
754 } 707 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698