| Index: third_party/pkg/angular/lib/core/parser/parser.dart
|
| diff --git a/third_party/pkg/angular/lib/core/parser/parser.dart b/third_party/pkg/angular/lib/core/parser/parser.dart
|
| index 0de9632fd17f6e5c28847d4e4319c641d0a2669a..74fbb09681ff47575b81451a2f9934e52091e101 100644
|
| --- a/third_party/pkg/angular/lib/core/parser/parser.dart
|
| +++ b/third_party/pkg/angular/lib/core/parser/parser.dart
|
| @@ -1,485 +1,103 @@
|
| -part of angular.core.parser;
|
| -
|
| -typedef ParsedGetter(self);
|
| -typedef ParsedSetter(self, value);
|
| -
|
| -typedef Getter([locals]);
|
| -typedef Setter(value, [locals]);
|
| -
|
| -abstract class ParserAST {
|
| - bool get assignable;
|
| -}
|
| -
|
| -class Token {
|
| - final int index;
|
| - final String text;
|
| -
|
| - var value;
|
| - // Tokens should have one of these set.
|
| - String opKey;
|
| - String key;
|
| -
|
| - Token(this.index, this.text);
|
| -
|
| - withOp(op) {
|
| - this.opKey = op;
|
| - }
|
| -
|
| - withGetterSetter(key) {
|
| - this.key = key;
|
| - }
|
| -
|
| - withValue(value) { this.value = value; }
|
| -
|
| - toString() => "Token($text)";
|
| -}
|
| -
|
| -typedef Operator(dynamic self, ParserAST a, ParserAST b);
|
| -
|
| -Operator NULL_OP = (_, _0, _1) => null;
|
| -Operator NOT_IMPL_OP = (_, _0, _1) { throw "Op not implemented"; };
|
| -
|
| -// FUNCTIONS USED AT RUNTIME.
|
| -
|
| -parserEvalError(String s, String text, stack) =>
|
| - ['Eval Error: $s while evaling [$text]' +
|
| - (stack != null ? '\n\nFROM:\n$stack' : '')];
|
| -
|
| -// Automatic type conversion.
|
| -autoConvertAdd(a, b) {
|
| - if (a != null && b != null) {
|
| - // TODO(deboer): Support others.
|
| - if (a is String && b is! String) {
|
| - return a + b.toString();
|
| - }
|
| - if (a is! String && b is String) {
|
| - return a.toString() + b;
|
| - }
|
| - return a + b;
|
| - }
|
| - if (a != null) return a;
|
| - if (b != null) return b;
|
| - return null;
|
| -}
|
| -
|
| -objectIndexGetField(o, i, evalError) {
|
| - if (o == null) throw evalError('Accessing null object');
|
| -
|
| - if (o is List) {
|
| - return o[i.toInt()];
|
| - } else if (o is Map) {
|
| - return o[i.toString()]; // toString dangerous?
|
| - }
|
| - throw evalError("Attempted field access on a non-list, non-map");
|
| -}
|
| -
|
| -objectIndexSetField(o, i, v, evalError) {
|
| - if (o is List) {
|
| - int arrayIndex = i.toInt();
|
| - if (o.length <= arrayIndex) { o.length = arrayIndex + 1; }
|
| - o[arrayIndex] = v;
|
| - } else if (o is Map) {
|
| - o[i.toString()] = v; // toString dangerous?
|
| - } else {
|
| - throw evalError("Attempting to set a field on a non-list, non-map");
|
| - }
|
| - return v;
|
| -}
|
| -
|
| -safeFunctionCall(userFn, fnName, evalError) {
|
| - if (userFn == null) {
|
| - throw evalError("Undefined function $fnName");
|
| - }
|
| - if (userFn is! Function) {
|
| - throw evalError("$fnName is not a function");
|
| - }
|
| - return userFn;
|
| +library angular.core.parser;
|
| +
|
| +export 'package:angular/core/parser/syntax.dart'
|
| + show Visitor, Expression, BoundExpression;
|
| +export 'package:angular/core/parser/dynamic_parser.dart'
|
| + show DynamicParser, DynamicParserBackend, ClosureMap;
|
| +export 'package:angular/core/parser/static_parser.dart'
|
| + show StaticParser, StaticParserFunctions;
|
| +
|
| +typedef LocalsWrapper(context, locals);
|
| +typedef Getter(self);
|
| +typedef Setter(self, value);
|
| +
|
| +/// Placeholder for DI. The parser you are looking for is [DynamicParser].
|
| +abstract class Parser<T> {
|
| + T call(String input);
|
| }
|
|
|
|
|
| -Map<String, Operator> OPERATORS = {
|
| - 'undefined': NULL_OP,
|
| - 'null': NULL_OP,
|
| - 'true': (self, a, b) => true,
|
| - 'false': (self, a, b) => false,
|
| - '+': (self, aFn, bFn) {
|
| - var a = aFn.eval(self);
|
| - var b = bFn.eval(self);
|
| - return autoConvertAdd(a, b);
|
| - },
|
| - '-': (self, a, b) {
|
| - assert(a != null || b != null);
|
| - var aResult = a != null ? a.eval(self) : null;
|
| - var bResult = b != null ? b.eval(self) : null;
|
| - return (aResult == null ? 0 : aResult) - (bResult == null ? 0 : bResult);
|
| - },
|
| - '*': (s, a, b) => a.eval(s) * b.eval(s),
|
| - '/': (s, a, b) => a.eval(s) / b.eval(s),
|
| - '~/': (s, a, b) => a.eval(s) ~/ b.eval(s),
|
| - '%': (s, a, b) => a.eval(s) % b.eval(s),
|
| - '^': (s, a, b) => a.eval(s) ^ b.eval(s),
|
| - '=': NULL_OP,
|
| - '==': (s, a, b) => a.eval(s) == b.eval(s),
|
| - '!=': (s, a, b) => a.eval(s) != b.eval(s),
|
| - '<': (s, a, b) => a.eval(s) < b.eval(s),
|
| - '>': (s, a, b) => a.eval(s) > b.eval(s),
|
| - '<=': (s, a, b) => a.eval(s) <= b.eval(s),
|
| - '>=': (s, a, b) => a.eval(s) >= b.eval(s),
|
| - '&&': (s, a, b) => toBool(a.eval(s)) && toBool(b.eval(s)),
|
| - '||': (s, a, b) => toBool(a.eval(s)) || toBool(b.eval(s)),
|
| - '&': (s, a, b) => a.eval(s) & b.eval(s),
|
| - '|': NOT_IMPL_OP, //b()(a())
|
| - '!': (s, a, b) => !toBool(a.eval(s)),
|
| - '?': (s, c, t, f) => toBool(c.eval(s)) ? t.eval(s) : f.eval(s),
|
| -};
|
| -
|
| -@NgInjectableService()
|
| -class DynamicParser implements Parser {
|
| - final Lexer _lexer;
|
| - final ParserBackend _b;
|
| -
|
| - DynamicParser(this._lexer, this._b);
|
| -
|
| - List<Token> _tokens;
|
| - String _text;
|
| - var _evalError;
|
| -
|
| - Map<String, ParserAST> _cache = {};
|
| -
|
| - ParserAST call(String text) {
|
| - var value = _cache[text];
|
| - if (value != null) {
|
| - return value;
|
| - }
|
| - return _cache[text] = _call(text);
|
| - }
|
| -
|
| - ParserAST _call(String text) {
|
| - try {
|
| - if (text == null) text = '';
|
| - _tokenSavers = [];
|
| - _text = text;
|
| - _tokens = _lexer.call(text);
|
| - _evalError = (String s, [stack]) => parserEvalError(s, text, stack);
|
| -
|
| - ParserAST value = _statements();
|
| -
|
| - if (_tokens.length != 0) {
|
| - throw _parserError("Unconsumed token ${_tokens[0].text}");
|
| - }
|
| - return value;
|
| - } finally {
|
| - _tokens = null;
|
| - _text = null;
|
| - _evalError = null;
|
| - _tokenSavers = null;
|
| - }
|
| - }
|
| -
|
| - primaryFromToken(Token token, parserError) {
|
| - if (token.key != null) {
|
| - return _b.getterSetter(token.key);
|
| - }
|
| - if (token.opKey != null) {
|
| - return _b.fromOperator(token.opKey);
|
| - }
|
| - if (token.value != null) {
|
| - return _b.value(token.value);
|
| - }
|
| - if (token.text != null) {
|
| - return _b.value(token.text);
|
| - }
|
| - throw parserError("Internal Angular Error: Tokens should have keys, text or fns");
|
| - }
|
| -
|
| - _parserError(String s, [Token t]) {
|
| - if (t == null && !_tokens.isEmpty) t = _tokens[0];
|
| - String location = t == null ?
|
| - 'the end of the expression' :
|
| - 'at column ${t.index + 1} in';
|
| - return 'Parser Error: $s $location [$_text]';
|
| - }
|
| -
|
| -
|
| - Token _peekToken() {
|
| - if (_tokens.length == 0)
|
| - throw "Unexpected end of expression: " + _text;
|
| - return _tokens[0];
|
| - }
|
| -
|
| - Token _peek([String e1, String e2, String e3, String e4]) {
|
| - if (_tokens.length > 0) {
|
| - Token token = _tokens[0];
|
| - String t = token.text;
|
| - if (t==e1 || t==e2 || t==e3 || t==e4 ||
|
| - (e1 == null && e2 == null && e3 == null && e4 == null)) {
|
| - return token;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Token savers are synchronous lists that allows Parser functions to
|
| - * access the tokens parsed during some amount of time. They are useful
|
| - * for printing helpful debugging messages.
|
| - */
|
| - List<List<Token>> _tokenSavers;
|
| - List<Token> _saveTokens() { var n = []; _tokenSavers.add(n); return n; }
|
| - _stopSavingTokens(x) { if (!_tokenSavers.remove(x)) { throw 'bad token saver'; } return x; }
|
| - _tokensText(List x) => x.map((x) => x.text).join();
|
| -
|
| -
|
| - Token _expect([String e1, String e2, String e3, String e4]){
|
| - Token token = _peek(e1, e2, e3, e4);
|
| - if (token != null) {
|
| - var consumed = _tokens.removeAt(0);
|
| - _tokenSavers.forEach((ts) => ts.add(consumed));
|
| - return token;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - ParserAST _consume(e1){
|
| - if (_expect(e1) == null) {
|
| - throw _parserError("Missing expected $e1");
|
| - }
|
| - }
|
| -
|
| - ParserAST _primary() {
|
| - var primary;
|
| - var ts = _saveTokens();
|
| - if (_expect('(') != null) {
|
| - primary = _filterChain();
|
| - _consume(')');
|
| - } else if (_expect('[') != null) {
|
| - primary = _arrayDeclaration();
|
| - } else if (_expect('{') != null) {
|
| - primary = _object();
|
| - } else {
|
| - Token token = _expect();
|
| - primary = primaryFromToken(token, _parserError);
|
| - if (primary == null) {
|
| - throw _parserError("Internal Angular Error: Unreachable code A.");
|
| - }
|
| - }
|
| -
|
| - var next;
|
| - while ((next = _expect('(', '[', '.')) != null) {
|
| - if (next.text == '(') {
|
| - primary = _functionCall(primary, _tokensText(ts.sublist(0, ts.length - 1)));
|
| - } else if (next.text == '[') {
|
| - primary = _objectIndex(primary);
|
| - } else if (next.text == '.') {
|
| - primary = _fieldAccess(primary);
|
| - } else {
|
| - throw _parserError("Internal Angular Error: Unreachable code B.");
|
| - }
|
| - }
|
| - _stopSavingTokens(ts);
|
| - return primary;
|
| - }
|
| -
|
| - ParserAST _binaryFn(ParserAST left, String op, ParserAST right) =>
|
| - _b.binaryFn(left, op, right);
|
| -
|
| - ParserAST _unaryFn(String op, ParserAST right) =>
|
| - _b.unaryFn(op, right);
|
| -
|
| - ParserAST _unary() {
|
| - var token;
|
| - if (_expect('+') != null) {
|
| - return _primary();
|
| - } else if ((token = _expect('-')) != null) {
|
| - return _binaryFn(_b.zero(), token.opKey, _unary());
|
| - } else if ((token = _expect('!')) != null) {
|
| - return _unaryFn(token.opKey, _unary());
|
| - } else {
|
| - return _primary();
|
| - }
|
| - }
|
| -
|
| - ParserAST _multiplicative() {
|
| - var left = _unary();
|
| - var token;
|
| - while ((token = _expect('*','%','/','~/')) != null) {
|
| - left = _binaryFn(left, token.opKey, _unary());
|
| - }
|
| - return left;
|
| - }
|
| -
|
| - ParserAST _additive() {
|
| - var left = _multiplicative();
|
| - var token;
|
| - while ((token = _expect('+','-')) != null) {
|
| - left = _binaryFn(left, token.opKey, _multiplicative());
|
| - }
|
| - return left;
|
| - }
|
| -
|
| - ParserAST _relational() {
|
| - var left = _additive();
|
| - var token;
|
| - if ((token = _expect('<', '>', '<=', '>=')) != null) {
|
| - left = _binaryFn(left, token.opKey, _relational());
|
| - }
|
| - return left;
|
| - }
|
| -
|
| - ParserAST _equality() {
|
| - var left = _relational();
|
| - var token;
|
| - if ((token = _expect('==','!=')) != null) {
|
| - left = _binaryFn(left, token.opKey, _equality());
|
| - }
|
| - return left;
|
| - }
|
| -
|
| - ParserAST _logicalAND() {
|
| - var left = _equality();
|
| - var token;
|
| - if ((token = _expect('&&')) != null) {
|
| - left = _binaryFn(left, token.opKey, _logicalAND());
|
| - }
|
| - return left;
|
| - }
|
| -
|
| - ParserAST _logicalOR() {
|
| - var left = _logicalAND();
|
| - var token;
|
| - while(true) {
|
| - if ((token = _expect('||')) != null) {
|
| - left = _binaryFn(left, token.opKey, _logicalAND());
|
| - } else {
|
| - return left;
|
| - }
|
| - }
|
| - }
|
| -
|
| - ParserAST _ternary() {
|
| - var ts = _saveTokens();
|
| - var cond = _logicalOR();
|
| - var token = _expect('?');
|
| - if (token != null) {
|
| - var _true = _expression();
|
| - if ((token = _expect(':')) != null) {
|
| - cond = _b.ternaryFn(cond, _true, _expression());
|
| - } else {
|
| - throw _parserError('Conditional expression ${_tokensText(ts)} requires '
|
| - 'all 3 expressions');
|
| - }
|
| - }
|
| - _stopSavingTokens(ts);
|
| - return cond;
|
| - }
|
| -
|
| - ParserAST _assignment() {
|
| - var ts = _saveTokens();
|
| - var left = _ternary();
|
| - _stopSavingTokens(ts);
|
| - var right;
|
| - var token;
|
| - if ((token = _expect('=')) != null) {
|
| - if (!left.assignable) {
|
| - throw _parserError('Expression ${_tokensText(ts)} is not assignable', token);
|
| - }
|
| - right = _ternary();
|
| - return _b.assignment(left, right, _evalError);
|
| - } else {
|
| - return left;
|
| - }
|
| - }
|
| -
|
| - ParserAST _expression() {
|
| - return _assignment();
|
| - }
|
| -
|
| - _filterChain() {
|
| - var left = _expression();
|
| - var token;
|
| - while(true) {
|
| - if ((token = _expect('|')) != null) {
|
| - left = _filter(left);
|
| - } else {
|
| - return left;
|
| - }
|
| - }
|
| - }
|
| -
|
| - ParserAST _filter(ParserAST left) {
|
| - var token = _expect();
|
| - var filterName = token.text;
|
| - var argsFn = [];
|
| - while(true) {
|
| - if ((token = _expect(':')) != null) {
|
| - argsFn.add(_expression());
|
| - } else {
|
| - return _b.filter(filterName, left, argsFn, _evalError);
|
| - }
|
| - }
|
| - }
|
| -
|
| - _statements() {
|
| - List<ParserAST> statements = [];
|
| - while (true) {
|
| - if (_tokens.length > 0 && _peek('}', ')', ';', ']') == null)
|
| - statements.add(_filterChain());
|
| - if (_expect(';') == null) {
|
| - return statements.length == 1
|
| - ? statements[0]
|
| - : _b.multipleStatements(statements);
|
| - }
|
| - }
|
| - }
|
| -
|
| - _functionCall(fn, fnName) {
|
| - var argsFn = [];
|
| - if (_peekToken().text != ')') {
|
| - do {
|
| - argsFn.add(_expression());
|
| - } while (_expect(',') != null);
|
| - }
|
| - _consume(')');
|
| - return _b.functionCall(fn, fnName, argsFn, _evalError);
|
| - }
|
| -
|
| - // This is used with json array declaration
|
| - _arrayDeclaration() {
|
| - var elementFns = [];
|
| - if (_peekToken().text != ']') {
|
| - do {
|
| - elementFns.add(_expression());
|
| - } while (_expect(',') != null);
|
| - }
|
| - _consume(']');
|
| - return _b.arrayDeclaration(elementFns);
|
| - }
|
| -
|
| - _objectIndex(obj) {
|
| - var indexFn = _expression();
|
| - _consume(']');
|
| - return _b.objectIndex(obj, indexFn, _evalError);
|
| - }
|
| -
|
| - _fieldAccess(object) {
|
| - var field = _expect().text;
|
| - //var getter = getter(field);
|
| - return _b.fieldAccess(object, field);
|
| - }
|
| -
|
| - _object() {
|
| - var keyValues = [];
|
| - if (_peekToken().text != '}') {
|
| - do {
|
| - var token = _expect(),
|
| - key = token.value != null && token.value is String ? token.value : token.text;
|
| - _consume(":");
|
| - var value = _expression();
|
| - keyValues.add({"key":key, "value":value});
|
| - } while (_expect(',') != null);
|
| - }
|
| - _consume('}');
|
| - return _b.object(keyValues);
|
| - }
|
| -
|
| +abstract class ParserBackend<T> {
|
| + bool isAssignable(T expression);
|
| +
|
| + T newChain(List expressions)
|
| + => null;
|
| + T newFilter(T expression, String name, List arguments)
|
| + => null;
|
| +
|
| + T newAssign(T target, T value)
|
| + => null;
|
| + T newConditional(T condition, T yes, T no)
|
| + => null;
|
| +
|
| + T newAccessScope(String name)
|
| + => null;
|
| + T newAccessMember(T object, String name)
|
| + => null;
|
| + T newAccessKeyed(T object, T key)
|
| + => null;
|
| +
|
| + T newCallScope(String name, List arguments)
|
| + => null;
|
| + T newCallFunction(T function, List arguments)
|
| + => null;
|
| + T newCallMember(T object, String name, List arguments)
|
| + => null;
|
| +
|
| + T newPrefix(String operation, T expression)
|
| + => null;
|
| + T newPrefixPlus(T expression)
|
| + => expression;
|
| + T newPrefixMinus(T expression)
|
| + => newBinaryMinus(newLiteralZero(), expression);
|
| + T newPrefixNot(T expression)
|
| + => newPrefix('!', expression);
|
| +
|
| + T newBinary(String operation, T left, T right)
|
| + => null;
|
| + T newBinaryPlus(T left, T right)
|
| + => newBinary('+', left, right);
|
| + T newBinaryMinus(T left, T right)
|
| + => newBinary('-', left, right);
|
| + T newBinaryMultiply(T left, T right)
|
| + => newBinary('*', left, right);
|
| + T newBinaryDivide(T left, T right)
|
| + => newBinary('/', left, right);
|
| + T newBinaryModulo(T left, T right)
|
| + => newBinary('%', left, right);
|
| + T newBinaryTruncatingDivide(T left, T right)
|
| + => newBinary('~/', left, right);
|
| + T newBinaryLogicalAnd(T left, T right)
|
| + => newBinary('&&', left, right);
|
| + T newBinaryLogicalOr(T left, T right)
|
| + => newBinary('||', left, right);
|
| + T newBinaryEqual(T left, T right)
|
| + => newBinary('==', left, right);
|
| + T newBinaryNotEqual(T left, T right)
|
| + => newBinary('!=', left, right);
|
| + T newBinaryLessThan(T left, T right)
|
| + => newBinary('<', left, right);
|
| + T newBinaryGreaterThan(T left, T right)
|
| + => newBinary('>', left, right);
|
| + T newBinaryLessThanEqual(T left, T right)
|
| + => newBinary('<=', left, right);
|
| + T newBinaryGreaterThanEqual(T left, T right)
|
| + => newBinary('>=', left, right);
|
| +
|
| + T newLiteralPrimitive(value)
|
| + => null;
|
| + T newLiteralArray(List elements)
|
| + => null;
|
| + T newLiteralObject(List<String> keys, List values)
|
| + => null;
|
| + T newLiteralNull()
|
| + => newLiteralPrimitive(null);
|
| + T newLiteralZero()
|
| + => newLiteralNumber(0);
|
| + T newLiteralBoolean(bool value)
|
| + => newLiteralPrimitive(value);
|
| + T newLiteralNumber(num value)
|
| + => newLiteralPrimitive(value);
|
| + T newLiteralString(String value)
|
| + => null;
|
| }
|
|
|