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)
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._nestingLevelLevel = 0;
48 FormattedContentBuilder.prototype = {
49 addToken: function(token)
51 for (var i = 0; i < token.comments_before.length; ++i)
52 this._addComment(token.comments_before[i]);
54 while (this._lineNumber < token.line) {
57 this._needNewLine = false;
58 this._lineNumber += 1;
61 if (this._needNewLine) {
64 this._needNewLine = false;
67 this._addMappingIfNeeded(token.pos);
68 this._addText(this._originalContent.substring(token.pos, token.endPos));
69 this._lineNumber = token.endLine;
77 addNewLine: function()
79 this._needNewLine = true;
82 increaseNestingLevel: function()
84 this._nestingLevelLevel += 1;
87 decreaseNestingLevel: function()
89 this._nestingLevelLevel -= 1;
94 return this._formattedContent.join("");
99 return { original: this._originalPositions, formatted: this._formattedPositions };
102 _addIndent: function()
104 for (var i = 0; i < this._nestingLevelLevel * 4; ++i)
108 _addComment: function(comment)
110 if (this._lineNumber < comment.line) {
111 for (var j = this._lineNumber; j < comment.line; ++j)
113 this._lineNumber = comment.line;
114 this._needNewLine = false;
119 this._addMappingIfNeeded(comment.pos);
120 if (comment.type === "comment1")
125 this._addText(comment.value);
127 if (comment.type !== "comment1") {
130 while ((position = comment.value.indexOf("\n", position + 1)) !== -1)
131 this._lineNumber += 1;
135 _addText: function(text)
137 this._formattedContent.push(text);
138 this._formattedContentLength += text.length;
141 _addMappingIfNeeded: function(originalPosition)
143 if (originalPosition - this._lastOriginalPosition === this._formattedContentLength - this._lastFormattedPosition)
145 this._mapping.original.push(this._originalOffset + originalPosition);
146 this._lastOriginalPosition = originalPosition;
147 this._mapping.formatted.push(this._formattedOffset + this._formattedContentLength);
148 this._lastFormattedPosition = this._formattedContentLength;
154 ["LPAREN", "("], ["RPAREN", ")"], ["LBRACK", "["], ["RBRACK", "]"], ["LBRACE", "{"], ["RBRACE", "}"], ["COLON", ":"], ["SEMICOLON", ";"], ["PERIOD", "."], ["CONDITIONAL", "?"],
155 ["INC", "++"], ["DEC", "--"],
156 ["ASSIGN", "="], ["ASSIGN_BIT_OR", "|="], ["ASSIGN_BIT_XOR", "^="], ["ASSIGN_BIT_AND", "&="], ["ASSIGN_SHL", "<<="], ["ASSIGN_SAR", ">>="], ["ASSIGN_SHR", ">>>="],
157 ["ASSIGN_ADD", "+="], ["ASSIGN_SUB", "-="], ["ASSIGN_MUL", "*="], ["ASSIGN_DIV", "/="], ["ASSIGN_MOD", "%="],
158 ["COMMA", ","], ["OR", "||"], ["AND", "&&"], ["BIT_OR", "|"], ["BIT_XOR", "^"], ["BIT_AND", "&"], ["SHL", "<<"], ["SAR", ">>"], ["SHR", ">>>"],
159 ["ADD", "+"], ["SUB", "-"], ["MUL", "*"], ["DIV", "/"], ["MOD", "%"],
160 ["EQ", "=="], ["NE", "!="], ["EQ_STRICT", "==="], ["NE_STRICT", "!=="], ["LT", "<"], ["GT", ">"], ["LTE", "<="], ["GTE", ">="],
161 ["INSTANCEOF", "instanceof"], ["IN", "in"], ["NOT", "!"], ["BIT_NOT", "~"], ["DELETE", "delete"], ["TYPEOF", "typeof"], ["VOID", "void"],
162 ["BREAK", "break"], ["CASE", "case"], ["CATCH", "catch"], ["CONTINUE", "continue"], ["DEBUGGER", "debugger"], ["DEFAULT", "default"], ["DO", "do"], ["ELSE", "else"], ["FINALLY", "finally"],
163 ["FOR", "for"], ["FUNCTION", "function"], ["IF", "if"], ["NEW", "new"], ["RETURN", "return"], ["SWITCH", "switch"], ["THIS", "this"], ["THROW", "throw"], ["TRY", "try"], ["VAR", "var"],
164 ["WHILE", "while"], ["WITH", "with"], ["NULL_LITERAL", "null"], ["TRUE_LITERAL", "true"], ["FALSE_LITERAL", "false"], ["NUMBER"], ["STRING"], ["IDENTIFIER"], ["CONST", "const"]
168 for (var i = 0; i < tokens.length; ++i)
169 Tokens[tokens[i][0]] = i;
171 var TokensByValue = {};
172 for (var i = 0; i < tokens.length; ++i) {
174 TokensByValue[tokens[i][1]] = i;
179 "name": Tokens.IDENTIFIER,
180 "num": Tokens.NUMBER,
181 "regexp": Tokens.DIV,
182 "string": Tokens.STRING
185 function Tokenizer(content)
187 this._readNextToken = parse.tokenizer(content);
188 this._state = this._readNextToken.context();
191 Tokenizer.prototype = {
194 return this._state.text;
197 next: function(forceRegexp)
199 var uglifyToken = this._readNextToken(forceRegexp);
200 uglifyToken.endPos = this._state.pos;
201 uglifyToken.endLine = this._state.line;
202 uglifyToken.token = this._convertUglifyToken(uglifyToken);
206 _convertUglifyToken: function(uglifyToken)
208 var token = TokensByType[uglifyToken.type];
209 if (typeof token === "number")
211 token = TokensByValue[uglifyToken.value];
212 if (typeof token === "number")
214 throw "Unknown token type " + uglifyToken.type;
218 function JavaScriptFormatter(tokenizer, builder)
220 this._tokenizer = tokenizer;
221 this._builder = builder;
223 this._nextToken = this._tokenizer.next();
226 JavaScriptFormatter.prototype = {
229 this._parseSourceElements(Tokens.EOS);
230 this._consume(Tokens.EOS);
235 return this._nextToken.token;
240 if (this._token && this._token.token === Tokens.EOS)
241 throw "Unexpected EOS token";
243 this._builder.addToken(this._nextToken);
244 this._token = this._nextToken;
245 this._nextToken = this._tokenizer.next(this._forceRegexp);
246 this._forceRegexp = false;
247 return this._token.token;
250 _consume: function(token)
252 var next = this._next();
254 throw "Unexpected token in consume: expected " + token + ", actual " + next;
257 _expect: function(token)
259 var next = this._next();
261 throw "Unexpected token: expected " + token + ", actual " + next;
264 _expectSemicolon: function()
266 if (this._peek() === Tokens.SEMICOLON)
267 this._consume(Tokens.SEMICOLON);
270 _hasLineTerminatorBeforeNext: function()
272 return this._nextToken.nlb;
275 _parseSourceElements: function(endToken)
277 while (this._peek() !== endToken) {
278 this._parseStatement();
279 this._builder.addNewLine();
283 _parseStatementOrBlock: function()
285 if (this._peek() === Tokens.LBRACE) {
286 this._builder.addSpace();
291 this._builder.addNewLine();
292 this._builder.increaseNestingLevel();
293 this._parseStatement();
294 this._builder.decreaseNestingLevel();
297 _parseStatement: function()
299 switch (this._peek()) {
301 return this._parseBlock();
304 return this._parseVariableStatement();
305 case Tokens.SEMICOLON:
308 return this._parseIfStatement();
310 return this._parseDoWhileStatement();
312 return this._parseWhileStatement();
314 return this._parseForStatement();
315 case Tokens.CONTINUE:
316 return this._parseContinueStatement();
318 return this._parseBreakStatement();
320 return this._parseReturnStatement();
322 return this._parseWithStatement();
324 return this._parseSwitchStatement();
326 return this._parseThrowStatement();
328 return this._parseTryStatement();
329 case Tokens.FUNCTION:
330 return this._parseFunctionDeclaration();
331 case Tokens.DEBUGGER:
332 return this._parseDebuggerStatement();
334 return this._parseExpressionOrLabelledStatement();
338 _parseFunctionDeclaration: function()
340 this._expect(Tokens.FUNCTION);
341 this._builder.addSpace();
342 this._expect(Tokens.IDENTIFIER);
343 this._parseFunctionLiteral()
346 _parseBlock: function()
348 this._expect(Tokens.LBRACE);
349 this._builder.addNewLine();
350 this._builder.increaseNestingLevel();
351 while (this._peek() !== Tokens.RBRACE) {
352 this._parseStatement();
353 this._builder.addNewLine();
355 this._builder.decreaseNestingLevel();
356 this._expect(Tokens.RBRACE);
359 _parseVariableStatement: function()
361 this._parseVariableDeclarations();
362 this._expectSemicolon();
365 _parseVariableDeclarations: function()
367 if (this._peek() === Tokens.VAR)
368 this._consume(Tokens.VAR);
370 this._consume(Tokens.CONST)
371 this._builder.addSpace();
373 var isFirstVariable = true;
375 if (!isFirstVariable) {
376 this._consume(Tokens.COMMA);
377 this._builder.addSpace();
379 isFirstVariable = false;
380 this._expect(Tokens.IDENTIFIER);
381 if (this._peek() === Tokens.ASSIGN) {
382 this._builder.addSpace();
383 this._consume(Tokens.ASSIGN);
384 this._builder.addSpace();
385 this._parseAssignmentExpression();
387 } while (this._peek() === Tokens.COMMA);
390 _parseExpressionOrLabelledStatement: function()
392 this._parseExpression();
393 if (this._peek() === Tokens.COLON) {
394 this._expect(Tokens.COLON);
395 this._builder.addSpace();
396 this._parseStatement();
398 this._expectSemicolon();
401 _parseIfStatement: function()
403 this._expect(Tokens.IF);
404 this._builder.addSpace();
405 this._expect(Tokens.LPAREN);
406 this._parseExpression();
407 this._expect(Tokens.RPAREN);
409 var isBlock = this._parseStatementOrBlock();
410 if (this._peek() === Tokens.ELSE) {
412 this._builder.addSpace();
414 this._builder.addNewLine();
417 if (this._peek() === Tokens.IF) {
418 this._builder.addSpace();
419 this._parseStatement();
421 this._parseStatementOrBlock();
425 _parseContinueStatement: function()
427 this._expect(Tokens.CONTINUE);
428 var token = this._peek();
429 if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
430 this._builder.addSpace();
431 this._expect(Tokens.IDENTIFIER);
433 this._expectSemicolon();
436 _parseBreakStatement: function()
438 this._expect(Tokens.BREAK);
439 var token = this._peek();
440 if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
441 this._builder.addSpace();
442 this._expect(Tokens.IDENTIFIER);
444 this._expectSemicolon();
447 _parseReturnStatement: function()
449 this._expect(Tokens.RETURN);
450 var token = this._peek();
451 if (!this._hasLineTerminatorBeforeNext() && token !== Tokens.SEMICOLON && token !== Tokens.RBRACE && token !== Tokens.EOS) {
452 this._builder.addSpace();
453 this._parseExpression();
455 this._expectSemicolon();
458 _parseWithStatement: function()
460 this._expect(Tokens.WITH);
461 this._builder.addSpace();
462 this._expect(Tokens.LPAREN);
463 this._parseExpression();
464 this._expect(Tokens.RPAREN);
465 this._parseStatementOrBlock();
468 _parseCaseClause: function()
470 if (this._peek() === Tokens.CASE) {
471 this._expect(Tokens.CASE);
472 this._builder.addSpace();
473 this._parseExpression();
475 this._expect(Tokens.DEFAULT);
476 this._expect(Tokens.COLON);
477 this._builder.addNewLine();
479 this._builder.increaseNestingLevel();
480 while (this._peek() !== Tokens.CASE && this._peek() !== Tokens.DEFAULT && this._peek() !== Tokens.RBRACE) {
481 this._parseStatement();
482 this._builder.addNewLine();
484 this._builder.decreaseNestingLevel();
487 _parseSwitchStatement: function()
489 this._expect(Tokens.SWITCH);
490 this._builder.addSpace();
491 this._expect(Tokens.LPAREN);
492 this._parseExpression();
493 this._expect(Tokens.RPAREN);
494 this._builder.addSpace();
496 this._expect(Tokens.LBRACE);
497 this._builder.addNewLine();
498 this._builder.increaseNestingLevel();
499 while (this._peek() !== Tokens.RBRACE)
500 this._parseCaseClause();
501 this._builder.decreaseNestingLevel();
502 this._expect(Tokens.RBRACE);
505 _parseThrowStatement: function()
507 this._expect(Tokens.THROW);
508 this._builder.addSpace();
509 this._parseExpression();
510 this._expectSemicolon();
513 _parseTryStatement: function()
515 this._expect(Tokens.TRY);
516 this._builder.addSpace();
519 var token = this._peek();
520 if (token === Tokens.CATCH) {
521 this._builder.addSpace();
522 this._consume(Tokens.CATCH);
523 this._builder.addSpace();
524 this._expect(Tokens.LPAREN);
525 this._expect(Tokens.IDENTIFIER);
526 this._expect(Tokens.RPAREN);
527 this._builder.addSpace();
529 token = this._peek();
532 if (token === Tokens.FINALLY) {
533 this._consume(Tokens.FINALLY);
534 this._builder.addSpace();
539 _parseDoWhileStatement: function()
541 this._expect(Tokens.DO);
542 var isBlock = this._parseStatementOrBlock();
544 this._builder.addSpace();
546 this._builder.addNewLine();
547 this._expect(Tokens.WHILE);
548 this._builder.addSpace();
549 this._expect(Tokens.LPAREN);
550 this._parseExpression();
551 this._expect(Tokens.RPAREN);
552 this._expectSemicolon();
555 _parseWhileStatement: function()
557 this._expect(Tokens.WHILE);
558 this._builder.addSpace();
559 this._expect(Tokens.LPAREN);
560 this._parseExpression();
561 this._expect(Tokens.RPAREN);
562 this._parseStatementOrBlock();
565 _parseForStatement: function()
567 this._expect(Tokens.FOR);
568 this._builder.addSpace();
569 this._expect(Tokens.LPAREN);
570 if (this._peek() !== Tokens.SEMICOLON) {
571 if (this._peek() === Tokens.VAR || this._peek() === Tokens.CONST) {
572 this._parseVariableDeclarations();
573 if (this._peek() === Tokens.IN) {
574 this._builder.addSpace();
575 this._consume(Tokens.IN);
576 this._builder.addSpace();
577 this._parseExpression();
580 this._parseExpression();
583 if (this._peek() !== Tokens.RPAREN) {
584 this._expect(Tokens.SEMICOLON);
585 this._builder.addSpace();
586 if (this._peek() !== Tokens.SEMICOLON)
587 this._parseExpression();
588 this._expect(Tokens.SEMICOLON);
589 this._builder.addSpace();
590 if (this._peek() !== Tokens.RPAREN)
591 this._parseExpression();
593 this._expect(Tokens.RPAREN);
595 this._parseStatementOrBlock();
598 _parseExpression: function()
600 this._parseAssignmentExpression();
601 while (this._peek() === Tokens.COMMA) {
602 this._expect(Tokens.COMMA);
603 this._builder.addSpace();
604 this._parseAssignmentExpression();
608 _parseAssignmentExpression: function()
610 this._parseConditionalExpression();
611 var token = this._peek();
612 if (Tokens.ASSIGN <= token && token <= Tokens.ASSIGN_MOD) {
613 this._builder.addSpace();
615 this._builder.addSpace();
616 this._parseAssignmentExpression();
620 _parseConditionalExpression: function()
622 this._parseBinaryExpression();
623 if (this._peek() === Tokens.CONDITIONAL) {
624 this._builder.addSpace();
625 this._consume(Tokens.CONDITIONAL);
626 this._builder.addSpace();
627 this._parseAssignmentExpression();
628 this._builder.addSpace();
629 this._expect(Tokens.COLON);
630 this._builder.addSpace();
631 this._parseAssignmentExpression();
635 _parseBinaryExpression: function()
637 this._parseUnaryExpression();
638 var token = this._peek();
639 while (Tokens.OR <= token && token <= Tokens.IN) {
640 this._builder.addSpace();
642 this._builder.addSpace();
643 this._parseBinaryExpression();
644 token = this._peek();
648 _parseUnaryExpression: function()
650 var token = this._peek();
651 if ((Tokens.NOT <= token && token <= Tokens.VOID) || token === Tokens.ADD || token === Tokens.SUB || token === Tokens.INC || token === Tokens.DEC) {
653 if (token === Tokens.DELETE || token === Tokens.TYPEOF || token === Tokens.VOID)
654 this._builder.addSpace();
655 this._parseUnaryExpression();
657 return this._parsePostfixExpression();
660 _parsePostfixExpression: function()
662 this._parseLeftHandSideExpression();
663 var token = this._peek();
664 if (!this._hasLineTerminatorBeforeNext() && (token === Tokens.INC || token === Tokens.DEC))
668 _parseLeftHandSideExpression: function()
670 if (this._peek() === Tokens.NEW)
671 this._parseNewExpression();
673 this._parseMemberExpression();
676 switch (this._peek()) {
678 this._consume(Tokens.LBRACK);
679 this._parseExpression();
680 this._expect(Tokens.RBRACK);
684 this._parseArguments();
688 this._consume(Tokens.PERIOD);
689 this._expect(Tokens.IDENTIFIER);
698 _parseNewExpression: function()
700 this._expect(Tokens.NEW);
701 this._builder.addSpace();
702 if (this._peek() === Tokens.NEW)
703 this._parseNewExpression();
705 this._parseMemberExpression();
708 _parseMemberExpression: function()
710 if (this._peek() === Tokens.FUNCTION) {
711 this._expect(Tokens.FUNCTION);
712 if (this._peek() === Tokens.IDENTIFIER) {
713 this._builder.addSpace();
714 this._expect(Tokens.IDENTIFIER);
716 this._parseFunctionLiteral();
718 this._parsePrimaryExpression();
721 switch (this._peek()) {
723 this._consume(Tokens.LBRACK);
724 this._parseExpression();
725 this._expect(Tokens.RBRACK);
729 this._consume(Tokens.PERIOD);
730 this._expect(Tokens.IDENTIFIER);
734 this._parseArguments();
743 _parseDebuggerStatement: function()
745 this._expect(Tokens.DEBUGGER);
746 this._expectSemicolon();
749 _parsePrimaryExpression: function()
751 switch (this._peek()) {
753 return this._consume(Tokens.THIS);
754 case Tokens.NULL_LITERAL:
755 return this._consume(Tokens.NULL_LITERAL);
756 case Tokens.TRUE_LITERAL:
757 return this._consume(Tokens.TRUE_LITERAL);
758 case Tokens.FALSE_LITERAL:
759 return this._consume(Tokens.FALSE_LITERAL);
760 case Tokens.IDENTIFIER:
761 return this._consume(Tokens.IDENTIFIER);
763 return this._consume(Tokens.NUMBER);
765 return this._consume(Tokens.STRING);
766 case Tokens.ASSIGN_DIV:
767 return this._parseRegExpLiteral();
769 return this._parseRegExpLiteral();
771 return this._parseArrayLiteral();
773 return this._parseObjectLiteral();
775 this._consume(Tokens.LPAREN);
776 this._parseExpression();
777 this._expect(Tokens.RPAREN);
784 _parseArrayLiteral: function()
786 this._expect(Tokens.LBRACK);
787 this._builder.increaseNestingLevel();
788 while (this._peek() !== Tokens.RBRACK) {
789 if (this._peek() !== Tokens.COMMA)
790 this._parseAssignmentExpression();
791 if (this._peek() !== Tokens.RBRACK) {
792 this._expect(Tokens.COMMA);
793 this._builder.addSpace();
796 this._builder.decreaseNestingLevel();
797 this._expect(Tokens.RBRACK);
800 _parseObjectLiteralGetSet: function()
802 var token = this._peek();
803 if (token === Tokens.IDENTIFIER || token === Tokens.NUMBER || token === Tokens.STRING ||
804 Tokens.DELETE <= token && token <= Tokens.FALSE_LITERAL ||
805 token === Tokens.INSTANCEOF || token === Tokens.IN || token === Tokens.CONST) {
807 this._parseFunctionLiteral();
811 _parseObjectLiteral: function()
813 this._expect(Tokens.LBRACE);
814 this._builder.increaseNestingLevel();
815 while (this._peek() !== Tokens.RBRACE) {
816 var token = this._peek();
818 case Tokens.IDENTIFIER:
819 this._consume(Tokens.IDENTIFIER);
820 var name = this._token.value;
821 if ((name === "get" || name === "set") && this._peek() !== Tokens.COLON) {
822 this._builder.addSpace();
823 this._parseObjectLiteralGetSet();
824 if (this._peek() !== Tokens.RBRACE) {
825 this._expect(Tokens.COMMA);
832 this._consume(Tokens.STRING);
836 this._consume(Tokens.NUMBER);
843 this._expect(Tokens.COLON);
844 this._builder.addSpace();
845 this._parseAssignmentExpression();
846 if (this._peek() !== Tokens.RBRACE) {
847 this._expect(Tokens.COMMA);
850 this._builder.decreaseNestingLevel();
852 this._expect(Tokens.RBRACE);
855 _parseRegExpLiteral: function()
857 if (this._nextToken.type === "regexp")
860 this._forceRegexp = true;
865 _parseArguments: function()
867 this._expect(Tokens.LPAREN);
868 var done = (this._peek() === Tokens.RPAREN);
870 this._parseAssignmentExpression();
871 done = (this._peek() === Tokens.RPAREN);
873 this._expect(Tokens.COMMA);
874 this._builder.addSpace();
877 this._expect(Tokens.RPAREN);
880 _parseFunctionLiteral: function()
882 this._expect(Tokens.LPAREN);
883 var done = (this._peek() === Tokens.RPAREN);
885 this._expect(Tokens.IDENTIFIER);
886 done = (this._peek() === Tokens.RPAREN);
888 this._expect(Tokens.COMMA);
889 this._builder.addSpace();
892 this._expect(Tokens.RPAREN);
893 this._builder.addSpace();
895 this._expect(Tokens.LBRACE);
896 this._builder.addNewLine();
897 this._builder.increaseNestingLevel();
898 this._parseSourceElements(Tokens.RBRACE);
899 this._builder.decreaseNestingLevel();
900 this._expect(Tokens.RBRACE);