better parsing of decorators - support class expressions

This commit is contained in:
Sebastian McKenzie 2015-03-26 00:58:38 +11:00
parent e52af24999
commit f5f77d4720
2 changed files with 33 additions and 24 deletions

View File

@ -335,8 +335,13 @@ pp.parseExprAtom = function(refShorthandDefaultPos) {
this.next() this.next()
return this.parseFunction(node, false) return this.parseFunction(node, false)
case tt.at:
this.parseDecorators()
case tt._class: case tt._class:
return this.parseClass(this.startNode(), false) node = this.startNode()
this.takeDecorators(node)
return this.parseClass(node, false)
case tt._new: case tt._new:
return this.parseNew() return this.parseNew()

View File

@ -53,19 +53,11 @@ pp.parseStatement = function(declaration, topLevel) {
return this.parseFunctionStatement(node) return this.parseFunctionStatement(node)
case tt.at: case tt.at:
while (this.type === tt.at) { this.parseDecorators()
this.decorators.push(this.parseDecorator());
}
if (this.type !== tt._class) {
this.raise(this.start, "Leading decorators must be attached to a class declaration");
}
case tt._class: case tt._class:
if (!declaration) this.unexpected() if (!declaration) this.unexpected()
if (this.decorators.length) { this.takeDecorators(node)
node.decorators = this.decorators
this.decorators = []
}
return this.parseClass(node, true) return this.parseClass(node, true)
case tt._if: return this.parseIfStatement(node) case tt._if: return this.parseIfStatement(node)
@ -90,14 +82,10 @@ pp.parseStatement = function(declaration, topLevel) {
return starttype === tt._import ? this.parseImport(node) : this.parseExport(node) return starttype === tt._import ? this.parseImport(node) : this.parseExport(node)
case tt.name: case tt.name:
if (this.options.features["es7.asyncFunctions"] && this.value === "async") { if (this.options.features["es7.asyncFunctions"] && this.value === "async" && this.lookahead().type === tt._function) {
// check to see if `function ` appears after this token, this is this.next();
// pretty hacky this.expect(tt._function);
if (this.lookahead().type === tt._function) { return this.parseFunction(node, true, false, true);
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 // If the statement does not start with a statement keyword or a
@ -113,7 +101,26 @@ pp.parseStatement = function(declaration, topLevel) {
} }
} }
pp.takeDecorators = function(node) {
if (this.decorators.length) {
node.decorators = this.decorators
this.decorators = []
}
}
pp.parseDecorators = function() {
while (this.type === tt.at) {
this.decorators.push(this.parseDecorator());
}
if (this.type !== tt._class) {
this.raise(this.start, "Leading decorators must be attached to a class declaration");
}
}
pp.parseDecorator = function() { pp.parseDecorator = function() {
if (!this.options.features["es7.decorators"]) {
this.unexpected()
}
let node = this.startNode() let node = this.startNode()
this.next() this.next()
node.expression = this.parseMaybeAssign() node.expression = this.parseMaybeAssign()
@ -466,10 +473,7 @@ pp.parseClass = function(node, isStatement) {
continue; continue;
} }
var method = this.startNode() var method = this.startNode()
if (this.options.features["es7.decorators"] && decorators.length) { this.takeDecorators(method)
method.decorators = decorators
decorators = []
}
var isGenerator = this.eat(tt.star), isAsync = false var isGenerator = this.eat(tt.star), isAsync = false
this.parsePropertyName(method) this.parsePropertyName(method)
if (this.options.features["es7.classProperties"] && this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" && if (this.options.features["es7.classProperties"] && this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" &&
@ -509,7 +513,7 @@ pp.parseClass = function(node, isStatement) {
this.parseClassMethod(classBody, method, isGenerator, isAsync) this.parseClassMethod(classBody, method, isGenerator, isAsync)
} }
if (decorators.length) { if (decorators.length) {
raise(this.start, "You have trailing decorators with no method"); this.raise(this.start, "You have trailing decorators with no method");
} }
node.body = this.finishNode(classBody, "ClassBody") node.body = this.finishNode(classBody, "ClassBody")
return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression")