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

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 @MirrorsUsed(
11 override: 'polymer_expressions.eval') 11 metaTargets: const [Reflectable, ObservableProperty],
12 import 'dart:mirrors'; 12 override: 'smoke.mirrors')
13 import 'dart:mirrors' show MirrorsUsed;
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';
21 22
22 final _BINARY_OPERATORS = { 23 final _BINARY_OPERATORS = {
23 '+': (a, b) => a + b, 24 '+': (a, b) => a + b,
24 '-': (a, b) => a - b, 25 '-': (a, b) => a - b,
25 '*': (a, b) => a * b, 26 '*': (a, b) => a * b,
26 '/': (a, b) => a / b, 27 '/': (a, b) => a / b,
27 '==': (a, b) => a == b, 28 '==': (a, b) => a == b,
28 '!=': (a, b) => a != b, 29 '!=': (a, b) => a != b,
29 '>': (a, b) => a > b, 30 '>': (a, b) => a > b,
30 '>=': (a, b) => a >= b, 31 '>=': (a, b) => a >= b,
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 throw new EvalException("filter must implement Transformer: $filterExpr"); 136 throw new EvalException("filter must implement Transformer: $filterExpr");
136 } 137 }
137 value = filter.reverse(value); 138 value = filter.reverse(value);
138 } 139 }
139 // make the assignment 140 // make the assignment
140 var o = eval(expression, scope); 141 var o = eval(expression, scope);
141 if (o == null) throw new EvalException("Can't assign to null: $expression"); 142 if (o == null) throw new EvalException("Can't assign to null: $expression");
142 if (isIndex) { 143 if (isIndex) {
143 o[property] = value; 144 o[property] = value;
144 } else { 145 } else {
145 reflect(o).setField(new Symbol(property), value); 146 smoke.write(o, smoke.nameToSymbol(property), value);
146 } 147 }
147 } 148 }
148 149
149 /** 150 /**
150 * A mapping of names to objects. Scopes contain a set of named [variables] and 151 * 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). 152 * 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]. 153 * Names are currently looked up in [variables] first, then the [model].
153 * 154 *
154 * Scopes can be nested by giving them a [parent]. If a name in not found in a 155 * 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. 156 * Scope, it will look for it in it's parent.
156 */ 157 */
157 class Scope { 158 class Scope {
158 final Scope parent; 159 final Scope parent;
159 final Object model; 160 final Object model;
160 // TODO(justinfagnani): disallow adding/removing names 161 // TODO(justinfagnani): disallow adding/removing names
161 final ObservableMap<String, Object> _variables; 162 final ObservableMap<String, Object> _variables;
162 InstanceMirror __modelMirror;
163 163
164 Scope({this.model, Map<String, Object> variables, this.parent}) 164 Scope({this.model, Map<String, Object> variables, this.parent})
165 : _variables = new ObservableMap.from(variables == null ? {} : variables); 165 : _variables = new ObservableMap.from(variables == null ? {} : variables);
166 166
167 InstanceMirror get _modelMirror {
168 if (__modelMirror != null) return __modelMirror;
169 __modelMirror = reflect(model);
170 return __modelMirror;
171 }
172
173 Object operator[](String name) { 167 Object operator[](String name) {
174 if (name == 'this') { 168 if (name == 'this') {
175 return model; 169 return model;
176 } else if (_variables.containsKey(name)) { 170 } else if (_variables.containsKey(name)) {
177 return _convert(_variables[name]); 171 return _convert(_variables[name]);
178 } else if (model != null) { 172 } else {
179 var symbol = new Symbol(name); 173 var symbol = smoke.nameToSymbol(name);
180 var classMirror = _modelMirror.type; 174 if (model != null && smoke.hasGetter(model.runtimeType, symbol)) {
181 var memberMirror = getMemberMirror(classMirror, symbol); 175 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 } 176 }
190 } 177 }
191 if (parent != null) { 178 if (parent != null) {
192 return _convert(parent[name]); 179 return _convert(parent[name]);
193 } else { 180 } else {
194 throw new EvalException("variable '$name' not found"); 181 throw new EvalException("variable '$name' not found");
195 } 182 }
196 } 183 }
197 184
198 Object ownerOf(String name) { 185 Object ownerOf(String name) {
199 if (name == 'this') { 186 if (name == 'this') {
200 // we could return the Scope if it were Observable, but since assigning 187 // 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 188 // a model to a template destroys and recreates the instance, it doesn't
202 // seem neccessary 189 // seem neccessary
203 return null; 190 return null;
204 } else if (_variables.containsKey(name)) { 191 } else if (_variables.containsKey(name)) {
205 return _variables; 192 return _variables;
206 } else { 193 } else if (smoke.hasGetter(model.runtimeType, smoke.nameToSymbol(name))) {
207 var symbol = new Symbol(name); 194 return model;
208 var classMirror = _modelMirror.type;
209 if (getMemberMirror(classMirror, symbol) != null) {
210 return model;
211 }
212 } 195 }
213 if (parent != null) { 196 if (parent != null) {
214 return parent.ownerOf(name); 197 return parent.ownerOf(name);
215 } 198 }
216 } 199 }
217 200
218 bool contains(String name) { 201 bool contains(String name) {
219 if (_variables.containsKey(name)) { 202 if (_variables.containsKey(name) ||
203 smoke.hasGetter(model.runtimeType, smoke.nameToSymbol(name))) {
220 return true; 204 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 } 205 }
228 if (parent != null) { 206 if (parent != null) {
229 return parent.contains(name); 207 return parent.contains(name);
230 } 208 }
231 return false; 209 return false;
232 } 210 }
233 } 211 }
234 212
235 Object _convert(v) { 213 Object _convert(v) {
236 if (v is Stream) return new StreamBinding(v); 214 if (v is Stream) return new StreamBinding(v);
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 451
474 IdentifierObserver(Identifier value) : super(value); 452 IdentifierObserver(Identifier value) : super(value);
475 453
476 String get value => _expr.value; 454 String get value => _expr.value;
477 455
478 _updateSelf(Scope scope) { 456 _updateSelf(Scope scope) {
479 _value = scope[value]; 457 _value = scope[value];
480 458
481 var owner = scope.ownerOf(value); 459 var owner = scope.ownerOf(value);
482 if (owner is Observable) { 460 if (owner is Observable) {
483 var symbol = new Symbol(value); 461 var symbol = smoke.nameToSymbol(value);
484 _subscription = (owner as Observable).changes.listen((changes) { 462 _subscription = (owner as Observable).changes.listen((changes) {
485 if (changes.any( 463 if (changes.any(
486 (c) => c is PropertyChangeRecord && c.name == symbol)) { 464 (c) => c is PropertyChangeRecord && c.name == symbol)) {
487 _invalidate(scope); 465 _invalidate(scope);
488 } 466 }
489 }); 467 });
490 } 468 }
491 } 469 }
492 470
493 accept(Visitor v) => v.visitIdentifier(this); 471 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); 561 GetterObserver(Expression expr, this.receiver) : super(expr);
584 562
585 String get name => _expr.name; 563 String get name => _expr.name;
586 564
587 _updateSelf(Scope scope) { 565 _updateSelf(Scope scope) {
588 var receiverValue = receiver._value; 566 var receiverValue = receiver._value;
589 if (receiverValue == null) { 567 if (receiverValue == null) {
590 _value = null; 568 _value = null;
591 return; 569 return;
592 } 570 }
593 var mirror = reflect(receiverValue); 571 var symbol = smoke.nameToSymbol(_expr.name);
594 var symbol = new Symbol(_expr.name); 572 _value = smoke.read(receiverValue, symbol);
595 _value = mirror.getField(symbol).reflectee;
596 573
597 if (receiverValue is Observable) { 574 if (receiverValue is Observable) {
598 _subscription = (receiverValue as Observable).changes.listen((changes) { 575 _subscription = (receiverValue as Observable).changes.listen((changes) {
599 if (changes.any((c) => c is PropertyChangeRecord && c.name == symbol)) { 576 if (changes.any((c) => c is PropertyChangeRecord && c.name == symbol)) {
600 _invalidate(scope); 577 _invalidate(scope);
601 } 578 }
602 }); 579 });
603 } 580 }
604 } 581 }
605 582
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 if (receiverValue == null) { 627 if (receiverValue == null) {
651 _value = null; 628 _value = null;
652 return; 629 return;
653 } 630 }
654 if (_expr.method == null) { 631 if (_expr.method == null) {
655 // top-level function or model method 632 // top-level function or model method
656 // TODO(justin): listen to model changes to see if the method has 633 // 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 634 // changed? listen to the scope to see if the top-level method has
658 // changed? 635 // changed?
659 assert(receiverValue is Function); 636 assert(receiverValue is Function);
660 _value = call(receiverValue, args); 637 _value = _convert(Function.apply(receiverValue, args));
661 } else { 638 } else {
662 var mirror = reflect(receiverValue); 639 var symbol = smoke.nameToSymbol(_expr.method);
663 var symbol = new Symbol(_expr.method); 640 _value = smoke.invoke(receiverValue, symbol, args);
664 _value = mirror.invoke(symbol, args, null).reflectee;
665 641
666 if (receiverValue is Observable) { 642 if (receiverValue is Observable) {
667 _subscription = (receiverValue as Observable).changes.listen( 643 _subscription = (receiverValue as Observable).changes.listen(
668 (List<ChangeRecord> changes) { 644 (List<ChangeRecord> changes) {
669 if (changes.any( 645 if (changes.any(
670 (c) => c is PropertyChangeRecord && c.name == symbol)) { 646 (c) => c is PropertyChangeRecord && c.name == symbol)) {
671 _invalidate(scope); 647 _invalidate(scope);
672 } 648 }
673 }); 649 });
674 } 650 }
(...skipping 24 matching lines...) Expand all
699 675
700 // TODO: make Comprehension observable and update it 676 // TODO: make Comprehension observable and update it
701 _value = new Comprehension(identifier.value, iterable); 677 _value = new Comprehension(identifier.value, iterable);
702 } 678 }
703 679
704 accept(Visitor v) => v.visitInExpression(this); 680 accept(Visitor v) => v.visitInExpression(this);
705 } 681 }
706 682
707 _toBool(v) => (v == null) ? false : v; 683 _toBool(v) => (v == null) ? false : v;
708 684
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 /** 685 /**
724 * A comprehension declaration ("a in b"). [identifier] is the loop variable 686 * 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 687 * that's added to the scope during iteration. [iterable] is the set of
726 * objects to iterate over. 688 * objects to iterate over.
727 */ 689 */
728 class Comprehension { 690 class Comprehension {
729 final String identifier; 691 final String identifier;
730 final Iterable iterable; 692 final Iterable iterable;
731 693
732 Comprehension(this.identifier, Iterable iterable) 694 Comprehension(this.identifier, Iterable iterable)
733 : iterable = (iterable != null) ? iterable : const []; 695 : iterable = (iterable != null) ? iterable : const [];
734 } 696 }
735 697
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 { 698 class EvalException implements Exception {
751 final String message; 699 final String message;
752 EvalException(this.message); 700 EvalException(this.message);
753 String toString() => "EvalException: $message"; 701 String toString() => "EvalException: $message";
754 } 702 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698