落地 12.2 二十个用例目录:toml + .st + 期望表。
- tests/cases/ 01~20:13 正例 / 6 负例 / 1 运行时故障 - 负例冻结报错类别:非 GVL 写全局、同名全局、io.var 未声明、FUNCTION 写全局、未声明实例、循环调用 - tests/README 补充用例清单与点亮节奏
This commit is contained in:
@@ -4,6 +4,16 @@
|
||||
|
||||
可以 `add_test` 调 `STCompiler` / `BytecodeExecutor`(编译→执行管线),或直接链接 `compiler` + `vm` 做单元断言。样例工程数据按「一份 toml + 若干 `.st`」分子目录存放,不要做成 library。
|
||||
|
||||
## 用例目录(`cases/`)
|
||||
|
||||
每个用例一个子目录:`project.toml` + `.st` + `EXPECTED.md`(期望:通过 / 报哪类错)。清单与编号见 [`Doc/初步计划.md`](../Doc/初步计划.md) 12.2 节,共 20 个:
|
||||
|
||||
- 正例:01 空 MAIN、02 BOOL、03 短路、04 IF、05 WHILE、07 算术、08 TIME、09 GVL+EXTERNAL、13 FUNCTION、15 FB、17 TON、18 TOF/CTU、20 line1
|
||||
- 负例(编译错误/链接失败):10 非 GVL 写全局、11 同名全局、12 io.var 未声明、14 FUNCTION 写全局、16 未声明实例、19 循环调用
|
||||
- 运行时故障:06 cycle_limit 打满
|
||||
|
||||
12.2 完成标准:目录和期望表齐,此时大部分还编不过,属正常。实现阶段逐个点亮。
|
||||
|
||||
## 第一版要冻的
|
||||
|
||||
- 关键字表与约 20 个样例程序
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- 映像:MAIN(fn_id=0)字节码为一条 `RET`,`nregs=0`
|
||||
- 运行任意周期数无故障
|
||||
@@ -0,0 +1,2 @@
|
||||
PROGRAM MAIN
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case01"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- 执行后 `a` = TRUE、`b` = FALSE
|
||||
- `TRUE` / `FALSE` 是关键字,不是标识符
|
||||
@@ -0,0 +1,8 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
a : BOOL;
|
||||
b : BOOL;
|
||||
END_VAR
|
||||
a := TRUE;
|
||||
b := FALSE;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case02"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- 反汇编中 `AND` / `OR` 必须编成条件跳转(`JT` / `JF`),不得先算两侧再组合
|
||||
- v1 表达式无调用、无副作用;「右侧有副作用时不执行」以编译产物含条件跳转为验收标准
|
||||
@@ -0,0 +1,9 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
a : BOOL;
|
||||
b : BOOL;
|
||||
x : BOOL;
|
||||
END_VAR
|
||||
x := a AND b;
|
||||
x := a OR b;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case03"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- `sel` = 0 → `out` = 10;`sel` = 1 → `out` = 20;其他 → `out` = 30
|
||||
- 必须编成比较 + 条件跳转,不逐分支执行
|
||||
@@ -0,0 +1,13 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
sel : INT;
|
||||
out : INT;
|
||||
END_VAR
|
||||
IF sel = 0 THEN
|
||||
out := 10;
|
||||
ELSIF sel = 1 THEN
|
||||
out := 20;
|
||||
ELSE
|
||||
out := 30;
|
||||
END_IF
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case04"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,3 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- 循环结束后 `n` = 10(正常终止,不触发 cycle_limit)
|
||||
@@ -0,0 +1,9 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
n : INT;
|
||||
END_VAR
|
||||
n := 0;
|
||||
WHILE n < 10 DO
|
||||
n := n + 1;
|
||||
END_WHILE
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case05"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:运行时故障
|
||||
|
||||
- 单周期指令数超 `cycle_limit = 10`,VM 报故障并停止
|
||||
- 编译本身通过;WHILE 不做终止证明
|
||||
@@ -0,0 +1,4 @@
|
||||
PROGRAM MAIN
|
||||
WHILE TRUE DO
|
||||
END_WHILE
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case06"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 10
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- `a` = 42、`b` = 10、`c` = 32、`eq` = TRUE
|
||||
- 溢出饱和:`30000 + 30000` = 32767、`-30000 - 30000` = -32768(由 isa 饱和函数保证)
|
||||
@@ -0,0 +1,10 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
a, b, c : INT;
|
||||
eq : BOOL;
|
||||
END_VAR
|
||||
a := 7 * 6;
|
||||
b := a / 4;
|
||||
c := a - b;
|
||||
eq := c > 30;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case07"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- `t1` = 10 毫秒、`t2` = 1250 毫秒(内部一律毫秒)
|
||||
- `TIME` 与 `INT` 不混用;不支持 `T#` 以外的 TIME 语法
|
||||
@@ -0,0 +1,7 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
t1, t2 : TIME;
|
||||
END_VAR
|
||||
t1 := T#10ms;
|
||||
t2 := T#1s250ms;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case08"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- 符号表里 `G1` 的 global 与 external 指向**同一槽**,不是新变量
|
||||
- 执行后 `x` = 5(初值来自 GVL)
|
||||
@@ -0,0 +1,3 @@
|
||||
VAR_GLOBAL
|
||||
G1 : INT := 5;
|
||||
END_VAR
|
||||
@@ -0,0 +1,9 @@
|
||||
PROGRAM MAIN
|
||||
VAR_EXTERNAL
|
||||
G1 : INT;
|
||||
END_VAR
|
||||
VAR
|
||||
x : INT;
|
||||
END_VAR
|
||||
x := G1;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,11 @@
|
||||
[project]
|
||||
name = "case09"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["globals.st", "main.st"]
|
||||
|
||||
[gvl]
|
||||
file = "globals.st"
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译错误
|
||||
|
||||
- `other.st` 出现 `VAR_GLOBAL`,但 `gvl.file = globals.st`
|
||||
- 报错类别:VAR_GLOBAL 只允许出现在 gvl.file
|
||||
@@ -0,0 +1,3 @@
|
||||
VAR_GLOBAL
|
||||
G1 : BOOL;
|
||||
END_VAR
|
||||
@@ -0,0 +1,5 @@
|
||||
PROGRAM MAIN
|
||||
VAR_GLOBAL
|
||||
G2 : BOOL;
|
||||
END_VAR
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,11 @@
|
||||
[project]
|
||||
name = "case10"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["globals.st", "other.st"]
|
||||
|
||||
[gvl]
|
||||
file = "globals.st"
|
||||
@@ -0,0 +1,3 @@
|
||||
# 期望:链接失败
|
||||
|
||||
- 同名 `VAR_GLOBAL`(G1)出现两次,禁止覆盖
|
||||
@@ -0,0 +1,7 @@
|
||||
VAR_GLOBAL
|
||||
G1 : INT;
|
||||
END_VAR
|
||||
|
||||
VAR_GLOBAL
|
||||
G1 : INT;
|
||||
END_VAR
|
||||
@@ -0,0 +1,2 @@
|
||||
PROGRAM MAIN
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,11 @@
|
||||
[project]
|
||||
name = "case11"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["globals.st", "main.st"]
|
||||
|
||||
[gvl]
|
||||
file = "globals.st"
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译错误
|
||||
|
||||
- `[[io.input]]` 的 `var = "Nope"` 未在 GVL 声明
|
||||
- 报错类别:io.var 未在 GVL(io 不创造变量)
|
||||
@@ -0,0 +1,3 @@
|
||||
VAR_GLOBAL
|
||||
G1 : BOOL;
|
||||
END_VAR
|
||||
@@ -0,0 +1,2 @@
|
||||
PROGRAM MAIN
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,16 @@
|
||||
[project]
|
||||
name = "case12"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["globals.st", "main.st"]
|
||||
|
||||
[gvl]
|
||||
file = "globals.st"
|
||||
|
||||
[[io.input]]
|
||||
var = "Nope"
|
||||
channel = 0
|
||||
bit = 0
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- `CALL fn_id` + 有界调用帧;函数无内部状态
|
||||
- 执行后 `x` = 7;结果值 = 函数名赋值(`Add := ...`)
|
||||
@@ -0,0 +1,13 @@
|
||||
FUNCTION Add : INT
|
||||
VAR_INPUT
|
||||
a, b : INT;
|
||||
END_VAR
|
||||
Add := a + b;
|
||||
END_FUNCTION
|
||||
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
x : INT;
|
||||
END_VAR
|
||||
x := Add(3, 4);
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case13"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译错误
|
||||
|
||||
- `FUNCTION` 内写全局(此处经 `VAR_EXTERNAL` 写 `G1`)
|
||||
- 报错类别:FUNCTION 禁止写全局
|
||||
@@ -0,0 +1,3 @@
|
||||
VAR_GLOBAL
|
||||
G1 : INT;
|
||||
END_VAR
|
||||
@@ -0,0 +1,9 @@
|
||||
FUNCTION Bad : INT
|
||||
VAR_EXTERNAL
|
||||
G1 : INT;
|
||||
END_VAR
|
||||
G1 := 1;
|
||||
END_FUNCTION
|
||||
|
||||
PROGRAM MAIN
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,11 @@
|
||||
[project]
|
||||
name = "case14"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["globals.st", "main.st"]
|
||||
|
||||
[gvl]
|
||||
file = "globals.st"
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过
|
||||
|
||||
- FB 实例固定布局,`starter.Q` 字段偏移编译期算死
|
||||
- 命名输入绑定 `start` / `stop`;执行后 `q` = TRUE
|
||||
@@ -0,0 +1,8 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
starter : MotorStarter;
|
||||
q : BOOL;
|
||||
END_VAR
|
||||
starter(start := TRUE, stop := FALSE);
|
||||
q := starter.Q;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,9 @@
|
||||
FUNCTION_BLOCK MotorStarter
|
||||
VAR_INPUT
|
||||
start, stop : BOOL;
|
||||
END_VAR
|
||||
VAR_OUTPUT
|
||||
Q : BOOL;
|
||||
END_VAR
|
||||
Q := start AND NOT stop;
|
||||
END_FUNCTION_BLOCK
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case15"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["motor.st", "main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译错误
|
||||
|
||||
- 调用 `starter(...)` 但未声明实例
|
||||
- 报错类别:FB 必须先声明实例才能调用
|
||||
@@ -0,0 +1,7 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
q : BOOL;
|
||||
END_VAR
|
||||
starter(start := TRUE, stop := FALSE);
|
||||
q := starter.Q;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,9 @@
|
||||
FUNCTION_BLOCK MotorStarter
|
||||
VAR_INPUT
|
||||
start, stop : BOOL;
|
||||
END_VAR
|
||||
VAR_OUTPUT
|
||||
Q : BOOL;
|
||||
END_VAR
|
||||
Q := start AND NOT stop;
|
||||
END_FUNCTION_BLOCK
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case16"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["motor.st", "main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译通过;运行行为与 Δt 一致
|
||||
|
||||
- `dt_ms = 10`、`PT = 30ms`:前 2 周期 `Q` = FALSE,第 3 周期起 `Q` = TRUE
|
||||
- 累计用映像里的 Δt,不用 wall clock
|
||||
@@ -0,0 +1,8 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
t : TON;
|
||||
q : BOOL;
|
||||
END_VAR
|
||||
t(in := TRUE, pt := T#30ms);
|
||||
q := t.Q;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case17"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,5 @@
|
||||
# 期望:编译通过;运行行为与 Δt 一致
|
||||
|
||||
- TOF:`in` 掉电后 `Q` 保持 `PT` 时长(20ms)再复位
|
||||
- CTU:`cu` 上升沿计数 +1;`r` 复位;`CV` 到 `PV`(3)时 `Q` = TRUE
|
||||
- 内部累计用映像 Δt,不用 wall clock
|
||||
@@ -0,0 +1,13 @@
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
tf : TOF;
|
||||
c : CTU;
|
||||
q1, q2 : BOOL;
|
||||
cnt : INT;
|
||||
END_VAR
|
||||
tf(in := FALSE, pt := T#20ms);
|
||||
q1 := tf.Q;
|
||||
c(cu := TRUE, r := FALSE, pv := 3);
|
||||
q2 := c.Q;
|
||||
cnt := c.CV;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case18"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# 期望:编译错误
|
||||
|
||||
- `A` ↔ `B` 函数体循环调用(无界递归)
|
||||
- 报错类别:有界 CALL 检查拒绝循环调用
|
||||
@@ -0,0 +1,14 @@
|
||||
FUNCTION A : INT
|
||||
A := B();
|
||||
END_FUNCTION
|
||||
|
||||
FUNCTION B : INT
|
||||
B := A();
|
||||
END_FUNCTION
|
||||
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
x : INT;
|
||||
END_VAR
|
||||
x := A();
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,8 @@
|
||||
[project]
|
||||
name = "case19"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 1000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["main.st"]
|
||||
@@ -0,0 +1,11 @@
|
||||
# 期望:编译通过;I 组合 → `Q0_0` 与急停语义一致
|
||||
|
||||
| I0_0 | I0_1 | EmergencyStop | Q0_0 |
|
||||
|---|---|---|---|
|
||||
| TRUE | FALSE | FALSE | TRUE |
|
||||
| TRUE | TRUE | FALSE | FALSE |
|
||||
| FALSE | FALSE | FALSE | FALSE |
|
||||
| TRUE | FALSE | TRUE | FALSE |
|
||||
|
||||
- `Q0_0 = I0_0 AND NOT I0_1 AND NOT EmergencyStop`
|
||||
- 固定 I 序列跑两遍,槽位与工程哈希一致(回放确定性)
|
||||
@@ -0,0 +1,7 @@
|
||||
(* globals.st *)
|
||||
VAR_GLOBAL
|
||||
EmergencyStop : BOOL := FALSE;
|
||||
I0_0 : BOOL;
|
||||
I0_1 : BOOL;
|
||||
Q0_0 : BOOL;
|
||||
END_VAR
|
||||
@@ -0,0 +1,8 @@
|
||||
(* main.st *)
|
||||
PROGRAM MAIN
|
||||
VAR
|
||||
starter : MotorStarter;
|
||||
END_VAR
|
||||
starter(start := I0_0, stop := I0_1);
|
||||
Q0_0 := starter.Q;
|
||||
END_PROGRAM
|
||||
@@ -0,0 +1,13 @@
|
||||
(* motor.st *)
|
||||
FUNCTION_BLOCK MotorStarter
|
||||
VAR_EXTERNAL
|
||||
EmergencyStop : BOOL;
|
||||
END_VAR
|
||||
VAR_INPUT
|
||||
start, stop : BOOL;
|
||||
END_VAR
|
||||
VAR_OUTPUT
|
||||
Q : BOOL;
|
||||
END_VAR
|
||||
Q := start AND NOT stop AND NOT EmergencyStop;
|
||||
END_FUNCTION_BLOCK
|
||||
@@ -0,0 +1,28 @@
|
||||
[project]
|
||||
name = "line1"
|
||||
entry = "program MAIN"
|
||||
cycle_limit = 100000
|
||||
dt_ms = 10
|
||||
|
||||
[files]
|
||||
st = ["globals.st", "motor.st", "main.st"]
|
||||
|
||||
# 全工程只允许这一处出现 VAR_GLOBAL(第一版:单个文件)
|
||||
[gvl]
|
||||
file = "globals.st"
|
||||
|
||||
# 可选:I/O 绑定。不创造变量,var 必须已在 GVL 里声明
|
||||
[[io.input]]
|
||||
var = "EmergencyStop"
|
||||
channel = 0
|
||||
bit = 2
|
||||
|
||||
[[io.input]]
|
||||
var = "I0_0"
|
||||
channel = 0
|
||||
bit = 0
|
||||
|
||||
[[io.output]]
|
||||
var = "Q0_0"
|
||||
channel = 0
|
||||
bit = 0
|
||||
Reference in New Issue
Block a user