| Index: sky/framework/sky-element/third_party/esprima/esprima.sky
|
| diff --git a/sky/framework/sky-element/third_party/esprima/esprima.sky b/sky/framework/sky-element/third_party/esprima/esprima.sky
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0ac5dedc9a98f23c157bbfa67bd04d2489081aba
|
| --- /dev/null
|
| +++ b/sky/framework/sky-element/third_party/esprima/esprima.sky
|
| @@ -0,0 +1,1042 @@
|
| +<script>
|
| +
|
| +/*
|
| + Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
|
| + Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
|
| + Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
|
| + Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
|
| + Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
|
| + Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
|
| + Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
|
| + Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
|
| + Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
|
| +
|
| + Redistribution and use in source and binary forms, with or without
|
| + modification, are permitted provided that the following conditions are met:
|
| +
|
| + * Redistributions of source code must retain the above copyright
|
| + notice, this list of conditions and the following disclaimer.
|
| + * Redistributions in binary form must reproduce the above copyright
|
| + notice, this list of conditions and the following disclaimer in the
|
| + documentation and/or other materials provided with the distribution.
|
| +
|
| + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| + ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
| + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
| + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
| + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
| + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
| + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +*/
|
| +
|
| +var Token,
|
| + TokenName,
|
| + Syntax,
|
| + Messages,
|
| + source,
|
| + index,
|
| + length,
|
| + delegate,
|
| + lookahead,
|
| + state;
|
| +
|
| +Token = {
|
| + BooleanLiteral: 1,
|
| + EOF: 2,
|
| + Identifier: 3,
|
| + Keyword: 4,
|
| + NullLiteral: 5,
|
| + NumericLiteral: 6,
|
| + Punctuator: 7,
|
| + StringLiteral: 8
|
| +};
|
| +
|
| +TokenName = {};
|
| +TokenName[Token.BooleanLiteral] = 'Boolean';
|
| +TokenName[Token.EOF] = '<end>';
|
| +TokenName[Token.Identifier] = 'Identifier';
|
| +TokenName[Token.Keyword] = 'Keyword';
|
| +TokenName[Token.NullLiteral] = 'Null';
|
| +TokenName[Token.NumericLiteral] = 'Numeric';
|
| +TokenName[Token.Punctuator] = 'Punctuator';
|
| +TokenName[Token.StringLiteral] = 'String';
|
| +
|
| +Syntax = {
|
| + ArrayExpression: 'ArrayExpression',
|
| + BinaryExpression: 'BinaryExpression',
|
| + CallExpression: 'CallExpression',
|
| + ConditionalExpression: 'ConditionalExpression',
|
| + EmptyStatement: 'EmptyStatement',
|
| + ExpressionStatement: 'ExpressionStatement',
|
| + Identifier: 'Identifier',
|
| + Literal: 'Literal',
|
| + LabeledStatement: 'LabeledStatement',
|
| + LogicalExpression: 'LogicalExpression',
|
| + MemberExpression: 'MemberExpression',
|
| + ObjectExpression: 'ObjectExpression',
|
| + Program: 'Program',
|
| + Property: 'Property',
|
| + ThisExpression: 'ThisExpression',
|
| + UnaryExpression: 'UnaryExpression'
|
| +};
|
| +
|
| +// Error messages should be identical to V8.
|
| +Messages = {
|
| + UnexpectedToken: 'Unexpected token %0',
|
| + UnknownLabel: 'Undefined label \'%0\'',
|
| + Redeclaration: '%0 \'%1\' has already been declared'
|
| +};
|
| +
|
| +// Ensure the condition is true, otherwise throw an error.
|
| +// This is only to have a better contract semantic, i.e. another safety net
|
| +// to catch a logic error. The condition shall be fulfilled in normal case.
|
| +// Do NOT use this to enforce a certain condition on any user input.
|
| +
|
| +function assert(condition, message) {
|
| + if (!condition) {
|
| + throw new Error('ASSERT: ' + message);
|
| + }
|
| +}
|
| +
|
| +function isDecimalDigit(ch) {
|
| + return (ch >= 48 && ch <= 57); // 0..9
|
| +}
|
| +
|
| +
|
| +// 7.2 White Space
|
| +
|
| +function isWhiteSpace(ch) {
|
| + return (ch === 32) || // space
|
| + (ch === 9) || // tab
|
| + (ch === 0xB) ||
|
| + (ch === 0xC) ||
|
| + (ch === 0xA0) ||
|
| + (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0);
|
| +}
|
| +
|
| +// 7.3 Line Terminators
|
| +
|
| +function isLineTerminator(ch) {
|
| + return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029);
|
| +}
|
| +
|
| +// 7.6 Identifier Names and Identifiers
|
| +
|
| +function isIdentifierStart(ch) {
|
| + return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
|
| + (ch >= 65 && ch <= 90) || // A..Z
|
| + (ch >= 97 && ch <= 122); // a..z
|
| +}
|
| +
|
| +function isIdentifierPart(ch) {
|
| + return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
|
| + (ch >= 65 && ch <= 90) || // A..Z
|
| + (ch >= 97 && ch <= 122) || // a..z
|
| + (ch >= 48 && ch <= 57); // 0..9
|
| +}
|
| +
|
| +// 7.6.1.1 Keywords
|
| +
|
| +function isKeyword(id) {
|
| + return (id === 'this')
|
| +}
|
| +
|
| +// 7.4 Comments
|
| +
|
| +function skipWhitespace() {
|
| + while (index < length && isWhiteSpace(source.charCodeAt(index))) {
|
| + ++index;
|
| + }
|
| +}
|
| +
|
| +function getIdentifier() {
|
| + var start, ch;
|
| +
|
| + start = index++;
|
| + while (index < length) {
|
| + ch = source.charCodeAt(index);
|
| + if (isIdentifierPart(ch)) {
|
| + ++index;
|
| + } else {
|
| + break;
|
| + }
|
| + }
|
| +
|
| + return source.slice(start, index);
|
| +}
|
| +
|
| +function scanIdentifier() {
|
| + var start, id, type;
|
| +
|
| + start = index;
|
| +
|
| + id = getIdentifier();
|
| +
|
| + // There is no keyword or literal with only one character.
|
| + // Thus, it must be an identifier.
|
| + if (id.length === 1) {
|
| + type = Token.Identifier;
|
| + } else if (isKeyword(id)) {
|
| + type = Token.Keyword;
|
| + } else if (id === 'null') {
|
| + type = Token.NullLiteral;
|
| + } else if (id === 'true' || id === 'false') {
|
| + type = Token.BooleanLiteral;
|
| + } else {
|
| + type = Token.Identifier;
|
| + }
|
| +
|
| + return {
|
| + type: type,
|
| + value: id,
|
| + range: [start, index]
|
| + };
|
| +}
|
| +
|
| +
|
| +// 7.7 Punctuators
|
| +
|
| +function scanPunctuator() {
|
| + var start = index,
|
| + code = source.charCodeAt(index),
|
| + code2,
|
| + ch1 = source[index],
|
| + ch2;
|
| +
|
| + switch (code) {
|
| +
|
| + // Check for most common single-character punctuators.
|
| + case 46: // . dot
|
| + case 40: // ( open bracket
|
| + case 41: // ) close bracket
|
| + case 59: // ; semicolon
|
| + case 44: // , comma
|
| + case 123: // { open curly brace
|
| + case 125: // } close curly brace
|
| + case 91: // [
|
| + case 93: // ]
|
| + case 58: // :
|
| + case 63: // ?
|
| + ++index;
|
| + return {
|
| + type: Token.Punctuator,
|
| + value: String.fromCharCode(code),
|
| + range: [start, index]
|
| + };
|
| +
|
| + default:
|
| + code2 = source.charCodeAt(index + 1);
|
| +
|
| + // '=' (char #61) marks an assignment or comparison operator.
|
| + if (code2 === 61) {
|
| + switch (code) {
|
| + case 37: // %
|
| + case 38: // &
|
| + case 42: // *:
|
| + case 43: // +
|
| + case 45: // -
|
| + case 47: // /
|
| + case 60: // <
|
| + case 62: // >
|
| + case 124: // |
|
| + index += 2;
|
| + return {
|
| + type: Token.Punctuator,
|
| + value: String.fromCharCode(code) + String.fromCharCode(code2),
|
| + range: [start, index]
|
| + };
|
| +
|
| + case 33: // !
|
| + case 61: // =
|
| + index += 2;
|
| +
|
| + // !== and ===
|
| + if (source.charCodeAt(index) === 61) {
|
| + ++index;
|
| + }
|
| + return {
|
| + type: Token.Punctuator,
|
| + value: source.slice(start, index),
|
| + range: [start, index]
|
| + };
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| + break;
|
| + }
|
| +
|
| + // Peek more characters.
|
| +
|
| + ch2 = source[index + 1];
|
| +
|
| + // Other 2-character punctuators: && ||
|
| +
|
| + if (ch1 === ch2 && ('&|'.indexOf(ch1) >= 0)) {
|
| + index += 2;
|
| + return {
|
| + type: Token.Punctuator,
|
| + value: ch1 + ch2,
|
| + range: [start, index]
|
| + };
|
| + }
|
| +
|
| + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
|
| + ++index;
|
| + return {
|
| + type: Token.Punctuator,
|
| + value: ch1,
|
| + range: [start, index]
|
| + };
|
| + }
|
| +
|
| + throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
|
| +}
|
| +
|
| +// 7.8.3 Numeric Literals
|
| +function scanNumericLiteral() {
|
| + var number, start, ch;
|
| +
|
| + ch = source[index];
|
| + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
|
| + 'Numeric literal must start with a decimal digit or a decimal point');
|
| +
|
| + start = index;
|
| + number = '';
|
| + if (ch !== '.') {
|
| + number = source[index++];
|
| + ch = source[index];
|
| +
|
| + // Hex number starts with '0x'.
|
| + // Octal number starts with '0'.
|
| + if (number === '0') {
|
| + // decimal number starts with '0' such as '09' is illegal.
|
| + if (ch && isDecimalDigit(ch.charCodeAt(0))) {
|
| + throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
|
| + }
|
| + }
|
| +
|
| + while (isDecimalDigit(source.charCodeAt(index))) {
|
| + number += source[index++];
|
| + }
|
| + ch = source[index];
|
| + }
|
| +
|
| + if (ch === '.') {
|
| + number += source[index++];
|
| + while (isDecimalDigit(source.charCodeAt(index))) {
|
| + number += source[index++];
|
| + }
|
| + ch = source[index];
|
| + }
|
| +
|
| + if (ch === 'e' || ch === 'E') {
|
| + number += source[index++];
|
| +
|
| + ch = source[index];
|
| + if (ch === '+' || ch === '-') {
|
| + number += source[index++];
|
| + }
|
| + if (isDecimalDigit(source.charCodeAt(index))) {
|
| + while (isDecimalDigit(source.charCodeAt(index))) {
|
| + number += source[index++];
|
| + }
|
| + } else {
|
| + throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
|
| + }
|
| + }
|
| +
|
| + if (isIdentifierStart(source.charCodeAt(index))) {
|
| + throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
|
| + }
|
| +
|
| + return {
|
| + type: Token.NumericLiteral,
|
| + value: parseFloat(number),
|
| + range: [start, index]
|
| + };
|
| +}
|
| +
|
| +// 7.8.4 String Literals
|
| +
|
| +function scanStringLiteral() {
|
| + var str = '', quote, start, ch, octal = false;
|
| +
|
| + quote = source[index];
|
| + assert((quote === '\'' || quote === '"'),
|
| + 'String literal must starts with a quote');
|
| +
|
| + start = index;
|
| + ++index;
|
| +
|
| + while (index < length) {
|
| + ch = source[index++];
|
| +
|
| + if (ch === quote) {
|
| + quote = '';
|
| + break;
|
| + } else if (ch === '\\') {
|
| + ch = source[index++];
|
| + if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
|
| + switch (ch) {
|
| + case 'n':
|
| + str += '\n';
|
| + break;
|
| + case 'r':
|
| + str += '\r';
|
| + break;
|
| + case 't':
|
| + str += '\t';
|
| + break;
|
| + case 'b':
|
| + str += '\b';
|
| + break;
|
| + case 'f':
|
| + str += '\f';
|
| + break;
|
| + case 'v':
|
| + str += '\x0B';
|
| + break;
|
| +
|
| + default:
|
| + str += ch;
|
| + break;
|
| + }
|
| + } else {
|
| + if (ch === '\r' && source[index] === '\n') {
|
| + ++index;
|
| + }
|
| + }
|
| + } else if (isLineTerminator(ch.charCodeAt(0))) {
|
| + break;
|
| + } else {
|
| + str += ch;
|
| + }
|
| + }
|
| +
|
| + if (quote !== '') {
|
| + throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
|
| + }
|
| +
|
| + return {
|
| + type: Token.StringLiteral,
|
| + value: str,
|
| + octal: octal,
|
| + range: [start, index]
|
| + };
|
| +}
|
| +
|
| +function isIdentifierName(token) {
|
| + return token.type === Token.Identifier ||
|
| + token.type === Token.Keyword ||
|
| + token.type === Token.BooleanLiteral ||
|
| + token.type === Token.NullLiteral;
|
| +}
|
| +
|
| +function advance() {
|
| + var ch;
|
| +
|
| + skipWhitespace();
|
| +
|
| + if (index >= length) {
|
| + return {
|
| + type: Token.EOF,
|
| + range: [index, index]
|
| + };
|
| + }
|
| +
|
| + ch = source.charCodeAt(index);
|
| +
|
| + // Very common: ( and ) and ;
|
| + if (ch === 40 || ch === 41 || ch === 58) {
|
| + return scanPunctuator();
|
| + }
|
| +
|
| + // String literal starts with single quote (#39) or double quote (#34).
|
| + if (ch === 39 || ch === 34) {
|
| + return scanStringLiteral();
|
| + }
|
| +
|
| + if (isIdentifierStart(ch)) {
|
| + return scanIdentifier();
|
| + }
|
| +
|
| + // Dot (.) char #46 can also start a floating-point number, hence the need
|
| + // to check the next character.
|
| + if (ch === 46) {
|
| + if (isDecimalDigit(source.charCodeAt(index + 1))) {
|
| + return scanNumericLiteral();
|
| + }
|
| + return scanPunctuator();
|
| + }
|
| +
|
| + if (isDecimalDigit(ch)) {
|
| + return scanNumericLiteral();
|
| + }
|
| +
|
| + return scanPunctuator();
|
| +}
|
| +
|
| +function lex() {
|
| + var token;
|
| +
|
| + token = lookahead;
|
| + index = token.range[1];
|
| +
|
| + lookahead = advance();
|
| +
|
| + index = token.range[1];
|
| +
|
| + return token;
|
| +}
|
| +
|
| +function peek() {
|
| + var pos;
|
| +
|
| + pos = index;
|
| + lookahead = advance();
|
| + index = pos;
|
| +}
|
| +
|
| +// Throw an exception
|
| +
|
| +function throwError(token, messageFormat) {
|
| + var error,
|
| + args = Array.prototype.slice.call(arguments, 2),
|
| + msg = messageFormat.replace(
|
| + /%(\d)/g,
|
| + function (whole, index) {
|
| + assert(index < args.length, 'Message reference must be in range');
|
| + return args[index];
|
| + }
|
| + );
|
| +
|
| + error = new Error(msg);
|
| + error.index = index;
|
| + error.description = msg;
|
| + throw error;
|
| +}
|
| +
|
| +// Throw an exception because of the token.
|
| +
|
| +function throwUnexpected(token) {
|
| + throwError(token, Messages.UnexpectedToken, token.value);
|
| +}
|
| +
|
| +// Expect the next token to match the specified punctuator.
|
| +// If not, an exception will be thrown.
|
| +
|
| +function expect(value) {
|
| + var token = lex();
|
| + if (token.type !== Token.Punctuator || token.value !== value) {
|
| + throwUnexpected(token);
|
| + }
|
| +}
|
| +
|
| +// Return true if the next token matches the specified punctuator.
|
| +
|
| +function match(value) {
|
| + return lookahead.type === Token.Punctuator && lookahead.value === value;
|
| +}
|
| +
|
| +// Return true if the next token matches the specified keyword
|
| +
|
| +function matchKeyword(keyword) {
|
| + return lookahead.type === Token.Keyword && lookahead.value === keyword;
|
| +}
|
| +
|
| +function consumeSemicolon() {
|
| + // Catch the very common case first: immediately a semicolon (char #59).
|
| + if (source.charCodeAt(index) === 59) {
|
| + lex();
|
| + return;
|
| + }
|
| +
|
| + skipWhitespace();
|
| +
|
| + if (match(';')) {
|
| + lex();
|
| + return;
|
| + }
|
| +
|
| + if (lookahead.type !== Token.EOF && !match('}')) {
|
| + throwUnexpected(lookahead);
|
| + }
|
| +}
|
| +
|
| +// 11.1.4 Array Initialiser
|
| +
|
| +function parseArrayInitialiser() {
|
| + var elements = [];
|
| +
|
| + expect('[');
|
| +
|
| + while (!match(']')) {
|
| + if (match(',')) {
|
| + lex();
|
| + elements.push(null);
|
| + } else {
|
| + elements.push(parseExpression());
|
| +
|
| + if (!match(']')) {
|
| + expect(',');
|
| + }
|
| + }
|
| + }
|
| +
|
| + expect(']');
|
| +
|
| + return delegate.createArrayExpression(elements);
|
| +}
|
| +
|
| +// 11.1.5 Object Initialiser
|
| +
|
| +function parseObjectPropertyKey() {
|
| + var token;
|
| +
|
| + skipWhitespace();
|
| + token = lex();
|
| +
|
| + // Note: This function is called only from parseObjectProperty(), where
|
| + // EOF and Punctuator tokens are already filtered out.
|
| + if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
|
| + return delegate.createLiteral(token);
|
| + }
|
| +
|
| + return delegate.createIdentifier(token.value);
|
| +}
|
| +
|
| +function parseObjectProperty() {
|
| + var token, key;
|
| +
|
| + token = lookahead;
|
| + skipWhitespace();
|
| +
|
| + if (token.type === Token.EOF || token.type === Token.Punctuator) {
|
| + throwUnexpected(token);
|
| + }
|
| +
|
| + key = parseObjectPropertyKey();
|
| + expect(':');
|
| + return delegate.createProperty('init', key, parseExpression());
|
| +}
|
| +
|
| +function parseObjectInitialiser() {
|
| + var properties = [];
|
| +
|
| + expect('{');
|
| +
|
| + while (!match('}')) {
|
| + properties.push(parseObjectProperty());
|
| +
|
| + if (!match('}')) {
|
| + expect(',');
|
| + }
|
| + }
|
| +
|
| + expect('}');
|
| +
|
| + return delegate.createObjectExpression(properties);
|
| +}
|
| +
|
| +// 11.1.6 The Grouping Operator
|
| +
|
| +function parseGroupExpression() {
|
| + var expr;
|
| +
|
| + expect('(');
|
| +
|
| + expr = parseExpression();
|
| +
|
| + expect(')');
|
| +
|
| + return expr;
|
| +}
|
| +
|
| +
|
| +// 11.1 Primary Expressions
|
| +
|
| +function parsePrimaryExpression() {
|
| + var type, token, expr;
|
| +
|
| + if (match('(')) {
|
| + return parseGroupExpression();
|
| + }
|
| +
|
| + type = lookahead.type;
|
| +
|
| + if (type === Token.Identifier) {
|
| + expr = delegate.createIdentifier(lex().value);
|
| + } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
|
| + expr = delegate.createLiteral(lex());
|
| + } else if (type === Token.Keyword) {
|
| + if (matchKeyword('this')) {
|
| + lex();
|
| + expr = delegate.createThisExpression();
|
| + }
|
| + } else if (type === Token.BooleanLiteral) {
|
| + token = lex();
|
| + token.value = (token.value === 'true');
|
| + expr = delegate.createLiteral(token);
|
| + } else if (type === Token.NullLiteral) {
|
| + token = lex();
|
| + token.value = null;
|
| + expr = delegate.createLiteral(token);
|
| + } else if (match('[')) {
|
| + expr = parseArrayInitialiser();
|
| + } else if (match('{')) {
|
| + expr = parseObjectInitialiser();
|
| + }
|
| +
|
| + if (expr) {
|
| + return expr;
|
| + }
|
| +
|
| + throwUnexpected(lex());
|
| +}
|
| +
|
| +// 11.2 Left-Hand-Side Expressions
|
| +
|
| +function parseArguments() {
|
| + var args = [];
|
| +
|
| + expect('(');
|
| +
|
| + if (!match(')')) {
|
| + while (index < length) {
|
| + args.push(parseExpression());
|
| + if (match(')')) {
|
| + break;
|
| + }
|
| + expect(',');
|
| + }
|
| + }
|
| +
|
| + expect(')');
|
| +
|
| + return args;
|
| +}
|
| +
|
| +function parseNonComputedProperty() {
|
| + var token;
|
| +
|
| + token = lex();
|
| +
|
| + if (!isIdentifierName(token)) {
|
| + throwUnexpected(token);
|
| + }
|
| +
|
| + return delegate.createIdentifier(token.value);
|
| +}
|
| +
|
| +function parseNonComputedMember() {
|
| + expect('.');
|
| +
|
| + return parseNonComputedProperty();
|
| +}
|
| +
|
| +function parseComputedMember() {
|
| + var expr;
|
| +
|
| + expect('[');
|
| +
|
| + expr = parseExpression();
|
| +
|
| + expect(']');
|
| +
|
| + return expr;
|
| +}
|
| +
|
| +function parseLeftHandSideExpression() {
|
| + var expr, args, property;
|
| +
|
| + expr = parsePrimaryExpression();
|
| +
|
| + while (true) {
|
| + if (match('[')) {
|
| + property = parseComputedMember();
|
| + expr = delegate.createMemberExpression('[', expr, property);
|
| + } else if (match('.')) {
|
| + property = parseNonComputedMember();
|
| + expr = delegate.createMemberExpression('.', expr, property);
|
| + } else if (match('(')) {
|
| + args = parseArguments();
|
| + expr = delegate.createCallExpression(expr, args);
|
| + } else {
|
| + break;
|
| + }
|
| + }
|
| +
|
| + return expr;
|
| +}
|
| +
|
| +// 11.3 Postfix Expressions
|
| +
|
| +var parsePostfixExpression = parseLeftHandSideExpression;
|
| +
|
| +// 11.4 Unary Operators
|
| +
|
| +function parseUnaryExpression() {
|
| + var token, expr;
|
| +
|
| + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
|
| + expr = parsePostfixExpression();
|
| + } else if (match('+') || match('-') || match('!')) {
|
| + token = lex();
|
| + expr = parseUnaryExpression();
|
| + expr = delegate.createUnaryExpression(token.value, expr);
|
| + } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
|
| + throwError({}, Messages.UnexpectedToken);
|
| + } else {
|
| + expr = parsePostfixExpression();
|
| + }
|
| +
|
| + return expr;
|
| +}
|
| +
|
| +function binaryPrecedence(token) {
|
| + var prec = 0;
|
| +
|
| + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
|
| + return 0;
|
| + }
|
| +
|
| + switch (token.value) {
|
| + case '||':
|
| + prec = 1;
|
| + break;
|
| +
|
| + case '&&':
|
| + prec = 2;
|
| + break;
|
| +
|
| + case '==':
|
| + case '!=':
|
| + case '===':
|
| + case '!==':
|
| + prec = 6;
|
| + break;
|
| +
|
| + case '<':
|
| + case '>':
|
| + case '<=':
|
| + case '>=':
|
| + case 'instanceof':
|
| + prec = 7;
|
| + break;
|
| +
|
| + case 'in':
|
| + prec = 7;
|
| + break;
|
| +
|
| + case '+':
|
| + case '-':
|
| + prec = 9;
|
| + break;
|
| +
|
| + case '*':
|
| + case '/':
|
| + case '%':
|
| + prec = 11;
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return prec;
|
| +}
|
| +
|
| +// 11.5 Multiplicative Operators
|
| +// 11.6 Additive Operators
|
| +// 11.7 Bitwise Shift Operators
|
| +// 11.8 Relational Operators
|
| +// 11.9 Equality Operators
|
| +// 11.10 Binary Bitwise Operators
|
| +// 11.11 Binary Logical Operators
|
| +
|
| +function parseBinaryExpression() {
|
| + var expr, token, prec, stack, right, operator, left, i;
|
| +
|
| + left = parseUnaryExpression();
|
| +
|
| + token = lookahead;
|
| + prec = binaryPrecedence(token);
|
| + if (prec === 0) {
|
| + return left;
|
| + }
|
| + token.prec = prec;
|
| + lex();
|
| +
|
| + right = parseUnaryExpression();
|
| +
|
| + stack = [left, token, right];
|
| +
|
| + while ((prec = binaryPrecedence(lookahead)) > 0) {
|
| +
|
| + // Reduce: make a binary expression from the three topmost entries.
|
| + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
|
| + right = stack.pop();
|
| + operator = stack.pop().value;
|
| + left = stack.pop();
|
| + expr = delegate.createBinaryExpression(operator, left, right);
|
| + stack.push(expr);
|
| + }
|
| +
|
| + // Shift.
|
| + token = lex();
|
| + token.prec = prec;
|
| + stack.push(token);
|
| + expr = parseUnaryExpression();
|
| + stack.push(expr);
|
| + }
|
| +
|
| + // Final reduce to clean-up the stack.
|
| + i = stack.length - 1;
|
| + expr = stack[i];
|
| + while (i > 1) {
|
| + expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
|
| + i -= 2;
|
| + }
|
| +
|
| + return expr;
|
| +}
|
| +
|
| +
|
| +// 11.12 Conditional Operator
|
| +
|
| +function parseConditionalExpression() {
|
| + var expr, consequent, alternate;
|
| +
|
| + expr = parseBinaryExpression();
|
| +
|
| + if (match('?')) {
|
| + lex();
|
| + consequent = parseConditionalExpression();
|
| + expect(':');
|
| + alternate = parseConditionalExpression();
|
| +
|
| + expr = delegate.createConditionalExpression(expr, consequent, alternate);
|
| + }
|
| +
|
| + return expr;
|
| +}
|
| +
|
| +// Simplification since we do not support AssignmentExpression.
|
| +var parseExpression = parseConditionalExpression;
|
| +
|
| +// Polymer Syntax extensions
|
| +
|
| +// Filter ::
|
| +// Identifier
|
| +// Identifier "(" ")"
|
| +// Identifier "(" FilterArguments ")"
|
| +
|
| +function parseFilter() {
|
| + var identifier, args;
|
| +
|
| + identifier = lex();
|
| +
|
| + if (identifier.type !== Token.Identifier) {
|
| + throwUnexpected(identifier);
|
| + }
|
| +
|
| + args = match('(') ? parseArguments() : [];
|
| +
|
| + return delegate.createFilter(identifier.value, args);
|
| +}
|
| +
|
| +// Filters ::
|
| +// "|" Filter
|
| +// Filters "|" Filter
|
| +
|
| +function parseFilters() {
|
| + while (match('|')) {
|
| + lex();
|
| + parseFilter();
|
| + }
|
| +}
|
| +
|
| +// TopLevel ::
|
| +// LabelledExpressions
|
| +// AsExpression
|
| +// InExpression
|
| +// FilterExpression
|
| +
|
| +// AsExpression ::
|
| +// FilterExpression as Identifier
|
| +
|
| +// InExpression ::
|
| +// Identifier, Identifier in FilterExpression
|
| +// Identifier in FilterExpression
|
| +
|
| +// FilterExpression ::
|
| +// Expression
|
| +// Expression Filters
|
| +
|
| +function parseTopLevel() {
|
| + skipWhitespace();
|
| + peek();
|
| +
|
| + var expr = parseExpression();
|
| + if (expr) {
|
| + if (lookahead.value === ',' || lookahead.value == 'in' &&
|
| + expr.type === Syntax.Identifier) {
|
| + parseInExpression(expr);
|
| + } else {
|
| + parseFilters();
|
| + if (lookahead.value === 'as') {
|
| + parseAsExpression(expr);
|
| + } else {
|
| + delegate.createTopLevel(expr);
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (lookahead.type !== Token.EOF) {
|
| + throwUnexpected(lookahead);
|
| + }
|
| +}
|
| +
|
| +function parseAsExpression(expr) {
|
| + lex(); // as
|
| + var identifier = lex().value;
|
| + delegate.createAsExpression(expr, identifier);
|
| +}
|
| +
|
| +function parseInExpression(identifier) {
|
| + var indexName;
|
| + if (lookahead.value === ',') {
|
| + lex();
|
| + if (lookahead.type !== Token.Identifier)
|
| + throwUnexpected(lookahead);
|
| + indexName = lex().value;
|
| + }
|
| +
|
| + lex(); // in
|
| + var expr = parseExpression();
|
| + parseFilters();
|
| + delegate.createInExpression(identifier.name, indexName, expr);
|
| +}
|
| +
|
| +function parse(code, inDelegate) {
|
| + delegate = inDelegate;
|
| + source = code;
|
| + index = 0;
|
| + length = source.length;
|
| + lookahead = null;
|
| + state = {
|
| + labelSet: {}
|
| + };
|
| +
|
| + return parseTopLevel();
|
| +}
|
| +
|
| +module.exports = {
|
| + parse: parse
|
| +};
|
| +
|
| +</script>
|
|
|