more estree updates - finish flow parsing

This commit is contained in:
Sebastian McKenzie 2015-03-19 01:48:44 +11:00
parent 57af08bea8
commit 7c84db45fd
6 changed files with 145 additions and 61 deletions

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
@ -347,6 +349,7 @@
kw("with");
kw("new", beforeExpr);
kw("this");
kw("super");
kw("class");
kw("extends", beforeExpr);
kw("export");
@ -421,6 +424,10 @@
var isStrictReservedWord = makePredicate("implements interface let package private protected public static yield");
// ECMAScript 6 reserved words.
var isReservedWord6 = makePredicate("enum await");
// The forbidden variable names in strict mode.
var isStrictBadIdWord = makePredicate("eval arguments");
@ -431,7 +438,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
@ -548,6 +555,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
@ -583,9 +591,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.inModule = this.options.sourceType === "module";
this.strict = options.strictMode === false ? false : this.inModule;
// Flags to track whether we are in a function, a generator.
this.inFunction = this.inGenerator = this.inAsync = false;
// Labels in scope.
this.labels = [];
@ -623,6 +633,25 @@
this.nextToken();
};
var STATE_KEYS = ["lastTokStartLoc", "lastTokEndLoc", "lastTokStart", "lastTokEnd", "startLoc", "endLoc", "start", "pos", "end", "type", "value"];
pp.getState = function () {
var state = {};
for (var i = 0; i < STATE_KEYS.length; i++) {
var key = STATE_KEYS[i];
state[key] = this[key];
}
return state;
};
pp.lookahead = function() {
var old = this.getState();
this.next();
var curr = this.getState();
for (var key in old) this[key] = old[key];
return curr;
};
pp.getToken = function() {
this.next();
return new Token(this);
@ -964,6 +993,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();
@ -1685,8 +1715,11 @@
break;
case "ObjectPattern":
for (var i = 0; i < param.properties.length; i++)
this.checkFunctionParam(param.properties[i].value, nameHash);
for (var i = 0; i < param.properties.length; i++) {
var prop = param.properties[i];
if (prop.type === "Property") prop = prop.value;
this.checkFunctionParam(prop, nameHash);
}
break;
case "ArrayPattern":
@ -1696,6 +1729,7 @@
}
break;
case "SpreadProperty":
case "RestElement":
return this.checkFunctionParam(param.argument, nameHash);
}
@ -1791,6 +1825,9 @@
}
this.next();
if (this.options.ecmaVersion >= 6) {
node.sourceType = this.options.sourceType;
}
return this.finishNode(node, "Program");
};
@ -1834,8 +1871,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);
case tt.name:
@ -2349,20 +2390,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 node = this.startNode();
var id = this.parseIdent(this.type !== tt.name);
@ -2860,7 +2897,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");
@ -2898,7 +2935,7 @@
return this.finishNode(node, "ExportDefaultDeclaration");
}
// export var|const|let|function|class ...;
if (this.type.keyword || (this.options.features["es7.asyncFunctions"] && this.isContextual("async"))) {
if (this.type.keyword || this.shouldParseExportDeclaration()) {
node.declaration = this.parseStatement(true);
node.specifiers = [];
node.source = null;
@ -2915,6 +2952,10 @@
return this.finishNode(node, "ExportNamedDeclaration");
};
pp.shouldParseExportDeclaration = function () {
return this.options.features["es7.asyncFunctions"] && this.isContextual("async");
};
// Parses a comma-separated list of module exports.
pp.parseExportSpecifiers = function() {

View File

@ -460,27 +460,19 @@ pp.flow_parsePrimaryType = function () {
case tt.parenL:
this.next();
var tmpId;
// Check to see if this is actually a grouped type
if (this.type !== tt.parenR && this.type !== tt.ellipsis) {
if (this.type === tt.name) {
//raise(tokStart, "Grouped types are currently the only flow feature not supported, request it?");
//tmpId = identToTypeAnnotation(start, node, parseIdent());
//next();
//isGroupedType = this.type !== tt.question && this.type !== tt.colon;
var token = this.lookahead().type;
isGroupedType = token !== tt.question && token !== tt.colon;
} else {
isGroupedType = true;
}
}
if (isGroupedType) {
if (tmpId && tt.parenR) {
type = tmpId;
} else {
type = this.flow_parseType();
this.expect(tt.parenR);
}
type = this.flow_parseType();
this.expect(tt.parenR);
// If we see a => next then someone was probably confused about
// function types, so we can provide a better error message
@ -627,6 +619,19 @@ acorn.plugins.flow = function (instance) {
};
});
instance.extend("parseStatement", function (inner) {
return function(declaration, topLevel) {
// strict mode handling of `interface` since it's a reserved word
if (this.strict && this.type === tt.name && this.value === "interface") {
var node = this.startNode();
this.next();
return this.flow_parseInterface(node);
} else {
return inner.call(this, declaration, topLevel);
}
};
});
instance.extend("parseExpressionStatement", function (inner) {
return function (node, expr) {
if (expr.type === "Identifier") {
@ -647,6 +652,12 @@ acorn.plugins.flow = function (instance) {
};
});
instance.extend("shouldParseExportDeclaration", function (inner) {
return function () {
return this.isContextual("type") || inner.call(this);
};
});
instance.extend("parseParenItem", function (inner) {
return function (node, start) {
if (this.type === tt.colon) {
@ -669,7 +680,7 @@ acorn.plugins.flow = function (instance) {
};
});
instance.extend("readToken", function(inner) {
instance.extend("readToken", function (inner) {
return function(code) {
if (this.inType && (code === 62 || code === 60)) {
return this.finishOp(tt.relational, 1);
@ -679,6 +690,12 @@ acorn.plugins.flow = function (instance) {
};
});
instance.extend("jsx_readToken", function (inner) {
return function () {
if (!this.inType) return inner.call(this);
};
});
instance.extend("parseParenArrowList", function (inner) {
return function (start, exprList, isAsync) {
for (var i = 0; i < exprList.length; i++) {

View File

@ -614,27 +614,25 @@ acorn.plugins.jsx = function(instance) {
instance.extend("readToken", function(inner) {
return function(code) {
if (!this.inType) {
var context = this.curContext();
var context = this.curContext();
if (context === tc.j_expr) return this.jsx_readToken();
if (context === tc.j_expr) return this.jsx_readToken();
if (context === tc.j_oTag || context === tc.j_cTag) {
if (acorn.isIdentifierStart(code)) return this.jsx_readWord();
if (context === tc.j_oTag || context === tc.j_cTag) {
if (acorn.isIdentifierStart(code)) return this.jsx_readWord();
if (code == 62) {
++this.pos;
return this.finishToken(tt.jsxTagEnd);
}
if ((code === 34 || code === 39) && context == tc.j_oTag)
return this.jsx_readString(code);
}
if (code === 60 && this.exprAllowed) {
if (code == 62) {
++this.pos;
return this.finishToken(tt.jsxTagStart);
return this.finishToken(tt.jsxTagEnd);
}
if ((code === 34 || code === 39) && context == tc.j_oTag)
return this.jsx_readString(code);
}
if (code === 60 && this.exprAllowed) {
++this.pos;
return this.finishToken(tt.jsxTagStart);
}
return inner.call(this, code);

View File

@ -2053,5 +2053,6 @@ test('export async function foo(){}', {
}]
}, {
ecmaVersion: 7,
sourceType: "module",
features: { "es7.asyncFunctions": true }
});

View File

@ -7734,8 +7734,7 @@ var fbTestFixture = {
}
},
'export type Foo = number;': {
type: 'ExportDeclaration',
'default': false,
type: 'ExportNamedDeclaration',
declaration: {
type: 'TypeAlias',
id: {
@ -7762,7 +7761,7 @@ var fbTestFixture = {
end: { line: 1, column: 25 }
}
},
specifiers: null,
specifiers: [],
source: null,
range: [0, 25],
loc: {
@ -11116,7 +11115,8 @@ for (var ns in fbTestFixture) {
body: [ns[code]]
}, {
ecmaVersion: 7,
plugins: { flow: true, jsx: true },
sourceType: "module",
plugins: { jsx: true, flow: true },
features: { "es7.asyncFunctions": true },
locations: true,
ranges: true

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"});