diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-08-14 05:01:11 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-08-14 05:02:09 +0200 |
commit | 363723fc84f7b8477592e0105aeb331ec9a017af (patch) | |
tree | 29f92724f34131bac64d6a318dd7e30612e631c7 /node_modules/acorn/src/statement.js | |
parent | 5634e77ad96bfe1818f6b6ee70b7379652e5487f (diff) |
node_modules
Diffstat (limited to 'node_modules/acorn/src/statement.js')
-rw-r--r-- | node_modules/acorn/src/statement.js | 765 |
1 files changed, 0 insertions, 765 deletions
diff --git a/node_modules/acorn/src/statement.js b/node_modules/acorn/src/statement.js deleted file mode 100644 index eb2f18e8b..000000000 --- a/node_modules/acorn/src/statement.js +++ /dev/null @@ -1,765 +0,0 @@ -import {types as tt} from "./tokentype" -import {Parser} from "./state" -import {lineBreak, skipWhiteSpace} from "./whitespace" -import {isIdentifierStart, isIdentifierChar} from "./identifier" -import {has} from "./util" -import {DestructuringErrors} from "./parseutil" - -const pp = Parser.prototype - -// ### Statement parsing - -// Parse a program. Initializes the parser, reads any number of -// statements, and wraps them in a Program node. Optionally takes a -// `program` argument. If present, the statements will be appended -// to its body instead of creating a new node. - -pp.parseTopLevel = function(node) { - let exports = {} - if (!node.body) node.body = [] - while (this.type !== tt.eof) { - let stmt = this.parseStatement(true, true, exports) - node.body.push(stmt) - } - this.next() - if (this.options.ecmaVersion >= 6) { - node.sourceType = this.options.sourceType - } - return this.finishNode(node, "Program") -} - -const loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"} - -pp.isLet = function() { - if (this.type !== tt.name || this.options.ecmaVersion < 6 || this.value != "let") return false - skipWhiteSpace.lastIndex = this.pos - let skip = skipWhiteSpace.exec(this.input) - let next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next) - if (nextCh === 91 || nextCh == 123) return true // '{' and '[' - if (isIdentifierStart(nextCh, true)) { - let pos = next + 1 - while (isIdentifierChar(this.input.charCodeAt(pos), true)) ++pos - let ident = this.input.slice(next, pos) - if (!this.isKeyword(ident)) return true - } - return false -} - -// check 'async [no LineTerminator here] function' -// - 'async /*foo*/ function' is OK. -// - 'async /*\n*/ function' is invalid. -pp.isAsyncFunction = function() { - if (this.type !== tt.name || this.options.ecmaVersion < 8 || this.value != "async") - return false - - skipWhiteSpace.lastIndex = this.pos - let skip = skipWhiteSpace.exec(this.input) - let next = this.pos + skip[0].length - return !lineBreak.test(this.input.slice(this.pos, next)) && - this.input.slice(next, next + 8) === "function" && - (next + 8 == this.input.length || !isIdentifierChar(this.input.charAt(next + 8))) -} - -// Parse a single statement. -// -// If expecting a statement and finding a slash operator, parse a -// regular expression literal. This is to handle cases like -// `if (foo) /blah/.exec(foo)`, where looking at the previous token -// does not help. - -pp.parseStatement = function(declaration, topLevel, exports) { - let starttype = this.type, node = this.startNode(), kind - - if (this.isLet()) { - starttype = tt._var - kind = "let" - } - - // Most types of statements are recognized by the keyword they - // start with. Many are trivial to parse, some require a bit of - // complexity. - - switch (starttype) { - case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword) - case tt._debugger: return this.parseDebuggerStatement(node) - case tt._do: return this.parseDoStatement(node) - case tt._for: return this.parseForStatement(node) - case tt._function: - if (!declaration && this.options.ecmaVersion >= 6) this.unexpected() - return this.parseFunctionStatement(node, false) - case tt._class: - if (!declaration) this.unexpected() - return this.parseClass(node, true) - case tt._if: return this.parseIfStatement(node) - case tt._return: return this.parseReturnStatement(node) - case tt._switch: return this.parseSwitchStatement(node) - case tt._throw: return this.parseThrowStatement(node) - case tt._try: return this.parseTryStatement(node) - case tt._const: case tt._var: - kind = kind || this.value - if (!declaration && kind != "var") this.unexpected() - return this.parseVarStatement(node, kind) - case tt._while: return this.parseWhileStatement(node) - case tt._with: return this.parseWithStatement(node) - case tt.braceL: return this.parseBlock() - case tt.semi: return this.parseEmptyStatement(node) - case tt._export: - case tt._import: - if (!this.options.allowImportExportEverywhere) { - if (!topLevel) - this.raise(this.start, "'import' and 'export' may only appear at the top level") - if (!this.inModule) - this.raise(this.start, "'import' and 'export' may appear only with 'sourceType: module'") - } - return starttype === tt._import ? this.parseImport(node) : this.parseExport(node, exports) - - // If the statement does not start with a statement keyword or a - // brace, it's an ExpressionStatement or LabeledStatement. We - // simply start parsing an expression, and afterwards, if the - // next token is a colon and the expression was a simple - // Identifier node, we switch to interpreting it as a label. - default: - if (this.isAsyncFunction() && declaration) { - this.next() - return this.parseFunctionStatement(node, true) - } - - let maybeName = this.value, expr = this.parseExpression() - if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) - return this.parseLabeledStatement(node, maybeName, expr) - else return this.parseExpressionStatement(node, expr) - } -} - -pp.parseBreakContinueStatement = function(node, keyword) { - let isBreak = keyword == "break" - this.next() - if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null - else if (this.type !== tt.name) this.unexpected() - else { - node.label = this.parseIdent() - this.semicolon() - } - - // Verify that there is an actual destination to break or - // continue to. - let i = 0 - for (; i < this.labels.length; ++i) { - let lab = this.labels[i] - if (node.label == null || lab.name === node.label.name) { - if (lab.kind != null && (isBreak || lab.kind === "loop")) break - if (node.label && isBreak) break - } - } - if (i === this.labels.length) this.raise(node.start, "Unsyntactic " + keyword) - return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement") -} - -pp.parseDebuggerStatement = function(node) { - this.next() - this.semicolon() - return this.finishNode(node, "DebuggerStatement") -} - -pp.parseDoStatement = function(node) { - this.next() - this.labels.push(loopLabel) - node.body = this.parseStatement(false) - this.labels.pop() - this.expect(tt._while) - node.test = this.parseParenExpression() - if (this.options.ecmaVersion >= 6) - this.eat(tt.semi) - else - this.semicolon() - return this.finishNode(node, "DoWhileStatement") -} - -// Disambiguating between a `for` and a `for`/`in` or `for`/`of` -// loop is non-trivial. Basically, we have to parse the init `var` -// statement or expression, disallowing the `in` operator (see -// the second parameter to `parseExpression`), and then check -// whether the next token is `in` or `of`. When there is no init -// part (semicolon immediately after the opening parenthesis), it -// is a regular `for` loop. - -pp.parseForStatement = function(node) { - this.next() - this.labels.push(loopLabel) - this.enterLexicalScope() - this.expect(tt.parenL) - if (this.type === tt.semi) return this.parseFor(node, null) - let isLet = this.isLet() - if (this.type === tt._var || this.type === tt._const || isLet) { - let init = this.startNode(), kind = isLet ? "let" : this.value - this.next() - this.parseVar(init, true, kind) - this.finishNode(init, "VariableDeclaration") - if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) && init.declarations.length === 1 && - !(kind !== "var" && init.declarations[0].init)) - return this.parseForIn(node, init) - return this.parseFor(node, init) - } - let refDestructuringErrors = new DestructuringErrors - let init = this.parseExpression(true, refDestructuringErrors) - if (this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of"))) { - this.toAssignable(init) - this.checkLVal(init) - this.checkPatternErrors(refDestructuringErrors, true) - return this.parseForIn(node, init) - } else { - this.checkExpressionErrors(refDestructuringErrors, true) - } - return this.parseFor(node, init) -} - -pp.parseFunctionStatement = function(node, isAsync) { - this.next() - return this.parseFunction(node, true, false, isAsync) -} - -pp.isFunction = function() { - return this.type === tt._function || this.isAsyncFunction() -} - -pp.parseIfStatement = function(node) { - this.next() - node.test = this.parseParenExpression() - // allow function declarations in branches, but only in non-strict mode - node.consequent = this.parseStatement(!this.strict && this.isFunction()) - node.alternate = this.eat(tt._else) ? this.parseStatement(!this.strict && this.isFunction()) : null - return this.finishNode(node, "IfStatement") -} - -pp.parseReturnStatement = function(node) { - if (!this.inFunction && !this.options.allowReturnOutsideFunction) - this.raise(this.start, "'return' outside of function") - this.next() - - // In `return` (and `break`/`continue`), the keywords with - // optional arguments, we eagerly look for a semicolon or the - // possibility to insert one. - - if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null - else { node.argument = this.parseExpression(); this.semicolon() } - return this.finishNode(node, "ReturnStatement") -} - -pp.parseSwitchStatement = function(node) { - this.next() - node.discriminant = this.parseParenExpression() - node.cases = [] - this.expect(tt.braceL) - this.labels.push(switchLabel) - this.enterLexicalScope() - - // Statements under must be grouped (by label) in SwitchCase - // nodes. `cur` is used to keep the node that we are currently - // adding statements to. - - let cur - for (let sawDefault = false; this.type != tt.braceR;) { - if (this.type === tt._case || this.type === tt._default) { - let isCase = this.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 { - if (sawDefault) this.raiseRecoverable(this.lastTokStart, "Multiple default clauses") - sawDefault = true - cur.test = null - } - this.expect(tt.colon) - } else { - if (!cur) this.unexpected() - cur.consequent.push(this.parseStatement(true)) - } - } - this.exitLexicalScope() - if (cur) this.finishNode(cur, "SwitchCase") - this.next() // Closing brace - this.labels.pop() - return this.finishNode(node, "SwitchStatement") -} - -pp.parseThrowStatement = function(node) { - this.next() - if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) - this.raise(this.lastTokEnd, "Illegal newline after throw") - node.argument = this.parseExpression() - this.semicolon() - return this.finishNode(node, "ThrowStatement") -} - -// Reused empty array added for node fields that are always empty. - -const empty = [] - -pp.parseTryStatement = function(node) { - this.next() - node.block = this.parseBlock() - node.handler = null - if (this.type === tt._catch) { - let clause = this.startNode() - this.next() - this.expect(tt.parenL) - clause.param = this.parseBindingAtom() - this.enterLexicalScope() - this.checkLVal(clause.param, "let") - this.expect(tt.parenR) - clause.body = this.parseBlock(false) - this.exitLexicalScope() - node.handler = this.finishNode(clause, "CatchClause") - } - node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null - if (!node.handler && !node.finalizer) - this.raise(node.start, "Missing catch or finally clause") - return this.finishNode(node, "TryStatement") -} - -pp.parseVarStatement = function(node, kind) { - this.next() - this.parseVar(node, false, kind) - this.semicolon() - return this.finishNode(node, "VariableDeclaration") -} - -pp.parseWhileStatement = function(node) { - this.next() - node.test = this.parseParenExpression() - this.labels.push(loopLabel) - node.body = this.parseStatement(false) - this.labels.pop() - return this.finishNode(node, "WhileStatement") -} - -pp.parseWithStatement = function(node) { - if (this.strict) this.raise(this.start, "'with' in strict mode") - this.next() - node.object = this.parseParenExpression() - node.body = this.parseStatement(false) - return this.finishNode(node, "WithStatement") -} - -pp.parseEmptyStatement = function(node) { - this.next() - return this.finishNode(node, "EmptyStatement") -} - -pp.parseLabeledStatement = function(node, maybeName, expr) { - for (let i = 0; i < this.labels.length; ++i) - if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared") - let kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null - for (let i = this.labels.length - 1; i >= 0; i--) { - let label = this.labels[i] - if (label.statementStart == node.start) { - label.statementStart = this.start - label.kind = kind - } else break - } - this.labels.push({name: maybeName, kind: kind, statementStart: this.start}) - node.body = this.parseStatement(true) - if (node.body.type == "ClassDeclaration" || - node.body.type == "VariableDeclaration" && node.body.kind != "var" || - node.body.type == "FunctionDeclaration" && (this.strict || node.body.generator)) - this.raiseRecoverable(node.body.start, "Invalid labeled declaration") - this.labels.pop() - node.label = expr - return this.finishNode(node, "LabeledStatement") -} - -pp.parseExpressionStatement = function(node, expr) { - node.expression = expr - this.semicolon() - return this.finishNode(node, "ExpressionStatement") -} - -// Parse a semicolon-enclosed block of statements, handling `"use -// strict"` declarations when `allowStrict` is true (used for -// function bodies). - -pp.parseBlock = function(createNewLexicalScope = true) { - let node = this.startNode() - node.body = [] - this.expect(tt.braceL) - if (createNewLexicalScope) { - this.enterLexicalScope() - } - while (!this.eat(tt.braceR)) { - let stmt = this.parseStatement(true) - node.body.push(stmt) - } - if (createNewLexicalScope) { - this.exitLexicalScope() - } - return this.finishNode(node, "BlockStatement") -} - -// Parse a regular `for` loop. The disambiguation code in -// `parseStatement` will already have parsed the init statement or -// expression. - -pp.parseFor = function(node, init) { - node.init = init - this.expect(tt.semi) - node.test = this.type === tt.semi ? null : this.parseExpression() - this.expect(tt.semi) - node.update = this.type === tt.parenR ? null : this.parseExpression() - this.expect(tt.parenR) - this.exitLexicalScope() - node.body = this.parseStatement(false) - this.labels.pop() - return this.finishNode(node, "ForStatement") -} - -// Parse a `for`/`in` and `for`/`of` loop, which are almost -// same from parser's perspective. - -pp.parseForIn = function(node, init) { - let type = this.type === tt._in ? "ForInStatement" : "ForOfStatement" - this.next() - node.left = init - node.right = this.parseExpression() - this.expect(tt.parenR) - this.exitLexicalScope() - node.body = this.parseStatement(false) - this.labels.pop() - return this.finishNode(node, type) -} - -// Parse a list of variable declarations. - -pp.parseVar = function(node, isFor, kind) { - node.declarations = [] - node.kind = kind - for (;;) { - let decl = this.startNode() - this.parseVarId(decl, kind) - if (this.eat(tt.eq)) { - decl.init = this.parseMaybeAssign(isFor) - } else if (kind === "const" && !(this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual("of")))) { - this.unexpected() - } else if (decl.id.type != "Identifier" && !(isFor && (this.type === tt._in || this.isContextual("of")))) { - this.raise(this.lastTokEnd, "Complex binding patterns require an initialization value") - } else { - decl.init = null - } - node.declarations.push(this.finishNode(decl, "VariableDeclarator")) - if (!this.eat(tt.comma)) break - } - return node -} - -pp.parseVarId = function(decl, kind) { - decl.id = this.parseBindingAtom(kind) - this.checkLVal(decl.id, kind, false) -} - -// Parse a function declaration or literal (depending on the -// `isStatement` parameter). - -pp.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) { - this.initFunction(node) - if (this.options.ecmaVersion >= 6 && !isAsync) - node.generator = this.eat(tt.star) - if (this.options.ecmaVersion >= 8) - node.async = !!isAsync - - if (isStatement) { - node.id = isStatement === "nullableID" && this.type != tt.name ? null : this.parseIdent() - if (node.id) { - this.checkLVal(node.id, "var") - } - } - - let oldInGen = this.inGenerator, oldInAsync = this.inAsync, - oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, oldInFunc = this.inFunction - this.inGenerator = node.generator - this.inAsync = node.async - this.yieldPos = 0 - this.awaitPos = 0 - this.inFunction = true - this.enterFunctionScope() - - if (!isStatement) - node.id = this.type == tt.name ? this.parseIdent() : null - - this.parseFunctionParams(node) - this.parseFunctionBody(node, allowExpressionBody) - - this.inGenerator = oldInGen - this.inAsync = oldInAsync - this.yieldPos = oldYieldPos - this.awaitPos = oldAwaitPos - this.inFunction = oldInFunc - return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression") -} - -pp.parseFunctionParams = function(node) { - this.expect(tt.parenL) - node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8, true) - this.checkYieldAwaitInDefaultParams() -} - -// Parse a class declaration or literal (depending on the -// `isStatement` parameter). - -pp.parseClass = function(node, isStatement) { - this.next() - - this.parseClassId(node, isStatement) - this.parseClassSuper(node) - let classBody = this.startNode() - let hadConstructor = false - classBody.body = [] - this.expect(tt.braceL) - while (!this.eat(tt.braceR)) { - if (this.eat(tt.semi)) continue - let method = this.startNode() - let isGenerator = this.eat(tt.star) - let isAsync = false - let isMaybeStatic = this.type === tt.name && this.value === "static" - this.parsePropertyName(method) - method.static = isMaybeStatic && this.type !== tt.parenL - if (method.static) { - if (isGenerator) this.unexpected() - isGenerator = this.eat(tt.star) - this.parsePropertyName(method) - } - if (this.options.ecmaVersion >= 8 && !isGenerator && !method.computed && - method.key.type === "Identifier" && method.key.name === "async" && this.type !== tt.parenL && - !this.canInsertSemicolon()) { - isAsync = true - this.parsePropertyName(method) - } - method.kind = "method" - let isGetSet = false - if (!method.computed) { - let {key} = method - if (!isGenerator && !isAsync && key.type === "Identifier" && this.type !== tt.parenL && (key.name === "get" || key.name === "set")) { - isGetSet = true - method.kind = key.name - key = this.parsePropertyName(method) - } - if (!method.static && (key.type === "Identifier" && key.name === "constructor" || - key.type === "Literal" && key.value === "constructor")) { - if (hadConstructor) this.raise(key.start, "Duplicate constructor in the same class") - if (isGetSet) this.raise(key.start, "Constructor can't have get/set modifier") - if (isGenerator) this.raise(key.start, "Constructor can't be a generator") - if (isAsync) this.raise(key.start, "Constructor can't be an async method") - method.kind = "constructor" - hadConstructor = true - } - } - this.parseClassMethod(classBody, method, isGenerator, isAsync) - if (isGetSet) { - let paramCount = method.kind === "get" ? 0 : 1 - if (method.value.params.length !== paramCount) { - let start = method.value.start - if (method.kind === "get") - this.raiseRecoverable(start, "getter should have no params") - else - this.raiseRecoverable(start, "setter should have exactly one param") - } else { - if (method.kind === "set" && method.value.params[0].type === "RestElement") - this.raiseRecoverable(method.value.params[0].start, "Setter cannot use rest params") - } - } - } - node.body = this.finishNode(classBody, "ClassBody") - return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") -} - -pp.parseClassMethod = function(classBody, method, isGenerator, isAsync) { - method.value = this.parseMethod(isGenerator, isAsync) - classBody.body.push(this.finishNode(method, "MethodDefinition")) -} - -pp.parseClassId = function(node, isStatement) { - node.id = this.type === tt.name ? this.parseIdent() : isStatement === true ? this.unexpected() : null -} - -pp.parseClassSuper = function(node) { - node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null -} - -// Parses module export declaration. - -pp.parseExport = function(node, exports) { - this.next() - // export * from '...' - if (this.eat(tt.star)) { - this.expectContextual("from") - node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() - this.semicolon() - return this.finishNode(node, "ExportAllDeclaration") - } - if (this.eat(tt._default)) { // export default ... - this.checkExport(exports, "default", this.lastTokStart) - let isAsync - if (this.type === tt._function || (isAsync = this.isAsyncFunction())) { - let fNode = this.startNode() - this.next() - if (isAsync) this.next() - node.declaration = this.parseFunction(fNode, "nullableID", false, isAsync) - } else if (this.type === tt._class) { - let cNode = this.startNode() - node.declaration = this.parseClass(cNode, "nullableID") - } else { - node.declaration = this.parseMaybeAssign() - this.semicolon() - } - return this.finishNode(node, "ExportDefaultDeclaration") - } - // export var|const|let|function|class ... - if (this.shouldParseExportStatement()) { - node.declaration = this.parseStatement(true) - if (node.declaration.type === "VariableDeclaration") - this.checkVariableExport(exports, node.declaration.declarations) - else - this.checkExport(exports, node.declaration.id.name, node.declaration.id.start) - node.specifiers = [] - node.source = null - } else { // export { x, y as z } [from '...'] - node.declaration = null - node.specifiers = this.parseExportSpecifiers(exports) - if (this.eatContextual("from")) { - node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() - } else { - // check for keywords used as local names - for (let i = 0; i < node.specifiers.length; i++) { - if (this.keywords.test(node.specifiers[i].local.name) || this.reservedWords.test(node.specifiers[i].local.name)) { - this.unexpected(node.specifiers[i].local.start) - } - } - - node.source = null - } - this.semicolon() - } - return this.finishNode(node, "ExportNamedDeclaration") -} - -pp.checkExport = function(exports, name, pos) { - if (!exports) return - if (has(exports, name)) - this.raiseRecoverable(pos, "Duplicate export '" + name + "'") - exports[name] = true -} - -pp.checkPatternExport = function(exports, pat) { - let type = pat.type - if (type == "Identifier") - this.checkExport(exports, pat.name, pat.start) - else if (type == "ObjectPattern") - for (let i = 0; i < pat.properties.length; ++i) - this.checkPatternExport(exports, pat.properties[i].value) - else if (type == "ArrayPattern") - for (let i = 0; i < pat.elements.length; ++i) { - let elt = pat.elements[i] - if (elt) this.checkPatternExport(exports, elt) - } - else if (type == "AssignmentPattern") - this.checkPatternExport(exports, pat.left) - else if (type == "ParenthesizedExpression") - this.checkPatternExport(exports, pat.expression) -} - -pp.checkVariableExport = function(exports, decls) { - if (!exports) return - for (let i = 0; i < decls.length; i++) - this.checkPatternExport(exports, decls[i].id) -} - -pp.shouldParseExportStatement = function() { - return this.type.keyword === "var" || - this.type.keyword === "const" || - this.type.keyword === "class" || - this.type.keyword === "function" || - this.isLet() || - this.isAsyncFunction() -} - -// Parses a comma-separated list of module exports. - -pp.parseExportSpecifiers = function(exports) { - let nodes = [], first = true - // export { x, y as z } [from '...'] - this.expect(tt.braceL) - while (!this.eat(tt.braceR)) { - if (!first) { - this.expect(tt.comma) - if (this.afterTrailingComma(tt.braceR)) break - } else first = false - - let node = this.startNode() - node.local = this.parseIdent(true) - node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local - this.checkExport(exports, node.exported.name, node.exported.start) - nodes.push(this.finishNode(node, "ExportSpecifier")) - } - return nodes -} - -// Parses import declaration. - -pp.parseImport = function(node) { - this.next() - // import '...' - if (this.type === tt.string) { - node.specifiers = empty - node.source = this.parseExprAtom() - } else { - node.specifiers = this.parseImportSpecifiers() - this.expectContextual("from") - node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected() - } - this.semicolon() - return this.finishNode(node, "ImportDeclaration") -} - -// Parses a comma-separated list of module imports. - -pp.parseImportSpecifiers = function() { - let nodes = [], first = true - if (this.type === tt.name) { - // import defaultObj, { x, y as z } from '...' - let node = this.startNode() - node.local = this.parseIdent() - this.checkLVal(node.local, "let") - nodes.push(this.finishNode(node, "ImportDefaultSpecifier")) - if (!this.eat(tt.comma)) return nodes - } - if (this.type === tt.star) { - let node = this.startNode() - this.next() - this.expectContextual("as") - node.local = this.parseIdent() - this.checkLVal(node.local, "let") - nodes.push(this.finishNode(node, "ImportNamespaceSpecifier")) - return nodes - } - this.expect(tt.braceL) - while (!this.eat(tt.braceR)) { - if (!first) { - this.expect(tt.comma) - if (this.afterTrailingComma(tt.braceR)) break - } else first = false - - let node = this.startNode() - node.imported = this.parseIdent(true) - if (this.eatContextual("as")) { - node.local = this.parseIdent() - } else { - node.local = node.imported - if (this.isKeyword(node.local.name)) this.unexpected(node.local.start) - if (this.reservedWordsStrict.test(node.local.name)) this.raiseRecoverable(node.local.start, "The keyword '" + node.local.name + "' is reserved") - } - this.checkLVal(node.local, "let") - nodes.push(this.finishNode(node, "ImportSpecifier")) - } - return nodes -} |