同步KDL工程源码到云仓库

This commit is contained in:
wangdequan
2026-06-27 08:45:38 -04:00
parent 93d8ede54b
commit 95c684fc4d
93 changed files with 25712 additions and 0 deletions

View File

@@ -0,0 +1,201 @@
import { describe, expect, it } from "vitest";
import type { GrlFunctionDeclaration, GrlProcedureDeclaration } from "../../src/grl/ast/index.js";
import { parseGrl } from "../../src/grl/parser/index.js";
import { analyzeProcFunctionSemantics } from "../../src/grl/semantic/index.js";
function declarations(source: string) {
return parseGrl(source).module.declarations;
}
describe("GRL proc, func, call, return, and scope semantics", () => {
it("parses function declarations and analyzes proc/func signatures, calls, returns, and warnings", () => {
const decls = declarations(`language grl 0.1
module Main
var int global_count = 0
proc read_sensor(out bool ok)
ok = true
end
proc main(in bool start, out bool done, inout int count)
call read_sensor(done)
call helper(count)
call self_check()
return
end
proc self_check()
call self_check()
end
func int helper(inout int value)
var int global_count = 1
return value
end
end
`);
const func = decls.find((decl): decl is GrlFunctionDeclaration => decl.kind === "FunctionDeclaration")!;
expect(func).toMatchObject({
kind: "FunctionDeclaration",
returnType: "int",
name: "helper",
bodyTokens: [
{ raw: "var" },
{ raw: "int" },
{ raw: "global_count" },
{ raw: "=" },
{ raw: "1" },
{ raw: "return" },
{ raw: "value" }
]
});
const analysis = analyzeProcFunctionSemantics(decls);
expect(analysis.procedures).toEqual([
expect.objectContaining({
name: "read_sensor",
parameters: [expect.objectContaining({ name: "ok", typeName: "bool", direction: "out" })]
}),
expect.objectContaining({
name: "main",
parameters: [
expect.objectContaining({ name: "start", typeName: "bool", direction: "in" }),
expect.objectContaining({ name: "done", typeName: "bool", direction: "out" }),
expect.objectContaining({ name: "count", typeName: "int", direction: "inout" })
]
}),
expect.objectContaining({ name: "self_check", parameters: [] })
]);
expect(analysis.functions).toEqual([
expect.objectContaining({
name: "helper",
returnType: "int",
parameters: [expect.objectContaining({ name: "value", typeName: "int", direction: "inout" })]
})
]);
expect(analysis.calls).toEqual([
expect.objectContaining({ kind: "CALL", target: "read_sensor", args: [expect.objectContaining({ text: "done" })] }),
expect.objectContaining({ kind: "CALL", target: "helper", args: [expect.objectContaining({ text: "count" })] }),
expect.objectContaining({ kind: "CALL", target: "self_check", args: [] }),
expect.objectContaining({ kind: "CALL", target: "self_check", args: [] })
]);
expect(analysis.returns).toEqual([
expect.objectContaining({ kind: "RETURN" }),
expect.objectContaining({ kind: "RETURN", value: expect.objectContaining({ text: "value" }) })
]);
expect(analysis.diagnostics).toEqual([
expect.objectContaining({ severity: "warning", code: "GRL_RECURSIVE_CALL" }),
expect.objectContaining({ severity: "warning", code: "GRL_NAME_SHADOWS_OUTER_SCOPE" })
]);
});
it("reports out parameters that are not assigned on all normal return paths", () => {
const decls = declarations(`language grl 0.1
module Main
proc main(out bool done)
if ready == true
done = true
end
return
end
end
`);
expect(() => analyzeProcFunctionSemantics(decls)).toThrowError(
expect.objectContaining({ code: "GRL_OUT_PARAM_NOT_ASSIGNED" })
);
});
it("reports out and inout call arguments that are not lvalues", () => {
const decls = declarations(`language grl 0.1
module Main
proc set_done(out bool done)
done = true
end
proc main()
call set_done(true)
end
end
`);
expect(() => analyzeProcFunctionSemantics(decls)).toThrowError(
expect.objectContaining({ code: "GRL_ARGUMENT_NOT_LVALUE" })
);
});
it("reports missing or incompatible function returns", () => {
const missingReturn = declarations(`language grl 0.1
module Main
func int bad(in bool ready)
if ready == true
return 1
end
end
end
`);
const wrongReturn = declarations(`language grl 0.1
module Main
func bool bad()
return 1
end
end
`);
expect(() => analyzeProcFunctionSemantics(missingReturn)).toThrowError(
expect.objectContaining({ code: "GRL_FUNC_MISSING_RETURN" })
);
expect(() => analyzeProcFunctionSemantics(wrongReturn)).toThrowError(
expect.objectContaining({ code: "GRL_RETURN_TYPE_MISMATCH" })
);
});
it("reports illegal function side effects and procedure return values", () => {
const functionSideEffect = declarations(`language grl 0.1
module Main
func bool bad()
wait io.di[1] == true
return true
end
end
`);
const procedureReturnValue = declarations(`language grl 0.1
module Main
proc main()
return true
end
end
`);
expect(() => analyzeProcFunctionSemantics(functionSideEffect)).toThrowError(
expect.objectContaining({ code: "GRL_FUNC_SIDE_EFFECT" })
);
expect(() => analyzeProcFunctionSemantics(procedureReturnValue)).toThrowError(
expect.objectContaining({ code: "GRL_RETURN_VALUE_IN_PROC" })
);
});
it("reports call target and argument type errors", () => {
const missingCall = declarations(`language grl 0.1
module Main
proc main()
call missing()
end
end
`);
const typeMismatch = declarations(`language grl 0.1
module Main
proc expects_int(in int value)
return
end
proc main()
call expects_int("bad")
end
end
`);
expect(() => analyzeProcFunctionSemantics(missingCall)).toThrowError(
expect.objectContaining({ code: "GRL_CALL_TARGET_NOT_FOUND" })
);
expect(() => analyzeProcFunctionSemantics(typeMismatch)).toThrowError(
expect.objectContaining({ code: "GRL_CALL_ARGUMENT_TYPE" })
);
});
});