同步KDL工程源码到云仓库
This commit is contained in:
94
kdl-wasm/web/tests/grl/lexer.test.ts
Normal file
94
kdl-wasm/web/tests/grl/lexer.test.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { GRL_KEYWORDS, lexGrl, normalizeUnitLiteral, normalizeUnitValue } from "../../src/grl/lexer/index.js";
|
||||
import type { GrlNumberToken } from "../../src/grl/lexer/index.js";
|
||||
|
||||
function numbers(source: string): GrlNumberToken[] {
|
||||
return lexGrl(source).filter((token): token is GrlNumberToken => token.kind === "number");
|
||||
}
|
||||
|
||||
describe("GRL lexer", () => {
|
||||
it("recognizes comments, keywords, identifiers, and source positions", () => {
|
||||
const tokens = lexGrl(`// generated\nlanguage grl 0.1\nmodule Main\n proc main()\n end\nend\n`);
|
||||
|
||||
expect(tokens[0]).toMatchObject({
|
||||
kind: "comment",
|
||||
style: "line",
|
||||
value: " generated",
|
||||
range: {
|
||||
start: { line: 1, column: 1 },
|
||||
end: { line: 1, column: 13 }
|
||||
}
|
||||
});
|
||||
expect(tokens.filter((token) => token.kind === "keyword").map((token) => token.raw)).toEqual([
|
||||
"language",
|
||||
"module",
|
||||
"proc",
|
||||
"end",
|
||||
"end"
|
||||
]);
|
||||
expect(tokens.find((token) => token.raw === "Main")).toMatchObject({
|
||||
kind: "identifier",
|
||||
range: {
|
||||
start: { line: 3, column: 8 }
|
||||
}
|
||||
});
|
||||
expect(tokens.at(-1)).toMatchObject({ kind: "eof" });
|
||||
});
|
||||
|
||||
it("normalizes numeric literals with GRL units into SI values", () => {
|
||||
const found = numbers("100 mm 0.25 m 180 deg 3.14159 rad 300 mm/s 50 % 200 ms 2.5 kg 500 mm/s2");
|
||||
|
||||
expect(found.map((token) => token.unit?.raw)).toEqual([
|
||||
"mm",
|
||||
"m",
|
||||
"deg",
|
||||
"rad",
|
||||
"mm/s",
|
||||
"%",
|
||||
"ms",
|
||||
"kg",
|
||||
"mm/s2"
|
||||
]);
|
||||
expect(found[0]?.unit?.normalizedValue).toBeCloseTo(0.1);
|
||||
expect(found[1]?.unit?.normalizedValue).toBeCloseTo(0.25);
|
||||
expect(found[2]?.unit?.normalizedValue).toBeCloseTo(Math.PI);
|
||||
expect(found[3]?.unit?.normalizedValue).toBeCloseTo(3.14159);
|
||||
expect(found[4]?.unit?.normalizedValue).toBeCloseTo(0.3);
|
||||
expect(found[5]?.unit?.normalizedValue).toBeCloseTo(0.5);
|
||||
expect(found[6]?.unit?.normalizedValue).toBeCloseTo(0.2);
|
||||
expect(found[7]?.unit?.normalizedValue).toBeCloseTo(2.5);
|
||||
expect(found[8]?.unit?.normalizedValue).toBeCloseTo(0.5);
|
||||
});
|
||||
|
||||
it("keeps unit raw text on number tokens", () => {
|
||||
const [token] = numbers("linear(300 mm/s)");
|
||||
|
||||
expect(token).toMatchObject({
|
||||
kind: "number",
|
||||
raw: "300 mm/s",
|
||||
value: 300,
|
||||
unit: {
|
||||
raw: "mm/s",
|
||||
kind: "linear_velocity",
|
||||
siUnit: "m/s"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("exposes the full reserved keyword set from the specification", () => {
|
||||
expect(GRL_KEYWORDS).toContain("movej");
|
||||
expect(GRL_KEYWORDS).toContain("run_operation");
|
||||
expect(GRL_KEYWORDS).toContain("post_hint");
|
||||
expect(GRL_KEYWORDS).toContain("continuous");
|
||||
expect(GRL_KEYWORDS).toHaveLength(85);
|
||||
});
|
||||
|
||||
it("provides direct unit helpers for parser and semantic layers", () => {
|
||||
expect(normalizeUnitLiteral("deg/s")).toMatchObject({
|
||||
kind: "angular_velocity",
|
||||
siUnit: "rad/s"
|
||||
});
|
||||
expect(normalizeUnitValue(90, "deg/s")).toBeCloseTo(Math.PI / 2);
|
||||
expect(() => normalizeUnitLiteral("inch")).toThrow("Unknown GRL unit");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user