diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 74d09fd8a05f..9df262f9cf13 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -2306,20 +2306,23 @@ export default class ExpressionParser extends LValParser { parseIdentifierName(pos: number, liberal?: boolean): string { let name: string; - if (this.match(tt.name)) { + const { start, type } = this.state; + + if (type === tt.name) { name = this.state.value; - } else if (this.state.type.keyword) { - name = this.state.type.keyword; + } else if (type.keyword) { + name = type.keyword; // `class` and `function` keywords push function-type token context into this.context. // But there is no chance to pop the context if the keyword is consumed // as an identifier such as a property name. - const context = this.state.context; + const curContext = this.curContext(); if ( - (name === "class" || name === "function") && - context[context.length - 1].token === "function" + (type === tt._class || type === tt._function) && + (curContext === ct.functionStatement || + curContext === ct.functionExpression) ) { - context.pop(); + this.state.context.pop(); } } else { throw this.unexpected(); @@ -2330,12 +2333,7 @@ export default class ExpressionParser extends LValParser { // This will prevent this.next() from throwing about unexpected escapes. this.state.type = tt.name; } else { - this.checkReservedWord( - name, - this.state.start, - !!this.state.type.keyword, - false, - ); + this.checkReservedWord(name, start, !!type.keyword, false); } this.next(); diff --git a/packages/babel-parser/src/tokenizer/context.js b/packages/babel-parser/src/tokenizer/context.js index a53ec3d11040..f93c19971efb 100644 --- a/packages/babel-parser/src/tokenizer/context.js +++ b/packages/babel-parser/src/tokenizer/context.js @@ -104,10 +104,7 @@ tt.incDec.updateContext = function () { }; tt._function.updateContext = tt._class.updateContext = function (prevType) { - if (prevType === tt.dot || prevType === tt.questionDot) { - // when function/class follows dot/questionDot, it is part of - // (optional)MemberExpression, then we don't need to push new token context - } else if ( + if ( prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else && @@ -134,10 +131,6 @@ tt.backQuote.updateContext = function () { this.state.exprAllowed = false; }; -tt.star.updateContext = function () { - this.state.exprAllowed = false; -}; - // we don't need to update context for tt.braceBarL because we do not pop context for tt.braceBarR tt.braceHashL.updateContext = function () { this.state.context.push(types.recordExpression); diff --git a/packages/babel-parser/src/tokenizer/types.js b/packages/babel-parser/src/tokenizer/types.js index 535e16bd1204..ca67cb0732cf 100644 --- a/packages/babel-parser/src/tokenizer/types.js +++ b/packages/babel-parser/src/tokenizer/types.js @@ -155,7 +155,8 @@ export const types: { [name: string]: TokenType } = { plusMin: new TokenType("+/-", { beforeExpr, binop: 9, prefix, startsExpr }), // startsExpr: required by v8intrinsic plugin modulo: new TokenType("%", { beforeExpr, binop: 10, startsExpr }), - star: createBinop("*", 10), + // unset `beforeExpr` as it can be `function *` + star: new TokenType("*", { binop: 10 }), slash: createBinop("/", 10), exponent: new TokenType("**", { beforeExpr,