toolkit/devtools/acorn/acorn_loose.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 // Acorn: Loose parser
     2 //
     3 // This module provides an alternative parser (`parse_dammit`) that
     4 // exposes that same interface as `parse`, but will try to parse
     5 // anything as JavaScript, repairing syntax error the best it can.
     6 // There are circumstances in which it will raise an error and give
     7 // up, but they are very rare. The resulting AST will be a mostly
     8 // valid JavaScript AST (as per the [Mozilla parser API][api], except
     9 // that:
    10 //
    11 // - Return outside functions is allowed
    12 //
    13 // - Label consistency (no conflicts, break only to existing labels)
    14 //   is not enforced.
    15 //
    16 // - Bogus Identifier nodes with a name of `"✖"` are inserted whenever
    17 //   the parser got too confused to return anything meaningful.
    18 //
    19 // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
    20 //
    21 // The expected use for this is to *first* try `acorn.parse`, and only
    22 // if that fails switch to `parse_dammit`. The loose parser might
    23 // parse badly indented code incorrectly, so **don't** use it as
    24 // your default parser.
    25 //
    26 // Quite a lot of acorn.js is duplicated here. The alternative was to
    27 // add a *lot* of extra cruft to that file, making it less readable
    28 // and slower. Copying and editing the code allowed me to make
    29 // invasive changes and simplifications without creating a complicated
    30 // tangle.
    32 (function(root, mod) {
    33   if (typeof exports == "object" && typeof module == "object") return mod(exports, require("./acorn")); // CommonJS
    34   if (typeof define == "function" && define.amd) return define(["exports", "./acorn"], mod); // AMD
    35   mod(root.acorn || (root.acorn = {}), root.acorn); // Plain browser env
    36 })(this, function(exports, acorn) {
    37   "use strict";
    39   var tt = acorn.tokTypes;
    41   var options, input, fetchToken, context;
    43   exports.parse_dammit = function(inpt, opts) {
    44     if (!opts) opts = {};
    45     input = String(inpt);
    46     options = opts;
    47     if (!opts.tabSize) opts.tabSize = 4;
    48     fetchToken = acorn.tokenize(inpt, opts);
    49     sourceFile = options.sourceFile || null;
    50     context = [];
    51     nextLineStart = 0;
    52     ahead.length = 0;
    53     next();
    54     return parseTopLevel();
    55   };
    57   var lastEnd, token = {start: 0, end: 0}, ahead = [];
    58   var curLineStart, nextLineStart, curIndent, lastEndLoc, sourceFile;
    60   function next() {
    61     lastEnd = token.end;
    62     if (options.locations)
    63       lastEndLoc = token.endLoc;
    65     if (ahead.length)
    66       token = ahead.shift();
    67     else
    68       token = readToken();
    70     if (token.start >= nextLineStart) {
    71       while (token.start >= nextLineStart) {
    72         curLineStart = nextLineStart;
    73         nextLineStart = lineEnd(curLineStart) + 1;
    74       }
    75       curIndent = indentationAfter(curLineStart);
    76     }
    77   }
    79   function readToken() {
    80     for (;;) {
    81       try {
    82         return fetchToken();
    83       } catch(e) {
    84         if (!(e instanceof SyntaxError)) throw e;
    86         // Try to skip some text, based on the error message, and then continue
    87         var msg = e.message, pos = e.raisedAt, replace = true;
    88         if (/unterminated/i.test(msg)) {
    89           pos = lineEnd(e.pos);
    90           if (/string/.test(msg)) {
    91             replace = {start: e.pos, end: pos, type: tt.string, value: input.slice(e.pos + 1, pos)};
    92           } else if (/regular expr/i.test(msg)) {
    93             var re = input.slice(e.pos, pos);
    94             try { re = new RegExp(re); } catch(e) {}
    95             replace = {start: e.pos, end: pos, type: tt.regexp, value: re};
    96           } else {
    97             replace = false;
    98           }
    99         } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number/i.test(msg)) {
   100           while (pos < input.length && !isSpace(input.charCodeAt(pos))) ++pos;
   101         } else if (/character escape|expected hexadecimal/i.test(msg)) {
   102           while (pos < input.length) {
   103             var ch = input.charCodeAt(pos++);
   104             if (ch === 34 || ch === 39 || isNewline(ch)) break;
   105           }
   106         } else if (/unexpected character/i.test(msg)) {
   107           pos++;
   108           replace = false;
   109         } else {
   110           throw e;
   111         }
   112         resetTo(pos);
   113         if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: "✖"};
   114         if (replace) {
   115           if (options.locations) {
   116             replace.startLoc = acorn.getLineInfo(input, replace.start);
   117             replace.endLoc = acorn.getLineInfo(input, replace.end);
   118           }
   119           return replace;
   120         }
   121       }
   122     }
   123   }
   125   function resetTo(pos) {
   126     var ch = input.charAt(pos - 1);
   127     var reAllowed = !ch || /[\[\{\(,;:?\/*=+\-~!|&%^<>]/.test(ch) ||
   128       /[enwfd]/.test(ch) && /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(input.slice(pos - 10, pos));
   129     fetchToken.jumpTo(pos, reAllowed);
   130   }
   132   function copyToken(token) {
   133     var copy = {start: token.start, end: token.end, type: token.type, value: token.value};
   134     if (options.locations) {
   135       copy.startLoc = token.startLoc;
   136       copy.endLoc = token.endLoc;
   137     }
   138     return copy;
   139   }
   141   function lookAhead(n) {
   142     // Copy token objects, because fetchToken will overwrite the one
   143     // it returns, and in this case we still need it
   144     if (!ahead.length)
   145       token = copyToken(token);
   146     while (n > ahead.length)
   147       ahead.push(copyToken(readToken()));
   148     return ahead[n-1];
   149   }
   151   var newline = /[\n\r\u2028\u2029]/;
   153   function isNewline(ch) {
   154     return ch === 10 || ch === 13 || ch === 8232 || ch === 8329;
   155   }
   156   function isSpace(ch) {
   157     return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || isNewline(ch);
   158   }
   160   function pushCx() {
   161     context.push(curIndent);
   162   }
   163   function popCx() {
   164     curIndent = context.pop();
   165   }
   167   function lineEnd(pos) {
   168     while (pos < input.length && !isNewline(input.charCodeAt(pos))) ++pos;
   169     return pos;
   170   }
   171   function indentationAfter(pos) {
   172     for (var count = 0;; ++pos) {
   173       var ch = input.charCodeAt(pos);
   174       if (ch === 32) ++count;
   175       else if (ch === 9) count += options.tabSize;
   176       else return count;
   177     }
   178   }
   180   function closes(closeTok, indent, line, blockHeuristic) {
   181     if (token.type === closeTok || token.type === tt.eof) return true;
   182     if (line != curLineStart && curIndent < indent && tokenStartsLine() &&
   183         (!blockHeuristic || nextLineStart >= input.length ||
   184          indentationAfter(nextLineStart) < indent)) return true;
   185     return false;
   186   }
   188   function tokenStartsLine() {
   189     for (var p = token.start - 1; p >= curLineStart; --p) {
   190       var ch = input.charCodeAt(p);
   191       if (ch !== 9 && ch !== 32) return false;
   192     }
   193     return true;
   194   }
   196   function node_t(start) {
   197     this.type = null;
   198     this.start = start;
   199     this.end = null;
   200   }
   202   function node_loc_t(start) {
   203     this.start = start || token.startLoc || {line: 1, column: 0};
   204     this.end = null;
   205     if (sourceFile !== null) this.source = sourceFile;
   206   }
   208   function startNode() {
   209     var node = new node_t(token.start);
   210     if (options.locations)
   211       node.loc = new node_loc_t();
   212     if (options.directSourceFile)
   213       node.sourceFile = options.directSourceFile;
   214     return node;
   215   }
   217   function startNodeFrom(other) {
   218     var node = new node_t(other.start);
   219     if (options.locations)
   220       node.loc = new node_loc_t(other.loc.start);
   221     return node;
   222   }
   224   function finishNode(node, type) {
   225     node.type = type;
   226     node.end = lastEnd;
   227     if (options.locations)
   228       node.loc.end = lastEndLoc;
   229     return node;
   230   }
   232   function getDummyLoc() {
   233     if (options.locations) {
   234       var loc = new node_loc_t();
   235       loc.end = loc.start;
   236       return loc;
   237     }
   238   };
   240   function dummyIdent() {
   241     var dummy = new node_t(token.start);
   242     dummy.type = "Identifier";
   243     dummy.end = token.start;
   244     dummy.name = "✖";
   245     dummy.loc = getDummyLoc();
   246     return dummy;
   247   }
   248   function isDummy(node) { return node.name == "✖"; }
   250   function eat(type) {
   251     if (token.type === type) {
   252       next();
   253       return true;
   254     }
   255   }
   257   function canInsertSemicolon() {
   258     return (token.type === tt.eof || token.type === tt.braceR || newline.test(input.slice(lastEnd, token.start)));
   259   }
   260   function semicolon() {
   261     eat(tt.semi);
   262   }
   264   function expect(type) {
   265     if (eat(type)) return true;
   266     if (lookAhead(1).type == type) {
   267       next(); next();
   268       return true;
   269     }
   270     if (lookAhead(2).type == type) {
   271       next(); next(); next();
   272       return true;
   273     }
   274   }
   276   function checkLVal(expr) {
   277     if (expr.type === "Identifier" || expr.type === "MemberExpression") return expr;
   278     return dummyIdent();
   279   }
   281   function parseTopLevel() {
   282     var node = startNode();
   283     node.body = [];
   284     while (token.type !== tt.eof) node.body.push(parseStatement());
   285     return finishNode(node, "Program");
   286   }
   288   function parseStatement() {
   289     var starttype = token.type, node = startNode();
   291     switch (starttype) {
   292     case tt._break: case tt._continue:
   293       next();
   294       var isBreak = starttype === tt._break;
   295       node.label = token.type === tt.name ? parseIdent() : null;
   296       semicolon();
   297       return finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
   299     case tt._debugger:
   300       next();
   301       semicolon();
   302       return finishNode(node, "DebuggerStatement");
   304     case tt._do:
   305       next();
   306       node.body = parseStatement();
   307       node.test = eat(tt._while) ? parseParenExpression() : dummyIdent();
   308       semicolon();
   309       return finishNode(node, "DoWhileStatement");
   311     case tt._for:
   312       next();
   313       pushCx();
   314       expect(tt.parenL);
   315       if (token.type === tt.semi) return parseFor(node, null);
   316       if (token.type === tt._var) {
   317         var init = startNode();
   318         next();
   319         parseVar(init, true);
   320         if (init.declarations.length === 1 && eat(tt._in))
   321           return parseForIn(node, init);
   322         return parseFor(node, init);
   323       }
   324       var init = parseExpression(false, true);
   325       if (eat(tt._in)) {return parseForIn(node, checkLVal(init));}
   326       return parseFor(node, init);
   328     case tt._function:
   329       next();
   330       return parseFunction(node, true);
   332     case tt._if:
   333       next();
   334       node.test = parseParenExpression();
   335       node.consequent = parseStatement();
   336       node.alternate = eat(tt._else) ? parseStatement() : null;
   337       return finishNode(node, "IfStatement");
   339     case tt._return:
   340       next();
   341       if (eat(tt.semi) || canInsertSemicolon()) node.argument = null;
   342       else { node.argument = parseExpression(); semicolon(); }
   343       return finishNode(node, "ReturnStatement");
   345     case tt._switch:
   346       var blockIndent = curIndent, line = curLineStart;
   347       next();
   348       node.discriminant = parseParenExpression();
   349       node.cases = [];
   350       pushCx();
   351       expect(tt.braceL);
   353       for (var cur; !closes(tt.braceR, blockIndent, line, true);) {
   354         if (token.type === tt._case || token.type === tt._default) {
   355           var isCase = token.type === tt._case;
   356           if (cur) finishNode(cur, "SwitchCase");
   357           node.cases.push(cur = startNode());
   358           cur.consequent = [];
   359           next();
   360           if (isCase) cur.test = parseExpression();
   361           else cur.test = null;
   362           expect(tt.colon);
   363         } else {
   364           if (!cur) {
   365             node.cases.push(cur = startNode());
   366             cur.consequent = [];
   367             cur.test = null;
   368           }
   369           cur.consequent.push(parseStatement());
   370         }
   371       }
   372       if (cur) finishNode(cur, "SwitchCase");
   373       popCx();
   374       eat(tt.braceR);
   375       return finishNode(node, "SwitchStatement");
   377     case tt._throw:
   378       next();
   379       node.argument = parseExpression();
   380       semicolon();
   381       return finishNode(node, "ThrowStatement");
   383     case tt._try:
   384       next();
   385       node.block = parseBlock();
   386       node.handler = null;
   387       if (token.type === tt._catch) {
   388         var clause = startNode();
   389         next();
   390         expect(tt.parenL);
   391         clause.param = parseIdent();
   392         expect(tt.parenR);
   393         clause.guard = null;
   394         clause.body = parseBlock();
   395         node.handler = finishNode(clause, "CatchClause");
   396       }
   397       node.finalizer = eat(tt._finally) ? parseBlock() : null;
   398       if (!node.handler && !node.finalizer) return node.block;
   399       return finishNode(node, "TryStatement");
   401     case tt._var:
   402       next();
   403       node = parseVar(node);
   404       semicolon();
   405       return node;
   407     case tt._while:
   408       next();
   409       node.test = parseParenExpression();
   410       node.body = parseStatement();
   411       return finishNode(node, "WhileStatement");
   413     case tt._with:
   414       next();
   415       node.object = parseParenExpression();
   416       node.body = parseStatement();
   417       return finishNode(node, "WithStatement");
   419     case tt.braceL:
   420       return parseBlock();
   422     case tt.semi:
   423       next();
   424       return finishNode(node, "EmptyStatement");
   426     default:
   427       var expr = parseExpression();
   428       if (isDummy(expr)) {
   429         next();
   430         if (token.type === tt.eof) return finishNode(node, "EmptyStatement");
   431         return parseStatement();
   432       } else if (starttype === tt.name && expr.type === "Identifier" && eat(tt.colon)) {
   433         node.body = parseStatement();
   434         node.label = expr;
   435         return finishNode(node, "LabeledStatement");
   436       } else {
   437         node.expression = expr;
   438         semicolon();
   439         return finishNode(node, "ExpressionStatement");
   440       }
   441     }
   442   }
   444   function parseBlock() {
   445     var node = startNode();
   446     pushCx();
   447     expect(tt.braceL);
   448     var blockIndent = curIndent, line = curLineStart;
   449     node.body = [];
   450     while (!closes(tt.braceR, blockIndent, line, true))
   451       node.body.push(parseStatement());
   452     popCx();
   453     eat(tt.braceR);
   454     return finishNode(node, "BlockStatement");
   455   }
   457   function parseFor(node, init) {
   458     node.init = init;
   459     node.test = node.update = null;
   460     if (eat(tt.semi) && token.type !== tt.semi) node.test = parseExpression();
   461     if (eat(tt.semi) && token.type !== tt.parenR) node.update = parseExpression();
   462     popCx();
   463     expect(tt.parenR);
   464     node.body = parseStatement();
   465     return finishNode(node, "ForStatement");
   466   }
   468   function parseForIn(node, init) {
   469     node.left = init;
   470     node.right = parseExpression();
   471     popCx();
   472     expect(tt.parenR);
   473     node.body = parseStatement();
   474     return finishNode(node, "ForInStatement");
   475   }
   477   function parseVar(node, noIn) {
   478     node.declarations = [];
   479     node.kind = "var";
   480     while (token.type === tt.name) {
   481       var decl = startNode();
   482       decl.id = parseIdent();
   483       decl.init = eat(tt.eq) ? parseExpression(true, noIn) : null;
   484       node.declarations.push(finishNode(decl, "VariableDeclarator"));
   485       if (!eat(tt.comma)) break;
   486     }
   487     if (!node.declarations.length) {
   488       var decl = startNode();
   489       decl.id = dummyIdent();
   490       node.declarations.push(finishNode(decl, "VariableDeclarator"));
   491     }
   492     return finishNode(node, "VariableDeclaration");
   493   }
   495   function parseExpression(noComma, noIn) {
   496     var expr = parseMaybeAssign(noIn);
   497     if (!noComma && token.type === tt.comma) {
   498       var node = startNodeFrom(expr);
   499       node.expressions = [expr];
   500       while (eat(tt.comma)) node.expressions.push(parseMaybeAssign(noIn));
   501       return finishNode(node, "SequenceExpression");
   502     }
   503     return expr;
   504   }
   506   function parseParenExpression() {
   507     pushCx();
   508     expect(tt.parenL);
   509     var val = parseExpression();
   510     popCx();
   511     expect(tt.parenR);
   512     return val;
   513   }
   515   function parseMaybeAssign(noIn) {
   516     var left = parseMaybeConditional(noIn);
   517     if (token.type.isAssign) {
   518       var node = startNodeFrom(left);
   519       node.operator = token.value;
   520       node.left = checkLVal(left);
   521       next();
   522       node.right = parseMaybeAssign(noIn);
   523       return finishNode(node, "AssignmentExpression");
   524     }
   525     return left;
   526   }
   528   function parseMaybeConditional(noIn) {
   529     var expr = parseExprOps(noIn);
   530     if (eat(tt.question)) {
   531       var node = startNodeFrom(expr);
   532       node.test = expr;
   533       node.consequent = parseExpression(true);
   534       node.alternate = expect(tt.colon) ? parseExpression(true, noIn) : dummyIdent();
   535       return finishNode(node, "ConditionalExpression");
   536     }
   537     return expr;
   538   }
   540   function parseExprOps(noIn) {
   541     var indent = curIndent, line = curLineStart;
   542     return parseExprOp(parseMaybeUnary(noIn), -1, noIn, indent, line);
   543   }
   545   function parseExprOp(left, minPrec, noIn, indent, line) {
   546     if (curLineStart != line && curIndent < indent && tokenStartsLine()) return left;
   547     var prec = token.type.binop;
   548     if (prec != null && (!noIn || token.type !== tt._in)) {
   549       if (prec > minPrec) {
   550         var node = startNodeFrom(left);
   551         node.left = left;
   552         node.operator = token.value;
   553         next();
   554         if (curLineStart != line && curIndent < indent && tokenStartsLine())
   555           node.right = dummyIdent();
   556         else
   557           node.right = parseExprOp(parseMaybeUnary(noIn), prec, noIn, indent, line);
   558         var node = finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression");
   559         return parseExprOp(node, minPrec, noIn, indent, line);
   560       }
   561     }
   562     return left;
   563   }
   565   function parseMaybeUnary(noIn) {
   566     if (token.type.prefix) {
   567       var node = startNode(), update = token.type.isUpdate;
   568       node.operator = token.value;
   569       node.prefix = true;
   570       next();
   571       node.argument = parseMaybeUnary(noIn);
   572       if (update) node.argument = checkLVal(node.argument);
   573       return finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
   574     }
   575     var expr = parseExprSubscripts();
   576     while (token.type.postfix && !canInsertSemicolon()) {
   577       var node = startNodeFrom(expr);
   578       node.operator = token.value;
   579       node.prefix = false;
   580       node.argument = checkLVal(expr);
   581       next();
   582       expr = finishNode(node, "UpdateExpression");
   583     }
   584     return expr;
   585   }
   587   function parseExprSubscripts() {
   588     return parseSubscripts(parseExprAtom(), false, curIndent, curLineStart);
   589   }
   591   function parseSubscripts(base, noCalls, startIndent, line) {
   592     for (;;) {
   593       if (curLineStart != line && curIndent <= startIndent && tokenStartsLine()) {
   594         if (token.type == tt.dot && curIndent == startIndent)
   595           --startIndent;
   596         else
   597           return base;
   598       }
   600       if (eat(tt.dot)) {
   601         var node = startNodeFrom(base);
   602         node.object = base;
   603         if (curLineStart != line && curIndent <= startIndent && tokenStartsLine())
   604           node.property = dummyIdent();
   605         else
   606           node.property = parsePropertyName() || dummyIdent();
   607         node.computed = false;
   608         base = finishNode(node, "MemberExpression");
   609       } else if (token.type == tt.bracketL) {
   610         pushCx();
   611         next();
   612         var node = startNodeFrom(base);
   613         node.object = base;
   614         node.property = parseExpression();
   615         node.computed = true;
   616         popCx();
   617         expect(tt.bracketR);
   618         base = finishNode(node, "MemberExpression");
   619       } else if (!noCalls && token.type == tt.parenL) {
   620         pushCx();
   621         var node = startNodeFrom(base);
   622         node.callee = base;
   623         node.arguments = parseExprList(tt.parenR);
   624         base = finishNode(node, "CallExpression");
   625       } else {
   626         return base;
   627       }
   628     }
   629   }
   631   function parseExprAtom() {
   632     switch (token.type) {
   633     case tt._this:
   634       var node = startNode();
   635       next();
   636       return finishNode(node, "ThisExpression");
   637     case tt.name:
   638       return parseIdent();
   639     case tt.num: case tt.string: case tt.regexp:
   640       var node = startNode();
   641       node.value = token.value;
   642       node.raw = input.slice(token.start, token.end);
   643       next();
   644       return finishNode(node, "Literal");
   646     case tt._null: case tt._true: case tt._false:
   647       var node = startNode();
   648       node.value = token.type.atomValue;
   649       node.raw = token.type.keyword;
   650       next();
   651       return finishNode(node, "Literal");
   653     case tt.parenL:
   654       var tokStart1 = token.start;
   655       next();
   656       var val = parseExpression();
   657       val.start = tokStart1;
   658       val.end = token.end;
   659       expect(tt.parenR);
   660       return val;
   662     case tt.bracketL:
   663       var node = startNode();
   664       pushCx();
   665       node.elements = parseExprList(tt.bracketR);
   666       return finishNode(node, "ArrayExpression");
   668     case tt.braceL:
   669       return parseObj();
   671     case tt._function:
   672       var node = startNode();
   673       next();
   674       return parseFunction(node, false);
   676     case tt._new:
   677       return parseNew();
   679     default:
   680       return dummyIdent();
   681     }
   682   }
   684   function parseNew() {
   685     var node = startNode(), startIndent = curIndent, line = curLineStart;
   686     next();
   687     node.callee = parseSubscripts(parseExprAtom(), true, startIndent, line);
   688     if (token.type == tt.parenL) {
   689       pushCx();
   690       node.arguments = parseExprList(tt.parenR);
   691     } else {
   692       node.arguments = [];
   693     }
   694     return finishNode(node, "NewExpression");
   695   }
   697   function parseObj() {
   698     var node = startNode();
   699     node.properties = [];
   700     pushCx();
   701     next();
   702     var propIndent = curIndent, line = curLineStart;
   703     while (!closes(tt.braceR, propIndent, line)) {
   704       var name = parsePropertyName();
   705       if (!name) { if (isDummy(parseExpression(true))) next(); eat(tt.comma); continue; }
   706       var prop = {key: name}, isGetSet = false, kind;
   707       if (eat(tt.colon)) {
   708         prop.value = parseExpression(true);
   709         kind = prop.kind = "init";
   710       } else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" &&
   711                  (prop.key.name === "get" || prop.key.name === "set")) {
   712         isGetSet = true;
   713         kind = prop.kind = prop.key.name;
   714         prop.key = parsePropertyName() || dummyIdent();
   715         prop.value = parseFunction(startNode(), false);
   716       } else {
   717         next();
   718         eat(tt.comma);
   719         continue;
   720       }
   722       node.properties.push(prop);
   723       eat(tt.comma);
   724     }
   725     popCx();
   726     eat(tt.braceR);
   727     return finishNode(node, "ObjectExpression");
   728   }
   730   function parsePropertyName() {
   731     if (token.type === tt.num || token.type === tt.string) return parseExprAtom();
   732     if (token.type === tt.name || token.type.keyword) return parseIdent();
   733   }
   735   function parseIdent() {
   736     var node = startNode();
   737     node.name = token.type === tt.name ? token.value : token.type.keyword;
   738     next();
   739     return finishNode(node, "Identifier");
   740   }
   742   function parseFunction(node, isStatement) {
   743     if (token.type === tt.name) node.id = parseIdent();
   744     else if (isStatement) node.id = dummyIdent();
   745     else node.id = null;
   746     node.params = [];
   747     pushCx();
   748     expect(tt.parenL);
   749     while (token.type == tt.name) {
   750       node.params.push(parseIdent());
   751       eat(tt.comma);
   752     }
   753     popCx();
   754     eat(tt.parenR);
   755     node.body = parseBlock();
   756     return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
   757   }
   759   function parseExprList(close) {
   760     var indent = curIndent, line = curLineStart, elts = [], continuedLine = nextLineStart;
   761     next(); // Opening bracket
   762     if (curLineStart > continuedLine) continuedLine = curLineStart;
   763     while (!closes(close, indent + (curLineStart <= continuedLine ? 1 : 0), line)) {
   764       var elt = parseExpression(true);
   765       if (isDummy(elt)) {
   766         if (closes(close, indent, line)) break;
   767         next();
   768       } else {
   769         elts.push(elt);
   770       }
   771       while (eat(tt.comma)) {}
   772     }
   773     popCx();
   774     eat(close);
   775     return elts;
   776   }
   777 });

mercurial