| OLD | NEW |
| 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 import 'dart:mirrors'; | 9 import 'dart:mirrors'; |
| 10 | 10 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 } | 141 } |
| 142 | 142 |
| 143 /** | 143 /** |
| 144 * A mapping of names to objects. Scopes contain a set of named [variables] and | 144 * A mapping of names to objects. Scopes contain a set of named [variables] and |
| 145 * a single [model] object (which can be thought of as the "this" reference). | 145 * a single [model] object (which can be thought of as the "this" reference). |
| 146 * Names are currently looked up in [variables] first, then the [model]. | 146 * Names are currently looked up in [variables] first, then the [model]. |
| 147 * | 147 * |
| 148 * Scopes can be nested by giving them a [parent]. If a name in not found in a | 148 * Scopes can be nested by giving them a [parent]. If a name in not found in a |
| 149 * Scope, it will look for it in it's parent. | 149 * Scope, it will look for it in it's parent. |
| 150 */ | 150 */ |
| 151 class Scope extends Object { | 151 class Scope { |
| 152 final Scope parent; | 152 final Scope parent; |
| 153 final Object model; | 153 final Object model; |
| 154 // TODO(justinfagnani): disallow adding/removing names | 154 // TODO(justinfagnani): disallow adding/removing names |
| 155 final ObservableMap<String, Object> _variables; | 155 final ObservableMap<String, Object> _variables; |
| 156 InstanceMirror __modelMirror; | 156 InstanceMirror __modelMirror; |
| 157 | 157 |
| 158 Scope({this.model, Map<String, Object> variables: const {}, this.parent}) | 158 Scope({this.model, Map<String, Object> variables: const {}, this.parent}) |
| 159 : _variables = new ObservableMap.from(variables); | 159 : _variables = new ObservableMap.from(variables); |
| 160 | 160 |
| 161 InstanceMirror get _modelMirror { | 161 InstanceMirror get _modelMirror { |
| 162 if (__modelMirror != null) return __modelMirror; | 162 if (__modelMirror != null) return __modelMirror; |
| 163 __modelMirror = reflect(model); | 163 __modelMirror = reflect(model); |
| 164 return __modelMirror; | 164 return __modelMirror; |
| 165 } | 165 } |
| 166 | 166 |
| 167 Object operator[](String name) { | 167 Object operator[](String name) { |
| 168 if (name == 'this') { | 168 if (name == 'this') { |
| 169 return model; | 169 return model; |
| 170 } else if (_variables.containsKey(name)) { | 170 } else if (_variables.containsKey(name)) { |
| 171 return _convert(_variables[name]); | 171 return _convert(_variables[name]); |
| 172 } else if (model != null) { | 172 } else if (model != null) { |
| 173 var symbol = new Symbol(name); | 173 var symbol = new Symbol(name); |
| 174 var classMirror = _modelMirror.type; | 174 var classMirror = _modelMirror.type; |
| 175 var memberMirror = getMemberMirror(classMirror, symbol); | 175 var memberMirror = getMemberMirror(classMirror, symbol); |
| 176 // TODO(jmesserly): simplify once dartbug.com/13002 is fixed. |
| 177 // This can just be "if memberMirror != null" and delete the Method class. |
| 176 if (memberMirror is VariableMirror || | 178 if (memberMirror is VariableMirror || |
| 177 (memberMirror is MethodMirror && memberMirror.isGetter)) { | 179 (memberMirror is MethodMirror && memberMirror.isGetter)) { |
| 178 return _convert(_modelMirror.getField(symbol).reflectee); | 180 return _convert(_modelMirror.getField(symbol).reflectee); |
| 179 } else if (memberMirror is MethodMirror) { | 181 } else if (memberMirror is MethodMirror) { |
| 180 return new Method(_modelMirror, symbol); | 182 return new Method(_modelMirror, symbol); |
| 181 } | 183 } |
| 182 } | 184 } |
| 183 if (parent != null) { | 185 if (parent != null) { |
| 184 return _convert(parent[name]); | 186 return _convert(parent[name]); |
| 185 } else { | 187 } else { |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 593 | 595 |
| 594 // TODO: make Comprehension observable and update it | 596 // TODO: make Comprehension observable and update it |
| 595 _value = new Comprehension(identifier.value, iterable); | 597 _value = new Comprehension(identifier.value, iterable); |
| 596 } | 598 } |
| 597 | 599 |
| 598 accept(Visitor v) => v.visitInExpression(this); | 600 accept(Visitor v) => v.visitInExpression(this); |
| 599 } | 601 } |
| 600 | 602 |
| 601 _toBool(v) => (v == null) ? false : v; | 603 _toBool(v) => (v == null) ? false : v; |
| 602 | 604 |
| 603 call(dynamic receiver, List args) { | 605 /** Call a [Function] or a [Method]. */ |
| 606 // TODO(jmesserly): remove this once dartbug.com/13002 is fixed. |
| 607 // Just inline `_convert(Function.apply(...))` to the call site. |
| 608 Object call(Object receiver, List args) { |
| 609 var result; |
| 604 if (receiver is Method) { | 610 if (receiver is Method) { |
| 605 return | 611 result = receiver.mirror.invoke(receiver.symbol, args, null).reflectee; |
| 606 _convert(receiver.mirror.invoke(receiver.symbol, args, null).reflectee); | |
| 607 } else { | 612 } else { |
| 608 return _convert(Function.apply(receiver, args, null)); | 613 result = Function.apply(receiver, args, null); |
| 609 } | 614 } |
| 615 return _convert(result); |
| 610 } | 616 } |
| 611 | 617 |
| 612 /** | 618 /** |
| 613 * A comprehension declaration ("a in b"). [identifier] is the loop variable | 619 * A comprehension declaration ("a in b"). [identifier] is the loop variable |
| 614 * that's added to the scope during iteration. [iterable] is the set of | 620 * that's added to the scope during iteration. [iterable] is the set of |
| 615 * objects to iterate over. | 621 * objects to iterate over. |
| 616 */ | 622 */ |
| 617 class Comprehension { | 623 class Comprehension { |
| 618 final String identifier; | 624 final String identifier; |
| 619 final Iterable iterable; | 625 final Iterable iterable; |
| 620 | 626 |
| 621 Comprehension(this.identifier, Iterable iterable) | 627 Comprehension(this.identifier, Iterable iterable) |
| 622 : iterable = (iterable != null) ? iterable : const []; | 628 : iterable = (iterable != null) ? iterable : const []; |
| 623 } | 629 } |
| 624 | 630 |
| 625 /** | 631 /** A method on a model object in a [Scope]. */ |
| 626 * A method on a model object in a [Scope]. | 632 class Method { |
| 627 */ | |
| 628 class Method { //implements _FunctionWrapper { | |
| 629 final InstanceMirror mirror; | 633 final InstanceMirror mirror; |
| 630 final Symbol symbol; | 634 final Symbol symbol; |
| 631 | 635 |
| 632 Method(this.mirror, this.symbol); | 636 Method(this.mirror, this.symbol); |
| 633 | 637 |
| 634 dynamic call(List args) => mirror.invoke(symbol, args, null).reflectee; | 638 /** |
| 639 * Support for calling single argument methods like [Filter]s. |
| 640 * This does not work for calls that need to pass more than one argument. |
| 641 */ |
| 642 call(arg0) => mirror.invoke(symbol, [arg0], null).reflectee; |
| 635 } | 643 } |
| 636 | 644 |
| 637 class EvalException implements Exception { | 645 class EvalException implements Exception { |
| 638 final String message; | 646 final String message; |
| 639 EvalException(this.message); | 647 EvalException(this.message); |
| 640 String toString() => "EvalException: $message"; | 648 String toString() => "EvalException: $message"; |
| 641 } | 649 } |
| OLD | NEW |