mirror of
https://github.com/Horizontal42/summarum.git
synced 2026-11-10 22:41:58 +03:00
add parser tests for parseLine
This commit is contained in:
parent
e70c69df52
commit
adea6870fd
1 changed files with 95 additions and 0 deletions
95
src/engine/parser.test.ts
Normal file
95
src/engine/parser.test.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { parseLine } from "./parser";
|
||||||
|
import { tokenize } from "./tokenizer";
|
||||||
|
import { buildRegistry } from "./registry";
|
||||||
|
import { Decimal } from "./types";
|
||||||
|
|
||||||
|
const reg = buildRegistry();
|
||||||
|
|
||||||
|
function parse(line: string, knownVars = new Set<string>()) {
|
||||||
|
const tokens = tokenize(line, reg);
|
||||||
|
return parseLine(tokens, knownVars, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("parseLine", () => {
|
||||||
|
it("parses basic expressions", () => {
|
||||||
|
const res = parse("2 + 2");
|
||||||
|
expect(res.assign).toBeUndefined();
|
||||||
|
expect(res.expr).toMatchObject({
|
||||||
|
k: "bin",
|
||||||
|
op: "plus",
|
||||||
|
l: { k: "num", v: new Decimal(2) },
|
||||||
|
r: { k: "num", v: new Decimal(2) }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("parses variable assignment with '='", () => {
|
||||||
|
const res = parse("x = 5 + 3");
|
||||||
|
expect(res.assign).toBe("x");
|
||||||
|
expect(res.expr).toMatchObject({
|
||||||
|
k: "bin",
|
||||||
|
op: "plus",
|
||||||
|
l: { k: "num", v: new Decimal(5) },
|
||||||
|
r: { k: "num", v: new Decimal(3) }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("parses variable assignment with 'is'", () => {
|
||||||
|
const res = parse("myVar is 10");
|
||||||
|
expect(res.assign).toBe("myVar");
|
||||||
|
expect(res.expr).toMatchObject({
|
||||||
|
k: "num",
|
||||||
|
v: new Decimal(10)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects invalid variable names for assignment", () => {
|
||||||
|
const res = parse("123 = 5");
|
||||||
|
expect(res.assign).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("handles known variables shadowing built-ins", () => {
|
||||||
|
// "m" is normally a unit (meters), but if it's a known variable, it's treated as a word
|
||||||
|
const res = parse("m = 5", new Set(["m"]));
|
||||||
|
expect(res.assign).toBe("m");
|
||||||
|
expect(res.expr).toMatchObject({
|
||||||
|
k: "num",
|
||||||
|
v: new Decimal(5)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters noise words", () => {
|
||||||
|
// "what is 2 + 2" -> "what" and "is" are noise, leaving "2 + 2"
|
||||||
|
const res = parse("what is 2 + 2");
|
||||||
|
expect(res.expr).toMatchObject({
|
||||||
|
k: "bin",
|
||||||
|
op: "plus"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps words after a conversion operator (e.g., timezones)", () => {
|
||||||
|
// "now in Europe/Berlin"
|
||||||
|
// "Europe/Berlin" should be kept as a timezone, not dropped as noise.
|
||||||
|
const res = parse("now in Europe/Berlin");
|
||||||
|
expect(res.expr).toMatchObject({
|
||||||
|
k: "conv",
|
||||||
|
target: {
|
||||||
|
type: "tz"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("parses goal seek expressions", () => {
|
||||||
|
const res = parse("? * 1.2 = 1000");
|
||||||
|
expect(res.expr).toMatchObject({
|
||||||
|
k: "goalseek",
|
||||||
|
lhs: { k: "bin", op: "mul", l: { k: "unknown" }, r: { k: "num", v: new Decimal(1.2) } },
|
||||||
|
rhs: { k: "num", v: new Decimal(1000) }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns null expression for empty or noise-only lines", () => {
|
||||||
|
const res = parse("just some noise");
|
||||||
|
expect(res.expr).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Add table
Reference in a new issue