You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2019/12/18 17:56:36 UTC
[couchdb-escodegen] 05/11: script upgrade
This is an automated email from the ASF dual-hosted git repository.
davisp pushed a commit to branch gh-pages
in repository https://gitbox.apache.org/repos/asf/couchdb-escodegen.git
commit 590f4f89abadf2a3f091b9a783bbfcaf5f7baea7
Author: Constellation <ut...@gmail.com>
AuthorDate: Thu Jun 7 15:57:29 2012 +0900
script upgrade
---
assets/esprima.js | 1364 ++++++++++++++++++++++++++++++++++++-----------------
escodegen.js | 781 ++++++++++++++++++++++++++----
2 files changed, 1636 insertions(+), 509 deletions(-)
diff --git a/assets/esprima.js b/assets/esprima.js
index 8a11eba..5fee256 100644
--- a/assets/esprima.js
+++ b/assets/esprima.js
@@ -28,14 +28,15 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/*jslint bitwise:true */
+/*jslint bitwise:true plusplus:true */
/*global esprima:true, exports:true,
throwError: true, createLiteral: true, generateStatement: true,
parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
parseFunctionDeclaration: true, parseFunctionExpression: true,
parseFunctionSourceElements: true, parseVariableIdentifier: true,
+parseImportSpecifier: true,
parseLeftHandSideExpression: true,
-parseStatement: true, parseSourceElement: true */
+parseStatement: true, parseSourceElement: true, parseModuleBlock: true */
(function (exports) {
'use strict';
@@ -47,19 +48,14 @@ parseStatement: true, parseSourceElement: true */
Messages,
Regex,
source,
- allowIn,
- lastParenthesized,
strict,
index,
lineNumber,
lineStart,
length,
buffer,
- extra,
- labelSet,
- inIteration,
- inSwitch,
- inFunctionBody;
+ state,
+ extra;
Token = {
BooleanLiteral: 1,
@@ -85,6 +81,7 @@ parseStatement: true, parseSourceElement: true */
Syntax = {
AssignmentExpression: 'AssignmentExpression',
ArrayExpression: 'ArrayExpression',
+ ArrayPattern: 'ArrayPattern',
BlockStatement: 'BlockStatement',
BinaryExpression: 'BinaryExpression',
BreakStatement: 'BreakStatement',
@@ -95,21 +92,32 @@ parseStatement: true, parseSourceElement: true */
DoWhileStatement: 'DoWhileStatement',
DebuggerStatement: 'DebuggerStatement',
EmptyStatement: 'EmptyStatement',
+ ExportSpecifier: 'ExportSpecifier',
+ ExportSpecifierSet: 'ExportSpecifierSet',
+ ExportDeclaration: 'ExportDeclaration',
ExpressionStatement: 'ExpressionStatement',
ForStatement: 'ForStatement',
ForInStatement: 'ForInStatement',
+ ForOfStatement: 'ForOfStatement',
FunctionDeclaration: 'FunctionDeclaration',
FunctionExpression: 'FunctionExpression',
+ Glob: 'Glob',
Identifier: 'Identifier',
IfStatement: 'IfStatement',
+ ImportDeclaration: 'ImportDeclaration',
+ ImportSpecifier: 'ImportSpecifier',
Literal: 'Literal',
LabeledStatement: 'LabeledStatement',
LogicalExpression: 'LogicalExpression',
MemberExpression: 'MemberExpression',
+ ModuleDeclaration: 'ModuleDeclaration',
NewExpression: 'NewExpression',
ObjectExpression: 'ObjectExpression',
+ ObjectPattern: 'ObjectPattern',
+ Path: 'Path',
Program: 'Program',
Property: 'Property',
+ ProtoExpression: 'ProtoExpression',
ReturnStatement: 'ReturnStatement',
SequenceExpression: 'SequenceExpression',
SwitchStatement: 'SwitchStatement',
@@ -140,6 +148,7 @@ parseStatement: true, parseSourceElement: true */
UnexpectedReserved: 'Unexpected reserved word',
UnexpectedEOS: 'Unexpected end of input',
NewlineAfterThrow: 'Illegal newline after throw',
+ NewlineAfterModule: 'Illegal newline after module',
InvalidRegExp: 'Invalid regular expression',
UnterminatedRegExp: 'Invalid regular expression: missing /',
InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
@@ -164,7 +173,8 @@ parseStatement: true, parseSourceElement: true */
StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
- StrictReservedWord: 'Use of future reserved word in strict mode'
+ StrictReservedWord: 'Use of future reserved word in strict mode',
+ NoFromAfterImport: 'Missing from after import'
};
// See also tools/generate-unicode-regex.py.
@@ -173,15 +183,6 @@ parseStatement: true, parseSourceElement: true */
NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u08 [...]
};
- if (typeof Object.freeze === 'function') {
- Object.freeze(Token);
- Object.freeze(TokenName);
- Object.freeze(Syntax);
- Object.freeze(PropertyKind);
- Object.freeze(Messages);
- Object.freeze(Regex);
- }
-
// 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.
@@ -338,18 +339,18 @@ parseStatement: true, parseSourceElement: true */
return true;
}
+ // Harmony
+ if (id === 'module') {
+ return true;
+ }
+
return isFutureReservedWord(id);
}
// Return the next character and move forward.
function nextChar() {
- var ch;
- if (index < length) {
- ch = source[index];
- index += 1;
- }
- return ch;
+ return source[index++];
}
// 7.4 Comments
@@ -368,18 +369,18 @@ parseStatement: true, parseSourceElement: true */
if (isLineTerminator(ch)) {
lineComment = false;
if (ch === '\r' && source[index] === '\n') {
- index += 1;
+ ++index;
}
- lineNumber += 1;
+ ++lineNumber;
lineStart = index;
}
} else if (blockComment) {
if (isLineTerminator(ch)) {
if (ch === '\r' && source[index + 1] === '\n') {
- index += 1;
+ ++index;
}
- lineNumber += 1;
- index += 1;
+ ++lineNumber;
+ ++index;
lineStart = index;
if (index >= length) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
@@ -392,7 +393,7 @@ parseStatement: true, parseSourceElement: true */
if (ch === '*') {
ch = source[index];
if (ch === '/') {
- index += 1;
+ ++index;
blockComment = false;
}
}
@@ -412,13 +413,13 @@ parseStatement: true, parseSourceElement: true */
break;
}
} else if (isWhiteSpace(ch)) {
- index += 1;
+ ++index;
} else if (isLineTerminator(ch)) {
- index += 1;
+ ++index;
if (ch === '\r' && source[index] === '\n') {
- index += 1;
+ ++index;
}
- lineNumber += 1;
+ ++lineNumber;
lineStart = index;
} else {
break;
@@ -430,7 +431,7 @@ parseStatement: true, parseSourceElement: true */
var i, len, ch, code = 0;
len = (prefix === 'u') ? 4 : 2;
- for (i = 0; i < len; i += 1) {
+ for (i = 0; i < len; ++i) {
if (index < length && isHexDigit(source[index])) {
ch = nextChar();
code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
@@ -451,11 +452,11 @@ parseStatement: true, parseSourceElement: true */
start = index;
if (ch === '\\') {
- index += 1;
+ ++index;
if (source[index] !== 'u') {
return;
}
- index += 1;
+ ++index;
restore = index;
ch = scanHexEscape('u');
if (ch) {
@@ -477,11 +478,11 @@ parseStatement: true, parseSourceElement: true */
break;
}
if (ch === '\\') {
- index += 1;
+ ++index;
if (source[index] !== 'u') {
return;
}
- index += 1;
+ ++index;
restore = index;
ch = scanHexEscape('u');
if (ch) {
@@ -565,7 +566,7 @@ parseStatement: true, parseSourceElement: true */
// Check for most common single-character punctuators.
if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
- index += 1;
+ ++index;
return {
type: Token.Punctuator,
value: ch1,
@@ -576,7 +577,7 @@ parseStatement: true, parseSourceElement: true */
}
if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
- index += 1;
+ ++index;
return {
type: Token.Punctuator,
value: ch1,
@@ -706,9 +707,31 @@ parseStatement: true, parseSourceElement: true */
}
}
+ if (ch1 === '<' && ch2 === '|') {
+ index += 2;
+ return {
+ type: Token.Punctuator,
+ value: '<|',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ if (ch1 === '=' && ch2 === '>') {
+ index += 2;
+ return {
+ type: Token.Punctuator,
+ value: '=>',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
// The remaining 1-character punctuators.
- if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
+ if ('[]<>+-*%&|^!~?:=#/'.indexOf(ch1) >= 0) {
return {
type: Token.Punctuator,
value: nextChar(),
@@ -722,7 +745,7 @@ parseStatement: true, parseSourceElement: true */
// 7.8.3 Numeric Literals
function scanNumericLiteral() {
- var number, start, ch;
+ var number, start, ch, octal;
ch = source[index];
assert(isDecimalDigit(ch) || (ch === '.'),
@@ -736,6 +759,8 @@ parseStatement: true, parseSourceElement: true */
// Hex number starts with '0x'.
// Octal number starts with '0'.
+ // Octal number in ES6 starts with '0o'.
+ // Binary number in ES6 starts with '0b'.
if (number === '0') {
if (ch === 'x' || ch === 'X') {
number += nextChar();
@@ -765,8 +790,46 @@ parseStatement: true, parseSourceElement: true */
lineStart: lineStart,
range: [start, index]
};
- } else if (isOctalDigit(ch)) {
- number += nextChar();
+ } else if (ch === 'b' || ch === 'B') {
+ nextChar();
+ number = '';
+
+ while (index < length) {
+ ch = source[index];
+ if (ch !== '0' && ch !== '1') {
+ break;
+ }
+ number += nextChar();
+ }
+
+ if (number.length === 0) {
+ // only 0b or 0B
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ if (index < length) {
+ ch = source[index];
+ if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ }
+ return {
+ type: Token.NumericLiteral,
+ value: parseInt(number, 2),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ } else if (ch === 'o' || ch === 'O' || isOctalDigit(ch)) {
+ if (isOctalDigit(ch)) {
+ octal = true;
+ number = nextChar();
+ } else {
+ octal = false;
+ nextChar();
+ number = '';
+ }
+
while (index < length) {
ch = source[index];
if (!isOctalDigit(ch)) {
@@ -775,16 +838,22 @@ parseStatement: true, parseSourceElement: true */
number += nextChar();
}
+ if (number.length === 0) {
+ // only 0o or 0O
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
if (index < length) {
ch = source[index];
if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
}
}
+
return {
type: Token.NumericLiteral,
value: parseInt(number, 8),
- octal: true,
+ octal: octal,
lineNumber: lineNumber,
lineStart: lineStart,
range: [start, index]
@@ -870,7 +939,7 @@ parseStatement: true, parseSourceElement: true */
'String literal must starts with a quote');
start = index;
- index += 1;
+ ++index;
while (index < length) {
ch = nextChar();
@@ -940,9 +1009,9 @@ parseStatement: true, parseSourceElement: true */
break;
}
} else {
- lineNumber += 1;
+ ++lineNumber;
if (ch === '\r' && source[index] === '\n') {
- index += 1;
+ ++index;
}
}
} else if (isLineTerminator(ch)) {
@@ -986,15 +1055,17 @@ parseStatement: true, parseSourceElement: true */
}
} else {
if (ch === '\\') {
- str += nextChar();
- }
- if (ch === '/') {
+ ch = nextChar();
+ // ECMA-262 7.8.5
+ if (isLineTerminator(ch)) {
+ throwError({}, Messages.UnterminatedRegExp);
+ }
+ str += ch;
+ } else if (ch === '/') {
break;
- }
- if (ch === '[') {
+ } else if (ch === '[') {
classMarker = true;
- }
- if (isLineTerminator(ch)) {
+ } else if (isLineTerminator(ch)) {
throwError({}, Messages.UnterminatedRegExp);
}
}
@@ -1014,17 +1085,17 @@ parseStatement: true, parseSourceElement: true */
break;
}
- index += 1;
+ ++index;
if (ch === '\\' && index < length) {
ch = source[index];
if (ch === 'u') {
- index += 1;
+ ++index;
restore = index;
ch = scanHexEscape('u');
if (ch) {
flags += ch;
str += '\\u';
- for (; restore < index; restore += 1) {
+ for (; restore < index; ++restore) {
str += source[restore];
}
} else {
@@ -1176,6 +1247,20 @@ parseStatement: true, parseSourceElement: true */
throw error;
}
+ function throwErrorTolerant() {
+ var error;
+ try {
+ throwError.apply(null, arguments);
+ } catch (e) {
+ if (extra.errors) {
+ extra.errors.push(e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+
// Throw an exception because of the token.
function throwUnexpected(token) {
@@ -1244,6 +1329,14 @@ parseStatement: true, parseSourceElement: true */
return token.type === Token.Keyword && token.value === keyword;
}
+
+ // Return true if the next token matches the specified contextual keyword
+
+ function matchContextualKeyword(keyword) {
+ var token = lookahead();
+ return token.type === Token.Identifier && token.value === keyword;
+ }
+
// Return true if the next token is an assignment operator
function matchAssign() {
@@ -1339,6 +1432,12 @@ parseStatement: true, parseSourceElement: true */
};
}
+ function parseSealedArrayInitialiser() {
+ var result = parseArrayInitialiser();
+ result.sealed = true;
+ return result;
+ }
+
// 11.1.5 Object Initialiser
function parsePropertyFunction(param, first) {
@@ -1359,61 +1458,85 @@ parseStatement: true, parseSourceElement: true */
};
}
+ function parsePropertyMethodFunction() {
+ var token, previousStrict, param, params, paramSet, method;
+
+ previousStrict = strict;
+ strict = true;
+ params = [];
+
+ expect('(');
+
+ if (!match(')')) {
+ paramSet = {};
+ while (index < length) {
+ token = lookahead();
+ param = parseVariableIdentifier();
+ if (isRestrictedWord(token.value)) {
+ throwError(token, Messages.StrictParamName);
+ }
+ if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+ throwError(token, Messages.StrictParamDupe);
+ }
+ params.push(param);
+ paramSet[param.name] = true;
+ if (match(')')) {
+ break;
+ }
+ expect(',');
+ }
+ }
+
+ expect(')');
+
+ method = parsePropertyFunction(params);
+
+ strict = previousStrict;
+
+ return method;
+ }
+
function parseObjectPropertyKey() {
- var token = lex(),
- key;
+ var token = lex();
- switch (token.type) {
+ // Note: This function is called only from parseObjectProperty(), where
+ // EOF and Punctuator tokens are already filtered out.
- case Token.StringLiteral:
- case Token.NumericLiteral:
+ if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
if (strict && token.octal) {
throwError(token, Messages.StrictOctalLiteral);
}
- key = createLiteral(token);
- break;
-
- case Token.Identifier:
- case Token.Keyword:
- case Token.BooleanLiteral:
- case Token.NullLiteral:
- key = {
- type: Syntax.Identifier,
- name: token.value
- };
- break;
-
- default:
- // Unreachable, since parseObjectProperty() will not call this
- // function with any other type of token.
+ return createLiteral(token);
}
- return key;
+ return {
+ type: Syntax.Identifier,
+ name: token.value
+ };
}
function parseObjectProperty() {
- var token, property, key, id, param;
+ var token, key, id, param;
token = lookahead();
- switch (token.type) {
+ if (token.type === Token.Identifier) {
- case Token.Identifier:
id = parseObjectPropertyKey();
// Property Assignment: Getter and Setter.
- if (token.value === 'get' && !match(':')) {
+ if (token.value === 'get' && !(match(':') || match('('))) {
key = parseObjectPropertyKey();
expect('(');
expect(')');
- property = {
+ return {
type: Syntax.Property,
key: key,
value: parsePropertyFunction([]),
kind: 'get'
};
- } else if (token.value === 'set' && !match(':')) {
+ } else if (token.value === 'set' && !(match(':') || match('('))) {
key = parseObjectPropertyKey();
expect('(');
token = lookahead();
@@ -1422,43 +1545,69 @@ parseStatement: true, parseSourceElement: true */
}
param = [ parseVariableIdentifier() ];
expect(')');
- property = {
+ return {
type: Syntax.Property,
key: key,
value: parsePropertyFunction(param, token),
kind: 'set'
};
} else {
- expect(':');
- property = {
+ if (match(':')) {
+ lex();
+ return {
+ type: Syntax.Property,
+ key: id,
+ value: parseAssignmentExpression(),
+ kind: 'init'
+ };
+ } else if (match('(')) {
+ return {
+ type: Syntax.Property,
+ key: id,
+ value: parsePropertyMethodFunction(),
+ kind: 'init',
+ method: true
+ };
+ } else {
+ return {
+ type: Syntax.Property,
+ key: id,
+ value: id,
+ kind: 'init',
+ shorthand: true
+ };
+ }
+ }
+ } else if (token.type === Token.EOF || token.type === Token.Punctuator) {
+ throwUnexpected(token);
+ } else {
+ key = parseObjectPropertyKey();
+ if (match(':')) {
+ lex();
+ return {
type: Syntax.Property,
- key: id,
+ key: key,
value: parseAssignmentExpression(),
kind: 'init'
};
+ } else if (match('(')) {
+ return {
+ type: Syntax.Property,
+ key: key,
+ value: parsePropertyMethodFunction(),
+ kind: 'init',
+ method: true
+ };
+ } else {
+ return {
+ type: Syntax.Property,
+ key: key,
+ value: key,
+ kind: 'init',
+ shorthand: true
+ };
}
- break;
-
- case Token.Keyword:
- case Token.BooleanLiteral:
- case Token.NullLiteral:
- case Token.StringLiteral:
- case Token.NumericLiteral:
- key = parseObjectPropertyKey();
- expect(':');
- property = {
- type: Syntax.Property,
- key: key,
- value: parseAssignmentExpression(),
- kind: 'init'
- };
- break;
-
- default:
- throwUnexpected(token);
}
-
- return property;
}
function parseObjectInitialiser() {
@@ -1478,7 +1627,7 @@ parseStatement: true, parseSourceElement: true */
if (Object.prototype.hasOwnProperty.call(map, name)) {
if (map[name] === PropertyKind.Data) {
if (strict && kind === PropertyKind.Data) {
- throwError({}, Messages.StrictDuplicateProperty);
+ throwErrorTolerant({}, Messages.StrictDuplicateProperty);
} else if (kind !== PropertyKind.Data) {
throwError({}, Messages.AccessorDataProperty);
}
@@ -1509,6 +1658,12 @@ parseStatement: true, parseSourceElement: true */
};
}
+ function parseSealedObjectInitialiser() {
+ var result = parseObjectInitialiser();
+ result.sealed = true;
+ return result;
+ }
+
// 11.1 Primary Expressions
function parsePrimaryExpression() {
@@ -1525,7 +1680,7 @@ parseStatement: true, parseSourceElement: true */
if (type === Token.StringLiteral || type === Token.NumericLiteral) {
if (strict && token.octal) {
- throwError(token, Messages.StrictOctalLiteral);
+ throwErrorTolerant(token, Messages.StrictOctalLiteral);
}
return createLiteral(lex());
}
@@ -1565,7 +1720,7 @@ parseStatement: true, parseSourceElement: true */
if (match('(')) {
lex();
- lastParenthesized = expr = parseExpression();
+ state.lastParenthesized = expr = parseExpression();
expect(')');
return expr;
}
@@ -1574,6 +1729,17 @@ parseStatement: true, parseSourceElement: true */
return createLiteral(scanRegExp());
}
+ if (match('#')) {
+ lex();
+ if (match('[')) {
+ return parseSealedArrayInitialiser();
+ }
+
+ if (match('{')) {
+ return parseSealedObjectInitialiser();
+ }
+ }
+
return throwUnexpected(lex());
}
@@ -1662,6 +1828,57 @@ parseStatement: true, parseSourceElement: true */
return expr;
}
+ function parseTriangleLiteral() {
+ var expr,
+ token = lookahead(),
+ type = token.type;
+
+ if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+ if (strict && token.octal) {
+ throwErrorTolerant(token, Messages.StrictOctalLiteral);
+ }
+ return createLiteral(lex());
+ }
+
+ if (type === Token.Keyword) {
+ if (matchKeyword('function')) {
+ return parseFunctionExpression();
+ }
+ }
+
+ if (type === Token.BooleanLiteral) {
+ lex();
+ token.value = (token.value === 'true');
+ return createLiteral(token);
+ }
+
+ if (match('[')) {
+ return parseArrayInitialiser();
+ }
+
+ if (match('{')) {
+ return parseObjectInitialiser();
+ }
+
+ if (match('/') || match('/=')) {
+ return createLiteral(scanRegExp());
+ }
+
+ // ArrowFunctionExpression
+ expr = parseExpression();
+
+ return parseArrowFunctionExpression(expr);
+ }
+
+ function parseProtoExpression(proto) {
+ expect('<|');
+ return {
+ type: Syntax.ProtoExpression,
+ proto: proto,
+ literal: parseTriangleLiteral()
+ };
+ }
+
function parseLeftHandSideExpressionAllowCall() {
var useNew, expr;
@@ -1674,6 +1891,8 @@ parseStatement: true, parseSourceElement: true */
expr = parseNonComputedMember(expr);
} else if (match('[')) {
expr = parseComputedMember(expr);
+ } else if (match('<|')) {
+ expr = parseProtoExpression(expr);
} else if (match('(')) {
expr = parseCallMember(expr);
} else {
@@ -1696,6 +1915,8 @@ parseStatement: true, parseSourceElement: true */
expr = parseNonComputedMember(expr);
} else if (match('[')) {
expr = parseComputedMember(expr);
+ } else if (match('<|')) {
+ expr = parseProtoExpression(expr);
} else {
break;
}
@@ -1762,7 +1983,7 @@ parseStatement: true, parseSourceElement: true */
argument: parseUnaryExpression()
};
if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
- throwError({}, Messages.StrictDelete);
+ throwErrorTolerant({}, Messages.StrictDelete);
}
return expr;
}
@@ -1825,10 +2046,10 @@ parseStatement: true, parseSourceElement: true */
function parseRelationalExpression() {
var expr, previousAllowIn;
- previousAllowIn = allowIn;
- allowIn = true;
+ previousAllowIn = state.allowIn;
+ state.allowIn = true;
expr = parseShiftExpression();
- allowIn = previousAllowIn;
+ state.allowIn = previousAllowIn;
if (match('<') || match('>') || match('<=') || match('>=')) {
expr = {
@@ -1837,7 +2058,7 @@ parseStatement: true, parseSourceElement: true */
left: expr,
right: parseRelationalExpression()
};
- } else if (allowIn && matchKeyword('in')) {
+ } else if (state.allowIn && matchKeyword('in')) {
lex();
expr = {
type: Syntax.BinaryExpression,
@@ -1863,7 +2084,7 @@ parseStatement: true, parseSourceElement: true */
function parseEqualityExpression() {
var expr = parseRelationalExpression();
- while (match('==') || match('!=') || match('===') || match('!==')) {
+ while ((!peekLineTerminator() && (matchContextualKeyword('is') || matchContextualKeyword('isnt'))) || match('==') || match('!=') || match('===') || match('!==')) {
expr = {
type: Syntax.BinaryExpression,
operator: lex().value,
@@ -1968,10 +2189,10 @@ parseStatement: true, parseSourceElement: true */
if (match('?')) {
lex();
- previousAllowIn = allowIn;
- allowIn = true;
+ previousAllowIn = state.allowIn;
+ state.allowIn = true;
consequent = parseAssignmentExpression();
- allowIn = previousAllowIn;
+ state.allowIn = previousAllowIn;
expect(':');
expr = {
@@ -1987,6 +2208,81 @@ parseStatement: true, parseSourceElement: true */
// 11.13 Assignment Operators
+ function reinterpretAsAssignmentBindingPattern(expr) {
+ var i, len, property, element;
+
+ if (expr.sealed) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+
+ if (expr.type === Syntax.ObjectExpression) {
+ expr.type = Syntax.ObjectPattern;
+ for (i = 0, len = expr.properties.length; i < len; i += 1) {
+ property = expr.properties[i];
+ if (property.kind !== 'init') {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ reinterpretAsAssignmentBindingPattern(property.value);
+ }
+ } else if (expr.type === Syntax.ArrayExpression) {
+ expr.type = Syntax.ArrayPattern;
+ for (i = 0, len = expr.elements.length; i < len; i += 1) {
+ element = expr.elements[i];
+ if (element) {
+ reinterpretAsAssignmentBindingPattern(element);
+ }
+ }
+ } else if (expr.type === Syntax.Identifier) {
+ if (isRestrictedWord(expr.name)) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ } else {
+ if (expr.type !== Syntax.MemberExpression && expr.type !== Syntax.CallExpression && expr.type !== Syntax.NewExpression) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ }
+ }
+
+ function reinterpretAsCoverFormalsList(expr) {
+ if (state.lastParenthesized !== expr) {
+ if (expr.type === Syntax.Identifier) {
+ // e => ConciseBody style
+ return [ expr ];
+ }
+ throwError({}, Messages.InvalidCoverFormalsList);
+ }
+
+ if (expr.type === Syntax.Identifier) {
+ // (e) => ConciseBody style
+ return [ expr ];
+ }
+
+ if (expr.type !== Syntax.SequenceExpression) {
+ throwError({}, Messages.InvalidCoverFormalsList);
+ }
+
+ return expr;
+ }
+
+ function parseArrowFunctionExpression(expr) {
+ var params, previousStrict;
+
+ params = reinterpretAsCoverFormalsList(expr);
+
+ expect('=>');
+
+ previousStrict = strict;
+ strict = true;
+ expr = {
+ type: Syntax.ArrowFunctionExpression,
+ params: params,
+ body: parseConciseBody()
+ };
+ strict = previousStrict;
+
+ return expr;
+ }
+
function parseAssignmentExpression() {
var expr;
@@ -1994,7 +2290,7 @@ parseStatement: true, parseSourceElement: true */
if (matchAssign()) {
// LeftHandSideExpression
- if (lastParenthesized !== expr && !isLeftHandSide(expr)) {
+ if (state.lastParenthesized !== expr && !isLeftHandSide(expr)) {
throwError({}, Messages.InvalidLHSInAssignment);
}
@@ -2003,12 +2299,20 @@ parseStatement: true, parseSourceElement: true */
throwError({}, Messages.StrictLHSAssignment);
}
+ // ES.next draf 11.13 Runtime Semantics step 1
+ if (expr.type === Syntax.ObjectExpression || expr.type === Syntax.ArrayExpression) {
+ reinterpretAsAssignmentBindingPattern(expr);
+ }
+
expr = {
type: Syntax.AssignmentExpression,
operator: lex().value,
left: expr,
right: parseAssignmentExpression()
};
+ } else if (match('=>')) {
+ lex();
+ return parseArrowFunctionExpression(expr);
}
return expr;
@@ -2093,7 +2397,7 @@ parseStatement: true, parseSourceElement: true */
// 12.2.1
if (strict && isRestrictedWord(id.name)) {
- throwError({}, Messages.StrictVarName);
+ throwErrorTolerant({}, Messages.StrictVarName);
}
if (kind === 'const') {
@@ -2161,17 +2465,255 @@ parseStatement: true, parseSourceElement: true */
};
}
- // 12.3 Empty Statement
+ // http://wiki.ecmascript.org/doku.php?id=harmony:modules
- function parseEmptyStatement() {
- expect(';');
+ function parsePath() {
+ var result, id;
- return {
- type: Syntax.EmptyStatement
+ result = {
+ type: Syntax.Path,
+ body: []
};
- }
- // 12.4 Expression Statement
+ while (true) {
+ id = parseVariableIdentifier();
+ result.body.push(id);
+ if (!match('.')) {
+ break;
+ }
+ lex();
+ }
+
+ return result;
+ }
+
+ function parseGlob() {
+ expect('*');
+ return {
+ type: Syntax.Glob
+ };
+ }
+
+ function parseModuleDeclaration() {
+ var id, token, declaration;
+
+ expectKeyword('module');
+
+ if (peekLineTerminator()) {
+ throwError({}, Messages.NewlineAfterModule);
+ }
+
+ id = parseVariableIdentifier();
+
+ if (match('{')) {
+ return {
+ type: Syntax.ModuleDeclaration,
+ id: id,
+ body: parseModuleBlock()
+ };
+ }
+
+ expect('=');
+
+ token = lookahead();
+ if (token.type === Token.StringLiteral) {
+ declaration = {
+ type: Syntax.ModuleDeclaration,
+ id: id,
+ from: parsePrimaryExpression()
+ };
+ } else {
+ declaration = {
+ type: Syntax.ModuleDeclaration,
+ id: id,
+ from: parsePath()
+ };
+ }
+
+ consumeSemicolon();
+
+ return declaration;
+ }
+
+ function parseExportSpecifierSetProperty() {
+ var specifier;
+
+ specifier = {
+ type: Syntax.ExportSpecifier,
+ id: parseVariableIdentifier(),
+ from: null
+ };
+
+ if (match(':')) {
+ lex();
+ specifier.from = parsePath();
+ }
+
+ return specifier;
+ }
+
+ function parseExportSpecifier() {
+ var specifier, specifiers;
+
+ if (match('{')) {
+ lex();
+ specifiers = [];
+
+ do {
+ specifiers.push(parseExportSpecifierSetProperty());
+ } while (match(',') && lex());
+
+ expect('}');
+
+ return {
+ type: Syntax.ExportSpecifierSet,
+ specifiers: specifiers
+ };
+ }
+
+ if (match('*')) {
+ specifier = {
+ type: Syntax.ExportSpecifier,
+ id: parseGlob(),
+ from: null
+ };
+
+ if (matchContextualKeyword('from')) {
+ lex();
+ specifier.from = parsePath();
+ }
+ } else {
+ specifier = {
+ type: Syntax.ExportSpecifier,
+ id: parseVariableIdentifier(),
+ from: null
+ };
+ }
+ return specifier;
+ }
+
+ function parseExportDeclaration() {
+ var id, token, declaration, specifiers;
+
+ expectKeyword('export');
+
+ token = lookahead();
+
+ if (token.type === Token.Keyword) {
+ switch (token.value) {
+ case 'function':
+ return {
+ type: Syntax.ExportDeclaration,
+ declaration: parseFunctionDeclaration()
+ };
+ case 'module':
+ return {
+ type: Syntax.ExportDeclaration,
+ declaration: parseModuleDeclaration()
+ };
+ case 'let':
+ case 'const':
+ return {
+ type: Syntax.ExportDeclaration,
+ declaration: parseConstLetDeclaration(token.value)
+ };
+ case 'var':
+ return {
+ type: Syntax.ExportDeclaration,
+ declaration: parseStatement()
+ };
+ }
+ throwUnexpected(lex());
+ }
+
+ specifiers = [ parseExportSpecifier() ];
+ if (match(',')) {
+ while (index < length) {
+ if (!match(',')) {
+ break;
+ }
+ lex();
+ specifiers.push(parseExportSpecifier());
+ }
+ }
+
+ consumeSemicolon();
+
+ return {
+ type: Syntax.ExportDeclaration,
+ specifiers: specifiers
+ };
+ }
+
+ function parseImportDeclaration() {
+ var specifiers, from;
+
+ expectKeyword('import');
+
+ if (match('*')) {
+ specifiers = [parseGlob()];
+ } else if (match('{')) {
+ lex();
+ specifiers = [];
+
+ do {
+ specifiers.push(parseImportSpecifier());
+ } while (match(',') && lex());
+
+ expect('}');
+ } else {
+ specifiers = [parseVariableIdentifier()];
+ }
+
+ if (!matchContextualKeyword('from')) {
+ throwError({}, Messages.NoFromAfterImport);
+ }
+
+ lex();
+
+ if (lookahead().type === Token.StringLiteral) {
+ from = parsePrimaryExpression();
+ } else {
+ from = parsePath();
+ }
+
+ consumeSemicolon();
+
+ return {
+ type: Syntax.ImportDeclaration,
+ specifiers: specifiers,
+ from: from
+ };
+ }
+
+ function parseImportSpecifier() {
+ var specifier;
+
+ specifier = {
+ type: Syntax.ImportSpecifier,
+ id: parseVariableIdentifier(),
+ from: null
+ };
+
+ if (match(':')) {
+ lex();
+ specifier.from = parsePath();
+ }
+
+ return specifier;
+ }
+
+ // 12.3 Empty Statement
+
+ function parseEmptyStatement() {
+ expect(';');
+
+ return {
+ type: Syntax.EmptyStatement
+ };
+ }
+
+ // 12.4 Expression Statement
function parseExpressionStatement() {
var expr = parseExpression();
@@ -2221,12 +2763,12 @@ parseStatement: true, parseSourceElement: true */
expectKeyword('do');
- oldInIteration = inIteration;
- inIteration = true;
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
body = parseStatement();
- inIteration = oldInIteration;
+ state.inIteration = oldInIteration;
expectKeyword('while');
@@ -2258,12 +2800,12 @@ parseStatement: true, parseSourceElement: true */
expect(')');
- oldInIteration = inIteration;
- inIteration = true;
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
body = parseStatement();
- inIteration = oldInIteration;
+ state.inIteration = oldInIteration;
return {
type: Syntax.WhileStatement,
@@ -2283,7 +2825,7 @@ parseStatement: true, parseSourceElement: true */
}
function parseForStatement() {
- var init, test, update, left, right, body, oldInIteration;
+ var init, test, update, left, right, body, operator, oldInIteration, i, len;
init = test = update = null;
@@ -2294,28 +2836,38 @@ parseStatement: true, parseSourceElement: true */
if (match(';')) {
lex();
} else {
- if (matchKeyword('var') || matchKeyword('let')) {
- allowIn = false;
+ if (matchKeyword('var') || matchKeyword('let') || matchKeyword('const')) {
+ state.allowIn = false;
init = parseForVariableDeclaration();
- allowIn = true;
-
- if (init.declarations.length === 1 && matchKeyword('in')) {
- lex();
- left = init;
- right = parseExpression();
- init = null;
+ state.allowIn = true;
+
+ if (init.declarations.length === 1) {
+ if (matchKeyword('in') || matchContextualKeyword('of')) {
+ operator = lookahead();
+ if (!((operator.value === 'in' || init.kind !== 'var') && init.declarations[0].init)) {
+ lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ }
+ }
}
} else {
- allowIn = false;
+ state.allowIn = false;
init = parseExpression();
- allowIn = true;
+ state.allowIn = true;
- if (matchKeyword('in')) {
+ if (matchContextualKeyword('of')) {
+ operator = lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ } else if (matchKeyword('in')) {
// LeftHandSideExpression
- if (matchKeyword('in') && (lastParenthesized !== init && !isLeftHandSide(init))) {
+ if (matchKeyword('in') && (state.lastParenthesized !== init && !isLeftHandSide(init))) {
throwError({}, Messages.InvalidLHSInForIn);
}
- lex();
+ operator = lex();
left = init;
right = parseExpression();
init = null;
@@ -2341,12 +2893,12 @@ parseStatement: true, parseSourceElement: true */
expect(')');
- oldInIteration = inIteration;
- inIteration = true;
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
body = parseStatement();
- inIteration = oldInIteration;
+ state.inIteration = oldInIteration;
if (typeof left === 'undefined') {
return {
@@ -2358,13 +2910,23 @@ parseStatement: true, parseSourceElement: true */
};
}
- return {
- type: Syntax.ForInStatement,
- left: left,
- right: right,
- body: body,
- each: false
- };
+ if (operator.value === 'in') {
+ return {
+ type: Syntax.ForInStatement,
+ left: left,
+ right: right,
+ body: body,
+ each: false
+ };
+ } else {
+ return {
+ type: Syntax.ForOfStatement,
+ left: left,
+ right: right,
+ body: body,
+ each: false
+ };
+ }
}
// 12.7 The continue statement
@@ -2377,8 +2939,8 @@ parseStatement: true, parseSourceElement: true */
// Optimize the most common form: 'continue;'.
if (source[index] === ';') {
lex();
-
- if (!inIteration) {
+
+ if (!state.inIteration) {
throwError({}, Messages.IllegalContinue);
}
@@ -2389,7 +2951,7 @@ parseStatement: true, parseSourceElement: true */
}
if (peekLineTerminator()) {
- if (!inIteration) {
+ if (!state.inIteration) {
throwError({}, Messages.IllegalContinue);
}
@@ -2403,14 +2965,14 @@ parseStatement: true, parseSourceElement: true */
if (token.type === Token.Identifier) {
label = parseVariableIdentifier();
- if (!Object.prototype.hasOwnProperty.call(labelSet, label.name)) {
+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
throwError({}, Messages.UnknownLabel, label.name);
}
}
consumeSemicolon();
- if (label === null && !inIteration) {
+ if (label === null && !state.inIteration) {
throwError({}, Messages.IllegalContinue);
}
@@ -2430,8 +2992,8 @@ parseStatement: true, parseSourceElement: true */
// Optimize the most common form: 'break;'.
if (source[index] === ';') {
lex();
-
- if (!(inIteration || inSwitch)) {
+
+ if (!(state.inIteration || state.inSwitch)) {
throwError({}, Messages.IllegalBreak);
}
@@ -2442,7 +3004,7 @@ parseStatement: true, parseSourceElement: true */
}
if (peekLineTerminator()) {
- if (!(inIteration || inSwitch)) {
+ if (!(state.inIteration || state.inSwitch)) {
throwError({}, Messages.IllegalBreak);
}
@@ -2456,14 +3018,14 @@ parseStatement: true, parseSourceElement: true */
if (token.type === Token.Identifier) {
label = parseVariableIdentifier();
- if (!Object.prototype.hasOwnProperty.call(labelSet, label.name)) {
+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
throwError({}, Messages.UnknownLabel, label.name);
}
}
consumeSemicolon();
- if (label === null && !(inIteration || inSwitch)) {
+ if (label === null && !(state.inIteration || state.inSwitch)) {
throwError({}, Messages.IllegalBreak);
}
@@ -2480,8 +3042,8 @@ parseStatement: true, parseSourceElement: true */
expectKeyword('return');
- if (!inFunctionBody) {
- throwError({}, Messages.IllegalReturn);
+ if (!state.inFunctionBody) {
+ throwErrorTolerant({}, Messages.IllegalReturn);
}
// 'return' followed by a space and an identifier is very common.
@@ -2524,7 +3086,7 @@ parseStatement: true, parseSourceElement: true */
var object, body;
if (strict) {
- throwError({}, Messages.StrictModeWith);
+ throwErrorTolerant({}, Messages.StrictModeWith);
}
expectKeyword('with');
@@ -2546,10 +3108,20 @@ parseStatement: true, parseSourceElement: true */
// 12.10 The swith statement
- function parseSwitchCase(test) {
- var consequent = [],
+ function parseSwitchCase() {
+ var test,
+ consequent = [],
statement;
+ if (matchKeyword('default')) {
+ lex();
+ test = null;
+ } else {
+ expectKeyword('case');
+ test = parseExpression();
+ }
+ expect(':');
+
while (index < length) {
if (match('}') || matchKeyword('default') || matchKeyword('case')) {
break;
@@ -2569,7 +3141,7 @@ parseStatement: true, parseSourceElement: true */
}
function parseSwitchStatement() {
- var discriminant, cases, test, oldInSwitch;
+ var discriminant, cases, oldInSwitch;
expectKeyword('switch');
@@ -2591,27 +3163,17 @@ parseStatement: true, parseSourceElement: true */
cases = [];
- oldInSwitch = inSwitch;
- inSwitch = true;
+ oldInSwitch = state.inSwitch;
+ state.inSwitch = true;
while (index < length) {
if (match('}')) {
break;
}
-
- if (matchKeyword('default')) {
- lex();
- test = null;
- } else {
- expectKeyword('case');
- test = parseExpression();
- }
- expect(':');
-
- cases.push(parseSwitchCase(test));
+ cases.push(parseSwitchCase());
}
- inSwitch = oldInSwitch;
+ state.inSwitch = oldInSwitch;
expect('}');
@@ -2655,7 +3217,7 @@ parseStatement: true, parseSourceElement: true */
param = parseExpression();
// 12.14.1
if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
- throwError({}, Messages.StrictCatchVariable);
+ throwErrorTolerant({}, Messages.StrictCatchVariable);
}
}
expect(')');
@@ -2773,13 +3335,13 @@ parseStatement: true, parseSourceElement: true */
if ((expr.type === Syntax.Identifier) && match(':')) {
lex();
- if (Object.prototype.hasOwnProperty.call(labelSet, expr.name)) {
+ if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) {
throwError({}, Messages.Redeclaration, 'Label', expr.name);
}
- labelSet[expr.name] = true;
+ state.labelSet[expr.name] = true;
labeledBody = parseStatement();
- delete labelSet[expr.name];
+ delete state.labelSet[expr.name];
return {
type: Syntax.LabeledStatement,
@@ -2799,7 +3361,8 @@ parseStatement: true, parseSourceElement: true */
// 13 Function Definition
function parseFunctionSourceElements() {
- var sourceElement, sourceElements = [], token, directive, firstRestricted, oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
+ var sourceElement, sourceElements = [], token, directive, firstRestricted,
+ oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
expect('{');
@@ -2828,15 +3391,15 @@ parseStatement: true, parseSourceElement: true */
}
}
- oldLabelSet = labelSet;
- oldInIteration = inIteration;
- oldInSwitch = inSwitch;
- oldInFunctionBody = inFunctionBody;
+ oldLabelSet = state.labelSet;
+ oldInIteration = state.inIteration;
+ oldInSwitch = state.inSwitch;
+ oldInFunctionBody = state.inFunctionBody;
- labelSet = {};
- inIteration = false;
- inSwitch = false;
- inFunctionBody = true;
+ state.labelSet = {};
+ state.inIteration = false;
+ state.inSwitch = false;
+ state.inFunctionBody = true;
while (index < length) {
if (match('}')) {
@@ -2851,10 +3414,10 @@ parseStatement: true, parseSourceElement: true */
expect('}');
- labelSet = oldLabelSet;
- inIteration = oldInIteration;
- inSwitch = oldInSwitch;
- inFunctionBody = oldInFunctionBody;
+ state.labelSet = oldLabelSet;
+ state.inIteration = oldInIteration;
+ state.inSwitch = oldInSwitch;
+ state.inFunctionBody = oldInFunctionBody;
return {
type: Syntax.BlockStatement,
@@ -3031,7 +3594,24 @@ parseStatement: true, parseSourceElement: true */
}
}
- function parseSourceElements() {
+ function parseProgramElement() {
+ var token = lookahead();
+
+ if (token.type === Token.Keyword) {
+ switch (token.value) {
+ case 'module':
+ return parseModuleDeclaration(token.value);
+ case 'export':
+ return parseExportDeclaration();
+ case 'import':
+ return parseImportDeclaration();
+ }
+ }
+
+ return parseSourceElement();
+ }
+
+ function parseProgramElements() {
var sourceElement, sourceElements = [], token, directive, firstRestricted;
while (index < length) {
@@ -3040,7 +3620,7 @@ parseStatement: true, parseSourceElement: true */
break;
}
- sourceElement = parseSourceElement();
+ sourceElement = parseProgramElement();
sourceElements.push(sourceElement);
if (sourceElement.expression.type !== Syntax.Literal) {
// this is not directive
@@ -3060,7 +3640,7 @@ parseStatement: true, parseSourceElement: true */
}
while (index < length) {
- sourceElement = parseSourceElement();
+ sourceElement = parseProgramElement();
if (typeof sourceElement === 'undefined') {
break;
}
@@ -3069,12 +3649,49 @@ parseStatement: true, parseSourceElement: true */
return sourceElements;
}
+ function parseModuleElement() {
+ return parseProgramElement();
+ }
+
+ function parseModuleElements() {
+ var list = [],
+ statement;
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ statement = parseModuleElement();
+ if (typeof statement === 'undefined') {
+ break;
+ }
+ list.push(statement);
+ }
+
+ return list;
+ }
+
+ function parseModuleBlock() {
+ var block;
+
+ expect('{');
+
+ block = parseModuleElements();
+
+ expect('}');
+
+ return {
+ type: Syntax.BlockStatement,
+ body: block
+ };
+ }
+
function parseProgram() {
var program;
strict = false;
program = {
type: Syntax.Program,
- body: parseSourceElements()
+ body: parseProgramElements()
};
return program;
}
@@ -3083,9 +3700,7 @@ parseStatement: true, parseSourceElement: true */
// the comments is active.
function addComment(start, end, type, value) {
- if (typeof start !== 'number') {
- return;
- }
+ assert(typeof start === 'number', 'Comment must have valid position');
// Because the way the actual token is scanned, often the comments
// (if any) are skipped twice during the lexical analysis.
@@ -3116,13 +3731,17 @@ parseStatement: true, parseSourceElement: true */
if (lineComment) {
ch = nextChar();
- if (isLineTerminator(ch)) {
+ if (index >= length) {
+ lineComment = false;
+ comment += ch;
+ addComment(start, index, 'Line', comment);
+ } else if (isLineTerminator(ch)) {
lineComment = false;
- addComment(start, index - 1, 'Line', comment);
+ addComment(start, index, 'Line', comment);
if (ch === '\r' && source[index] === '\n') {
- index += 1;
+ ++index;
}
- lineNumber += 1;
+ ++lineNumber;
lineStart = index;
comment = '';
} else {
@@ -3131,10 +3750,13 @@ parseStatement: true, parseSourceElement: true */
} else if (blockComment) {
if (isLineTerminator(ch)) {
if (ch === '\r' && source[index + 1] === '\n') {
- index += 1;
+ ++index;
+ comment += '\r\n';
+ } else {
+ comment += ch;
}
- lineNumber += 1;
- index += 1;
+ ++lineNumber;
+ ++index;
lineStart = index;
if (index >= length) {
throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
@@ -3150,8 +3772,8 @@ parseStatement: true, parseSourceElement: true */
if (ch === '/') {
comment = comment.substr(0, comment.length - 1);
blockComment = false;
- index += 1;
- addComment(start, index - 1, 'Block', comment);
+ ++index;
+ addComment(start, index, 'Block', comment);
comment = '';
}
}
@@ -3173,20 +3795,18 @@ parseStatement: true, parseSourceElement: true */
break;
}
} else if (isWhiteSpace(ch)) {
- index += 1;
+ ++index;
} else if (isLineTerminator(ch)) {
- index += 1;
+ ++index;
if (ch === '\r' && source[index] === '\n') {
- index += 1;
+ ++index;
}
- lineNumber += 1;
+ ++lineNumber;
lineStart = index;
} else {
break;
}
}
-
- addComment(start, index, (blockComment) ? 'Block' : 'Line', comment);
}
function collectToken() {
@@ -3195,7 +3815,7 @@ parseStatement: true, parseSourceElement: true */
value;
if (token.type !== Token.EOF) {
- range = [token.range[0], token.range[1] - 1];
+ range = [token.range[0], token.range[1]];
value = sliceSource(token.range[0], token.range[1]);
extra.tokens.push({
type: TokenName[token.type],
@@ -3228,7 +3848,7 @@ parseStatement: true, parseSourceElement: true */
extra.tokens.push({
type: 'RegularExpression',
value: regex.literal,
- range: [pos, index - 1]
+ range: [pos, index]
});
return regex;
@@ -3259,34 +3879,21 @@ parseStatement: true, parseSourceElement: true */
}
function visit(node) {
- if (range) {
- if (isBinary(node.left) && (typeof node.left.range === 'undefined')) {
- visit(node.left);
- }
- if (isBinary(node.right) && (typeof node.right.range === 'undefined')) {
- visit(node.right);
- }
-
- // Expression enclosed in brackets () already has the correct range.
- if (typeof node.range === 'undefined') {
- node.range = [node.left.range[0], node.right.range[1]];
- }
+ if (isBinary(node.left)) {
+ visit(node.left);
+ }
+ if (isBinary(node.right)) {
+ visit(node.right);
}
- if (loc) {
- if (isBinary(node.left) && (typeof node.left.loc === 'undefined')) {
- visit(node.left);
- }
- if (isBinary(node.right) && (typeof node.right.loc === 'undefined')) {
- visit(node.right);
- }
-
- if (typeof node.loc === 'undefined') {
- node.loc = {
- start: node.left.loc.start,
- end: node.right.loc.end
- };
- }
+ if (range && typeof node.range === 'undefined') {
+ node.range = [node.left.range[0], node.right.range[1]];
+ }
+ if (loc && typeof node.loc === 'undefined') {
+ node.loc = {
+ start: node.left.loc.start,
+ end: node.right.loc.end
+ };
}
}
@@ -3306,7 +3913,7 @@ parseStatement: true, parseSourceElement: true */
if (typeof node !== 'undefined') {
if (range) {
- rangeInfo[1] = index - 1;
+ rangeInfo[1] = index;
node.range = rangeInfo;
}
@@ -3368,26 +3975,37 @@ parseStatement: true, parseSourceElement: true */
extra.parseConditionalExpression = parseConditionalExpression;
extra.parseConstLetDeclaration = parseConstLetDeclaration;
extra.parseEqualityExpression = parseEqualityExpression;
+ extra.parseExportDeclaration = parseExportDeclaration;
+ extra.parseExportSpecifier = parseExportSpecifier;
+ extra.parseExportSpecifierSetProperty = parseExportSpecifierSetProperty;
extra.parseExpression = parseExpression;
extra.parseForVariableDeclaration = parseForVariableDeclaration;
extra.parseFunctionDeclaration = parseFunctionDeclaration;
extra.parseFunctionExpression = parseFunctionExpression;
+ extra.parseGlob = parseGlob;
+ extra.parseImportDeclaration = parseImportDeclaration;
+ extra.parseImportSpecifier = parseImportSpecifier;
extra.parseLogicalANDExpression = parseLogicalANDExpression;
extra.parseLogicalORExpression = parseLogicalORExpression;
extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
+ extra.parseModuleDeclaration = parseModuleDeclaration;
+ extra.parseModuleBlock = parseModuleBlock;
extra.parseNewExpression = parseNewExpression;
extra.parseNonComputedMember = parseNonComputedMember;
extra.parseNonComputedProperty = parseNonComputedProperty;
extra.parseObjectProperty = parseObjectProperty;
extra.parseObjectPropertyKey = parseObjectPropertyKey;
+ extra.parsePath = parsePath;
extra.parsePostfixExpression = parsePostfixExpression;
extra.parsePrimaryExpression = parsePrimaryExpression;
extra.parseProgram = parseProgram;
extra.parsePropertyFunction = parsePropertyFunction;
+ extra.parseProtoExpression = parseProtoExpression;
extra.parseRelationalExpression = parseRelationalExpression;
extra.parseStatement = parseStatement;
extra.parseShiftExpression = parseShiftExpression;
extra.parseSwitchCase = parseSwitchCase;
+ extra.parseTriangleLiteral = parseTriangleLiteral;
extra.parseUnaryExpression = parseUnaryExpression;
extra.parseVariableDeclaration = parseVariableDeclaration;
extra.parseVariableIdentifier = parseVariableIdentifier;
@@ -3404,27 +4022,38 @@ parseStatement: true, parseSourceElement: true */
parseComputedMember = wrapTracking(extra.parseComputedMember);
parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
+ parseExportDeclaration = wrapTracking(parseExportDeclaration);
+ parseExportSpecifier = wrapTracking(parseExportSpecifier);
+ parseExportSpecifierSetProperty = wrapTracking(parseExportSpecifierSetProperty);
parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
parseExpression = wrapTracking(extra.parseExpression);
parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
+ parseGlob = wrapTracking(extra.parseGlob);
+ parseImportDeclaration = wrapTracking(extra.parseImportDeclaration);
+ parseImportSpecifier = wrapTracking(extra.parseImportSpecifier);
parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
+ parseModuleDeclaration = wrapTracking(extra.parseModuleDeclaration);
+ parseModuleBlock = wrapTracking(extra.parseModuleBlock);
parseNewExpression = wrapTracking(extra.parseNewExpression);
parseNonComputedMember = wrapTracking(extra.parseNonComputedMember);
parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
parseObjectProperty = wrapTracking(extra.parseObjectProperty);
parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
+ parsePath = wrapTracking(extra.parsePath);
parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
parseProgram = wrapTracking(extra.parseProgram);
parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
+ parseProtoExpression = wrapTracking(parseProtoExpression);
parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
parseStatement = wrapTracking(extra.parseStatement);
parseShiftExpression = wrapTracking(extra.parseShiftExpression);
parseSwitchCase = wrapTracking(extra.parseSwitchCase);
+ parseTriangleLiteral = wrapTracking(extra.parseTriangleLiteral);
parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
@@ -3462,26 +4091,37 @@ parseStatement: true, parseSourceElement: true */
parseConditionalExpression = extra.parseConditionalExpression;
parseConstLetDeclaration = extra.parseConstLetDeclaration;
parseEqualityExpression = extra.parseEqualityExpression;
+ parseExportDeclaration = extra.parseExportDeclaration;
+ parseExportSpecifier = extra.parseExportSpecifier;
+ parseExportSpecifierSetProperty = extra.parseExportSpecifierSetProperty;
parseExpression = extra.parseExpression;
parseForVariableDeclaration = extra.parseForVariableDeclaration;
parseFunctionDeclaration = extra.parseFunctionDeclaration;
parseFunctionExpression = extra.parseFunctionExpression;
+ parseGlob = extra.parseGlob;
+ parseImportDeclaration = extra.parseImportDeclaration;
+ parseImportSpecifier = extra.parseImportSpecifier;
parseLogicalANDExpression = extra.parseLogicalANDExpression;
parseLogicalORExpression = extra.parseLogicalORExpression;
parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
+ parseModuleDeclaration = extra.parseModuleDeclaration;
+ parseModuleBlock = extra.parseModuleBlock;
parseNewExpression = extra.parseNewExpression;
parseNonComputedMember = extra.parseNonComputedMember;
parseNonComputedProperty = extra.parseNonComputedProperty;
parseObjectProperty = extra.parseObjectProperty;
parseObjectPropertyKey = extra.parseObjectPropertyKey;
- parsePrimaryExpression = extra.parsePrimaryExpression;
+ parsePath = extra.parsePath;
parsePostfixExpression = extra.parsePostfixExpression;
+ parsePrimaryExpression = extra.parsePrimaryExpression;
parseProgram = extra.parseProgram;
parsePropertyFunction = extra.parsePropertyFunction;
+ parseProtoExpression = extra.parseProtoExpression;
parseRelationalExpression = extra.parseRelationalExpression;
parseStatement = extra.parseStatement;
parseShiftExpression = extra.parseShiftExpression;
parseSwitchCase = extra.parseSwitchCase;
+ parseTriangleLiteral = extra.parseTriangleLiteral;
parseUnaryExpression = extra.parseUnaryExpression;
parseVariableDeclaration = extra.parseVariableDeclaration;
parseVariableIdentifier = extra.parseVariableIdentifier;
@@ -3497,7 +4137,7 @@ parseStatement: true, parseSourceElement: true */
var length = str.length,
result = [],
i;
- for (i = 0; i < length; i += 1) {
+ for (i = 0; i < length; ++i) {
result[i] = str.charAt(i);
}
return result;
@@ -3517,12 +4157,14 @@ parseStatement: true, parseSourceElement: true */
lineStart = 0;
length = source.length;
buffer = null;
- allowIn = true;
- labelSet = {};
- inSwitch = false;
- inIteration = false;
- lastParenthesized = null;
- inFunctionBody = false;
+ state = {
+ allowIn: true,
+ labelSet: {},
+ lastParenthesized: null,
+ inFunctionBody: false,
+ inIteration: false,
+ inSwitch: false
+ };
extra = {};
if (typeof options !== 'undefined') {
@@ -3535,6 +4177,9 @@ parseStatement: true, parseSourceElement: true */
if (typeof options.comment === 'boolean' && options.comment) {
extra.comments = [];
}
+ if (typeof options.tolerant === 'boolean' && options.tolerant) {
+ extra.errors = [];
+ }
}
if (length > 0) {
@@ -3562,6 +4207,9 @@ parseStatement: true, parseSourceElement: true */
if (typeof extra.tokens !== 'undefined') {
program.tokens = extra.tokens;
}
+ if (typeof extra.errors !== 'undefined') {
+ program.errors = extra.errors;
+ }
} catch (e) {
throw e;
} finally {
@@ -3572,173 +4220,31 @@ parseStatement: true, parseSourceElement: true */
return program;
}
- // Executes visitor on the object and its children (recursively).
+ // Sync with package.json.
+ exports.version = '1.0.0-dev';
- function traverse(object, visitor, master) {
- var key, child, parent, path;
+ exports.parse = parse;
- parent = (typeof master === 'undefined') ? [] : master;
+ // Deep copy.
+ exports.Syntax = (function () {
+ var name, types = {};
- if (visitor.call(null, object, parent) === false) {
- return;
+ if (typeof Object.create === 'function') {
+ types = Object.create(null);
}
- for (key in object) {
- if (object.hasOwnProperty(key)) {
- child = object[key];
- path = [ object ];
- path.push(parent);
- if (typeof child === 'object' && child !== null) {
- traverse(child, visitor, path);
- }
- }
- }
- }
-
- // Insert a prolog in the body of every function.
- // It will be in the form of a function call:
- //
- // traceName(object);
- //
- // where the object contains the following properties:
- //
- // 'name' holds the name of the function
- // 'lineNumber' holds the starting line number of the function block
- // 'range' contains the index-based range of the function
- //
- // The name of the function represents the associated reference for
- // the function (deduced on a best-effort basis if it is not
- // a function declaration).
- //
- // If traceName is a function instead of a string, it will be invoked and
- // the result will be used as the entire prolog. The arguments for the
- // invocation are the function name, range, and location info.
-
- function traceFunctionEntrance(traceName) {
-
- return function (code) {
- var tree,
- functionList,
- param,
- signature,
- pos,
- i;
-
-
- tree = parse(code, { range: true, loc: true });
-
- functionList = [];
- traverse(tree, function (node, path) {
- var parent;
- if (node.type === Syntax.FunctionDeclaration) {
- functionList.push({
- name: node.id.name,
- range: node.range,
- loc: node.loc,
- blockStart: node.body.range[0]
- });
- } else if (node.type === Syntax.FunctionExpression) {
- parent = path[0];
- if (parent.type === Syntax.AssignmentExpression) {
- if (typeof parent.left.range !== 'undefined') {
- functionList.push({
- name: code.slice(parent.left.range[0],
- parent.left.range[1] + 1),
- range: node.range,
- loc: node.loc,
- blockStart: node.body.range[0]
- });
- }
- } else if (parent.type === Syntax.VariableDeclarator) {
- functionList.push({
- name: parent.id.name,
- range: node.range,
- loc: node.loc,
- blockStart: node.body.range[0]
- });
- } else if (parent.type === Syntax.CallExpression) {
- functionList.push({
- name: parent.id ? parent.id.name : '[Anonymous]',
- range: node.range,
- loc: node.loc,
- blockStart: node.body.range[0]
- });
- } else if (typeof parent.length === 'number') {
- functionList.push({
- name: parent.id ? parent.id.name : '[Anonymous]',
- range: node.range,
- loc: node.loc,
- blockStart: node.body.range[0]
- });
- } else if (typeof parent.key !== 'undefined') {
- if (parent.key.type === 'Identifier') {
- if (parent.value === node && parent.key.name) {
- functionList.push({
- name: parent.key.name,
- range: node.range,
- loc: node.loc,
- blockStart: node.body.range[0]
- });
- }
- }
- }
- }
- });
-
- // Insert the instrumentation code from the last entry.
- // This is to ensure that the range for each entry remains valid)
- // (it won't shift due to some new inserting string before the range).
- for (i = functionList.length - 1; i >= 0; i -= 1) {
- param = {
- name: functionList[i].name,
- range: functionList[i].range,
- loc: functionList[i].loc
- };
- if (typeof traceName === 'function') {
- signature = traceName.call(null, param);
- } else {
- signature = traceName + '({ ';
- signature += 'name: \'' + functionList[i].name + '\', ';
- if (typeof functionList[i].loc !== 'undefined') {
- signature += 'lineNumber: ' + functionList[i].loc.start.line + ', ';
- }
- signature += 'range: [' + functionList[i].range[0] + ', ' +
- functionList[i].range[1] + '] ';
- signature += '});';
- }
- pos = functionList[i].blockStart + 1;
- code = code.slice(0, pos) + '\n' + signature + code.slice(pos, code.length);
- }
- return code;
- };
- }
-
- function modify(code, modifiers) {
- var i;
-
- if (Object.prototype.toString.call(modifiers) === '[object Array]') {
- for (i = 0; i < modifiers.length; i += 1) {
- code = modifiers[i].call(null, code);
+ for (name in Syntax) {
+ if (Syntax.hasOwnProperty(name)) {
+ types[name] = Syntax[name];
}
- } else if (typeof modifiers === 'function') {
- code = modifiers.call(null, code);
- } else {
- throw new Error('Wrong use of esprima.modify() function');
}
- return code;
- }
-
- // Sync with package.json.
- exports.version = '0.9.9-dev';
-
- exports.parse = parse;
-
- exports.modify = modify;
+ if (typeof Object.freeze === 'function') {
+ Object.freeze(types);
+ }
- exports.Tracer = {
- FunctionEntrance: traceFunctionEntrance
- };
+ return types;
+ }());
}(typeof exports === 'undefined' ? (esprima = {}) : exports));
/* vim: set sw=4 ts=4 et tw=80 : */
diff --git a/escodegen.js b/escodegen.js
index 0590190..59087f6 100644
--- a/escodegen.js
+++ b/escodegen.js
@@ -1,4 +1,5 @@
/*
+ Copyright (C) 2012 John Freeman <jf...@gmail.com>
Copyright (C) 2012 Ariya Hidayat <ar...@gmail.com>
Copyright (C) 2012 Mathias Bynens <ma...@qiwi.be>
Copyright (C) 2012 Joost-Wim Boekesteijn <jo...@boekesteijn.nl>
@@ -37,6 +38,9 @@
var Syntax,
Precedence,
BinaryPrecedence,
+ VisitorKeys,
+ VisitorOption,
+ isArray,
base,
indent,
extra,
@@ -139,10 +143,12 @@
indent: null,
base: null,
parse: null,
+ comment: false,
format: {
indent: {
style: ' ',
- base: 0
+ base: 0,
+ adjustMultilineComment: false
}
}
};
@@ -179,6 +185,42 @@
return result;
}
+ isArray = Array.isArray;
+ if (!isArray) {
+ isArray = function isArray(array) {
+ return Object.prototype.toString.call(array) === '[object Array]';
+ };
+ }
+
+ function endsWithLineTerminator(value) {
+ return (/(?:\r\n|[\n\r])$/).test(value);
+ }
+
+ function shallowCopy(obj) {
+ var ret = {}, key;
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ ret[key] = obj[key];
+ }
+ }
+ return ret;
+ }
+
+ function deepCopy(obj) {
+ var ret = {}, key, val;
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ val = obj[key];
+ if (typeof val === 'object' && val !== null) {
+ ret[key] = deepCopy(val);
+ } else {
+ ret[key] = val;
+ }
+ }
+ }
+ return ret;
+ }
+
function updateDeeply(target, override) {
var key, val;
@@ -247,18 +289,71 @@
return '\'' + result + '\'';
}
+ function isWhiteSpace(ch) {
+ return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
+ (ch === '\u000C') || (ch === '\u00A0') ||
+ (ch.charCodeAt(0) >= 0x1680 &&
+ '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
+ }
+
function addIndent(stmt) {
return base + stmt;
}
+ function adjustMultilineComment(value) {
+ var array, i, len, line, j, ch, spaces;
+
+ spaces = Number.MAX_VALUE;
+ array = value.split(/\r\n|[\r\n]/);
+
+ // first line doesn't have indentation
+ for (i = 1, len = array.length; i < len; i += 1) {
+ line = array[i];
+ j = 0;
+ while (j < line.length && isWhiteSpace(line[j])) {
+ j += 1;
+ }
+ if (spaces > j) {
+ spaces = j;
+ }
+ }
+
+ if (spaces % 2 === 1) {
+ // /*
+ // *
+ // */
+ // If spaces are odd number, above pattern is considered.
+ // We waste 1 space.
+ spaces -= 1;
+ }
+ for (i = 1, len = array.length; i < len; i += 1) {
+ array[i] = addIndent(array[i].slice(spaces));
+ }
+ return array.join('\n');
+ }
+
+ function generateComment(comment) {
+ if (comment.type === 'Line') {
+ // Esprima always produce last line comment with LineTerminator
+ return '//' + comment.value;
+ }
+ if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
+ return adjustMultilineComment('/*' + comment.value + '*/');
+ }
+ return '/*' + comment.value + '*/';
+ }
+
function parenthesize(text, current, should) {
- return (current < should) ? '(' + text + ')' : text;
+ if (current < should) {
+ return '(' + text + ')';
+ }
+ return text;
}
function maybeBlock(stmt, suffix) {
var previousBase, result;
- if (stmt.type === Syntax.BlockStatement) {
+ if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments)) {
result = ' ' + generateStatement(stmt);
if (suffix) {
return result + ' ';
@@ -266,7 +361,7 @@
return result;
}
- if (stmt.type === Syntax.EmptyStatement) {
+ if (stmt.type === Syntax.EmptyStatement && (!extra.comment || !stmt.leadingComments)) {
result = ';';
} else {
previousBase = base;
@@ -293,18 +388,23 @@
return result + ')' + maybeBlock(node.body);
}
- function generateExpression(expr, precedence) {
- var result, currentPrecedence, previousBase, i, len, raw;
+ function generateExpression(expr, option) {
+ var result, precedence, currentPrecedence, previousBase, i, len, raw, allowIn, allowCall;
- if (!precedence) {
- precedence = Precedence.Sequence;
- }
+ precedence = option.precedence;
+ allowIn = option.allowIn;
+ allowCall = option.allowCall;
switch (expr.type) {
case Syntax.SequenceExpression:
result = '';
+ allowIn |= (Precedence.Sequence < precedence);
for (i = 0, len = expr.expressions.length; i < len; i += 1) {
- result += generateExpression(expr.expressions[i], Precedence.Assignment);
+ result += generateExpression(expr.expressions[i], {
+ precedence: Precedence.Assignment,
+ allowIn: allowIn,
+ allowCall: true
+ });
if ((i + 1) < len) {
result += ', ';
}
@@ -313,19 +413,41 @@
break;
case Syntax.AssignmentExpression:
+ allowIn |= (Precedence.Assignment < precedence);
result = parenthesize(
- generateExpression(expr.left, Precedence.Call) + ' ' + expr.operator + ' ' +
- generateExpression(expr.right, Precedence.Assignment),
+ generateExpression(expr.left, {
+ precedence: Precedence.Call,
+ allowIn: allowIn,
+ allowCall: true
+ }) + ' ' + expr.operator + ' ' +
+ generateExpression(expr.right, {
+ precedence: Precedence.Assignment,
+ allowIn: allowIn,
+ allowCall: true
+ }),
Precedence.Assignment,
precedence
);
break;
case Syntax.ConditionalExpression:
+ allowIn |= (Precedence.Conditional < precedence);
result = parenthesize(
- generateExpression(expr.test, Precedence.LogicalOR) + ' ? ' +
- generateExpression(expr.consequent, Precedence.Assignment) + ' : ' +
- generateExpression(expr.alternate, Precedence.Assignment),
+ generateExpression(expr.test, {
+ precedence: Precedence.LogicalOR,
+ allowIn: allowIn,
+ allowCall: true
+ }) + ' ? ' +
+ generateExpression(expr.consequent, {
+ precedence: Precedence.Assignment,
+ allowIn: allowIn,
+ allowCall: true
+ }) + ' : ' +
+ generateExpression(expr.alternate, {
+ precedence: Precedence.Assignment,
+ allowIn: allowIn,
+ allowCall: true
+ }),
Precedence.Conditional,
precedence
);
@@ -335,51 +457,91 @@
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
+ allowIn |= (currentPrecedence < precedence);
+
+ result =
+ generateExpression(expr.left, {
+ precedence: currentPrecedence,
+ allowIn: allowIn,
+ allowCall: true
+ }) + ' ' + expr.operator + ' ' +
+ generateExpression(expr.right, {
+ precedence: currentPrecedence + 1,
+ allowIn: allowIn,
+ allowCall: true
+ });
+
+ if (expr.operator === 'in' && !allowIn) {
result = '(' + result + ')';
} else {
result = parenthesize(result, currentPrecedence, precedence);
}
+
break;
case Syntax.CallExpression:
- result = '';
+ result = generateExpression(expr.callee, {
+ precedence: Precedence.Call,
+ allowIn: true,
+ allowCall: true
+ });
+
+ result += '(';
for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
- result += generateExpression(expr['arguments'][i], Precedence.Assignment);
+ result += generateExpression(expr['arguments'][i], {
+ precedence: Precedence.Assignment,
+ allowIn: true,
+ allowCall: true
+ });
if ((i + 1) < len) {
result += ', ';
}
}
- result = parenthesize(
- generateExpression(expr.callee, Precedence.Call) + '(' + result + ')',
- Precedence.Call,
- precedence
- );
+ result += ')';
+
+ if (!allowCall) {
+ result = '(' + result + ')';
+ } else {
+ result = parenthesize(result, Precedence.Call, precedence);
+ }
break;
case Syntax.NewExpression:
- result = '';
+ result = 'new ' + generateExpression(expr.callee, {
+ precedence: Precedence.New,
+ allowIn: true,
+ allowCall: false
+ });
+
+ result += '(';
for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
- result += generateExpression(expr['arguments'][i], Precedence.Assignment);
+ result += generateExpression(expr['arguments'][i], {
+ precedence: Precedence.Assignment,
+ allowIn: true,
+ allowCall: true
+ });
if ((i + 1) < len) {
result += ', ';
}
}
- result = parenthesize(
- 'new ' + generateExpression(expr.callee, Precedence.New) + '(' + result + ')',
- Precedence.New,
- precedence
- );
+ result += ')';
+
+ result = parenthesize(result, Precedence.New, precedence);
break;
case Syntax.MemberExpression:
- result = generateExpression(expr.object, Precedence.Call);
+ result = generateExpression(expr.object, {
+ precedence: Precedence.Call,
+ allowIn: true,
+ allowCall: allowCall
+ });
+
if (expr.computed) {
- result += '[' + generateExpression(expr.property) + ']';
+ result += '[' + generateExpression(expr.property, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: allowCall
+ }) + ']';
} else {
if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
if (result.indexOf('.') < 0) {
@@ -390,6 +552,7 @@
}
result += '.' + expr.property.name;
}
+
result = parenthesize(result, Precedence.Member, precedence);
break;
@@ -399,13 +562,15 @@
result += ' ';
}
result = parenthesize(
- result + generateExpression(expr.argument, Precedence.Unary +
- (
+ result + generateExpression(expr.argument, {
+ precedence: Precedence.Unary + (
expr.argument.type === Syntax.UnaryExpression &&
- expr.operator.length < 3 &&
- expr.argument.operator === expr.operator ? 1 : 0
- )
+ expr.operator.length < 3 &&
+ expr.argument.operator === expr.operator ? 1 : 0
),
+ allowIn: true,
+ allowCall: true
+ }),
Precedence.Unary,
precedence
);
@@ -415,14 +580,21 @@
if (expr.prefix) {
result = parenthesize(
expr.operator +
- generateExpression(expr.argument, Precedence.Unary),
+ generateExpression(expr.argument, {
+ precedence: Precedence.Unary,
+ allowIn: true,
+ allowCall: true
+ }),
Precedence.Unary,
precedence
);
} else {
result = parenthesize(
- generateExpression(expr.argument, Precedence.Postfix) +
- expr.operator,
+ generateExpression(expr.argument, {
+ precedence: Precedence.Postfix,
+ allowIn: true,
+ allowCall: true
+ }) + expr.operator,
Precedence.Postfix,
precedence
);
@@ -452,7 +624,11 @@
result += ',';
}
} else {
- result += addIndent(generateExpression(expr.elements[i], Precedence.Assignment));
+ result += addIndent(generateExpression(expr.elements[i], {
+ precedence: Precedence.Assignment,
+ allowIn: true,
+ allowCall: true
+ }));
}
if ((i + 1) < len) {
result += ',\n';
@@ -464,11 +640,22 @@
case Syntax.Property:
if (expr.kind === 'get' || expr.kind === 'set') {
- result = expr.kind + ' ' + generateExpression(expr.key) +
- generateFunctionBody(expr.value);
+ result = expr.kind + ' ' + generateExpression(expr.key, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + generateFunctionBody(expr.value);
} else {
- result = generateExpression(expr.key) + ': ' +
- generateExpression(expr.value, Precedence.Assignment);
+ result =
+ generateExpression(expr.key, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ': ' + generateExpression(expr.value, {
+ precedence: Precedence.Assignment,
+ allowIn: true,
+ allowCall: true
+ });
}
break;
@@ -481,7 +668,11 @@
previousBase = base;
base += indent;
for (i = 0, len = expr.properties.length; i < len; i += 1) {
- result += addIndent(generateExpression(expr.properties[i]));
+ result += addIndent(generateExpression(expr.properties[i], {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }));
if ((i + 1) < len) {
result += ',\n';
}
@@ -542,8 +733,13 @@
return result;
}
- function generateStatement(stmt) {
- var i, len, result, previousBase;
+ function generateStatement(stmt, option) {
+ var i, len, result, previousBase, comment, save, ret, node, allowIn;
+
+ allowIn = true;
+ if (option) {
+ allowIn = option.allowIn;
+ }
switch (stmt.type) {
case Syntax.BlockStatement:
@@ -576,13 +772,21 @@
break;
case Syntax.DoWhileStatement:
- result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test) + ');';
+ result = 'do' + maybeBlock(stmt.body, true) + 'while (' + generateExpression(stmt.test, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ');';
break;
case Syntax.CatchClause:
previousBase = base;
base += indent;
- result = ' catch (' + generateExpression(stmt.param) + ')';
+ result = ' catch (' + generateExpression(stmt.param, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ')';
base = previousBase;
result += maybeBlock(stmt.body);
break;
@@ -596,7 +800,11 @@
break;
case Syntax.ExpressionStatement:
- result = generateExpression(stmt.expression);
+ result = generateExpression(stmt.expression, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ });
// 12.4 '{', 'function' is not allowed in this position.
// wrap espression with parentheses
if (result[0] === '{' || result.indexOf('function ') === 0) {
@@ -608,27 +816,54 @@
case Syntax.VariableDeclarator:
if (stmt.init) {
- result = stmt.id.name + ' = ' + generateExpression(stmt.init, Precedence.Assignment);
+ result = stmt.id.name + ' = ' + generateExpression(stmt.init, {
+ precedence: Precedence.Assignment,
+ allowIn: allowIn,
+ allowCall: true
+ });
} else {
result = stmt.id.name;
}
break;
case Syntax.VariableDeclaration:
- result = stmt.kind + ' ';
+ 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]);
+ result += ' ' + generateStatement(stmt.declarations[0], {
+ allowIn: allowIn
+ });
} else {
+ // VariableDeclarator is typed as Statement,
+ // but joined with comma (not LineTerminator).
+ // So if comment is attached to target node, we should specialize.
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 += ', ';
+
+ node = stmt.declarations[0];
+ if (extra.comment && node.leadingComments) {
+ result += '\n' + addIndent(generateStatement(node, {
+ allowIn: allowIn
+ }));
+ } else {
+ result += ' ' + generateStatement(node, {
+ allowIn: allowIn
+ });
+ }
+
+ for (i = 1, len = stmt.declarations.length; i < len; i += 1) {
+ node = stmt.declarations[i];
+ if (extra.comment && node.leadingComments) {
+ result += ',\n' + addIndent(generateStatement(node, {
+ allowIn: allowIn
+ }));
+ } else {
+ result += ', ' + generateStatement(node, {
+ allowIn: allowIn
+ });
}
}
base = previousBase;
@@ -637,7 +872,11 @@
break;
case Syntax.ThrowStatement:
- result = 'throw ' + generateExpression(stmt.argument) + ';';
+ result = 'throw ' + generateExpression(stmt.argument, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ';';
break;
case Syntax.TryStatement:
@@ -653,7 +892,11 @@
case Syntax.SwitchStatement:
previousBase = base;
base += indent;
- result = 'switch (' + generateExpression(stmt.discriminant) + ') {\n';
+ result = 'switch (' + generateExpression(stmt.discriminant, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ') {\n';
base = previousBase;
if (stmt.cases) {
for (i = 0, len = stmt.cases.length; i < len; i += 1) {
@@ -667,7 +910,11 @@
previousBase = base;
base += indent;
if (stmt.test) {
- result = 'case ' + generateExpression(stmt.test) + ':';
+ result = 'case ' + generateExpression(stmt.test, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ':';
} else {
result = 'default:';
}
@@ -691,20 +938,32 @@
if (stmt.alternate.type === Syntax.IfStatement) {
previousBase = base;
base += indent;
- result = 'if (' + generateExpression(stmt.test) + ')';
+ result = 'if (' + generateExpression(stmt.test, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ')';
base = previousBase;
result += maybeBlock(stmt.consequent, true) + 'else ' + generateStatement(stmt.alternate);
} else {
previousBase = base;
base += indent;
- result = 'if (' + generateExpression(stmt.test) + ')';
+ result = 'if (' + generateExpression(stmt.test, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ')';
base = previousBase;
result += maybeBlock(stmt.consequent, true) + 'else' + maybeBlock(stmt.alternate);
}
} else {
previousBase = base;
base += indent;
- result = 'if (' + generateExpression(stmt.test) + ')';
+ result = 'if (' + generateExpression(stmt.test, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ')';
base = previousBase;
result += maybeBlock(stmt.consequent);
}
@@ -716,22 +975,36 @@
result = 'for (';
if (stmt.init) {
if (stmt.init.type === Syntax.VariableDeclaration) {
- result += generateStatement(stmt.init);
+ result += generateStatement(stmt.init, {
+ allowIn: false
+ });
} else {
- result += generateExpression(stmt.init) + ';';
+ result += generateExpression(stmt.init, {
+ precedence: Precedence.Sequence,
+ allowIn: false,
+ allowCall: true
+ }) + ';';
}
} else {
result += ';';
}
if (stmt.test) {
- result += ' ' + generateExpression(stmt.test) + ';';
+ result += ' ' + generateExpression(stmt.test, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ';';
} else {
result += ';';
}
if (stmt.update) {
- result += ' ' + generateExpression(stmt.update) + ')';
+ result += ' ' + generateExpression(stmt.update, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ')';
} else {
result += ')';
}
@@ -745,18 +1018,28 @@
if (stmt.left.type === Syntax.VariableDeclaration) {
previousBase = base;
base += indent + indent;
- result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0]);
+ result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0], {
+ allowIn: false
+ });
base = previousBase;
} else {
previousBase = base;
base += indent;
- result += generateExpression(stmt.left, Precedence.Call);
+ result += generateExpression(stmt.left, {
+ precedence: Precedence.Call,
+ allowIn: true,
+ allowCall: true
+ });
base = previousBase;
}
previousBase = base;
base += indent;
- result += ' in ' + generateExpression(stmt.right) + ')';
+ result += ' in ' + generateExpression(stmt.right, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ')';
base = previousBase;
result += maybeBlock(stmt.body);
break;
@@ -785,7 +1068,11 @@
case Syntax.ReturnStatement:
if (stmt.argument) {
- result = 'return ' + generateExpression(stmt.argument) + ';';
+ result = 'return ' + generateExpression(stmt.argument, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ';';
} else {
result = 'return;';
}
@@ -794,7 +1081,11 @@
case Syntax.WhileStatement:
previousBase = base;
base += indent;
- result = 'while (' + generateExpression(stmt.test) + ')';
+ result = 'while (' + generateExpression(stmt.test, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ')';
base = previousBase;
result += maybeBlock(stmt.body);
break;
@@ -802,7 +1093,11 @@
case Syntax.WithStatement:
previousBase = base;
base += indent;
- result = 'with (' + generateExpression(stmt.object) + ')';
+ result = 'with (' + generateExpression(stmt.object, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ }) + ')';
base = previousBase;
result += maybeBlock(stmt.body);
break;
@@ -814,6 +1109,42 @@
if (result === undefined) {
throw new Error('Unknown statement type: ' + stmt.type);
}
+
+ // Attach comments
+
+ if (extra.comment) {
+ if (stmt.leadingComments) {
+ save = result;
+
+ comment = stmt.leadingComments[0];
+ result = generateComment(comment);
+ if (!endsWithLineTerminator(result)) {
+ result += '\n';
+ }
+
+ for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) {
+ comment = stmt.leadingComments[i];
+ ret = generateComment(comment);
+ if (!endsWithLineTerminator(ret)) {
+ ret += '\n';
+ }
+ result += addIndent(ret);
+ }
+
+ result += addIndent(save);
+ }
+
+ if (stmt.trailingComments) {
+ for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) {
+ comment = stmt.trailingComments[i];
+ if (!endsWithLineTerminator(result)) {
+ result += '\n';
+ }
+ result += addIndent(generateComment(comment));
+ }
+ }
+ }
+
return result;
}
@@ -845,6 +1176,7 @@
base = stringRepeat(indent, options.format.indent.base);
parse = options.parse;
}
+ extra = options;
switch (node.type) {
case Syntax.BlockStatement:
@@ -889,7 +1221,11 @@
case Syntax.ThisExpression:
case Syntax.UnaryExpression:
case Syntax.UpdateExpression:
- return generateExpression(node);
+ return generateExpression(node, {
+ precedence: Precedence.Sequence,
+ allowIn: true,
+ allowCall: true
+ });
default:
break;
@@ -897,10 +1233,295 @@
throw new Error('Unknown node type: ' + node.type);
}
+ // simple visitor implementation
+
+ VisitorKeys = {
+ AssignmentExpression: ['left', 'right'],
+ ArrayExpression: ['elements'],
+ BlockStatement: ['body'],
+ BinaryExpression: ['left', 'right'],
+ BreakStatement: ['label'],
+ CallExpression: ['callee', 'arguments'],
+ CatchClause: ['param', 'body'],
+ ConditionalExpression: ['test', 'consequent', 'alternate'],
+ ContinueStatement: ['label'],
+ DoWhileStatement: ['body', 'test'],
+ DebuggerStatement: [],
+ EmptyStatement: [],
+ ExpressionStatement: ['expression'],
+ ForStatement: ['init', 'test', 'update', 'body'],
+ ForInStatement: ['left', 'right', 'body'],
+ FunctionDeclaration: ['id', 'params', 'body'],
+ FunctionExpression: ['id', 'params', 'body'],
+ Identifier: [],
+ IfStatement: ['test', 'consequent', 'alternate'],
+ Literal: [],
+ LabeledStatement: ['label', 'body'],
+ LogicalExpression: ['left', 'right'],
+ MemberExpression: ['object', 'property'],
+ NewExpression: ['callee', 'arguments'],
+ ObjectExpression: ['properties'],
+ Program: ['body'],
+ Property: ['key', 'value'],
+ ReturnStatement: ['argument'],
+ SequenceExpression: ['expressions'],
+ SwitchStatement: ['descriminant', 'cases'],
+ SwitchCase: ['test', 'consequent'],
+ ThisExpression: [],
+ ThrowStatement: ['argument'],
+ TryStatement: ['block', 'handlers', 'finalizer'],
+ UnaryExpression: ['argument'],
+ UpdateExpression: ['argument'],
+ VariableDeclaration: ['declarations'],
+ VariableDeclarator: ['id', 'init'],
+ WhileStatement: ['test', 'body'],
+ WithStatement: ['object', 'body']
+ };
+
+ VisitorOption = {
+ Break: 1,
+ Skip: 2
+ };
+
+ function traverse(top, visitor) {
+ var worklist, leavelist, node, ret, current, current2, candidates, candidate;
+
+ worklist = [ top ];
+ leavelist = [];
+
+ while (worklist.length) {
+ node = worklist.pop();
+
+ if (node) {
+ if (visitor.enter) {
+ ret = visitor.enter(node);
+ } else {
+ ret = undefined;
+ }
+
+ if (ret === VisitorOption.Break) {
+ return;
+ }
+
+ worklist.push(null);
+ leavelist.push(node);
+
+ if (ret !== VisitorOption.Skip) {
+ candidates = VisitorKeys[node.type];
+ current = candidates.length;
+ while ((current -= 1) >= 0) {
+ candidate = node[candidates[current]];
+ if (candidate) {
+ if (isArray(candidate)) {
+ current2 = candidate.length;
+ while ((current2 -= 1) >= 0) {
+ if (candidate[current2]) {
+ worklist.push(candidate[current2]);
+ }
+ }
+ } else {
+ worklist.push(candidate);
+ }
+ }
+ }
+ }
+ } else {
+ node = leavelist.pop();
+ if (visitor.leave) {
+ ret = visitor.leave(node);
+ } else {
+ ret = undefined;
+ }
+ if (ret === VisitorOption.Break) {
+ return;
+ }
+ }
+ }
+ }
+
+
+ // based on LLVM libc++ upper_bound / lower_bound
+ // MIT License
+
+ function upperBound(array, func) {
+ var diff, len, i, current;
+
+ len = array.length;
+ i = 0;
+
+ while (len) {
+ diff = len >>> 1;
+ current = i + diff;
+ if (func(array[current])) {
+ len = diff;
+ } else {
+ i = current + 1;
+ len -= diff + 1;
+ }
+ }
+ return i;
+ }
+
+ function lowerBound(array, func) {
+ var diff, len, i, current;
+
+ len = array.length;
+ i = 0;
+
+ while (len) {
+ diff = len >>> 1;
+ current = i + diff;
+ if (func(array[current])) {
+ i = current + 1;
+ len -= diff + 1;
+ } else {
+ len = diff;
+ }
+ }
+ return i;
+ }
+
+ function extendCommentRange(comment, tokens) {
+ var target, token;
+
+ target = upperBound(tokens, function search(token) {
+ return token.range[0] > comment.range[0];
+ });
+
+ comment.extendedRange = [comment.range[0], comment.range[1]];
+
+ if (target !== tokens.length) {
+ comment.extendedRange[1] = tokens[target].range[0];
+ }
+
+ target -= 1;
+ if (target >= 0) {
+ if (target < tokens.length) {
+ comment.extendedRange[0] = tokens[target].range[1];
+ } else if (token.length) {
+ comment.extendedRange[1] = tokens[tokens.length - 1].range[0];
+ }
+ }
+
+ return comment;
+ }
+
+ function attachComments(tree, providedComments, tokens) {
+ // At first, we should calculate extended comment ranges.
+ var comments = [], len, i;
+
+ if (!tree.range) {
+ throw new Error('attachComments needs range information');
+ }
+
+ for (i = 0, len = providedComments.length; i < len; i += 1) {
+ comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
+ }
+
+ //
+ // For example,
+ //
+ // var i1 = 10, // test
+ // i2 = 20;
+ //
+ // Above comment is probably trailing to i1 = 10.
+ // So we specialize comma token.
+ //
+ // And second, comma first style example,
+ //
+ // var i = [
+ // 10 // testing
+ // , 20 // testing 2
+ // ];
+ //
+ // 'testing' comment is trailing to 10 is proper.
+ //
+ // So we add some specialize path.
+ //
+ // 1. check comment is'nt containing LineTerminator
+ // 2. check LineTerminator is not found between previous token and comment
+ // 3. check LineTerminator is found between comment and next token
+ //
+ // If above conditions are all true,
+ // we assume this comment should be attached to previous token as trailing comment.
+ //
+
+ // This traverse attacher is based on John Freeman's implementation.
+ traverse(tree, {
+ cursor: 0,
+ enter: function (node) {
+ var comment;
+
+ while (this.cursor < comments.length) {
+ comment = comments[this.cursor];
+ if (comment.extendedRange[1] > node.range[0]) {
+ break;
+ }
+
+ if (comment.extendedRange[1] === node.range[0]) {
+ if (!node.leadingComments) {
+ node.leadingComments = [];
+ }
+ node.leadingComments.push(comment);
+ comments.splice(this.cursor, 1);
+ } else {
+ this.cursor += 1;
+ }
+ }
+
+ // already out of owned node
+ if (this.cursor === comments.length) {
+ return VisitorOption.Break;
+ }
+
+ if (comments[this.cursor].extendedRange[0] > node.range[1]) {
+ return VisitorOption.Skip;
+ }
+ }
+ });
+
+ traverse(tree, {
+ cursor: 0,
+ leave: function (node) {
+ var comment;
+
+ while (this.cursor < comments.length) {
+ comment = comments[this.cursor];
+ if (node.range[1] < comment.extendedRange[0]) {
+ break;
+ }
+
+ if (node.range[1] === comment.extendedRange[0]) {
+ if (!node.trailingComments) {
+ node.trailingComments = [];
+ }
+ node.trailingComments.push(comment);
+ comments.splice(this.cursor, 1);
+ } else {
+ this.cursor += 1;
+ }
+ }
+
+ // already out of owned node
+ if (this.cursor === comments.length) {
+ return VisitorOption.Break;
+ }
+
+ if (comments[this.cursor].extendedRange[0] > node.range[1]) {
+ return VisitorOption.Skip;
+ }
+ }
+ });
+
+ return tree;
+ }
+
// Sync with package.json.
- exports.version = '0.0.4-dev';
+ exports.version = '0.0.4';
exports.generate = generate;
+ exports.traverse = traverse;
+ exports.attachComments = attachComments;
}(typeof exports === 'undefined' ? (escodegen = {}) : exports));
/* vim: set sw=4 ts=4 et tw=80 : */