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

Unified Diff: pkg/polymer_expressions/lib/eval.dart

Issue 335943003: merge to trunk all changes from 36817 until 37378 under the packages: polymer, (Closed) Base URL: http://dart.googlecode.com/svn/trunk/dart/
Patch Set: Created 6 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/polymer_expressions/CHANGELOG.md ('k') | pkg/polymer_expressions/lib/parser.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/polymer_expressions/lib/eval.dart
===================================================================
--- pkg/polymer_expressions/lib/eval.dart (revision 37373)
+++ pkg/polymer_expressions/lib/eval.dart (working copy)
@@ -16,20 +16,22 @@
import 'visitor.dart';
final _BINARY_OPERATORS = {
- '+': (a, b) => a + b,
- '-': (a, b) => a - b,
- '*': (a, b) => a * b,
- '/': (a, b) => a / b,
- '%': (a, b) => a % b,
- '==': (a, b) => a == b,
- '!=': (a, b) => a != b,
- '>': (a, b) => a > b,
- '>=': (a, b) => a >= b,
- '<': (a, b) => a < b,
- '<=': (a, b) => a <= b,
- '||': (a, b) => a || b,
- '&&': (a, b) => a && b,
- '|': (a, f) {
+ '+': (a, b) => a + b,
+ '-': (a, b) => a - b,
+ '*': (a, b) => a * b,
+ '/': (a, b) => a / b,
+ '%': (a, b) => a % b,
+ '==': (a, b) => a == b,
+ '!=': (a, b) => a != b,
+ '===': (a, b) => identical(a, b),
+ '!==': (a, b) => !identical(a, b),
+ '>': (a, b) => a > b,
+ '>=': (a, b) => a >= b,
+ '<': (a, b) => a < b,
+ '<=': (a, b) => a <= b,
+ '||': (a, b) => a || b,
+ '&&': (a, b) => a && b,
+ '|': (a, f) {
if (f is Transformer) return f.forward(a);
if (f is Filter) return f(a);
throw new EvalException("Filters must be a one-argument function.");
@@ -47,11 +49,7 @@
/**
* Evaluation [expr] in the context of [scope].
*/
-Object eval(Expression expr, Scope scope) {
- var observer = observe(expr, scope);
- new Updater(scope).visit(observer);
- return observer._value;
-}
+Object eval(Expression expr, Scope scope) => new EvalVisitor(scope).visit(expr);
/**
* Returns an [ExpressionObserver] that evaluates [expr] in the context of
@@ -152,9 +150,6 @@
* and then finally looks up the name as a property in the model.
*/
abstract class Scope implements Indexable<String, Object> {
- static int __seq = 1;
- final int _seq = __seq++;
-
Scope._();
/** Create a scope containing a [model] and all of [variables]. */
@@ -188,9 +183,6 @@
/** Create a new scope extending this scope with an additional variable. */
Scope childScope(String name, Object value) =>
new _LocalVariableScope(name, value, this);
-
- String toString() => 'Scope(seq: $_seq model: $model)';
-
}
/**
@@ -307,13 +299,16 @@
}
}
- _observe(Scope scope) {
- // unobserve last value
+ _unobserve() {
if (_subscription != null) {
_subscription.cancel();
_subscription = null;
}
+ }
+ _observe(Scope scope) {
+ _unobserve();
+
var _oldValue = _value;
// evaluate
@@ -337,6 +332,110 @@
}
}
+class Closer extends RecursiveVisitor {
+ static final _instance = new Closer._();
+ factory Closer() => _instance;
+ Closer._();
+
+ visitExpression(ExpressionObserver e) {
+ e._unobserve();
+ }
+}
+
+class EvalVisitor extends Visitor {
+ final Scope scope;
+
+ EvalVisitor(this.scope);
+
+ visitEmptyExpression(EmptyExpression e) => scope.model;
+
+ visitParenthesizedExpression(ParenthesizedExpression e) => visit(e.child);
+
+ visitGetter(Getter g) {
+ var receiver = visit(g.receiver);
+ if (receiver == null) return null;
+ var symbol = smoke.nameToSymbol(g.name);
+ return smoke.read(receiver, symbol);
+ }
+
+ visitIndex(Index i) {
+ var receiver = visit(i.receiver);
+ if (receiver == null) return null;
+ var key = visit(i.argument);
+ return receiver[key];
+ }
+
+ visitInvoke(Invoke i) {
+ var receiver = visit(i.receiver);
+ if (receiver == null) return null;
+ var args = (i.arguments == null)
+ ? null
+ : i.arguments.map(visit).toList(growable: false);
+
+ if (i.method == null) {
+ assert(receiver is Function);
+ return Function.apply(receiver, args);
+ }
+
+ var symbol = smoke.nameToSymbol(i.method);
+ return smoke.invoke(receiver, symbol, args);
+ }
+
+ visitLiteral(Literal l) => l.value;
+
+ visitListLiteral(ListLiteral l) => l.items.map(visit).toList();
+
+ visitMapLiteral(MapLiteral l) {
+ var map = {};
+ for (var entry in l.entries) {
+ var key = visit(entry.key);
+ var value = visit(entry.entryValue);
+ map[key] = value;
+ }
+ return map;
+ }
+
+ visitMapLiteralEntry(MapLiteralEntry e) =>
+ throw new UnsupportedError("should never be called");
+
+ visitIdentifier(Identifier i) => scope[i.value];
+
+ visitBinaryOperator(BinaryOperator o) {
+ var operator = o.operator;
+ var left = visit(o.left);
+ var right = visit(o.right);
+
+ var f = _BINARY_OPERATORS[operator];
+ if (operator == '&&' || operator == '||') {
+ // TODO: short-circuit
+ return f(_toBool(left), _toBool(right));
+ } else if (operator == '==' || operator == '!=') {
+ return f(left, right);
+ } else if (left == null || right == null) {
+ return null;
+ }
+ return f(left, right);
+ }
+
+ visitUnaryOperator(UnaryOperator o) {
+ var expr = visit(o.child);
+ var f = _UNARY_OPERATORS[o.operator];
+ if (o.operator == '!') {
+ return f(_toBool(expr));
+ }
+ return (expr == null) ? null : f(expr);
+ }
+
+ visitTernaryOperator(TernaryOperator o) =>
+ visit(o.condition) == true ? visit(o.trueExpr) : visit(o.falseExpr);
+
+ visitInExpression(InExpression i) =>
+ throw new UnsupportedError("can't eval an 'in' expression");
+
+ visitAsExpression(AsExpression i) =>
+ throw new UnsupportedError("can't eval an 'as' expression");
+}
+
class ObserverBuilder extends Visitor {
final Queue parents = new Queue();
@@ -470,7 +569,7 @@
ListLiteralObserver(ListLiteral value, this.items) : super(value);
_updateSelf(Scope scope) {
- _value = items.map((i) => i._value).toList(growable: false);
+ _value = items.map((i) => i._value).toList();
}
accept(Visitor v) => v.visitListLiteral(this);
« no previous file with comments | « pkg/polymer_expressions/CHANGELOG.md ('k') | pkg/polymer_expressions/lib/parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698