Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 50831c28d2569abd5fd758b51111e7fbe03cdeda 0 parents
@Constellation Constellation authored
Showing with 104,425 additions and 0 deletions.
  1. +19 −0 LICENSE.BSD
  2. +66 −0 README.md
  3. +843 −0 escodegen.js
  4. +29 −0 package.json
  5. +646 −0 test/3rdparty/Tokenizer.js
  6. +509 −0 test/3rdparty/XMLHttpRequest.js
  7. +2,185 −0 test/3rdparty/ZeParser.js
  8. +1,158 −0 test/3rdparty/backbone-0.5.3.js
  9. +3,261 −0 test/3rdparty/benchmark.js
  10. +4,336 −0 test/3rdparty/esprima.js
  11. +6,579 −0 test/3rdparty/ext-core-3.0.0.js
  12. +10,255 −0 test/3rdparty/ext-core-3.1.0.js
  13. +9,046 −0 test/3rdparty/jquery-1.6.4.js
  14. +9,266 −0 test/3rdparty/jquery-1.7.1.js
  15. +6,951 −0 test/3rdparty/jquery.mobile-1.0.js
  16. +731 −0 test/3rdparty/jsdefs.js
  17. +588 −0 test/3rdparty/jslex.js
  18. +1,921 −0 test/3rdparty/jsparse.js
  19. +5,952 −0 test/3rdparty/mootools-1.3.2.js
  20. +6,297 −0 test/3rdparty/mootools-1.4.1.js
  21. +1,342 −0 test/3rdparty/parse-js.js
  22. +891 −0 test/3rdparty/platform.js
  23. +4,874 −0 test/3rdparty/prototype-1.6.1.js
  24. +6,082 −0 test/3rdparty/prototype-1.7.0.0.js
  25. +981 −0 test/3rdparty/underscore-1.2.3.js
  26. +132 −0 test/identity.js
  27. +66 −0 test/run.js
  28. +19,419 −0 test/test.js
19 LICENSE.BSD
@@ -0,0 +1,19 @@
+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.
66 README.md
@@ -0,0 +1,66 @@
+Esprima ([esprima.org](http://esprima.org)) is an educational
+[ECMAScript](http://www.ecma-international.org/publications/standards/Ecma-262.htm)
+(also popularly known as [JavaScript](http://en.wikipedia.org/wiki/JavaScript>JavaScript))
+parsing infrastructure for multipurpose analysis. It is also written in ECMAScript.
+
+Esprima can be used in a web browser:
+
+ <script src="esprima.js"></script>
+
+or in a Node.js application via the package manager:
+
+ npm install esprima
+
+Esprima parser output is compatible with Mozilla (SpiderMonkey)
+[Parser API](https://developer.mozilla.org/en/SpiderMonkey/Parser_API).
+
+A very simple example:
+
+ esprima.parse('var answer=42').body[0].declarations[0].init
+
+produces the following object:
+
+ { type: 'Literal', value: 42 }
+
+Esprima is still in the development, for now please check
+[the wiki documentation](http://wiki.esprima.org).
+
+Since it is not comprehensive nor complete, refer to the
+[issue tracker](http://issues.esprima.org) for
+[known problems](http://code.google.com/p/esprima/issues/list?q=Defect)
+and [future plans](http://code.google.com/p/esprima/issues/list?q=Enhancement).
+Esprima is supported on [many browsers](http://code.google.com/p/esprima/wiki/BrowserCompatibility):
+IE 6+, Firefox 1+, Safari 3+, Chrome 1+, and Opera 8+.
+
+Feedback and contribution are welcomed! Please join the
+[mailing list](http://groups.google.com/group/esprima) and read the
+[contribution guide](http://code.google.com/p/esprima/wiki/ContributionGuide)
+for further info.
+
+
+### License
+
+Copyright (C) 2012, 2011 [Ariya Hidayat](http://ariya.ofilabs.com/about)
+ (twitter: [@ariyahidayat](http://twitter.com/ariyahidayat)) and other contributors.
+
+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.
+
843 escodegen.js
@@ -0,0 +1,843 @@
+/*
+ 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.
+*/
+
+/*jslint bitwise:true */
+/*global escodegen:true, exports:true, generateStatement: true*/
+
+(function (exports) {
+ 'use strict';
+
+ var Syntax,
+ Precedence,
+ BinaryPrecedence,
+ base,
+ indent,
+ extra,
+ parse;
+
+ Syntax = {
+ AssignmentExpression: 'AssignmentExpression',
+ ArrayExpression: 'ArrayExpression',
+ BlockStatement: 'BlockStatement',
+ BinaryExpression: 'BinaryExpression',
+ BreakStatement: 'BreakStatement',
+ CallExpression: 'CallExpression',
+ CatchClause: 'CatchClause',
+ ConditionalExpression: 'ConditionalExpression',
+ ContinueStatement: 'ContinueStatement',
+ DoWhileStatement: 'DoWhileStatement',
+ DebuggerStatement: 'DebuggerStatement',
+ EmptyStatement: 'EmptyStatement',
+ ExpressionStatement: 'ExpressionStatement',
+ ForStatement: 'ForStatement',
+ ForInStatement: 'ForInStatement',
+ FunctionDeclaration: 'FunctionDeclaration',
+ FunctionExpression: 'FunctionExpression',
+ Identifier: 'Identifier',
+ IfStatement: 'IfStatement',
+ Literal: 'Literal',
+ LabeledStatement: 'LabeledStatement',
+ LogicalExpression: 'LogicalExpression',
+ MemberExpression: 'MemberExpression',
+ NewExpression: 'NewExpression',
+ ObjectExpression: 'ObjectExpression',
+ Program: 'Program',
+ Property: 'Property',
+ ReturnStatement: 'ReturnStatement',
+ SequenceExpression: 'SequenceExpression',
+ SwitchStatement: 'SwitchStatement',
+ SwitchCase: 'SwitchCase',
+ ThisExpression: 'ThisExpression',
+ ThrowStatement: 'ThrowStatement',
+ TryStatement: 'TryStatement',
+ UnaryExpression: 'UnaryExpression',
+ UpdateExpression: 'UpdateExpression',
+ VariableDeclaration: 'VariableDeclaration',
+ VariableDeclarator: 'VariableDeclarator',
+ WhileStatement: 'WhileStatement',
+ WithStatement: 'WithStatement'
+ };
+
+ Precedence = {
+ Sequence: 0,
+ Assignment: 1,
+ Conditional: 2,
+ LogicalOR: 3,
+ LogicalAND: 4,
+ LogicalXOR: 5,
+ BitwiseOR: 6,
+ BitwiseAND: 7,
+ Equality: 8,
+ Relational: 9,
+ BitwiseSHIFT: 10,
+ Additive: 11,
+ Multiplicative: 12,
+ Unary: 13,
+ Postfix: 14,
+ Call: 15,
+ New: 16,
+ Member: 17,
+ Primary: 18
+ };
+
+ BinaryPrecedence = {
+ '||': Precedence.LogicalOR,
+ '&&': Precedence.LogicalAND,
+ '^': Precedence.LogicalXOR,
+ '|': Precedence.BitwiseOR,
+ '&': Precedence.BitwiseAND,
+ '==': Precedence.Equality,
+ '!=': Precedence.Equality,
+ '===': Precedence.Equality,
+ '!==': Precedence.Equality,
+ '<': Precedence.Relational,
+ '>': Precedence.Relational,
+ '<=': Precedence.Relational,
+ '>=': Precedence.Relational,
+ 'in': Precedence.Relational,
+ 'instanceof': Precedence.Relational,
+ '<<': Precedence.BitwiseSHIFT,
+ '>>': Precedence.BitwiseSHIFT,
+ '>>>': Precedence.BitwiseSHIFT,
+ '+': Precedence.Additive,
+ '-': Precedence.Additive,
+ '*': Precedence.Multiplicative,
+ '%': Precedence.Multiplicative,
+ '/': Precedence.Multiplicative
+ };
+
+ if (typeof Object.freeze === 'function') {
+ Object.freeze(Syntax);
+ Object.freeze(Precedence);
+ Object.freeze(BinaryPrecedence);
+ }
+
+ function unicodeEscape(ch) {
+ var result, i;
+ result = ch.charCodeAt(0).toString(16);
+ for (i = result.length; i < 4; i += 1) {
+ result = '0' + result;
+ }
+ return '\\u' + result;
+ }
+
+ function stringToArray(str) {
+ var length = str.length,
+ result = [],
+ i;
+ for (i = 0; i < length; i += 1) {
+ result[i] = str.charAt(i);
+ }
+ return result;
+ }
+
+ function escapeString(str) {
+ var result = '', i, len, ch;
+
+ if (typeof str[0] === 'undefined') {
+ str = stringToArray(str);
+ }
+
+ for (i = 0, len = str.length; i < len; i += 1) {
+ ch = str[i];
+ if ('\'\\\b\f\n\r\t'.indexOf(ch) >= 0) {
+ result += '\\';
+ switch (ch) {
+ case '\'':
+ result += '\'';
+ break;
+ case '\\':
+ result += '\\';
+ break;
+ case '\b':
+ result += 'b';
+ break;
+ case '\f':
+ result += 'f';
+ break;
+ case '\n':
+ result += 'n';
+ break;
+ case '\r':
+ result += 'r';
+ break;
+ case '\t':
+ result += 't';
+ break;
+ }
+ } else if (ch < ' ' || ch.charCodeAt(0) >= 0x80) {
+ result += unicodeEscape(ch);
+ } else {
+ result += ch;
+ }
+ }
+
+ return '\'' + result + '\'';
+ }
+
+ function addIndent(stmt) {
+ return base + stmt;
+ }
+
+ function parenthesize(text, current, should) {
+ return (current < should) ? '(' + text + ')' : text;
+ }
+
+ function maybeBlock(stmt, suffix) {
+ var previousBase, result;
+
+ if (stmt.type === Syntax.BlockStatement) {
+ result = ' ' + generateStatement(stmt);
+ if (suffix) {
+ return result + ' ';
+ }
+ return result;
+ }
+
+ if (stmt.type === Syntax.EmptyStatement) {
+ result = ';';
+ } else {
+ previousBase = base;
+ base += indent;
+ result = '\n' + addIndent(generateStatement(stmt));
+ base = previousBase;
+ }
+
+ if (suffix) {
+ return result + '\n' + addIndent('');
+ }
+ return result;
+ }
+
+ function generateFunctionBody(node) {
+ var result, i, len;
+ result = '(';
+ for (i = 0, len = node.params.length; i < len; i += 1) {
+ result += node.params[i].name;
+ if ((i + 1) < len) {
+ result += ', ';
+ }
+ }
+ return result + ')' + maybeBlock(node.body);
+ }
+
+ function generateExpression(expr, precedence) {
+ var result, currentPrecedence, previousBase, i, len, raw;
+
+ if (!precedence) {
+ precedence = Precedence.Sequence;
+ }
+
+ switch (expr.type) {
+ case Syntax.SequenceExpression:
+ result = '';
+ for (i = 0, len = expr.expressions.length; i < len; i += 1) {
+ result += generateExpression(expr.expressions[i], Precedence.Assignment);
+ if ((i + 1) < len) {
+ result += ', ';
+ }
+ }
+ result = parenthesize(result, Precedence.Sequence, precedence);
+ break;
+
+ case Syntax.AssignmentExpression:
+ result = parenthesize(
+ generateExpression(expr.left) + ' ' + expr.operator + ' ' +
+ generateExpression(expr.right, Precedence.Assignment),
+ Precedence.Assignment,
+ precedence
+ );
+ break;
+
+ case Syntax.ConditionalExpression:
+ result = parenthesize(
+ generateExpression(expr.test, Precedence.LogicalOR) + ' ? ' +
+ generateExpression(expr.consequent, Precedence.Assignment) + ' : ' +
+ generateExpression(expr.alternate, Precedence.Assignment),
+ Precedence.Conditional,
+ precedence
+ );
+ break;
+
+ case Syntax.LogicalExpression:
+ case Syntax.BinaryExpression:
+ currentPrecedence = BinaryPrecedence[expr.operator];
+
+ result = generateExpression(expr.left, currentPrecedence) +
+ ' ' + expr.operator + ' ' +
+ generateExpression(expr.right, currentPrecedence + 1);
+ if (expr.operator === 'in') {
+ // TODO parenthesize only in allowIn = false case
+ result = '(' + result + ')';
+ } else {
+ result = parenthesize(result, currentPrecedence, precedence);
+ }
+ break;
+
+ case Syntax.CallExpression:
+ result = '';
+ for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
+ result += generateExpression(expr['arguments'][i], Precedence.Assignment);
+ if ((i + 1) < len) {
+ result += ', ';
+ }
+ }
+ result = parenthesize(
+ generateExpression(expr.callee, Precedence.Call) + '(' + result + ')',
+ Precedence.Call,
+ precedence
+ );
+ break;
+
+ case Syntax.NewExpression:
+ result = '';
+ for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
+ result += generateExpression(expr['arguments'][i], Precedence.Assignment);
+ if ((i + 1) < len) {
+ result += ', ';
+ }
+ }
+ result = parenthesize(
+ 'new ' + generateExpression(expr.callee, Precedence.New) + '(' + result + ')',
+ Precedence.New,
+ precedence
+ );
+ break;
+
+ case Syntax.MemberExpression:
+ result = generateExpression(expr.object, Precedence.Call);
+ if (expr.computed) {
+ result += '[' + generateExpression(expr.property) + ']';
+ } else {
+ if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
+ if (result.indexOf('.') < 0) {
+ if (!/[eExX]/.test(result) && !(result.length >= 2 && result[0] === '0')) {
+ result += '.';
+ }
+ }
+ }
+ result += '.' + expr.property.name;
+ }
+ result = parenthesize(result, Precedence.Member, precedence);
+ break;
+
+ case Syntax.UnaryExpression:
+ result = expr.operator;
+ if (result.length > 2) {
+ result += ' ';
+ }
+ result = parenthesize(
+ result + generateExpression(expr.argument, Precedence.Unary +
+ (
+ expr.argument.type === Syntax.UnaryExpression &&
+ expr.operator.length < 3 &&
+ expr.argument.operator === expr.operator ? 1 : 0
+ )
+ ),
+ Precedence.Unary,
+ precedence
+ );
+ break;
+
+ case Syntax.UpdateExpression:
+ if (expr.prefix) {
+ result = parenthesize(
+ expr.operator +
+ generateExpression(expr.argument, Precedence.Unary),
+ Precedence.Unary,
+ precedence
+ );
+ } else {
+ result = parenthesize(
+ generateExpression(expr.argument, Precedence.Postfix) +
+ expr.operator,
+ Precedence.Postfix,
+ precedence
+ );
+ }
+ break;
+
+ case Syntax.FunctionExpression:
+ result = 'function ';
+ if (expr.id) {
+ result += expr.id.name;
+ }
+ result += generateFunctionBody(expr);
+ break;
+
+ case Syntax.ArrayExpression:
+ if (!expr.elements.length) {
+ result = '[]';
+ break;
+ }
+ result = '[\n';
+ previousBase = base;
+ base += indent;
+ for (i = 0, len = expr.elements.length; i < len; i += 1) {
+ if (!expr.elements[i]) {
+ result += addIndent('');
+ if ((i + 1) === len) {
+ result += ',';
+ }
+ } else {
+ result += addIndent(generateExpression(expr.elements[i], Precedence.Assignment));
+ }
+ if ((i + 1) < len) {
+ result += ',\n';
+ }
+ }
+ base = previousBase;
+ result += '\n' + addIndent(']');
+ break;
+
+ case Syntax.Property:
+ if (expr.kind === 'get' || expr.kind === 'set') {
+ result = expr.kind + ' ' + generateExpression(expr.key) +
+ generateFunctionBody(expr.value);
+ } else {
+ result = generateExpression(expr.key) + ': ' +
+ generateExpression(expr.value, Precedence.Assignment);
+ }
+ break;
+
+ case Syntax.ObjectExpression:
+ if (!expr.properties.length) {
+ result = '{}';
+ break;
+ }
+ result = '{\n';
+ previousBase = base;
+ base += indent;
+ for (i = 0, len = expr.properties.length; i < len; i += 1) {
+ result += addIndent(generateExpression(expr.properties[i]));
+ if ((i + 1) < len) {
+ result += ',\n';
+ }
+ }
+ base = previousBase;
+ result += '\n' + addIndent('}');
+ break;
+
+ case Syntax.ThisExpression:
+ result = 'this';
+ break;
+
+ case Syntax.Identifier:
+ result = expr.name;
+ break;
+
+ case Syntax.Literal:
+ if (expr.hasOwnProperty('raw') && parse) {
+ try {
+ raw = parse(expr.raw).body[0].expression;
+ if (raw.type === Syntax.Literal) {
+ if (raw.value === expr.value) {
+ result = expr.raw;
+ break;
+ }
+ }
+ } catch (e) {
+ // not use raw property
+ }
+ }
+
+ if (expr.value === null) {
+ result = 'null';
+ break;
+ }
+
+ if (typeof expr.value === 'string') {
+ result = escapeString(expr.value);
+ break;
+ }
+
+ if (typeof expr.value === 'number' && expr.value === Infinity) {
+ // Infinity is variable
+ result = '1e+1000';
+ break;
+ }
+
+ result = expr.value.toString();
+ break;
+
+ default:
+ break;
+ }
+
+ if (result === undefined) {
+ throw new Error('Unknown expression type: ' + expr.type);
+ }
+ return result;
+ }
+
+ function generateStatement(stmt) {
+ var i, len, result, previousBase;
+
+ switch (stmt.type) {
+ case Syntax.BlockStatement:
+ result = '{\n';
+
+ previousBase = base;
+ base += indent;
+ for (i = 0, len = stmt.body.length; i < len; i += 1) {
+ result += addIndent(generateStatement(stmt.body[i])) + '\n';
+ }
+ base = previousBase;
+
+ result += addIndent('}');
+ break;
+
+ case Syntax.BreakStatement:
+ if (stmt.label) {
+ result = 'break ' + stmt.label.name + ';';
+ } else {
+ result = 'break;';
+ }
+ break;
+
+ case Syntax.ContinueStatement:
+ if (stmt.label) {
+ result = 'continue ' + stmt.label.name + ';';
+ } else {
+ result = 'continue;';
+ }
+ break;
+
+ case Syntax.DoWhileStatement:
+ result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test) + ');';
+ break;
+
+ case Syntax.CatchClause:
+ previousBase = base;
+ base += indent;
+ result = ' catch (' + generateExpression(stmt.param) + ')';
+ base = previousBase;
+ result += maybeBlock(stmt.body);
+ break;
+
+ case Syntax.DebuggerStatement:
+ result = 'debugger;';
+ break;
+
+ case Syntax.EmptyStatement:
+ result = ';';
+ break;
+
+ case Syntax.ExpressionStatement:
+ result = generateExpression(stmt.expression);
+ // 12.4 '{', 'function' is not allowed in this position.
+ // wrap espression with parentheses
+ if (result[0] === '{' || result.indexOf('function ') === 0) {
+ result = '(' + result + ');';
+ } else {
+ result += ';';
+ }
+ break;
+
+ case Syntax.VariableDeclarator:
+ if (stmt.init) {
+ result = stmt.id.name + ' = ' + generateExpression(stmt.init, Precedence.Assignment);
+ } else {
+ result = stmt.id.name;
+ }
+ break;
+
+ case Syntax.VariableDeclaration:
+ result = stmt.kind + ' ';
+ // special path for
+ // var x = function () {
+ // };
+ if (stmt.declarations.length === 1 && stmt.declarations[0].init &&
+ stmt.declarations[0].init.type === Syntax.FunctionExpression) {
+ result += generateStatement(stmt.declarations[0]);
+ } else {
+ previousBase = base;
+ base += indent;
+ for (i = 0, len = stmt.declarations.length; i < len; i += 1) {
+ result += generateStatement(stmt.declarations[i]);
+ if ((i + 1) < len) {
+ result += ', ';
+ }
+ }
+ base = previousBase;
+ }
+ result += ';';
+ break;
+
+ case Syntax.ThrowStatement:
+ result = 'throw ' + generateExpression(stmt.argument) + ';';
+ break;
+
+ case Syntax.TryStatement:
+ result = 'try' + maybeBlock(stmt.block);
+ for (i = 0, len = stmt.handlers.length; i < len; i += 1) {
+ result += generateStatement(stmt.handlers[i]);
+ }
+ if (stmt.finalizer) {
+ result += ' finally' + maybeBlock(stmt.finalizer);
+ }
+ break;
+
+ case Syntax.SwitchStatement:
+ previousBase = base;
+ base += indent;
+ result = 'switch (' + generateExpression(stmt.discriminant) + ') {\n';
+ base = previousBase;
+ if (stmt.cases) {
+ for (i = 0, len = stmt.cases.length; i < len; i += 1) {
+ result += addIndent(generateStatement(stmt.cases[i])) + '\n';
+ }
+ }
+ result += addIndent('}');
+ break;
+
+ case Syntax.SwitchCase:
+ previousBase = base;
+ base += indent;
+ if (stmt.test) {
+ result = 'case ' + generateExpression(stmt.test) + ':';
+ } else {
+ result = 'default:';
+ }
+
+ i = 0;
+ len = stmt.consequent.length;
+ if (len && stmt.consequent[0].type === Syntax.BlockStatement) {
+ result += maybeBlock(stmt.consequent[0]);
+ i = 1;
+ }
+
+ for (; i < len; i += 1) {
+ result += '\n' + addIndent(generateStatement(stmt.consequent[i]));
+ }
+
+ base = previousBase;
+ break;
+
+ case Syntax.IfStatement:
+ if (stmt.alternate) {
+ if (stmt.alternate.type === Syntax.IfStatement) {
+ previousBase = base;
+ base += indent;
+ result = 'if (' + generateExpression(stmt.test) + ')';
+ base = previousBase;
+ result += maybeBlock(stmt.consequent, true) + 'else ' + generateStatement(stmt.alternate);
+ } else {
+ previousBase = base;
+ base += indent;
+ result = 'if (' + generateExpression(stmt.test) + ')';
+ base = previousBase;
+ result += maybeBlock(stmt.consequent, true) + 'else' + maybeBlock(stmt.alternate);
+ }
+ } else {
+ previousBase = base;
+ base += indent;
+ result = 'if (' + generateExpression(stmt.test) + ')';
+ base = previousBase;
+ result += maybeBlock(stmt.consequent);
+ }
+ break;
+
+ case Syntax.ForStatement:
+ previousBase = base;
+ base += indent;
+ result = 'for (';
+ if (stmt.init) {
+ if (stmt.init.type === Syntax.VariableDeclaration) {
+ result += generateStatement(stmt.init);
+ } else {
+ result += generateExpression(stmt.init) + ';';
+ }
+ } else {
+ result += ';';
+ }
+
+ if (stmt.test) {
+ result += ' ' + generateExpression(stmt.test) + ';';
+ } else {
+ result += ';';
+ }
+
+ if (stmt.update) {
+ result += ' ' + generateExpression(stmt.update) + ')';
+ } else {
+ result += ')';
+ }
+ base = previousBase;
+
+ result += maybeBlock(stmt.body);
+ break;
+
+ case Syntax.ForInStatement:
+ result = 'for (';
+ if (stmt.left.type === Syntax.VariableDeclaration) {
+ previousBase = base;
+ base += indent + indent;
+ result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0]);
+ base = previousBase;
+ } else {
+ previousBase = base;
+ base += indent;
+ result += generateExpression(stmt.left);
+ base = previousBase;
+ }
+
+ previousBase = base;
+ base += indent;
+ result += ' in ' + generateExpression(stmt.right) + ')';
+ base = previousBase;
+ result += maybeBlock(stmt.body);
+ break;
+
+ case Syntax.LabeledStatement:
+ result = stmt.label.name + ':' + maybeBlock(stmt.body);
+ break;
+
+ case Syntax.Program:
+ result = '';
+ for (i = 0, len = stmt.body.length; i < len; i += 1) {
+ result += generateStatement(stmt.body[i]);
+ if ((i + 1) < len) {
+ result += '\n';
+ }
+ }
+ break;
+
+ case Syntax.FunctionDeclaration:
+ result = 'function ';
+ if (stmt.id) {
+ result += stmt.id.name;
+ }
+ result += generateFunctionBody(stmt);
+ break;
+
+ case Syntax.ReturnStatement:
+ if (stmt.argument) {
+ result = 'return ' + generateExpression(stmt.argument) + ';';
+ } else {
+ result = 'return;';
+ }
+ break;
+
+ case Syntax.WhileStatement:
+ previousBase = base;
+ base += indent;
+ result = 'while (' + generateExpression(stmt.test) + ')';
+ base = previousBase;
+ result += maybeBlock(stmt.body);
+ break;
+
+ case Syntax.WithStatement:
+ previousBase = base;
+ base += indent;
+ result = 'with (' + generateExpression(stmt.object) + ')';
+ base = previousBase;
+ result += maybeBlock(stmt.body);
+ break;
+
+ default:
+ break;
+ }
+
+ if (result === undefined) {
+ throw new Error('Unknown statement type: ' + stmt.type);
+ }
+ return result;
+ }
+
+ function generate(node, options) {
+ if (typeof options !== 'undefined') {
+ base = options.base || '';
+ indent = options.indent || ' ';
+ parse = options.parse;
+ } else {
+ base = '';
+ indent = ' ';
+ parse = null;
+ }
+
+ switch (node.type) {
+ case Syntax.BlockStatement:
+ case Syntax.BreakStatement:
+ case Syntax.CatchClause:
+ case Syntax.ContinueStatement:
+ case Syntax.DoWhileStatement:
+ case Syntax.DebuggerStatement:
+ case Syntax.EmptyStatement:
+ case Syntax.ExpressionStatement:
+ case Syntax.ForStatement:
+ case Syntax.ForInStatement:
+ case Syntax.FunctionDeclaration:
+ case Syntax.IfStatement:
+ case Syntax.LabeledStatement:
+ case Syntax.Program:
+ case Syntax.ReturnStatement:
+ case Syntax.SwitchStatement:
+ case Syntax.SwitchCase:
+ case Syntax.ThrowStatement:
+ case Syntax.TryStatement:
+ case Syntax.VariableDeclaration:
+ case Syntax.VariableDeclarator:
+ case Syntax.WhileStatement:
+ case Syntax.WithStatement:
+ return generateStatement(node);
+
+ case Syntax.AssignmentExpression:
+ case Syntax.ArrayExpression:
+ case Syntax.BinaryExpression:
+ case Syntax.CallExpression:
+ case Syntax.ConditionalExpression:
+ case Syntax.FunctionExpression:
+ case Syntax.Identifier:
+ case Syntax.Literal:
+ case Syntax.LogicalExpression:
+ case Syntax.MemberExpression:
+ case Syntax.NewExpression:
+ case Syntax.ObjectExpression:
+ case Syntax.Property:
+ case Syntax.SequenceExpression:
+ case Syntax.ThisExpression:
+ case Syntax.UnaryExpression:
+ case Syntax.UpdateExpression:
+ return generateExpression(node);
+
+ default:
+ break;
+ }
+ throw new Error('Unknown node type: ' + node.type);
+ }
+
+ // Sync with package.json.
+ exports.version = '0.0.1-dev';
+
+ exports.generate = generate;
+
+}(typeof exports === 'undefined' ? (escodegen = {}) : exports));
+/* vim: set sw=4 ts=4 et tw=80 : */
29 package.json
@@ -0,0 +1,29 @@
+{
+ "name": "escodegen",
+ "description": "ECMAScript code generator",
+ "homepage": "http://github.com/Constellation/escodegen.html",
+ "main": "escodegen.js",
+ "bin": {
+ "escodegen": "./bin/escodegen.js"
+ },
+ "version": "0.0.1-dev",
+ "engines": {
+ "node": ">=0.4.0"
+ },
+ "maintainers": [{
+ "name": "Yusuke Suzuki",
+ "email": "utatane.tea@gmail.com",
+ "web": "http://github.com/Constellation"
+ }],
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/Constellation/escodegen.git"
+ },
+ "licenses": [{
+ "type": "BSD",
+ "url": "http://github.com/Constellation/escodegen/raw/master/LICENSE.BSD"
+ }],
+ "scripts": {
+ "test": "node test/run.js"
+ }
+}
646 test/3rdparty/Tokenizer.js
@@ -0,0 +1,646 @@
+if (typeof exports !== 'undefined') {
+ var window = {Unicode: require('./unicodecategories').Unicode};
+ exports.Tokenizer = Tokenizer;
+}
+
+/*!
+ * Tokenizer for JavaScript / ECMAScript 5
+ * (c) Peter van der Zee, qfox.nl
+ */
+
+/**
+ * @param {Object} inp
+ */
+function Tokenizer(inp){
+ this.inp = inp||'';
+ // replace all other line terminators with \n (leave \r\n in tact though). we should probably remove the shadowInp when finished...
+ // only replace \r if it is not followed by a \n else \r\n would become \n\n causing a double newline where it is just a single
+ this.shadowInp = (inp||'').replace(Tokenizer.regexNormalizeNewlines, '\n');
+ this.pos = 0;
+ this.line = 0;
+ this.column = 0;
+ this.cache = {};
+
+ this.errorStack = [];
+
+ this.wtree = [];
+ this.btree = [];
+
+// this.regexWhiteSpace = Tokenizer.regexWhiteSpace;
+ this.regexLineTerminator = Tokenizer.regexLineTerminator; // used in fallback
+ this.regexAsciiIdentifier = Tokenizer.regexAsciiIdentifier;
+ this.hashAsciiIdentifier = Tokenizer.hashAsciiIdentifier;
+// this.regexHex = Tokenizer.regexHex;
+ this.hashHex = Tokenizer.hashHex
+ this.regexUnicodeEscape = Tokenizer.regexUnicodeEscape;
+ this.regexIdentifierStop = Tokenizer.regexIdentifierStop;
+ this.hashIdentifierStop = Tokenizer.hashIdentifierStop;
+// this.regexPunctuators = Tokenizer.regexPunctuators;
+ this.regexNumber = Tokenizer.regexNumber;
+ this.regexNewline = Tokenizer.regexNewline;
+
+ this.regexBig = Tokenizer.regexBig;
+ this.regexBigAlt = Tokenizer.regexBigAlt;
+
+ this.tokenCount = 0;
+ this.tokenCountNoWhite = 0;
+
+ this.Unicode = window.Unicode;
+
+ // if the Parser throws an error. it will set this property to the next match
+ // at the time of the error (which was not what it was expecting at that point)
+ // and pass on an "error" match. the error should be scooped on the stack and
+ // this property should be returned, without looking at the input...
+ this.errorEscape = null;
+};
+
+Tokenizer.prototype = {
+ inp:null,
+ shadowInp:null,
+ pos:null,
+ line:null,
+ column:null,
+ cache:null,
+ errorStack:null,
+
+ wtree: null, // contains whitespace (spaces, comments, newlines)
+ btree: null, // does not contain any whitespace tokens.
+
+ regexLineTerminator:null,
+ regexAsciiIdentifier:null,
+ hashAsciiIdentifier:null,
+ hashHex:null,
+ regexUnicodeEscape:null,
+ regexIdentifierStop:null,
+ hashIdentifierStop:null,
+ regexNumber:null,
+ regexNewline:null,
+ regexBig:null,
+ regexBigAlt:null,
+ tokenCount:null,
+ tokenCountNoWhite:null,
+
+ Unicode:null,
+
+ // storeCurrentAndFetchNextToken(bool, false, false true) to get just one token
+ storeCurrentAndFetchNextToken: function(noRegex, returnValue, stack, _dontStore){
+ var regex = !noRegex; // TOFIX :)
+ var pos = this.pos;
+ var inp = this.inp;
+ var shadowInp = this.shadowInp;
+ var matchedNewline = false;
+ do {
+ if (!_dontStore) {
+ ++this.tokenCount;
+ stack.push(returnValue);
+ // did the parent Parser throw up?
+ if (this.errorEscape) {
+ returnValue = this.errorEscape;
+ this.errorEscape = null;
+ return returnValue;
+ }
+ }
+ _dontStore = false;
+
+ if (pos >= inp.length) {
+ returnValue = {start:inp.length,stop:inp.length,name:12/*EOF*/};
+ break;
+ }
+ var returnValue = null;
+
+ var start = pos;
+ var chr = inp[pos];
+
+ // 1 ws 2 lt 3 scmt 4 mcmt 5/6 str 7 nr 8 rx 9 punc
+ //if (true) {
+ // substring method (I think this is faster..)
+ var part2 = inp.substring(pos,pos+4);
+ var part = this.regexBig.exec(part2);
+ //} else {
+ // // non-substring method (lastIndex)
+ // // this method does not need a substring to apply it
+ // this.regexBigAlt.lastIndex = pos;
+ // var part = this.regexBigAlt.exec(inp);
+ //}
+
+ if (part[1]) { //this.regexWhiteSpace.test(chr)) { // SP, TAB, VT, FF, NBSP, BOM (, TOFIX: USP)
+ ++pos;
+ returnValue = {start:start,stop:pos,name:9/*WHITE_SPACE*/,line:this.line,col:this.column,isWhite:true};
+ ++this.column;
+ } else if (part[2]) { //this.regexLineTerminator.test(chr)) { // LF, CR, LS, PS
+ var end = pos+1;
+ if (chr=='\r' && inp[pos+1] == '\n') ++end; // support crlf=>lf
+ returnValue = {start:pos,stop:end,name:10/*LINETERMINATOR*/,line:this.line,col:this.column,isWhite:true};
+ pos = end;
+ // mark newlines for ASI
+ matchedNewline = true;
+ ++this.line;
+ this.column = 0;
+ returnValue.hasNewline = 1;
+ } else if (part[3]) { //chr == '/' && inp[pos+1] == '/') {
+ pos = shadowInp.indexOf('\n',pos);
+ if (pos == -1) pos = inp.length;
+ returnValue = {start:start,stop:pos,name:7/*COMMENT_SINGLE*/,line:this.line,col:this.column,isComment:true,isWhite:true};
+ this.column = returnValue.stop;
+ } else if (part[4]) { //chr == '/' && inp[pos+1] == '*') {
+ var newpos = inp.indexOf('*/',pos);
+ if (newpos == -1) {
+ newpos = shadowInp.indexOf('\n', pos);
+ if (newpos < 0) pos += 2;
+ else pos = newpos;
+ returnValue = {start:start,stop:pos,name:14/*error*/,value:inp.substring(start, pos),line:this.line,col:this.column,isComment:true,isWhite:true,tokenError:true,error:Tokenizer.Error.UnterminatedMultiLineComment};
+ this.errorStack.push(returnValue);
+ } else {
+ pos = newpos+2;
+ returnValue = {start:start,stop:pos,name:8/*COMMENT_MULTI*/,value:inp.substring(start, pos),line:this.line,col:this.column,isComment:true,isWhite:true};
+
+ // multi line comments are also reason for asi, but only if they contain at least one newline (use shadow input, because all line terminators would be valid...)
+ var shadowValue = shadowInp.substring(start, pos);
+ var i = 0, hasNewline = 0;
+ while (i < (i = shadowValue.indexOf('\n', i+1))) {
+ ++hasNewline;
+ }
+ if (hasNewline) {
+ matchedNewline = true;
+ returnValue.hasNewline = hasNewline;
+ this.line += hasNewline;
+ this.column = 0;
+ } else {
+ this.column = returnValue.stop;
+ }
+ }
+ } else if (part[5]) { //chr == "'") {
+ // old method
+ //console.log("old method");
+
+ var hasNewline = 0;
+ do {
+ // process escaped characters
+ while (pos < inp.length && inp[++pos] == '\\') {
+ if (shadowInp[pos+1] == '\n') ++hasNewline;
+ ++pos;
+ }
+ if (this.regexLineTerminator.test(inp[pos])) {
+ returnValue = {start:start,stop:pos,name:14/*error*/,value:inp.substring(start, pos),isString:true,tokenError:true,error:Tokenizer.Error.UnterminatedDoubleStringNewline};
+ this.errorStack.push(returnValue);
+ break;
+ }
+ } while (pos < inp.length && inp[pos] != "'");
+ if (returnValue) {} // error
+ else if (inp[pos] != "'") {
+ returnValue = {start:start,stop:pos,name:14/*error*/,value:inp.substring(start, pos),isString:true,tokenError:true,error:Tokenizer.Error.UnterminatedDoubleStringOther};
+ this.errorStack.push(returnValue);
+ } else {
+ ++pos;
+ returnValue = {start:start,stop:pos,name:5/*STRING_SINGLE*/,isPrimitive:true,isString:true};
+ if (hasNewline) {
+ returnValue.hasNewline = hasNewline;
+ this.line += hasNewline;
+ this.column = 0;
+ } else {
+ this.column += (pos-start);
+ }
+ }
+ } else if (part[6]) { //chr == '"') {
+ var hasNewline = 0;
+ // TODO: something like this: var regexmatch = /([^\']|$)+/.match();
+ do {
+ // process escaped chars
+ while (pos < inp.length && inp[++pos] == '\\') {
+ if (shadowInp[pos+1] == '\n') ++hasNewline;
+ ++pos;
+ }
+ if (this.regexLineTerminator.test(inp[pos])) {
+ returnValue = {start:start,stop:pos,name:14/*error*/,value:inp.substring(start, pos),isString:true,tokenError:true,error:Tokenizer.Error.UnterminatedSingleStringNewline};
+ this.errorStack.push(returnValue);
+ break;
+ }
+ } while (pos < inp.length && inp[pos] != '"');
+ if (returnValue) {}
+ else if (inp[pos] != '"') {
+ returnValue = {start:start,stop:pos,name:14/*error*/,value:inp.substring(start, pos),isString:true,tokenError:true,error:Tokenizer.Error.UnterminatedSingleStringOther};
+ this.errorStack.push(returnValue);
+ } else {
+ ++pos;
+ returnValue = {start:start,stop:pos,name:6/*STRING_DOUBLE*/,isPrimitive:true,isString:true};
+ if (hasNewline) {
+ returnValue.hasNewline = hasNewline;
+ this.line += hasNewline;
+ this.column = 0;
+ } else {
+ this.column += (pos-start);
+ }
+ }
+ } else if (part[7]) { //(chr >= '0' && chr <= '9') || (chr == '.' && inp[pos+1] >= '0' && inp[pos+1] <= '9')) {
+ var nextPart = inp.substring(pos, pos+30);
+ var match = nextPart.match(this.regexNumber);
+ if (match[2]) { // decimal
+ var value = match[2];
+ var parsingOctal = value[0] == '0' && value[1] && value[1] != 'e' && value[1] != 'E' && value[1] != '.';
+ if (parsingOctal) {
+ returnValue = {start:start,stop:pos,name:14/*error*/,isNumber:true,isOctal:true,tokenError:true,error:Tokenizer.Error.IllegalOctalEscape,value:value};
+ this.errorStack.push(returnValue);
+ } else {
+ returnValue = {start:start,stop:start+value.length,name:4/*NUMERIC_DEC*/,isPrimitive:true,isNumber:true,value:value};
+ }
+ } else if (match[1]) { // hex
+ var value = match[1];
+ returnValue = {start:start,stop:start+value.length,name:3/*NUMERIC_HEX*/,isPrimitive:true,isNumber:true,value:value};
+ } else {
+ throw 'unexpected parser errror... regex fail :(';
+ }
+
+ if (value.length < 300) {
+ pos += value.length;
+ } else {
+ // old method of parsing numbers. only used for extremely long number literals (300+ chars).
+ // this method does not require substringing... just memory :)
+ var tmpReturnValue = this.oldNumberParser(pos, chr, inp, returnValue, start, Tokenizer);
+ pos = tmpReturnValue[0];
+ returnValue = tmpReturnValue[1];
+ }
+ } else if (regex && part[8]) { //chr == '/') { // regex cannot start with /* (would be multiline comment, and not make sense anyways). but if it was /* then an earlier if would have eated it. so we only check for /
+ var twinfo = []; // matching {[( info
+ var found = false;
+ var parens = [];
+ var nonLethalError = null;
+ while (++pos < inp.length) {
+ chr = shadowInp[pos];
+ // parse RegularExpressionChar
+ if (chr == '\n') {
+ returnValue = {start:start,stop:pos,name:14/*error*/,tokenError:true,errorHasContent:true,error:Tokenizer.Error.UnterminatedRegularExpressionNewline};
+ this.errorStack.push(returnValue);
+ break; // fail
+ } else if (chr == '/') {
+ found = true;
+ break;
+ } else if (chr == '?' || chr == '*' || chr == '+') {
+ nonLethalError = Tokenizer.Error.NothingToRepeat;
+ } else if (chr == '^') {
+ if (
+ inp[pos-1] != '/' &&
+ inp[pos-1] != '|' &&
+ inp[pos-1] != '(' &&
+ !(inp[pos-3] == '(' && inp[pos-2] == '?' && (inp[pos-1] == ':' || inp[pos-1] == '!' || inp[pos-1] == '='))
+ ) {
+ nonLethalError = Tokenizer.Error.StartOfMatchShouldBeAtStart;
+ }
+ } else if (chr == '$') {
+ if (inp[pos+1] != '/' && inp[pos+1] != '|' && inp[pos+1] != ')') nonLethalError = Tokenizer.Error.DollarShouldBeEnd;
+ } else if (chr == '}') {
+ nonLethalError = Tokenizer.Error.MissingOpeningCurly;
+ } else { // it's a "character" (can be group or class), something to match
+ // match parenthesis
+ if (chr == '(') {
+ parens.push(pos-start);
+ } else if (chr == ')') {
+ if (parens.length == 0) {
+ nonLethalError = {start:start,stop:pos,name:14/*error*/,tokenError:true,error:Tokenizer.Error.RegexNoOpenGroups};
+ } else {
+ var twin = parens.pop();
+ var now = pos-start;
+ twinfo[twin] = now;
+ twinfo[now] = twin;
+ }
+ }
+ // first process character class
+ if (chr == '[') {
+ var before = pos-start;
+ while (++pos < inp.length && shadowInp[pos] != '\n' && inp[pos] != ']') {
+ // only newline is not allowed in class range
+ // anything else can be escaped, most of it does not have to be escaped...
+ if (inp[pos] == '\\') {
+ if (shadowInp[pos+1] == '\n') break;
+ else ++pos; // skip next char. (mainly prohibits ] to be picked up as closing the group...)
+ }
+ }
+ if (inp[pos] != ']') {
+ returnValue = {start:start,stop:pos,name:14/*error*/,tokenError:true,error:Tokenizer.Error.ClosingClassRangeNotFound};
+ this.errorStack.push(returnValue);
+ break;
+ } else {
+ var after = pos-start;
+ twinfo[before] = after;
+ twinfo[after] = before;
+ }
+ } else if (chr == '\\' && shadowInp[pos+1] != '\n') {
+ // is ok anywhere in the regex (match next char literally, regardless of its otherwise special meaning)
+ ++pos;
+ }
+
+ // now process repeaters (+, ? and *)
+
+ // non-collecting group (?:...) and positive (?=...) or negative (?!...) lookahead
+ if (chr == '(') {
+ if (inp[pos+1] == '?' && (inp[pos+2] == ':' || inp[pos+2] == '=' || inp[pos+2] == '!')) {
+ pos += 2;
+ }
+ }
+ // matching "char"
+ else if (inp[pos+1] == '?') ++pos;
+ else if (inp[pos+1] == '*' || inp[pos+1] == '+') {
+ ++pos;
+ if (inp[pos+1] == '?') ++pos; // non-greedy match
+ } else if (inp[pos+1] == '{') {
+ pos += 1;
+ var before = pos-start;
+ // quantifier:
+ // - {n}
+ // - {n,}
+ // - {n,m}
+ if (!/[0-9]/.test(inp[pos+1])) {
+ nonLethalError = Tokenizer.Error.QuantifierRequiresNumber;
+ }
+ while (++pos < inp.length && /[0-9]/.test(inp[pos+1]));
+ if (inp[pos+1] == ',') {
+ ++pos;
+ while (pos < inp.length && /[0-9]/.test(inp[pos+1])) ++pos;
+ }
+ if (inp[pos+1] != '}') {
+ nonLethalError = Tokenizer.Error.QuantifierRequiresClosingCurly;
+ } else {
+ ++pos;
+ var after = pos-start;
+ twinfo[before] = after;
+ twinfo[after] = before;
+ if (inp[pos+1] == '?') ++pos; // non-greedy match
+ }
+ }
+ }
+ }
+ // if found=false, fail right now. otherwise try to parse an identifiername (that's all RegularExpressionFlags is..., but it's constructed in a stupid fashion)
+ if (!found || returnValue) {
+ if (!returnValue) {
+ returnValue = {start:start,stop:pos,name:14/*error*/,tokenError:true,error:Tokenizer.Error.UnterminatedRegularExpressionOther};
+ this.errorStack.push(returnValue);
+ }
+ } else {
+ // this is the identifier scanner, for now
+ do ++pos;
+ while (pos < inp.length && this.hashAsciiIdentifier[inp[pos]]); /*this.regexAsciiIdentifier.test(inp[pos])*/
+
+ if (parens.length) {
+ // nope, this is still an error, there was at least one paren that did not have a matching twin
+ if (parens.length > 0) returnValue = {start:start,stop:pos,name:14/*error*/,tokenError:true,error:Tokenizer.Error.RegexOpenGroup};
+ this.errorStack.push(returnValue);
+ } else if (nonLethalError) {
+ returnValue = {start:start,stop:pos,name:14/*error*/,errorHasContent:true,tokenError:true,error:nonLethalError};
+ this.errorStack.push(returnValue);
+ } else {
+ returnValue = {start:start,stop:pos,name:1/*REG_EX*/,isPrimitive:true};
+ }
+ }
+ returnValue.twinfo = twinfo;
+ } else {
+ // note: operators need to be ordered from longest to smallest. regex will take care of the rest.
+ // no need to worry about div vs regex. if looking for regex, earlier if will have eaten it
+ //var result = this.regexPunctuators.exec(inp.substring(pos,pos+4));
+
+ // note: due to the regex, the single forward slash might be caught by an earlier part of the regex. so check for that.
+ var result = part[8] || part[9];
+ if (result) {
+ //result = result[1];
+ returnValue = {start:pos,stop:pos+=result.length,name:11/*PUNCTUATOR*/,value:result};
+ } else {
+ var found = false;
+ // identifiers cannot start with a number. but if the leading string would be a number, another if would have eaten it already for numeric literal :)
+ while (pos < inp.length) {
+ var c = inp[pos];
+
+ if (this.hashAsciiIdentifier[c]) ++pos; //if (this.regexAsciiIdentifier.test(c)) ++pos;
+ else if (c == '\\' && this.regexUnicodeEscape.test(inp.substring(pos,pos+6))) pos += 6; // this is like a \uxxxx
+ // ok, now test unicode ranges...
+ // basically this hardly ever happens so there's little risk of this hitting performance
+ // however, if you do happen to have used them, it's not a problem. the parser will support it :)
+ else if (this.Unicode) { // the unicode is optional.
+ // these chars may not be part of identifier. i want to try to prevent running the unicode regexes here...
+ if (this.hashIdentifierStop[c] /*this.regexIdentifierStop.test(c)*/) break;
+ // for most scripts, the code wont reach here. which is good, because this is going to be relatively slow :)
+ var Unicode = this.Unicode; // cache
+ if (!(
+ // these may all occur in an identifier... (pure a specification compliance thing :)
+ Unicode.Lu.test(c) || Unicode.Ll.test(c) || Unicode.Lt.test(c) || Unicode.Lm.test(c) ||
+ Unicode.Lo.test(c) || Unicode.Nl.test(c) || Unicode.Mn.test(c) || Unicode.Mc.test(c) ||
+ Unicode.Nd.test(c) || Unicode.Pc.test(c) || Unicode.sp.test(c)
+ )) break; // end of match.
+ // passed, next char
+ ++pos;
+ } else break; // end of match.
+
+ found = true;
+ }
+
+ if (found) {
+ returnValue = {start:start,stop:pos,name:2/*IDENTIFIER*/,value:inp.substring(start,pos)};
+ if (returnValue.value == 'undefined' || returnValue.value == 'null' || returnValue.value == 'true' || returnValue.value == 'false') returnValue.isPrimitive = true;
+ } else {
+ if (inp[pos] == '`') {
+ returnValue = {start:start,stop:pos+1,name:14/*error*/,tokenError:true,error:Tokenizer.Error.BacktickNotSupported};
+ this.errorStack.push(returnValue);
+ } else if (inp[pos] == '\\') {
+ if (inp[pos+1] == 'u') {
+ returnValue = {start:start,stop:pos+1,name:14/*error*/,tokenError:true,error:Tokenizer.Error.InvalidUnicodeEscape};
+ this.errorStack.push(returnValue);
+ } else {
+ returnValue = {start:start,stop:pos+1,name:14/*error*/,tokenError:true,error:Tokenizer.Error.InvalidBackslash};
+ this.errorStack.push(returnValue);
+ }
+ } else {
+ returnValue = {start:start,stop:pos+1,name:14/*error*/,tokenError:true,error:Tokenizer.Error.Unknown,value:c};
+ this.errorStack.push(returnValue);
+ // try to skip this char. it's not going anywhere.
+ }
+ ++pos;
+ }
+ }
+ }
+
+ if (returnValue) {
+ // note that ASI's are slipstreamed in here from the parser since the tokenizer cant determine that
+ // if this part ever changes, make sure you change that too :)
+ returnValue.tokposw = this.wtree.length;
+ this.wtree.push(returnValue);
+ if (!returnValue.isWhite) {
+ returnValue.tokposb = this.btree.length;
+ this.btree.push(returnValue);
+ }
+ }
+
+
+ } while (stack && returnValue && returnValue.isWhite); // WHITE_SPACE LINETERMINATOR COMMENT_SINGLE COMMENT_MULTI
+ ++this.tokenCountNoWhite;
+
+ this.pos = pos;
+
+ if (matchedNewline) returnValue.newline = true;
+ return returnValue;
+ },
+ addTokenToStreamBefore: function(token, match){
+ var wtree = this.wtree;
+ var btree = this.btree;
+ if (match.name == 12/*asi*/) {
+ token.tokposw = wtree.length;
+ wtree.push(token);
+ token.tokposb = btree.length;
+ btree.push(token);
+ } else {
+ token.tokposw = match.tokposw;
+ wtree[token.tokposw] = token;
+ match.tokposw += 1;
+ wtree[match.tokposw] = match;
+
+ if (match.tokposb) {
+ token.tokposb = match.tokposb;
+ btree[token.tokposb] = token;
+ match.tokposb += 1;
+ btree[match.tokposb] = match;
+ }
+ }
+ },
+ oldNumberParser: function(pos, chr, inp, returnValue, start, Tokenizer){
+ ++pos;
+ // either: 0x 0X 0 .3
+ if (chr == '0' && (inp[pos] == 'x' || inp[pos] == 'X')) {
+ // parsing hex
+ while (++pos < inp.length && this.hashHex[inp[pos]]); // this.regexHex.test(inp[pos]));
+ returnValue = {start:start,stop:pos,name:3/*NUMERIC_HEX*/,isPrimitive:true,isNumber:true};
+ } else {
+ var parsingOctal = chr == '0' && inp[pos] >= '0' && inp[pos] <= '9';
+ // parsing dec
+ if (chr != '.') { // integer part
+ while (pos < inp.length && inp[pos] >= '0' && inp[pos] <= '9') ++pos;
+ if (inp[pos] == '.') ++pos;
+ }
+ // decimal part
+ while (pos < inp.length && inp[pos] >= '0' && inp[pos] <= '9') ++pos;
+ // exponent part
+ if (inp[pos] == 'e' || inp[pos] == 'E') {
+ if (inp[++pos] == '+' || inp[pos] == '-') ++pos;
+ var expPosBak = pos;
+ while (pos < inp.length && inp[pos] >= '0' && inp[pos] <= '9') ++pos;
+ if (expPosBak == pos) {
+ returnValue = {start:start,stop:pos,name:14/*error*/,tokenError:true,error:Tokenizer.Error.NumberExponentRequiresDigits};
+ this.errorStack.push(returnValue);
+ }
+ }
+ if (returnValue.name != 14/*error*/) {
+ if (parsingOctal) {
+ returnValue = {start:start,stop:pos,name:14/*error*/,isNumber:true,isOctal:true,tokenError:true,error:Tokenizer.Error.IllegalOctalEscape};
+ this.errorStack.push(returnValue);
+ console.log("foo")
+ } else {
+ returnValue = {start:start,stop:pos,name:4/*NUMERIC_DEC*/,isPrimitive:true,isNumber:true};
+ }
+ }
+ }
+ return [pos, returnValue];
+ },
+ tokens: function(arrx){
+ arrx = arrx || [];
+ var n = 0;
+ var last;
+ var stack = [];
+ while ((last = this.storeCurrentAndFetchNextToken(!arrx[n++], false, false, true)) && last.name != 12/*EOF*/) stack.push(last);
+ return stack;
+ },
+ fixValues: function(){
+ this.wtree.forEach(function(t){
+ if (!t.value) t.value = this.inp.substring(t.start, t.stop);
+ },this);
+ }
+};
+
+//#ifdef TEST_SUITE
+Tokenizer.escape = function(s){
+ return s.replace(/\n/g,'\\n').replace(/\t/g,'\\t').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\uFFFF/g, '\\uFFFF').replace(/\s/g, function(s){
+ // replace whitespace as is...
+ var ord = s.charCodeAt(0).toString(16);
+ switch (ord.length) {
+ case 1: ord = '000'+ord; break;
+ case 2: ord = '00'+ord; break;
+ case 3: ord = '0'+ord; break;
+ }
+ return '\\u'+ord;
+ });
+};
+Tokenizer.testSuite = function(arr){
+ var out = document.createElement('pre');
+ document.body.appendChild(out);
+ var debug = function(){
+ var f = document.createElement('div');
+ f.innerHTML = Array.prototype.slice.call(arguments).join(' ');
+ out.appendChild(f);
+ return arguments[0];
+ };
+
+ debug("Running test suite...",arr.length,"tests");
+ debug(' ');
+ var start = +new Date;
+ var ok = 0;
+ var fail = 0;
+ for (var i=0; i<arr.length; ++i) {
+ var test = arr[i], result;
+ var input = test[0];
+ var outputLen = test[1].length ? test[1][0] : test[1];
+ var regexHints = test[3] ? test[2] : null; // if flags, then len=4
+ var desc = test[3] || test[2];
+
+ var result = new Tokenizer(input).tokens(regexHints); // regexHints can be null, that's ok
+ if (result.length == outputLen) {
+ debug('<span class="green">Test '+i+' ok:</span>',desc);
+ ++ok;
+ } else {
+ debug('<b class="red">Test failed:</span>',desc,'(found',result.length,'expected',outputLen+')'),console.log(desc, result);
+ ++fail;
+ }
+ debug('<b>'+Tokenizer.escape(input)+'</b>');
+ debug('<br/>');
+ }
+ debug("Tokenizer test suite finished ("+(+new Date - start)+' ms). ok:'+ok+', fail:'+fail);
+};
+//#endif
+
+Tokenizer.regexWhiteSpace = /[ \t\u000B\u000C\u00A0\uFFFF]/;
+Tokenizer.regexLineTerminator = /[\u000A\u000D\u2028\u2029]/;
+Tokenizer.regexAsciiIdentifier = /[a-zA-Z0-9\$_]/;
+Tokenizer.hashAsciiIdentifier = {_:1,$:1,a:1,b:1,c:1,d:1,e:1,f:1,g:1,h:1,i:1,j:1,k:1,l:1,m:1,n:1,o:1,p:1,q:1,r:1,s:1,t:1,u:1,v:1,w:1,x:1,y:1,z:1,A:1,B:1,C:1,D:1,E:1,F:1,G:1,H:1,I:1,J:1,K:1,L:1,M:1,N:1,O:1,P:1,Q:1,R:1,S:1,T:1,U:1,V:1,W:1,X:1,Y:1,Z:1,0:1,1:1,2:1,3:1,4:1,5:1,6:1,7:1,8:1,9:1};
+Tokenizer.regexHex = /[0-9A-Fa-f]/;
+Tokenizer.hashHex = {0:1,1:1,2:1,3:1,4:1,5:1,6:1,7:1,8:1,9:1,a:1,b:1,c:1,d:1,e:1,f:1,A:1,B:1,C:1,D:1,E:1,F:1};
+Tokenizer.regexUnicodeEscape = /u[0-9A-Fa-f]{4}/; // the \ is already checked at usage...
+Tokenizer.regexIdentifierStop = /[\>\=\!\|\<\+\-\&\*\%\^\/\{\}\(\)\[\]\.\;\,\~\?\:\ \t\n\\\'\"]/;
+Tokenizer.hashIdentifierStop = {'>':1,'=':1,'!':1,'|':1,'<':1,'+':1,'-':1,'&':1,'*':1,'%':1,'^':1,'/':1,'{':1,'}':1,'(':1,')':1,'[':1,']':1,'.':1,';':1,',':1,'~':1,'?':1,':':1,'\\':1,'\'':1,'"':1,' ':1,'\t':1,'\n':1};
+Tokenizer.regexNewline = /\n/g;
+//Tokenizer.regexPunctuators = /^(>>>=|===|!==|>>>|<<=|>>=|<=|>=|==|!=|\+\+|--|<<|>>|\&\&|\|\||\+=|-=|\*=|%=|\&=|\|=|\^=|\/=|\{|\}|\(|\)|\[|\]|\.|;|,|<|>|\+|-|\*|%|\||\&|\||\^|!|~|\?|:|=|\/)/;
+Tokenizer.Unidocde = window.Unicode;
+Tokenizer.regexNumber = /^(?:(0[xX][0-9A-Fa-f]+)|((?:(?:(?:(?:[0-9]+)(?:\.[0-9]*)?))|(?:\.[0-9]+))(?:[eE][-+]?[0-9]{1,})?))/;
+Tokenizer.regexNormalizeNewlines = /(\u000D[^\u000A])|[\u2028\u2029]/;
+
+// 1 ws 2 lt 3 scmt 4 mcmt 5/6 str 7 nr 8 rx 9 punc
+Tokenizer.regexBig = /^([ \t\u000B\u000C\u00A0\uFFFF])?([\u000A\u000D\u2028\u2029])?(\/\/)?(\/\*)?(')?(")?(\.?[0-9])?(?:(\/)[^=])?(>>>=|===|!==|>>>|<<=|>>=|<=|>=|==|!=|\+\+|--|<<|>>|\&\&|\|\||\+=|-=|\*=|%=|\&=|\|=|\^=|\/=|\{|\}|\(|\)|\[|\]|\.|;|,|<|>|\+|-|\*|%|\||\&|\||\^|!|~|\?|:|=|\/)?/;
+Tokenizer.regexBigAlt = /([ \t\u000B\u000C\u00A0\uFFFF])?([\u000A\u000D\u2028\u2029])?(\/\/)?(\/\*)?(')?(")?(\.?[0-9])?(?:(\/)[^=])?(>>>=|===|!==|>>>|<<=|>>=|<=|>=|==|!=|\+\+|--|<<|>>|\&\&|\|\||\+=|-=|\*=|%=|\&=|\|=|\^=|\/=|\{|\}|\(|\)|\[|\]|\.|;|,|<|>|\+|-|\*|%|\||\&|\||\^|!|~|\?|:|=|\/)?/g;
+
+Tokenizer.Error = {
+ UnterminatedSingleStringNewline: {msg:'Newlines are not allowed in string literals'},
+ UnterminatedSingleStringOther: {msg:'Unterminated single string'},
+ UnterminatedDoubleStringNewline: {msg:'Newlines are not allowed in string literals'},
+ UnterminatedDoubleStringOther: {msg:'Unterminated double string'},
+ UnterminatedRegularExpressionNewline: {msg:'Newlines are not allowed in regular expressions'},
+ NothingToRepeat: {msg:'Used a repeat character (*?+) in a regex without something prior to it to match'},
+ ClosingClassRangeNotFound: {msg: 'Unable to find ] for class range'},
+ RegexOpenGroup: {msg: 'Open group did not find closing parenthesis'},
+ RegexNoOpenGroups: {msg: 'Closing parenthesis found but no group open'},
+ UnterminatedRegularExpressionOther: {msg:'Unterminated regular expression'},
+ UnterminatedMultiLineComment: {msg:'Unterminated multi line comment'},
+ UnexpectedIdentifier: {msg:'Unexpected identifier'},
+ IllegalOctalEscape: {msg:'Octal escapes are not valid'},
+ Unknown: {msg:'Unknown input'}, // if this happens, my parser is bad :(
+ NumberExponentRequiresDigits: {msg:'Numbers with exponents require at least one digit after the `e`'},
+ BacktickNotSupported: {msg:'The backtick is not used in js, maybe you copy/pasted from a fancy site/doc?'},
+ InvalidUnicodeEscape: {msg:'Encountered an invalid unicode escape, must be followed by exactly four hex numbers'},
+ InvalidBackslash: {msg:'Encountered a backslash where it not allowed'},
+ StartOfMatchShouldBeAtStart: {msg: 'The ^ signifies the start of match but was not found at a start'},
+ DollarShouldBeEnd: {msg: 'The $ signifies the stop of match but was not found at a stop'},
+ QuantifierRequiresNumber: {msg:'Quantifier curly requires at least one digit before the comma'},
+ QuantifierRequiresClosingCurly: {msg:'Quantifier curly requires to be closed'},
+ MissingOpeningCurly: {msg:'Encountered closing quantifier curly without seeing an opening curly'}
+};
509 test/3rdparty/XMLHttpRequest.js
@@ -0,0 +1,509 @@
+/**
+* XMLHttpRequest.js Copyright (C) 2011 Sergey Ilinsky (http://www.ilinsky.com)
+*
+* This work is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as published by
+* the Free Software Foundation; either version 2.1 of the License, or
+* (at your option) any later version.
+*
+* This work is distributed in the hope that it will be useful,
+* but without any warranty; without even the implied warranty of
+* merchantability or fitness for a particular purpose. See the
+* GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this library; if not, write to the Free Software Foundation, Inc.,
+* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+(function () {
+
+ // Save reference to earlier defined object implementation (if any)
+ var oXMLHttpRequest = window.XMLHttpRequest;
+
+ // Define on browser type
+ var bGecko = !!window.controllers;
+ var bIE = window.document.all && !window.opera;
+ var bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/);
+
+ // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()"
+ function fXMLHttpRequest() {
+ this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP");
+ this._listeners = [];
+ }
+
+ // Constructor
+ function cXMLHttpRequest() {
+ return new fXMLHttpRequest;
+ }
+ cXMLHttpRequest.prototype = fXMLHttpRequest.prototype;
+
+ // BUGFIX: Firefox with Firebug installed would break pages if not executed
+ if (bGecko && oXMLHttpRequest.wrapped) {
+ cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped;
+ }
+
+ // Constants
+ cXMLHttpRequest.UNSENT = 0;
+ cXMLHttpRequest.OPENED = 1;
+ cXMLHttpRequest.HEADERS_RECEIVED = 2;
+ cXMLHttpRequest.LOADING = 3;
+ cXMLHttpRequest.DONE = 4;
+
+ // Public Properties
+ cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT;
+ cXMLHttpRequest.prototype.responseText = '';
+ cXMLHttpRequest.prototype.responseXML = null;
+ cXMLHttpRequest.prototype.status = 0;
+ cXMLHttpRequest.prototype.statusText = '';
+
+ // Priority proposal
+ cXMLHttpRequest.prototype.priority = "NORMAL";
+
+ // Instance-level Events Handlers
+ cXMLHttpRequest.prototype.onreadystatechange = null;
+
+ // Class-level Events Handlers
+ cXMLHttpRequest.onreadystatechange = null;
+ cXMLHttpRequest.onopen = null;
+ cXMLHttpRequest.onsend = null;
+ cXMLHttpRequest.onabort = null;
+
+ // Public Methods
+ cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) {
+ // Delete headers, required when object is reused
+ delete this._headers;
+
+ // When bAsync parameter value is omitted, use true as default
+ if (arguments.length < 3) {
+ bAsync = true;
+ }
+
+ // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests
+ this._async = bAsync;
+
+ // Set the onreadystatechange handler
+ var oRequest = this;
+ var nState = this.readyState;
+ var fOnUnload = null;
+
+ // BUGFIX: IE - memory leak on page unload (inter-page leak)
+ if (bIE && bAsync) {
+ fOnUnload = function() {
+ if (nState != cXMLHttpRequest.DONE) {
+ fCleanTransport(oRequest);
+ // Safe to abort here since onreadystatechange handler removed
+ oRequest.abort();
+ }
+ };
+ window.attachEvent("onunload", fOnUnload);
+ }
+
+ // Add method sniffer
+ if (cXMLHttpRequest.onopen) {
+ cXMLHttpRequest.onopen.apply(this, arguments);
+ }
+
+ if (arguments.length > 4) {
+ this._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+ } else if (arguments.length > 3) {
+ this._object.open(sMethod, sUrl, bAsync, sUser);
+ } else {
+ this._object.open(sMethod, sUrl, bAsync);
+ }
+
+ this.readyState = cXMLHttpRequest.OPENED;
+ fReadyStateChange(this);
+
+ this._object.onreadystatechange = function() {
+ if (bGecko && !bAsync) {
+ return;
+ }
+
+ // Synchronize state
+ oRequest.readyState = oRequest._object.readyState;
+ fSynchronizeValues(oRequest);
+
+ // BUGFIX: Firefox fires unnecessary DONE when aborting
+ if (oRequest._aborted) {
+ // Reset readyState to UNSENT
+ oRequest.readyState = cXMLHttpRequest.UNSENT;
+
+ // Return now
+ return;
+ }
+
+ if (oRequest.readyState == cXMLHttpRequest.DONE) {
+ // Free up queue
+ delete oRequest._data;
+
+ // Uncomment these lines for bAsync
+ /**
+ * if (bAsync) {
+ * fQueue_remove(oRequest);
+ * }
+ */
+
+ fCleanTransport(oRequest);
+
+ // Uncomment this block if you need a fix for IE cache
+ /**
+ * // BUGFIX: IE - cache issue
+ * if (!oRequest._object.getResponseHeader("Date")) {
+ * // Save object to cache
+ * oRequest._cached = oRequest._object;
+ *
+ * // Instantiate a new transport object
+ * cXMLHttpRequest.call(oRequest);
+ *
+ * // Re-send request
+ * if (sUser) {
+ * if (sPassword) {
+ * oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword);
+ * } else {
+ * oRequest._object.open(sMethod, sUrl, bAsync);
+ * }
+ *
+ * oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0));
+ * // Copy headers set
+ * if (oRequest._headers) {
+ * for (var sHeader in oRequest._headers) {
+ * // Some frameworks prototype objects with functions
+ * if (typeof oRequest._headers[sHeader] == "string") {
+ * oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]);
+ * }
+ * }
+ * }
+ * oRequest._object.onreadystatechange = function() {
+ * // Synchronize state
+ * oRequest.readyState = oRequest._object.readyState;
+ *
+ * if (oRequest._aborted) {
+ * //
+ * oRequest.readyState = cXMLHttpRequest.UNSENT;
+ *
+ * // Return
+ * return;
+ * }
+ *
+ * if (oRequest.readyState == cXMLHttpRequest.DONE) {
+ * // Clean Object
+ * fCleanTransport(oRequest);
+ *
+ * // get cached request
+ * if (oRequest.status == 304) {
+ * oRequest._object = oRequest._cached;
+ * }
+ *
+ * //
+ * delete oRequest._cached;
+ *
+ * //
+ * fSynchronizeValues(oRequest);
+ *
+ * //
+ * fReadyStateChange(oRequest);
+ *
+ * // BUGFIX: IE - memory leak in interrupted
+ * if (bIE && bAsync) {
+ * window.detachEvent("onunload", fOnUnload);
+ * }
+ *
+ * }
+ * };
+ * oRequest._object.send(null);
+ *
+ * // Return now - wait until re-sent request is finished
+ * return;
+ * };
+ */
+
+ // BUGFIX: IE - memory leak in interrupted
+ if (bIE && bAsync) {
+ window.detachEvent("onunload", fOnUnload);
+ }
+
+ // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice
+ if (nState != oRequest.readyState) {
+ fReadyStateChange(oRequest);
+ }
+
+ nState = oRequest.readyState;
+ }
+ };
+ };
+
+ cXMLHttpRequest.prototype.send = function(vData) {
+ // Add method sniffer
+ if (cXMLHttpRequest.onsend) {
+ cXMLHttpRequest.onsend.apply(this, arguments);
+ }
+
+ if (!arguments.length) {
+ vData = null;
+ }
+
+ // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required
+ // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent
+ // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard)
+ if (vData && vData.nodeType) {
+ vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml;
+ if (!this._headers["Content-Type"]) {
+ this._object.setRequestHeader("Content-Type", "application/xml");
+ }
+ }
+
+ this._data = vData;
+
+ /**
+ * // Add to queue
+ * if (this._async) {
+ * fQueue_add(this);
+ * } else { */
+ fXMLHttpRequest_send(this);
+ /**
+ * }
+ */
+ };
+
+ cXMLHttpRequest.prototype.abort = function() {
+ // Add method sniffer
+ if (cXMLHttpRequest.onabort) {
+ cXMLHttpRequest.onabort.apply(this, arguments);
+ }
+
+ // BUGFIX: Gecko - unnecessary DONE when aborting
+ if (this.readyState > cXMLHttpRequest.UNSENT) {
+ this._aborted = true;
+ }
+
+ this._object.abort();
+
+ // BUGFIX: IE - memory leak
+ fCleanTransport(this);
+
+ this.readyState = cXMLHttpRequest.UNSENT;
+
+ delete this._data;
+
+ /* if (this._async) {
+ * fQueue_remove(this);
+ * }
+ */
+ };
+
+ cXMLHttpRequest.prototype.getAllResponseHeaders = function() {
+ return this._object.getAllResponseHeaders();
+ };
+
+ cXMLHttpRequest.prototype.getResponseHeader = function(sName) {
+ return this._object.getResponseHeader(sName);
+ };
+
+ cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) {
+ // BUGFIX: IE - cache issue
+ if (!this._headers) {
+ this._headers = {};
+ }
+
+ this._headers[sName] = sValue;
+
+ return this._object.setRequestHeader(sName, sValue);
+ };
+
+ // EventTarget interface implementation
+ cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) {
+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
+ if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) {
+ return;
+ }
+ }
+
+ // Add listener
+ this._listeners.push([sName, fHandler, bUseCapture]);
+ };
+
+ cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) {
+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
+ if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) {
+ break;
+ }
+ }
+
+ // Remove listener
+ if (oListener) {
+ this._listeners.splice(nIndex, 1);
+ }
+ };
+
+ cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) {
+ var oEventPseudo = {
+ 'type': oEvent.type,
+ 'target': this,
+ 'currentTarget': this,
+ 'eventPhase': 2,
+ 'bubbles': oEvent.bubbles,
+ 'cancelable': oEvent.cancelable,
+ 'timeStamp': oEvent.timeStamp,
+ 'stopPropagation': function() {}, // There is no flow
+ 'preventDefault': function() {}, // There is no default action
+ 'initEvent': function() {} // Original event object should be initialized
+ };
+
+ // Execute onreadystatechange
+ if (oEventPseudo.type == "readystatechange" && this.onreadystatechange) {
+ (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]);
+ }
+
+
+ // Execute listeners
+ for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) {
+ if (oListener[0] == oEventPseudo.type && !oListener[2]) {
+ (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]);
+ }
+ }
+
+ };
+
+ //
+ cXMLHttpRequest.prototype.toString = function() {
+ return '[' + "object" + ' ' + "XMLHttpRequest" + ']';
+ };
+
+ cXMLHttpRequest.toString = function() {
+ return '[' + "XMLHttpRequest" + ']';
+ };
+
+ /**
+ * // Queue manager
+ * var oQueuePending = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]},
+ * aQueueRunning = [];
+ * function fQueue_add(oRequest) {
+ * oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest);
+ * //
+ * setTimeout(fQueue_process);
+ * };
+ *
+ * function fQueue_remove(oRequest) {
+ * for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++)
+ * if (bFound) {
+ * aQueueRunning[nIndex - 1] = aQueueRunning[nIndex];
+ * } else {
+ * if (aQueueRunning[nIndex] == oRequest) {
+ * bFound = true;
+ * }
+ * }
+ *
+ * if (bFound) {
+ * aQueueRunning.length--;
+ * }
+ *
+ *
+ * //
+ * setTimeout(fQueue_process);
+ * };
+ *
+ * function fQueue_process() {
+ * if (aQueueRunning.length < 6) {
+ * for (var sPriority in oQueuePending) {
+ * if (oQueuePending[sPriority].length) {
+ * var oRequest = oQueuePending[sPriority][0];
+ * oQueuePending[sPriority] = oQueuePending[sPriority].slice(1);
+ * //
+ * aQueueRunning.push(oRequest);
+ * // Send request
+ * fXMLHttpRequest_send(oRequest);
+ * break;
+ * }
+ * }
+ * }
+ * };
+ */
+
+ // Helper function
+ function fXMLHttpRequest_send(oRequest) {
+ oRequest._object.send(oRequest._data);
+
+ // BUGFIX: Gecko - missing readystatechange calls in synchronous requests
+ if (bGecko && !oRequest._async) {
+ oRequest.readyState = cXMLHttpRequest.OPENED;
+
+ // Synchronize state
+ fSynchronizeValues(oRequest);
+
+ // Simulate missing states
+ while (oRequest.readyState < cXMLHttpRequest.DONE) {
+ oRequest.readyState++;
+ fReadyStateChange(oRequest);
+ // Check if we are aborted
+ if (oRequest._aborted) {
+ return;
+ }
+ }
+ }
+ }
+
+ function fReadyStateChange(oRequest) {
+ // Sniffing code
+ if (cXMLHttpRequest.onreadystatechange){
+ cXMLHttpRequest.onreadystatechange.apply(oRequest);
+ }
+
+
+ // Fake event
+ oRequest.dispatchEvent({
+ 'type': "readystatechange",
+ 'bubbles': false,
+ 'cancelable': false,
+ 'timeStamp': new Date + 0
+ });
+ }
+
+ function fGetDocument(oRequest) {
+ var oDocument = oRequest.responseXML;
+ var sResponse = oRequest.responseText;
+ // Try parsing responseText
+ if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) {
+ oDocument = new window.ActiveXObject("Microsoft.XMLDOM");
+ oDocument.async = false;
+ oDocument.validateOnParse = false;
+ oDocument.loadXML(sResponse);
+ }
+
+ // Check if there is no error in document
+ if (oDocument){
+ if ((bIE && oDocument.parseError !== 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror")) {
+ return null;
+ }
+ }
+ return oDocument;
+ }
+
+ function fSynchronizeValues(oRequest) {
+ try { oRequest.responseText = oRequest._object.responseText; } catch (e) {}
+ try { oRequest.responseXML = fGetDocument(oRequest._object); } catch (e) {}
+ try { oRequest.status = oRequest._object.status; } catch (e) {}
+ try { oRequest.statusText = oRequest._object.statusText; } catch (e) {}
+ }
+
+ function fCleanTransport(oRequest) {
+ // BUGFIX: IE - memory leak (on-page leak)
+ oRequest._object.onreadystatechange = new window.Function;
+ }
+
+ // Internet Explorer 5.0 (missing apply)
+ if (!window.Function.prototype.apply) {
+ window.Function.prototype.apply = function(oRequest, oArguments) {
+ if (!oArguments) {
+ oArguments = [];
+ }
+ oRequest.__func = this;
+ oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]);
+ delete oRequest.__func;
+ };
+ }
+
+ // Register new object with window
+ window.XMLHttpRequest = cXMLHttpRequest;
+
+})();
2,185 test/3rdparty/ZeParser.js
@@ -0,0 +1,2185 @@
+if (typeof exports !== 'undefined') {
+ var Tokenizer = require('./Tokenizer').Tokenizer;
+ exports.ZeParser = ZeParser;
+}
+
+/**
+ * This is my js Parser: Ze. It's actually the post-dev pre-cleanup version. Clearly.
+ * Some optimizations have been applied :)
+ * (c) Peter van der Zee, qfox.nl
+ * @param {String} inp Input
+ * @param {Tokenizer} tok
+ * @param {Array} stack The tokens will be put in this array. If you're looking for the AST, this would be it :)
+ */
+function ZeParser(inp, tok, stack, simple){
+ this.input = inp;
+ this.tokenizer = tok;
+ this.stack = stack;
+ this.stack.root = true;
+ this.scope = stack.scope = [{value:'this', isDeclared:true, isEcma:true, thisIsGlobal:true}]; // names of variables
+ this.scope.global = true;
+ this.statementLabels = [];
+
+ this.errorStack = [];
+
+ stack.scope = this.scope; // hook root
+ stack.labels = this.statementLabels;
+
+ this.regexLhsStart = ZeParser.regexLhsStart;
+/*
+ this.regexStartKeyword = ZeParser.regexStartKeyword;
+ this.regexKeyword = ZeParser.regexKeyword;
+ this.regexStartReserved = ZeParser.regexStartReserved;
+ this.regexReserved = ZeParser.regexReserved;
+*/
+ this.regexStartKeyOrReserved = ZeParser.regexStartKeyOrReserved;
+ this.hashStartKeyOrReserved = ZeParser.hashStartKeyOrReserved;
+ this.regexIsKeywordOrReserved = ZeParser.regexIsKeywordOrReserved;
+ this.regexAssignments = ZeParser.regexAssignments;
+ this.regexNonAssignmentBinaryExpressionOperators = ZeParser.regexNonAssignmentBinaryExpressionOperators;
+ this.regexUnaryKeywords = ZeParser.regexUnaryKeywords;
+ this.hashUnaryKeywordStart = ZeParser.hashUnaryKeywordStart;
+ this.regexUnaryOperators = ZeParser.regexUnaryOperators;
+ this.regexLiteralKeywords = ZeParser.regexLiteralKeywords;
+ this.testing = {'this':1,'null':1,'true':1,'false':1};
+
+ this.ast = !simple; ///#define FULL_AST
+};
+/**
+ * Returns just a stacked parse tree (regular array)
+ * @param {string} input
+ * @param {boolean} simple=false
+ * @return {Array}
+ */
+ZeParser.parse = function(input, simple){
+ var tok = new Tokenizer(input);
+ var stack = [];
+ try {
+ var parser = new ZeParser(input, tok, stack);
+ if (simple) parser.ast = false;
+ parser.parse();
+ return stack;
+ } catch (e) {
+ console.log("Parser has a bug for this input, please report it :)", e);
+ return null;
+ }
+};
+/**
+ * Returns a new parser instance with parse details for input
+ * @param {string} input
+ * @returns {ZeParser}
+ */
+ZeParser.createParser = function(input){
+ var tok = new Tokenizer(input);
+ var stack = [];
+ try {
+ var parser = new ZeParser(input, tok, stack);
+ parser.parse();
+ return parser;
+ } catch (e) {
+ console.log("Parser has a bug for this input, please report it :)", e);
+ return null;
+ }
+};
+ZeParser.prototype = {
+ input: null,
+ tokenizer: null,
+ stack: null,
+ scope: null,
+ statementLabels: null,
+ errorStack: null,
+
+ ast: null,
+
+ parse: function(match){
+ if (match) match = this.tokenizer.storeCurrentAndFetchNextToken(false, match, this.stack); // meh
+ else match = this.tokenizer.storeCurrentAndFetchNextToken(false, null, this.stack, true); // initialization step, dont store the match (there isnt any!)
+
+ match = this.eatSourceElements(match, this.stack);
+
+ var cycled = false;
+ do {
+ if (match && match.name != 12/*eof*/) {
+ // if not already an error, insert an error before it
+ if (match.name != 14/*error*/) this.failignore('UnexpectedToken', match, this.stack);
+ // just parse the token as is and continue.
+ match = this.tokenizer.storeCurrentAndFetchNextToken(false, match, this.stack);
+ cycled = true;
+ }
+
+ // keep gobbling any errors...
+ } while (match && match.name == 14/*error*/);
+
+ // now try again (but only if we gobbled at least one token)...
+ if (cycled && match && match.name != 12/*eof*/) match = this.parse(match);
+
+ // pop the last token off the stack if it caused an error at eof
+ if (this.tokenizer.errorEscape) {
+ this.stack.push(this.tokenizer.errorEscape);
+ this.tokenizer.errorEscape = null;
+ }
+
+ return match;
+ },
+
+ eatSemiColon: function(match, stack){
+ //this.stats.eatSemiColon = (+//this.stats.eatSemiColon||0)+1;
+ if (match.value == ';') match = this.tokenizer.storeCurrentAndFetchNextToken(false, match, stack);
+ else {
+ // try asi
+ // only if:
+ // - this token was preceeded by at least one newline (match.newline) or next token is }
+ // - this is EOF
+ // - prev token was one of return,continue,break,throw (restricted production), not checked here.
+
+ // the exceptions to this rule are
+ // - if the next line is a regex
+ // - the semi is part of the for-header.
+ // these exceptions are automatically caught by the way the parser is built
+
+ // not eof and just parsed semi or no newline preceeding and next isnt }
+ if (match.name != 12/*EOF*/ && (match.semi || (!match.newline && match.value != '}')) && !(match.newline && (match.value == '++' || match.value == '--'))) {
+ this.failignore('NoASI', match, stack);
+ } else {
+ // ASI
+ // (match is actually the match _after_ this asi, so the position of asi is match.start, not stop (!)
+ var asi = {start:match.start,stop:match.start,name:13/*ASI*/};
+ stack.push(asi);
+
+ // slip it in the stream, before the current match.
+ // for the other tokens see the tokenizer near the end of the main parsing function
+ this.tokenizer.addTokenToStreamBefore(asi, match);
+ }
+ }
+ match.semi = true;
+ return match;
+ },
+ /**
+ * Eat one or more "AssignmentExpression"s. May also eat a labeled statement if
+ * the parameters are set that way. This is the only way to linearly distinct between