| OLD | NEW |
| (Empty) |
| 1 part of angular.core.parser; | |
| 2 | |
| 3 typedef dynamic LocalsWrapper(dynamic context, dynamic locals); | |
| 4 | |
| 5 class BoundExpression { | |
| 6 var _context; | |
| 7 LocalsWrapper _localsWrapper; | |
| 8 Expression expression; | |
| 9 | |
| 10 BoundExpression(this._context, this.expression, this._localsWrapper); | |
| 11 _localContext(locals) { | |
| 12 if (locals != null) { | |
| 13 if (_localsWrapper == null) { | |
| 14 throw new StateError("Locals $locals provided, but no LocalsWrapper st
rategy."); | |
| 15 } | |
| 16 return _localsWrapper(_context, locals); | |
| 17 } | |
| 18 return _context; | |
| 19 } | |
| 20 | |
| 21 call([locals]) => expression.eval(_localContext(locals)); | |
| 22 assign(value, [locals]) => expression.assign(_localContext(locals), value); | |
| 23 } | |
| 24 | |
| 25 class Expression implements ParserAST { | |
| 26 final ParsedGetter eval; | |
| 27 final ParsedSetter assign; | |
| 28 | |
| 29 String exp; | |
| 30 List parts; | |
| 31 | |
| 32 // Expressions that represent field accesses have a couple of | |
| 33 // extra fields. We use that to generate an optimized closure | |
| 34 // for calling fields of objects without having to load the | |
| 35 // field separately. | |
| 36 Expression fieldHolder; | |
| 37 String fieldName; | |
| 38 bool get isFieldAccess => fieldHolder != null; | |
| 39 | |
| 40 Expression(ParsedGetter this.eval, [ParsedSetter this.assign]); | |
| 41 | |
| 42 bind(context, [localsWrapper]) => new BoundExpression(context, this, localsWra
pper); | |
| 43 | |
| 44 get assignable => assign != null; | |
| 45 } | |
| 46 | |
| 47 @NgInjectableService() | |
| 48 class GetterSetter { | |
| 49 static stripTrailingNulls(List l) { | |
| 50 while (l.length > 0 && l.last == null) { | |
| 51 l.removeLast(); | |
| 52 } | |
| 53 return l; | |
| 54 } | |
| 55 | |
| 56 static _computeUseInstanceMembers() { | |
| 57 try { | |
| 58 reflect(Object).type.instanceMembers; | |
| 59 return true; | |
| 60 } catch (e) { | |
| 61 return false; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 final bool _useInstanceMembers = _computeUseInstanceMembers(); | |
| 66 | |
| 67 _containsKey(InstanceMirror instanceMirror, Symbol symbol) { | |
| 68 dynamic type = (instanceMirror.type as dynamic); | |
| 69 var members = _useInstanceMembers ? type.instanceMembers : type.members; | |
| 70 return members.containsKey(symbol); | |
| 71 } | |
| 72 | |
| 73 _maybeInvoke(instanceMirror, symbol) { | |
| 74 if (_containsKey(instanceMirror, symbol)) { | |
| 75 MethodMirror methodMirror = instanceMirror.type.members[symbol]; | |
| 76 return relaxFnArgs(([a0, a1, a2, a3, a4, a5]) { | |
| 77 var args = stripTrailingNulls([a0, a1, a2, a3, a4, a5]); | |
| 78 return instanceMirror.invoke(symbol, args).reflectee; | |
| 79 }); | |
| 80 } | |
| 81 return null; | |
| 82 } | |
| 83 | |
| 84 Map<String, Function> _getter_cache = {}; | |
| 85 | |
| 86 Function getter(String key) { | |
| 87 var value = _getter_cache[key]; | |
| 88 if (value != null) return value; | |
| 89 return _getter_cache[key] = _getter(key); | |
| 90 } | |
| 91 | |
| 92 Function _getter(String key) { | |
| 93 var symbol = new Symbol(key); | |
| 94 Map<ClassMirror, Function> fieldCache = {}; | |
| 95 return (o) { | |
| 96 InstanceMirror instanceMirror = reflect(o); | |
| 97 ClassMirror classMirror = instanceMirror.type; | |
| 98 Function fn = fieldCache[classMirror]; | |
| 99 if (fn == null) { | |
| 100 try { | |
| 101 return (fieldCache[classMirror] = (instanceMirror) => instanceMirror.g
etField(symbol).reflectee)(instanceMirror); | |
| 102 } on NoSuchMethodError catch (e) { | |
| 103 var value = (fieldCache[classMirror] = (instanceMirror) => _maybeInvok
e(instanceMirror, symbol))(instanceMirror); | |
| 104 if (value == null) { rethrow; } | |
| 105 return value; | |
| 106 } on UnsupportedError catch (e) { | |
| 107 var value = (fieldCache[classMirror] = (instanceMirror) => _maybeInvok
e(instanceMirror, symbol))(instanceMirror); | |
| 108 if (value == null) { rethrow; } | |
| 109 return value; | |
| 110 } | |
| 111 } else { | |
| 112 return fn(instanceMirror); | |
| 113 } | |
| 114 }; | |
| 115 } | |
| 116 | |
| 117 Function setter(String key) { | |
| 118 var symbol = new Symbol(key); | |
| 119 return (o, v) { | |
| 120 reflect(o).setField(symbol, v); | |
| 121 return v; | |
| 122 }; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 var undefined_ = const Symbol("UNDEFINED"); | |
| 127 | |
| 128 @NgInjectableService() | |
| 129 class ParserBackend { | |
| 130 GetterSetter _getterSetter; | |
| 131 FilterMap _filters; | |
| 132 | |
| 133 ParserBackend(GetterSetter this._getterSetter, FilterMap this._filters); | |
| 134 | |
| 135 static Expression ZERO = new Expression((_, [_x]) => 0); | |
| 136 | |
| 137 getter(String path) { | |
| 138 List<String> keys = path.split('.'); | |
| 139 List<Function> getters = keys.map(_getterSetter.getter).toList(); | |
| 140 | |
| 141 if (getters.isEmpty) { | |
| 142 return (self) => self; | |
| 143 } else { | |
| 144 return (dynamic self) { | |
| 145 if (self == null) { | |
| 146 return null; | |
| 147 } | |
| 148 | |
| 149 // Cache for local closure access | |
| 150 List<String> _keys = keys; | |
| 151 List<Function> _getters = getters; | |
| 152 var _gettersLength = _getters.length; | |
| 153 | |
| 154 num i = 0; | |
| 155 for (; i < _gettersLength; i++) { | |
| 156 if (self is Map) { | |
| 157 self = self[_keys[i]]; | |
| 158 } else { | |
| 159 self = _getters[i](self); | |
| 160 } | |
| 161 if (self == null) { | |
| 162 return null; | |
| 163 } | |
| 164 } | |
| 165 return self; | |
| 166 }; | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 setter(String path) { | |
| 171 List<String> keys = path.split('.'); | |
| 172 List<Function> getters = keys.map(_getterSetter.getter).toList(); | |
| 173 List<Function> setters = keys.map(_getterSetter.setter).toList(); | |
| 174 return (dynamic self, dynamic value) { | |
| 175 num i = 0; | |
| 176 List<String> _keys = keys; | |
| 177 List<Function> _getters = getters; | |
| 178 List<Function> _setters = setters; | |
| 179 var setterLengthMinusOne = _keys.length - 1; | |
| 180 | |
| 181 dynamic selfNext; | |
| 182 for (; i < setterLengthMinusOne; i++) { | |
| 183 if (self is Map) { | |
| 184 selfNext = self[_keys[i]]; | |
| 185 } else { | |
| 186 selfNext = _getters[i](self); | |
| 187 } | |
| 188 | |
| 189 if (selfNext == null) { | |
| 190 selfNext = {}; | |
| 191 if (self is Map) { | |
| 192 self[_keys[i]] = selfNext; | |
| 193 } else { | |
| 194 _setters[i](self, selfNext); | |
| 195 } | |
| 196 } | |
| 197 self = selfNext; | |
| 198 } | |
| 199 if (self is Map) { | |
| 200 self[_keys[setterLengthMinusOne]] = value; | |
| 201 } else { | |
| 202 _setters[i](self, value); | |
| 203 } | |
| 204 return value; | |
| 205 }; | |
| 206 } | |
| 207 | |
| 208 List evalList(List<Expression> list, self) { | |
| 209 int length = list.length; | |
| 210 List result = new List(length); | |
| 211 for (int i = 0; i < length; i++) { | |
| 212 result[i] = list[i].eval(self); | |
| 213 } | |
| 214 return result; | |
| 215 } | |
| 216 | |
| 217 _op(opKey) => OPERATORS[opKey]; | |
| 218 | |
| 219 Expression ternaryFn(Expression cond, Expression _true, Expression _false) => | |
| 220 new Expression((self) => _op('?')( | |
| 221 self, cond, _true, _false)); | |
| 222 | |
| 223 Expression binaryFn(Expression left, String op, Expression right) => | |
| 224 new Expression((self) => _op(op)(self, left, right)); | |
| 225 | |
| 226 Expression unaryFn(String op, Expression right) => | |
| 227 new Expression((self) => _op(op)(self, right, null)); | |
| 228 | |
| 229 Expression assignment(Expression left, Expression right, evalError) => | |
| 230 new Expression((self) { | |
| 231 try { | |
| 232 return left.assign(self, right.eval(self)); | |
| 233 } catch (e, s) { | |
| 234 throw evalError('Caught $e', s); | |
| 235 } | |
| 236 }); | |
| 237 | |
| 238 Expression multipleStatements(statements) => | |
| 239 new Expression((self) { | |
| 240 var value; | |
| 241 for ( var i = 0; i < statements.length; i++) { | |
| 242 var statement = statements[i]; | |
| 243 if (statement != null) | |
| 244 value = statement.eval(self); | |
| 245 } | |
| 246 return value; | |
| 247 }); | |
| 248 | |
| 249 Expression functionCall(fn, fnName, argsFn, evalError) { | |
| 250 if (fn.isFieldAccess) { | |
| 251 Symbol key = new Symbol(fn.fieldName); | |
| 252 return new Expression((self) { | |
| 253 List args = evalList(argsFn, self); | |
| 254 var holder = fn.fieldHolder.eval(self); | |
| 255 InstanceMirror instanceMirror = reflect(holder); | |
| 256 return instanceMirror.invoke(key, args).reflectee; | |
| 257 }); | |
| 258 } else { | |
| 259 return new Expression((self) { | |
| 260 List args = evalList(argsFn, self); | |
| 261 var userFn = safeFunctionCall(fn.eval(self), fnName, evalError); | |
| 262 return relaxFnApply(userFn, args); | |
| 263 }); | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 Expression arrayDeclaration(elementFns) => | |
| 268 new Expression((self){ | |
| 269 var array = []; | |
| 270 for ( var i = 0; i < elementFns.length; i++) { | |
| 271 array.add(elementFns[i].eval(self)); | |
| 272 } | |
| 273 return array; | |
| 274 }); | |
| 275 | |
| 276 Expression objectIndex(obj, indexFn, evalError) => | |
| 277 new Expression((self) { | |
| 278 var i = indexFn.eval(self); | |
| 279 var o = obj.eval(self), | |
| 280 v, p; | |
| 281 | |
| 282 v = objectIndexGetField(o, i, evalError); | |
| 283 | |
| 284 return v; | |
| 285 }, (self, value) => | |
| 286 objectIndexSetField(obj.eval(self), | |
| 287 indexFn.eval(self), value, evalError) | |
| 288 ); | |
| 289 | |
| 290 Expression fieldAccess(object, field) { | |
| 291 var setterFn = setter(field); | |
| 292 var getterFn = getter(field); | |
| 293 return new Expression( | |
| 294 (self) => getterFn(object.eval(self)), | |
| 295 (self, value) => setterFn(object.eval(self), value)) | |
| 296 ..fieldHolder = object | |
| 297 ..fieldName = field; | |
| 298 } | |
| 299 | |
| 300 Expression object(keyValues) => | |
| 301 new Expression((self){ | |
| 302 var object = {}; | |
| 303 for ( var i = 0; i < keyValues.length; i++) { | |
| 304 var keyValue = keyValues[i]; | |
| 305 var value = keyValue["value"].eval(self); | |
| 306 object[keyValue["key"]] = value; | |
| 307 } | |
| 308 return object; | |
| 309 }); | |
| 310 | |
| 311 Expression profiled(value, _perf, text) { | |
| 312 if (value is FilterExpression) return value; | |
| 313 var wrappedGetter = (s) => | |
| 314 _perf.time('angular.parser.getter', () => value.eval(s), text); | |
| 315 var wrappedAssignFn = null; | |
| 316 if (value.assign != null) { | |
| 317 wrappedAssignFn = (s, v) => | |
| 318 _perf.time('angular.parser.assign', | |
| 319 () => value.assign(s, v), text); | |
| 320 } | |
| 321 return new Expression(wrappedGetter, wrappedAssignFn); | |
| 322 } | |
| 323 | |
| 324 Expression fromOperator(String op) => | |
| 325 new Expression((s) => OPERATORS[op](s, null, null)); | |
| 326 | |
| 327 Expression getterSetter(key) => | |
| 328 new Expression(getter(key), setter(key)); | |
| 329 | |
| 330 Expression value(v) => | |
| 331 new Expression((self) => v); | |
| 332 | |
| 333 zero() => ZERO; | |
| 334 | |
| 335 Expression filter(String filterName, | |
| 336 Expression leftHandSide, | |
| 337 List<Expression> parameters, | |
| 338 Function evalError) { | |
| 339 var filterFn = _filters(filterName); | |
| 340 return new FilterExpression(filterFn, leftHandSide, parameters); | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 class FilterExpression extends Expression { | |
| 345 final Function filterFn; | |
| 346 final Expression leftHandSide; | |
| 347 final List<Expression> parameters; | |
| 348 | |
| 349 FilterExpression(Function this.filterFn, | |
| 350 Expression this.leftHandSide, | |
| 351 List<Expression> this.parameters): super(null); | |
| 352 | |
| 353 get eval => _eval; | |
| 354 | |
| 355 dynamic _eval(self) { | |
| 356 var args = [leftHandSide.eval(self)]; | |
| 357 for ( var i = 0; i < parameters.length; i++) { | |
| 358 args.add(parameters[i].eval(self)); | |
| 359 } | |
| 360 return Function.apply(filterFn, args); | |
| 361 } | |
| 362 } | |
| OLD | NEW |