diff options
Diffstat (limited to 'src/Parser.js')
| -rw-r--r-- | src/Parser.js | 663 |
1 files changed, 0 insertions, 663 deletions
diff --git a/src/Parser.js b/src/Parser.js deleted file mode 100644 index 8dc8f9c2..00000000 --- a/src/Parser.js +++ /dev/null @@ -1,663 +0,0 @@ -var OPERATORS = { - 'null':function(self){return _null;}, - 'true':function(self){return true;}, - 'false':function(self){return false;}, - $undefined:noop, - '+':function(self, a,b){return (isDefined(a)?a:0)+(isDefined(b)?b:0);}, - '-':function(self, a,b){return (isDefined(a)?a:0)-(isDefined(b)?b:0);}, - '*':function(self, a,b){return a*b;}, - '/':function(self, a,b){return a/b;}, - '%':function(self, a,b){return a%b;}, - '^':function(self, a,b){return a^b;}, - '=':function(self, a,b){return setter(self, a, b);}, - '==':function(self, a,b){return a==b;}, - '!=':function(self, a,b){return a!=b;}, - '<':function(self, a,b){return a<b;}, - '>':function(self, a,b){return a>b;}, - '<=':function(self, a,b){return a<=b;}, - '>=':function(self, a,b){return a>=b;}, - '&&':function(self, a,b){return a&&b;}, - '||':function(self, a,b){return a||b;}, - '&':function(self, a,b){return a&b;}, -// '|':function(self, a,b){return a|b;}, - '|':function(self, a,b){return b(self, a);}, - '!':function(self, a){return !a;} -}; -var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'}; - -function lex(text, parseStringsForObjects){ - var dateParseLength = parseStringsForObjects ? 20 : -1, - tokens = [], - token, - index = 0, - json = [], - ch, - lastCh = ':'; // can start regexp - - while (index < text.length) { - ch = text.charAt(index); - if (is('"\'')) { - readString(ch); - } else if (isNumber(ch) || is('.') && isNumber(peek())) { - readNumber(); - } else if ( was('({[:,;') && is('/') ) { - readRegexp(); - } else if (isIdent(ch)) { - readIdent(); - if (was('{,') && json[0]=='{' && - (token=tokens[tokens.length-1])) { - token.json = token.text.indexOf('.') == -1; - } - } else if (is('(){}[].,;:')) { - tokens.push({index:index, text:ch, json:is('{}[]:,')}); - if (is('{[')) json.unshift(ch); - if (is('}]')) json.shift(); - index++; - } else if (isWhitespace(ch)) { - index++; - continue; - } else { - var ch2 = ch + peek(), - fn = OPERATORS[ch], - fn2 = OPERATORS[ch2]; - if (fn2) { - tokens.push({index:index, text:ch2, fn:fn2}); - index += 2; - } else if (fn) { - tokens.push({index:index, text:ch, fn:fn, json: was('[,:') && is('+-')}); - index += 1; - } else { - throw "Lexer Error: Unexpected next character [" + - text.substring(index) + - "] in expression '" + text + - "' at column '" + (index+1) + "'."; - } - } - lastCh = ch; - } - return tokens; - - function is(chars) { - return chars.indexOf(ch) != -1; - } - - function was(chars) { - return chars.indexOf(lastCh) != -1; - } - - function peek() { - return index + 1 < text.length ? text.charAt(index + 1) : false; - } - function isNumber(ch) { - return '0' <= ch && ch <= '9'; - } - function isWhitespace(ch) { - return ch == ' ' || ch == '\r' || ch == '\t' || - ch == '\n' || ch == '\v' || ch == '\u00A0'; // IE treats non-breaking space as \u00A0 - } - function isIdent(ch) { - return 'a' <= ch && ch <= 'z' || - 'A' <= ch && ch <= 'Z' || - '_' == ch || ch == '$'; - } - function isExpOperator(ch) { - return ch == '-' || ch == '+'; - } - function readNumber() { - var number = ""; - var start = index; - while (index < text.length) { - var ch = text.charAt(index); - if (ch == '.' || isNumber(ch)) { - number += ch; - } else { - var peekCh = peek(); - if (ch == 'E' && isExpOperator(peekCh)) { - number += ch; - } else if (isExpOperator(ch) && - peekCh && isNumber(peekCh) && - number.charAt(number.length - 1) == 'E') { - number += ch; - } else if (isExpOperator(ch) && - (!peekCh || !isNumber(peekCh)) && - number.charAt(number.length - 1) == 'E') { - throw 'Lexer found invalid exponential value "' + text + '"'; - } else { - break; - } - } - index++; - } - number = 1 * number; - tokens.push({index:start, text:number, json:true, - fn:function(){return number;}}); - } - function readIdent() { - var ident = ""; - var start = index; - while (index < text.length) { - var ch = text.charAt(index); - if (ch == '.' || isIdent(ch) || isNumber(ch)) { - ident += ch; - } else { - break; - } - index++; - } - var fn = OPERATORS[ident]; - if (!fn) { - fn = getterFn(ident); - fn.isAssignable = ident; - } - tokens.push({index:start, text:ident, fn:fn, json: OPERATORS[ident]}); - } - - function readString(quote) { - var start = index; - index++; - var string = ""; - var rawString = quote; - var escape = false; - while (index < text.length) { - var ch = text.charAt(index); - rawString += ch; - if (escape) { - if (ch == 'u') { - var hex = text.substring(index + 1, index + 5); - if (!hex.match(/[\da-f]{4}/i)) - throw "Lexer Error: Invalid unicode escape [\\u" + - hex + "] starting at column '" + - start + "' in expression '" + text + "'."; - index += 4; - string += String.fromCharCode(parseInt(hex, 16)); - } else { - var rep = ESCAPE[ch]; - if (rep) { - string += rep; - } else { - string += ch; - } - } - escape = false; - } else if (ch == '\\') { - escape = true; - } else if (ch == quote) { - index++; - tokens.push({index:start, text:rawString, string:string, json:true, - fn:function(){ - return (string.length == dateParseLength) ? - angular['String']['toDate'](string) : string; - }}); - return; - } else { - string += ch; - } - index++; - } - throw "Lexer Error: Unterminated quote [" + - text.substring(start) + "] starting at column '" + - (start+1) + "' in expression '" + text + "'."; - } - function readRegexp(quote) { - var start = index; - index++; - var regexp = ""; - var escape = false; - while (index < text.length) { - var ch = text.charAt(index); - if (escape) { - regexp += ch; - escape = false; - } else if (ch === '\\') { - regexp += ch; - escape = true; - } else if (ch === '/') { - index++; - var flags = ""; - if (isIdent(text.charAt(index))) { - readIdent(); - flags = tokens.pop().text; - } - var compiledRegexp = new RegExp(regexp, flags); - tokens.push({index:start, text:regexp, flags:flags, - fn:function(){return compiledRegexp;}}); - return; - } else { - regexp += ch; - } - index++; - } - throw "Lexer Error: Unterminated RegExp [" + - text.substring(start) + "] starting at column '" + - (start+1) + "' in expression '" + text + "'."; - } -} - -///////////////////////////////////////// - -function parser(text, json){ - var ZERO = valueFn(0), - tokens = lex(text, json); - return { - assertAllConsumed: assertAllConsumed, - primary: primary, - statements: statements, - validator: validator, - filter: filter, - watch: watch - }; - - /////////////////////////////////// - - function error(msg, token) { - throw "Token '" + token.text + - "' is " + msg + " at column='" + - (token.index + 1) + "' of expression '" + - text + "' starting at '" + text.substring(token.index) + "'."; - } - - function peekToken() { - if (tokens.length === 0) - throw "Unexpected end of expression: " + text; - return tokens[0]; - } - - function peek(e1, e2, e3, e4) { - if (tokens.length > 0) { - var token = tokens[0]; - var t = token.text; - if (t==e1 || t==e2 || t==e3 || t==e4 || - (!e1 && !e2 && !e3 && !e4)) { - return token; - } - } - return false; - } - - function expect(e1, e2, e3, e4){ - var token = peek(e1, e2, e3, e4); - if (token) { - if (json && !token.json) { - index = token.index; - throw "Expression at column='" + - token.index + "' of expression '" + - text + "' starting at '" + text.substring(token.index) + - "' is not valid json."; - } - tokens.shift(); - this.currentToken = token; - return token; - } - return false; - } - - function consume(e1){ - if (!expect(e1)) { - var token = peek(); - throw "Expecting '" + e1 + "' at column '" + - (token.index+1) + "' in '" + - text + "' got '" + - text.substring(token.index) + "'."; - } - } - - function unaryFn(fn, right) { - return function(self) { - return fn(self, right(self)); - }; - } - - function binaryFn(left, fn, right) { - return function(self) { - return fn(self, left(self), right(self)); - }; - } - - function hasTokens () { - return tokens.length > 0; - } - - function assertAllConsumed(){ - if (tokens.length !== 0) { - throw "Did not understand '" + text.substring(tokens[0].index) + - "' while evaluating '" + text + "'."; - } - } - - function statements(){ - var statements = []; - while(true) { - if (tokens.length > 0 && !peek('}', ')', ';', ']')) - statements.push(filterChain()); - if (!expect(';')) { - return function (self){ - var value; - for ( var i = 0; i < statements.length; i++) { - var statement = statements[i]; - if (statement) - value = statement(self); - } - return value; - }; - } - } - } - - function filterChain(){ - var left = expression(); - var token; - while(true) { - if ((token = expect('|'))) { - left = binaryFn(left, token.fn, filter()); - } else { - return left; - } - } - } - - function filter(){ - return pipeFunction(angularFilter); - } - - function validator(){ - return pipeFunction(angularValidator); - } - - function pipeFunction(fnScope){ - var fn = functionIdent(fnScope); - var argsFn = []; - var token; - while(true) { - if ((token = expect(':'))) { - argsFn.push(expression()); - } else { - var fnInvoke = function(self, input){ - var args = [input]; - for ( var i = 0; i < argsFn.length; i++) { - args.push(argsFn[i](self)); - } - return fn.apply(self, args); - }; - return function(){ - return fnInvoke; - }; - } - } - } - - function expression(){ - return throwStmt(); - } - - function throwStmt(){ - if (expect('throw')) { - var throwExp = assignment(); - return function (self) { - throw throwExp(self); - }; - } else { - return assignment(); - } - } - - function assignment(){ - var left = logicalOR(); - var token; - if (token = expect('=')) { - if (!left.isAssignable) { - throw "Left hand side '" + - text.substring(0, token.index) + "' of assignment '" + - text.substring(token.index) + "' is not assignable."; - } - var ident = function(){return left.isAssignable;}; - return binaryFn(ident, token.fn, logicalOR()); - } else { - return left; - } - } - - function logicalOR(){ - var left = logicalAND(); - var token; - while(true) { - if ((token = expect('||'))) { - left = binaryFn(left, token.fn, logicalAND()); - } else { - return left; - } - } - } - - function logicalAND(){ - var left = equality(); - var token; - if ((token = expect('&&'))) { - left = binaryFn(left, token.fn, logicalAND()); - } - return left; - } - - function equality(){ - var left = relational(); - var token; - if ((token = expect('==','!='))) { - left = binaryFn(left, token.fn, equality()); - } - return left; - } - - function relational(){ - var left = additive(); - var token; - if (token = expect('<', '>', '<=', '>=')) { - left = binaryFn(left, token.fn, relational()); - } - return left; - } - - function additive(){ - var left = multiplicative(); - var token; - while(token = expect('+','-')) { - left = binaryFn(left, token.fn, multiplicative()); - } - return left; - } - - function multiplicative(){ - var left = unary(); - var token; - while(token = expect('*','/','%')) { - left = binaryFn(left, token.fn, unary()); - } - return left; - } - - function unary(){ - var token; - if (expect('+')) { - return primary(); - } else if (token = expect('-')) { - return binaryFn(ZERO, token.fn, unary()); - } else if (token = expect('!')) { - return unaryFn(token.fn, unary()); - } else { - return primary(); - } - } - - function functionIdent(fnScope) { - var token = expect(); - var element = token.text.split('.'); - var instance = fnScope; - var key; - for ( var i = 0; i < element.length; i++) { - key = element[i]; - if (instance) - instance = instance[key]; - } - if (typeof instance != $function) { - throw "Function '" + token.text + "' at column '" + - (token.index+1) + "' in '" + text + "' is not defined."; - } - return instance; - } - - function primary() { - var primary; - if (expect('(')) { - var expression = filterChain(); - consume(')'); - primary = expression; - } else if (expect('[')) { - primary = arrayDeclaration(); - } else if (expect('{')) { - primary = object(); - } else { - var token = expect(); - primary = token.fn; - if (!primary) { - error("not a primary expression", token); - } - } - var next; - while (next = expect('(', '[', '.')) { - if (next.text === '(') { - primary = functionCall(primary); - } else if (next.text === '[') { - primary = objectIndex(primary); - } else if (next.text === '.') { - primary = fieldAccess(primary); - } else { - throw "IMPOSSIBLE"; - } - } - return primary; - } - - function fieldAccess(object) { - var field = expect().text; - var getter = getterFn(field); - var fn = function (self){ - return getter(object(self)); - }; - fn.isAssignable = field; - return fn; - } - - function objectIndex(obj) { - var indexFn = expression(); - consume(']'); - if (expect('=')) { - var rhs = expression(); - return function (self){ - return obj(self)[indexFn(self)] = rhs(self); - }; - } else { - return function (self){ - var o = obj(self); - var i = indexFn(self); - return (o) ? o[i] : _undefined; - }; - } - } - - function functionCall(fn) { - var argsFn = []; - if (peekToken().text != ')') { - do { - argsFn.push(expression()); - } while (expect(',')); - } - consume(')'); - return function (self){ - var args = []; - for ( var i = 0; i < argsFn.length; i++) { - args.push(argsFn[i](self)); - } - var fnPtr = fn(self) || noop; - // IE stupidity! - return fnPtr.apply ? - fnPtr.apply(self, args) : - fnPtr(args[0], args[1], args[2], args[3], args[4]); - }; - } - - // This is used with json array declaration - function arrayDeclaration () { - var elementFns = []; - if (peekToken().text != ']') { - do { - elementFns.push(expression()); - } while (expect(',')); - } - consume(']'); - return function (self){ - var array = []; - for ( var i = 0; i < elementFns.length; i++) { - array.push(elementFns[i](self)); - } - return array; - }; - } - - function object () { - var keyValues = []; - if (peekToken().text != '}') { - do { - var token = expect(), - key = token.string || token.text; - consume(":"); - var value = expression(); - keyValues.push({key:key, value:value}); - } while (expect(',')); - } - consume('}'); - return function (self){ - var object = {}; - for ( var i = 0; i < keyValues.length; i++) { - var keyValue = keyValues[i]; - var value = keyValue.value(self); - object[keyValue.key] = value; - } - return object; - }; - } - - function watch () { - var decl = []; - while(hasTokens()) { - decl.push(watchDecl()); - if (!expect(';')) { - assertAllConsumed(); - } - } - assertAllConsumed(); - return function (self){ - for ( var i = 0; i < decl.length; i++) { - var d = decl[i](self); - self.addListener(d.name, d.fn); - } - }; - } - - function watchDecl () { - var anchorName = expect().text; - consume(":"); - var expressionFn; - if (peekToken().text == '{') { - consume("{"); - expressionFn = statements(); - consume("}"); - } else { - expressionFn = expression(); - } - return function(self) { - return {name:anchorName, fn:expressionFn}; - }; - } -} - - - - |
