refactor: extract tt.lt and tt.gt from tt.relation (#13892)

This commit is contained in:
Huáng Jùnliàng 2021-11-01 21:15:42 -04:00 committed by GitHub
parent 05af38cff2
commit 1fa759f989
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 137 deletions

View File

@ -1211,23 +1211,24 @@ export default class ExpressionParser extends LValParser {
if (pipeProposal) {
return this.parseTopicReference(pipeProposal);
} else {
throw this.unexpected();
}
}
// fall through
case tt.relational: {
if (this.state.value === "<") {
case tt.lt: {
const lookaheadCh = this.input.codePointAt(this.nextTokenStart());
if (
isIdentifierStart(lookaheadCh) || // Element/Type Parameter <foo>
lookaheadCh === charCodes.greaterThan // Fragment <>
) {
this.expectOnePlugin(["jsx", "flow", "typescript"]);
}
break;
} else {
throw this.unexpected();
}
}
// fall through
default:
if (tokenIsIdentifier(type)) {
if (

View File

@ -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 {

View File

@ -316,7 +316,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
);
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<Parser>): Class<Parser> =>
);
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
node.typeParameters = null;
node.id = this.flowParseQualifiedTypeIdentifier(startPos, startLoc, id);
if (this.isRelational("<")) {
if (this.match(tt.lt)) {
node.typeParameters = this.flowParseTypeParameterInstantiation();
}
@ -1453,8 +1453,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.state.noAnonFunctionType = oldNoAnonFunctionType;
return type;
case tt.relational:
if (this.state.value === "<") {
case tt.lt:
node.typeParameters = this.flowParseTypeParameterDeclaration();
this.expect(tt.parenL);
tmp = this.flowParseFunctionTypeParams();
@ -1468,8 +1467,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.returnType = this.flowParseType();
return this.finishNode(node, "FunctionTypeAnnotation");
}
break;
case tt.parenL:
this.next();
@ -2178,7 +2175,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
// 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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
// 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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
}
}
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<Parser>): Class<Parser> =>
} 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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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) {

View File

@ -520,7 +520,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
} 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

View File

@ -351,7 +351,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
if (bracket) {
this.expect(tt.bracketL);
} else {
this.expectRelational("<");
this.expect(tt.lt);
}
}
@ -453,7 +453,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (bracket) {
this.expect(tt.bracketR);
} else {
this.expectRelational(">");
this.expect(tt.gt);
}
return result;
@ -474,7 +474,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
}
tsTryParseTypeParameters(): ?N.TsTypeParameterDeclaration {
if (this.isRelational("<")) {
if (this.match(tt.lt)) {
return this.tsParseTypeParameters();
}
}
@ -543,7 +543,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
}
tsIsStartOfFunctionType() {
if (this.isRelational("<")) {
if (this.match(tt.lt)) {
return true;
}
return (
@ -1441,7 +1441,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
// 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<Parser>): Class<Parser> =>
startPos: number,
startLoc: Position,
): ?N.ArrowFunctionExpression {
if (!this.isRelational("<")) {
if (!this.match(tt.lt)) {
return undefined;
}
@ -1955,7 +1955,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
}
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<T>();`. But may be `new C < T;`, which is also legal.
const typeParameters = this.tsTryParseAndCatch(() => {
@ -2803,7 +2803,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
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<Parser>): Class<Parser> =>
}
}
if (!jsx?.error && !this.isRelational("<")) {
if (!jsx?.error && !this.match(tt.lt)) {
return super.parseMaybeAssign(...args);
}
@ -2973,7 +2973,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// 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<Parser>): Class<Parser> =>
}
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<Parser>): Class<Parser> =>
// === === === === === === === === === === === === === === === ===
isClassMethod(): boolean {
return this.isRelational("<") || super.isClassMethod();
return this.match(tt.lt) || super.isClassMethod();
}
isClassProperty(): boolean {
@ -3175,24 +3175,26 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// 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) {
const { type } = this.state;
if (type === tt.lt) {
this.state.pos -= 1;
this.readToken_lt_gt(code);
}
this.readToken_lt();
} else if (type === tt.gt) {
this.state.pos -= 1;
this.readToken_gt();
}
}
@ -3248,7 +3250,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
jsxParseOpeningElementAfterName(
node: N.JSXOpeningElement,
): N.JSXOpeningElement {
if (this.isRelational("<")) {
if (this.match(tt.lt)) {
const typeArguments = this.tsTryParseAndCatch(() =>
this.tsParseTypeArguments(),
);

View File

@ -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:

View File

@ -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 }),