同步KDL工程源码到云仓库
This commit is contained in:
148
kdl-wasm/web/tests/grl/semanticIr.test.ts
Normal file
148
kdl-wasm/web/tests/grl/semanticIr.test.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { parseGrl } from "../../src/grl/parser/index.js";
|
||||
import { compileSemanticProgram } from "../../src/grl/semantic/index.js";
|
||||
|
||||
const PROGRAM = `language grl 0.1
|
||||
module Main
|
||||
const speed vj = joint(50 %)
|
||||
const speed vl = linear(200 mm/s)
|
||||
const zone zf = fine
|
||||
target home = joint_target { joints: [0 deg] }
|
||||
target pick = pose_target { pose: pose(500 mm, 0 mm, 0 mm, 0 deg, 0 deg, 0 deg) }
|
||||
path pick_path {
|
||||
defaults { speed: vl, zone: zf }
|
||||
point p0 movej home speed vj zone fine
|
||||
point p1 movel pick
|
||||
event before p1 io.do[1] = true
|
||||
}
|
||||
operation pick_op {
|
||||
kind: handling
|
||||
path: pick_path
|
||||
start_action:
|
||||
io.do[2] = true
|
||||
end_action:
|
||||
io.do[2] = false
|
||||
}
|
||||
proc set_done(out bool done)
|
||||
done = true
|
||||
end
|
||||
proc main(out bool done)
|
||||
set_speed vl
|
||||
set_zone zf
|
||||
movej home speed vj zone fine
|
||||
io.do[3] = true
|
||||
wait io.di[1] == true timeout 1 s
|
||||
if done == false
|
||||
pulse io.do[4] duration 100 ms
|
||||
else
|
||||
alarm DONE "Already done"
|
||||
end
|
||||
call set_done(done)
|
||||
run_path pick_path
|
||||
run_operation pick_op
|
||||
return
|
||||
end
|
||||
end
|
||||
`;
|
||||
|
||||
describe("GRL semantic analyzer, executable IR, and source map", () => {
|
||||
it("compiles a complete program into unified executable IR and KDL bridge requests", () => {
|
||||
const ir = compileSemanticProgram(parseGrl(PROGRAM), {
|
||||
startJoints: [0],
|
||||
sampleTime: 0.004
|
||||
});
|
||||
|
||||
expect(ir.moduleName).toBe("Main");
|
||||
expect(ir.semanticChecks).toHaveLength(22);
|
||||
expect(ir.symbols).toEqual([
|
||||
expect.objectContaining({ kind: "data", name: "vj", typeName: "speed" }),
|
||||
expect.objectContaining({ kind: "data", name: "vl", typeName: "speed" }),
|
||||
expect.objectContaining({ kind: "data", name: "zf", typeName: "zone" }),
|
||||
expect.objectContaining({ kind: "target", name: "home" }),
|
||||
expect.objectContaining({ kind: "target", name: "pick" }),
|
||||
expect.objectContaining({ kind: "path", name: "pick_path" }),
|
||||
expect.objectContaining({ kind: "operation", name: "pick_op" }),
|
||||
expect.objectContaining({ kind: "procedure", name: "set_done" }),
|
||||
expect.objectContaining({ kind: "procedure", name: "main" })
|
||||
]);
|
||||
expect(ir.paths).toHaveLength(1);
|
||||
expect(ir.operations).toHaveLength(1);
|
||||
expect(ir.kdlBridge.pathRequests).toEqual([
|
||||
expect.objectContaining({
|
||||
pathId: "pick_path",
|
||||
segments: [
|
||||
expect.objectContaining({ id: "p0", motion: "MOVEJ" }),
|
||||
expect.objectContaining({ id: "p1", motion: "MOVEL" })
|
||||
]
|
||||
})
|
||||
]);
|
||||
expect(ir.kdlBridge.motionRequests).toEqual([
|
||||
expect.objectContaining({
|
||||
startJoints: [0],
|
||||
speed: { kind: "joint_percent", value: 0.5 },
|
||||
zone: { kind: "fine" },
|
||||
sampleTime: 0.004
|
||||
})
|
||||
]);
|
||||
|
||||
const main = ir.procedures.find((procedure) => procedure.name === "main")!;
|
||||
expect(main.instructions).toEqual([
|
||||
expect.objectContaining({ kind: "MOVEJ" }),
|
||||
expect.objectContaining({ kind: "IO_WRITE", target: expect.objectContaining({ domain: "do", index: 3 }) }),
|
||||
expect.objectContaining({ kind: "WAIT", timeout: 1 }),
|
||||
expect.objectContaining({
|
||||
kind: "EXEC_IF",
|
||||
branches: [
|
||||
expect.objectContaining({
|
||||
branchKind: "if",
|
||||
body: expect.arrayContaining([expect.objectContaining({ kind: "PULSE", duration: 0.1 })])
|
||||
}),
|
||||
expect.objectContaining({
|
||||
branchKind: "else",
|
||||
body: expect.arrayContaining([expect.objectContaining({ kind: "ALARM", alarmId: "DONE" })])
|
||||
})
|
||||
]
|
||||
}),
|
||||
expect.objectContaining({ kind: "CALL", target: "set_done" }),
|
||||
expect.objectContaining({ kind: "RUN_PATH", pathId: "pick_path" }),
|
||||
expect.objectContaining({ kind: "RUN_OPERATION", operationId: "pick_op" }),
|
||||
expect.objectContaining({ kind: "RETURN" })
|
||||
]);
|
||||
});
|
||||
|
||||
it("exposes source map entries for GRL procedure lines, path points, and operation actions", () => {
|
||||
const ir = compileSemanticProgram(parseGrl(PROGRAM), {
|
||||
startJoints: [0],
|
||||
sampleTime: 0.004
|
||||
});
|
||||
|
||||
expect(ir.sourceMap).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ kind: "path_point", pathId: "pick_path", pointId: "p0" }),
|
||||
expect.objectContaining({ kind: "path_point", pathId: "pick_path", pointId: "p1" }),
|
||||
expect.objectContaining({ kind: "operation_action", operationId: "pick_op" }),
|
||||
expect.objectContaining({ kind: "MOVEJ", procedureId: "main", sourceMap: expect.objectContaining({ line: 28 }) }),
|
||||
expect.objectContaining({ kind: "EXEC_IF", procedureId: "main" }),
|
||||
expect.objectContaining({ kind: "RUN_OPERATION", procedureId: "main" })
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("reports duplicate symbols through semantic diagnostics", () => {
|
||||
const ir = compileSemanticProgram(parseGrl(`language grl 0.1
|
||||
module Main
|
||||
const speed v = joint(10 %)
|
||||
const speed v = joint(20 %)
|
||||
proc main()
|
||||
end
|
||||
end
|
||||
`), {
|
||||
startJoints: [],
|
||||
sampleTime: 0.004
|
||||
});
|
||||
|
||||
expect(ir.diagnostics).toEqual([
|
||||
expect.objectContaining({ severity: "error", code: "GRL_SYMBOL_DUPLICATE" })
|
||||
]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user