From ff0c26c65df21fe21beef5c9ae98805eae8c2557 Mon Sep 17 00:00:00 2001 From: Alan Pierce Date: Tue, 24 Dec 2019 15:05:42 -0800 Subject: [PATCH] Port babel-parser changes from 2019-04-01 to 2019-09-06 (#485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Progress toward #483 c7587c016 Don't accept '\08' or '\09' in strict mode (#9769) 🚫 Validation change, not relevant for Sucrase. 508fde400 v7.4.3 🚫 Release only 338853b5d Fix parsing typescript bodiless methods with the estree plugin also enabled (#9890) 🚫 AST-only 4198d91b8 Fix: remove constant context type check for TS (#9869) 🚫 Validation-only d7757f6d0 Fix TypeScript readonly error location (#9887) 🚫 Error-handling only cf3668779 Always register global bindings as exportable (#9865) 🚫 Scope code not relevant to Sucrase 30d507c91 Add TS support to @babel/parser's Scope (#9766) 🚫 Sucrase deals with scope differently and generally doesn't need to implement TS scope. 277a2620c allow directives and other comments before flow pragma (#9891) 🚫 We already remove all flow pragmas everywhere. 2c8869438 v7.4.4 🚫 Release only 555d50a08 Generate missing test output 🚫 Test only 354666aa1 fix: allow shebang directive (#9922) 🚫 We already handle shebangs and remove flow pragmas. 85432e2c4 Remove guardedHandlers from ASTs (#9979) 🚫 AST-only 47eb1ddfe Do not use lookahead when parsing dynamic import or import.meta (#9983) ✅ Implemented in a slightly different way with new tests. 4da7a01aa Avoid unnecessary work during lookahead (#9982) 🚫 Not relevant here c2d303f8b Do not use lookahead when parsing declare module or declare module.exports in flow (#9985) ✅ Straightforward port. 5661de590 Do not use lookahead when parsing imports in declare module in flow (#9987) 🚫 Code removed from Sucrase. 3f0590de2 Do not use lookahead when parsing jsx expression containers (#9988) ✅ Ported in a similar way to original code. b1826bf0a Only compute Position if not already in state (#9989) 🚫 Not relevant for Sucrase. f5b814058 Do not use lookahead when parsing construct signature declarations (#9995) ✅ Ported in similar way to original code, removed unnecessary enum. 9c06e4ed4 avoid exceptions for control flow (#9974) 🚫 Sucrase already avoids exceptions. 54d257c10 Fix location for optional params in arrow functions (#9998) 🚫 AST-only change. 33ab4f166 v7.4.5 🚫 Release only. 888b9f694 Remove unused code in the TS parser plugin (#10025) 🚫 Already removed from Sucrase. fdbbb743b flow - allow type parameter defaults in function declarations (#10084) 🚫 Nothing to do, we already allow defaults in function type parameters. 11fa2461c Disallow "let" as name at lexical bindings (#10099) 🚫 Validation-only. 1d3f9815d fix import typeof in declare module (#10132) 🚫 Code doesn't exist in Sucrase. ca67637da [@babel/parser] Add "allowUndeclaredExports" option (#9864) 🚫 Validation-only. 8bf9714d6 [legacy decorators] Allow decorating generator methods (#9912) 🚫 Sucrase doesn't support legacy decorators. 6b8a37c41 Implement f# pipeline in parser (#9450) 🚫 I'll leave out support for F# pipelines for now. 0bf0ae341 Fix typos (#10153) 🚫 Not relevant for Sucrase. f588e4ec4 BigInt type for Flow (#10091) 🚫 No changes necessary. 49da9a07c v7.5.0 🚫 Release only. 7f47cb65d Add Pipeline nodes to ast.spec (#10214) 🚫 Docs only. d8da63c92 Use correct extension for typescript fixtures (#10014) 🚫 Test only. 0407f034f v7.5.5 🚫 Release only. 1e7ed5c46 Add `allowUndeclaredExports` option to typings. (#10263) 🚫 Types only. f160522ab updated ParsePlugin type definition (#10259) 🚫 Types only. 4f0840ab8 Update dev dependencies and fix linting errors (#10228) 🚫 Formatting only. 75090f10e fix: assign comment to ObjectProperty only when inside an ObjectExpression (#10292) 🚫 Comment parsing only, not relevant for Sucrase. 15aa511b8 Do not register ambient classes to the TS scope (#10352) 🚫 Scope code not relevant for Sucrase. 1664cce68 Don't allow JSXNamespacedName to chain (#10366) 🚫 Validation only. 8a775a32b Retain trailing comments in array expressions (#10369) 🚫 Comment only. c0e3fa008 Refactor trailing comma comment adjustment (#10380) 🚫 Comment only. b02e35c19 Fix parenthesis for nullish coalescing (#10269) ✅ Updated precedence for operators. da0af5fd9 V8intrinsic syntax plugin (#10148) ✅ Added case to the start of `parseExprAtom`. --- generator/generateTokenTypes.ts | 36 +++++++++++++++--------------- src/parser/plugins/flow.ts | 8 ++----- src/parser/plugins/jsx/index.ts | 15 ++++++------- src/parser/plugins/typescript.ts | 30 ++++++++++--------------- src/parser/tokenizer/types.ts | 36 +++++++++++++++--------------- src/parser/traverser/expression.ts | 32 +++++++++++++------------- test/imports-test.ts | 12 ++++++++++ test/sucrase-test.ts | 12 ++++++++++ test/tokens-test.ts | 16 +++++++++++++ 9 files changed, 112 insertions(+), 85 deletions(-) diff --git a/generator/generateTokenTypes.ts b/generator/generateTokenTypes.ts index bb8562f1..a506724f 100644 --- a/generator/generateTokenTypes.ts +++ b/generator/generateTokenTypes.ts @@ -87,22 +87,22 @@ const types = { tilde: new TokenType("~", {prefix}), pipeline: new BinopTokenType("|>", 0), nullishCoalescing: new BinopTokenType("??", 1), - logicalOR: new BinopTokenType("||", 1), - logicalAND: new BinopTokenType("&&", 2), - bitwiseOR: new BinopTokenType("|", 3), - bitwiseXOR: new BinopTokenType("^", 4), - bitwiseAND: new BinopTokenType("&", 5), - equality: new BinopTokenType("==/!=", 6), - lessThan: new BinopTokenType("<", 7), - greaterThan: new BinopTokenType(">", 7), - relationalOrEqual: new BinopTokenType("<=/>=", 7), - bitShift: new BinopTokenType("<>", 8), - plus: new TokenType("+", {binop: 9, prefix}), - minus: new TokenType("-", {binop: 9, prefix}), - modulo: new BinopTokenType("%", 10), - star: new BinopTokenType("*", 10), - slash: new BinopTokenType("/", 10), - exponent: new TokenType("**", {binop: 11, rightAssociative: true}), + logicalOR: new BinopTokenType("||", 2), + logicalAND: new BinopTokenType("&&", 3), + bitwiseOR: new BinopTokenType("|", 4), + bitwiseXOR: new BinopTokenType("^", 5), + bitwiseAND: new BinopTokenType("&", 6), + equality: new BinopTokenType("==/!=", 7), + lessThan: new BinopTokenType("<", 8), + greaterThan: new BinopTokenType(">", 8), + relationalOrEqual: new BinopTokenType("<=/>=", 8), + bitShift: new BinopTokenType("<>", 9), + plus: new TokenType("+", {binop: 10, prefix}), + minus: new TokenType("-", {binop: 10, prefix}), + modulo: new BinopTokenType("%", 11), + star: new BinopTokenType("*", 11), + slash: new BinopTokenType("/", 11), + exponent: new TokenType("**", {binop: 12, rightAssociative: true}), jsxName: new TokenType("jsxName"), jsxText: new TokenType("jsxText"), @@ -144,8 +144,8 @@ const types = { _null: new KeywordTokenType("null"), _true: new KeywordTokenType("true"), _false: new KeywordTokenType("false"), - _in: new KeywordTokenType("in", {binop: 7}), - _instanceof: new KeywordTokenType("instanceof", {binop: 7}), + _in: new KeywordTokenType("in", {binop: 8}), + _instanceof: new KeywordTokenType("instanceof", {binop: 8}), _typeof: new KeywordTokenType("typeof", {prefix}), _void: new KeywordTokenType("void", {prefix}), _delete: new KeywordTokenType("delete", {prefix}), diff --git a/src/parser/plugins/flow.ts b/src/parser/plugins/flow.ts index 6996ae4f..707e9537 100644 --- a/src/parser/plugins/flow.ts +++ b/src/parser/plugins/flow.ts @@ -113,8 +113,8 @@ function flowParseDeclare(): void { flowParseDeclareFunction(); } else if (match(tt._var)) { flowParseDeclareVariable(); - } else if (isContextual(ContextualKeyword._module)) { - if (lookaheadType() === tt.dot) { + } else if (eatContextual(ContextualKeyword._module)) { + if (eat(tt.dot)) { flowParseDeclareModuleExports(); } else { flowParseDeclareModule(); @@ -139,8 +139,6 @@ function flowParseDeclareVariable(): void { } function flowParseDeclareModule(): void { - next(); - if (match(tt.string)) { parseExprAtom(); } else { @@ -193,8 +191,6 @@ function flowParseDeclareExportDeclaration(): void { } function flowParseDeclareModuleExports(): void { - expectContextual(ContextualKeyword._module); - expect(tt.dot); expectContextual(ContextualKeyword._exports); flowParseTypeAnnotation(); semicolon(); diff --git a/src/parser/plugins/jsx/index.ts b/src/parser/plugins/jsx/index.ts index 9b38c0a9..fee7f34e 100644 --- a/src/parser/plugins/jsx/index.ts +++ b/src/parser/plugins/jsx/index.ts @@ -3,7 +3,6 @@ import { finishToken, getTokenFromCode, IdentifierRole, - lookaheadType, match, next, skipSpace, @@ -116,6 +115,7 @@ function jsxParseElementName(): void { function jsxParseAttributeValue(): void { switch (state.type) { case tt.braceL: + next(); jsxParseExpressionContainer(); nextJSXTagToken(); return; @@ -138,18 +138,16 @@ function jsxParseEmptyExpression(): void { // Do nothing. } -// Parse JSX spread child -// Does not parse the last token. +// Parse JSX spread child, after already processing the { +// Does not parse the closing } function jsxParseSpreadChild(): void { - expect(tt.braceL); expect(tt.ellipsis); parseExpression(); } -// Parses JSX expression enclosed into curly brackets. -// Does not parse the last token. +// Parses JSX expression enclosed into curly brackets, after already processing the { +// Does not parse the closing } function jsxParseExpressionContainer(): void { - next(); if (match(tt.braceR)) { jsxParseEmptyExpression(); } else { @@ -231,7 +229,8 @@ function jsxParseElementAt(): void { break; case tt.braceL: - if (lookaheadType() === tt.ellipsis) { + next(); + if (match(tt.ellipsis)) { jsxParseSpreadChild(); nextJSXExprToken(); } else { diff --git a/src/parser/plugins/typescript.ts b/src/parser/plugins/typescript.ts index 6414de43..615d2665 100644 --- a/src/parser/plugins/typescript.ts +++ b/src/parser/plugins/typescript.ts @@ -226,15 +226,7 @@ function tsParseTypeMemberSemicolon(): void { } } -enum SignatureMemberKind { - TSCallSignatureDeclaration, - TSConstructSignatureDeclaration, -} - -function tsParseSignatureMember(kind: SignatureMemberKind): void { - if (kind === SignatureMemberKind.TSConstructSignatureDeclaration) { - expect(tt._new); - } +function tsParseSignatureMember(): void { tsFillSignature(tt.colon); tsParseTypeMemberSemicolon(); } @@ -267,7 +259,6 @@ function tsTryParseIndexSignature(): boolean { } function tsParsePropertyOrMethodSignature(isReadonly: boolean): void { - parsePropertyName(-1 /* Types don't need context IDs. */); eat(tt.question); if (!isReadonly && (match(tt.parenL) || match(tt.lessThan))) { @@ -281,11 +272,18 @@ function tsParsePropertyOrMethodSignature(isReadonly: boolean): void { function tsParseTypeMember(): void { if (match(tt.parenL) || match(tt.lessThan)) { - tsParseSignatureMember(SignatureMemberKind.TSCallSignatureDeclaration); + // call signature + tsParseSignatureMember(); return; } - if (match(tt._new) && tsIsStartOfConstructSignature()) { - tsParseSignatureMember(SignatureMemberKind.TSConstructSignatureDeclaration); + if (match(tt._new)) { + next(); + if (match(tt.parenL) || match(tt.lessThan)) { + // constructor signature + tsParseSignatureMember(); + } else { + tsParsePropertyOrMethodSignature(false); + } return; } const readonly = !!tsParseModifier([ContextualKeyword._readonly]); @@ -294,14 +292,10 @@ function tsParseTypeMember(): void { if (found) { return; } + parsePropertyName(-1 /* Types don't need context IDs. */); tsParsePropertyOrMethodSignature(readonly); } -function tsIsStartOfConstructSignature(): boolean { - const lookahead = lookaheadType(); - return lookahead === tt.parenL || lookahead === tt.lessThan; -} - function tsParseTypeLiteral(): void { tsParseObjectTypeMembers(); } diff --git a/src/parser/tokenizer/types.ts b/src/parser/tokenizer/types.ts index 68e0c3b3..134656b2 100644 --- a/src/parser/tokenizer/types.ts +++ b/src/parser/tokenizer/types.ts @@ -47,22 +47,22 @@ export enum TokenType { tilde = 17024, // ~ prefix pipeline = 17409, // |> prec:1 nullishCoalescing = 17922, // ?? prec:2 - logicalOR = 18434, // || prec:2 - logicalAND = 18947, // && prec:3 - bitwiseOR = 19460, // | prec:4 - bitwiseXOR = 19973, // ^ prec:5 - bitwiseAND = 20486, // & prec:6 - equality = 20999, // ==/!= prec:7 - lessThan = 21512, // < prec:8 - greaterThan = 22024, // > prec:8 - relationalOrEqual = 22536, // <=/>= prec:8 - bitShift = 23049, // <> prec:9 - plus = 23690, // + prec:10 prefix - minus = 24202, // - prec:10 prefix - modulo = 24587, // % prec:11 - star = 25099, // * prec:11 - slash = 25611, // / prec:11 - exponent = 26188, // ** prec:12 rightAssociative + logicalOR = 18435, // || prec:3 + logicalAND = 18948, // && prec:4 + bitwiseOR = 19461, // | prec:5 + bitwiseXOR = 19974, // ^ prec:6 + bitwiseAND = 20487, // & prec:7 + equality = 21000, // ==/!= prec:8 + lessThan = 21513, // < prec:9 + greaterThan = 22025, // > prec:9 + relationalOrEqual = 22537, // <=/>= prec:9 + bitShift = 23050, // <> prec:10 + plus = 23691, // + prec:11 prefix + minus = 24203, // - prec:11 prefix + modulo = 24588, // % prec:12 + star = 25100, // * prec:12 + slash = 25612, // / prec:12 + exponent = 26189, // ** prec:13 rightAssociative jsxName = 26624, // jsxName jsxText = 27136, // jsxText jsxTagStart = 27648, // jsxTagStart @@ -101,8 +101,8 @@ export enum TokenType { _null = 44560, // null keyword _true = 45072, // true keyword _false = 45584, // false keyword - _in = 46104, // in prec:8 keyword - _instanceof = 46616, // instanceof prec:8 keyword + _in = 46105, // in prec:9 keyword + _instanceof = 46617, // instanceof prec:9 keyword _typeof = 47248, // typeof keyword prefix _void = 47760, // void keyword prefix _delete = 48272, // delete keyword prefix diff --git a/src/parser/traverser/expression.ts b/src/parser/traverser/expression.ts index 7d248628..7cd4a636 100644 --- a/src/parser/traverser/expression.ts +++ b/src/parser/traverser/expression.ts @@ -399,6 +399,13 @@ function parseNoCallExpr(): void { // or `{}`. // Returns true if the parsed expression was an arrow function. export function parseExprAtom(): boolean { + if (eat(tt.modulo)) { + // V8 intrinsic expression. Just parse the identifier, and the function invocation is parsed + // naturally. + parseIdentifier(); + return false; + } + if (match(tt.jsxText)) { parseLiteral(); return false; @@ -429,11 +436,13 @@ export function parseExprAtom(): boolean { return false; case tt._import: - if (lookaheadType() === tt.dot) { - parseImportMetaProperty(); - return false; - } next(); + if (match(tt.dot)) { + // import.meta + state.tokens[state.tokens.length - 1].type = tt.name; + next(); + parseIdentifier(); + } return false; case tt.name: { @@ -546,22 +555,11 @@ function parseFunctionExpression(): void { parseIdentifier(); if (eat(tt.dot)) { // function.sent - parseMetaProperty(); + parseIdentifier(); } parseFunction(functionStart, false); } -function parseMetaProperty(): void { - parseIdentifier(); -} - -function parseImportMetaProperty(): void { - parseIdentifier(); - expect(tt.dot); - // import.meta - parseMetaProperty(); -} - export function parseLiteral(): void { next(); } @@ -652,7 +650,7 @@ function parseNew(): void { expect(tt._new); if (eat(tt.dot)) { // new.target - parseMetaProperty(); + parseIdentifier(); return; } parseNoCallExpr(); diff --git a/test/imports-test.ts b/test/imports-test.ts index cde32ebc..a76a2f91 100644 --- a/test/imports-test.ts +++ b/test/imports-test.ts @@ -1284,6 +1284,18 @@ module.exports = exports.default; ); }); + it("leaves import.meta alone", () => { + assertResult( + ` + console.log(import.meta); + `, + `"use strict"; + console.log(import.meta); + `, + {transforms: ["imports"]}, + ); + }); + it("implements basic live bindings", () => { assertMultiFileOutput( { diff --git a/test/sucrase-test.ts b/test/sucrase-test.ts index c51efdd0..80e67df0 100644 --- a/test/sucrase-test.ts +++ b/test/sucrase-test.ts @@ -847,4 +847,16 @@ describe("sucrase", () => { {transforms: []}, ); }); + + it("handles V8 intrinsic syntax", () => { + assertResult( + ` + %DebugPrint(foo) + `, + ` + %DebugPrint(foo) + `, + {transforms: []}, + ); + }); }); diff --git a/test/tokens-test.ts b/test/tokens-test.ts index bc4dd80c..3e979c65 100644 --- a/test/tokens-test.ts +++ b/test/tokens-test.ts @@ -303,4 +303,20 @@ describe("tokens", () => { ], ); }); + + it("properly parses import.meta", () => { + assertTokens( + ` + f = import.meta + `, + [ + {type: tt.name}, + {type: tt.eq}, + {type: tt.name}, + {type: tt.dot}, + {type: tt.name}, + {type: tt.eof}, + ], + ); + }); });