Doodle3D-API/jspm_packages/npm/babel-core@5.6.20/lib/acorn/src/statement.js

779 lines
28 KiB
JavaScript

/* */
"format cjs";
"use strict";
var _babelToolsProtectJs2 = require("./../../babel/tools/protect.js");
var _babelToolsProtectJs3 = _interopRequireDefault(_babelToolsProtectJs2);
var _tokentype = require("./tokentype");
var _state = require("./state");
var _whitespace = require("./whitespace");
_babelToolsProtectJs3["default"](module);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var pp = _state.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) {
var first = true;
if (!node.body) node.body = [];
while (this.type !== _tokentype.types.eof) {
var stmt = this.parseStatement(true, true);
node.body.push(stmt);
if (first && this.isUseStrict(stmt)) this.setStrict(true);
first = false;
}
this.next();
if (this.options.ecmaVersion >= 6) {
node.sourceType = this.options.sourceType;
}
return this.finishNode(node, "Program");
};
var loopLabel = { kind: "loop" },
switchLabel = { kind: "switch" };
// 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) {
if (this.type === _tokentype.types.at) {
this.parseDecorators(true);
}
var starttype = this.type,
node = this.startNode();
// 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 _tokentype.types._break:case _tokentype.types._continue:
return this.parseBreakContinueStatement(node, starttype.keyword);
case _tokentype.types._debugger:
return this.parseDebuggerStatement(node);
case _tokentype.types._do:
return this.parseDoStatement(node);
case _tokentype.types._for:
return this.parseForStatement(node);
case _tokentype.types._function:
if (!declaration && this.options.ecmaVersion >= 6) this.unexpected();
return this.parseFunctionStatement(node);
case _tokentype.types._class:
if (!declaration) this.unexpected();
this.takeDecorators(node);
return this.parseClass(node, true);
case _tokentype.types._if:
return this.parseIfStatement(node);
case _tokentype.types._return:
return this.parseReturnStatement(node);
case _tokentype.types._switch:
return this.parseSwitchStatement(node);
case _tokentype.types._throw:
return this.parseThrowStatement(node);
case _tokentype.types._try:
return this.parseTryStatement(node);
case _tokentype.types._let:case _tokentype.types._const:
if (!declaration) this.unexpected(); // NOTE: falls through to _var
case _tokentype.types._var:
return this.parseVarStatement(node, starttype);
case _tokentype.types._while:
return this.parseWhileStatement(node);
case _tokentype.types._with:
return this.parseWithStatement(node);
case _tokentype.types.braceL:
return this.parseBlock();
case _tokentype.types.semi:
return this.parseEmptyStatement(node);
case _tokentype.types._export:
case _tokentype.types._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 === _tokentype.types._import ? this.parseImport(node) : this.parseExport(node);
case _tokentype.types.name:
if (this.options.features["es7.asyncFunctions"] && this.value === "async") {
var lookahead = this.lookahead();
if (lookahead.type === _tokentype.types._function && !this.canInsertSemicolon.call(lookahead)) {
this.next();
this.expect(_tokentype.types._function);
return this.parseFunction(node, true, false, true);
}
}
// 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:
var maybeName = this.value,
expr = this.parseExpression();
if (starttype === _tokentype.types.name && expr.type === "Identifier" && this.eat(_tokentype.types.colon)) return this.parseLabeledStatement(node, maybeName, expr);else return this.parseExpressionStatement(node, expr);
}
};
pp.takeDecorators = function (node) {
if (this.decorators.length) {
node.decorators = this.decorators;
this.decorators = [];
}
};
pp.parseDecorators = function (allowExport) {
while (this.type === _tokentype.types.at) {
this.decorators.push(this.parseDecorator());
}
if (allowExport && this.type === _tokentype.types._export) {
return;
}
if (this.type !== _tokentype.types._class) {
this.raise(this.start, "Leading decorators must be attached to a class declaration");
}
};
pp.parseDecorator = function (allowExport) {
if (!this.options.features["es7.decorators"]) {
this.unexpected();
}
var node = this.startNode();
this.next();
node.expression = this.parseMaybeAssign();
return this.finishNode(node, "Decorator");
};
pp.parseBreakContinueStatement = function (node, keyword) {
var isBreak = keyword == "break";
this.next();
if (this.eat(_tokentype.types.semi) || this.insertSemicolon()) node.label = null;else if (this.type !== _tokentype.types.name) this.unexpected();else {
node.label = this.parseIdent();
this.semicolon();
}
// Verify that there is an actual destination to break or
// continue to.
for (var i = 0; i < this.labels.length; ++i) {
var 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) {
var start = this.markPosition();
this.next();
this.labels.push(loopLabel);
node.body = this.parseStatement(false);
this.labels.pop();
this.expect(_tokentype.types._while);
node.test = this.parseParenExpression();
if (this.options.ecmaVersion >= 6) this.eat(_tokentype.types.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.expect(_tokentype.types.parenL);
if (this.type === _tokentype.types.semi) return this.parseFor(node, null);
if (this.type === _tokentype.types._var || this.type === _tokentype.types._let || this.type === _tokentype.types._const) {
var _init = this.startNode(),
varKind = this.type;
this.next();
this.parseVar(_init, true, varKind);
this.finishNode(_init, "VariableDeclaration");
if ((this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of")) && _init.declarations.length === 1 && !(varKind !== _tokentype.types._var && _init.declarations[0].init)) return this.parseForIn(node, _init);
return this.parseFor(node, _init);
}
var refShorthandDefaultPos = { start: 0 };
var init = this.parseExpression(true, refShorthandDefaultPos);
if (this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of")) {
this.toAssignable(init);
this.checkLVal(init);
return this.parseForIn(node, init);
} else if (refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start);
}
return this.parseFor(node, init);
};
pp.parseFunctionStatement = function (node) {
this.next();
return this.parseFunction(node, true);
};
pp.parseIfStatement = function (node) {
this.next();
node.test = this.parseParenExpression();
node.consequent = this.parseStatement(false);
node.alternate = this.eat(_tokentype.types._else) ? this.parseStatement(false) : 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(_tokentype.types.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(_tokentype.types.braceL);
this.labels.push(switchLabel);
// Statements under must be grouped (by label) in SwitchCase
// nodes. `cur` is used to keep the node that we are currently
// adding statements to.
for (var cur, sawDefault; this.type != _tokentype.types.braceR;) {
if (this.type === _tokentype.types._case || this.type === _tokentype.types._default) {
var isCase = this.type === _tokentype.types._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.raise(this.lastTokStart, "Multiple default clauses");
sawDefault = true;
cur.test = null;
}
this.expect(_tokentype.types.colon);
} else {
if (!cur) this.unexpected();
cur.consequent.push(this.parseStatement(true));
}
}
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 (_whitespace.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.
var empty = [];
pp.parseTryStatement = function (node) {
this.next();
node.block = this.parseBlock();
node.handler = null;
if (this.type === _tokentype.types._catch) {
var clause = this.startNode();
this.next();
this.expect(_tokentype.types.parenL);
clause.param = this.parseBindingAtom();
this.checkLVal(clause.param, true);
this.expect(_tokentype.types.parenR);
clause.guard = null;
clause.body = this.parseBlock();
node.handler = this.finishNode(clause, "CatchClause");
}
node.guardedHandlers = empty;
node.finalizer = this.eat(_tokentype.types._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 (var i = 0; i < this.labels.length; ++i) {
if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared");
}var kind = this.type.isLoop ? "loop" : this.type === _tokentype.types._switch ? "switch" : null;
for (var i = this.labels.length - 1; i >= 0; i--) {
var 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);
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 (allowStrict) {
var node = this.startNode(),
first = true,
oldStrict = undefined;
node.body = [];
this.expect(_tokentype.types.braceL);
while (!this.eat(_tokentype.types.braceR)) {
var stmt = this.parseStatement(true);
node.body.push(stmt);
if (first && allowStrict && this.isUseStrict(stmt)) {
oldStrict = this.strict;
this.setStrict(this.strict = true);
}
first = false;
}
if (oldStrict === false) this.setStrict(false);
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(_tokentype.types.semi);
node.test = this.type === _tokentype.types.semi ? null : this.parseExpression();
this.expect(_tokentype.types.semi);
node.update = this.type === _tokentype.types.parenR ? null : this.parseExpression();
this.expect(_tokentype.types.parenR);
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) {
var type = this.type === _tokentype.types._in ? "ForInStatement" : "ForOfStatement";
this.next();
node.left = init;
node.right = this.parseExpression();
this.expect(_tokentype.types.parenR);
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.keyword;
for (;;) {
var decl = this.startNode();
this.parseVarHead(decl);
if (this.eat(_tokentype.types.eq)) {
decl.init = this.parseMaybeAssign(isFor);
} else if (kind === _tokentype.types._const && !(this.type === _tokentype.types._in || this.options.ecmaVersion >= 6 && this.isContextual("of"))) {
this.unexpected();
} else if (decl.id.type != "Identifier" && !(isFor && (this.type === _tokentype.types._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(_tokentype.types.comma)) break;
}
return node;
};
pp.parseVarHead = function (decl) {
decl.id = this.parseBindingAtom();
this.checkLVal(decl.id, true);
};
// Parse a function declaration or literal (depending on the
// `isStatement` parameter).
pp.parseFunction = function (node, isStatement, allowExpressionBody, isAsync) {
this.initFunction(node, isAsync);
if (this.options.ecmaVersion >= 6) node.generator = this.eat(_tokentype.types.star);
if (isStatement || this.type === _tokentype.types.name) node.id = this.parseIdent();
this.parseFunctionParams(node);
this.parseFunctionBody(node, allowExpressionBody);
return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
};
pp.parseFunctionParams = function (node) {
this.expect(_tokentype.types.parenL);
node.params = this.parseBindingList(_tokentype.types.parenR, false, this.options.features["es7.trailingFunctionCommas"]);
};
// 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);
var classBody = this.startNode();
var hadConstructor = false;
classBody.body = [];
this.expect(_tokentype.types.braceL);
var decorators = [];
while (!this.eat(_tokentype.types.braceR)) {
if (this.eat(_tokentype.types.semi)) continue;
if (this.type === _tokentype.types.at) {
decorators.push(this.parseDecorator());
continue;
}
var method = this.startNode();
if (decorators.length) {
method.decorators = decorators;
decorators = [];
}
var isMaybeStatic = this.type === _tokentype.types.name && this.value === "static";
var isGenerator = this.eat(_tokentype.types.star),
isAsync = false;
this.parsePropertyName(method);
method["static"] = isMaybeStatic && this.type !== _tokentype.types.parenL;
if (method["static"]) {
if (isGenerator) this.unexpected();
isGenerator = this.eat(_tokentype.types.star);
this.parsePropertyName(method);
}
if (!isGenerator && method.key.type === "Identifier" && !method.computed && this.isClassProperty()) {
classBody.body.push(this.parseClassProperty(method));
continue;
}
if (this.options.features["es7.asyncFunctions"] && this.type !== _tokentype.types.parenL && !method.computed && method.key.type === "Identifier" && method.key.name === "async") {
isAsync = true;
this.parsePropertyName(method);
}
var isGetSet = false;
method.kind = "method";
if (!method.computed) {
var key = method.key;
if (!isAsync && !isGenerator && key.type === "Identifier" && this.type !== _tokentype.types.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 function");
method.kind = "constructor";
hadConstructor = true;
}
}
if (method.kind === "constructor" && method.decorators) {
this.raise(method.start, "You can't attach decorators to a class constructor");
}
this.parseClassMethod(classBody, method, isGenerator, isAsync);
if (isGetSet) {
var paramCount = method.kind === "get" ? 0 : 1;
if (method.value.params.length !== paramCount) {
var start = method.value.start;
if (method.kind === "get") this.raise(start, "getter should have no params");else this.raise(start, "setter should have exactly one param");
}
}
}
if (decorators.length) {
this.raise(this.start, "You have trailing decorators with no method");
}
node.body = this.finishNode(classBody, "ClassBody");
return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
};
pp.isClassProperty = function () {
return this.type === _tokentype.types.eq || (this.type === _tokentype.types.semi || this.canInsertSemicolon());
};
pp.parseClassProperty = function (node) {
if (this.type === _tokentype.types.eq) {
if (!this.options.features["es7.classProperties"]) this.unexpected();
this.next();
node.value = this.parseMaybeAssign();
} else {
node.value = null;
}
this.semicolon();
return this.finishNode(node, "ClassProperty");
};
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 === _tokentype.types.name ? this.parseIdent() : isStatement ? this.unexpected() : null;
};
pp.parseClassSuper = function (node) {
node.superClass = this.eat(_tokentype.types._extends) ? this.parseExprSubscripts() : null;
};
// Parses module export declaration.
pp.parseExport = function (node) {
this.next();
// export * from '...'
if (this.type === _tokentype.types.star) {
var specifier = this.startNode();
this.next();
if (this.options.features["es7.exportExtensions"] && this.eatContextual("as")) {
specifier.exported = this.parseIdent();
node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")];
this.parseExportSpecifiersMaybe(node);
this.parseExportFrom(node);
} else {
this.parseExportFrom(node);
return this.finishNode(node, "ExportAllDeclaration");
}
} else if (this.options.features["es7.exportExtensions"] && this.isExportDefaultSpecifier()) {
var specifier = this.startNode();
specifier.exported = this.parseIdent(true);
node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
if (this.type === _tokentype.types.comma && this.lookahead().type === _tokentype.types.star) {
this.expect(_tokentype.types.comma);
var _specifier = this.startNode();
this.expect(_tokentype.types.star);
this.expectContextual("as");
_specifier.exported = this.parseIdent();
node.specifiers.push(this.finishNode(_specifier, "ExportNamespaceSpecifier"));
} else {
this.parseExportSpecifiersMaybe(node);
}
this.parseExportFrom(node);
} else if (this.eat(_tokentype.types._default)) {
// export default ...
var expr = this.parseMaybeAssign();
var needsSemi = true;
if (expr.type == "FunctionExpression" || expr.type == "ClassExpression") {
needsSemi = false;
if (expr.id) {
expr.type = expr.type == "FunctionExpression" ? "FunctionDeclaration" : "ClassDeclaration";
}
}
node.declaration = expr;
if (needsSemi) this.semicolon();
this.checkExport(node);
return this.finishNode(node, "ExportDefaultDeclaration");
} else if (this.type.keyword || this.shouldParseExportDeclaration()) {
node.declaration = this.parseStatement(true);
node.specifiers = [];
node.source = null;
} else {
// export { x, y as z } [from '...']
node.declaration = null;
node.specifiers = this.parseExportSpecifiers();
if (this.eatContextual("from")) {
node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected();
} else {
node.source = null;
}
this.semicolon();
}
this.checkExport(node);
return this.finishNode(node, "ExportNamedDeclaration");
};
pp.isExportDefaultSpecifier = function () {
if (this.type === _tokentype.types.name) {
return this.value !== "type" && this.value !== "async";
}
if (this.type !== _tokentype.types._default) {
return false;
}
var lookahead = this.lookahead();
return lookahead.type === _tokentype.types.comma || lookahead.type === _tokentype.types.name && lookahead.value === "from";
};
pp.parseExportSpecifiersMaybe = function (node) {
if (this.eat(_tokentype.types.comma)) {
node.specifiers = node.specifiers.concat(this.parseExportSpecifiers());
}
};
pp.parseExportFrom = function (node) {
this.expectContextual("from");
node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected();
this.semicolon();
this.checkExport(node);
};
pp.shouldParseExportDeclaration = function () {
return this.options.features["es7.asyncFunctions"] && this.isContextual("async");
};
pp.checkExport = function (node) {
if (this.decorators.length) {
var isClass = node.declaration && (node.declaration.type === "ClassDeclaration" || node.declaration.type === "ClassExpression");
if (!node.declaration || !isClass) {
this.raise(node.start, "You can only use decorators on an export when exporting a class");
}
this.takeDecorators(node.declaration);
}
};
// Parses a comma-separated list of module exports.
pp.parseExportSpecifiers = function () {
var nodes = [],
first = true;
// export { x, y as z } [from '...']
this.expect(_tokentype.types.braceL);
while (!this.eat(_tokentype.types.braceR)) {
if (!first) {
this.expect(_tokentype.types.comma);
if (this.afterTrailingComma(_tokentype.types.braceR)) break;
} else first = false;
var node = this.startNode();
node.local = this.parseIdent(this.type === _tokentype.types._default);
node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local;
nodes.push(this.finishNode(node, "ExportSpecifier"));
}
return nodes;
};
// Parses import declaration.
pp.parseImport = function (node) {
this.next();
// import '...'
if (this.type === _tokentype.types.string) {
node.specifiers = empty;
node.source = this.parseExprAtom();
} else {
node.specifiers = [];
this.parseImportSpecifiers(node);
this.expectContextual("from");
node.source = this.type === _tokentype.types.string ? this.parseExprAtom() : this.unexpected();
}
this.semicolon();
return this.finishNode(node, "ImportDeclaration");
};
// Parses a comma-separated list of module imports.
pp.parseImportSpecifiers = function (node) {
var first = true;
if (this.type === _tokentype.types.name) {
// import defaultObj, { x, y as z } from '...'
var start = this.markPosition();
node.specifiers.push(this.parseImportSpecifierDefault(this.parseIdent(), start));
if (!this.eat(_tokentype.types.comma)) return;
}
if (this.type === _tokentype.types.star) {
var specifier = this.startNode();
this.next();
this.expectContextual("as");
specifier.local = this.parseIdent();
this.checkLVal(specifier.local, true);
node.specifiers.push(this.finishNode(specifier, "ImportNamespaceSpecifier"));
return;
}
this.expect(_tokentype.types.braceL);
while (!this.eat(_tokentype.types.braceR)) {
if (!first) {
this.expect(_tokentype.types.comma);
if (this.afterTrailingComma(_tokentype.types.braceR)) break;
} else first = false;
var specifier = this.startNode();
specifier.imported = this.parseIdent(true);
specifier.local = this.eatContextual("as") ? this.parseIdent() : specifier.imported;
this.checkLVal(specifier.local, true);
node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
}
};
pp.parseImportSpecifierDefault = function (id, start) {
var node = this.startNodeAt(start);
node.local = id;
this.checkLVal(node.local, true);
return this.finishNode(node, "ImportDefaultSpecifier");
};