2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 function FormattedContentBuilder(content, mapping, originalOffset, formattedOffset, indentString)
33 this._originalContent = content;
34 this._originalOffset = originalOffset;
35 this._lastOriginalPosition = 0;
37 this._formattedContent = [];
38 this._formattedContentLength = 0;
39 this._formattedOffset = formattedOffset;
40 this._lastFormattedPosition = 0;
42 this._mapping = mapping;
45 this._nestingLevel = 0;
46 this._indentString = indentString;
47 this._cachedIndents = {};
50 FormattedContentBuilder.prototype = {
51 addToken: function(token)
53 for (var i = 0; i < token.comments_before.length; ++i)
54 this._addComment(token.comments_before[i]);
56 while (this._lineNumber < token.line) {
59 this._needNewLine = false;
60 this._lineNumber += 1;
63 if (this._needNewLine) {
66 this._needNewLine = false;
69 this._addMappingIfNeeded(token.pos);
70 this._addText(this._originalContent.substring(token.pos, token.endPos));
71 this._lineNumber = token.endLine;
79 addNewLine: function()
81 this._needNewLine = true;
84 increaseNestingLevel: function()
86 this._nestingLevel += 1;
89 decreaseNestingLevel: function()
91 this._nestingLevel -= 1;
96 return this._formattedContent.join("");
101 return { original: this._originalPositions, formatted: this._formattedPositions };
104 _addIndent: function()
106 if (this._cachedIndents[this._nestingLevel]) {
107 this._addText(this._cachedIndents[this._nestingLevel]);
112 for (var i = 0; i < this._nestingLevel; ++i)
113 fullIndent += this._indentString;
114 this._addText(fullIndent);
116 // Cache a maximum of 20 nesting level indents.
117 if (this._nestingLevel <= 20)
118 this._cachedIndents[this._nestingLevel] = fullIndent;
121 _addComment: function(comment)
123 if (this._lineNumber < comment.line) {
124 for (var j = this._lineNumber; j < comment.line; ++j)
126 this._lineNumber = comment.line;
127 this._needNewLine = false;
132 this._addMappingIfNeeded(comment.pos);
133 if (comment.type === "comment1")
138 this._addText(comment.value);
140 if (comment.type !== "comment1") {
143 while ((position = comment.value.indexOf("\n", position + 1)) !== -1)
144 this._lineNumber += 1;
148 _addText: function(text)
150 this._formattedContent.push(text);
151 this._formattedContentLength += text.length;
154 _addMappingIfNeeded: function(originalPosition)
156 if (originalPosition - this._lastOriginalPosition === this._formattedContentLength - this._lastFormattedPosition)
158 this._mapping.original.push(this._originalOffset + originalPosition);
159 this._lastOriginalPosition = originalPosition;
160 this._mapping.formatted.push(this._formattedOffset + this._formattedContentLength);
161 this._lastFormattedPosition = this._formattedContentLength;
167 ["LPAREN", "("], ["RPAREN", ")"], ["LBRACK", "["], ["RBRACK", "]"], ["LBRACE", "{"], ["RBRACE", "}"], ["COLON", ":"], ["SEMICOLON", ";"], ["PERIOD", "."], ["CONDITIONAL", "?"],
168 ["INC", "++"], ["DEC", "--"],
169 ["ASSIGN", "="], ["ASSIGN_BIT_OR", "|="], ["ASSIGN_BIT_XOR", "^="], ["ASSIGN_BIT_AND", "&="], ["ASSIGN_SHL", "<<="], ["ASSIGN_SAR", ">>="], ["ASSIGN_SHR", ">>>="],
170 ["ASSIGN_ADD", "+="], ["ASSIGN_SUB", "-="], ["ASSIGN_MUL", "*="], ["ASSIGN_DIV", "/="], ["ASSIGN_MOD", "%="],
171 ["COMMA", ","], ["OR", "||"], ["AND", "&&"], ["BIT_OR", "|"], ["BIT_XOR", "^"], ["BIT_AND", "&"], ["SHL", "<<"], ["SAR", ">>"], ["SHR", ">>>"],
172 ["ADD", "+"], ["SUB", "-"], ["MUL", "*"], ["DIV", "/"], ["MOD", "%"],
173 ["EQ", "=="], ["NE", "!="], ["EQ_STRICT", "==="], ["NE_STRICT", "!=="], ["LT", "<"], ["GT", ">"], ["LTE", "<="], ["GTE", ">="],
174 ["INSTANCEOF", "instanceof"], ["IN", "in"], ["NOT", "!"], ["BIT_NOT", "~"], ["DELETE", "delete"], ["TYPEOF", "typeof"], ["VOID", "void"],
175 ["BREAK", "break"], ["CASE", "case"], ["CATCH", "catch"], ["CONTINUE", "continue"], ["DEBUGGER", "debugger"], ["DEFAULT", "default"], ["DO", "do"], ["ELSE", "else"], ["FINALLY", "finally"],
176 ["FOR", "for"], ["FUNCTION", "function"], ["IF", "if"], ["NEW", "new"], ["RETURN", "return"], ["SWITCH", "switch"], ["THIS", "this"], ["THROW", "throw"], ["TRY", "try"], ["VAR", "var"],
177 ["WHILE", "while"], ["WITH", "with"], ["NULL_LITERAL", "null"], ["TRUE_LITERAL", "true"], ["FALSE_LITERAL", "false"], ["NUMBER"], ["STRING"], ["IDENTIFIER"], ["CONST", "const"]
181 for (var i = 0; i < tokens.length; ++i)
182 Tokens[tokens[i][0]] = i;
184 var TokensByValue = {};
185 for (var i = 0; i < tokens.length; ++i) {
187 TokensByValue[tokens[i][1]] = i;
192 "name": Tokens.IDENTIFIER,
193 "num": Tokens.NUMBER,
194 "regexp": Tokens.DIV,
195 "string": Tokens.STRING
198 function Tokenizer(content)
200 this._readNextToken = parse.tokenizer(content);
201 this._state = this._readNextToken.context();
204 Tokenizer.prototype = {
207 return this._state.text;
210 next: function(forceRegexp)
212 var uglifyToken = this._readNextToken(forceRegexp);
213 uglifyToken.endPos = this._state.pos;
214 uglifyToken.endLine = this._state.line;
215 uglifyToken.token = this._convertUglifyToken(uglifyToken);
219 _convertUglifyToken: function(uglifyToken)
221 var token = TokensByType[uglifyToken.type];
222 if (typeof token === "number")
224 token = TokensByValue[uglifyToken.value];
225 if (typeof token === "number")
227 throw "Unknown token type " + uglifyToken.type;
231 function JavaScriptFormatter(tokenizer, builder)
233 this._tokenizer = tokenizer;
234 this._builder = builder;
236 this._nextToken = this._tokenizer.next();
239 JavaScriptFormatter.prototype = {
242 this._parseSourceElements(Tokens.EOS);
243 this._consume(Tokens.EOS);
248 return this._nextToken.token;
253 if (this._token && this._token.token === Tokens.EOS)
254 throw "Unexpected EOS token";
256 this._builder.addToken(this._nextToken);
257 this._token = this._nextToken;
258 this._nextToken = this._tokenizer.next(this._forceRegexp);
259 this._forceRegexp = false;
260 return this._token.token;
263 _consume: function(token)
265 var next = this._next();
267 throw "Unexpected token in consume: expected " + token + ", actual " + next;
270 _expect: function(token)
272 var next = this._next();
274 throw "Unexpected token: expected " + token + ", actual " + next;
277 _expectSemicolon: function()
279 if (this._peek() === Tokens.SEMICOLON)
280 this._consume(Tokens.SEMICOLON);
283 _hasLineTerminatorBeforeNext: function()
285 return this._nextToken.nlb;
288 _parseSourceElements: function(endToken)
290 while (this._peek() !== endToken) {
291 this._parseStatement();
292 this._builder.addNewLine();
296 _parseStatementOrBlock: function()
298 if (this._peek() === Tokens.LBRACE) {
299 this._builder.addSpace();
304 this._builder.addNewLine();
305 this._builder.increaseNestingLevel();
306 this._parseStatement();
307 this._builder.decreaseNestingLevel();
310 _parseStatement: function()
312 switch (this._peek()) {
314 return this._parseBlock();
317 return this._parseVariableStatement();
318 case Tokens.SEMICOLON:
321 return this._parseIfStatement();
323 return this._parseDoWhileStatement();
325 return this._parseWhileStatement();
327 return this._parseForStatement();
328 case Tokens.CONTINUE:
329 return this._parseContinueStatement();
331 return this._parseBreakStatement();
333 return this._parseReturnStatement();
335 return this._parseWithStatement();
337 return this._parseSwitchStatement();
339 return this._parseThrowStatement();
341 return this._parseTryStatement();
342 case Tokens.FUNCTION:
343 return this._parseFunctionDeclaration();
344 case Tokens.DEBUGGER:
345 return this._parseDebuggerStatement();
347 return this._parseExpressionOrLabelledStatement();
351 _parseFunctionDeclaration: function()
353 this._expect(Tokens.FUNCTION);
354 this._builder.addSpace();
355 this._expect(Tokens.IDENTIFIER);
356 this._parseFunctionLiteral()
359 _parseBlock: function()
361 this._expect(Tokens.LBRACE);
362 this._builder.addNewLine();
363 this._builder.increaseNestingLevel();
364 while (this._peek() !== Tokens.RBRACE) {
365 this._parseStatement();
366 this._builder.addNewLine();
368 this._builder.decreaseNestingLevel();
369 this._expect(Tokens.RBRACE);
372 _parseVariableStatement: function()
374 this._parseVariableDeclarations();
375 this._expectSemicolon();
378 _parseVariableDeclarations: function()
380 if (this._peek() === Tokens.VAR)
381 this._consume(Tokens.VAR);
383 this._consume(Tokens.CONST)
384 this._builder.addSpace();
386 var isFirstVariable = true;
388 if (!isFirstVariable) {
389 this._consume(Tokens.COMMA);
390 this._builder.addSpace();
392 isFirstVariable = false;
393 this._expect(Tokens.IDENTIFIER);
394 if (this._peek() === Tokens.ASSIGN) {
395 this._builder.addSpace();
396 this._consume(Tokens.ASSIGN);
397 this._builder.addSpace();
398 this._parseAssignmentExpression();
400 } while (this._peek() === Tokens.COMMA);
403 _parseExpressionOrLabelledStatement: function()
405 this._parseExpression();
406 if (this._peek() === Tokens.COLON) {
407 this._expect(Tokens.COLON);
408 this._builder.addSpace();
409 this._parseStatement();
411 this._expectSemicolon();
414 _parseIfStatement: function()
416 this._expect(Tokens.IF);
417 this._builder.addSpace();
418 this._expect(Tokens.LPAREN);
419 this._parseExpression();
420 this._expect(Tokens.RPAREN);
422 var isBlock = this._parseStatementOrBlock();
423 if (this._peek() === Tokens.ELSE) {
425 this._builder.addSpace();
427 this._builder.addNewLine();
430 if (this._peek() === Tokens.IF) {
431 this._builder.addSpace();
432 this._parseStatement();
434 this._parseStatementOrBlock();
438 _parseContinueStatement: function()
440 this._expect(Tokens.CONTINUE);
441 var token = this._peek();
442 if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
443 this._builder.addSpace();
444 this._expect(Tokens.IDENTIFIER);
446 this._expectSemicolon();
449 _parseBreakStatement: function()
451 this._expect(Tokens.BREAK);
452 var token = this._peek();
453 if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
454 this._builder.addSpace();
455 this._expect(Tokens.IDENTIFIER);
457 this._expectSemicolon();
460 _parseReturnStatement: function()
462 this._expect(Tokens.RETURN);
463 var token = this._peek();
464 if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
465 this._builder.addSpace();
466 this._parseExpression();
468 this._expectSemicolon();
471 _parseWithStatement: function()
473 this._expect(Tokens.WITH);
474 this._builder.addSpace();
475 this._expect(Tokens.LPAREN);
476 this._parseExpression();
477 this._expect(Tokens.RPAREN);
478 this._parseStatementOrBlock();
481 _parseCaseClause: function()
483 if (this._peek() === Tokens.CASE) {
484 this._expect(Tokens.CASE);
485 this._builder.addSpace();
486 this._parseExpression();
488 this._expect(Tokens.DEFAULT);
489 this._expect(Tokens.COLON);
490 this._builder.addNewLine();
492 this._builder.increaseNestingLevel();
493 while (this._peek() !== Tokens.CASE && this._peek() !== Tokens.DEFAULT && this._peek() !== Tokens.RBRACE) {
494 this._parseStatement();
495 this._builder.addNewLine();
497 this._builder.decreaseNestingLevel();
500 _parseSwitchStatement: function()
502 this._expect(Tokens.SWITCH);
503 this._builder.addSpace();
504 this._expect(Tokens.LPAREN);
505 this._parseExpression();
506 this._expect(Tokens.RPAREN);
507 this._builder.addSpace();
509 this._expect(Tokens.LBRACE);
510 this._builder.addNewLine();
511 this._builder.increaseNestingLevel();
512 while (this._peek() !== Tokens.RBRACE)
513 this._parseCaseClause();
514 this._builder.decreaseNestingLevel();
515 this._expect(Tokens.RBRACE);
518 _parseThrowStatement: function()
520 this._expect(Tokens.THROW);
521 this._builder.addSpace();
522 this._parseExpression();
523 this._expectSemicolon();
526 _parseTryStatement: function()
528 this._expect(Tokens.TRY);
529 this._builder.addSpace();
532 var token = this._peek();
533 if (token === Tokens.CATCH) {
534 this._builder.addSpace();
535 this._consume(Tokens.CATCH);
536 this._builder.addSpace();
537 this._expect(Tokens.LPAREN);
538 this._expect(Tokens.IDENTIFIER);
539 this._expect(Tokens.RPAREN);
540 this._builder.addSpace();
542 token = this._peek();
545 if (token === Tokens.FINALLY) {
546 this._consume(Tokens.FINALLY);
547 this._builder.addSpace();
552 _parseDoWhileStatement: function()
554 this._expect(Tokens.DO);
555 var isBlock = this._parseStatementOrBlock();
557 this._builder.addSpace();
559 this._builder.addNewLine();
560 this._expect(Tokens.WHILE);
561 this._builder.addSpace();
562 this._expect(Tokens.LPAREN);
563 this._parseExpression();
564 this._expect(Tokens.RPAREN);
565 this._expectSemicolon();
568 _parseWhileStatement: function()
570 this._expect(Tokens.WHILE);
571 this._builder.addSpace();
572 this._expect(Tokens.LPAREN);
573 this._parseExpression();
574 this._expect(Tokens.RPAREN);
575 this._parseStatementOrBlock();
578 _parseForStatement: function()
580 this._expect(Tokens.FOR);
581 this._builder.addSpace();
582 this._expect(Tokens.LPAREN);
583 if (this._peek() !== Tokens.SEMICOLON) {
584 if (this._peek() === Tokens.VAR || this._peek() === Tokens.CONST) {
585 this._parseVariableDeclarations();
586 if (this._peek() === Tokens.IN) {
587 this._builder.addSpace();
588 this._consume(Tokens.IN);
589 this._builder.addSpace();
590 this._parseExpression();
593 this._parseExpression();
596 if (this._peek() !== Tokens.RPAREN) {
597 this._expect(Tokens.SEMICOLON);
598 this._builder.addSpace();
599 if (this._peek() !== Tokens.SEMICOLON)
600 this._parseExpression();
601 this._expect(Tokens.SEMICOLON);
602 this._builder.addSpace();
603 if (this._peek() !== Tokens.RPAREN)
604 this._parseExpression();
606 this._expect(Tokens.RPAREN);
608 this._parseStatementOrBlock();
611 _parseExpression: function()
613 this._parseAssignmentExpression();
614 while (this._peek() === Tokens.COMMA) {
615 this._expect(Tokens.COMMA);
616 this._builder.addSpace();
617 this._parseAssignmentExpression();
621 _parseAssignmentExpression: function()
623 this._parseConditionalExpression();
624 var token = this._peek();
625 if (Tokens.ASSIGN <= token && token <= Tokens.ASSIGN_MOD) {
626 this._builder.addSpace();
628 this._builder.addSpace();
629 this._parseAssignmentExpression();
633 _parseConditionalExpression: function()
635 this._parseBinaryExpression();
636 if (this._peek() === Tokens.CONDITIONAL) {
637 this._builder.addSpace();
638 this._consume(Tokens.CONDITIONAL);
639 this._builder.addSpace();
640 this._parseAssignmentExpression();
641 this._builder.addSpace();
642 this._expect(Tokens.COLON);
643 this._builder.addSpace();
644 this._parseAssignmentExpression();
648 _parseBinaryExpression: function()
650 this._parseUnaryExpression();
651 var token = this._peek();
652 while (Tokens.OR <= token && token <= Tokens.IN) {
653 this._builder.addSpace();
655 this._builder.addSpace();
656 this._parseBinaryExpression();
657 token = this._peek();
661 _parseUnaryExpression: function()
663 var token = this._peek();
664 if ((Tokens.NOT <= token && token <= Tokens.VOID) || token === Tokens.ADD || token === Tokens.SUB || token === Tokens.INC || token === Tokens.DEC) {
666 if (token === Tokens.DELETE || token === Tokens.TYPEOF || token === Tokens.VOID)
667 this._builder.addSpace();
668 this._parseUnaryExpression();
670 return this._parsePostfixExpression();
673 _parsePostfixExpression: function()
675 this._parseLeftHandSideExpression();
676 var token = this._peek();
677 if (!this._hasLineTerminatorBeforeNext() && (token === Tokens.INC || token === Tokens.DEC))
681 _parseLeftHandSideExpression: function()
683 if (this._peek() === Tokens.NEW)
684 this._parseNewExpression();
686 this._parseMemberExpression();
689 switch (this._peek()) {
691 this._consume(Tokens.LBRACK);
692 this._parseExpression();
693 this._expect(Tokens.RBRACK);
697 this._parseArguments();
701 this._consume(Tokens.PERIOD);
702 this._expect(Tokens.IDENTIFIER);
711 _parseNewExpression: function()
713 this._expect(Tokens.NEW);
714 this._builder.addSpace();
715 if (this._peek() === Tokens.NEW)
716 this._parseNewExpression();
718 this._parseMemberExpression();
721 _parseMemberExpression: function()
723 if (this._peek() === Tokens.FUNCTION) {
724 this._expect(Tokens.FUNCTION);
725 if (this._peek() === Tokens.IDENTIFIER) {
726 this._builder.addSpace();
727 this._expect(Tokens.IDENTIFIER);
729 this._parseFunctionLiteral();
731 this._parsePrimaryExpression();
734 switch (this._peek()) {
736 this._consume(Tokens.LBRACK);
737 this._parseExpression();
738 this._expect(Tokens.RBRACK);
742 this._consume(Tokens.PERIOD);
743 this._expect(Tokens.IDENTIFIER);
747 this._parseArguments();
756 _parseDebuggerStatement: function()
758 this._expect(Tokens.DEBUGGER);
759 this._expectSemicolon();
762 _parsePrimaryExpression: function()
764 switch (this._peek()) {
766 return this._consume(Tokens.THIS);
767 case Tokens.NULL_LITERAL:
768 return this._consume(Tokens.NULL_LITERAL);
769 case Tokens.TRUE_LITERAL:
770 return this._consume(Tokens.TRUE_LITERAL);
771 case Tokens.FALSE_LITERAL:
772 return this._consume(Tokens.FALSE_LITERAL);
773 case Tokens.IDENTIFIER:
774 return this._consume(Tokens.IDENTIFIER);
776 return this._consume(Tokens.NUMBER);
778 return this._consume(Tokens.STRING);
779 case Tokens.ASSIGN_DIV:
780 return this._parseRegExpLiteral();
782 return this._parseRegExpLiteral();
784 return this._parseArrayLiteral();
786 return this._parseObjectLiteral();
788 this._consume(Tokens.LPAREN);
789 this._parseExpression();
790 this._expect(Tokens.RPAREN);
797 _parseArrayLiteral: function()
799 this._expect(Tokens.LBRACK);
800 this._builder.increaseNestingLevel();
801 while (this._peek() !== Tokens.RBRACK) {
802 if (this._peek() !== Tokens.COMMA)
803 this._parseAssignmentExpression();
804 if (this._peek() !== Tokens.RBRACK) {
805 this._expect(Tokens.COMMA);
806 this._builder.addSpace();
809 this._builder.decreaseNestingLevel();
810 this._expect(Tokens.RBRACK);
813 _parseObjectLiteralGetSet: function()
815 var token = this._peek();
816 if (token === Tokens.IDENTIFIER || token === Tokens.NUMBER || token === Tokens.STRING ||
817 Tokens.DELETE <= token && token <= Tokens.FALSE_LITERAL ||
818 token === Tokens.INSTANCEOF || token === Tokens.IN || token === Tokens.CONST) {
820 this._parseFunctionLiteral();
824 _parseObjectLiteral: function()
826 this._expect(Tokens.LBRACE);
827 this._builder.increaseNestingLevel();
828 while (this._peek() !== Tokens.RBRACE) {
829 var token = this._peek();
831 case Tokens.IDENTIFIER:
832 this._consume(Tokens.IDENTIFIER);
833 var name = this._token.value;
834 if ((name === "get" || name === "set") && this._peek() !== Tokens.COLON) {
835 this._builder.addSpace();
836 this._parseObjectLiteralGetSet();
837 if (this._peek() !== Tokens.RBRACE) {
838 this._expect(Tokens.COMMA);
845 this._consume(Tokens.STRING);
849 this._consume(Tokens.NUMBER);
856 this._expect(Tokens.COLON);
857 this._builder.addSpace();
858 this._parseAssignmentExpression();
859 if (this._peek() !== Tokens.RBRACE) {
860 this._expect(Tokens.COMMA);
863 this._builder.decreaseNestingLevel();
865 this._expect(Tokens.RBRACE);
868 _parseRegExpLiteral: function()
870 if (this._nextToken.type === "regexp")
873 this._forceRegexp = true;
878 _parseArguments: function()
880 this._expect(Tokens.LPAREN);
881 var done = (this._peek() === Tokens.RPAREN);
883 this._parseAssignmentExpression();
884 done = (this._peek() === Tokens.RPAREN);
886 this._expect(Tokens.COMMA);
887 this._builder.addSpace();
890 this._expect(Tokens.RPAREN);
893 _parseFunctionLiteral: function()
895 this._expect(Tokens.LPAREN);
896 var done = (this._peek() === Tokens.RPAREN);
898 this._expect(Tokens.IDENTIFIER);
899 done = (this._peek() === Tokens.RPAREN);
901 this._expect(Tokens.COMMA);
902 this._builder.addSpace();
905 this._expect(Tokens.RPAREN);
906 this._builder.addSpace();
908 this._expect(Tokens.LBRACE);
909 this._builder.addNewLine();
910 this._builder.increaseNestingLevel();
911 this._parseSourceElements(Tokens.RBRACE);
912 this._builder.decreaseNestingLevel();
913 this._expect(Tokens.RBRACE);