1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/devtools/acorn/acorn_loose.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,777 @@ 1.4 +// Acorn: Loose parser 1.5 +// 1.6 +// This module provides an alternative parser (`parse_dammit`) that 1.7 +// exposes that same interface as `parse`, but will try to parse 1.8 +// anything as JavaScript, repairing syntax error the best it can. 1.9 +// There are circumstances in which it will raise an error and give 1.10 +// up, but they are very rare. The resulting AST will be a mostly 1.11 +// valid JavaScript AST (as per the [Mozilla parser API][api], except 1.12 +// that: 1.13 +// 1.14 +// - Return outside functions is allowed 1.15 +// 1.16 +// - Label consistency (no conflicts, break only to existing labels) 1.17 +// is not enforced. 1.18 +// 1.19 +// - Bogus Identifier nodes with a name of `"✖"` are inserted whenever 1.20 +// the parser got too confused to return anything meaningful. 1.21 +// 1.22 +// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API 1.23 +// 1.24 +// The expected use for this is to *first* try `acorn.parse`, and only 1.25 +// if that fails switch to `parse_dammit`. The loose parser might 1.26 +// parse badly indented code incorrectly, so **don't** use it as 1.27 +// your default parser. 1.28 +// 1.29 +// Quite a lot of acorn.js is duplicated here. The alternative was to 1.30 +// add a *lot* of extra cruft to that file, making it less readable 1.31 +// and slower. Copying and editing the code allowed me to make 1.32 +// invasive changes and simplifications without creating a complicated 1.33 +// tangle. 1.34 + 1.35 +(function(root, mod) { 1.36 + if (typeof exports == "object" && typeof module == "object") return mod(exports, require("./acorn")); // CommonJS 1.37 + if (typeof define == "function" && define.amd) return define(["exports", "./acorn"], mod); // AMD 1.38 + mod(root.acorn || (root.acorn = {}), root.acorn); // Plain browser env 1.39 +})(this, function(exports, acorn) { 1.40 + "use strict"; 1.41 + 1.42 + var tt = acorn.tokTypes; 1.43 + 1.44 + var options, input, fetchToken, context; 1.45 + 1.46 + exports.parse_dammit = function(inpt, opts) { 1.47 + if (!opts) opts = {}; 1.48 + input = String(inpt); 1.49 + options = opts; 1.50 + if (!opts.tabSize) opts.tabSize = 4; 1.51 + fetchToken = acorn.tokenize(inpt, opts); 1.52 + sourceFile = options.sourceFile || null; 1.53 + context = []; 1.54 + nextLineStart = 0; 1.55 + ahead.length = 0; 1.56 + next(); 1.57 + return parseTopLevel(); 1.58 + }; 1.59 + 1.60 + var lastEnd, token = {start: 0, end: 0}, ahead = []; 1.61 + var curLineStart, nextLineStart, curIndent, lastEndLoc, sourceFile; 1.62 + 1.63 + function next() { 1.64 + lastEnd = token.end; 1.65 + if (options.locations) 1.66 + lastEndLoc = token.endLoc; 1.67 + 1.68 + if (ahead.length) 1.69 + token = ahead.shift(); 1.70 + else 1.71 + token = readToken(); 1.72 + 1.73 + if (token.start >= nextLineStart) { 1.74 + while (token.start >= nextLineStart) { 1.75 + curLineStart = nextLineStart; 1.76 + nextLineStart = lineEnd(curLineStart) + 1; 1.77 + } 1.78 + curIndent = indentationAfter(curLineStart); 1.79 + } 1.80 + } 1.81 + 1.82 + function readToken() { 1.83 + for (;;) { 1.84 + try { 1.85 + return fetchToken(); 1.86 + } catch(e) { 1.87 + if (!(e instanceof SyntaxError)) throw e; 1.88 + 1.89 + // Try to skip some text, based on the error message, and then continue 1.90 + var msg = e.message, pos = e.raisedAt, replace = true; 1.91 + if (/unterminated/i.test(msg)) { 1.92 + pos = lineEnd(e.pos); 1.93 + if (/string/.test(msg)) { 1.94 + replace = {start: e.pos, end: pos, type: tt.string, value: input.slice(e.pos + 1, pos)}; 1.95 + } else if (/regular expr/i.test(msg)) { 1.96 + var re = input.slice(e.pos, pos); 1.97 + try { re = new RegExp(re); } catch(e) {} 1.98 + replace = {start: e.pos, end: pos, type: tt.regexp, value: re}; 1.99 + } else { 1.100 + replace = false; 1.101 + } 1.102 + } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number/i.test(msg)) { 1.103 + while (pos < input.length && !isSpace(input.charCodeAt(pos))) ++pos; 1.104 + } else if (/character escape|expected hexadecimal/i.test(msg)) { 1.105 + while (pos < input.length) { 1.106 + var ch = input.charCodeAt(pos++); 1.107 + if (ch === 34 || ch === 39 || isNewline(ch)) break; 1.108 + } 1.109 + } else if (/unexpected character/i.test(msg)) { 1.110 + pos++; 1.111 + replace = false; 1.112 + } else { 1.113 + throw e; 1.114 + } 1.115 + resetTo(pos); 1.116 + if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: "✖"}; 1.117 + if (replace) { 1.118 + if (options.locations) { 1.119 + replace.startLoc = acorn.getLineInfo(input, replace.start); 1.120 + replace.endLoc = acorn.getLineInfo(input, replace.end); 1.121 + } 1.122 + return replace; 1.123 + } 1.124 + } 1.125 + } 1.126 + } 1.127 + 1.128 + function resetTo(pos) { 1.129 + var ch = input.charAt(pos - 1); 1.130 + var reAllowed = !ch || /[\[\{\(,;:?\/*=+\-~!|&%^<>]/.test(ch) || 1.131 + /[enwfd]/.test(ch) && /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(input.slice(pos - 10, pos)); 1.132 + fetchToken.jumpTo(pos, reAllowed); 1.133 + } 1.134 + 1.135 + function copyToken(token) { 1.136 + var copy = {start: token.start, end: token.end, type: token.type, value: token.value}; 1.137 + if (options.locations) { 1.138 + copy.startLoc = token.startLoc; 1.139 + copy.endLoc = token.endLoc; 1.140 + } 1.141 + return copy; 1.142 + } 1.143 + 1.144 + function lookAhead(n) { 1.145 + // Copy token objects, because fetchToken will overwrite the one 1.146 + // it returns, and in this case we still need it 1.147 + if (!ahead.length) 1.148 + token = copyToken(token); 1.149 + while (n > ahead.length) 1.150 + ahead.push(copyToken(readToken())); 1.151 + return ahead[n-1]; 1.152 + } 1.153 + 1.154 + var newline = /[\n\r\u2028\u2029]/; 1.155 + 1.156 + function isNewline(ch) { 1.157 + return ch === 10 || ch === 13 || ch === 8232 || ch === 8329; 1.158 + } 1.159 + function isSpace(ch) { 1.160 + return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || isNewline(ch); 1.161 + } 1.162 + 1.163 + function pushCx() { 1.164 + context.push(curIndent); 1.165 + } 1.166 + function popCx() { 1.167 + curIndent = context.pop(); 1.168 + } 1.169 + 1.170 + function lineEnd(pos) { 1.171 + while (pos < input.length && !isNewline(input.charCodeAt(pos))) ++pos; 1.172 + return pos; 1.173 + } 1.174 + function indentationAfter(pos) { 1.175 + for (var count = 0;; ++pos) { 1.176 + var ch = input.charCodeAt(pos); 1.177 + if (ch === 32) ++count; 1.178 + else if (ch === 9) count += options.tabSize; 1.179 + else return count; 1.180 + } 1.181 + } 1.182 + 1.183 + function closes(closeTok, indent, line, blockHeuristic) { 1.184 + if (token.type === closeTok || token.type === tt.eof) return true; 1.185 + if (line != curLineStart && curIndent < indent && tokenStartsLine() && 1.186 + (!blockHeuristic || nextLineStart >= input.length || 1.187 + indentationAfter(nextLineStart) < indent)) return true; 1.188 + return false; 1.189 + } 1.190 + 1.191 + function tokenStartsLine() { 1.192 + for (var p = token.start - 1; p >= curLineStart; --p) { 1.193 + var ch = input.charCodeAt(p); 1.194 + if (ch !== 9 && ch !== 32) return false; 1.195 + } 1.196 + return true; 1.197 + } 1.198 + 1.199 + function node_t(start) { 1.200 + this.type = null; 1.201 + this.start = start; 1.202 + this.end = null; 1.203 + } 1.204 + 1.205 + function node_loc_t(start) { 1.206 + this.start = start || token.startLoc || {line: 1, column: 0}; 1.207 + this.end = null; 1.208 + if (sourceFile !== null) this.source = sourceFile; 1.209 + } 1.210 + 1.211 + function startNode() { 1.212 + var node = new node_t(token.start); 1.213 + if (options.locations) 1.214 + node.loc = new node_loc_t(); 1.215 + if (options.directSourceFile) 1.216 + node.sourceFile = options.directSourceFile; 1.217 + return node; 1.218 + } 1.219 + 1.220 + function startNodeFrom(other) { 1.221 + var node = new node_t(other.start); 1.222 + if (options.locations) 1.223 + node.loc = new node_loc_t(other.loc.start); 1.224 + return node; 1.225 + } 1.226 + 1.227 + function finishNode(node, type) { 1.228 + node.type = type; 1.229 + node.end = lastEnd; 1.230 + if (options.locations) 1.231 + node.loc.end = lastEndLoc; 1.232 + return node; 1.233 + } 1.234 + 1.235 + function getDummyLoc() { 1.236 + if (options.locations) { 1.237 + var loc = new node_loc_t(); 1.238 + loc.end = loc.start; 1.239 + return loc; 1.240 + } 1.241 + }; 1.242 + 1.243 + function dummyIdent() { 1.244 + var dummy = new node_t(token.start); 1.245 + dummy.type = "Identifier"; 1.246 + dummy.end = token.start; 1.247 + dummy.name = "✖"; 1.248 + dummy.loc = getDummyLoc(); 1.249 + return dummy; 1.250 + } 1.251 + function isDummy(node) { return node.name == "✖"; } 1.252 + 1.253 + function eat(type) { 1.254 + if (token.type === type) { 1.255 + next(); 1.256 + return true; 1.257 + } 1.258 + } 1.259 + 1.260 + function canInsertSemicolon() { 1.261 + return (token.type === tt.eof || token.type === tt.braceR || newline.test(input.slice(lastEnd, token.start))); 1.262 + } 1.263 + function semicolon() { 1.264 + eat(tt.semi); 1.265 + } 1.266 + 1.267 + function expect(type) { 1.268 + if (eat(type)) return true; 1.269 + if (lookAhead(1).type == type) { 1.270 + next(); next(); 1.271 + return true; 1.272 + } 1.273 + if (lookAhead(2).type == type) { 1.274 + next(); next(); next(); 1.275 + return true; 1.276 + } 1.277 + } 1.278 + 1.279 + function checkLVal(expr) { 1.280 + if (expr.type === "Identifier" || expr.type === "MemberExpression") return expr; 1.281 + return dummyIdent(); 1.282 + } 1.283 + 1.284 + function parseTopLevel() { 1.285 + var node = startNode(); 1.286 + node.body = []; 1.287 + while (token.type !== tt.eof) node.body.push(parseStatement()); 1.288 + return finishNode(node, "Program"); 1.289 + } 1.290 + 1.291 + function parseStatement() { 1.292 + var starttype = token.type, node = startNode(); 1.293 + 1.294 + switch (starttype) { 1.295 + case tt._break: case tt._continue: 1.296 + next(); 1.297 + var isBreak = starttype === tt._break; 1.298 + node.label = token.type === tt.name ? parseIdent() : null; 1.299 + semicolon(); 1.300 + return finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement"); 1.301 + 1.302 + case tt._debugger: 1.303 + next(); 1.304 + semicolon(); 1.305 + return finishNode(node, "DebuggerStatement"); 1.306 + 1.307 + case tt._do: 1.308 + next(); 1.309 + node.body = parseStatement(); 1.310 + node.test = eat(tt._while) ? parseParenExpression() : dummyIdent(); 1.311 + semicolon(); 1.312 + return finishNode(node, "DoWhileStatement"); 1.313 + 1.314 + case tt._for: 1.315 + next(); 1.316 + pushCx(); 1.317 + expect(tt.parenL); 1.318 + if (token.type === tt.semi) return parseFor(node, null); 1.319 + if (token.type === tt._var) { 1.320 + var init = startNode(); 1.321 + next(); 1.322 + parseVar(init, true); 1.323 + if (init.declarations.length === 1 && eat(tt._in)) 1.324 + return parseForIn(node, init); 1.325 + return parseFor(node, init); 1.326 + } 1.327 + var init = parseExpression(false, true); 1.328 + if (eat(tt._in)) {return parseForIn(node, checkLVal(init));} 1.329 + return parseFor(node, init); 1.330 + 1.331 + case tt._function: 1.332 + next(); 1.333 + return parseFunction(node, true); 1.334 + 1.335 + case tt._if: 1.336 + next(); 1.337 + node.test = parseParenExpression(); 1.338 + node.consequent = parseStatement(); 1.339 + node.alternate = eat(tt._else) ? parseStatement() : null; 1.340 + return finishNode(node, "IfStatement"); 1.341 + 1.342 + case tt._return: 1.343 + next(); 1.344 + if (eat(tt.semi) || canInsertSemicolon()) node.argument = null; 1.345 + else { node.argument = parseExpression(); semicolon(); } 1.346 + return finishNode(node, "ReturnStatement"); 1.347 + 1.348 + case tt._switch: 1.349 + var blockIndent = curIndent, line = curLineStart; 1.350 + next(); 1.351 + node.discriminant = parseParenExpression(); 1.352 + node.cases = []; 1.353 + pushCx(); 1.354 + expect(tt.braceL); 1.355 + 1.356 + for (var cur; !closes(tt.braceR, blockIndent, line, true);) { 1.357 + if (token.type === tt._case || token.type === tt._default) { 1.358 + var isCase = token.type === tt._case; 1.359 + if (cur) finishNode(cur, "SwitchCase"); 1.360 + node.cases.push(cur = startNode()); 1.361 + cur.consequent = []; 1.362 + next(); 1.363 + if (isCase) cur.test = parseExpression(); 1.364 + else cur.test = null; 1.365 + expect(tt.colon); 1.366 + } else { 1.367 + if (!cur) { 1.368 + node.cases.push(cur = startNode()); 1.369 + cur.consequent = []; 1.370 + cur.test = null; 1.371 + } 1.372 + cur.consequent.push(parseStatement()); 1.373 + } 1.374 + } 1.375 + if (cur) finishNode(cur, "SwitchCase"); 1.376 + popCx(); 1.377 + eat(tt.braceR); 1.378 + return finishNode(node, "SwitchStatement"); 1.379 + 1.380 + case tt._throw: 1.381 + next(); 1.382 + node.argument = parseExpression(); 1.383 + semicolon(); 1.384 + return finishNode(node, "ThrowStatement"); 1.385 + 1.386 + case tt._try: 1.387 + next(); 1.388 + node.block = parseBlock(); 1.389 + node.handler = null; 1.390 + if (token.type === tt._catch) { 1.391 + var clause = startNode(); 1.392 + next(); 1.393 + expect(tt.parenL); 1.394 + clause.param = parseIdent(); 1.395 + expect(tt.parenR); 1.396 + clause.guard = null; 1.397 + clause.body = parseBlock(); 1.398 + node.handler = finishNode(clause, "CatchClause"); 1.399 + } 1.400 + node.finalizer = eat(tt._finally) ? parseBlock() : null; 1.401 + if (!node.handler && !node.finalizer) return node.block; 1.402 + return finishNode(node, "TryStatement"); 1.403 + 1.404 + case tt._var: 1.405 + next(); 1.406 + node = parseVar(node); 1.407 + semicolon(); 1.408 + return node; 1.409 + 1.410 + case tt._while: 1.411 + next(); 1.412 + node.test = parseParenExpression(); 1.413 + node.body = parseStatement(); 1.414 + return finishNode(node, "WhileStatement"); 1.415 + 1.416 + case tt._with: 1.417 + next(); 1.418 + node.object = parseParenExpression(); 1.419 + node.body = parseStatement(); 1.420 + return finishNode(node, "WithStatement"); 1.421 + 1.422 + case tt.braceL: 1.423 + return parseBlock(); 1.424 + 1.425 + case tt.semi: 1.426 + next(); 1.427 + return finishNode(node, "EmptyStatement"); 1.428 + 1.429 + default: 1.430 + var expr = parseExpression(); 1.431 + if (isDummy(expr)) { 1.432 + next(); 1.433 + if (token.type === tt.eof) return finishNode(node, "EmptyStatement"); 1.434 + return parseStatement(); 1.435 + } else if (starttype === tt.name && expr.type === "Identifier" && eat(tt.colon)) { 1.436 + node.body = parseStatement(); 1.437 + node.label = expr; 1.438 + return finishNode(node, "LabeledStatement"); 1.439 + } else { 1.440 + node.expression = expr; 1.441 + semicolon(); 1.442 + return finishNode(node, "ExpressionStatement"); 1.443 + } 1.444 + } 1.445 + } 1.446 + 1.447 + function parseBlock() { 1.448 + var node = startNode(); 1.449 + pushCx(); 1.450 + expect(tt.braceL); 1.451 + var blockIndent = curIndent, line = curLineStart; 1.452 + node.body = []; 1.453 + while (!closes(tt.braceR, blockIndent, line, true)) 1.454 + node.body.push(parseStatement()); 1.455 + popCx(); 1.456 + eat(tt.braceR); 1.457 + return finishNode(node, "BlockStatement"); 1.458 + } 1.459 + 1.460 + function parseFor(node, init) { 1.461 + node.init = init; 1.462 + node.test = node.update = null; 1.463 + if (eat(tt.semi) && token.type !== tt.semi) node.test = parseExpression(); 1.464 + if (eat(tt.semi) && token.type !== tt.parenR) node.update = parseExpression(); 1.465 + popCx(); 1.466 + expect(tt.parenR); 1.467 + node.body = parseStatement(); 1.468 + return finishNode(node, "ForStatement"); 1.469 + } 1.470 + 1.471 + function parseForIn(node, init) { 1.472 + node.left = init; 1.473 + node.right = parseExpression(); 1.474 + popCx(); 1.475 + expect(tt.parenR); 1.476 + node.body = parseStatement(); 1.477 + return finishNode(node, "ForInStatement"); 1.478 + } 1.479 + 1.480 + function parseVar(node, noIn) { 1.481 + node.declarations = []; 1.482 + node.kind = "var"; 1.483 + while (token.type === tt.name) { 1.484 + var decl = startNode(); 1.485 + decl.id = parseIdent(); 1.486 + decl.init = eat(tt.eq) ? parseExpression(true, noIn) : null; 1.487 + node.declarations.push(finishNode(decl, "VariableDeclarator")); 1.488 + if (!eat(tt.comma)) break; 1.489 + } 1.490 + if (!node.declarations.length) { 1.491 + var decl = startNode(); 1.492 + decl.id = dummyIdent(); 1.493 + node.declarations.push(finishNode(decl, "VariableDeclarator")); 1.494 + } 1.495 + return finishNode(node, "VariableDeclaration"); 1.496 + } 1.497 + 1.498 + function parseExpression(noComma, noIn) { 1.499 + var expr = parseMaybeAssign(noIn); 1.500 + if (!noComma && token.type === tt.comma) { 1.501 + var node = startNodeFrom(expr); 1.502 + node.expressions = [expr]; 1.503 + while (eat(tt.comma)) node.expressions.push(parseMaybeAssign(noIn)); 1.504 + return finishNode(node, "SequenceExpression"); 1.505 + } 1.506 + return expr; 1.507 + } 1.508 + 1.509 + function parseParenExpression() { 1.510 + pushCx(); 1.511 + expect(tt.parenL); 1.512 + var val = parseExpression(); 1.513 + popCx(); 1.514 + expect(tt.parenR); 1.515 + return val; 1.516 + } 1.517 + 1.518 + function parseMaybeAssign(noIn) { 1.519 + var left = parseMaybeConditional(noIn); 1.520 + if (token.type.isAssign) { 1.521 + var node = startNodeFrom(left); 1.522 + node.operator = token.value; 1.523 + node.left = checkLVal(left); 1.524 + next(); 1.525 + node.right = parseMaybeAssign(noIn); 1.526 + return finishNode(node, "AssignmentExpression"); 1.527 + } 1.528 + return left; 1.529 + } 1.530 + 1.531 + function parseMaybeConditional(noIn) { 1.532 + var expr = parseExprOps(noIn); 1.533 + if (eat(tt.question)) { 1.534 + var node = startNodeFrom(expr); 1.535 + node.test = expr; 1.536 + node.consequent = parseExpression(true); 1.537 + node.alternate = expect(tt.colon) ? parseExpression(true, noIn) : dummyIdent(); 1.538 + return finishNode(node, "ConditionalExpression"); 1.539 + } 1.540 + return expr; 1.541 + } 1.542 + 1.543 + function parseExprOps(noIn) { 1.544 + var indent = curIndent, line = curLineStart; 1.545 + return parseExprOp(parseMaybeUnary(noIn), -1, noIn, indent, line); 1.546 + } 1.547 + 1.548 + function parseExprOp(left, minPrec, noIn, indent, line) { 1.549 + if (curLineStart != line && curIndent < indent && tokenStartsLine()) return left; 1.550 + var prec = token.type.binop; 1.551 + if (prec != null && (!noIn || token.type !== tt._in)) { 1.552 + if (prec > minPrec) { 1.553 + var node = startNodeFrom(left); 1.554 + node.left = left; 1.555 + node.operator = token.value; 1.556 + next(); 1.557 + if (curLineStart != line && curIndent < indent && tokenStartsLine()) 1.558 + node.right = dummyIdent(); 1.559 + else 1.560 + node.right = parseExprOp(parseMaybeUnary(noIn), prec, noIn, indent, line); 1.561 + var node = finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression"); 1.562 + return parseExprOp(node, minPrec, noIn, indent, line); 1.563 + } 1.564 + } 1.565 + return left; 1.566 + } 1.567 + 1.568 + function parseMaybeUnary(noIn) { 1.569 + if (token.type.prefix) { 1.570 + var node = startNode(), update = token.type.isUpdate; 1.571 + node.operator = token.value; 1.572 + node.prefix = true; 1.573 + next(); 1.574 + node.argument = parseMaybeUnary(noIn); 1.575 + if (update) node.argument = checkLVal(node.argument); 1.576 + return finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); 1.577 + } 1.578 + var expr = parseExprSubscripts(); 1.579 + while (token.type.postfix && !canInsertSemicolon()) { 1.580 + var node = startNodeFrom(expr); 1.581 + node.operator = token.value; 1.582 + node.prefix = false; 1.583 + node.argument = checkLVal(expr); 1.584 + next(); 1.585 + expr = finishNode(node, "UpdateExpression"); 1.586 + } 1.587 + return expr; 1.588 + } 1.589 + 1.590 + function parseExprSubscripts() { 1.591 + return parseSubscripts(parseExprAtom(), false, curIndent, curLineStart); 1.592 + } 1.593 + 1.594 + function parseSubscripts(base, noCalls, startIndent, line) { 1.595 + for (;;) { 1.596 + if (curLineStart != line && curIndent <= startIndent && tokenStartsLine()) { 1.597 + if (token.type == tt.dot && curIndent == startIndent) 1.598 + --startIndent; 1.599 + else 1.600 + return base; 1.601 + } 1.602 + 1.603 + if (eat(tt.dot)) { 1.604 + var node = startNodeFrom(base); 1.605 + node.object = base; 1.606 + if (curLineStart != line && curIndent <= startIndent && tokenStartsLine()) 1.607 + node.property = dummyIdent(); 1.608 + else 1.609 + node.property = parsePropertyName() || dummyIdent(); 1.610 + node.computed = false; 1.611 + base = finishNode(node, "MemberExpression"); 1.612 + } else if (token.type == tt.bracketL) { 1.613 + pushCx(); 1.614 + next(); 1.615 + var node = startNodeFrom(base); 1.616 + node.object = base; 1.617 + node.property = parseExpression(); 1.618 + node.computed = true; 1.619 + popCx(); 1.620 + expect(tt.bracketR); 1.621 + base = finishNode(node, "MemberExpression"); 1.622 + } else if (!noCalls && token.type == tt.parenL) { 1.623 + pushCx(); 1.624 + var node = startNodeFrom(base); 1.625 + node.callee = base; 1.626 + node.arguments = parseExprList(tt.parenR); 1.627 + base = finishNode(node, "CallExpression"); 1.628 + } else { 1.629 + return base; 1.630 + } 1.631 + } 1.632 + } 1.633 + 1.634 + function parseExprAtom() { 1.635 + switch (token.type) { 1.636 + case tt._this: 1.637 + var node = startNode(); 1.638 + next(); 1.639 + return finishNode(node, "ThisExpression"); 1.640 + case tt.name: 1.641 + return parseIdent(); 1.642 + case tt.num: case tt.string: case tt.regexp: 1.643 + var node = startNode(); 1.644 + node.value = token.value; 1.645 + node.raw = input.slice(token.start, token.end); 1.646 + next(); 1.647 + return finishNode(node, "Literal"); 1.648 + 1.649 + case tt._null: case tt._true: case tt._false: 1.650 + var node = startNode(); 1.651 + node.value = token.type.atomValue; 1.652 + node.raw = token.type.keyword; 1.653 + next(); 1.654 + return finishNode(node, "Literal"); 1.655 + 1.656 + case tt.parenL: 1.657 + var tokStart1 = token.start; 1.658 + next(); 1.659 + var val = parseExpression(); 1.660 + val.start = tokStart1; 1.661 + val.end = token.end; 1.662 + expect(tt.parenR); 1.663 + return val; 1.664 + 1.665 + case tt.bracketL: 1.666 + var node = startNode(); 1.667 + pushCx(); 1.668 + node.elements = parseExprList(tt.bracketR); 1.669 + return finishNode(node, "ArrayExpression"); 1.670 + 1.671 + case tt.braceL: 1.672 + return parseObj(); 1.673 + 1.674 + case tt._function: 1.675 + var node = startNode(); 1.676 + next(); 1.677 + return parseFunction(node, false); 1.678 + 1.679 + case tt._new: 1.680 + return parseNew(); 1.681 + 1.682 + default: 1.683 + return dummyIdent(); 1.684 + } 1.685 + } 1.686 + 1.687 + function parseNew() { 1.688 + var node = startNode(), startIndent = curIndent, line = curLineStart; 1.689 + next(); 1.690 + node.callee = parseSubscripts(parseExprAtom(), true, startIndent, line); 1.691 + if (token.type == tt.parenL) { 1.692 + pushCx(); 1.693 + node.arguments = parseExprList(tt.parenR); 1.694 + } else { 1.695 + node.arguments = []; 1.696 + } 1.697 + return finishNode(node, "NewExpression"); 1.698 + } 1.699 + 1.700 + function parseObj() { 1.701 + var node = startNode(); 1.702 + node.properties = []; 1.703 + pushCx(); 1.704 + next(); 1.705 + var propIndent = curIndent, line = curLineStart; 1.706 + while (!closes(tt.braceR, propIndent, line)) { 1.707 + var name = parsePropertyName(); 1.708 + if (!name) { if (isDummy(parseExpression(true))) next(); eat(tt.comma); continue; } 1.709 + var prop = {key: name}, isGetSet = false, kind; 1.710 + if (eat(tt.colon)) { 1.711 + prop.value = parseExpression(true); 1.712 + kind = prop.kind = "init"; 1.713 + } else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" && 1.714 + (prop.key.name === "get" || prop.key.name === "set")) { 1.715 + isGetSet = true; 1.716 + kind = prop.kind = prop.key.name; 1.717 + prop.key = parsePropertyName() || dummyIdent(); 1.718 + prop.value = parseFunction(startNode(), false); 1.719 + } else { 1.720 + next(); 1.721 + eat(tt.comma); 1.722 + continue; 1.723 + } 1.724 + 1.725 + node.properties.push(prop); 1.726 + eat(tt.comma); 1.727 + } 1.728 + popCx(); 1.729 + eat(tt.braceR); 1.730 + return finishNode(node, "ObjectExpression"); 1.731 + } 1.732 + 1.733 + function parsePropertyName() { 1.734 + if (token.type === tt.num || token.type === tt.string) return parseExprAtom(); 1.735 + if (token.type === tt.name || token.type.keyword) return parseIdent(); 1.736 + } 1.737 + 1.738 + function parseIdent() { 1.739 + var node = startNode(); 1.740 + node.name = token.type === tt.name ? token.value : token.type.keyword; 1.741 + next(); 1.742 + return finishNode(node, "Identifier"); 1.743 + } 1.744 + 1.745 + function parseFunction(node, isStatement) { 1.746 + if (token.type === tt.name) node.id = parseIdent(); 1.747 + else if (isStatement) node.id = dummyIdent(); 1.748 + else node.id = null; 1.749 + node.params = []; 1.750 + pushCx(); 1.751 + expect(tt.parenL); 1.752 + while (token.type == tt.name) { 1.753 + node.params.push(parseIdent()); 1.754 + eat(tt.comma); 1.755 + } 1.756 + popCx(); 1.757 + eat(tt.parenR); 1.758 + node.body = parseBlock(); 1.759 + return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); 1.760 + } 1.761 + 1.762 + function parseExprList(close) { 1.763 + var indent = curIndent, line = curLineStart, elts = [], continuedLine = nextLineStart; 1.764 + next(); // Opening bracket 1.765 + if (curLineStart > continuedLine) continuedLine = curLineStart; 1.766 + while (!closes(close, indent + (curLineStart <= continuedLine ? 1 : 0), line)) { 1.767 + var elt = parseExpression(true); 1.768 + if (isDummy(elt)) { 1.769 + if (closes(close, indent, line)) break; 1.770 + next(); 1.771 + } else { 1.772 + elts.push(elt); 1.773 + } 1.774 + while (eat(tt.comma)) {} 1.775 + } 1.776 + popCx(); 1.777 + eat(close); 1.778 + return elts; 1.779 + } 1.780 +});