🧹 refactor: Extract large switch from parser loop to parseExprStep

Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot] 2026-08-26 14:07:13 +00:00
parent 37cfd2144b
commit a893036772

View file

@ -217,136 +217,129 @@ class Parser {
if (!lhs) return null; if (!lhs) return null;
loop: for (;;) { for (;;) {
tk = this.peek(); tk = this.peek();
if (!tk) break; if (!tk) break;
switch (tk.t) { const nextLhs = this.parseExprStep(tk, lhs, minPrec);
case "percent": { if (nextLhs === undefined) break;
if (PREC.POSTFIX < minPrec) break loop; lhs = nextLhs;
this.i++; }
lhs = { k: "pct", x: lhs }; return lhs;
continue loop; }
}
case "bang": { private parseExprStep(tk: Token, lhs: Node, minPrec: number): Node | undefined {
if (PREC.POSTFIX < minPrec) break loop; switch (tk.t) {
this.i++; case "percent": {
lhs = { k: "fact", x: lhs }; if (PREC.POSTFIX < minPrec) return undefined;
continue loop; this.i++;
} return { k: "pct", x: lhs };
case "unit": { }
if (PREC.POSTFIX < minPrec) break loop; case "bang": {
this.i++; if (PREC.POSTFIX < minPrec) return undefined;
lhs = { k: "unit", x: lhs, unit: tk.unit }; this.i++;
continue loop; return { k: "fact", x: lhs };
} }
case "currency": { case "unit": {
if (PREC.POSTFIX < minPrec) break loop; if (PREC.POSTFIX < minPrec) return undefined;
this.i++; this.i++;
lhs = { k: "curr", x: lhs, code: tk.code }; return { k: "unit", x: lhs, unit: tk.unit };
continue loop; }
} case "currency": {
case "scale": { if (PREC.POSTFIX < minPrec) return undefined;
if (PREC.POSTFIX < minPrec) break loop; this.i++;
this.i++; return { k: "curr", x: lhs, code: tk.code };
lhs = { k: "scale", x: lhs, mult: tk.mult, label: "" }; }
continue loop; case "scale": {
} if (PREC.POSTFIX < minPrec) return undefined;
case "op": { this.i++;
switch (tk.op) { return { k: "scale", x: lhs, mult: tk.mult, label: "" };
case "pow": { }
if (PREC.POW < minPrec) break loop; case "op": {
const save = this.i; switch (tk.op) {
this.i++; case "pow": {
const r = this.parseExpr(PREC.POW); if (PREC.POW < minPrec) return undefined;
if (!r) { this.i = save; break loop; } const save = this.i;
lhs = { k: "bin", op: "pow", l: lhs, r }; this.i++;
continue loop; const r = this.parseExpr(PREC.POW);
} if (!r) { this.i = save; return undefined; }
case "mul": return { k: "bin", op: "pow", l: lhs, r };
case "div":
case "mod": {
if (PREC.MUL < minPrec) break loop;
const save = this.i;
this.i++;
const r = this.parseExpr(PREC.MUL + 1);
if (!r) { this.i = save; break loop; }
lhs = { k: "bin", op: tk.op, l: lhs, r };
continue loop;
}
case "plus":
case "minus": {
if (PREC.ADD < minPrec) break loop;
const save = this.i;
this.i++;
const r = this.parseExpr(PREC.ADD + 1);
if (!r) { this.i = save; break loop; }
lhs = { k: "bin", op: tk.op, l: lhs, r };
continue loop;
}
} }
break loop; case "mul":
} case "div":
case "pctop": { case "mod": {
if (tk.op === "of" || tk.op === "off" || tk.op === "on") { if (PREC.MUL < minPrec) return undefined;
if (!(lhs.k === "pct" || lhs.k === "var" || lhs.k === "pctop")) {
this.i++;
continue loop;
}
if (PREC.MUL < minPrec) break loop;
const save = this.i; const save = this.i;
this.i++; this.i++;
const r = this.parseExpr(PREC.MUL + 1); const r = this.parseExpr(PREC.MUL + 1);
if (!r) { this.i = save; break loop; } if (!r) { this.i = save; return undefined; }
lhs = { k: "pctop", op: tk.op, l: lhs, r }; return { k: "bin", op: tk.op, l: lhs, r };
continue loop;
} }
if (tk.op.startsWith("as_pct") || tk.op.endsWith("what_is")) { case "plus":
if (PREC.CONV < minPrec) break loop; case "minus": {
if (PREC.ADD < minPrec) return undefined;
const save = this.i; const save = this.i;
this.i++; this.i++;
const r = this.parseExpr(PREC.ADD); const r = this.parseExpr(PREC.ADD + 1);
if (!r) { this.i = save; break loop; } if (!r) { this.i = save; return undefined; }
lhs = { k: "pctop", op: tk.op, l: lhs, r }; return { k: "bin", op: tk.op, l: lhs, r };
continue loop;
} }
break loop;
}
case "lparen":
case "const":
case "func":
case "word": {
if (tk.t === "word" && !this.vars.has(tk.raw)) break loop;
if (PREC.MUL < minPrec) break loop;
const save = this.i;
const r = this.parseExpr(PREC.MUL + 1);
if (!r) { this.i = save; break loop; }
lhs = { k: "bin", op: "mul", l: lhs, r };
continue loop;
}
case "bitop": {
if (PREC.BIT < minPrec) break loop;
const save = this.i;
this.i++;
const r = this.parseExpr(PREC.BIT + 1);
if (!r) { this.i = save; break loop; }
lhs = { k: "bit", op: tk.op, l: lhs, r };
continue loop;
}
case "conv": {
if (PREC.CONV < minPrec) break loop;
const save = this.i;
this.i++;
const target = this.parseTarget();
if (!target) { this.i = save; break loop; }
lhs = { k: "conv", x: lhs, target: this.tryHistoricalDate(target) };
continue loop;
} }
return undefined;
} }
case "pctop": {
break; if (tk.op === "of" || tk.op === "off" || tk.op === "on") {
if (!(lhs.k === "pct" || lhs.k === "var" || lhs.k === "pctop")) {
this.i++;
return lhs;
}
if (PREC.MUL < minPrec) return undefined;
const save = this.i;
this.i++;
const r = this.parseExpr(PREC.MUL + 1);
if (!r) { this.i = save; return undefined; }
return { k: "pctop", op: tk.op, l: lhs, r };
}
if (tk.op.startsWith("as_pct") || tk.op.endsWith("what_is")) {
if (PREC.CONV < minPrec) return undefined;
const save = this.i;
this.i++;
const r = this.parseExpr(PREC.ADD);
if (!r) { this.i = save; return undefined; }
return { k: "pctop", op: tk.op, l: lhs, r };
}
return undefined;
}
case "lparen":
case "const":
case "func":
case "word": {
if (tk.t === "word" && !this.vars.has(tk.raw)) return undefined;
if (PREC.MUL < minPrec) return undefined;
const save = this.i;
const r = this.parseExpr(PREC.MUL + 1);
if (!r) { this.i = save; return undefined; }
return { k: "bin", op: "mul", l: lhs, r };
}
case "bitop": {
if (PREC.BIT < minPrec) return undefined;
const save = this.i;
this.i++;
const r = this.parseExpr(PREC.BIT + 1);
if (!r) { this.i = save; return undefined; }
return { k: "bit", op: tk.op, l: lhs, r };
}
case "conv": {
if (PREC.CONV < minPrec) return undefined;
const save = this.i;
this.i++;
const target = this.parseTarget();
if (!target) { this.i = save; return undefined; }
return { k: "conv", x: lhs, target: this.tryHistoricalDate(target) };
}
default:
return undefined;
} }
return lhs;
} }
/** If the current token is `pctop(on)` + `datelit`, consume them and attach `onDate`. */ /** If the current token is `pctop(on)` + `datelit`, consume them and attach `onDate`. */
private tryHistoricalDate(target: ConvTarget): ConvTarget { private tryHistoricalDate(target: ConvTarget): ConvTarget {