diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-05-03 15:35:00 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-05-03 15:35:00 +0200 |
commit | de98e0b232509d5f40c135d540a70e415272ff85 (patch) | |
tree | a79222a5b58484ab3b80d18efcaaa7ccc4769b33 /node_modules/acorn/src/loose | |
parent | e0c9d480a73fa629c1e4a47d3e721f1d2d345406 (diff) |
node_modules
Diffstat (limited to 'node_modules/acorn/src/loose')
-rw-r--r-- | node_modules/acorn/src/loose/expression.js | 562 | ||||
-rw-r--r-- | node_modules/acorn/src/loose/index.js | 49 | ||||
-rw-r--r-- | node_modules/acorn/src/loose/parseutil.js | 1 | ||||
-rw-r--r-- | node_modules/acorn/src/loose/state.js | 161 | ||||
-rw-r--r-- | node_modules/acorn/src/loose/statement.js | 448 | ||||
-rw-r--r-- | node_modules/acorn/src/loose/tokenize.js | 111 |
6 files changed, 1332 insertions, 0 deletions
diff --git a/node_modules/acorn/src/loose/expression.js b/node_modules/acorn/src/loose/expression.js new file mode 100644 index 000000000..62bd42de3 --- /dev/null +++ b/node_modules/acorn/src/loose/expression.js @@ -0,0 +1,562 @@ +import {LooseParser} from "./state" +import {isDummy} from "./parseutil" +import {tokTypes as tt} from "../index" + +const lp = LooseParser.prototype + +lp.checkLVal = function(expr) { + if (!expr) return expr + switch (expr.type) { + case "Identifier": + case "MemberExpression": + return expr + + case "ParenthesizedExpression": + expr.expression = this.checkLVal(expr.expression) + return expr + + default: + return this.dummyIdent() + } +} + +lp.parseExpression = function(noIn) { + let start = this.storeCurrentPos() + let expr = this.parseMaybeAssign(noIn) + if (this.tok.type === tt.comma) { + let node = this.startNodeAt(start) + node.expressions = [expr] + while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn)) + return this.finishNode(node, "SequenceExpression") + } + return expr +} + +lp.parseParenExpression = function() { + this.pushCx() + this.expect(tt.parenL) + let val = this.parseExpression() + this.popCx() + this.expect(tt.parenR) + return val +} + +lp.parseMaybeAssign = function(noIn) { + if (this.toks.isContextual("yield")) { + let node = this.startNode() + this.next() + if (this.semicolon() || this.canInsertSemicolon() || (this.tok.type != tt.star && !this.tok.type.startsExpr)) { + node.delegate = false + node.argument = null + } else { + node.delegate = this.eat(tt.star) + node.argument = this.parseMaybeAssign() + } + return this.finishNode(node, "YieldExpression") + } + + let start = this.storeCurrentPos() + let left = this.parseMaybeConditional(noIn) + if (this.tok.type.isAssign) { + let node = this.startNodeAt(start) + node.operator = this.tok.value + node.left = this.tok.type === tt.eq ? this.toAssignable(left) : this.checkLVal(left) + this.next() + node.right = this.parseMaybeAssign(noIn) + return this.finishNode(node, "AssignmentExpression") + } + return left +} + +lp.parseMaybeConditional = function(noIn) { + let start = this.storeCurrentPos() + let expr = this.parseExprOps(noIn) + if (this.eat(tt.question)) { + let node = this.startNodeAt(start) + node.test = expr + node.consequent = this.parseMaybeAssign() + node.alternate = this.expect(tt.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent() + return this.finishNode(node, "ConditionalExpression") + } + return expr +} + +lp.parseExprOps = function(noIn) { + let start = this.storeCurrentPos() + let indent = this.curIndent, line = this.curLineStart + return this.parseExprOp(this.parseMaybeUnary(false), start, -1, noIn, indent, line) +} + +lp.parseExprOp = function(left, start, minPrec, noIn, indent, line) { + if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) return left + let prec = this.tok.type.binop + if (prec != null && (!noIn || this.tok.type !== tt._in)) { + if (prec > minPrec) { + let node = this.startNodeAt(start) + node.left = left + node.operator = this.tok.value + this.next() + if (this.curLineStart != line && this.curIndent < indent && this.tokenStartsLine()) { + node.right = this.dummyIdent() + } else { + let rightStart = this.storeCurrentPos() + node.right = this.parseExprOp(this.parseMaybeUnary(false), rightStart, prec, noIn, indent, line) + } + this.finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression") + return this.parseExprOp(node, start, minPrec, noIn, indent, line) + } + } + return left +} + +lp.parseMaybeUnary = function(sawUnary) { + let start = this.storeCurrentPos(), expr + if (this.options.ecmaVersion >= 8 && this.inAsync && this.toks.isContextual("await")) { + expr = this.parseAwait() + sawUnary = true + } else if (this.tok.type.prefix) { + let node = this.startNode(), update = this.tok.type === tt.incDec + if (!update) sawUnary = true + node.operator = this.tok.value + node.prefix = true + this.next() + node.argument = this.parseMaybeUnary(true) + if (update) node.argument = this.checkLVal(node.argument) + expr = this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression") + } else if (this.tok.type === tt.ellipsis) { + let node = this.startNode() + this.next() + node.argument = this.parseMaybeUnary(sawUnary) + expr = this.finishNode(node, "SpreadElement") + } else { + expr = this.parseExprSubscripts() + while (this.tok.type.postfix && !this.canInsertSemicolon()) { + let node = this.startNodeAt(start) + node.operator = this.tok.value + node.prefix = false + node.argument = this.checkLVal(expr) + this.next() + expr = this.finishNode(node, "UpdateExpression") + } + } + + if (!sawUnary && this.eat(tt.starstar)) { + let node = this.startNodeAt(start) + node.operator = "**" + node.left = expr + node.right = this.parseMaybeUnary(false) + return this.finishNode(node, "BinaryExpression") + } + + return expr +} + +lp.parseExprSubscripts = function() { + let start = this.storeCurrentPos() + return this.parseSubscripts(this.parseExprAtom(), start, false, this.curIndent, this.curLineStart) +} + +lp.parseSubscripts = function(base, start, noCalls, startIndent, line) { + for (;;) { + if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) { + if (this.tok.type == tt.dot && this.curIndent == startIndent) + --startIndent + else + return base + } + + let maybeAsyncArrow = base.type === "Identifier" && base.name === "async" && !this.canInsertSemicolon() + + if (this.eat(tt.dot)) { + let node = this.startNodeAt(start) + node.object = base + if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) + node.property = this.dummyIdent() + else + node.property = this.parsePropertyAccessor() || this.dummyIdent() + node.computed = false + base = this.finishNode(node, "MemberExpression") + } else if (this.tok.type == tt.bracketL) { + this.pushCx() + this.next() + let node = this.startNodeAt(start) + node.object = base + node.property = this.parseExpression() + node.computed = true + this.popCx() + this.expect(tt.bracketR) + base = this.finishNode(node, "MemberExpression") + } else if (!noCalls && this.tok.type == tt.parenL) { + let exprList = this.parseExprList(tt.parenR) + if (maybeAsyncArrow && this.eat(tt.arrow)) + return this.parseArrowExpression(this.startNodeAt(start), exprList, true) + let node = this.startNodeAt(start) + node.callee = base + node.arguments = exprList + base = this.finishNode(node, "CallExpression") + } else if (this.tok.type == tt.backQuote) { + let node = this.startNodeAt(start) + node.tag = base + node.quasi = this.parseTemplate() + base = this.finishNode(node, "TaggedTemplateExpression") + } else { + return base + } + } +} + +lp.parseExprAtom = function() { + let node + switch (this.tok.type) { + case tt._this: + case tt._super: + let type = this.tok.type === tt._this ? "ThisExpression" : "Super" + node = this.startNode() + this.next() + return this.finishNode(node, type) + + case tt.name: + let start = this.storeCurrentPos() + let id = this.parseIdent() + let isAsync = false + if (id.name === "async" && !this.canInsertSemicolon()) { + if (this.eat(tt._function)) + return this.parseFunction(this.startNodeAt(start), false, true) + if (this.tok.type === tt.name) { + id = this.parseIdent() + isAsync = true + } + } + return this.eat(tt.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id], isAsync) : id + + case tt.regexp: + node = this.startNode() + let val = this.tok.value + node.regex = {pattern: val.pattern, flags: val.flags} + node.value = val.value + node.raw = this.input.slice(this.tok.start, this.tok.end) + this.next() + return this.finishNode(node, "Literal") + + case tt.num: case tt.string: + node = this.startNode() + node.value = this.tok.value + node.raw = this.input.slice(this.tok.start, this.tok.end) + this.next() + return this.finishNode(node, "Literal") + + case tt._null: case tt._true: case tt._false: + node = this.startNode() + node.value = this.tok.type === tt._null ? null : this.tok.type === tt._true + node.raw = this.tok.type.keyword + this.next() + return this.finishNode(node, "Literal") + + case tt.parenL: + let parenStart = this.storeCurrentPos() + this.next() + let inner = this.parseExpression() + this.expect(tt.parenR) + if (this.eat(tt.arrow)) { + // (a,)=>a // SequenceExpression makes dummy in the last hole. Drop the dummy. + let params = inner.expressions || [inner] + if (params.length && isDummy(params[params.length - 1])) + params.pop() + return this.parseArrowExpression(this.startNodeAt(parenStart), params) + } + if (this.options.preserveParens) { + let par = this.startNodeAt(parenStart) + par.expression = inner + inner = this.finishNode(par, "ParenthesizedExpression") + } + return inner + + case tt.bracketL: + node = this.startNode() + node.elements = this.parseExprList(tt.bracketR, true) + return this.finishNode(node, "ArrayExpression") + + case tt.braceL: + return this.parseObj() + + case tt._class: + return this.parseClass(false) + + case tt._function: + node = this.startNode() + this.next() + return this.parseFunction(node, false) + + case tt._new: + return this.parseNew() + + case tt.backQuote: + return this.parseTemplate() + + default: + return this.dummyIdent() + } +} + +lp.parseNew = function() { + let node = this.startNode(), startIndent = this.curIndent, line = this.curLineStart + let meta = this.parseIdent(true) + if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { + node.meta = meta + node.property = this.parseIdent(true) + return this.finishNode(node, "MetaProperty") + } + let start = this.storeCurrentPos() + node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line) + if (this.tok.type == tt.parenL) { + node.arguments = this.parseExprList(tt.parenR) + } else { + node.arguments = [] + } + return this.finishNode(node, "NewExpression") +} + +lp.parseTemplateElement = function() { + let elem = this.startNode() + elem.value = { + raw: this.input.slice(this.tok.start, this.tok.end).replace(/\r\n?/g, "\n"), + cooked: this.tok.value + } + this.next() + elem.tail = this.tok.type === tt.backQuote + return this.finishNode(elem, "TemplateElement") +} + +lp.parseTemplate = function() { + let node = this.startNode() + this.next() + node.expressions = [] + let curElt = this.parseTemplateElement() + node.quasis = [curElt] + while (!curElt.tail) { + this.next() + node.expressions.push(this.parseExpression()) + if (this.expect(tt.braceR)) { + curElt = this.parseTemplateElement() + } else { + curElt = this.startNode() + curElt.value = {cooked: "", raw: ""} + curElt.tail = true + this.finishNode(curElt, "TemplateElement") + } + node.quasis.push(curElt) + } + this.expect(tt.backQuote) + return this.finishNode(node, "TemplateLiteral") +} + +lp.parseObj = function() { + let node = this.startNode() + node.properties = [] + this.pushCx() + let indent = this.curIndent + 1, line = this.curLineStart + this.eat(tt.braceL) + if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart } + while (!this.closes(tt.braceR, indent, line)) { + let prop = this.startNode(), isGenerator, isAsync, start + if (this.options.ecmaVersion >= 6) { + start = this.storeCurrentPos() + prop.method = false + prop.shorthand = false + isGenerator = this.eat(tt.star) + } + this.parsePropertyName(prop) + if (!prop.computed && + prop.key.type === "Identifier" && prop.key.name === "async" && this.tok.type !== tt.parenL && + this.tok.type !== tt.colon && !this.canInsertSemicolon()) { + this.parsePropertyName(prop) + isAsync = true + } else { + isAsync = false + } + if (isDummy(prop.key)) { if (isDummy(this.parseMaybeAssign())) this.next(); this.eat(tt.comma); continue } + if (this.eat(tt.colon)) { + prop.kind = "init" + prop.value = this.parseMaybeAssign() + } else if (this.options.ecmaVersion >= 6 && (this.tok.type === tt.parenL || this.tok.type === tt.braceL)) { + prop.kind = "init" + prop.method = true + prop.value = this.parseMethod(isGenerator, isAsync) + } else if (this.options.ecmaVersion >= 5 && prop.key.type === "Identifier" && + !prop.computed && (prop.key.name === "get" || prop.key.name === "set") && + (this.tok.type != tt.comma && this.tok.type != tt.braceR)) { + prop.kind = prop.key.name + this.parsePropertyName(prop) + prop.value = this.parseMethod(false) + } else { + prop.kind = "init" + if (this.options.ecmaVersion >= 6) { + if (this.eat(tt.eq)) { + let assign = this.startNodeAt(start) + assign.operator = "=" + assign.left = prop.key + assign.right = this.parseMaybeAssign() + prop.value = this.finishNode(assign, "AssignmentExpression") + } else { + prop.value = prop.key + } + } else { + prop.value = this.dummyIdent() + } + prop.shorthand = true + } + node.properties.push(this.finishNode(prop, "Property")) + this.eat(tt.comma) + } + this.popCx() + if (!this.eat(tt.braceR)) { + // If there is no closing brace, make the node span to the start + // of the next token (this is useful for Tern) + this.last.end = this.tok.start + if (this.options.locations) this.last.loc.end = this.tok.loc.start + } + return this.finishNode(node, "ObjectExpression") +} + +lp.parsePropertyName = function(prop) { + if (this.options.ecmaVersion >= 6) { + if (this.eat(tt.bracketL)) { + prop.computed = true + prop.key = this.parseExpression() + this.expect(tt.bracketR) + return + } else { + prop.computed = false + } + } + let key = (this.tok.type === tt.num || this.tok.type === tt.string) ? this.parseExprAtom() : this.parseIdent() + prop.key = key || this.dummyIdent() +} + +lp.parsePropertyAccessor = function() { + if (this.tok.type === tt.name || this.tok.type.keyword) return this.parseIdent() +} + +lp.parseIdent = function() { + let name = this.tok.type === tt.name ? this.tok.value : this.tok.type.keyword + if (!name) return this.dummyIdent() + let node = this.startNode() + this.next() + node.name = name + return this.finishNode(node, "Identifier") +} + +lp.initFunction = function(node) { + node.id = null + node.params = [] + if (this.options.ecmaVersion >= 6) { + node.generator = false + node.expression = false + } + if (this.options.ecmaVersion >= 8) + node.async = false +} + +// Convert existing expression atom to assignable pattern +// if possible. + +lp.toAssignable = function(node, binding) { + if (!node || node.type == "Identifier" || (node.type == "MemberExpression" && !binding)) { + // Okay + } else if (node.type == "ParenthesizedExpression") { + node.expression = this.toAssignable(node.expression, binding) + } else if (this.options.ecmaVersion < 6) { + return this.dummyIdent() + } else if (node.type == "ObjectExpression") { + node.type = "ObjectPattern" + let props = node.properties + for (let i = 0; i < props.length; i++) + props[i].value = this.toAssignable(props[i].value, binding) + } else if (node.type == "ArrayExpression") { + node.type = "ArrayPattern" + this.toAssignableList(node.elements, binding) + } else if (node.type == "SpreadElement") { + node.type = "RestElement" + node.argument = this.toAssignable(node.argument, binding) + } else if (node.type == "AssignmentExpression") { + node.type = "AssignmentPattern" + delete node.operator + } else { + return this.dummyIdent() + } + return node +} + +lp.toAssignableList = function(exprList, binding) { + for (let i = 0; i < exprList.length; i++) + exprList[i] = this.toAssignable(exprList[i], binding) + return exprList +} + +lp.parseFunctionParams = function(params) { + params = this.parseExprList(tt.parenR) + return this.toAssignableList(params, true) +} + +lp.parseMethod = function(isGenerator, isAsync) { + let node = this.startNode(), oldInAsync = this.inAsync + this.initFunction(node) + if (this.options.ecmaVersion >= 6) + node.generator = !!isGenerator + if (this.options.ecmaVersion >= 8) + node.async = !!isAsync + this.inAsync = node.async + node.params = this.parseFunctionParams() + node.expression = this.options.ecmaVersion >= 6 && this.tok.type !== tt.braceL + node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock() + this.inAsync = oldInAsync + return this.finishNode(node, "FunctionExpression") +} + +lp.parseArrowExpression = function(node, params, isAsync) { + let oldInAsync = this.inAsync + this.initFunction(node) + if (this.options.ecmaVersion >= 8) + node.async = !!isAsync + this.inAsync = node.async + node.params = this.toAssignableList(params, true) + node.expression = this.tok.type !== tt.braceL + node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock() + this.inAsync = oldInAsync + return this.finishNode(node, "ArrowFunctionExpression") +} + +lp.parseExprList = function(close, allowEmpty) { + this.pushCx() + let indent = this.curIndent, line = this.curLineStart, elts = [] + this.next() // Opening bracket + while (!this.closes(close, indent + 1, line)) { + if (this.eat(tt.comma)) { + elts.push(allowEmpty ? null : this.dummyIdent()) + continue + } + let elt = this.parseMaybeAssign() + if (isDummy(elt)) { + if (this.closes(close, indent, line)) break + this.next() + } else { + elts.push(elt) + } + this.eat(tt.comma) + } + this.popCx() + if (!this.eat(close)) { + // If there is no closing brace, make the node span to the start + // of the next token (this is useful for Tern) + this.last.end = this.tok.start + if (this.options.locations) this.last.loc.end = this.tok.loc.start + } + return elts +} + +lp.parseAwait = function() { + let node = this.startNode() + this.next() + node.argument = this.parseMaybeUnary() + return this.finishNode(node, "AwaitExpression") +} diff --git a/node_modules/acorn/src/loose/index.js b/node_modules/acorn/src/loose/index.js new file mode 100644 index 000000000..daf7bf2d7 --- /dev/null +++ b/node_modules/acorn/src/loose/index.js @@ -0,0 +1,49 @@ +// Acorn: Loose parser +// +// This module provides an alternative parser (`parse_dammit`) that +// exposes that same interface as `parse`, but will try to parse +// anything as JavaScript, repairing syntax error the best it can. +// There are circumstances in which it will raise an error and give +// up, but they are very rare. The resulting AST will be a mostly +// valid JavaScript AST (as per the [Mozilla parser API][api], except +// that: +// +// - Return outside functions is allowed +// +// - Label consistency (no conflicts, break only to existing labels) +// is not enforced. +// +// - Bogus Identifier nodes with a name of `"✖"` are inserted whenever +// the parser got too confused to return anything meaningful. +// +// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API +// +// The expected use for this is to *first* try `acorn.parse`, and only +// if that fails switch to `parse_dammit`. The loose parser might +// parse badly indented code incorrectly, so **don't** use it as +// your default parser. +// +// Quite a lot of acorn.js is duplicated here. The alternative was to +// add a *lot* of extra cruft to that file, making it less readable +// and slower. Copying and editing the code allowed me to make +// invasive changes and simplifications without creating a complicated +// tangle. + +import {addLooseExports, defaultOptions} from "../index" +import {LooseParser, pluginsLoose} from "./state" +import "./tokenize" +import "./statement" +import "./expression" + +export {LooseParser, pluginsLoose} from "./state" + +defaultOptions.tabSize = 4 + +// eslint-disable-next-line camelcase +export function parse_dammit(input, options) { + let p = new LooseParser(input, options) + p.next() + return p.parseTopLevel() +} + +addLooseExports(parse_dammit, LooseParser, pluginsLoose) diff --git a/node_modules/acorn/src/loose/parseutil.js b/node_modules/acorn/src/loose/parseutil.js new file mode 100644 index 000000000..b620fdaf0 --- /dev/null +++ b/node_modules/acorn/src/loose/parseutil.js @@ -0,0 +1 @@ +export function isDummy(node) { return node.name == "✖" } diff --git a/node_modules/acorn/src/loose/state.js b/node_modules/acorn/src/loose/state.js new file mode 100644 index 000000000..18987aa22 --- /dev/null +++ b/node_modules/acorn/src/loose/state.js @@ -0,0 +1,161 @@ +import {tokenizer, SourceLocation, tokTypes as tt, Node, lineBreak, isNewLine} from "../index" + +// Registered plugins +export const pluginsLoose = {} + +export class LooseParser { + constructor(input, options = {}) { + this.toks = tokenizer(input, options) + this.options = this.toks.options + this.input = this.toks.input + this.tok = this.last = {type: tt.eof, start: 0, end: 0} + if (this.options.locations) { + let here = this.toks.curPosition() + this.tok.loc = new SourceLocation(this.toks, here, here) + } + this.ahead = [] // Tokens ahead + this.context = [] // Indentation contexted + this.curIndent = 0 + this.curLineStart = 0 + this.nextLineStart = this.lineEnd(this.curLineStart) + 1 + this.inAsync = false + // Load plugins + this.options.pluginsLoose = options.pluginsLoose || {} + this.loadPlugins(this.options.pluginsLoose) + } + + startNode() { + return new Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null) + } + + storeCurrentPos() { + return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start + } + + startNodeAt(pos) { + if (this.options.locations) { + return new Node(this.toks, pos[0], pos[1]) + } else { + return new Node(this.toks, pos) + } + } + + finishNode(node, type) { + node.type = type + node.end = this.last.end + if (this.options.locations) + node.loc.end = this.last.loc.end + if (this.options.ranges) + node.range[1] = this.last.end + return node + } + + dummyNode(type) { + let dummy = this.startNode() + dummy.type = type + dummy.end = dummy.start + if (this.options.locations) + dummy.loc.end = dummy.loc.start + if (this.options.ranges) + dummy.range[1] = dummy.start + this.last = {type: tt.name, start: dummy.start, end: dummy.start, loc: dummy.loc} + return dummy + } + + dummyIdent() { + let dummy = this.dummyNode("Identifier") + dummy.name = "✖" + return dummy + } + + dummyString() { + let dummy = this.dummyNode("Literal") + dummy.value = dummy.raw = "✖" + return dummy + } + + eat(type) { + if (this.tok.type === type) { + this.next() + return true + } else { + return false + } + } + + isContextual(name) { + return this.tok.type === tt.name && this.tok.value === name + } + + eatContextual(name) { + return this.tok.value === name && this.eat(tt.name) + } + + canInsertSemicolon() { + return this.tok.type === tt.eof || this.tok.type === tt.braceR || + lineBreak.test(this.input.slice(this.last.end, this.tok.start)) + } + + semicolon() { + return this.eat(tt.semi) + } + + expect(type) { + if (this.eat(type)) return true + for (let i = 1; i <= 2; i++) { + if (this.lookAhead(i).type == type) { + for (let j = 0; j < i; j++) this.next() + return true + } + } + } + + pushCx() { + this.context.push(this.curIndent) + } + + popCx() { + this.curIndent = this.context.pop() + } + + lineEnd(pos) { + while (pos < this.input.length && !isNewLine(this.input.charCodeAt(pos))) ++pos + return pos + } + + indentationAfter(pos) { + for (let count = 0;; ++pos) { + let ch = this.input.charCodeAt(pos) + if (ch === 32) ++count + else if (ch === 9) count += this.options.tabSize + else return count + } + } + + closes(closeTok, indent, line, blockHeuristic) { + if (this.tok.type === closeTok || this.tok.type === tt.eof) return true + return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && + (!blockHeuristic || this.nextLineStart >= this.input.length || + this.indentationAfter(this.nextLineStart) < indent) + } + + tokenStartsLine() { + for (let p = this.tok.start - 1; p >= this.curLineStart; --p) { + let ch = this.input.charCodeAt(p) + if (ch !== 9 && ch !== 32) return false + } + return true + } + + extend(name, f) { + this[name] = f(this[name]) + } + + loadPlugins(pluginConfigs) { + for (let name in pluginConfigs) { + let plugin = pluginsLoose[name] + if (!plugin) throw new Error("Plugin '" + name + "' not found") + plugin(this, pluginConfigs[name]) + } + } +} diff --git a/node_modules/acorn/src/loose/statement.js b/node_modules/acorn/src/loose/statement.js new file mode 100644 index 000000000..192df43e0 --- /dev/null +++ b/node_modules/acorn/src/loose/statement.js @@ -0,0 +1,448 @@ +import {LooseParser} from "./state" +import {isDummy} from "./parseutil" +import {getLineInfo, tokTypes as tt} from "../index" + +const lp = LooseParser.prototype + +lp.parseTopLevel = function() { + let node = this.startNodeAt(this.options.locations ? [0, getLineInfo(this.input, 0)] : 0) + node.body = [] + while (this.tok.type !== tt.eof) node.body.push(this.parseStatement()) + this.last = this.tok + if (this.options.ecmaVersion >= 6) { + node.sourceType = this.options.sourceType + } + return this.finishNode(node, "Program") +} + +lp.parseStatement = function() { + let starttype = this.tok.type, node = this.startNode(), kind + + if (this.toks.isLet()) { + starttype = tt._var + kind = "let" + } + + switch (starttype) { + case tt._break: case tt._continue: + this.next() + let isBreak = starttype === tt._break + if (this.semicolon() || this.canInsertSemicolon()) { + node.label = null + } else { + node.label = this.tok.type === tt.name ? this.parseIdent() : null + this.semicolon() + } + return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement") + + case tt._debugger: + this.next() + this.semicolon() + return this.finishNode(node, "DebuggerStatement") + + case tt._do: + this.next() + node.body = this.parseStatement() + node.test = this.eat(tt._while) ? this.parseParenExpression() : this.dummyIdent() + this.semicolon() + return this.finishNode(node, "DoWhileStatement") + + case tt._for: + this.next() + this.pushCx() + this.expect(tt.parenL) + if (this.tok.type === tt.semi) return this.parseFor(node, null) + let isLet = this.toks.isLet() + if (isLet || this.tok.type === tt._var || this.tok.type === tt._const) { + let init = this.parseVar(true, isLet ? "let" : this.tok.value) + if (init.declarations.length === 1 && (this.tok.type === tt._in || this.isContextual("of"))) { + return this.parseForIn(node, init) + } + return this.parseFor(node, init) + } + let init = this.parseExpression(true) + if (this.tok.type === tt._in || this.isContextual("of")) + return this.parseForIn(node, this.toAssignable(init)) + return this.parseFor(node, init) + + case tt._function: + this.next() + return this.parseFunction(node, true) + + case tt._if: + this.next() + node.test = this.parseParenExpression() + node.consequent = this.parseStatement() + node.alternate = this.eat(tt._else) ? this.parseStatement() : null + return this.finishNode(node, "IfStatement") + + case tt._return: + this.next() + if (this.eat(tt.semi) || this.canInsertSemicolon()) node.argument = null + else { node.argument = this.parseExpression(); this.semicolon() } + return this.finishNode(node, "ReturnStatement") + + case tt._switch: + let blockIndent = this.curIndent, line = this.curLineStart + this.next() + node.discriminant = this.parseParenExpression() + node.cases = [] + this.pushCx() + this.expect(tt.braceL) + + let cur + while (!this.closes(tt.braceR, blockIndent, line, true)) { + if (this.tok.type === tt._case || this.tok.type === tt._default) { + let isCase = this.tok.type === tt._case + if (cur) this.finishNode(cur, "SwitchCase") + node.cases.push(cur = this.startNode()) + cur.consequent = [] + this.next() + if (isCase) cur.test = this.parseExpression() + else cur.test = null + this.expect(tt.colon) + } else { + if (!cur) { + node.cases.push(cur = this.startNode()) + cur.consequent = [] + cur.test = null + } + cur.consequent.push(this.parseStatement()) + } + } + if (cur) this.finishNode(cur, "SwitchCase") + this.popCx() + this.eat(tt.braceR) + return this.finishNode(node, "SwitchStatement") + + case tt._throw: + this.next() + node.argument = this.parseExpression() + this.semicolon() + return this.finishNode(node, "ThrowStatement") + + case tt._try: + this.next() + node.block = this.parseBlock() + node.handler = null + if (this.tok.type === tt._catch) { + let clause = this.startNode() + this.next() + this.expect(tt.parenL) + clause.param = this.toAssignable(this.parseExprAtom(), true) + this.expect(tt.parenR) + clause.body = this.parseBlock() + node.handler = this.finishNode(clause, "CatchClause") + } + node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null + if (!node.handler && !node.finalizer) return node.block + return this.finishNode(node, "TryStatement") + + case tt._var: + case tt._const: + return this.parseVar(false, kind || this.tok.value) + + case tt._while: + this.next() + node.test = this.parseParenExpression() + node.body = this.parseStatement() + return this.finishNode(node, "WhileStatement") + + case tt._with: + this.next() + node.object = this.parseParenExpression() + node.body = this.parseStatement() + return this.finishNode(node, "WithStatement") + + case tt.braceL: + return this.parseBlock() + + case tt.semi: + this.next() + return this.finishNode(node, "EmptyStatement") + + case tt._class: + return this.parseClass(true) + + case tt._import: + return this.parseImport() + + case tt._export: + return this.parseExport() + + default: + if (this.toks.isAsyncFunction()) { + this.next() + this.next() + return this.parseFunction(node, true, true) + } + let expr = this.parseExpression() + if (isDummy(expr)) { + this.next() + if (this.tok.type === tt.eof) return this.finishNode(node, "EmptyStatement") + return this.parseStatement() + } else if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) { + node.body = this.parseStatement() + node.label = expr + return this.finishNode(node, "LabeledStatement") + } else { + node.expression = expr + this.semicolon() + return this.finishNode(node, "ExpressionStatement") + } + } +} + +lp.parseBlock = function() { + let node = this.startNode() + this.pushCx() + this.expect(tt.braceL) + let blockIndent = this.curIndent, line = this.curLineStart + node.body = [] + while (!this.closes(tt.braceR, blockIndent, line, true)) + node.body.push(this.parseStatement()) + this.popCx() + this.eat(tt.braceR) + return this.finishNode(node, "BlockStatement") +} + +lp.parseFor = function(node, init) { + node.init = init + node.test = node.update = null + if (this.eat(tt.semi) && this.tok.type !== tt.semi) node.test = this.parseExpression() + if (this.eat(tt.semi) && this.tok.type !== tt.parenR) node.update = this.parseExpression() + this.popCx() + this.expect(tt.parenR) + node.body = this.parseStatement() + return this.finishNode(node, "ForStatement") +} + +lp.parseForIn = function(node, init) { + let type = this.tok.type === tt._in ? "ForInStatement" : "ForOfStatement" + this.next() + node.left = init + node.right = this.parseExpression() + this.popCx() + this.expect(tt.parenR) + node.body = this.parseStatement() + return this.finishNode(node, type) +} + +lp.parseVar = function(noIn, kind) { + let node = this.startNode() + node.kind = kind + this.next() + node.declarations = [] + do { + let decl = this.startNode() + decl.id = this.options.ecmaVersion >= 6 ? this.toAssignable(this.parseExprAtom(), true) : this.parseIdent() + decl.init = this.eat(tt.eq) ? this.parseMaybeAssign(noIn) : null + node.declarations.push(this.finishNode(decl, "VariableDeclarator")) + } while (this.eat(tt.comma)) + if (!node.declarations.length) { + let decl = this.startNode() + decl.id = this.dummyIdent() + node.declarations.push(this.finishNode(decl, "VariableDeclarator")) + } + if (!noIn) this.semicolon() + return this.finishNode(node, "VariableDeclaration") +} + +lp.parseClass = function(isStatement) { + let node = this.startNode() + this.next() + if (this.tok.type === tt.name) node.id = this.parseIdent() + else if (isStatement === true) node.id = this.dummyIdent() + else node.id = null + node.superClass = this.eat(tt._extends) ? this.parseExpression() : null + node.body = this.startNode() + node.body.body = [] + this.pushCx() + let indent = this.curIndent + 1, line = this.curLineStart + this.eat(tt.braceL) + if (this.curIndent + 1 < indent) { indent = this.curIndent; line = this.curLineStart } + while (!this.closes(tt.braceR, indent, line)) { + if (this.semicolon()) continue + let method = this.startNode(), isGenerator, isAsync + if (this.options.ecmaVersion >= 6) { + method.static = false + isGenerator = this.eat(tt.star) + } + this.parsePropertyName(method) + if (isDummy(method.key)) { if (isDummy(this.parseMaybeAssign())) this.next(); this.eat(tt.comma); continue } + if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" && + (this.tok.type != tt.parenL && this.tok.type != tt.braceL)) { + method.static = true + isGenerator = this.eat(tt.star) + this.parsePropertyName(method) + } else { + method.static = false + } + if (!method.computed && + method.key.type === "Identifier" && method.key.name === "async" && this.tok.type !== tt.parenL && + !this.canInsertSemicolon()) { + this.parsePropertyName(method) + isAsync = true + } else { + isAsync = false + } + if (this.options.ecmaVersion >= 5 && method.key.type === "Identifier" && + !method.computed && (method.key.name === "get" || method.key.name === "set") && + this.tok.type !== tt.parenL && this.tok.type !== tt.braceL) { + method.kind = method.key.name + this.parsePropertyName(method) + method.value = this.parseMethod(false) + } else { + if (!method.computed && !method.static && !isGenerator && !isAsync && ( + method.key.type === "Identifier" && method.key.name === "constructor" || + method.key.type === "Literal" && method.key.value === "constructor")) { + method.kind = "constructor" + } else { + method.kind = "method" + } + method.value = this.parseMethod(isGenerator, isAsync) + } + node.body.body.push(this.finishNode(method, "MethodDefinition")) + } + this.popCx() + if (!this.eat(tt.braceR)) { + // If there is no closing brace, make the node span to the start + // of the next token (this is useful for Tern) + this.last.end = this.tok.start + if (this.options.locations) this.last.loc.end = this.tok.loc.start + } + this.semicolon() + this.finishNode(node.body, "ClassBody") + return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") +} + +lp.parseFunction = function(node, isStatement, isAsync) { + let oldInAsync = this.inAsync + this.initFunction(node) + if (this.options.ecmaVersion >= 6) { + node.generator = this.eat(tt.star) + } + if (this.options.ecmaVersion >= 8) { + node.async = !!isAsync + } + if (this.tok.type === tt.name) node.id = this.parseIdent() + else if (isStatement === true) node.id = this.dummyIdent() + this.inAsync = node.async + node.params = this.parseFunctionParams() + node.body = this.parseBlock() + this.inAsync = oldInAsync + return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") +} + +lp.parseExport = function() { + let node = this.startNode() + this.next() + if (this.eat(tt.star)) { + node.source = this.eatContextual("from") ? this.parseExprAtom() : this.dummyString() + return this.finishNode(node, "ExportAllDeclaration") + } + if (this.eat(tt._default)) { + // export default (function foo() {}) // This is FunctionExpression. + let isAsync + if (this.tok.type === tt._function || (isAsync = this.toks.isAsyncFunction())) { + let fNode = this.startNode() + this.next() + if (isAsync) this.next() + node.declaration = this.parseFunction(fNode, "nullableID", isAsync) + } else if (this.tok.type === tt._class) { + node.declaration = this.parseClass("nullableID") + } else { + node.declaration = this.parseMaybeAssign() + this.semicolon() + } + return this.finishNode(node, "ExportDefaultDeclaration") + } + if (this.tok.type.keyword || this.toks.isLet() || this.toks.isAsyncFunction()) { + node.declaration = this.parseStatement() + node.specifiers = [] + node.source = null + } else { + node.declaration = null + node.specifiers = this.parseExportSpecifierList() + node.source = this.eatContextual("from") ? this.parseExprAtom() : null + this.semicolon() + } + return this.finishNode(node, "ExportNamedDeclaration") +} + +lp.parseImport = function() { + let node = this.startNode() + this.next() + if (this.tok.type === tt.string) { + node.specifiers = [] + node.source = this.parseExprAtom() + node.kind = "" + } else { + let elt + if (this.tok.type === tt.name && this.tok.value !== "from") { + elt = this.startNode() + elt.local = this.parseIdent() + this.finishNode(elt, "ImportDefaultSpecifier") + this.eat(tt.comma) + } + node.specifiers = this.parseImportSpecifierList() + node.source = this.eatContextual("from") && this.tok.type == tt.string ? this.parseExprAtom() : this.dummyString() + if (elt) node.specifiers.unshift(elt) + } + this.semicolon() + return this.finishNode(node, "ImportDeclaration") +} + +lp.parseImportSpecifierList = function() { + let elts = [] + if (this.tok.type === tt.star) { + let elt = this.startNode() + this.next() + elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent() + elts.push(this.finishNode(elt, "ImportNamespaceSpecifier")) + } else { + let indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart + this.pushCx() + this.eat(tt.braceL) + if (this.curLineStart > continuedLine) continuedLine = this.curLineStart + while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { + let elt = this.startNode() + if (this.eat(tt.star)) { + elt.local = this.eatContextual("as") ? this.parseIdent() : this.dummyIdent() + this.finishNode(elt, "ImportNamespaceSpecifier") + } else { + if (this.isContextual("from")) break + elt.imported = this.parseIdent() + if (isDummy(elt.imported)) break + elt.local = this.eatContextual("as") ? this.parseIdent() : elt.imported + this.finishNode(elt, "ImportSpecifier") + } + elts.push(elt) + this.eat(tt.comma) + } + this.eat(tt.braceR) + this.popCx() + } + return elts +} + +lp.parseExportSpecifierList = function() { + let elts = [] + let indent = this.curIndent, line = this.curLineStart, continuedLine = this.nextLineStart + this.pushCx() + this.eat(tt.braceL) + if (this.curLineStart > continuedLine) continuedLine = this.curLineStart + while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { + if (this.isContextual("from")) break + let elt = this.startNode() + elt.local = this.parseIdent() + if (isDummy(elt.local)) break + elt.exported = this.eatContextual("as") ? this.parseIdent() : elt.local + this.finishNode(elt, "ExportSpecifier") + elts.push(elt) + this.eat(tt.comma) + } + this.eat(tt.braceR) + this.popCx() + return elts +} diff --git a/node_modules/acorn/src/loose/tokenize.js b/node_modules/acorn/src/loose/tokenize.js new file mode 100644 index 000000000..2d5130b63 --- /dev/null +++ b/node_modules/acorn/src/loose/tokenize.js @@ -0,0 +1,111 @@ +import {tokTypes as tt, Token, isNewLine, SourceLocation, getLineInfo, lineBreakG} from "../index" +import {LooseParser} from "./state" + +const lp = LooseParser.prototype + +function isSpace(ch) { + return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || isNewLine(ch) +} + +lp.next = function() { + this.last = this.tok + if (this.ahead.length) + this.tok = this.ahead.shift() + else + this.tok = this.readToken() + + if (this.tok.start >= this.nextLineStart) { + while (this.tok.start >= this.nextLineStart) { + this.curLineStart = this.nextLineStart + this.nextLineStart = this.lineEnd(this.curLineStart) + 1 + } + this.curIndent = this.indentationAfter(this.curLineStart) + } +} + +lp.readToken = function() { + for (;;) { + try { + this.toks.next() + if (this.toks.type === tt.dot && + this.input.substr(this.toks.end, 1) === "." && + this.options.ecmaVersion >= 6) { + this.toks.end++ + this.toks.type = tt.ellipsis + } + return new Token(this.toks) + } catch (e) { + if (!(e instanceof SyntaxError)) throw e + + // Try to skip some text, based on the error message, and then continue + let msg = e.message, pos = e.raisedAt, replace = true + if (/unterminated/i.test(msg)) { + pos = this.lineEnd(e.pos + 1) + if (/string/.test(msg)) { + replace = {start: e.pos, end: pos, type: tt.string, value: this.input.slice(e.pos + 1, pos)} + } else if (/regular expr/i.test(msg)) { + let re = this.input.slice(e.pos, pos) + try { re = new RegExp(re) } catch (e) { /* ignore compilation error due to new syntax */ } + replace = {start: e.pos, end: pos, type: tt.regexp, value: re} + } else if (/template/.test(msg)) { + replace = { + start: e.pos, + end: pos, + type: tt.template, + value: this.input.slice(e.pos, pos) + } + } else { + replace = false + } + } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number|expected number in radix/i.test(msg)) { + while (pos < this.input.length && !isSpace(this.input.charCodeAt(pos))) ++pos + } else if (/character escape|expected hexadecimal/i.test(msg)) { + while (pos < this.input.length) { + let ch = this.input.charCodeAt(pos++) + if (ch === 34 || ch === 39 || isNewLine(ch)) break + } + } else if (/unexpected character/i.test(msg)) { + pos++ + replace = false + } else if (/regular expression/i.test(msg)) { + replace = true + } else { + throw e + } + this.resetTo(pos) + if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: "✖"} + if (replace) { + if (this.options.locations) + replace.loc = new SourceLocation( + this.toks, + getLineInfo(this.input, replace.start), + getLineInfo(this.input, replace.end)) + return replace + } + } + } +} + +lp.resetTo = function(pos) { + this.toks.pos = pos + let ch = this.input.charAt(pos - 1) + this.toks.exprAllowed = !ch || /[[{(,;:?/*=+\-~!|&%^<>]/.test(ch) || + /[enwfd]/.test(ch) && + /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(this.input.slice(pos - 10, pos)) + + if (this.options.locations) { + this.toks.curLine = 1 + this.toks.lineStart = lineBreakG.lastIndex = 0 + let match + while ((match = lineBreakG.exec(this.input)) && match.index < pos) { + ++this.toks.curLine + this.toks.lineStart = match.index + match[0].length + } + } +} + +lp.lookAhead = function(n) { + while (n > this.ahead.length) + this.ahead.push(this.readToken()) + return this.ahead[n - 1] +} |