add esprima tests and fix bugs picked up by it

This commit is contained in:
Sebastian McKenzie
2015-08-11 00:59:15 +01:00
parent c318c88050
commit df021c7f23
2091 changed files with 82939 additions and 111 deletions

View File

@@ -72,8 +72,27 @@ pp.parseStatement = function (declaration, topLevel) {
case tt._switch: return this.parseSwitchStatement(node);
case tt._throw: return this.parseThrowStatement(node);
case tt._try: return this.parseTryStatement(node);
case tt._let: case tt._const: if (!declaration) this.unexpected(); // NOTE: falls through to _var
case tt._var: return this.parseVarStatement(node, starttype);
case tt._let:
// NOTE: falls through to _const
if (!this.strict) {
let state = this.state.clone();
this.next();
var isBindingAtomStart = this.isName() || this.match(tt.braceL) || this.match(tt.bracketL);
// set back lookahead
this.state = state;
if (!isBindingAtomStart) break;
}
case tt._const:
if (!declaration) this.unexpected(); // NOTE: falls through to _var
case tt._var:
return this.parseVarStatement(node, starttype);
case tt._while: return this.parseWhileStatement(node);
case tt._with: return this.parseWithStatement(node);
case tt.braceL: return this.parseBlock();
@@ -92,7 +111,7 @@ pp.parseStatement = function (declaration, topLevel) {
case tt.name:
if (this.options.features["es7.asyncFunctions"] && this.state.value === "async") {
// peek ahead and see if next token is a function
var state = this.state.clone();
let state = this.state.clone();
this.next();
if (this.match(tt._function) && !this.canInsertSemicolon()) {
this.expect(tt._function);
@@ -101,20 +120,19 @@ pp.parseStatement = function (declaration, topLevel) {
this.state = state;
}
}
}
// 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:
let maybeName = this.state.value, expr = this.parseExpression();
// 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.
let maybeName = this.state.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);
}
if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) {
return this.parseLabeledStatement(node, maybeName, expr);
} else {
return this.parseExpressionStatement(node, expr);
}
};
@@ -158,7 +176,7 @@ pp.parseBreakContinueStatement = function (node, keyword) {
} else if (!this.match(tt.name)) {
this.unexpected();
} else {
node.label = this.parseIdent();
node.label = this.parseIdentifier();
this.semicolon();
}
@@ -487,12 +505,12 @@ pp.parseFunction = function (node, isStatement, allowExpressionBody, isAsync, op
this.initFunction(node, isAsync);
node.generator = this.eat(tt.star);
if (isStatement && !optionalId && !this.match(tt.name)) {
if (isStatement && !optionalId && !this.isName()) {
this.unexpected();
}
if (this.match(tt.name)) {
node.id = this.parseIdent();
if (this.isName()) {
node.id = this.parseIdentifier();
}
this.parseFunctionParams(node);
@@ -613,7 +631,7 @@ pp.parseClassMethod = function (classBody, method, isGenerator, isAsync) {
pp.parseClassId = function (node, isStatement, optionalId) {
if (this.match(tt.name)) {
node.id = this.parseIdent();
node.id = this.parseIdentifier();
} else {
if (optionalId || !isStatement) {
node.id = null;
@@ -636,7 +654,7 @@ pp.parseExport = function (node) {
let specifier = this.startNode();
this.next();
if (this.options.features["es7.exportExtensions"] && this.eatContextual("as")) {
specifier.exported = this.parseIdent();
specifier.exported = this.parseIdentifier();
node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")];
this.parseExportSpecifiersMaybe(node);
this.parseExportFrom(node, true);
@@ -646,14 +664,14 @@ pp.parseExport = function (node) {
}
} else if (this.options.features["es7.exportExtensions"] && this.isExportDefaultSpecifier()) {
let specifier = this.startNode();
specifier.exported = this.parseIdent(true);
specifier.exported = this.parseIdentifier(true);
node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
if (this.match(tt.comma) && this.lookahead().type === tt.star) {
this.expect(tt.comma);
let specifier = this.startNode();
this.expect(tt.star);
this.expectContextual("as");
specifier.exported = this.parseIdent();
specifier.exported = this.parseIdentifier();
node.specifiers.push(this.finishNode(specifier, "ExportNamespaceSpecifier"));
} else {
this.parseExportSpecifiersMaybe(node);
@@ -744,7 +762,10 @@ pp.checkExport = function (node) {
// Parses a comma-separated list of module exports.
pp.parseExportSpecifiers = function () {
let nodes = [], first = true;
let nodes = [];
let first = true;
let needsFrom;
// export { x, y as z } [from '...']
this.expect(tt.braceL);
@@ -756,12 +777,20 @@ pp.parseExportSpecifiers = function () {
if (this.eat(tt.braceR)) break;
}
let isDefault = this.match(tt._default);
if (isDefault && !needsFrom) needsFrom = true;
let node = this.startNode();
node.local = this.parseIdent(this.match(tt._default));
node.exported = this.eatContextual("as") ? this.parseIdent(true) : node.local.__clone();
node.local = this.parseIdentifier(isDefault);
node.exported = this.eatContextual("as") ? this.parseIdentifier(true) : node.local.__clone();
nodes.push(this.finishNode(node, "ExportSpecifier"));
}
// https://github.com/ember-cli/ember-cli/pull/3739
if (needsFrom && !this.isContextual("from")) {
this.unexpected();
}
return nodes;
};
@@ -791,7 +820,7 @@ pp.parseImportSpecifiers = function (node) {
if (this.match(tt.name)) {
// import defaultObj, { x, y as z } from '...'
var startPos = this.state.start, startLoc = this.state.startLoc;
node.specifiers.push(this.parseImportSpecifierDefault(this.parseIdent(), startPos, startLoc));
node.specifiers.push(this.parseImportSpecifierDefault(this.parseIdentifier(), startPos, startLoc));
if (!this.eat(tt.comma)) return;
}
@@ -799,7 +828,7 @@ pp.parseImportSpecifiers = function (node) {
let specifier = this.startNode();
this.next();
this.expectContextual("as");
specifier.local = this.parseIdent();
specifier.local = this.parseIdentifier();
this.checkLVal(specifier.local, true);
node.specifiers.push(this.finishNode(specifier, "ImportNamespaceSpecifier"));
return;
@@ -815,8 +844,8 @@ pp.parseImportSpecifiers = function (node) {
}
let specifier = this.startNode();
specifier.imported = this.parseIdent(true);
specifier.local = this.eatContextual("as") ? this.parseIdent() : specifier.imported.__clone();
specifier.imported = this.parseIdentifier(true);
specifier.local = this.eatContextual("as") ? this.parseIdentifier() : specifier.imported.__clone();
this.checkLVal(specifier.local, true);
node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
}