aboutsummaryrefslogtreecommitdiffstats
path: root/src/Parser.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/Parser.js')
-rw-r--r--src/Parser.js663
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};
- };
- }
-}
-
-
-
-