diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 374f2f158350..0f5f415f5897 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1403,7 +1403,10 @@ export default class ExpressionParser extends LValParser { parseNew(): N.NewExpression | N.MetaProperty { const node = this.startNode(); - const meta = this.parseIdentifier(true); + + let meta = this.startNode(); + this.next(); + meta = this.createIdentifier(meta, "new"); if (this.eat(tt.dot)) { const metaProp = this.parseMetaProperty(node, meta, "target"); @@ -2112,6 +2115,8 @@ export default class ExpressionParser extends LValParser { // Parse the next token as an identifier. If `liberal` is true (used // when parsing properties), it will also convert keywords into // identifiers. + // This shouldn't be used to parse the keywords of meta properties, since they + // are not identifiers and cannot contain escape sequences. parseIdentifier(liberal?: boolean): N.Identifier { const node = this.startNode(); @@ -2132,11 +2137,6 @@ export default class ExpressionParser extends LValParser { if (this.match(tt.name)) { name = this.state.value; - - // An escaped identifier whose value is the same as a keyword - if (!liberal && this.state.containsEsc && isKeyword(name)) { - this.raise(this.state.pos, `Escape sequence in keyword ${name}`); - } } else if (this.state.type.keyword) { name = this.state.type.keyword; @@ -2156,7 +2156,11 @@ export default class ExpressionParser extends LValParser { throw this.unexpected(); } - if (!liberal) { + if (liberal) { + // If the current token is not used as a keyword, set its type to "tt.name". + // This will prevent this.next() from throwing about unexpected escapes. + this.state.type = tt.name; + } else { this.checkReservedWord( name, this.state.start, diff --git a/packages/babel-parser/src/tokenizer/index.js b/packages/babel-parser/src/tokenizer/index.js index fb0b71dfcd36..32c8a03fc0b9 100644 --- a/packages/babel-parser/src/tokenizer/index.js +++ b/packages/babel-parser/src/tokenizer/index.js @@ -126,8 +126,11 @@ export default class Tokenizer extends LocationParser { // Move to the next token next(): void { - if (this.options.tokens && !this.isLookahead) { - this.state.tokens.push(new Token(this.state)); + if (!this.isLookahead) { + this.checkKeywordEscapes(); + if (this.options.tokens) { + this.state.tokens.push(new Token(this.state)); + } } this.state.lastTokEnd = this.state.end; @@ -1395,7 +1398,7 @@ export default class Tokenizer extends LocationParser { readWord(): void { const word = this.readWord1(); - const type = (!this.state.containsEsc && keywordTypes.get(word)) || tt.name; + const type = keywordTypes.get(word) || tt.name; // Allow @@iterator and @@asyncIterator as a identifier only inside type if ( @@ -1408,6 +1411,13 @@ export default class Tokenizer extends LocationParser { this.finishToken(type, word); } + checkKeywordEscapes(): void { + const kw = this.state.type.keyword; + if (kw && this.state.containsEsc) { + this.raise(this.state.start, `Escape sequence in keyword ${kw}`); + } + } + braceIsBlock(prevType: TokenType): boolean { const parent = this.curContext(); if (parent === ct.functionExpression || parent === ct.functionStatement) { diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/input.js b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/input.js index 7db67c0d2dc7..3ec83f02b2f4 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/input.js +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/input.js @@ -1 +1,3 @@ var co\u{6e}st = 123; + +co\u{6e}st x = 2; diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/output.json b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/output.json index 9b7b38d58487..f5d632c23ace 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/output.json +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/output.json @@ -1,32 +1,34 @@ { "type": "File", "start": 0, - "end": 21, + "end": 40, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 1, - "column": 21 + "line": 3, + "column": 17 } }, "errors": [ - "SyntaxError: Escape sequence in keyword const (1:14)" + "SyntaxError: Unexpected keyword 'const' (1:4)", + "SyntaxError: Escape sequence in keyword const (1:4)", + "SyntaxError: Escape sequence in keyword const (3:0)" ], "program": { "type": "Program", "start": 0, - "end": 21, + "end": 40, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 1, - "column": 21 + "line": 3, + "column": 17 } }, "sourceType": "script", @@ -101,6 +103,76 @@ } ], "kind": "var" + }, + { + "type": "VariableDeclaration", + "start": 23, + "end": 40, + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 17 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 34, + "end": 39, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 16 + } + }, + "id": { + "type": "Identifier", + "start": 34, + "end": 35, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 12 + }, + "identifierName": "x" + }, + "name": "x" + }, + "init": { + "type": "NumericLiteral", + "start": 38, + "end": 39, + "loc": { + "start": { + "line": 3, + "column": 15 + }, + "end": { + "line": 3, + "column": 16 + } + }, + "extra": { + "rawValue": 2, + "raw": "2" + }, + "value": 2 + } + } + ], + "kind": "const" } ], "directives": [] diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/input.js b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/input.js index 2c49151ea912..c9bc4e4c28d9 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/input.js +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/input.js @@ -1 +1,4 @@ var expor\u{74} = 123; + +var x; +expor\u{74} { x }; diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/options.json b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/options.json new file mode 100644 index 000000000000..54925950e059 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/options.json @@ -0,0 +1,3 @@ +{ + "sourceType": "module" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/output.json b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/output.json index 306595677000..236b7dc15afa 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/output.json +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/output.json @@ -1,35 +1,37 @@ { "type": "File", "start": 0, - "end": 22, + "end": 49, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 1, - "column": 22 + "line": 4, + "column": 18 } }, "errors": [ - "SyntaxError: Escape sequence in keyword export (1:15)" + "SyntaxError: Unexpected keyword 'export' (1:4)", + "SyntaxError: Escape sequence in keyword export (1:4)", + "SyntaxError: Escape sequence in keyword export (4:0)" ], "program": { "type": "Program", "start": 0, - "end": 22, + "end": 49, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 1, - "column": 22 + "line": 4, + "column": 18 } }, - "sourceType": "script", + "sourceType": "module", "interpreter": null, "body": [ { @@ -101,6 +103,125 @@ } ], "kind": "var" + }, + { + "type": "VariableDeclaration", + "start": 24, + "end": 30, + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 28, + "end": 29, + "loc": { + "start": { + "line": 3, + "column": 4 + }, + "end": { + "line": 3, + "column": 5 + } + }, + "id": { + "type": "Identifier", + "start": 28, + "end": 29, + "loc": { + "start": { + "line": 3, + "column": 4 + }, + "end": { + "line": 3, + "column": 5 + }, + "identifierName": "x" + }, + "name": "x" + }, + "init": null + } + ], + "kind": "var" + }, + { + "type": "ExportNamedDeclaration", + "start": 31, + "end": 49, + "loc": { + "start": { + "line": 4, + "column": 0 + }, + "end": { + "line": 4, + "column": 18 + } + }, + "specifiers": [ + { + "type": "ExportSpecifier", + "start": 45, + "end": 46, + "loc": { + "start": { + "line": 4, + "column": 14 + }, + "end": { + "line": 4, + "column": 15 + } + }, + "local": { + "type": "Identifier", + "start": 45, + "end": 46, + "loc": { + "start": { + "line": 4, + "column": 14 + }, + "end": { + "line": 4, + "column": 15 + }, + "identifierName": "x" + }, + "name": "x" + }, + "exported": { + "type": "Identifier", + "start": 45, + "end": 46, + "loc": { + "start": { + "line": 4, + "column": 14 + }, + "end": { + "line": 4, + "column": 15 + }, + "identifierName": "x" + }, + "name": "x" + } + } + ], + "source": null, + "declaration": null } ], "directives": [] diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-if/output.json b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-if/output.json index 4da6a4e43640..d95df678e8c4 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-if/output.json +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-if/output.json @@ -13,7 +13,7 @@ } }, "errors": [ - "SyntaxError: Escape sequence in keyword if (1:12)" + "SyntaxError: Escape sequence in keyword if (1:0)" ], "program": { "type": "Program", diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/input.js b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/input.js index f23c79e20fb1..df174d0e56d1 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/input.js +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/input.js @@ -1 +1,3 @@ var \u{69}\u{6d}\u{70}\u{6f}\u{72}\u{74} = 123; + +\u{69}\u{6d}\u{70}\u{6f}\u{72}\u{74} "x"; diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/options.json b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/options.json new file mode 100644 index 000000000000..54925950e059 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/options.json @@ -0,0 +1,3 @@ +{ + "sourceType": "module" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/output.json b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/output.json index fe3db26d020a..8842ac412ce6 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/output.json +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/output.json @@ -1,35 +1,37 @@ { "type": "File", "start": 0, - "end": 47, + "end": 90, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 1, - "column": 47 + "line": 3, + "column": 41 } }, "errors": [ - "SyntaxError: Escape sequence in keyword import (1:40)" + "SyntaxError: Unexpected keyword 'import' (1:4)", + "SyntaxError: Escape sequence in keyword import (1:4)", + "SyntaxError: Escape sequence in keyword import (3:0)" ], "program": { "type": "Program", "start": 0, - "end": 47, + "end": 90, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 1, - "column": 47 + "line": 3, + "column": 41 } }, - "sourceType": "script", + "sourceType": "module", "interpreter": null, "body": [ { @@ -101,6 +103,42 @@ } ], "kind": "var" + }, + { + "type": "ImportDeclaration", + "start": 49, + "end": 90, + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 41 + } + }, + "specifiers": [], + "source": { + "type": "StringLiteral", + "start": 86, + "end": 89, + "loc": { + "start": { + "line": 3, + "column": 37 + }, + "end": { + "line": 3, + "column": 40 + } + }, + "extra": { + "rawValue": "x", + "raw": "\"x\"" + }, + "value": "x" + } } ], "directives": [] diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-null/output.json b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-null/output.json index 912c74d9fcbd..17c1ae03468e 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-null/output.json +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-null/output.json @@ -13,7 +13,7 @@ } }, "errors": [ - "SyntaxError: Escape sequence in keyword null (1:9)" + "SyntaxError: Escape sequence in keyword null (1:0)" ], "program": { "type": "Program", @@ -47,7 +47,7 @@ } }, "expression": { - "type": "Identifier", + "type": "NullLiteral", "start": 0, "end": 9, "loc": { @@ -58,10 +58,8 @@ "end": { "line": 1, "column": 9 - }, - "identifierName": "null" - }, - "name": "null" + } + } } } ], diff --git a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-true/output.json b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-true/output.json index d216ce539ec6..609a782c235a 100644 --- a/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-true/output.json +++ b/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-true/output.json @@ -13,7 +13,7 @@ } }, "errors": [ - "SyntaxError: Escape sequence in keyword true (1:9)" + "SyntaxError: Escape sequence in keyword true (1:0)" ], "program": { "type": "Program", @@ -47,7 +47,7 @@ } }, "expression": { - "type": "Identifier", + "type": "BooleanLiteral", "start": 0, "end": 9, "loc": { @@ -58,10 +58,9 @@ "end": { "line": 1, "column": 9 - }, - "identifierName": "true" + } }, - "name": "true" + "value": true } } ], diff --git a/packages/babel-parser/test/fixtures/es2015/meta-properties/new-target-invalid-escaped-new/output.json b/packages/babel-parser/test/fixtures/es2015/meta-properties/new-target-invalid-escaped-new/output.json index c500d9a7b8e4..1394b19bdb01 100644 --- a/packages/babel-parser/test/fixtures/es2015/meta-properties/new-target-invalid-escaped-new/output.json +++ b/packages/babel-parser/test/fixtures/es2015/meta-properties/new-target-invalid-escaped-new/output.json @@ -13,7 +13,7 @@ } }, "errors": [ - "SyntaxError: Escape sequence in keyword new (1:23)" + "SyntaxError: Escape sequence in keyword new (1:15)" ], "program": { "type": "Program", @@ -96,7 +96,7 @@ } }, "expression": { - "type": "MemberExpression", + "type": "MetaProperty", "start": 15, "end": 30, "loc": { @@ -109,7 +109,7 @@ "column": 30 } }, - "object": { + "meta": { "type": "Identifier", "start": 15, "end": 23, @@ -142,8 +142,7 @@ "identifierName": "target" }, "name": "target" - }, - "computed": false + } } } ],