blob: 9536289dd7376b40add3eb58fba400b490f3a8ad [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* 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 THE COPYRIGHT
* OWNER OR CONTRIBUTORS 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.
*/
function FormattedContentBuilder(content, mapping, originalOffset, formattedOffset, indentString)
{
this._originalContent = content;
this._originalOffset = originalOffset;
this._lastOriginalPosition = 0;
this._formattedContent = [];
this._formattedContentLength = 0;
this._formattedOffset = formattedOffset;
this._lastFormattedPosition = 0;
this._mapping = mapping;
this._lineNumber = 0;
this._nestingLevel = 0;
this._indentString = indentString;
this._cachedIndents = {};
}
FormattedContentBuilder.prototype = {
addToken: function(token)
{
for (var i = 0; i < token.comments_before.length; ++i)
this._addComment(token.comments_before[i]);
while (this._lineNumber < token.line) {
this._addText("\n");
this._addIndent();
this._needNewLine = false;
this._lineNumber += 1;
}
if (this._needNewLine) {
this._addText("\n");
this._addIndent();
this._needNewLine = false;
}
this._addMappingIfNeeded(token.pos);
this._addText(this._originalContent.substring(token.pos, token.endPos));
this._lineNumber = token.endLine;
},
addSpace: function()
{
this._addText(" ");
},
addNewLine: function()
{
this._needNewLine = true;
},
increaseNestingLevel: function()
{
this._nestingLevel += 1;
},
decreaseNestingLevel: function()
{
this._nestingLevel -= 1;
},
content: function()
{
return this._formattedContent.join("");
},
mapping: function()
{
return { original: this._originalPositions, formatted: this._formattedPositions };
},
_addIndent: function()
{
if (this._cachedIndents[this._nestingLevel]) {
this._addText(this._cachedIndents[this._nestingLevel]);
return;
}
var fullIndent = "";
for (var i = 0; i < this._nestingLevel; ++i)
fullIndent += this._indentString;
this._addText(fullIndent);
// Cache a maximum of 20 nesting level indents.
if (this._nestingLevel <= 20)
this._cachedIndents[this._nestingLevel] = fullIndent;
},
_addComment: function(comment)
{
if (this._lineNumber < comment.line) {
for (var j = this._lineNumber; j < comment.line; ++j)
this._addText("\n");
this._lineNumber = comment.line;
this._needNewLine = false;
this._addIndent();
} else
this.addSpace();
this._addMappingIfNeeded(comment.pos);
if (comment.type === "comment1")
this._addText("//");
else
this._addText("/*");
this._addText(comment.value);
if (comment.type !== "comment1") {
this._addText("*/");
var position;
while ((position = comment.value.indexOf("\n", position + 1)) !== -1)
this._lineNumber += 1;
}
},
_addText: function(text)
{
this._formattedContent.push(text);
this._formattedContentLength += text.length;
},
_addMappingIfNeeded: function(originalPosition)
{
if (originalPosition - this._lastOriginalPosition === this._formattedContentLength - this._lastFormattedPosition)
return;
this._mapping.original.push(this._originalOffset + originalPosition);
this._lastOriginalPosition = originalPosition;
this._mapping.formatted.push(this._formattedOffset + this._formattedContentLength);
this._lastFormattedPosition = this._formattedContentLength;
}
}
var tokens = [
["EOS"],
["LPAREN", "("], ["RPAREN", ")"], ["LBRACK", "["], ["RBRACK", "]"], ["LBRACE", "{"], ["RBRACE", "}"], ["COLON", ":"], ["SEMICOLON", ";"], ["PERIOD", "."], ["CONDITIONAL", "?"],
["INC", "++"], ["DEC", "--"],
["ASSIGN", "="], ["ASSIGN_BIT_OR", "|="], ["ASSIGN_BIT_XOR", "^="], ["ASSIGN_BIT_AND", "&="], ["ASSIGN_SHL", "<<="], ["ASSIGN_SAR", ">>="], ["ASSIGN_SHR", ">>>="],
["ASSIGN_ADD", "+="], ["ASSIGN_SUB", "-="], ["ASSIGN_MUL", "*="], ["ASSIGN_DIV", "/="], ["ASSIGN_MOD", "%="],
["COMMA", ","], ["OR", "||"], ["AND", "&&"], ["BIT_OR", "|"], ["BIT_XOR", "^"], ["BIT_AND", "&"], ["SHL", "<<"], ["SAR", ">>"], ["SHR", ">>>"],
["ADD", "+"], ["SUB", "-"], ["MUL", "*"], ["DIV", "/"], ["MOD", "%"],
["EQ", "=="], ["NE", "!="], ["EQ_STRICT", "==="], ["NE_STRICT", "!=="], ["LT", "<"], ["GT", ">"], ["LTE", "<="], ["GTE", ">="],
["INSTANCEOF", "instanceof"], ["IN", "in"], ["NOT", "!"], ["BIT_NOT", "~"], ["DELETE", "delete"], ["TYPEOF", "typeof"], ["VOID", "void"],
["BREAK", "break"], ["CASE", "case"], ["CATCH", "catch"], ["CONTINUE", "continue"], ["DEBUGGER", "debugger"], ["DEFAULT", "default"], ["DO", "do"], ["ELSE", "else"], ["FINALLY", "finally"],
["FOR", "for"], ["FUNCTION", "function"], ["IF", "if"], ["NEW", "new"], ["RETURN", "return"], ["SWITCH", "switch"], ["THIS", "this"], ["THROW", "throw"], ["TRY", "try"], ["VAR", "var"],
["WHILE", "while"], ["WITH", "with"], ["NULL_LITERAL", "null"], ["TRUE_LITERAL", "true"], ["FALSE_LITERAL", "false"], ["NUMBER"], ["STRING"], ["IDENTIFIER"], ["CONST", "const"]
];
var Tokens = {};
for (var i = 0; i < tokens.length; ++i)
Tokens[tokens[i][0]] = i;
var TokensByValue = {};
for (var i = 0; i < tokens.length; ++i) {
if (tokens[i][1])
TokensByValue[tokens[i][1]] = i;
}
var TokensByType = {
"eof": Tokens.EOS,
"name": Tokens.IDENTIFIER,
"num": Tokens.NUMBER,
"regexp": Tokens.DIV,
"string": Tokens.STRING
};
function Tokenizer(content)
{
this._readNextToken = parse.tokenizer(content);
this._state = this._readNextToken.context();
}
Tokenizer.prototype = {
content: function()
{
return this._state.text;
},
next: function(forceRegexp)
{
var uglifyToken = this._readNextToken(forceRegexp);
uglifyToken.endPos = this._state.pos;
uglifyToken.endLine = this._state.line;
uglifyToken.token = this._convertUglifyToken(uglifyToken);
return uglifyToken;
},
_convertUglifyToken: function(uglifyToken)
{
var token = TokensByType[uglifyToken.type];
if (typeof token === "number")
return token;
token = TokensByValue[uglifyToken.value];
if (typeof token === "number")
return token;
throw "Unknown token type " + uglifyToken.type;
}
}
function JavaScriptFormatter(tokenizer, builder)
{
this._tokenizer = tokenizer;
this._builder = builder;
this._token = null;
this._nextToken = this._tokenizer.next();
}
JavaScriptFormatter.prototype = {
format: function()
{
this._parseSourceElements(Tokens.EOS);
this._consume(Tokens.EOS);
},
_peek: function()
{
return this._nextToken.token;
},
_next: function()
{
if (this._token && this._token.token === Tokens.EOS)
throw "Unexpected EOS token";
this._builder.addToken(this._nextToken);
this._token = this._nextToken;
this._nextToken = this._tokenizer.next(this._forceRegexp);
this._forceRegexp = false;
return this._token.token;
},
_consume: function(token)
{
var next = this._next();
if (next !== token)
throw "Unexpected token in consume: expected " + token + ", actual " + next;
},
_expect: function(token)
{
var next = this._next();
if (next !== token)
throw "Unexpected token: expected " + token + ", actual " + next;
},
_expectSemicolon: function()
{
if (this._peek() === Tokens.SEMICOLON)
this._consume(Tokens.SEMICOLON);
},
_hasLineTerminatorBeforeNext: function()
{
return this._nextToken.nlb;
},
_parseSourceElements: function(endToken)
{
while (this._peek() !== endToken) {
this._parseStatement();
this._builder.addNewLine();
}
},
_parseStatementOrBlock: function()
{
if (this._peek() === Tokens.LBRACE) {
this._builder.addSpace();
this._parseBlock();
return true;
}
this._builder.addNewLine();
this._builder.increaseNestingLevel();
this._parseStatement();
this._builder.decreaseNestingLevel();
},
_parseStatement: function()
{
switch (this._peek()) {
case Tokens.LBRACE:
return this._parseBlock();
case Tokens.CONST:
case Tokens.VAR:
return this._parseVariableStatement();
case Tokens.SEMICOLON:
return this._next();
case Tokens.IF:
return this._parseIfStatement();
case Tokens.DO:
return this._parseDoWhileStatement();
case Tokens.WHILE:
return this._parseWhileStatement();
case Tokens.FOR:
return this._parseForStatement();
case Tokens.CONTINUE:
return this._parseContinueStatement();
case Tokens.BREAK:
return this._parseBreakStatement();
case Tokens.RETURN:
return this._parseReturnStatement();
case Tokens.WITH:
return this._parseWithStatement();
case Tokens.SWITCH:
return this._parseSwitchStatement();
case Tokens.THROW:
return this._parseThrowStatement();
case Tokens.TRY:
return this._parseTryStatement();
case Tokens.FUNCTION:
return this._parseFunctionDeclaration();
case Tokens.DEBUGGER:
return this._parseDebuggerStatement();
default:
return this._parseExpressionOrLabelledStatement();
}
},
_parseFunctionDeclaration: function()
{
this._expect(Tokens.FUNCTION);
this._builder.addSpace();
this._expect(Tokens.IDENTIFIER);
this._parseFunctionLiteral()
},
_parseBlock: function()
{
this._expect(Tokens.LBRACE);
this._builder.addNewLine();
this._builder.increaseNestingLevel();
while (this._peek() !== Tokens.RBRACE) {
this._parseStatement();
this._builder.addNewLine();
}
this._builder.decreaseNestingLevel();
this._expect(Tokens.RBRACE);
},
_parseVariableStatement: function()
{
this._parseVariableDeclarations();
this._expectSemicolon();
},
_parseVariableDeclarations: function()
{
if (this._peek() === Tokens.VAR)
this._consume(Tokens.VAR);
else
this._consume(Tokens.CONST)
this._builder.addSpace();
var isFirstVariable = true;
do {
if (!isFirstVariable) {
this._consume(Tokens.COMMA);
this._builder.addSpace();
}
isFirstVariable = false;
this._expect(Tokens.IDENTIFIER);
if (this._peek() === Tokens.ASSIGN) {
this._builder.addSpace();
this._consume(Tokens.ASSIGN);
this._builder.addSpace();
this._parseAssignmentExpression();
}
} while (this._peek() === Tokens.COMMA);
},
_parseExpressionOrLabelledStatement: function()
{
this._parseExpression();
if (this._peek() === Tokens.COLON) {
this._expect(Tokens.COLON);
this._builder.addSpace();
this._parseStatement();
}
this._expectSemicolon();
},
_parseIfStatement: function()
{
this._expect(Tokens.IF);
this._builder.addSpace();
this._expect(Tokens.LPAREN);
this._parseExpression();
this._expect(Tokens.RPAREN);
var isBlock = this._parseStatementOrBlock();
if (this._peek() === Tokens.ELSE) {
if (isBlock)
this._builder.addSpace();
else
this._builder.addNewLine();
this._next();
if (this._peek() === Tokens.IF) {
this._builder.addSpace();
this._parseStatement();
} else
this._parseStatementOrBlock();
}
},
_parseContinueStatement: function()
{
this._expect(Tokens.CONTINUE);
var token = this._peek();
if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
this._builder.addSpace();
this._expect(Tokens.IDENTIFIER);
}
this._expectSemicolon();
},
_parseBreakStatement: function()
{
this._expect(Tokens.BREAK);
var token = this._peek();
if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
this._builder.addSpace();
this._expect(Tokens.IDENTIFIER);
}
this._expectSemicolon();
},
_parseReturnStatement: function()
{
this._expect(Tokens.RETURN);
var token = this._peek();
if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
this._builder.addSpace();
this._parseExpression();
}
this._expectSemicolon();
},
_parseWithStatement: function()
{
this._expect(Tokens.WITH);
this._builder.addSpace();
this._expect(Tokens.LPAREN);
this._parseExpression();
this._expect(Tokens.RPAREN);
this._parseStatementOrBlock();
},
_parseCaseClause: function()
{
if (this._peek() === Tokens.CASE) {
this._expect(Tokens.CASE);
this._builder.addSpace();
this._parseExpression();
} else
this._expect(Tokens.DEFAULT);
this._expect(Tokens.COLON);
this._builder.addNewLine();
this._builder.increaseNestingLevel();
while (this._peek() !== Tokens.CASE && this._peek() !== Tokens.DEFAULT && this._peek() !== Tokens.RBRACE) {
this._parseStatement();
this._builder.addNewLine();
}
this._builder.decreaseNestingLevel();
},
_parseSwitchStatement: function()
{
this._expect(Tokens.SWITCH);
this._builder.addSpace();
this._expect(Tokens.LPAREN);
this._parseExpression();
this._expect(Tokens.RPAREN);
this._builder.addSpace();
this._expect(Tokens.LBRACE);
this._builder.addNewLine();
this._builder.increaseNestingLevel();
while (this._peek() !== Tokens.RBRACE)
this._parseCaseClause();
this._builder.decreaseNestingLevel();
this._expect(Tokens.RBRACE);
},
_parseThrowStatement: function()
{
this._expect(Tokens.THROW);
this._builder.addSpace();
this._parseExpression();
this._expectSemicolon();
},
_parseTryStatement: function()
{
this._expect(Tokens.TRY);
this._builder.addSpace();
this._parseBlock();
var token = this._peek();
if (token === Tokens.CATCH) {
this._builder.addSpace();
this._consume(Tokens.CATCH);
this._builder.addSpace();
this._expect(Tokens.LPAREN);
this._expect(Tokens.IDENTIFIER);
this._expect(Tokens.RPAREN);
this._builder.addSpace();
this._parseBlock();
token = this._peek();
}
if (token === Tokens.FINALLY) {
this._consume(Tokens.FINALLY);
this._builder.addSpace();
this._parseBlock();
}
},
_parseDoWhileStatement: function()
{
this._expect(Tokens.DO);
var isBlock = this._parseStatementOrBlock();
if (isBlock)
this._builder.addSpace();
else
this._builder.addNewLine();
this._expect(Tokens.WHILE);
this._builder.addSpace();
this._expect(Tokens.LPAREN);
this._parseExpression();
this._expect(Tokens.RPAREN);
this._expectSemicolon();
},
_parseWhileStatement: function()
{
this._expect(Tokens.WHILE);
this._builder.addSpace();
this._expect(Tokens.LPAREN);
this._parseExpression();
this._expect(Tokens.RPAREN);
this._parseStatementOrBlock();
},
_parseForStatement: function()
{
this._expect(Tokens.FOR);
this._builder.addSpace();
this._expect(Tokens.LPAREN);
if (this._peek() !== Tokens.SEMICOLON) {
if (this._peek() === Tokens.VAR || this._peek() === Tokens.CONST) {
this._parseVariableDeclarations();
if (this._peek() === Tokens.IN) {
this._builder.addSpace();
this._consume(Tokens.IN);
this._builder.addSpace();
this._parseExpression();
}
} else
this._parseExpression();
}
if (this._peek() !== Tokens.RPAREN) {
this._expect(Tokens.SEMICOLON);
this._builder.addSpace();
if (this._peek() !== Tokens.SEMICOLON)
this._parseExpression();
this._expect(Tokens.SEMICOLON);
this._builder.addSpace();
if (this._peek() !== Tokens.RPAREN)
this._parseExpression();
}
this._expect(Tokens.RPAREN);
this._parseStatementOrBlock();
},
_parseExpression: function()
{
this._parseAssignmentExpression();
while (this._peek() === Tokens.COMMA) {
this._expect(Tokens.COMMA);
this._builder.addSpace();
this._parseAssignmentExpression();
}
},
_parseAssignmentExpression: function()
{
this._parseConditionalExpression();
var token = this._peek();
if (Tokens.ASSIGN <= token && token <= Tokens.ASSIGN_MOD) {
this._builder.addSpace();
this._next();
this._builder.addSpace();
this._parseAssignmentExpression();
}
},
_parseConditionalExpression: function()
{
this._parseBinaryExpression();
if (this._peek() === Tokens.CONDITIONAL) {
this._builder.addSpace();
this._consume(Tokens.CONDITIONAL);
this._builder.addSpace();
this._parseAssignmentExpression();
this._builder.addSpace();
this._expect(Tokens.COLON);
this._builder.addSpace();
this._parseAssignmentExpression();
}
},
_parseBinaryExpression: function()
{
this._parseUnaryExpression();
var token = this._peek();
while (Tokens.OR <= token && token <= Tokens.IN) {
this._builder.addSpace();
this._next();
this._builder.addSpace();
this._parseBinaryExpression();
token = this._peek();
}
},
_parseUnaryExpression: function()
{
var token = this._peek();
if ((Tokens.NOT <= token && token <= Tokens.VOID) || token === Tokens.ADD || token === Tokens.SUB || token === Tokens.INC || token === Tokens.DEC) {
this._next();
if (token === Tokens.DELETE || token === Tokens.TYPEOF || token === Tokens.VOID)
this._builder.addSpace();
this._parseUnaryExpression();
} else
return this._parsePostfixExpression();
},
_parsePostfixExpression: function()
{
this._parseLeftHandSideExpression();
var token = this._peek();
if (!this._hasLineTerminatorBeforeNext() && (token === Tokens.INC || token === Tokens.DEC))
this._next();
},
_parseLeftHandSideExpression: function()
{
if (this._peek() === Tokens.NEW)
this._parseNewExpression();
else
this._parseMemberExpression();
while (true) {
switch (this._peek()) {
case Tokens.LBRACK:
this._consume(Tokens.LBRACK);
this._parseExpression();
this._expect(Tokens.RBRACK);
break;
case Tokens.LPAREN:
this._parseArguments();
break;
case Tokens.PERIOD:
this._consume(Tokens.PERIOD);
this._expect(Tokens.IDENTIFIER);
break;
default:
return;
}
}
},
_parseNewExpression: function()
{
this._expect(Tokens.NEW);
this._builder.addSpace();
if (this._peek() === Tokens.NEW)
this._parseNewExpression();
else
this._parseMemberExpression();
},
_parseMemberExpression: function()
{
if (this._peek() === Tokens.FUNCTION) {
this._expect(Tokens.FUNCTION);
if (this._peek() === Tokens.IDENTIFIER) {
this._builder.addSpace();
this._expect(Tokens.IDENTIFIER);
}
this._parseFunctionLiteral();
} else
this._parsePrimaryExpression();
while (true) {
switch (this._peek()) {
case Tokens.LBRACK:
this._consume(Tokens.LBRACK);
this._parseExpression();
this._expect(Tokens.RBRACK);
break;
case Tokens.PERIOD:
this._consume(Tokens.PERIOD);
this._expect(Tokens.IDENTIFIER);
break;
case Tokens.LPAREN:
this._parseArguments();
break;
default:
return;
}
}
},
_parseDebuggerStatement: function()
{
this._expect(Tokens.DEBUGGER);
this._expectSemicolon();
},
_parsePrimaryExpression: function()
{
switch (this._peek()) {
case Tokens.THIS:
return this._consume(Tokens.THIS);
case Tokens.NULL_LITERAL:
return this._consume(Tokens.NULL_LITERAL);
case Tokens.TRUE_LITERAL:
return this._consume(Tokens.TRUE_LITERAL);
case Tokens.FALSE_LITERAL:
return this._consume(Tokens.FALSE_LITERAL);
case Tokens.IDENTIFIER:
return this._consume(Tokens.IDENTIFIER);
case Tokens.NUMBER:
return this._consume(Tokens.NUMBER);
case Tokens.STRING:
return this._consume(Tokens.STRING);
case Tokens.ASSIGN_DIV:
return this._parseRegExpLiteral();
case Tokens.DIV:
return this._parseRegExpLiteral();
case Tokens.LBRACK:
return this._parseArrayLiteral();
case Tokens.LBRACE:
return this._parseObjectLiteral();
case Tokens.LPAREN:
this._consume(Tokens.LPAREN);
this._parseExpression();
this._expect(Tokens.RPAREN);
return;
default:
return this._next();
}
},
_parseArrayLiteral: function()
{
this._expect(Tokens.LBRACK);
this._builder.increaseNestingLevel();
while (this._peek() !== Tokens.RBRACK) {
if (this._peek() !== Tokens.COMMA)
this._parseAssignmentExpression();
if (this._peek() !== Tokens.RBRACK) {
this._expect(Tokens.COMMA);
this._builder.addSpace();
}
}
this._builder.decreaseNestingLevel();
this._expect(Tokens.RBRACK);
},
_parseObjectLiteralGetSet: function()
{
var token = this._peek();
if (token === Tokens.IDENTIFIER || token === Tokens.NUMBER || token === Tokens.STRING ||
Tokens.DELETE <= token && token <= Tokens.FALSE_LITERAL ||
token === Tokens.INSTANCEOF || token === Tokens.IN || token === Tokens.CONST) {
this._next();
this._parseFunctionLiteral();
}
},
_parseObjectLiteral: function()
{
this._expect(Tokens.LBRACE);
this._builder.increaseNestingLevel();
while (this._peek() !== Tokens.RBRACE) {
var token = this._peek();
switch (token) {
case Tokens.IDENTIFIER:
this._consume(Tokens.IDENTIFIER);
var name = this._token.value;
if ((name === "get" || name === "set") && this._peek() !== Tokens.COLON) {
this._builder.addSpace();
this._parseObjectLiteralGetSet();
if (this._peek() !== Tokens.RBRACE) {
this._expect(Tokens.COMMA);
}
continue;
}
break;
case Tokens.STRING:
this._consume(Tokens.STRING);
break;
case Tokens.NUMBER:
this._consume(Tokens.NUMBER);
break;
default:
this._next();
}
this._expect(Tokens.COLON);
this._builder.addSpace();
this._parseAssignmentExpression();
if (this._peek() !== Tokens.RBRACE) {
this._expect(Tokens.COMMA);
}
}
this._builder.decreaseNestingLevel();
this._expect(Tokens.RBRACE);
},
_parseRegExpLiteral: function()
{
if (this._nextToken.type === "regexp")
this._next();
else {
this._forceRegexp = true;
this._next();
}
},
_parseArguments: function()
{
this._expect(Tokens.LPAREN);
var done = (this._peek() === Tokens.RPAREN);
while (!done) {
this._parseAssignmentExpression();
done = (this._peek() === Tokens.RPAREN);
if (!done) {
this._expect(Tokens.COMMA);
this._builder.addSpace();
}
}
this._expect(Tokens.RPAREN);
},
_parseFunctionLiteral: function()
{
this._expect(Tokens.LPAREN);
var done = (this._peek() === Tokens.RPAREN);
while (!done) {
this._expect(Tokens.IDENTIFIER);
done = (this._peek() === Tokens.RPAREN);
if (!done) {
this._expect(Tokens.COMMA);
this._builder.addSpace();
}
}
this._expect(Tokens.RPAREN);
this._builder.addSpace();
this._expect(Tokens.LBRACE);
this._builder.addNewLine();
this._builder.increaseNestingLevel();
this._parseSourceElements(Tokens.RBRACE);
this._builder.decreaseNestingLevel();
this._expect(Tokens.RBRACE);
}
}