mirror of
https://github.com/Horizontal42/summarum.git
synced 2026-11-10 20:21:58 +03:00
🧹 Code Health: Extract operation parsing to reduce parseExpr complexity
Co-authored-by: Horizontal42 <75383519+Horizontal42@users.noreply.github.com>
This commit is contained in:
parent
bede889ced
commit
33b988818d
1 changed files with 108 additions and 116 deletions
|
|
@ -217,136 +217,128 @@ 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;
|
||||||
|
|
||||||
|
const nextLhs = this.parseExprOp(lhs, minPrec, tk);
|
||||||
|
if (nextLhs === undefined) break;
|
||||||
|
lhs = nextLhs;
|
||||||
|
}
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseExprOp(lhs: Node, minPrec: number, tk: Token): Node | undefined {
|
||||||
switch (tk.t) {
|
switch (tk.t) {
|
||||||
case "percent": {
|
case "percent": {
|
||||||
if (PREC.POSTFIX < minPrec) break loop;
|
if (PREC.POSTFIX < minPrec) return undefined;
|
||||||
this.i++;
|
this.i++;
|
||||||
lhs = { k: "pct", x: lhs };
|
return { k: "pct", x: lhs };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "bang": {
|
case "bang": {
|
||||||
if (PREC.POSTFIX < minPrec) break loop;
|
if (PREC.POSTFIX < minPrec) return undefined;
|
||||||
this.i++;
|
this.i++;
|
||||||
lhs = { k: "fact", x: lhs };
|
return { k: "fact", x: lhs };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "unit": {
|
case "unit": {
|
||||||
if (PREC.POSTFIX < minPrec) break loop;
|
if (PREC.POSTFIX < minPrec) return undefined;
|
||||||
this.i++;
|
this.i++;
|
||||||
lhs = { k: "unit", x: lhs, unit: tk.unit };
|
return { k: "unit", x: lhs, unit: tk.unit };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "currency": {
|
case "currency": {
|
||||||
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: "curr", x: lhs, code: tk.code };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "scale": {
|
case "scale": {
|
||||||
if (PREC.POSTFIX < minPrec) break loop;
|
if (PREC.POSTFIX < minPrec) return undefined;
|
||||||
this.i++;
|
this.i++;
|
||||||
lhs = { k: "scale", x: lhs, mult: tk.mult, label: "" };
|
return { k: "scale", x: lhs, mult: tk.mult, label: "" };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "op": {
|
case "op": {
|
||||||
switch (tk.op) {
|
switch (tk.op) {
|
||||||
case "pow": {
|
case "pow": {
|
||||||
if (PREC.POW < minPrec) break loop;
|
if (PREC.POW < minPrec) return undefined;
|
||||||
const save = this.i;
|
const save = this.i;
|
||||||
this.i++;
|
this.i++;
|
||||||
const r = this.parseExpr(PREC.POW);
|
const r = this.parseExpr(PREC.POW);
|
||||||
if (!r) { this.i = save; break loop; }
|
if (!r) { this.i = save; return undefined; }
|
||||||
lhs = { k: "bin", op: "pow", l: lhs, r };
|
return { k: "bin", op: "pow", l: lhs, r };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "mul":
|
case "mul":
|
||||||
case "div":
|
case "div":
|
||||||
case "mod": {
|
case "mod": {
|
||||||
if (PREC.MUL < minPrec) break loop;
|
if (PREC.MUL < minPrec) return undefined;
|
||||||
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: "bin", op: tk.op, l: lhs, r };
|
return { k: "bin", op: tk.op, l: lhs, r };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "plus":
|
case "plus":
|
||||||
case "minus": {
|
case "minus": {
|
||||||
if (PREC.ADD < minPrec) break loop;
|
if (PREC.ADD < minPrec) return undefined;
|
||||||
const save = this.i;
|
const save = this.i;
|
||||||
this.i++;
|
this.i++;
|
||||||
const r = this.parseExpr(PREC.ADD + 1);
|
const r = this.parseExpr(PREC.ADD + 1);
|
||||||
if (!r) { this.i = save; break loop; }
|
if (!r) { this.i = save; return undefined; }
|
||||||
lhs = { k: "bin", op: tk.op, l: lhs, r };
|
return { k: "bin", op: tk.op, l: lhs, r };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break loop;
|
return undefined;
|
||||||
}
|
}
|
||||||
case "pctop": {
|
case "pctop": {
|
||||||
if (tk.op === "of" || tk.op === "off" || tk.op === "on") {
|
if (tk.op === "of" || tk.op === "off" || tk.op === "on") {
|
||||||
if (!(lhs.k === "pct" || lhs.k === "var" || lhs.k === "pctop")) {
|
if (!(lhs.k === "pct" || lhs.k === "var" || lhs.k === "pctop")) {
|
||||||
this.i++;
|
this.i++;
|
||||||
continue loop;
|
return lhs;
|
||||||
}
|
}
|
||||||
if (PREC.MUL < minPrec) break loop;
|
if (PREC.MUL < minPrec) return undefined;
|
||||||
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: "pctop", op: tk.op, l: lhs, r };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
if (tk.op.startsWith("as_pct") || tk.op.endsWith("what_is")) {
|
if (tk.op.startsWith("as_pct") || tk.op.endsWith("what_is")) {
|
||||||
if (PREC.CONV < minPrec) break loop;
|
if (PREC.CONV < 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);
|
||||||
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: "pctop", op: tk.op, l: lhs, r };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
break loop;
|
return undefined;
|
||||||
}
|
}
|
||||||
case "lparen":
|
case "lparen":
|
||||||
case "const":
|
case "const":
|
||||||
case "func":
|
case "func":
|
||||||
case "word": {
|
case "word": {
|
||||||
if (tk.t === "word" && !this.vars.has(tk.raw)) break loop;
|
if (tk.t === "word" && !this.vars.has(tk.raw)) return undefined;
|
||||||
if (PREC.MUL < minPrec) break loop;
|
if (PREC.MUL < minPrec) return undefined;
|
||||||
const save = this.i;
|
const save = 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: "bin", op: "mul", l: lhs, r };
|
return { k: "bin", op: "mul", l: lhs, r };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "bitop": {
|
case "bitop": {
|
||||||
if (PREC.BIT < minPrec) break loop;
|
if (PREC.BIT < minPrec) return undefined;
|
||||||
const save = this.i;
|
const save = this.i;
|
||||||
this.i++;
|
this.i++;
|
||||||
const r = this.parseExpr(PREC.BIT + 1);
|
const r = this.parseExpr(PREC.BIT + 1);
|
||||||
if (!r) { this.i = save; break loop; }
|
if (!r) { this.i = save; return undefined; }
|
||||||
lhs = { k: "bit", op: tk.op, l: lhs, r };
|
return { k: "bit", op: tk.op, l: lhs, r };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
case "conv": {
|
case "conv": {
|
||||||
if (PREC.CONV < minPrec) break loop;
|
if (PREC.CONV < minPrec) return undefined;
|
||||||
const save = this.i;
|
const save = this.i;
|
||||||
this.i++;
|
this.i++;
|
||||||
const target = this.parseTarget();
|
const target = this.parseTarget();
|
||||||
if (!target) { this.i = save; break loop; }
|
if (!target) { this.i = save; return undefined; }
|
||||||
lhs = { k: "conv", x: lhs, target: this.tryHistoricalDate(target) };
|
return { k: "conv", x: lhs, target: this.tryHistoricalDate(target) };
|
||||||
continue loop;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return undefined;
|
||||||
break;
|
|
||||||
}
|
|
||||||
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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue