同步KDL工程源码到云仓库
This commit is contained in:
125
kdl-wasm/web/tests/grl/exceptionCompile.test.ts
Normal file
125
kdl-wasm/web/tests/grl/exceptionCompile.test.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { GrlProcedureDeclaration, GrlRawTopLevelDeclaration } from "../../src/grl/ast/index.js";
|
||||
import { parseGrl } from "../../src/grl/parser/index.js";
|
||||
import {
|
||||
analyzeExceptionSemantics,
|
||||
parseProcedureExceptionFlow
|
||||
} from "../../src/grl/semantic/index.js";
|
||||
|
||||
const PROGRAM = `language grl 0.1
|
||||
module Main
|
||||
trap recover_trap()
|
||||
raise E_STOP
|
||||
end
|
||||
task background cycle 10 ms
|
||||
call monitor()
|
||||
end
|
||||
proc main()
|
||||
alarm E_STOP "Emergency stop" severity fatal
|
||||
try
|
||||
raise E_STOP
|
||||
catch E_STOP
|
||||
alarm RECOVER "Recovering" severity warning
|
||||
finally
|
||||
alarm CLEANUP "Cleanup"
|
||||
end
|
||||
enable interrupt guard
|
||||
disable interrupt guard
|
||||
end
|
||||
end
|
||||
`;
|
||||
|
||||
function declarations() {
|
||||
return parseGrl(PROGRAM).module.declarations;
|
||||
}
|
||||
|
||||
describe("GRL alarm, raise, try/catch, interrupt, and task semantics", () => {
|
||||
it("keeps trap and task as parsed raw declarations for P1 diagnostics", () => {
|
||||
const raw = declarations().filter(
|
||||
(decl): decl is GrlRawTopLevelDeclaration => decl.kind === "RawTopLevelDeclaration"
|
||||
);
|
||||
|
||||
expect(raw[0]?.declarationType).toBe("trap");
|
||||
expect(raw[0]?.tokens[0]).toMatchObject({ raw: "trap" });
|
||||
expect(raw[0]?.tokens[1]).toMatchObject({ raw: "recover_trap" });
|
||||
expect(raw[1]?.declarationType).toBe("task");
|
||||
expect(raw[1]?.tokens[0]).toMatchObject({ raw: "task" });
|
||||
expect(raw[1]?.tokens[1]).toMatchObject({ raw: "background" });
|
||||
});
|
||||
|
||||
it("compiles alarm, raise, try/catch/finally, and interrupt diagnostics from procedure body", () => {
|
||||
const procedure = declarations().find(
|
||||
(decl): decl is GrlProcedureDeclaration => decl.kind === "ProcedureDeclaration"
|
||||
)!;
|
||||
|
||||
expect(parseProcedureExceptionFlow(procedure)).toEqual([
|
||||
expect.objectContaining({
|
||||
kind: "ALARM",
|
||||
alarmId: "E_STOP",
|
||||
message: "Emergency stop",
|
||||
severity: "fatal"
|
||||
}),
|
||||
expect.objectContaining({
|
||||
kind: "TRY",
|
||||
body: [expect.objectContaining({ kind: "RAISE", alarmId: "E_STOP" })],
|
||||
catches: [
|
||||
expect.objectContaining({
|
||||
alarmId: "E_STOP",
|
||||
body: [
|
||||
expect.objectContaining({
|
||||
kind: "ALARM",
|
||||
alarmId: "RECOVER",
|
||||
message: "Recovering",
|
||||
severity: "warning"
|
||||
})
|
||||
]
|
||||
})
|
||||
],
|
||||
finally: expect.objectContaining({
|
||||
body: [expect.objectContaining({ kind: "ALARM", alarmId: "CLEANUP", message: "Cleanup" })]
|
||||
})
|
||||
}),
|
||||
expect.objectContaining({ kind: "UNSUPPORTED_RUNTIME", feature: "interrupt" }),
|
||||
expect.objectContaining({ kind: "UNSUPPORTED_RUNTIME", feature: "interrupt" })
|
||||
]);
|
||||
});
|
||||
|
||||
it("reports P1 trap/task semantics as explicit unsupported diagnostics", () => {
|
||||
const analysis = analyzeExceptionSemantics(declarations());
|
||||
|
||||
expect(analysis.unsupported).toEqual([
|
||||
expect.objectContaining({ kind: "UNSUPPORTED_RUNTIME", feature: "trap" }),
|
||||
expect.objectContaining({ kind: "UNSUPPORTED_RUNTIME", feature: "task" })
|
||||
]);
|
||||
expect(analysis.diagnostics).toEqual([
|
||||
expect.objectContaining({ severity: "warning", code: "GRL_P1_UNIMPLEMENTED" }),
|
||||
expect.objectContaining({ severity: "warning", code: "GRL_P1_UNIMPLEMENTED" })
|
||||
]);
|
||||
});
|
||||
|
||||
it("reports missing alarm ids and try blocks without handlers", () => {
|
||||
const missingAlarmId = parseGrl(`language grl 0.1
|
||||
module Main
|
||||
proc main()
|
||||
alarm
|
||||
end
|
||||
end
|
||||
`).module.declarations.find((decl): decl is GrlProcedureDeclaration => decl.kind === "ProcedureDeclaration")!;
|
||||
const tryWithoutHandler = parseGrl(`language grl 0.1
|
||||
module Main
|
||||
proc main()
|
||||
try
|
||||
raise E_STOP
|
||||
end
|
||||
end
|
||||
end
|
||||
`).module.declarations.find((decl): decl is GrlProcedureDeclaration => decl.kind === "ProcedureDeclaration")!;
|
||||
|
||||
expect(() => parseProcedureExceptionFlow(missingAlarmId)).toThrowError(
|
||||
expect.objectContaining({ code: "GRL_ALARM_ID_MISSING" })
|
||||
);
|
||||
expect(() => parseProcedureExceptionFlow(tryWithoutHandler)).toThrowError(
|
||||
expect.objectContaining({ code: "GRL_TRY_HANDLER_MISSING" })
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user