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

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

Issue 141703024: Refactor of PolymerExpressions. Adds "as" expressions. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address review comments Created 6 years, 9 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( 10 @MirrorsUsed(
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 } 58 }
59 59
60 /** 60 /**
61 * Returns an [ExpressionObserver] that evaluates [expr] in the context of 61 * Returns an [ExpressionObserver] that evaluates [expr] in the context of
62 * scope] and listens for any changes on [Observable] values that are 62 * scope] and listens for any changes on [Observable] values that are
63 * returned from sub-expressions. When a value changes the expression is 63 * returned from sub-expressions. When a value changes the expression is
64 * reevaluated and the new result is sent to the [onUpdate] stream of the 64 * reevaluated and the new result is sent to the [onUpdate] stream of the
65 * [ExpressionObsserver]. 65 * [ExpressionObsserver].
66 */ 66 */
67 ExpressionObserver observe(Expression expr, Scope scope) { 67 ExpressionObserver observe(Expression expr, Scope scope) {
68 var observer = new ObserverBuilder(scope).visit(expr); 68 var observer = new ObserverBuilder(/*scope*/).visit(expr);
Jennifer Messerly 2014/03/17 23:10:08 did you mean to remove the scope argument to "obse
justinfagnani 2014/04/24 00:26:13 yep
69 return observer; 69 return observer;
70 } 70 }
71 71
72 /** 72 /**
73 * Causes [expr] to be reevaluated a returns it's value. 73 * Causes [expr] to be reevaluated a returns it's value.
74 */ 74 */
75 Object update(ExpressionObserver expr, Scope scope) { 75 Object update(ExpressionObserver expr, Scope scope) {
76 new Updater(scope).visit(expr); 76 new Updater(scope).visit(expr);
77 return expr.currentValue; 77 return expr.currentValue;
78 } 78 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 */ 157 */
158 class Scope { 158 class Scope {
159 final Scope parent; 159 final Scope parent;
160 final Object model; 160 final Object model;
161 // TODO(justinfagnani): disallow adding/removing names 161 // TODO(justinfagnani): disallow adding/removing names
162 final ObservableMap<String, Object> _variables; 162 final ObservableMap<String, Object> _variables;
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 get variables => _variables;
Jennifer Messerly 2014/03/17 23:10:08 another option is just to make _variables public.
justinfagnani 2014/04/24 00:26:13 Done.
168
167 Object operator[](String name) { 169 Object operator[](String name) {
168 if (name == 'this') { 170 if (name == 'this') {
169 return model; 171 return model;
170 } else if (_variables.containsKey(name)) { 172 } else if (_variables.containsKey(name)) {
171 return _convert(_variables[name]); 173 return _convert(_variables[name]);
172 } else { 174 } else {
173 var symbol = smoke.nameToSymbol(name); 175 var symbol = smoke.nameToSymbol(name);
174 if (model != null && smoke.hasGetter(model.runtimeType, symbol)) { 176 if (model != null && smoke.hasGetter(model.runtimeType, symbol)) {
175 return _convert(smoke.read(model, symbol)); 177 return _convert(smoke.read(model, symbol));
176 } 178 }
(...skipping 12 matching lines...) Expand all
189 // seem neccessary 191 // seem neccessary
190 return null; 192 return null;
191 } else if (_variables.containsKey(name)) { 193 } else if (_variables.containsKey(name)) {
192 return _variables; 194 return _variables;
193 } else if (smoke.hasGetter(model.runtimeType, smoke.nameToSymbol(name))) { 195 } else if (smoke.hasGetter(model.runtimeType, smoke.nameToSymbol(name))) {
194 return model; 196 return model;
195 } 197 }
196 if (parent != null) { 198 if (parent != null) {
197 return parent.ownerOf(name); 199 return parent.ownerOf(name);
198 } 200 }
201 return null;
199 } 202 }
200 203
201 bool contains(String name) { 204 String toString() => 'Scope(parent: $parent, model: $model, '
202 if (_variables.containsKey(name) || 205 'variables: $variables)';
203 smoke.hasGetter(model.runtimeType, smoke.nameToSymbol(name))) {
204 return true;
205 }
206 if (parent != null) {
207 return parent.contains(name);
208 }
209 return false;
210 }
211 } 206 }
212 207
213 Object _convert(v) { 208 Object _convert(v) {
214 if (v is Stream) return new StreamBinding(v); 209 if (v is Stream) return new StreamBinding(v);
215 return v; 210 return v;
216 } 211 }
217 212
218 abstract class ExpressionObserver<E extends Expression> implements Expression { 213 abstract class ExpressionObserver<E extends Expression> implements Expression {
219 final E _expr; 214 final E _expr;
220 ExpressionObserver _parent; 215 ExpressionObserver _parent;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 } 258 }
264 259
265 class Updater extends RecursiveVisitor { 260 class Updater extends RecursiveVisitor {
266 final Scope scope; 261 final Scope scope;
267 262
268 Updater(this.scope); 263 Updater(this.scope);
269 264
270 visitExpression(ExpressionObserver e) { 265 visitExpression(ExpressionObserver e) {
271 e._observe(scope); 266 e._observe(scope);
272 } 267 }
273
274 visitInExpression(InObserver c) {
275 visit(c.right);
276 visitExpression(c);
277 }
278 } 268 }
279 269
280 class ObserverBuilder extends Visitor { 270 class ObserverBuilder extends Visitor {
281 final Scope scope; 271 // final Scope scope;
282 final Queue parents = new Queue(); 272 final Queue parents = new Queue();
283 273
284 ObserverBuilder(this.scope); 274 ObserverBuilder(/*this.scope*/);
285 275
286 visitEmptyExpression(EmptyExpression e) => new EmptyObserver(e); 276 visitEmptyExpression(EmptyExpression e) => new EmptyObserver(e);
287 277
288 visitParenthesizedExpression(ParenthesizedExpression e) => visit(e.child); 278 visitParenthesizedExpression(ParenthesizedExpression e) => visit(e.child);
289 279
290 visitGetter(Getter g) { 280 visitGetter(Getter g) {
291 var receiver = visit(g.receiver); 281 var receiver = visit(g.receiver);
292 var getter = new GetterObserver(g, receiver); 282 var getter = new GetterObserver(g, receiver);
293 receiver._parent = getter; 283 receiver._parent = getter;
294 return getter; 284 return getter;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 var trueExpr = visit(o.trueExpr); 352 var trueExpr = visit(o.trueExpr);
363 var falseExpr = visit(o.falseExpr); 353 var falseExpr = visit(o.falseExpr);
364 var ternary = new TernaryObserver(o, condition, trueExpr, falseExpr); 354 var ternary = new TernaryObserver(o, condition, trueExpr, falseExpr);
365 condition._parent = ternary; 355 condition._parent = ternary;
366 trueExpr._parent = ternary; 356 trueExpr._parent = ternary;
367 falseExpr._parent = ternary; 357 falseExpr._parent = ternary;
368 return ternary; 358 return ternary;
369 } 359 }
370 360
371 visitInExpression(InExpression i) { 361 visitInExpression(InExpression i) {
372 // don't visit the left. It's an identifier, but we don't want to evaluate 362 throw new UnsupportedError("can't eval an 'in' expression");
373 // it, we just want to add it to the comprehension object
374 var left = visit(i.left);
375 var right = visit(i.right);
376 var inexpr = new InObserver(i, left, right);
377 right._parent = inexpr;
378 return inexpr;
379 } 363 }
364
365 visitAsExpression(AsExpression i) {
366 throw new UnsupportedError("can't eval an 'as' expression");
367 }
368
380 } 369 }
381 370
382 class EmptyObserver extends ExpressionObserver<EmptyExpression> 371 class EmptyObserver extends ExpressionObserver<EmptyExpression>
383 implements EmptyExpression { 372 implements EmptyExpression {
384 373
385 EmptyObserver(EmptyExpression value) : super(value); 374 EmptyObserver(EmptyExpression value) : super(value);
386 375
387 _updateSelf(Scope scope) { 376 _updateSelf(Scope scope) {
388 _value = scope.model; 377 _value = scope.model;
389 // TODO(justin): listen for scope.model changes? 378 // TODO(justin): listen for scope.model changes?
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 _invalidate(scope); 636 _invalidate(scope);
648 } 637 }
649 }); 638 });
650 } 639 }
651 } 640 }
652 } 641 }
653 642
654 accept(Visitor v) => v.visitInvoke(this); 643 accept(Visitor v) => v.visitInvoke(this);
655 } 644 }
656 645
657 class InObserver extends ExpressionObserver<InExpression>
658 implements InExpression {
659 IdentifierObserver left;
660 ExpressionObserver right;
661
662 InObserver(Expression expr, this.left, this.right) : super(expr);
663
664 _updateSelf(Scope scope) {
665 Identifier identifier = left;
666 var iterable = right._value;
667
668 if (iterable is! Iterable && iterable != null) {
669 throw new EvalException("right side of 'in' is not an iterator");
670 }
671
672 if (iterable is ObservableList) {
673 _subscription = iterable.listChanges.listen((_) => _invalidate(scope));
674 }
675
676 // TODO: make Comprehension observable and update it
677 _value = new Comprehension(identifier.value, iterable);
678 }
679
680 accept(Visitor v) => v.visitInExpression(this);
681 }
682
683 _toBool(v) => (v == null) ? false : v; 646 _toBool(v) => (v == null) ? false : v;
684 647
685 /**
686 * A comprehension declaration ("a in b"). [identifier] is the loop variable
687 * that's added to the scope during iteration. [iterable] is the set of
688 * objects to iterate over.
689 */
690 class Comprehension {
691 final String identifier;
692 final Iterable iterable;
693
694 Comprehension(this.identifier, Iterable iterable)
695 : iterable = (iterable != null) ? iterable : const [];
696 }
697
698 class EvalException implements Exception { 648 class EvalException implements Exception {
699 final String message; 649 final String message;
700 EvalException(this.message); 650 EvalException(this.message);
701 String toString() => "EvalException: $message"; 651 String toString() => "EvalException: $message";
702 } 652 }
OLDNEW
« no previous file with comments | « no previous file | pkg/polymer_expressions/lib/expression.dart » ('j') | pkg/polymer_expressions/lib/polymer_expressions.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698