move acorn into vendor

This commit is contained in:
Sebastian McKenzie 2015-03-18 19:01:30 +11:00
parent 16e8224ce6
commit 57af08bea8
9 changed files with 18541 additions and 110 deletions

265
acorn.js
View File

@ -122,7 +122,7 @@
preserveParens: false,
plugins: {},
// Babel-specific options
transformers: {},
features: {},
strictMode: false
};
@ -911,7 +911,7 @@
var width = 1;
var next = this.input.charCodeAt(this.pos + 1);
if (this.options.transformers["es7.exponentiationOperator"] && next === 42) { // '*'
if (next === 42) { // '*'
width++;
next = this.input.charCodeAt(this.pos + 2);
type = tt.exponent;
@ -1838,6 +1838,17 @@
this.raise(this.start, "'import' and 'export' may only appear at the top level");
return starttype === tt._import ? this.parseImport(node) : this.parseExport(node);
case tt.name:
if (this.options.features["es7.asyncFunctions"] && this.value === "async") {
// check to see if `function ` appears after this token, this is
// pretty hacky
if (this.input.slice(this.pos + 1, this.pos + 10) === "function ") {
this.next();
this.expect(tt._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
@ -2346,8 +2357,51 @@
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);
//
if (this.options.features["es7.asyncFunctions"]) {
// async functions!
if (id.name === "async") {
// arrow functions
if (this.type === tt.parenL) {
var expr = this.parseParenAndDistinguishExpression(start, true);
if (expr.type === "ArrowFunctionExpression") {
return expr;
} else {
node.callee = id;
if (expr.type === "SequenceExpression") {
node.arguments = expr.expressions;
} else {
node.arguments = [expr];
}
return this.parseSubscripts(this.finishNode(node, "CallExpression"), start);
}
} else if (this.type === tt.name) {
id = this.parseIdent();
this.expect(tt.arrow);
return this.parseArrowExpression(node, [id], true);
}
// normal functions
if (this.type === tt._function && !this.canInsertSemicolon()) {
this.next();
return this.parseFunction(node, false, false, true);
}
} else if (id.name === "await") {
if (this.inAsync) return this.parseAwait(node);
}
}
//
if (!this.canInsertSemicolon() && this.eat(tt.arrow)) {
return this.parseArrowExpression(this.startNodeAt(start), [id]);
}
@ -2376,7 +2430,7 @@
var node = this.startNode();
this.next();
// check whether this is array comprehension or regular array
if (this.options.transformers["es7.comprehensions"] && this.type === tt._for) {
if ((this.options.features["es7.comprehensions"] || this.options.ecmaVersion >= 7) && this.type === tt._for) {
return this.parseComprehension(node, false);
}
node.elements = this.parseExprList(tt.bracketR, true, true, refShorthandDefaultPos);
@ -2412,12 +2466,13 @@
return this.finishNode(node, "Literal");
};
pp.parseParenAndDistinguishExpression = function() {
var start = this.currentPos(), val;
pp.parseParenAndDistinguishExpression = function(start, isAsync) {
start = start || this.currentPos();
var val;
if (this.options.ecmaVersion >= 6) {
this.next();
if (this.options.transformers["es7.comprehensions"] && this.type === tt._for) {
if ((this.options.features["es7.comprehensions"] || this.options.ecmaVersion >= 7) && this.type === tt._for) {
return this.parseComprehension(this.startNodeAt(start), true);
}
@ -2442,7 +2497,7 @@
if (!this.canInsertSemicolon() && this.eat(tt.arrow)) {
if (innerParenStart) this.unexpected(innerParenStart);
return this.parseArrowExpression(this.startNodeAt(start), exprList);
return this.parseParenArrowList(start, exprList, isAsync);
}
if (!exprList.length) this.unexpected(this.lastTokStart);
@ -2469,6 +2524,10 @@
}
};
pp.parseParenArrowList = function (start, exprList, isAsync) {
return this.parseArrowExpression(this.startNodeAt(start), exprList, isAsync);
};
pp.parseParenItem = function (node, start) {
return node;
};
@ -2528,8 +2587,8 @@
if (this.afterTrailingComma(tt.braceR)) break;
} else first = false;
var prop = this.startNode(), isGenerator, start;
if (this.options.transformers["es7.objectRestSpread"] && this.type === tt.ellipsis) {
var prop = this.startNode(), isGenerator, isAsync, start;
if (this.options.features["es7.objectRestSpread"] && this.type === tt.ellipsis) {
prop = this.parseSpread();
prop.type = "SpreadProperty";
node.properties.push(prop);
@ -2545,47 +2604,62 @@
isGenerator = this.eat(tt.star);
}
}
this.parsePropertyName(prop);
if (this.eat(tt.colon)) {
prop.value = isPattern ? this.parseMaybeDefault() : this.parseMaybeAssign(false, refShorthandDefaultPos);
prop.kind = "init";
} else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) {
if (isPattern) this.unexpected();
prop.kind = "init";
prop.method = true;
prop.value = this.parseMethod(isGenerator);
} else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" &&
(prop.key.name === "get" || prop.key.name === "set") &&
(this.type != tt.comma && this.type != tt.braceR)) {
if (this.options.features["es7.asyncFunctions"] && this.isContextual("async")) {
if (isGenerator || isPattern) this.unexpected();
prop.kind = prop.key.name;
this.parsePropertyName(prop);
prop.value = this.parseMethod(false);
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
prop.kind = "init";
if (isPattern) {
prop.value = this.parseMaybeDefault(start, prop.key);
} else if (this.type === tt.eq && refShorthandDefaultPos) {
if (!refShorthandDefaultPos.start)
refShorthandDefaultPos.start = this.start;
prop.value = this.parseMaybeDefault(start, prop.key);
} else {
prop.value = prop.key;
}
prop.shorthand = true;
} else this.unexpected();
var asyncId = this.parseIdent();
if (this.type === tt.colon || this.type === tt.parenL) {
prop.key = asyncId;
} else {
isAsync = true;
this.parsePropertyName(prop);
}
} else {
this.parsePropertyName(prop);
}
this.parseObjPropValue(prop, start, isGenerator, isAsync, isPattern, refShorthandDefaultPos);
this.checkPropClash(prop, propHash);
node.properties.push(this.finishNode(prop, "Property"));
}
return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression");
};
pp.parseObjPropValue = function (prop, start, isGenerator, isAsync, isPattern, refShorthandDefaultPos) {
if (this.eat(tt.colon)) {
prop.value = isPattern ? this.parseMaybeDefault() : this.parseMaybeAssign(false, refShorthandDefaultPos);
prop.kind = "init";
} else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) {
if (isPattern) this.unexpected();
prop.kind = "init";
prop.method = true;
prop.value = this.parseMethod(isGenerator, isAsync);
} else if (this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === "Identifier" &&
(prop.key.name === "get" || prop.key.name === "set") &&
(this.type != tt.comma && this.type != tt.braceR)) {
if (isGenerator || isAsync || isPattern) this.unexpected();
prop.kind = prop.key.name;
this.parsePropertyName(prop);
prop.value = this.parseMethod(false);
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
prop.kind = "init";
if (isPattern) {
prop.value = this.parseMaybeDefault(start, prop.key);
} else if (this.type === tt.eq && refShorthandDefaultPos) {
if (!refShorthandDefaultPos.start)
refShorthandDefaultPos.start = this.start;
prop.value = this.parseMaybeDefault(start, prop.key);
} else {
prop.value = prop.key;
}
prop.shorthand = true;
} else this.unexpected();
};
pp.parsePropertyName = function(prop) {
if (this.options.ecmaVersion >= 6) {
if (this.eat(tt.bracketL)) {
prop.computed = true;
prop.key = this.parseExpression();
prop.key = this.parseMaybeAssign();
this.expect(tt.bracketR);
return;
} else {
@ -2597,19 +2671,22 @@
// Initialize empty function node.
pp.initFunction = function(node) {
pp.initFunction = function(node, isAsync) {
node.id = null;
if (this.options.ecmaVersion >= 6) {
node.generator = false;
node.expression = false;
}
if (this.options.features["es7.asyncFunctions"]) {
node.async = !!isAsync;
}
};
// Parse a function declaration or literal (depending on the
// `isStatement` parameter).
pp.parseFunction = function(node, isStatement, allowExpressionBody) {
this.initFunction(node);
pp.parseFunction = function(node, isStatement, allowExpressionBody, isAsync) {
this.initFunction(node, isAsync);
if (this.options.ecmaVersion >= 6) {
node.generator = this.eat(tt.star);
}
@ -2628,9 +2705,9 @@
// Parse object or class method.
pp.parseMethod = function(isGenerator) {
pp.parseMethod = function(isGenerator, isAsync) {
var node = this.startNode();
this.initFunction(node);
this.initFunction(node, isAsync);
this.expect(tt.parenL);
node.params = this.parseBindingList(tt.parenR, false, false);
var allowExpressionBody;
@ -2646,8 +2723,8 @@
// Parse arrow function expression with given parameters.
pp.parseArrowExpression = function(node, params) {
this.initFunction(node);
pp.parseArrowExpression = function(node, params, isAsync) {
this.initFunction(node, isAsync);
node.params = this.toAssignableList(params, true);
this.parseFunctionBody(node, true);
return this.finishNode(node, "ArrowFunctionExpression");
@ -2658,6 +2735,8 @@
pp.parseFunctionBody = function(node, allowExpression) {
var isExpression = allowExpression && this.type !== tt.braceL;
var oldInAsync = this.inAsync;
this.inAsync = node.async;
if (isExpression) {
node.body = this.parseMaybeAssign();
node.expression = true;
@ -2670,6 +2749,7 @@
node.expression = false;
this.inFunction = oldInFunc; this.inGenerator = oldInGen; this.labels = oldLabels;
}
this.inAsync = oldInAsync;
// If this is a strict mode function, verify that argument names
// are not repeated, and it does not try to bind the words `eval`
@ -2696,7 +2776,7 @@
while (!this.eat(tt.braceR)) {
if (this.eat(tt.semi)) continue;
var method = this.startNode();
var isGenerator = this.eat(tt.star);
var isGenerator = this.eat(tt.star), isAsync;
this.parsePropertyName(method);
if (this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" &&
method.key.name === "static") {
@ -2707,21 +2787,35 @@
} else {
method['static'] = false;
}
if (this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" &&
(method.key.name === "get" || method.key.name === "set")) {
if (isGenerator) this.unexpected();
method.kind = method.key.name;
if (this.options.features["es7.asyncFunctions"] && this.type !== tt.parenL &&
!method.computed && method.key.type === "Identifier" && method.key.name === "async") {
isAsync = true;
this.parsePropertyName(method);
} else {
method.kind = "";
}
method.value = this.parseMethod(isGenerator);
classBody.body.push(this.finishNode(method, "MethodDefinition"));
method.kind = "method";
if (!method.computed && !isGenerator) {
if (method.key.type === "Identifier") {
if (this.type !== tt.parenL && (method.key.name === "get" || method.key.name === "set")) {
method.kind = method.key.name;
this.parsePropertyName(method);
} else if (!method['static'] && method.key.name === "constructor") {
method.kind = "constructor";
}
} else if (!method['static'] && method.key.type === "Literal" && method.key.value === "constructor") {
method.kind = "constructor";
}
}
this.parseClassMethod(classBody, method, isGenerator, isAsync);
}
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 ? this.unexpected() : null;
};
@ -2788,6 +2882,7 @@
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 ...;
@ -2803,7 +2898,7 @@
return this.finishNode(node, "ExportDefaultDeclaration");
}
// export var|const|let|function|class ...;
if (this.type.keyword) {
if (this.type.keyword || (this.options.features["es7.asyncFunctions"] && this.isContextual("async"))) {
node.declaration = this.parseStatement(true);
node.specifiers = [];
node.source = null;
@ -2844,13 +2939,13 @@
pp.parseImport = function(node) {
this.next();
node.specifiers = [];
// import '...';
if (this.type === tt.string) {
node.specifiers = [];
node.source = this.parseExprAtom();
node.kind = "";
} else {
node.specifiers = this.parseImportSpecifiers();
this.parseImportSpecifiers(node);
this.expectContextual("from");
node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected();
}
@ -2860,24 +2955,22 @@
// Parses a comma-separated list of module imports.
pp.parseImportSpecifiers = function() {
var nodes = [], first = true;
pp.parseImportSpecifiers = function(node) {
var first = true;
if (this.type === tt.name) {
// import defaultObj, { x, y as z } from '...'
var node = this.startNode();
node.local = this.parseIdent();
this.checkLVal(node.local, true);
nodes.push(this.finishNode(node, "ImportDefaultSpecifier"));
if (!this.eat(tt.comma)) return nodes;
var start = this.currentPos();
node.specifiers.push(this.parseImportSpecifierDefault(this.parseIdent(), start));
if (!this.eat(tt.comma)) return;
}
if (this.type === tt.star) {
var node = this.startNode();
var specifier = this.startNode();
this.next();
this.expectContextual("as");
node.local = this.parseIdent();
this.checkLVal(node.local, true);
nodes.push(this.finishNode(node, "ImportNamespaceSpecifier"));
return nodes;
specifier.local = this.parseIdent();
this.checkLVal(specifier.local, true);
node.specifiers.push(this.finishNode(specifier, "ImportNamespaceSpecifier"));
return;
}
this.expect(tt.braceL);
while (!this.eat(tt.braceR)) {
@ -2886,13 +2979,19 @@
if (this.afterTrailingComma(tt.braceR)) break;
} else first = false;
var node = this.startNode();
node.imported = this.parseIdent(true);
node.local = this.eatContextual("as") ? this.parseIdent() : node.imported;
this.checkLVal(node.local, true);
nodes.push(this.finishNode(node, "ImportSpecifier"));
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"));
}
return nodes;
};
pp.parseImportSpecifierDefault = function (id, start) {
var node = this.startNodeAt(start);
node.local = id;
this.checkLVal(node.local, true);
return this.finishNode(node, "ImportDefaultSpecifier");
};
// Parses yield expression inside generator.
@ -2910,6 +3009,17 @@
return this.finishNode(node, "YieldExpression");
};
// Parses await expression inside async function.
pp.parseAwait = function (node) {
if (this.eat(tt.semi) || this.canInsertSemicolon()) {
this.unexpected();
}
node.all = this.eat(tt.star);
node.argument = this.parseMaybeAssign(true);
return this.finishNode(node, "AwaitExpression");
};
// Parses array and generator comprehensions.
pp.parseComprehension = function(node, isGenerator) {
@ -2931,4 +3041,9 @@
node.generator = isGenerator;
return this.finishNode(node, "ComprehensionExpression");
};
// init plugins
require("./plugins/flow");
require("./plugins/jsx");
});

806
plugins/flow.js Normal file
View File

@ -0,0 +1,806 @@
var acorn = require("../acorn");
var pp = acorn.Parser.prototype;
var tt = acorn.tokTypes;
pp.isRelational = function (op) {
return this.type === tt.relational && this.value === op;
};
pp.expectRelational = function (op) {
if (this.isRelational(op)) {
this.next();
} else {
this.unexpected();
}
};
pp.flow_parseDeclareClass = function (node) {
this.next();
this.flow_parseInterfaceish(node, true);
return this.finishNode(node, "DeclareClass");
};
pp.flow_parseDeclareFunction = function (node) {
this.next();
var id = node.id = this.parseIdent();
var typeNode = this.startNode();
var typeContainer = this.startNode();
if (this.isRelational("<")) {
typeNode.typeParameters = this.flow_parseTypeParameterDeclaration();
} else {
typeNode.typeParameters = null;
}
this.expect(tt.parenL);
var tmp = this.flow_parseFunctionTypeParams();
typeNode.params = tmp.params;
typeNode.rest = tmp.rest;
this.expect(tt.parenR);
this.expect(tt.colon);
typeNode.returnType = this.flow_parseType();
typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation");
id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation");
this.finishNode(id, id.type);
this.semicolon();
return this.finishNode(node, "DeclareFunction");
};
pp.flow_parseDeclare = function (node) {
if (this.type === tt._class) {
return this.flow_parseDeclareClass(node);
} else if (this.type === tt._function) {
return this.flow_parseDeclareFunction(node);
} else if (this.type === tt._var) {
return this.flow_parseDeclareVariable(node);
} else if (this.isContextual("module")) {
return this.flow_parseDeclareModule(node);
} else {
this.unexpected();
}
};
pp.flow_parseDeclareVariable = function (node) {
this.next();
node.id = this.flow_parseTypeAnnotatableIdentifier();
this.semicolon();
return this.finishNode(node, "DeclareVariable");
};
pp.flow_parseDeclareModule = function (node) {
this.next();
if (this.type === tt.string) {
node.id = this.parseExprAtom();
} else {
node.id = this.parseIdent();
}
var bodyNode = node.body = this.startNode();
var body = bodyNode.body = [];
this.expect(tt.braceL);
while (this.type !== tt.braceR) {
var node2 = this.startNode();
// todo: declare check
this.next();
body.push(this.flow_parseDeclare(node2));
}
this.expect(tt.braceR);
this.finishNode(bodyNode, "BlockStatement");
return this.finishNode(node, "DeclareModule");
};
// Interfaces
pp.flow_parseInterfaceish = function (node, allowStatic) {
node.id = this.parseIdent();
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
} else {
node.typeParameters = null;
}
node.extends = [];
if (this.eat(tt._extends)) {
do {
node.extends.push(this.flow_parseInterfaceExtends());
} while(this.eat(tt.comma));
}
node.body = this.flow_parseObjectType(allowStatic);
};
pp.flow_parseInterfaceExtends = function () {
var node = this.startNode();
node.id = this.parseIdent();
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterInstantiation();
} else {
node.typeParameters = null;
}
return this.finishNode(node, "InterfaceExtends");
};
pp.flow_parseInterface = function (node) {
this.flow_parseInterfaceish(node, false);
return this.finishNode(node, "InterfaceDeclaration");
};
// Type aliases
pp.flow_parseTypeAlias = function (node) {
node.id = this.parseIdent();
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
} else {
node.typeParameters = null;
}
this.expect(tt.eq);
node.right = this.flow_parseType();
this.semicolon();
return this.finishNode(node, "TypeAlias");
};
// Type annotations
pp.flow_parseTypeParameterDeclaration = function () {
var node = this.startNode();
node.params = [];
this.expectRelational("<");
while (!this.isRelational(">")) {
node.params.push(this.flow_parseTypeAnnotatableIdentifier());
if (!this.isRelational(">")) {
this.expect(tt.comma);
}
}
this.expectRelational(">");
return this.finishNode(node, "TypeParameterDeclaration");
};
pp.flow_parseTypeParameterInstantiation = function () {
var node = this.startNode(), oldInType = this.inType;
node.params = [];
this.inType = true;
this.expectRelational("<");
while (!this.isRelational(">")) {
node.params.push(this.flow_parseType());
if (!this.isRelational(">")) {
this.expect(tt.comma);
}
}
this.expectRelational(">");
this.inType = oldInType;
return this.finishNode(node, "TypeParameterInstantiation");
};
pp.flow_parseObjectPropertyKey = function () {
return (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true);
};
pp.flow_parseObjectTypeIndexer = function (node, isStatic) {
node.static = isStatic;
this.expect(tt.bracketL);
node.id = this.flow_parseObjectPropertyKey();
this.expect(tt.colon);
node.key = this.flow_parseType();
this.expect(tt.bracketR);
this.expect(tt.colon);
node.value = this.flow_parseType();
return this.finishNode(node, "ObjectTypeIndexer");
};
pp.flow_parseObjectTypeMethodish = function (node) {
node.params = [];
node.rest = null;
node.typeParameters = null;
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
}
this.expect(tt.parenL);
while (this.type === tt.name) {
node.params.push(this.flow_parseFunctionTypeParam());
if (this.type !== tt.parenR) {
this.expect(tt.comma);
}
}
if (this.eat(tt.ellipsis)) {
node.rest = this.flow_parseFunctionTypeParam();
}
this.expect(tt.parenR);
this.expect(tt.colon);
node.returnType = this.flow_parseType();
return this.finishNode(node, "FunctionTypeAnnotation");
};
pp.flow_parseObjectTypeMethod = function (start, isStatic, key) {
var node = this.startNodeAt(start);
node.value = this.flow_parseObjectTypeMethodish(this.startNodeAt(start));
node.static = isStatic;
node.key = key;
node.optional = false;
return this.finishNode(node, "ObjectTypeProperty");
};
pp.flow_parseObjectTypeCallProperty = function (node, isStatic) {
var valueNode = this.startNode();
node.static = isStatic;
node.value = this.flow_parseObjectTypeMethodish(valueNode);
return this.finishNode(node, "ObjectTypeCallProperty");
};
pp.flow_parseObjectType = function (allowStatic) {
var nodeStart = this.startNode();
var node;
var optional = false;
var property;
var propertyKey;
var propertyTypeAnnotation;
var token;
var isStatic;
nodeStart.callProperties = [];
nodeStart.properties = [];
nodeStart.indexers = [];
this.expect(tt.braceL);
while (this.type !== tt.braceR) {
var start = this.currentPos();
node = this.startNode();
if (allowStatic && this.isContextual("static")) {
this.next();
isStatic = true;
}
if (this.type === tt.bracketL) {
nodeStart.indexers.push(this.flow_parseObjectTypeIndexer(node, isStatic));
} else if (this.type === tt.parenL || this.isRelational("<")) {
nodeStart.callProperties.push(this.flow_parseObjectTypeCallProperty(node, allowStatic));
} else {
if (isStatic && this.type === tt.colon) {
propertyKey = this.parseIdent();
} else {
propertyKey = this.flow_parseObjectPropertyKey();
}
if (this.isRelational("<") || this.type === tt.parenL) {
// This is a method property
nodeStart.properties.push(this.flow_parseObjectTypeMethod(start, isStatic, propertyKey));
} else {
if (this.eat(tt.question)) {
optional = true;
}
this.expect(tt.colon);
node.key = propertyKey;
node.value = this.flow_parseType();
node.optional = optional;
node.static = isStatic;
nodeStart.properties.push(this.finishNode(node, "ObjectTypeProperty"));
}
}
if (!this.eat(tt.semi) && this.type !== tt.braceR) {
this.unexpected();
}
}
this.expect(tt.braceR);
return this.finishNode(nodeStart, "ObjectTypeAnnotation")
};
pp.flow_parseGenericType = function (start, id) {
var node = this.startNodeAt(start);
node.typeParameters = null;
node.id = id;
while (this.eat(tt.dot)) {
var node2 = this.startNodeAt(start);
node2.qualification = node.id;
node2.id = this.parseIdent();
node.id = this.finishNode(node2, "QualifiedTypeIdentifier");
}
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterInstantiation();
}
return this.finishNode(node, "GenericTypeAnnotation");
};
pp.flow_parseVoidType = function () {
var node = this.startNode();
this.expect(tt._void);
return this.finishNode(node, "VoidTypeAnnotation");
};
pp.flow_parseTypeofType = function () {
var node = this.startNode();
this.expect(tt._typeof);
node.argument = this.flow_parsePrimaryType();
return this.finishNode(node, "TypeofTypeAnnotation");
};
pp.flow_parseTupleType = function () {
var node = this.startNode();
node.types = [];
this.expect(tt.bracketL);
// We allow trailing commas
while (this.pos < this.input.length && this.type !== tt.bracketR) {
node.types.push(this.flow_parseType());
if (this.type === tt.bracketR) break;
this.expect(tt.comma);
}
this.expect(tt.bracketR);
return this.finishNode(node, "TupleTypeAnnotation");
};
pp.flow_parseFunctionTypeParam = function () {
var optional = false;
var node = this.startNode();
node.name = this.parseIdent();
if (this.eat(tt.question)) {
optional = true;
}
this.expect(tt.colon);
node.optional = optional;
node.typeAnnotation = this.flow_parseType();
return this.finishNode(node, "FunctionTypeParam");
};
pp.flow_parseFunctionTypeParams = function () {
var ret = { params: [], rest: null };
while (this.type === tt.name) {
ret.params.push(this.flow_parseFunctionTypeParam());
if (this.type !== tt.parenR) {
this.expect(tt.comma);
}
}
if (this.eat(tt.ellipsis)) {
ret.rest = this.flow_parseFunctionTypeParam();
}
return ret;
};
pp.flow_identToTypeAnnotation = function (start, node, id) {
switch (id.name) {
case "any":
return this.finishNode(node, "AnyTypeAnnotation");
case "bool":
case "boolean":
return this.finishNode(node, "BooleanTypeAnnotation");
case "number":
return this.finishNode(node, "NumberTypeAnnotation");
case "string":
return this.finishNode(node, "StringTypeAnnotation");
default:
return this.flow_parseGenericType(start, id);
}
};
// The parsing of types roughly parallels the parsing of expressions, and
// primary types are kind of like primary expressions...they're the
// primitives with which other types are constructed.
pp.flow_parsePrimaryType = function () {
var typeIdentifier = null;
var params = null;
var returnType = null;
var start = this.currentPos();
var node = this.startNode();
var rest = null;
var tmp;
var typeParameters;
var token;
var type;
var isGroupedType = false;
switch (this.type) {
case tt.name:
return this.flow_identToTypeAnnotation(start, node, this.parseIdent());
case tt.braceL:
return this.flow_parseObjectType();
case tt.bracketL:
return this.flow_parseTupleType();
case tt.relational:
if (this.value === "<") {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
this.expect(tt.parenL);
tmp = this.flow_parseFunctionTypeParams();
node.params = tmp.params;
node.rest = tmp.rest;
this.expect(tt.parenR);
this.expect(tt.arrow);
node.returnType = this.flow_parseType();
return this.finishNode(node, "FunctionTypeAnnotation");
}
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;
} else {
isGroupedType = true;
}
}
if (isGroupedType) {
if (tmpId && tt.parenR) {
type = tmpId;
} else {
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
if (this.eat(tt.arrow)) {
this.raise(node,
"Unexpected token =>. It looks like " +
"you are trying to write a function type, but you ended up " +
"writing a grouped type followed by an =>, which is a syntax " +
"error. Remember, function type parameters are named so function " +
"types look like (name1: type1, name2: type2) => returnType. You " +
"probably wrote (type1) => returnType"
);
}
return type;
}
tmp = this.flow_parseFunctionTypeParams();
node.params = tmp.params;
node.rest = tmp.rest;
this.expect(tt.parenR);
this.expect(tt.arrow);
node.returnType = this.flow_parseType();
node.typeParameters = null;
return this.finishNode(node, "FunctionTypeAnnotation");
case tt.string:
node.value = this.value;
node.raw = this.input.slice(this.start, this.end);
this.next();
return this.finishNode(node, "StringLiteralTypeAnnotation");
default:
if (this.type.keyword) {
switch (this.type.keyword) {
case "void":
return this.flow_parseVoidType();
case "typeof":
return this.flow_parseTypeofType();
}
}
}
this.unexpected();
};
pp.flow_parsePostfixType = function () {
var node = this.startNode();
var type = node.elementType = this.flow_parsePrimaryType();
if (this.type === tt.bracketL) {
this.expect(tt.bracketL);
this.expect(tt.bracketR);
return this.finishNode(node, "ArrayTypeAnnotation");
}
return type;
};
pp.flow_parsePrefixType = function () {
var node = this.startNode();
if (this.eat(tt.question)) {
node.typeAnnotation = this.flow_parsePrefixType();
return this.finishNode(node, "NullableTypeAnnotation");
}
return this.flow_parsePostfixType();
};
pp.flow_parseIntersectionType = function () {
var node = this.startNode();
var type = this.flow_parsePrefixType();
node.types = [type];
while (this.eat(tt.bitwiseAND)) {
node.types.push(this.flow_parsePrefixType());
}
return node.types.length === 1 ? type : this.finishNode(node, "IntersectionTypeAnnotation");
};
pp.flow_parseUnionType = function () {
var node = this.startNode();
var type = this.flow_parseIntersectionType();
node.types = [type];
while (this.eat(tt.bitwiseOR)) {
node.types.push(this.flow_parseIntersectionType());
}
return node.types.length === 1 ? type : this.finishNode(node, "UnionTypeAnnotation");
};
pp.flow_parseType = function () {
var oldInType = this.inType;
this.inType = true;
var type = this.flow_parseUnionType();
this.inType = oldInType;
return type;
};
pp.flow_parseTypeAnnotation = function () {
var node = this.startNode();
var oldInType = this.inType;
this.inType = true;
this.expect(tt.colon);
node.typeAnnotation = this.flow_parseType();
this.inType = oldInType;
return this.finishNode(node, "TypeAnnotation");
};
pp.flow_parseTypeAnnotatableIdentifier = function (requireTypeAnnotation, canBeOptionalParam) {
var node = this.startNode();
var ident = this.parseIdent();
var isOptionalParam = false;
if (canBeOptionalParam && this.eat(tt.question)) {
this.expect(tt.question);
isOptionalParam = true;
}
if (requireTypeAnnotation || this.type === tt.colon) {
ident.typeAnnotation = this.flow_parseTypeAnnotation();
this.finishNode(ident, ident.type);
}
if (isOptionalParam) {
ident.optional = true;
this.finishNode(ident, ident.type);
}
return ident;
};
acorn.plugins.flow = function (instance) {
// function name(): string {}
instance.extend("parseFunctionBody", function (inner) {
return function (node, allowExpression) {
if (this.type === tt.colon) {
node.returnType = this.flow_parseTypeAnnotation();
}
return inner.call(this, node, allowExpression);
};
});
instance.extend("parseExpressionStatement", function (inner) {
return function (node, expr) {
if (expr.type === "Identifier") {
if (expr.name === "declare") {
if (this.type === tt._class || this.type === tt.name || this.type === tt._function || this.type === tt._var) {
return this.flow_parseDeclare(node);
}
} else if (this.type === tt.name) {
if (expr.name === "interface") {
return this.flow_parseInterface(node);
} else if (expr.name === "type") {
return this.flow_parseTypeAlias(node);
}
}
}
return inner.call(this, node, expr);
};
});
instance.extend("parseParenItem", function (inner) {
return function (node, start) {
if (this.type === tt.colon) {
var typeCastNode = this.startNodeAt(start);
typeCastNode.expression = node;
typeCastNode.typeAnnotation = this.flow_parseTypeAnnotation();
return this.finishNode(typeCastNode, "TypeCastExpression");
} else {
return node;
}
};
});
instance.extend("parseClassId", function (inner) {
return function (node, isStatement) {
inner.call(this, node, isStatement);
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
}
};
});
instance.extend("readToken", function(inner) {
return function(code) {
if (this.inType && (code === 62 || code === 60)) {
return this.finishOp(tt.relational, 1);
} else {
return inner.call(this, code);
}
};
});
instance.extend("parseParenArrowList", function (inner) {
return function (start, exprList, isAsync) {
for (var i = 0; i < exprList.length; i++) {
var listItem = exprList[i];
if (listItem.type === "TypeCastExpression") {
var expr = listItem.expression;
expr.typeAnnotation = listItem.typeAnnotation;
exprList[i] = expr;
}
}
return inner.call(this, start, exprList, isAsync);
};
});
instance.extend("parseClassMethod", function (inner) {
return function (classBody, method, isGenerator, isAsync) {
var classProperty = false;
if (this.type === tt.colon) {
method.typeAnnotation = this.flow_parseTypeAnnotation();
classProperty = true;
}
if (classProperty) {
this.semicolon();
classBody.body.push(this.finishNode(method, "ClassProperty"));
} else {
var typeParameters;
if (this.isRelational("<")) {
typeParameters = this.flow_parseTypeParameterDeclaration();
}
method.value = this.parseMethod(isGenerator, isAsync);
method.value.typeParameters = typeParameters;
classBody.body.push(this.finishNode(method, "MethodDefinition"));
}
};
});
instance.extend("parseClassSuper", function (inner) {
return function (node, isStatement) {
inner.call(this, node, isStatement);
if (node.superClass && this.isRelational("<")) {
node.superTypeParameters = this.flow_parseTypeParameterInstantiation();
}
if (this.isContextual("implements")) {
this.next();
var implemented = node.implements = [];
do {
var node = this.startNode();
node.id = this.parseIdent();
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterInstantiation();
} else {
node.typeParameters = null;
}
implemented.push(this.finishNode(node, "ClassImplements"));
} while(this.eat(tt.comma));
}
};
});
instance.extend("parseObjPropValue", function (inner) {
return function (prop) {
var typeParameters;
if (this.isRelational("<")) {
typeParameters = this.flow_parseTypeParameterDeclaration();
if (this.type !== tt.parenL) this.unexpected();
}
inner.apply(this, arguments);
prop.value.typeParameters = typeParameters;
};
});
instance.extend("parseAssignableListItemTypes", function (inner) {
return function (param) {
if (this.eat(tt.question)) {
param.optional = true;
}
if (this.type === tt.colon) {
param.typeAnnotation = this.flow_parseTypeAnnotation();
}
this.finishNode(param, param.type);
return param;
};
});
instance.extend("parseImportSpecifiers", function (inner) {
return function (node) {
node.isType = false;
if (this.isContextual("type")) {
var start = this.currentPos();
var typeId = this.parseIdent();
if ((this.type === tt.name && this.value !== "from") || this.type === tt.braceL || this.type === tt.star) {
node.isType = true;
} else {
node.specifiers.push(this.parseImportSpecifierDefault(typeId, start));
if (this.isContextual("from")) return;
this.eat(tt.comma);
}
}
inner.call(this, node);
};
});
// function foo<T>() {}
instance.extend("parseFunctionParams", function (inner) {
return function (node) {
if (this.isRelational("<")) {
node.typeParameters = this.flow_parseTypeParameterDeclaration();
}
inner.call(this, node);
};
});
// var foo: string = bar;
instance.extend("parseVarHead", function (inner) {
return function (decl) {
inner.call(this, decl);
if (this.type === tt.colon) {
decl.id.typeAnnotation = this.flow_parseTypeAnnotation();
this.finishNode(decl.id, decl.id.type);
}
};
});
}

661
plugins/jsx.js Normal file
View File

@ -0,0 +1,661 @@
var acorn = require("../acorn");
var tt = acorn.tokTypes;
var tc = acorn.tokContexts;
tc.j_oTag = new acorn.TokContext("<tag", false);
tc.j_cTag = new acorn.TokContext("</tag", false);
tc.j_expr = new acorn.TokContext("<tag>...</tag>", true, true);
tt.jsxName = new acorn.TokenType("jsxName");
tt.jsxText = new acorn.TokenType("jsxText", {beforeExpr: true});
tt.jsxTagStart = new acorn.TokenType("jsxTagStart");
tt.jsxTagEnd = new acorn.TokenType("jsxTagEnd");
tt.jsxTagStart.updateContext = function() {
this.context.push(tc.j_expr); // treat as beginning of JSX expression
this.context.push(tc.j_oTag); // start opening tag context
this.exprAllowed = false;
};
tt.jsxTagEnd.updateContext = function(prevType) {
var out = this.context.pop();
if (out === tc.j_oTag && prevType === tt.slash || out === tc.j_cTag) {
this.context.pop();
this.exprAllowed = this.curContext() === tc.j_expr;
} else {
this.exprAllowed = true;
}
};
var pp = acorn.Parser.prototype;
// Reads inline JSX contents token.
pp.jsx_readToken = function() {
var out = "", chunkStart = this.pos;
for (;;) {
if (this.pos >= this.input.length)
this.raise(this.start, "Unterminated JSX contents");
var ch = this.input.charCodeAt(this.pos);
switch (ch) {
case 60: // '<'
case 123: // '{'
if (this.pos === this.start) {
if (ch === 60 && this.exprAllowed) {
++this.pos;
return this.finishToken(tt.jsxTagStart);
}
return this.getTokenFromCode(ch);
}
out += this.input.slice(chunkStart, this.pos);
return this.finishToken(tt.jsxText, out);
case 38: // '&'
out += this.input.slice(chunkStart, this.pos);
out += this.jsx_readEntity();
chunkStart = this.pos;
break;
default:
if (acorn.isNewLine(ch)) {
out += this.input.slice(chunkStart, this.pos);
++this.pos;
if (ch === 13 && this.input.charCodeAt(this.pos) === 10) {
++this.pos;
out += "\n";
} else {
out += String.fromCharCode(ch);
}
if (this.options.locations) {
++this.curLine;
this.lineStart = this.pos;
}
chunkStart = this.pos;
} else {
++this.pos;
}
}
}
};
pp.jsx_readString = function(quote) {
var out = "", chunkStart = ++this.pos;
for (;;) {
if (this.pos >= this.input.length)
this.raise(this.start, "Unterminated string constant");
var ch = this.input.charCodeAt(this.pos);
if (ch === quote) break;
if (ch === 38) { // '&'
out += this.input.slice(chunkStart, this.pos);
out += this.jsx_readEntity();
chunkStart = this.pos;
} else {
++this.pos;
}
}
out += this.input.slice(chunkStart, this.pos++);
return this.finishToken(tt.string, out);
};
var XHTMLEntities = {
quot: '\u0022',
amp: '&',
apos: '\u0027',
lt: '<',
gt: '>',
nbsp: '\u00A0',
iexcl: '\u00A1',
cent: '\u00A2',
pound: '\u00A3',
curren: '\u00A4',
yen: '\u00A5',
brvbar: '\u00A6',
sect: '\u00A7',
uml: '\u00A8',
copy: '\u00A9',
ordf: '\u00AA',
laquo: '\u00AB',
not: '\u00AC',
shy: '\u00AD',
reg: '\u00AE',
macr: '\u00AF',
deg: '\u00B0',
plusmn: '\u00B1',
sup2: '\u00B2',
sup3: '\u00B3',
acute: '\u00B4',
micro: '\u00B5',
para: '\u00B6',
middot: '\u00B7',
cedil: '\u00B8',
sup1: '\u00B9',
ordm: '\u00BA',
raquo: '\u00BB',
frac14: '\u00BC',
frac12: '\u00BD',
frac34: '\u00BE',
iquest: '\u00BF',
Agrave: '\u00C0',
Aacute: '\u00C1',
Acirc: '\u00C2',
Atilde: '\u00C3',
Auml: '\u00C4',
Aring: '\u00C5',
AElig: '\u00C6',
Ccedil: '\u00C7',
Egrave: '\u00C8',
Eacute: '\u00C9',
Ecirc: '\u00CA',
Euml: '\u00CB',
Igrave: '\u00CC',
Iacute: '\u00CD',
Icirc: '\u00CE',
Iuml: '\u00CF',
ETH: '\u00D0',
Ntilde: '\u00D1',
Ograve: '\u00D2',
Oacute: '\u00D3',
Ocirc: '\u00D4',
Otilde: '\u00D5',
Ouml: '\u00D6',
times: '\u00D7',
Oslash: '\u00D8',
Ugrave: '\u00D9',
Uacute: '\u00DA',
Ucirc: '\u00DB',
Uuml: '\u00DC',
Yacute: '\u00DD',
THORN: '\u00DE',
szlig: '\u00DF',
agrave: '\u00E0',
aacute: '\u00E1',
acirc: '\u00E2',
atilde: '\u00E3',
auml: '\u00E4',
aring: '\u00E5',
aelig: '\u00E6',
ccedil: '\u00E7',
egrave: '\u00E8',
eacute: '\u00E9',
ecirc: '\u00EA',
euml: '\u00EB',
igrave: '\u00EC',
iacute: '\u00ED',
icirc: '\u00EE',
iuml: '\u00EF',
eth: '\u00F0',
ntilde: '\u00F1',
ograve: '\u00F2',
oacute: '\u00F3',
ocirc: '\u00F4',
otilde: '\u00F5',
ouml: '\u00F6',
divide: '\u00F7',
oslash: '\u00F8',
ugrave: '\u00F9',
uacute: '\u00FA',
ucirc: '\u00FB',
uuml: '\u00FC',
yacute: '\u00FD',
thorn: '\u00FE',
yuml: '\u00FF',
OElig: '\u0152',
oelig: '\u0153',
Scaron: '\u0160',
scaron: '\u0161',
Yuml: '\u0178',
fnof: '\u0192',
circ: '\u02C6',
tilde: '\u02DC',
Alpha: '\u0391',
Beta: '\u0392',
Gamma: '\u0393',
Delta: '\u0394',
Epsilon: '\u0395',
Zeta: '\u0396',
Eta: '\u0397',
Theta: '\u0398',
Iota: '\u0399',
Kappa: '\u039A',
Lambda: '\u039B',
Mu: '\u039C',
Nu: '\u039D',
Xi: '\u039E',
Omicron: '\u039F',
Pi: '\u03A0',
Rho: '\u03A1',
Sigma: '\u03A3',
Tau: '\u03A4',
Upsilon: '\u03A5',
Phi: '\u03A6',
Chi: '\u03A7',
Psi: '\u03A8',
Omega: '\u03A9',
alpha: '\u03B1',
beta: '\u03B2',
gamma: '\u03B3',
delta: '\u03B4',
epsilon: '\u03B5',
zeta: '\u03B6',
eta: '\u03B7',
theta: '\u03B8',
iota: '\u03B9',
kappa: '\u03BA',
lambda: '\u03BB',
mu: '\u03BC',
nu: '\u03BD',
xi: '\u03BE',
omicron: '\u03BF',
pi: '\u03C0',
rho: '\u03C1',
sigmaf: '\u03C2',
sigma: '\u03C3',
tau: '\u03C4',
upsilon: '\u03C5',
phi: '\u03C6',
chi: '\u03C7',
psi: '\u03C8',
omega: '\u03C9',
thetasym: '\u03D1',
upsih: '\u03D2',
piv: '\u03D6',
ensp: '\u2002',
emsp: '\u2003',
thinsp: '\u2009',
zwnj: '\u200C',
zwj: '\u200D',
lrm: '\u200E',
rlm: '\u200F',
ndash: '\u2013',
mdash: '\u2014',
lsquo: '\u2018',
rsquo: '\u2019',
sbquo: '\u201A',
ldquo: '\u201C',
rdquo: '\u201D',
bdquo: '\u201E',
dagger: '\u2020',
Dagger: '\u2021',
bull: '\u2022',
hellip: '\u2026',
permil: '\u2030',
prime: '\u2032',
Prime: '\u2033',
lsaquo: '\u2039',
rsaquo: '\u203A',
oline: '\u203E',
frasl: '\u2044',
euro: '\u20AC',
image: '\u2111',
weierp: '\u2118',
real: '\u211C',
trade: '\u2122',
alefsym: '\u2135',
larr: '\u2190',
uarr: '\u2191',
rarr: '\u2192',
darr: '\u2193',
harr: '\u2194',
crarr: '\u21B5',
lArr: '\u21D0',
uArr: '\u21D1',
rArr: '\u21D2',
dArr: '\u21D3',
hArr: '\u21D4',
forall: '\u2200',
part: '\u2202',
exist: '\u2203',
empty: '\u2205',
nabla: '\u2207',
isin: '\u2208',
notin: '\u2209',
ni: '\u220B',
prod: '\u220F',
sum: '\u2211',
minus: '\u2212',
lowast: '\u2217',
radic: '\u221A',
prop: '\u221D',
infin: '\u221E',
ang: '\u2220',
and: '\u2227',
or: '\u2228',
cap: '\u2229',
cup: '\u222A',
'int': '\u222B',
there4: '\u2234',
sim: '\u223C',
cong: '\u2245',
asymp: '\u2248',
ne: '\u2260',
equiv: '\u2261',
le: '\u2264',
ge: '\u2265',
sub: '\u2282',
sup: '\u2283',
nsub: '\u2284',
sube: '\u2286',
supe: '\u2287',
oplus: '\u2295',
otimes: '\u2297',
perp: '\u22A5',
sdot: '\u22C5',
lceil: '\u2308',
rceil: '\u2309',
lfloor: '\u230A',
rfloor: '\u230B',
lang: '\u2329',
rang: '\u232A',
loz: '\u25CA',
spades: '\u2660',
clubs: '\u2663',
hearts: '\u2665',
diams: '\u2666'
};
var hexNumber = /^[\da-fA-F]+$/;
var decimalNumber = /^\d+$/;
pp.jsx_readEntity = function() {
var str = "", count = 0, entity;
var ch = this.input[this.pos];
if (ch !== "&")
this.raise(this.pos, "Entity must start with an ampersand");
var startPos = ++this.pos;
while (this.pos < this.input.length && count++ < 10) {
ch = this.input[this.pos++];
if (ch === ";") {
if (str[0] === "#") {
if (str[1] === "x") {
str = str.substr(2);
if (hexNumber.test(str))
entity = String.fromCharCode(parseInt(str, 16));
} else {
str = str.substr(1);
if (decimalNumber.test(str))
entity = String.fromCharCode(parseInt(str, 10));
}
} else {
entity = XHTMLEntities[str];
}
break;
}
str += ch;
}
if (!entity) {
this.pos = startPos;
return "&";
}
return entity;
};
// Read a JSX identifier (valid tag or attribute name).
//
// Optimized version since JSX identifiers can't contain
// escape characters and so can be read as single slice.
// Also assumes that first character was already checked
// by isIdentifierStart in readToken.
pp.jsx_readWord = function() {
var ch, start = this.pos;
do {
ch = this.input.charCodeAt(++this.pos);
} while (acorn.isIdentifierChar(ch) || ch === 45); // '-'
return this.finishToken(tt.jsxName, this.input.slice(start, this.pos));
};
// Transforms JSX element name to string.
function getQualifiedJSXName(object) {
if (object.type === "JSXIdentifier")
return object.name;
if (object.type === "JSXNamespacedName")
return object.namespace.name + ':' + object.name.name;
if (object.type === "JSXMemberExpression")
return getQualifiedJSXName(object.object) + '.' +
getQualifiedJSXName(object.property);
}
// Parse next token as JSX identifier
pp.jsx_parseIdentifier = function() {
var node = this.startNode();
if (this.type === tt.jsxName)
node.name = this.value;
else if (this.type.keyword)
node.name = this.type.keyword;
else
this.unexpected();
this.next();
return this.finishNode(node, "JSXIdentifier");
};
// Parse namespaced identifier.
pp.jsx_parseNamespacedName = function() {
var start = this.currentPos();
var name = this.jsx_parseIdentifier();
if (!this.eat(tt.colon)) return name;
var node = this.startNodeAt(start);
node.namespace = name;
node.name = this.jsx_parseIdentifier();
return this.finishNode(node, "JSXNamespacedName");
};
// Parses element name in any form - namespaced, member
// or single identifier.
pp.jsx_parseElementName = function() {
var start = this.currentPos();
var node = this.jsx_parseNamespacedName();
while (this.eat(tt.dot)) {
var newNode = this.startNodeAt(start);
newNode.object = node;
newNode.property = this.jsx_parseIdentifier();
node = this.finishNode(newNode, "JSXMemberExpression");
}
return node;
};
// Parses any type of JSX attribute value.
pp.jsx_parseAttributeValue = function() {
switch (this.type) {
case tt.braceL:
var node = this.jsx_parseExpressionContainer();
if (node.expression.type === "JSXEmptyExpression")
this.raise(node.start, "JSX attributes must only be assigned a non-empty expression");
return node;
case tt.jsxTagStart:
case tt.string:
return this.parseExprAtom();
default:
this.raise(this.start, "JSX value should be either an expression or a quoted JSX text");
}
};
// JSXEmptyExpression is unique type since it doesn't actually parse anything,
// and so it should start at the end of last read token (left brace) and finish
// at the beginning of the next one (right brace).
pp.jsx_parseEmptyExpression = function() {
var tmp = this.start;
this.start = this.lastTokEnd;
this.lastTokEnd = tmp;
tmp = this.startLoc;
this.startLoc = this.lastTokEndLoc;
this.lastTokEndLoc = tmp;
return this.finishNode(this.startNode(), "JSXEmptyExpression");
};
// Parses JSX expression enclosed into curly brackets.
pp.jsx_parseExpressionContainer = function() {
var node = this.startNode();
this.next();
node.expression = this.type === tt.braceR
? this.jsx_parseEmptyExpression()
: this.parseExpression();
this.expect(tt.braceR);
return this.finishNode(node, "JSXExpressionContainer");
};
// Parses following JSX attribute name-value pair.
pp.jsx_parseAttribute = function() {
var node = this.startNode();
if (this.eat(tt.braceL)) {
this.expect(tt.ellipsis);
node.argument = this.parseMaybeAssign();
this.expect(tt.braceR);
return this.finishNode(node, "JSXSpreadAttribute");
}
node.name = this.jsx_parseNamespacedName();
node.value = this.eat(tt.eq) ? this.jsx_parseAttributeValue() : null;
return this.finishNode(node, "JSXAttribute");
};
// Parses JSX opening tag starting after '<'.
pp.jsx_parseOpeningElementAt = function(start) {
var node = this.startNodeAt(start);
node.attributes = [];
node.name = this.jsx_parseElementName();
while (this.type !== tt.slash && this.type !== tt.jsxTagEnd)
node.attributes.push(this.jsx_parseAttribute());
node.selfClosing = this.eat(tt.slash);
this.expect(tt.jsxTagEnd);
return this.finishNode(node, "JSXOpeningElement");
};
// Parses JSX closing tag starting after '</'.
pp.jsx_parseClosingElementAt = function(start) {
var node = this.startNodeAt(start);
node.name = this.jsx_parseElementName();
this.expect(tt.jsxTagEnd);
return this.finishNode(node, "JSXClosingElement");
};
// Parses entire JSX element, including it's opening tag
// (starting after '<'), attributes, contents and closing tag.
pp.jsx_parseElementAt = function(start) {
var node = this.startNodeAt(start);
var children = [];
var openingElement = this.jsx_parseOpeningElementAt(start);
var closingElement = null;
if (!openingElement.selfClosing) {
contents: for (;;) {
switch (this.type) {
case tt.jsxTagStart:
start = this.currentPos();
this.next();
if (this.eat(tt.slash)) {
closingElement = this.jsx_parseClosingElementAt(start);
break contents;
}
children.push(this.jsx_parseElementAt(start));
break;
case tt.jsxText:
children.push(this.parseExprAtom());
break;
case tt.braceL:
children.push(this.jsx_parseExpressionContainer());
break;
default:
this.unexpected();
}
}
if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name))
this.raise(
closingElement.start,
"Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">");
}
node.openingElement = openingElement;
node.closingElement = closingElement;
node.children = children;
return this.finishNode(node, "JSXElement");
};
// Parses entire JSX element from current position.
pp.jsx_parseElement = function() {
var start = this.currentPos();
this.next();
return this.jsx_parseElementAt(start);
};
acorn.plugins.jsx = function(instance) {
instance.extend("parseExprAtom", function(inner) {
return function(refShortHandDefaultPos) {
if (this.type === tt.jsxText)
return this.parseLiteral(this.value);
else if (this.type === tt.jsxTagStart)
return this.jsx_parseElement();
else
return inner.call(this, refShortHandDefaultPos);
};
});
instance.extend("readToken", function(inner) {
return function(code) {
if (!this.inType) {
var context = this.curContext();
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 (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) {
++this.pos;
return this.finishToken(tt.jsxTagStart);
}
}
return inner.call(this, code);
};
});
instance.extend("updateContext", function(inner) {
return function(prevType) {
if (this.type == tt.braceL) {
var curContext = this.curContext();
if (curContext == tc.j_oTag) this.context.push(tc.b_expr);
else if (curContext == tc.j_expr) this.context.push(tc.b_tmpl);
else inner.call(this, prevType);
this.exprAllowed = true;
} else if (this.type === tt.slash && prevType === tt.jsxTagStart) {
this.context.length -= 2; // do not consider JSX expr -> JSX open tag -> ... anymore
this.context.push(tc.j_cTag); // reconsider as closing tag context
this.exprAllowed = false;
} else {
return inner.call(this, prevType);
}
};
});
}

View File

@ -33,7 +33,7 @@
else callback("fail", test.code,
"Expected error message: " + test.error + "\nGot error message: " + e.message);
} else {
callback("error", test.code, e.message || e.toString());
callback("error", test.code, e.stack || e.toString());
}
continue
}

View File

@ -5,6 +5,9 @@
driver = require("./driver.js");
require("./tests.js");
require("./tests-harmony.js");
require("./tests-flow.js");
require("./tests-babel.js");
require("./tests-jsx.js");
} else {
driver = window;
}
@ -49,17 +52,6 @@
config: {
parse: (typeof require === "undefined" ? window.acorn : require("../acorn.js")).parse
}
},
Loose: {
config: {
parse: (typeof require === "undefined" ? window.acorn : require("../acorn_loose")).parse_dammit,
loose: true,
filter: function (test) {
var opts = test.options || {};
if (opts.loose === false) return false;
return (opts.ecmaVersion || 5) <= 6;
}
}
}
};

2057
test/tests-babel.js Normal file

File diff suppressed because it is too large Load Diff

11125
test/tests-flow.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6560,7 +6560,7 @@ test("class A {get() {}}", {
end: {line: 1, column: 17}
}
},
kind: "",
kind: "method",
static: false,
loc: {
start: {line: 1, column: 9},
@ -6632,7 +6632,7 @@ test("class A { static get() {}}", {
end: {line: 1, column: 25}
}
},
kind: "",
kind: "method",
static: true,
loc: {
start: {line: 1, column: 10},
@ -7027,7 +7027,7 @@ test("class A {set(v) {};}", {
end: {line: 1, column: 18}
}
},
kind: "",
kind: "method",
static: false,
loc: {
start: {line: 1, column: 9},
@ -7106,7 +7106,7 @@ test("class A { static set(v) {};}", {
end: {line: 1, column: 26}
}
},
kind: "",
kind: "method",
static: true,
loc: {
start: {line: 1, column: 10},
@ -7207,7 +7207,7 @@ test("class A {*gen(v) { yield v; }}", {
end: {line: 1, column: 29}
}
},
kind: "",
kind: "method",
static: false,
loc: {
start: {line: 1, column: 9},
@ -7308,7 +7308,7 @@ test("class A { static *gen(v) { yield v; }}", {
end: {line: 1, column: 37}
}
},
kind: "",
kind: "method",
static: true,
loc: {
start: {line: 1, column: 10},
@ -7391,8 +7391,7 @@ test("\"use strict\"; (class A {constructor() { super() }})", {
expression: {
type: "CallExpression",
callee: {
type: "Identifier",
name: "super",
type: "SuperExpression",
loc: {
start: {line: 1, column: 40},
end: {line: 1, column: 45}
@ -7421,7 +7420,7 @@ test("\"use strict\"; (class A {constructor() { super() }})", {
end: {line: 1, column: 49}
}
},
kind: "",
kind: "constructor",
static: false,
loc: {
start: {line: 1, column: 24},
@ -7454,6 +7453,36 @@ test("\"use strict\"; (class A {constructor() { super() }})", {
locations: true
});
test("class A {'constructor'() {}}", {
type: "Program",
body: [{
type: "ClassDeclaration",
id: {type: "Identifier", name: "A"},
superClass: null,
body: {
type: "ClassBody",
body: [{
type: "MethodDefinition",
computed: false,
key: {type: "Literal", value: "constructor"},
static: false,
kind: "constructor",
value: {
type: "FunctionExpression",
id: null,
generator: false,
expression: false,
params: [],
body: {
type: "BlockStatement",
body: []
}
}
}]
}
}]
}, {ecmaVersion: 6});
test("class A {static foo() {}}", {
type: "Program",
body: [{
@ -7499,7 +7528,7 @@ test("class A {static foo() {}}", {
end: {line: 1, column: 24}
}
},
kind: "",
kind: "method",
static: true,
loc: {
start: {line: 1, column: 9},
@ -7572,7 +7601,7 @@ test("class A {foo() {} static bar() {}}", {
end: {line: 1, column: 17}
}
},
kind: "",
kind: "method",
static: false,
loc: {
start: {line: 1, column: 9},
@ -7609,7 +7638,7 @@ test("class A {foo() {} static bar() {}}", {
end: {line: 1, column: 33}
}
},
kind: "",
kind: "method",
static: true,
loc: {
start: {line: 1, column: 18},
@ -7693,8 +7722,7 @@ test("\"use strict\"; (class A { static constructor() { super() }})", {
expression: {
type: "CallExpression",
callee: {
type: "Identifier",
name: "super",
type: "SuperExpression",
loc: {
start: {line: 1, column: 48},
end: {line: 1, column: 53}
@ -7723,7 +7751,7 @@ test("\"use strict\"; (class A { static constructor() { super() }})", {
end: {line: 1, column: 57}
}
},
kind: "",
kind: "method",
static: true,
loc: {
start: {line: 1, column: 25},
@ -7802,7 +7830,7 @@ test("class A { foo() {} bar() {}}", {
end: {line: 1, column: 18}
}
},
kind: "",
kind: "method",
static: false,
loc: {
start: {line: 1, column: 10},
@ -7839,7 +7867,7 @@ test("class A { foo() {} bar() {}}", {
end: {line: 1, column: 27}
}
},
kind: "",
kind: "method",
static: false,
loc: {
start: {line: 1, column: 19},
@ -8450,7 +8478,7 @@ test("class A { static [foo]() {} }", {
},
name: "foo"
},
kind: "",
kind: "method",
value: {
type: "FunctionExpression",
loc: {
@ -8717,7 +8745,7 @@ test("class A { foo() {} get foo() {} }",{
},
name: "foo"
},
kind: "",
kind: "method",
value: {
type: "FunctionExpression",
loc: {
@ -9582,7 +9610,7 @@ test("class A {[x]() {}}", {
},
name: "x"
},
kind: "",
kind: "method",
value: {
type: "FunctionExpression",
loc: {
@ -10324,7 +10352,7 @@ test("(class {f({x} = {x: 10}) {}})", {
end: {line: 1, column: 27}
}
},
kind: "",
kind: "method",
static: false,
loc: {
start: {line: 1, column: 8},
@ -14947,7 +14975,7 @@ test("class A { static() {} }", {
name: "static"
},
static: false,
kind: "",
kind: "method",
value: {
type: "FunctionExpression",
range: [16, 21],
@ -15044,7 +15072,7 @@ test("class A { *static() {} }", {
name: "static"
},
static: false,
kind: "",
kind: "method",
value: {
type: "FunctionExpression",
range: [17, 22],

3647
test/tests-jsx.js Normal file

File diff suppressed because it is too large Load Diff