From 68087293fa10ba59e6d8147be3cf13aa9794b225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 27 Oct 2021 21:20:18 -0400 Subject: [PATCH] refactor: extract tt.lt and tt.gt from tt.relation --- .../babel-parser/src/parser/expression.js | 21 ++-- packages/babel-parser/src/parser/util.js | 16 --- .../babel-parser/src/plugins/flow/index.js | 103 ++++++++---------- .../babel-parser/src/plugins/jsx/index.js | 4 +- .../src/plugins/typescript/index.js | 80 +++++++------- packages/babel-parser/src/tokenizer/index.js | 52 ++++++--- packages/babel-parser/src/tokenizer/types.js | 2 + 7 files changed, 141 insertions(+), 137 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index eae9a7242d7f..33be4b156b6b 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1214,20 +1214,19 @@ export default class ExpressionParser extends LValParser { } } - // fall through - case tt.relational: { - if (this.state.value === "<") { - const lookaheadCh = this.input.codePointAt(this.nextTokenStart()); - if ( - isIdentifierStart(lookaheadCh) || // Element/Type Parameter - lookaheadCh === charCodes.greaterThan // Fragment <> - ) { - this.expectOnePlugin(["jsx", "flow", "typescript"]); - } + case tt.lt: { + const lookaheadCh = this.input.codePointAt(this.nextTokenStart()); + if ( + isIdentifierStart(lookaheadCh) || // Element/Type Parameter + lookaheadCh === charCodes.greaterThan // Fragment <> + ) { + this.expectOnePlugin(["jsx", "flow", "typescript"]); + break; + } else { + throw this.unexpected(); } } - // fall through default: if (tokenIsIdentifier(type)) { if ( diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index adb2e94cfaca..da64aa526483 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -50,22 +50,6 @@ export default class UtilParser extends Tokenizer { extra[key] = val; } - // TODO - - isRelational(op: "<" | ">"): boolean { - return this.match(tt.relational) && this.state.value === op; - } - - // TODO - - expectRelational(op: "<" | ">"): void { - if (this.isRelational(op)) { - this.next(); - } else { - this.unexpected(null, tt.relational); - } - } - // Tests whether parsed token is a contextual keyword. isContextual(token: TokenType): boolean { diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index fc915fe1dfe6..a9e309bdb72c 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -316,7 +316,7 @@ export default (superClass: Class): Class => const typeNode = this.startNode(); const typeContainer = this.startNode(); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { typeNode.typeParameters = this.flowParseTypeParameterDeclaration(); } else { typeNode.typeParameters = null; @@ -600,7 +600,7 @@ export default (superClass: Class): Class => node.id.start, ); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterDeclaration(); } else { node.typeParameters = null; @@ -643,7 +643,7 @@ export default (superClass: Class): Class => const node = this.startNode(); node.id = this.flowParseQualifiedTypeIdentifier(); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterInstantiation(); } else { node.typeParameters = null; @@ -692,7 +692,7 @@ export default (superClass: Class): Class => ); this.scope.declareName(node.id.name, BIND_LEXICAL, node.id.start); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterDeclaration(); } else { node.typeParameters = null; @@ -715,7 +715,7 @@ export default (superClass: Class): Class => ); this.scope.declareName(node.id.name, BIND_LEXICAL, node.id.start); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterDeclaration(); } else { node.typeParameters = null; @@ -770,7 +770,7 @@ export default (superClass: Class): Class => this.state.inType = true; // istanbul ignore else: this condition is already checked at all call sites - if (this.isRelational("<") || this.match(tt.jsxTagStart)) { + if (this.match(tt.lt) || this.match(tt.jsxTagStart)) { this.next(); } else { this.unexpected(); @@ -787,11 +787,11 @@ export default (superClass: Class): Class => defaultRequired = true; } - if (!this.isRelational(">")) { + if (!this.match(tt.gt)) { this.expect(tt.comma); } - } while (!this.isRelational(">")); - this.expectRelational(">"); + } while (!this.match(tt.gt)); + this.expect(tt.gt); this.state.inType = oldInType; @@ -805,17 +805,17 @@ export default (superClass: Class): Class => this.state.inType = true; - this.expectRelational("<"); + this.expect(tt.lt); const oldNoAnonFunctionType = this.state.noAnonFunctionType; this.state.noAnonFunctionType = false; - while (!this.isRelational(">")) { + while (!this.match(tt.gt)) { node.params.push(this.flowParseType()); - if (!this.isRelational(">")) { + if (!this.match(tt.gt)) { this.expect(tt.comma); } } this.state.noAnonFunctionType = oldNoAnonFunctionType; - this.expectRelational(">"); + this.expect(tt.gt); this.state.inType = oldInType; @@ -829,14 +829,14 @@ export default (superClass: Class): Class => this.state.inType = true; - this.expectRelational("<"); - while (!this.isRelational(">")) { + this.expect(tt.lt); + while (!this.match(tt.gt)) { node.params.push(this.flowParseTypeOrImplicitInstantiation()); - if (!this.isRelational(">")) { + if (!this.match(tt.gt)) { this.expect(tt.comma); } } - this.expectRelational(">"); + this.expect(tt.gt); this.state.inType = oldInType; @@ -902,7 +902,7 @@ export default (superClass: Class): Class => node.id = this.flowParseObjectPropertyKey(); this.expect(tt.bracketR); this.expect(tt.bracketR); - if (this.isRelational("<") || this.match(tt.parenL)) { + if (this.match(tt.lt) || this.match(tt.parenL)) { node.method = true; node.optional = false; node.value = this.flowParseObjectTypeMethodish( @@ -926,7 +926,7 @@ export default (superClass: Class): Class => node.typeParameters = null; node.this = null; - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterDeclaration(); } @@ -1047,7 +1047,7 @@ export default (superClass: Class): Class => this.flowParseObjectTypeIndexer(node, isStatic, variance), ); } - } else if (this.match(tt.parenL) || this.isRelational("<")) { + } else if (this.match(tt.parenL) || this.match(tt.lt)) { if (protoStart != null) { this.unexpected(protoStart); } @@ -1169,7 +1169,7 @@ export default (superClass: Class): Class => node.kind = kind; let optional = false; - if (this.isRelational("<") || this.match(tt.parenL)) { + if (this.match(tt.lt) || this.match(tt.parenL)) { // This is a method property node.method = true; @@ -1287,7 +1287,7 @@ export default (superClass: Class): Class => node.typeParameters = null; node.id = this.flowParseQualifiedTypeIdentifier(startPos, startLoc, id); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterInstantiation(); } @@ -1453,23 +1453,20 @@ export default (superClass: Class): Class => this.state.noAnonFunctionType = oldNoAnonFunctionType; return type; - case tt.relational: - if (this.state.value === "<") { - node.typeParameters = this.flowParseTypeParameterDeclaration(); - this.expect(tt.parenL); - tmp = this.flowParseFunctionTypeParams(); - node.params = tmp.params; - node.rest = tmp.rest; - node.this = tmp._this; - this.expect(tt.parenR); + case tt.lt: + node.typeParameters = this.flowParseTypeParameterDeclaration(); + this.expect(tt.parenL); + tmp = this.flowParseFunctionTypeParams(); + node.params = tmp.params; + node.rest = tmp.rest; + node.this = tmp._this; + this.expect(tt.parenR); - this.expect(tt.arrow); + this.expect(tt.arrow); - node.returnType = this.flowParseType(); + node.returnType = this.flowParseType(); - return this.finishNode(node, "FunctionTypeAnnotation"); - } - break; + return this.finishNode(node, "FunctionTypeAnnotation"); case tt.parenL: this.next(); @@ -2178,7 +2175,7 @@ export default (superClass: Class): Class => parseClassId(node: N.Class, isStatement: boolean, optionalId: ?boolean) { super.parseClassId(node, isStatement, optionalId); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterDeclaration(); } } @@ -2241,7 +2238,7 @@ export default (superClass: Class): Class => this.state.inType && (code === charCodes.greaterThan || code === charCodes.lessThan) ) { - return this.finishOp(tt.relational, 1); + return this.finishOp(code === charCodes.greaterThan ? tt.gt : tt.lt, 1); } else if (this.state.inType && code === charCodes.questionMark) { if (next === charCodes.dot) { return this.finishOp(tt.questionDot, 2); @@ -2369,7 +2366,7 @@ export default (superClass: Class): Class => // determine whether or not we're currently in the position where a class method would appear isClassMethod(): boolean { - return this.isRelational("<") || super.isClassMethod(); + return this.match(tt.lt) || super.isClassMethod(); } // determine whether or not we're currently in the position where a class property would appear @@ -2394,7 +2391,7 @@ export default (superClass: Class): Class => this.unexpected((method: $FlowFixMe).variance.start); } delete (method: $FlowFixMe).variance; - if (this.isRelational("<")) { + if (this.match(tt.lt)) { method.typeParameters = this.flowParseTypeParameterDeclaration(); } @@ -2436,7 +2433,7 @@ export default (superClass: Class): Class => this.unexpected((method: $FlowFixMe).variance.start); } delete (method: $FlowFixMe).variance; - if (this.isRelational("<")) { + if (this.match(tt.lt)) { method.typeParameters = this.flowParseTypeParameterDeclaration(); } @@ -2446,7 +2443,7 @@ export default (superClass: Class): Class => // parse a the super class type parameters and implements parseClassSuper(node: N.Class): void { super.parseClassSuper(node); - if (node.superClass && this.isRelational("<")) { + if (node.superClass && this.match(tt.lt)) { node.superTypeParameters = this.flowParseTypeParameterInstantiation(); } if (this.isContextual(tt._implements)) { @@ -2455,7 +2452,7 @@ export default (superClass: Class): Class => do { const node = this.startNode(); node.id = this.flowParseRestrictedIdentifier(/*liberal*/ true); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterInstantiation(); } else { node.typeParameters = null; @@ -2508,7 +2505,7 @@ export default (superClass: Class): Class => let typeParameters; // method shorthand - if (this.isRelational("<") && !isAccessor) { + if (this.match(tt.lt) && !isAccessor) { typeParameters = this.flowParseTypeParameterDeclaration(); if (!this.match(tt.parenL)) this.unexpected(); } @@ -2740,7 +2737,7 @@ export default (superClass: Class): Class => parseFunctionParams(node: N.Function, allowModifiers?: boolean): void { // $FlowFixMe const kind = node.kind; - if (kind !== "get" && kind !== "set" && this.isRelational("<")) { + if (kind !== "get" && kind !== "set" && this.match(tt.lt)) { node.typeParameters = this.flowParseTypeParameterDeclaration(); } super.parseFunctionParams(node, allowModifiers); @@ -2798,7 +2795,7 @@ export default (superClass: Class): Class => if ( this.hasPlugin("jsx") && - (this.match(tt.jsxTagStart) || this.isRelational("<")) + (this.match(tt.jsxTagStart) || this.match(tt.lt)) ) { state = this.state.clone(); @@ -2823,7 +2820,7 @@ export default (superClass: Class): Class => } } - if (jsx?.error || this.isRelational("<")) { + if (jsx?.error || this.match(tt.lt)) { state = state || this.state.clone(); let typeParameters; @@ -3020,7 +3017,7 @@ export default (superClass: Class): Class => } else if ( base.type === "Identifier" && base.name === "async" && - this.isRelational("<") + this.match(tt.lt) ) { const state = this.state.clone(); const arrow = this.tryParse( @@ -3081,11 +3078,7 @@ export default (superClass: Class): Class => node.arguments = this.parseCallExpressionArguments(tt.parenR, false); node.optional = true; return this.finishCallExpression(node, /* optional */ true); - } else if ( - !noCalls && - this.shouldParseTypes() && - this.isRelational("<") - ) { + } else if (!noCalls && this.shouldParseTypes() && this.match(tt.lt)) { const node = this.startNodeAt(startPos, startLoc); node.callee = base; @@ -3118,7 +3111,7 @@ export default (superClass: Class): Class => parseNewArguments(node: N.NewExpression): void { let targs = null; - if (this.shouldParseTypes() && this.isRelational("<")) { + if (this.shouldParseTypes() && this.match(tt.lt)) { targs = this.tryParse(() => this.flowParseTypeParameterInstantiationCallOrNew(), ).node; @@ -3665,7 +3658,7 @@ export default (superClass: Class): Class => return this.finishNode(node, "EnumDeclaration"); } - // check if the next token is a tt.relation("<") + // check if the next token is a tt.lt isLookaheadToken_lt(): boolean { const next = this.nextTokenStart(); if (this.input.charCodeAt(next) === charCodes.lessThan) { diff --git a/packages/babel-parser/src/plugins/jsx/index.js b/packages/babel-parser/src/plugins/jsx/index.js index 66da2eaed799..eabf67a94abe 100644 --- a/packages/babel-parser/src/plugins/jsx/index.js +++ b/packages/babel-parser/src/plugins/jsx/index.js @@ -520,7 +520,7 @@ export default (superClass: Class): Class => node.closingElement = closingElement; } node.children = children; - if (this.isRelational("<")) { + if (this.match(tt.lt)) { throw this.raise( this.state.start, JsxErrors.UnwrappedAdjacentJSXElements, @@ -551,7 +551,7 @@ export default (superClass: Class): Class => } else if (this.match(tt.jsxTagStart)) { return this.jsxParseElement(); } else if ( - this.isRelational("<") && + this.match(tt.lt) && this.input.charCodeAt(this.state.pos) !== charCodes.exclamationMark ) { // In case we encounter an lt token here it will always be the start of diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 4f1705b9c4bc..864a3bb351c8 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -351,7 +351,7 @@ export default (superClass: Class): Class => case "TupleElementTypes": return this.match(tt.bracketR); case "TypeParametersOrArguments": - return this.isRelational(">"); + return this.match(tt.gt); } throw new Error("Unreachable"); @@ -440,7 +440,7 @@ export default (superClass: Class): Class => if (bracket) { this.expect(tt.bracketL); } else { - this.expectRelational("<"); + this.expect(tt.lt); } } @@ -453,7 +453,7 @@ export default (superClass: Class): Class => if (bracket) { this.expect(tt.bracketR); } else { - this.expectRelational(">"); + this.expect(tt.gt); } return result; @@ -474,7 +474,7 @@ export default (superClass: Class): Class => if (this.eat(tt.dot)) { node.qualifier = this.tsParseEntityName(/* allowReservedWords */ true); } - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.tsParseTypeArguments(); } return this.finishNode(node, "TSImportType"); @@ -494,7 +494,7 @@ export default (superClass: Class): Class => tsParseTypeReference(): N.TsTypeReference { const node: N.TsTypeReference = this.startNode(); node.typeName = this.tsParseEntityName(/* allowReservedWords */ false); - if (!this.hasPrecedingLineBreak() && this.isRelational("<")) { + if (!this.hasPrecedingLineBreak() && this.match(tt.lt)) { node.typeParameters = this.tsParseTypeArguments(); } return this.finishNode(node, "TSTypeReference"); @@ -535,7 +535,7 @@ export default (superClass: Class): Class => } tsTryParseTypeParameters(): ?N.TsTypeParameterDeclaration { - if (this.isRelational("<")) { + if (this.match(tt.lt)) { return this.tsParseTypeParameters(); } } @@ -543,7 +543,7 @@ export default (superClass: Class): Class => tsParseTypeParameters() { const node: N.TsTypeParameterDeclaration = this.startNode(); - if (this.isRelational("<") || this.match(tt.jsxTagStart)) { + if (this.match(tt.lt) || this.match(tt.jsxTagStart)) { this.next(); } else { this.unexpected(); @@ -672,12 +672,12 @@ export default (superClass: Class): Class => if (this.eat(tt.question)) node.optional = true; const nodeAny: any = node; - if (this.match(tt.parenL) || this.isRelational("<")) { + if (this.match(tt.parenL) || this.match(tt.lt)) { if (readonly) { this.raise(node.start, TSErrors.ReadonlyForMethodSignature); } const method: N.TsMethodSignature = nodeAny; - if (method.kind && this.isRelational("<")) { + if (method.kind && this.match(tt.lt)) { this.raise(this.state.pos, TSErrors.AccesorCannotHaveTypeParameters); } this.tsFillSignature(tt.colon, method); @@ -742,14 +742,14 @@ export default (superClass: Class): Class => tsParseTypeMember(): N.TsTypeElement { const node: any = this.startNode(); - if (this.match(tt.parenL) || this.isRelational("<")) { + if (this.match(tt.parenL) || this.match(tt.lt)) { return this.tsParseSignatureMember("TSCallSignatureDeclaration", node); } if (this.match(tt._new)) { const id: N.Identifier = this.startNode(); this.next(); - if (this.match(tt.parenL) || this.isRelational("<")) { + if (this.match(tt.parenL) || this.match(tt.lt)) { return this.tsParseSignatureMember( "TSConstructSignatureDeclaration", node, @@ -1199,7 +1199,7 @@ export default (superClass: Class): Class => } tsIsStartOfFunctionType() { - if (this.isRelational("<")) { + if (this.match(tt.lt)) { return true; } return ( @@ -1441,7 +1441,7 @@ export default (superClass: Class): Class => const node: N.TsTypeAssertion = this.startNode(); const _const = this.tsTryNextParseConstantContext(); node.typeAnnotation = _const || this.tsNextThenParseType(); - this.expectRelational(">"); + this.expect(tt.gt); node.expression = this.parseMaybeUnary(); return this.finishNode(node, "TSTypeAssertion"); } @@ -1468,7 +1468,7 @@ export default (superClass: Class): Class => // Note: TS uses parseLeftHandSideExpressionOrHigher, // then has grammar errors later if it's not an EntityName. node.expression = this.tsParseEntityName(/* allowReservedWords */ false); - if (this.isRelational("<")) { + if (this.match(tt.lt)) { node.typeParameters = this.tsParseTypeArguments(); } @@ -1917,7 +1917,7 @@ export default (superClass: Class): Class => startPos: number, startLoc: Position, ): ?N.ArrowFunctionExpression { - if (!this.isRelational("<")) { + if (!this.match(tt.lt)) { return undefined; } @@ -1955,7 +1955,7 @@ export default (superClass: Class): Class => node.params = this.tsInType(() => // Temporarily remove a JSX parsing context, which makes us scan different tokens. this.tsInNoContext(() => { - this.expectRelational("<"); + this.expect(tt.lt); return this.tsParseDelimitedList( "TypeParametersOrArguments", this.tsParseType.bind(this), @@ -1965,7 +1965,7 @@ export default (superClass: Class): Class => if (node.params.length === 0) { this.raise(node.start, TSErrors.EmptyTypeArguments); } - this.expectRelational(">"); + this.expect(tt.gt); return this.finishNode(node, "TSTypeParameterInstantiation"); } @@ -2149,7 +2149,7 @@ export default (superClass: Class): Class => this.next(); } - if (this.isRelational("<")) { + if (this.match(tt.lt)) { let missingParenErrorPos; // tsTryParseAndCatch is expensive, so avoid if not necessary. // There are number of things we are going to "maybe" parse, like type arguments on @@ -2222,7 +2222,7 @@ export default (superClass: Class): Class => } parseNewArguments(node: N.NewExpression): void { - if (this.isRelational("<")) { + if (this.match(tt.lt)) { // tsTryParseAndCatch is expensive, so avoid if not necessary. // 99% certain this is `new C();`. But may be `new C < T;`, which is also legal. const typeParameters = this.tsTryParseAndCatch(() => { @@ -2803,7 +2803,7 @@ export default (superClass: Class): Class => parseClassSuper(node: N.Class): void { super.parseClassSuper(node); - if (node.superClass && this.isRelational("<")) { + if (node.superClass && this.match(tt.lt)) { node.superTypeParameters = this.tsParseTypeArguments(); } if (this.eatContextual(tt._implements)) { @@ -2861,7 +2861,7 @@ export default (superClass: Class): Class => if ( this.hasPlugin("jsx") && - (this.match(tt.jsxTagStart) || this.isRelational("<")) + (this.match(tt.jsxTagStart) || this.match(tt.lt)) ) { // Prefer to parse JSX if possible. But may be an arrow fn. state = this.state.clone(); @@ -2883,7 +2883,7 @@ export default (superClass: Class): Class => } } - if (!jsx?.error && !this.isRelational("<")) { + if (!jsx?.error && !this.match(tt.lt)) { return super.parseMaybeAssign(...args); } @@ -2973,7 +2973,7 @@ export default (superClass: Class): Class => // Handle type assertions parseMaybeUnary(refExpressionErrors?: ?ExpressionErrors): N.Expression { - if (!this.hasPlugin("jsx") && this.isRelational("<")) { + if (!this.hasPlugin("jsx") && this.match(tt.lt)) { return this.tsParseTypeAssertion(); } else { return super.parseMaybeUnary(refExpressionErrors); @@ -3114,7 +3114,7 @@ export default (superClass: Class): Class => } parseMaybeDecoratorArguments(expr: N.Expression): N.Expression { - if (this.isRelational("<")) { + if (this.match(tt.lt)) { const typeArguments = this.tsParseTypeArguments(); if (this.match(tt.parenL)) { @@ -3147,7 +3147,7 @@ export default (superClass: Class): Class => // === === === === === === === === === === === === === === === === isClassMethod(): boolean { - return this.isRelational("<") || super.isClassMethod(); + return this.match(tt.lt) || super.isClassMethod(); } isClassProperty(): boolean { @@ -3175,24 +3175,26 @@ export default (superClass: Class): Class => // ensure that inside types, we bypass the jsx parser plugin getTokenFromCode(code: number): void { - if ( - this.state.inType && - (code === charCodes.greaterThan || code === charCodes.lessThan) - ) { - return this.finishOp(tt.relational, 1); - } else { - return super.getTokenFromCode(code); + if (this.state.inType) { + if (code === charCodes.greaterThan) { + return this.finishOp(tt.gt, 1); + } + if (code === charCodes.lessThan) { + return this.finishOp(tt.lt, 1); + } } + return super.getTokenFromCode(code); } // used after we have finished parsing types reScan_lt_gt() { - if (this.match(tt.relational)) { - const code = this.input.charCodeAt(this.state.start); - if (code === charCodes.lessThan || code === charCodes.greaterThan) { - this.state.pos -= 1; - this.readToken_lt_gt(code); - } + const { type } = this.state; + if (type === tt.lt) { + this.state.pos -= 1; + this.readToken_lt(); + } else if (type === tt.gt) { + this.state.pos -= 1; + this.readToken_gt(); } } @@ -3248,7 +3250,7 @@ export default (superClass: Class): Class => jsxParseOpeningElementAfterName( node: N.JSXOpeningElement, ): N.JSXOpeningElement { - if (this.isRelational("<")) { + if (this.match(tt.lt)) { const typeArguments = this.tsTryParseAndCatch(() => this.tsParseTypeArguments(), ); diff --git a/packages/babel-parser/src/tokenizer/index.js b/packages/babel-parser/src/tokenizer/index.js index 93d19926876f..8050c1395666 100644 --- a/packages/babel-parser/src/tokenizer/index.js +++ b/packages/babel-parser/src/tokenizer/index.js @@ -727,18 +727,38 @@ export default class Tokenizer extends ParserErrors { } } - readToken_lt_gt(code: number): void { - // '<>' - const next = this.input.charCodeAt(this.state.pos + 1); - let size = 1; + readToken_lt(): void { + // '<' + const { pos } = this.state; + const next = this.input.charCodeAt(pos + 1); - if (next === code) { - size = - code === charCodes.greaterThan && - this.input.charCodeAt(this.state.pos + 2) === charCodes.greaterThan - ? 3 - : 2; - if (this.input.charCodeAt(this.state.pos + size) === charCodes.equalsTo) { + if (next === charCodes.lessThan) { + if (this.input.charCodeAt(pos + 2) === charCodes.equalsTo) { + this.finishOp(tt.assign, 3); + return; + } + this.finishOp(tt.bitShift, 2); + return; + } + + if (next === charCodes.equalsTo) { + // <= + this.finishOp(tt.relational, 2); + return; + } + + this.finishOp(tt.lt, 1); + } + + readToken_gt(): void { + // '>' + const { pos } = this.state; + const next = this.input.charCodeAt(pos + 1); + + if (next === charCodes.greaterThan) { + const size = + this.input.charCodeAt(pos + 2) === charCodes.greaterThan ? 3 : 2; + if (this.input.charCodeAt(pos + size) === charCodes.equalsTo) { this.finishOp(tt.assign, size + 1); return; } @@ -748,10 +768,11 @@ export default class Tokenizer extends ParserErrors { if (next === charCodes.equalsTo) { // <= | >= - size = 2; + this.finishOp(tt.relational, 2); + return; } - this.finishOp(tt.relational, size); + this.finishOp(tt.gt, 1); } readToken_eq_excl(code: number): void { @@ -963,8 +984,11 @@ export default class Tokenizer extends ParserErrors { return; case charCodes.lessThan: + this.readToken_lt(); + return; + case charCodes.greaterThan: - this.readToken_lt_gt(code); + this.readToken_gt(); return; case charCodes.equalsTo: diff --git a/packages/babel-parser/src/tokenizer/types.js b/packages/babel-parser/src/tokenizer/types.js index c9e8f2628c8e..974d9bcb9591 100644 --- a/packages/babel-parser/src/tokenizer/types.js +++ b/packages/babel-parser/src/tokenizer/types.js @@ -200,6 +200,8 @@ export const tt: { [name: string]: TokenType } = { bitwiseXOR: createBinop("^", 4), bitwiseAND: createBinop("&", 5), equality: createBinop("==/!=/===/!==", 6), + lt: createBinop("/<=/>=", 7), + gt: createBinop("/<=/>=", 7), relational: createBinop("/<=/>=", 7), bitShift: createBinop("<>/>>>", 8), plusMin: createToken("+/-", { beforeExpr, binop: 9, prefix, startsExpr }),