[es6][estree] Add support for sourceType: script|module modes.

+ Fix list of keywords and reserved words in ES6.
This commit is contained in:
Ingvar Stepanyan 2015-03-18 13:42:49 +02:00
parent 024a98431d
commit 0473c368e6
4 changed files with 75 additions and 31 deletions

View File

@ -54,6 +54,9 @@ object referring to that same position.
either 3, 5, or 6. This influences support for strict mode, the set
of reserved words, and support for new syntax features. Default is 5.
- **sourceType**: Indicate the mode the code should be parsed in. Can be
either `"script"` or `"module"`.
- **onInsertedSemicolon**: If given a callback, that callback will be
called whenever a missing semicolon is inserted by the parser. The
callback will be given the character offset of the point where the

View File

@ -51,6 +51,8 @@
// mode, the set of reserved words, support for getters and
// setters and other features.
ecmaVersion: 5,
// Source type ("script" or "module") for different semantics
sourceType: "script",
// `onInsertedSemicolon` can be a callback that will be called
// when a semicolon is automatically inserted. It will be passed
// th position of the comma as an offset, and if `locations` is
@ -342,6 +344,7 @@
kw("with");
kw("new", beforeExpr);
kw("this");
kw("super");
kw("class");
kw("extends", beforeExpr);
kw("export");
@ -412,6 +415,10 @@
var isReservedWord5 = makePredicate("class enum extends super const export import");
// ECMAScript 6 reserved words.
var isReservedWord6 = makePredicate("enum await");
// The additional reserved words in strict mode.
var isStrictReservedWord = makePredicate("implements interface let package private protected public static yield");
@ -426,7 +433,7 @@
var isEcma5AndLessKeyword = makePredicate(ecma5AndLessKeywords);
var isEcma6Keyword = makePredicate(ecma5AndLessKeywords + " let const class extends export import yield");
var isEcma6Keyword = makePredicate(ecma5AndLessKeywords + " let const class extends export import yield super");
// ## Character categories
@ -543,6 +550,7 @@
this.loadPlugins(this.options.plugins);
this.sourceFile = this.options.sourceFile || null;
this.isKeyword = this.options.ecmaVersion >= 6 ? isEcma6Keyword : isEcma5AndLessKeyword;
this.isReservedWord = this.options.ecmaVersion === 3 ? isReservedWord3 : this.options.ecmaVersion === 5 ? isReservedWord5 : isReservedWord6;
this.input = String(input);
// Set up token state
@ -578,9 +586,11 @@
this.context = [tc.b_stat];
this.exprAllowed = true;
// Flags to track whether we are in strict mode, a function, a
// generator.
this.strict = this.inFunction = this.inGenerator = false;
// Figure out if it's a module code.
this.strict = this.inModule = this.options.sourceType === "module";
// Flags to track whether we are in a function, a generator.
this.inFunction = this.inGenerator = false;
// Labels in scope.
this.labels = [];
@ -946,6 +956,7 @@
}
if (next == 33 && code == 60 && this.input.charCodeAt(this.pos + 2) == 45 &&
this.input.charCodeAt(this.pos + 3) == 45) {
if (this.inModule) unexpected();
// `<!--`, an XML-style comment that should be interpreted as a line comment
this.skipLineComment(4);
this.skipSpace();
@ -1763,8 +1774,10 @@
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");
};
@ -1808,8 +1821,12 @@
case tt.semi: return this.parseEmptyStatement(node);
case tt._export:
case tt._import:
if (!topLevel && !this.options.allowImportExportEverywhere)
this.raise(this.start, "'import' and 'export' may only appear at the top level");
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);
// If the statement does not start with a statement keyword or a
@ -2307,19 +2324,16 @@
pp.parseExprAtom = function(refShorthandDefaultPos) {
switch (this.type) {
case tt._this:
case tt._super:
var type = this.type === tt._this ? "ThisExpression" : "SuperExpression";
var node = this.startNode();
this.next();
return this.finishNode(node, "ThisExpression");
return this.finishNode(node, type);
case tt._yield:
if (this.inGenerator) unexpected();
case tt.name:
if (this.value === "super") {
var node = this.startNode();
this.next();
return this.finishNode(node, "SuperExpression");
}
var start = this.currentPos();
var id = this.parseIdent(this.type !== tt.name);
if (!this.canInsertSemicolon() && this.eat(tt.arrow)) {
@ -2722,7 +2736,7 @@
if (this.type === tt.name) {
if (!liberal &&
(!this.options.allowReserved &&
(this.options.ecmaVersion === 3 ? isReservedWord3 : isReservedWord5)(this.value) ||
this.isReservedWord(this.value) ||
this.strict && isStrictReservedWord(this.value)) &&
this.input.slice(this.start, this.end).indexOf("\\") == -1)
this.raise(this.start, "The keyword '" + this.value + "' is reserved");

View File

@ -311,6 +311,9 @@
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");
};
@ -694,16 +697,13 @@
lp.parseExprAtom = function() {
switch (this.tok.type) {
case tt._this:
case tt._super:
var type = this.tok.type === tt._this ? "ThisExpression" : "SuperExpression";
var node = this.startNode();
this.next();
return this.finishNode(node, "ThisExpression");
return this.finishNode(node, type);
case tt.name:
if (this.tok.value === "super") {
var node = this.startNode();
this.next();
return this.finishNode(node, "SuperExpression");
}
var start = this.storeCurrentPos();
var id = this.parseIdent();
return this.eat(tt.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id]) : id;

View File

@ -4381,6 +4381,7 @@ test("let {a:b} = {}", {
test("var {a:b} = {}", {
type: "Program",
sourceType: "script",
body: [{
type: "VariableDeclaration",
declarations: [{
@ -4452,6 +4453,7 @@ test("var {a:b} = {}", {
test("export var document", {
type: "Program",
sourceType: "module",
body: [{
type: "ExportNamedDeclaration",
declaration: {
@ -4491,6 +4493,7 @@ test("export var document", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4543,6 +4546,7 @@ test("export var document = { }", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4588,6 +4592,7 @@ test("export let document", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4640,6 +4645,7 @@ test("export let document = { }", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4692,6 +4698,7 @@ test("export const document = { }", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4739,6 +4746,7 @@ test("export function parse() { }", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4784,6 +4792,7 @@ test("export class Class {}", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4812,6 +4821,7 @@ test("export default 42", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4836,7 +4846,7 @@ test("export default function () {}", {
}
}
}]
}, {ecmaVersion: 6, ranges: true});
}, {ecmaVersion: 6, sourceType: "module", ranges: true});
test("export default function f() {}", {
type: "Program",
@ -4862,7 +4872,7 @@ test("export default function f() {}", {
}
}
}]
}, {ecmaVersion: 6, ranges: true});
}, {ecmaVersion: 6, sourceType: "module", ranges: true});
test("export default class {}", {
type: "Program",
@ -4882,7 +4892,7 @@ test("export default class {}", {
}
}
}]
}, {ecmaVersion: 6, ranges: true});
}, {ecmaVersion: 6, sourceType: "module", ranges: true});
test("export default class A {}", {
type: "Program",
@ -4906,9 +4916,9 @@ test("export default class A {}", {
}
}
}]
}, {ecmaVersion: 6, ranges: true});
}, {ecmaVersion: 6, sourceType: "module", ranges: true});
testFail("export *", "Unexpected token (1:8)", {ecmaVersion: 6});
testFail("export *", "Unexpected token (1:8)", {ecmaVersion: 6, sourceType: "module"});
test("export * from \"crypto\"", {
type: "Program",
@ -4934,6 +4944,7 @@ test("export * from \"crypto\"", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -4978,6 +4989,7 @@ test("export { encrypt }", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5047,6 +5059,7 @@ test("export { encrypt, decrypt }", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5091,6 +5104,7 @@ test("export { encrypt as default }", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5160,6 +5174,7 @@ test("export { encrypt, decrypt as dec }", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5220,6 +5235,7 @@ test("export { default } from \"other\"", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5249,6 +5265,7 @@ test("import \"jquery\"", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5292,6 +5309,7 @@ test("import $ from \"jquery\"", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5368,6 +5386,7 @@ test("import { encrypt, decrypt } from \"crypto\"", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5419,6 +5438,7 @@ test("import { encrypt as enc } from \"crypto\"", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5510,11 +5530,12 @@ test("import crypto, { decrypt, encrypt as enc } from \"crypto\"", {
}]
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
testFail("import default from \"foo\"", "Unexpected token (1:7)", {ecmaVersion: 6});
testFail("import default from \"foo\"", "Unexpected token (1:7)", {ecmaVersion: 6, sourceType: "module"});
test("import { null as nil } from \"bar\"", {
type: "Program",
@ -5563,6 +5584,7 @@ test("import { null as nil } from \"bar\"", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5606,6 +5628,7 @@ test("import * as crypto from \"crypto\"", {
}]
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5668,6 +5691,7 @@ test("(function* () { yield v })", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -5738,6 +5762,7 @@ test("(function* () { yield\nv })", {
}
}, {
ecmaVersion: 6,
sourceType: "module",
ranges: true,
locations: true
});
@ -13899,7 +13924,7 @@ testFail("function hello() {'use strict'; ({ i: 10, s(eval) { } }); }", "Definin
testFail("function a() { \"use strict\"; ({ b(t, t) { } }); }", "Argument name clash in strict mode (1:37)", {ecmaVersion: 6});
testFail("var super", "The keyword 'super' is reserved (1:4)", {ecmaVersion: 6, allowReserved: false});
testFail("var super", "Unexpected token (1:4)", {ecmaVersion: 6});
testFail("var default", "Unexpected token (1:4)", {ecmaVersion: 6});
@ -13915,11 +13940,11 @@ testFail("for (let x = 42 in list) process(x);", "Unexpected token (1:16)", {ecm
testFail("for (let x = 42 of list) process(x);", "Unexpected token (1:16)", {ecmaVersion: 6});
testFail("import foo", "Unexpected token (1:10)", {ecmaVersion: 6});
testFail("import foo", "Unexpected token (1:10)", {ecmaVersion: 6, sourceType: "module"});
testFail("import { foo, bar }", "Unexpected token (1:19)", {ecmaVersion: 6});
testFail("import { foo, bar }", "Unexpected token (1:19)", {ecmaVersion: 6, sourceType: "module"});
testFail("import foo from bar", "Unexpected token (1:16)", {ecmaVersion: 6});
testFail("import foo from bar", "Unexpected token (1:16)", {ecmaVersion: 6, sourceType: "module"});
testFail("((a)) => 42", "Unexpected token (1:1)", {ecmaVersion: 6});
@ -14415,7 +14440,7 @@ test("import foo, * as bar from 'baz';", {
raw: "'baz'"
}
}]
}, {ecmaVersion: 6});
}, {ecmaVersion: 6, sourceType: "module"});
// https://github.com/marijnh/acorn/issues/173
test("`{${x}}`, `}`", {
@ -15404,3 +15429,5 @@ testFail("if (1) ; else class Cls {}", "Unexpected token (1:14)", {ecmaVersion:
testFail("'use strict'; [...eval] = arr", "Assigning to eval in strict mode (1:18)", {ecmaVersion: 6});
testFail("'use strict'; ({eval = defValue} = obj)", "Assigning to eval in strict mode (1:16)", {ecmaVersion: 6});
testFail("[...eval] = arr", "Assigning to eval in strict mode (1:4)", {ecmaVersion: 6, sourceType: "module"});