diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index d547ebcec5..1ef98a1f87 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -3,8 +3,13 @@ import * as N from "../types"; import { types as tt, type TokenType } from "../tokenizer/types"; import ExpressionParser from "./expression"; -import { isIdentifierChar } from "../util/identifier"; +import { + isIdentifierChar, + isIdentifierStart, + keywordRelationalOperator, +} from "../util/identifier"; import { lineBreak, skipWhiteSpace } from "../util/whitespace"; +import * as charCodes from "charcodes"; // Reused empty array added for node fields that are always empty. @@ -71,6 +76,39 @@ export default class StatementParser extends ExpressionParser { return this.finishNode(node, "InterpreterDirective"); } + isLet(declaration?: boolean): boolean { + if (!this.isContextual("let")) { + return false; + } + skipWhiteSpace.lastIndex = this.state.pos; + const skip = skipWhiteSpace.exec(this.state.input); + // $FlowIgnore + const next = this.state.pos + skip[0].length; + const nextCh = this.state.input.charCodeAt(next); + if ( + (nextCh === charCodes.leftCurlyBrace && + !lineBreak.test(this.state.input.slice(this.state.end, next))) || + nextCh === charCodes.leftSquareBracket + ) { + return true; + } + if (isIdentifierStart(nextCh)) { + if ( + !declaration && + lineBreak.test(this.state.input.slice(this.state.end, next)) + ) { + return false; + } + let pos = next + 1; + while (isIdentifierChar(this.state.input.charCodeAt(pos))) { + ++pos; + } + const ident = this.state.input.slice(next, pos); + if (!keywordRelationalOperator.test(ident)) return true; + } + return false; + } + // Parse a single statement. // // If expecting a statement and finding a slash operator, parse a @@ -86,8 +124,14 @@ export default class StatementParser extends ExpressionParser { } parseStatementContent(declaration: boolean, topLevel: ?boolean): N.Statement { - const starttype = this.state.type; + let starttype = this.state.type; const node = this.startNode(); + let kind; + + if (this.isLet(declaration)) { + starttype = tt._var; + kind = "let"; + } // Most types of statements are recognized by the keyword they // start with. Many are trivial to parse, some require a bit of @@ -129,12 +173,11 @@ export default class StatementParser extends ExpressionParser { case tt._try: return this.parseTryStatement(node); - case tt._let: case tt._const: - if (!declaration) this.unexpected(); // NOTE: falls through to _var - case tt._var: - return this.parseVarStatement(node, starttype); + kind = kind || this.state.value; + if (!declaration && kind !== "var") this.unexpected(); + return this.parseVarStatement(node, kind); case tt._while: return this.parseWhileStatement(node); @@ -424,18 +467,19 @@ export default class StatementParser extends ExpressionParser { return this.parseFor(node, null); } - if (this.match(tt._var) || this.match(tt._let) || this.match(tt._const)) { + const isLet = this.isLet(); + if (this.match(tt._var) || this.match(tt._const) || isLet) { const init = this.startNode(); - const varKind = this.state.type; + const kind = isLet ? "let" : this.state.value; this.next(); - this.parseVar(init, true, varKind); + this.parseVar(init, true, kind); this.finishNode(init, "VariableDeclaration"); if (this.match(tt._in) || this.isContextual("of")) { if (init.declarations.length === 1) { const declaration = init.declarations[0]; const isForInInitializer = - varKind === tt._var && + kind === "var" && declaration.init && declaration.id.type != "ObjectPattern" && declaration.id.type != "ArrayPattern" && @@ -606,7 +650,7 @@ export default class StatementParser extends ExpressionParser { parseVarStatement( node: N.VariableDeclaration, - kind: TokenType, + kind: "var" | "let" | "const", ): N.VariableDeclaration { this.next(); this.parseVar(node, false, kind); @@ -862,20 +906,19 @@ export default class StatementParser extends ExpressionParser { parseVar( node: N.VariableDeclaration, isFor: boolean, - kind: TokenType, + kind: "var" | "let" | "const", ): N.VariableDeclaration { const declarations = (node.declarations = []); const isTypescript = this.hasPlugin("typescript"); - // $FlowFixMe - node.kind = kind.keyword; + node.kind = kind; for (;;) { const decl = this.startNode(); - this.parseVarHead(decl); + this.parseVarId(decl, kind); if (this.eat(tt.eq)) { decl.init = this.parseMaybeAssign(isFor); } else { if ( - kind === tt._const && + kind === "const" && !(this.match(tt._in) || this.isContextual("of")) ) { // `const` with no initializer is allowed in TypeScript. @@ -900,7 +943,10 @@ export default class StatementParser extends ExpressionParser { return node; } - parseVarHead(decl: N.VariableDeclarator): void { + parseVarId(decl: N.VariableDeclarator, kind: "var" | "let" | "const"): void { + if ((kind === "const" || kind === "let") && this.isContextual("let")) { + this.unexpected(null, "let is disallowed as a lexically bound name"); + } decl.id = this.parseBindingAtom(); this.checkLVal(decl.id, true, undefined, "variable declaration"); } @@ -1008,12 +1054,12 @@ export default class StatementParser extends ExpressionParser { ): T { this.next(); this.takeDecorators(node); - this.parseClassId(node, isStatement, optionalId); - // class bodies and heritages are implicitly strict + // A class definition is always strict mode code. const oldStrict = this.state.strict; this.state.strict = true; + this.parseClassId(node, isStatement, optionalId); this.parseClassSuper(node); this.parseClassBody(node); @@ -1638,11 +1684,7 @@ export default class StatementParser extends ExpressionParser { } this.parseDecorators(false); return this.parseClass(expr, true, true); - } else if ( - this.match(tt._let) || - this.match(tt._const) || - this.match(tt._var) - ) { + } else if (this.match(tt._const) || this.match(tt._var) || this.isLet()) { return this.raise( this.state.start, "Only expressions, functions or classes are allowed as the `default` export.", @@ -1661,7 +1703,7 @@ export default class StatementParser extends ExpressionParser { isExportDefaultSpecifier(): boolean { if (this.match(tt.name)) { - return this.state.value !== "async"; + return this.state.value !== "async" && this.state.value !== "let"; } if (!this.match(tt._default)) { @@ -1710,9 +1752,9 @@ export default class StatementParser extends ExpressionParser { return ( this.state.type.keyword === "var" || this.state.type.keyword === "const" || - this.state.type.keyword === "let" || this.state.type.keyword === "function" || this.state.type.keyword === "class" || + this.isLet() || this.isAsyncFunction() ); } diff --git a/packages/babel-parser/src/plugins/flow.js b/packages/babel-parser/src/plugins/flow.js index 0dbab81e3a..912bb09c5f 100644 --- a/packages/babel-parser/src/plugins/flow.js +++ b/packages/babel-parser/src/plugins/flow.js @@ -344,7 +344,7 @@ export default (superClass: Class): Class => } else { if ( this.match(tt._const) || - this.match(tt._let) || + this.isLet() || ((this.isContextual("type") || this.isContextual("interface")) && !insideModule) ) { @@ -2344,8 +2344,11 @@ export default (superClass: Class): Class => } // parse flow type annotations on variable declarator heads - let foo: string = bar - parseVarHead(decl: N.VariableDeclarator): void { - super.parseVarHead(decl); + parseVarId( + decl: N.VariableDeclarator, + kind: "var" | "let" | "const", + ): void { + super.parseVarId(decl, kind); if (this.match(tt.colon)) { decl.id.typeAnnotation = this.flowParseTypeAnnotation(); this.finishNode(decl.id, decl.id.type); diff --git a/packages/babel-parser/src/plugins/typescript.js b/packages/babel-parser/src/plugins/typescript.js index 0a7c527dfa..3afd592038 100644 --- a/packages/babel-parser/src/plugins/typescript.js +++ b/packages/babel-parser/src/plugins/typescript.js @@ -1190,8 +1190,15 @@ export default (superClass: Class): Class => if (this.isLineTerminator()) { return; } + let starttype = this.state.type; + let kind; - switch (this.state.type) { + if (this.isContextual("let")) { + starttype = tt._var; + kind = "let"; + } + + switch (starttype) { case tt._function: this.next(); return this.parseFunction(nany, /* isStatement */ true); @@ -1210,8 +1217,8 @@ export default (superClass: Class): Class => } // falls through case tt._var: - case tt._let: - return this.parseVarStatement(nany, this.state.type); + kind = kind || this.state.value; + return this.parseVarStatement(nany, kind); case tt.name: { const value = this.state.value; if (value === "global") { @@ -1941,8 +1948,11 @@ export default (superClass: Class): Class => } // `let x: number;` - parseVarHead(decl: N.VariableDeclarator): void { - super.parseVarHead(decl); + parseVarId( + decl: N.VariableDeclarator, + kind: "var" | "let" | "const", + ): void { + super.parseVarId(decl, kind); if (decl.id.type === "Identifier" && this.eat(tt.bang)) { decl.definite = true; } diff --git a/packages/babel-parser/src/tokenizer/index.js b/packages/babel-parser/src/tokenizer/index.js index d527c96913..b3ef098539 100644 --- a/packages/babel-parser/src/tokenizer/index.js +++ b/packages/babel-parser/src/tokenizer/index.js @@ -1384,8 +1384,8 @@ export default class Tokenizer extends LocationParser { if ( prevType === tt._var || - prevType === tt._let || - prevType === tt._const + prevType === tt._const || + prevType === tt.name ) { return false; } diff --git a/packages/babel-parser/src/tokenizer/types.js b/packages/babel-parser/src/tokenizer/types.js index 4d88ed0e11..07a85c30db 100644 --- a/packages/babel-parser/src/tokenizer/types.js +++ b/packages/babel-parser/src/tokenizer/types.js @@ -180,7 +180,6 @@ export const keywords = Object.create(null, { throw: makeKeywordProps("throw", { beforeExpr, prefix, startsExpr }), try: makeKeywordProps("try"), var: makeKeywordProps("var"), - let: makeKeywordProps("let"), const: makeKeywordProps("const"), while: makeKeywordProps("while", { isLoop }), with: makeKeywordProps("with"), diff --git a/packages/babel-parser/src/util/identifier.js b/packages/babel-parser/src/util/identifier.js index 847a61f878..631f9d0394 100644 --- a/packages/babel-parser/src/util/identifier.js +++ b/packages/babel-parser/src/util/identifier.js @@ -57,7 +57,6 @@ const keywords = new Set([ "new", "in", "this", - "let", "const", "class", "extends", @@ -71,6 +70,8 @@ export function isKeyword(word: string): boolean { return keywords.has(word); } +export const keywordRelationalOperator = /^in(stanceof)?$/; + // ## Character categories // Big ugly regular expressions that matches characters in the diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-1/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-1/input.js new file mode 100644 index 0000000000..2b8952b973 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-1/input.js @@ -0,0 +1 @@ +let + 1 diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-1/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-1/output.json new file mode 100644 index 0000000000..d5896aa4d5 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-1/output.json @@ -0,0 +1,103 @@ +{ + "type": "File", + "start": 0, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "expression": { + "type": "BinaryExpression", + "start": 0, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 3, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 3 + }, + "identifierName": "let" + }, + "name": "let" + }, + "operator": "+", + "right": { + "type": "NumericLiteral", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-2/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-2/input.js new file mode 100644 index 0000000000..15ea1476df --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-2/input.js @@ -0,0 +1 @@ +var let = 1 diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-2/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-2/output.json new file mode 100644 index 0000000000..dc261c3dcb --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-2/output.json @@ -0,0 +1,105 @@ +{ + "type": "File", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "VariableDeclaration", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 4, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "id": { + "type": "Identifier", + "start": 4, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "let" + }, + "name": "let" + }, + "init": { + "type": "NumericLiteral", + "start": 10, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + } + } + ], + "kind": "var" + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-3/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-3/input.js new file mode 100644 index 0000000000..bf4301ea13 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-3/input.js @@ -0,0 +1 @@ +let instanceof Foo diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-3/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-3/output.json new file mode 100644 index 0000000000..b0f5399086 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-3/output.json @@ -0,0 +1,100 @@ +{ + "type": "File", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "expression": { + "type": "BinaryExpression", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 3, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 3 + }, + "identifierName": "let" + }, + "name": "let" + }, + "operator": "instanceof", + "right": { + "type": "Identifier", + "start": 15, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 18 + }, + "identifierName": "Foo" + }, + "name": "Foo" + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-4/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-4/input.js new file mode 100644 index 0000000000..8b1ded17c0 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-4/input.js @@ -0,0 +1 @@ +let in {} diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-4/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-4/output.json new file mode 100644 index 0000000000..96851ba7aa --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-4/output.json @@ -0,0 +1,99 @@ +{ + "type": "File", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "expression": { + "type": "BinaryExpression", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 3, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 3 + }, + "identifierName": "let" + }, + "name": "let" + }, + "operator": "in", + "right": { + "type": "ObjectExpression", + "start": 7, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "properties": [] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-5/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-5/input.js new file mode 100644 index 0000000000..5ddea3e168 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-5/input.js @@ -0,0 +1,2 @@ +if (1) let +{} diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-5/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-5/output.json new file mode 100644 index 0000000000..ade78031a6 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-5/output.json @@ -0,0 +1,120 @@ +{ + "type": "File", + "start": 0, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 2 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 2 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "IfStatement", + "start": 0, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "test": { + "type": "NumericLiteral", + "start": 4, + "end": 5, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 5 + } + }, + "extra": { + "rawValue": 1, + "raw": "1" + }, + "value": 1 + }, + "consequent": { + "type": "ExpressionStatement", + "start": 7, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "expression": { + "type": "Identifier", + "start": 7, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 10 + }, + "identifierName": "let" + }, + "name": "let" + } + }, + "alternate": null + }, + { + "type": "BlockStatement", + "start": 11, + "end": 13, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 2 + } + }, + "body": [], + "directives": [] + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-6/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-6/input.js new file mode 100644 index 0000000000..2ebfa83ecf --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-6/input.js @@ -0,0 +1,2 @@ +while (0) let +foo diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-6/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-6/output.json new file mode 100644 index 0000000000..c51c3538f1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-6/output.json @@ -0,0 +1,134 @@ +{ + "type": "File", + "start": 0, + "end": 17, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 3 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 17, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 3 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "WhileStatement", + "start": 0, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "test": { + "type": "NumericLiteral", + "start": 7, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + } + }, + "extra": { + "rawValue": 0, + "raw": "0" + }, + "value": 0 + }, + "body": { + "type": "ExpressionStatement", + "start": 10, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "expression": { + "type": "Identifier", + "start": 10, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "let" + }, + "name": "let" + } + } + }, + { + "type": "ExpressionStatement", + "start": 14, + "end": 17, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 3 + } + }, + "expression": { + "type": "Identifier", + "start": 14, + "end": 17, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 3 + }, + "identifierName": "foo" + }, + "name": "foo" + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-7/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-7/input.js new file mode 100644 index 0000000000..7036d1f8e4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-7/input.js @@ -0,0 +1,2 @@ +while (0) let +instanceof Foo diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-7/output.json b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-7/output.json new file mode 100644 index 0000000000..721e29212e --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-7/output.json @@ -0,0 +1,135 @@ +{ + "type": "File", + "start": 0, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "WhileStatement", + "start": 0, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "test": { + "type": "NumericLiteral", + "start": 7, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + } + }, + "extra": { + "rawValue": 0, + "raw": "0" + }, + "value": 0 + }, + "body": { + "type": "ExpressionStatement", + "start": 10, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "expression": { + "type": "BinaryExpression", + "start": 10, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "left": { + "type": "Identifier", + "start": 10, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "let" + }, + "name": "let" + }, + "operator": "instanceof", + "right": { + "type": "Identifier", + "start": 25, + "end": 28, + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 14 + }, + "identifierName": "Foo" + }, + "name": "Foo" + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-strict-fail/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-strict-fail/input.js new file mode 100644 index 0000000000..dc734683c9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-strict-fail/input.js @@ -0,0 +1,2 @@ +"use strict"; +let + 1 diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-strict-fail/options.json b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-strict-fail/options.json new file mode 100644 index 0000000000..8773675903 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-as-identifier-strict-fail/options.json @@ -0,0 +1,3 @@ +{ + "throws": "let is a reserved word in strict mode (2:0)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0232/options.json b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0232/options.json index 9fa1302689..81e5594d82 100644 --- a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0232/options.json +++ b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0232/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token (1:37)" + "throws": "let is a reserved word in strict mode (1:37)" } diff --git a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0238/input.js b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0238/input.js deleted file mode 100644 index c87b8eaaf4..0000000000 --- a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0238/input.js +++ /dev/null @@ -1 +0,0 @@ -var let diff --git a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0238/options.json b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0238/options.json deleted file mode 100644 index 27a7b64d71..0000000000 --- a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0238/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "throws": "Unexpected token (1:4)" -} diff --git a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0253/input.js b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0253/input.js deleted file mode 100644 index 564a1caa1c..0000000000 --- a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0253/input.js +++ /dev/null @@ -1 +0,0 @@ -let diff --git a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0253/options.json b/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0253/options.json deleted file mode 100644 index 05dbd26b33..0000000000 --- a/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0253/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "throws": "Unexpected token (1:3)" -} diff --git a/packages/babel-parser/test/unit/util/identifier.js b/packages/babel-parser/test/unit/util/identifier.js index a0d6bb16d2..420971a577 100644 --- a/packages/babel-parser/test/unit/util/identifier.js +++ b/packages/babel-parser/test/unit/util/identifier.js @@ -1,18 +1,42 @@ -import { isKeyword } from "../../../src/util/identifier"; +import { + isKeyword, + keywordRelationalOperator, +} from "../../../src/util/identifier"; describe("identifier", () => { describe("isKeyword", () => { it("break is a keyword", () => { expect(isKeyword("break")).toBe(true); }); - it("let is a keyword", () => { - expect(isKeyword("let")).toBe(true); + it("const is a keyword", () => { + expect(isKeyword("const")).toBe(true); }); it("super is a keyword", () => { expect(isKeyword("super")).toBe(true); }); + it("let is not a keyword", () => { + expect(isKeyword("let")).toBe(false); + }); it("abc is not a keyword", () => { expect(isKeyword("abc")).toBe(false); }); }); + + describe("keywordRelationalOperator", () => { + it("in is true", () => { + expect(keywordRelationalOperator.test("in")).toBe(true); + }); + it("instanceof is true", () => { + expect(keywordRelationalOperator.test("instanceof")).toBe(true); + }); + it("stanceof is false", () => { + expect(keywordRelationalOperator.test("stanceof")).toBe(false); + }); + it("instance is false", () => { + expect(keywordRelationalOperator.test("instance")).toBe(false); + }); + it("abc is false", () => { + expect(keywordRelationalOperator.test("abc")).toBe(false); + }); + }); }); diff --git a/scripts/tests/test262/test262_whitelist.txt b/scripts/tests/test262/test262_whitelist.txt index 5211810741..e65ad9097d 100644 --- a/scripts/tests/test262/test262_whitelist.txt +++ b/scripts/tests/test262/test262_whitelist.txt @@ -672,8 +672,6 @@ language/expressions/async-generator/early-errors-expression-formals-body-duplic language/expressions/async-generator/early-errors-expression-formals-body-duplicate-let.js(default) language/expressions/async-generator/early-errors-expression-formals-body-duplicate-let.js(strict mode) language/expressions/async-generator/named-dflt-params-duplicates.js(default) -language/expressions/class/class-name-ident-static-escaped.js(default) -language/expressions/class/class-name-ident-static.js(default) language/expressions/class/elements/fields-duplicate-privatenames.js(default) language/expressions/class/elements/fields-duplicate-privatenames.js(strict mode) language/expressions/class/elements/fields-literal-name-static-propname-constructor.js(default) @@ -776,8 +774,6 @@ language/expressions/class/elements/syntax/early-errors/super-private-access-inv language/expressions/class/elements/syntax/early-errors/super-private-access-invalid.js(strict mode) language/expressions/function/dflt-params-duplicates.js(default) language/expressions/generators/dflt-params-duplicates.js(default) -language/expressions/object/let-non-strict-access.js(default) -language/expressions/object/let-non-strict-syntax.js(default) language/expressions/object/method-definition/async-gen-meth-dflt-params-duplicates.js(default) language/expressions/object/method-definition/async-meth-dflt-params-duplicates.js(default) language/expressions/object/method-definition/early-errors-object-method-async-lineterminator.js(default) @@ -1029,8 +1025,6 @@ language/statements/class/async-gen-meth-escaped-async.js(default) language/statements/class/async-gen-meth-escaped-async.js(strict mode) language/statements/class/async-meth-escaped-async.js(default) language/statements/class/async-meth-escaped-async.js(strict mode) -language/statements/class/class-name-ident-static-escaped.js(default) -language/statements/class/class-name-ident-static.js(default) language/statements/class/elements/fields-duplicate-privatenames.js(default) language/statements/class/elements/fields-duplicate-privatenames.js(strict mode) language/statements/class/elements/fields-literal-name-static-propname-constructor.js(default) @@ -1144,8 +1138,6 @@ language/statements/class/syntax/early-errors/class-definition-evaluation-block- language/statements/class/syntax/early-errors/class-definition-evaluation-scriptbody-duplicate-binding.js(default) language/statements/class/syntax/early-errors/class-definition-evaluation-scriptbody-duplicate-binding.js(strict mode) language/statements/const/redeclaration-error-from-within-strict-mode-function-const.js(default) -language/statements/for-await-of/let-block-with-newline.js(default) -language/statements/for-await-of/let-identifier-with-newline.js(default) language/statements/for-in/dstr/array-rest-before-elision.js(default) language/statements/for-in/dstr/array-rest-before-elision.js(strict mode) language/statements/for-in/dstr/array-rest-elision-invalid.js(default) @@ -1158,11 +1150,6 @@ language/statements/for-in/head-let-bound-names-dup.js(default) language/statements/for-in/head-let-bound-names-dup.js(strict mode) language/statements/for-in/head-let-bound-names-in-stmt.js(default) language/statements/for-in/head-let-bound-names-in-stmt.js(strict mode) -language/statements/for-in/head-lhs-let.js(default) -language/statements/for-in/head-var-bound-names-let.js(default) -language/statements/for-in/identifier-let-allowed-as-lefthandside-expression-not-strict.js(default) -language/statements/for-in/let-block-with-newline.js(default) -language/statements/for-in/let-identifier-with-newline.js(default) language/statements/for-of/dstr/array-rest-before-elision.js(default) language/statements/for-of/dstr/array-rest-before-elision.js(strict mode) language/statements/for-of/dstr/array-rest-elision-invalid.js(default) @@ -1180,26 +1167,16 @@ language/statements/for-of/head-let-bound-names-dup.js(default) language/statements/for-of/head-let-bound-names-dup.js(strict mode) language/statements/for-of/head-let-bound-names-in-stmt.js(default) language/statements/for-of/head-let-bound-names-in-stmt.js(strict mode) -language/statements/for-of/head-var-bound-names-let.js(default) language/statements/for-of/head-var-no-expr.js(default) language/statements/for-of/head-var-no-expr.js(strict mode) -language/statements/for-of/let-block-with-newline.js(default) -language/statements/for-of/let-identifier-with-newline.js(default) language/statements/for/head-let-bound-names-in-stmt.js(default) language/statements/for/head-let-bound-names-in-stmt.js(strict mode) -language/statements/for/head-lhs-let.js(default) -language/statements/for/let-block-with-newline.js(default) -language/statements/for/let-identifier-with-newline.js(default) language/statements/function/dflt-params-duplicates.js(default) language/statements/generators/dflt-params-duplicates.js(default) -language/statements/if/let-block-with-newline.js(default) -language/statements/if/let-identifier-with-newline.js(default) -language/statements/labeled/let-block-with-newline.js(default) language/statements/labeled/let-identifier-with-newline.js(default) language/statements/labeled/value-yield-non-strict-escaped.js(default) language/statements/labeled/value-yield-non-strict.js(default) language/statements/let/redeclaration-error-from-within-strict-mode-function.js(default) -language/statements/let/syntax/escaped-let.js(default) language/statements/switch/syntax/redeclaration/async-function-name-redeclaration-attempt-with-async-function.js(default) language/statements/switch/syntax/redeclaration/async-function-name-redeclaration-attempt-with-async-function.js(strict mode) language/statements/switch/syntax/redeclaration/async-function-name-redeclaration-attempt-with-async-generator.js(default) @@ -1330,8 +1307,4 @@ language/statements/try/early-catch-function.js(strict mode) language/statements/try/early-catch-lex.js(default) language/statements/try/early-catch-lex.js(strict mode) language/statements/try/early-catch-var.js(default) -language/statements/try/early-catch-var.js(strict mode) -language/statements/while/let-block-with-newline.js(default) -language/statements/while/let-identifier-with-newline.js(default) -language/statements/with/let-block-with-newline.js(default) -language/statements/with/let-identifier-with-newline.js(default) \ No newline at end of file +language/statements/try/early-catch-var.js(strict mode) \ No newline at end of file