tizen beta release
[profile/ivi/webkit-efl.git] / debian / tmp / usr / share / ewebkit-0 / webinspector / JavaScriptFormatter.js
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 function FormattedContentBuilder(content, mapping, originalOffset, formattedOffset, indentString)
32 {
33     this._originalContent = content;
34     this._originalOffset = originalOffset;
35     this._lastOriginalPosition = 0;
36
37     this._formattedContent = [];
38     this._formattedContentLength = 0;
39     this._formattedOffset = formattedOffset;
40     this._lastFormattedPosition = 0;
41
42     this._mapping = mapping;
43
44     this._lineNumber = 0;
45     this._nestingLevel = 0;
46     this._indentString = indentString;
47     this._cachedIndents = {};
48 }
49
50 FormattedContentBuilder.prototype = {
51     addToken: function(token)
52     {
53         for (var i = 0; i < token.comments_before.length; ++i)
54             this._addComment(token.comments_before[i]);
55
56         while (this._lineNumber < token.line) {
57             this._addText("\n");
58             this._addIndent();
59             this._needNewLine = false;
60             this._lineNumber += 1;
61         }
62
63         if (this._needNewLine) {
64             this._addText("\n");
65             this._addIndent();
66             this._needNewLine = false;
67         }
68
69         this._addMappingIfNeeded(token.pos);
70         this._addText(this._originalContent.substring(token.pos, token.endPos));
71         this._lineNumber = token.endLine;
72     },
73
74     addSpace: function()
75     {
76         this._addText(" ");
77     },
78
79     addNewLine: function()
80     {
81         this._needNewLine = true;
82     },
83
84     increaseNestingLevel: function()
85     {
86         this._nestingLevel += 1;
87     },
88
89     decreaseNestingLevel: function()
90     {
91         this._nestingLevel -= 1;
92     },
93
94     content: function()
95     {
96         return this._formattedContent.join("");
97     },
98
99     mapping: function()
100     {
101         return { original: this._originalPositions, formatted: this._formattedPositions };
102     },
103
104     _addIndent: function()
105     {
106         if (this._cachedIndents[this._nestingLevel]) {
107             this._addText(this._cachedIndents[this._nestingLevel]);
108             return;
109         }
110
111         var fullIndent = "";
112         for (var i = 0; i < this._nestingLevel; ++i)
113             fullIndent += this._indentString;
114         this._addText(fullIndent);
115
116         // Cache a maximum of 20 nesting level indents.
117         if (this._nestingLevel <= 20)
118             this._cachedIndents[this._nestingLevel] = fullIndent;
119     },
120
121     _addComment: function(comment)
122     {
123         if (this._lineNumber < comment.line) {
124             for (var j = this._lineNumber; j < comment.line; ++j)
125                 this._addText("\n");
126             this._lineNumber = comment.line;
127             this._needNewLine = false;
128             this._addIndent();
129         } else
130             this.addSpace();
131
132         this._addMappingIfNeeded(comment.pos);
133         if (comment.type === "comment1")
134             this._addText("//");
135         else
136             this._addText("/*");
137
138         this._addText(comment.value);
139
140         if (comment.type !== "comment1") {
141             this._addText("*/");
142             var position;
143             while ((position = comment.value.indexOf("\n", position + 1)) !== -1)
144                 this._lineNumber += 1;
145         }
146     },
147
148     _addText: function(text)
149     {
150         this._formattedContent.push(text);
151         this._formattedContentLength += text.length;
152     },
153
154     _addMappingIfNeeded: function(originalPosition)
155     {
156         if (originalPosition - this._lastOriginalPosition === this._formattedContentLength - this._lastFormattedPosition)
157             return;
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;
162     }
163 }
164
165 var tokens = [
166     ["EOS"],
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"]
178 ];
179
180 var Tokens = {};
181 for (var i = 0; i < tokens.length; ++i)
182     Tokens[tokens[i][0]] = i;
183
184 var TokensByValue = {};
185 for (var i = 0; i < tokens.length; ++i) {
186     if (tokens[i][1])
187         TokensByValue[tokens[i][1]] = i;
188 }
189
190 var TokensByType = {
191     "eof": Tokens.EOS,
192     "name": Tokens.IDENTIFIER,
193     "num": Tokens.NUMBER,
194     "regexp": Tokens.DIV,
195     "string": Tokens.STRING
196 };
197
198 function Tokenizer(content)
199 {
200     this._readNextToken = parse.tokenizer(content);
201     this._state = this._readNextToken.context();
202 }
203
204 Tokenizer.prototype = {
205     content: function()
206     {
207         return this._state.text;
208     },
209
210     next: function(forceRegexp)
211     {
212         var uglifyToken = this._readNextToken(forceRegexp);
213         uglifyToken.endPos = this._state.pos;
214         uglifyToken.endLine = this._state.line;
215         uglifyToken.token = this._convertUglifyToken(uglifyToken);
216         return uglifyToken;
217     },
218
219     _convertUglifyToken: function(uglifyToken)
220     {
221         var token = TokensByType[uglifyToken.type];
222         if (typeof token === "number")
223             return token;
224         token = TokensByValue[uglifyToken.value];
225         if (typeof token === "number")
226             return token;
227         throw "Unknown token type " + uglifyToken.type;
228     }
229 }
230
231 function JavaScriptFormatter(tokenizer, builder)
232 {
233     this._tokenizer = tokenizer;
234     this._builder = builder;
235     this._token = null;
236     this._nextToken = this._tokenizer.next();
237 }
238
239 JavaScriptFormatter.prototype = {
240     format: function()
241     {
242         this._parseSourceElements(Tokens.EOS);
243         this._consume(Tokens.EOS);
244     },
245
246     _peek: function()
247     {
248         return this._nextToken.token;
249     },
250
251     _next: function()
252     {
253         if (this._token && this._token.token === Tokens.EOS)
254             throw "Unexpected EOS token";
255
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;
261     },
262
263     _consume: function(token)
264     {
265         var next = this._next();
266         if (next !== token)
267             throw "Unexpected token in consume: expected " + token + ", actual " + next;
268     },
269
270     _expect: function(token)
271     {
272         var next = this._next();
273         if (next !== token)
274             throw "Unexpected token: expected " + token + ", actual " + next;
275     },
276
277     _expectSemicolon: function()
278     {
279         if (this._peek() === Tokens.SEMICOLON)
280             this._consume(Tokens.SEMICOLON);
281     },
282
283     _hasLineTerminatorBeforeNext: function()
284     {
285         return this._nextToken.nlb;
286     },
287
288     _parseSourceElements: function(endToken)
289     {
290         while (this._peek() !== endToken) {
291             this._parseStatement();
292             this._builder.addNewLine();
293         }
294     },
295
296     _parseStatementOrBlock: function()
297     {
298         if (this._peek() === Tokens.LBRACE) {
299             this._builder.addSpace();
300             this._parseBlock();
301             return true;
302         }
303
304         this._builder.addNewLine();
305         this._builder.increaseNestingLevel();
306         this._parseStatement();
307         this._builder.decreaseNestingLevel();
308     },
309
310     _parseStatement: function()
311     {
312         switch (this._peek()) {
313         case Tokens.LBRACE:
314             return this._parseBlock();
315         case Tokens.CONST:
316         case Tokens.VAR:
317             return this._parseVariableStatement();
318         case Tokens.SEMICOLON:
319             return this._next();
320         case Tokens.IF:
321             return this._parseIfStatement();
322         case Tokens.DO:
323             return this._parseDoWhileStatement();
324         case Tokens.WHILE:
325             return this._parseWhileStatement();
326         case Tokens.FOR:
327             return this._parseForStatement();
328         case Tokens.CONTINUE:
329             return this._parseContinueStatement();
330         case Tokens.BREAK:
331             return this._parseBreakStatement();
332         case Tokens.RETURN:
333             return this._parseReturnStatement();
334         case Tokens.WITH:
335             return this._parseWithStatement();
336         case Tokens.SWITCH:
337             return this._parseSwitchStatement();
338         case Tokens.THROW:
339             return this._parseThrowStatement();
340         case Tokens.TRY:
341             return this._parseTryStatement();
342         case Tokens.FUNCTION:
343             return this._parseFunctionDeclaration();
344         case Tokens.DEBUGGER:
345             return this._parseDebuggerStatement();
346         default:
347             return this._parseExpressionOrLabelledStatement();
348         }
349     },
350
351     _parseFunctionDeclaration: function()
352     {
353         this._expect(Tokens.FUNCTION);
354         this._builder.addSpace();
355         this._expect(Tokens.IDENTIFIER);
356         this._parseFunctionLiteral()
357     },
358
359     _parseBlock: function()
360     {
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();
367         }
368         this._builder.decreaseNestingLevel();
369         this._expect(Tokens.RBRACE);
370     },
371
372     _parseVariableStatement: function()
373     {
374         this._parseVariableDeclarations();
375         this._expectSemicolon();
376     },
377
378     _parseVariableDeclarations: function()
379     {
380         if (this._peek() === Tokens.VAR)
381             this._consume(Tokens.VAR);
382         else
383             this._consume(Tokens.CONST)
384         this._builder.addSpace();
385
386         var isFirstVariable = true;
387         do {
388             if (!isFirstVariable) {
389                 this._consume(Tokens.COMMA);
390                 this._builder.addSpace();
391             }
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();
399             }
400         } while (this._peek() === Tokens.COMMA);
401     },
402
403     _parseExpressionOrLabelledStatement: function()
404     {
405         this._parseExpression();
406         if (this._peek() === Tokens.COLON) {
407             this._expect(Tokens.COLON);
408             this._builder.addSpace();
409             this._parseStatement();
410         }
411         this._expectSemicolon();
412     },
413
414     _parseIfStatement: function()
415     {
416         this._expect(Tokens.IF);
417         this._builder.addSpace();
418         this._expect(Tokens.LPAREN);
419         this._parseExpression();
420         this._expect(Tokens.RPAREN);
421
422         var isBlock = this._parseStatementOrBlock();
423         if (this._peek() === Tokens.ELSE) {
424             if (isBlock)
425                 this._builder.addSpace();
426             else
427                 this._builder.addNewLine();
428             this._next();
429
430             if (this._peek() === Tokens.IF) {
431                 this._builder.addSpace();
432                 this._parseStatement();
433             } else
434                 this._parseStatementOrBlock();
435         }
436     },
437
438     _parseContinueStatement: function()
439     {
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);
445         }
446         this._expectSemicolon();
447     },
448
449     _parseBreakStatement: function()
450     {
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);
456         }
457         this._expectSemicolon();
458     },
459
460     _parseReturnStatement: function()
461     {
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();
467         }
468         this._expectSemicolon();
469     },
470
471     _parseWithStatement: function()
472     {
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();
479     },
480
481     _parseCaseClause: function()
482     {
483         if (this._peek() === Tokens.CASE) {
484             this._expect(Tokens.CASE);
485             this._builder.addSpace();
486             this._parseExpression();
487         } else
488             this._expect(Tokens.DEFAULT);
489         this._expect(Tokens.COLON);
490         this._builder.addNewLine();
491
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();
496         }
497         this._builder.decreaseNestingLevel();
498     },
499
500     _parseSwitchStatement: function()
501     {
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();
508
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);
516     },
517
518     _parseThrowStatement: function()
519     {
520         this._expect(Tokens.THROW);
521         this._builder.addSpace();
522         this._parseExpression();
523         this._expectSemicolon();
524     },
525
526     _parseTryStatement: function()
527     {
528         this._expect(Tokens.TRY);
529         this._builder.addSpace();
530         this._parseBlock();
531
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();
541             this._parseBlock();
542             token = this._peek();
543         }
544
545         if (token === Tokens.FINALLY) {
546             this._consume(Tokens.FINALLY);
547             this._builder.addSpace();
548             this._parseBlock();
549         }
550     },
551
552     _parseDoWhileStatement: function()
553     {
554         this._expect(Tokens.DO);
555         var isBlock = this._parseStatementOrBlock();
556         if (isBlock)
557             this._builder.addSpace();
558         else
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();
566     },
567
568     _parseWhileStatement: function()
569     {
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();
576     },
577
578     _parseForStatement: function()
579     {
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();
591                 }
592             } else
593                 this._parseExpression();
594         }
595
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();
605         }
606         this._expect(Tokens.RPAREN);
607
608         this._parseStatementOrBlock();
609     },
610
611     _parseExpression: function()
612     {
613         this._parseAssignmentExpression();
614         while (this._peek() === Tokens.COMMA) {
615             this._expect(Tokens.COMMA);
616             this._builder.addSpace();
617             this._parseAssignmentExpression();
618         }
619     },
620
621     _parseAssignmentExpression: function()
622     {
623         this._parseConditionalExpression();
624         var token = this._peek();
625         if (Tokens.ASSIGN <= token && token <= Tokens.ASSIGN_MOD) {
626             this._builder.addSpace();
627             this._next();
628             this._builder.addSpace();
629             this._parseAssignmentExpression();
630         }
631     },
632
633     _parseConditionalExpression: function()
634     {
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();
645         }
646     },
647
648     _parseBinaryExpression: function()
649     {
650         this._parseUnaryExpression();
651         var token = this._peek();
652         while (Tokens.OR <= token && token <= Tokens.IN) {
653             this._builder.addSpace();
654             this._next();
655             this._builder.addSpace();
656             this._parseBinaryExpression();
657             token = this._peek();
658         }
659     },
660
661     _parseUnaryExpression: function()
662     {
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) {
665             this._next();
666             if (token === Tokens.DELETE || token === Tokens.TYPEOF || token === Tokens.VOID)
667                 this._builder.addSpace();
668             this._parseUnaryExpression();
669         } else
670             return this._parsePostfixExpression();
671     },
672
673     _parsePostfixExpression: function()
674     {
675         this._parseLeftHandSideExpression();
676         var token = this._peek();
677         if (!this._hasLineTerminatorBeforeNext() && (token === Tokens.INC || token === Tokens.DEC))
678             this._next();
679     },
680
681     _parseLeftHandSideExpression: function()
682     {
683         if (this._peek() === Tokens.NEW)
684             this._parseNewExpression();
685         else
686             this._parseMemberExpression();
687
688         while (true) {
689             switch (this._peek()) {
690             case Tokens.LBRACK:
691                 this._consume(Tokens.LBRACK);
692                 this._parseExpression();
693                 this._expect(Tokens.RBRACK);
694                 break;
695
696             case Tokens.LPAREN:
697                 this._parseArguments();
698                 break;
699
700             case Tokens.PERIOD:
701                 this._consume(Tokens.PERIOD);
702                 this._expect(Tokens.IDENTIFIER);
703                 break;
704
705             default:
706                 return;
707             }
708         }
709     },
710
711     _parseNewExpression: function()
712     {
713         this._expect(Tokens.NEW);
714         this._builder.addSpace();
715         if (this._peek() === Tokens.NEW)
716             this._parseNewExpression();
717         else
718             this._parseMemberExpression();
719     },
720
721     _parseMemberExpression: function()
722     {
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);
728             }
729             this._parseFunctionLiteral();
730         } else
731             this._parsePrimaryExpression();
732
733         while (true) {
734             switch (this._peek()) {
735             case Tokens.LBRACK:
736                 this._consume(Tokens.LBRACK);
737                 this._parseExpression();
738                 this._expect(Tokens.RBRACK);
739                 break;
740
741             case Tokens.PERIOD:
742                 this._consume(Tokens.PERIOD);
743                 this._expect(Tokens.IDENTIFIER);
744                 break;
745
746             case Tokens.LPAREN:
747                 this._parseArguments();
748                 break;
749
750             default:
751                 return;
752             }
753         }
754     },
755
756     _parseDebuggerStatement: function()
757     {
758         this._expect(Tokens.DEBUGGER);
759         this._expectSemicolon();
760     },
761
762     _parsePrimaryExpression: function()
763     {
764         switch (this._peek()) {
765         case Tokens.THIS:
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);
775         case Tokens.NUMBER:
776             return this._consume(Tokens.NUMBER);
777         case Tokens.STRING:
778             return this._consume(Tokens.STRING);
779         case Tokens.ASSIGN_DIV:
780             return this._parseRegExpLiteral();
781         case Tokens.DIV:
782             return this._parseRegExpLiteral();
783         case Tokens.LBRACK:
784             return this._parseArrayLiteral();
785         case Tokens.LBRACE:
786             return this._parseObjectLiteral();
787         case Tokens.LPAREN:
788             this._consume(Tokens.LPAREN);
789             this._parseExpression();
790             this._expect(Tokens.RPAREN);
791             return;
792         default:
793             return this._next();
794         }
795     },
796
797     _parseArrayLiteral: function()
798     {
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();
807             }
808         }
809         this._builder.decreaseNestingLevel();
810         this._expect(Tokens.RBRACK);
811     },
812
813     _parseObjectLiteralGetSet: function()
814     {
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) {
819             this._next();
820             this._parseFunctionLiteral();
821         }
822     },
823
824     _parseObjectLiteral: function()
825     {
826         this._expect(Tokens.LBRACE);
827         this._builder.increaseNestingLevel();
828         while (this._peek() !== Tokens.RBRACE) {
829             var token = this._peek();
830             switch (token) {
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);
839                     }
840                     continue;
841                 }
842                 break;
843
844             case Tokens.STRING:
845                 this._consume(Tokens.STRING);
846                 break;
847
848             case Tokens.NUMBER:
849                 this._consume(Tokens.NUMBER);
850                 break;
851
852             default:
853                 this._next();
854             }
855
856             this._expect(Tokens.COLON);
857             this._builder.addSpace();
858             this._parseAssignmentExpression();
859             if (this._peek() !== Tokens.RBRACE) {
860                 this._expect(Tokens.COMMA);
861             }
862         }
863         this._builder.decreaseNestingLevel();
864
865         this._expect(Tokens.RBRACE);
866     },
867
868     _parseRegExpLiteral: function()
869     {
870         if (this._nextToken.type === "regexp")
871             this._next();
872         else {
873             this._forceRegexp = true;
874             this._next();
875         }
876     },
877
878     _parseArguments: function()
879     {
880         this._expect(Tokens.LPAREN);
881         var done = (this._peek() === Tokens.RPAREN);
882         while (!done) {
883             this._parseAssignmentExpression();
884             done = (this._peek() === Tokens.RPAREN);
885             if (!done) {
886                 this._expect(Tokens.COMMA);
887                 this._builder.addSpace();
888             }
889         }
890         this._expect(Tokens.RPAREN);
891     },
892
893     _parseFunctionLiteral: function()
894     {
895         this._expect(Tokens.LPAREN);
896         var done = (this._peek() === Tokens.RPAREN);
897         while (!done) {
898             this._expect(Tokens.IDENTIFIER);
899             done = (this._peek() === Tokens.RPAREN);
900             if (!done) {
901                 this._expect(Tokens.COMMA);
902                 this._builder.addSpace();
903             }
904         }
905         this._expect(Tokens.RPAREN);
906         this._builder.addSpace();
907
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);
914     }
915 }