feat(skills): add tsl syntax reference skill

This commit is contained in:
csh
2026-07-13 09:16:51 +08:00
parent 1a9a1aeee9
commit ce1b92bbde
42 changed files with 562 additions and 461 deletions
@@ -0,0 +1,485 @@
# TSL 控制流
文档类型:语法主线
是否可直接用于生成代码:是
是否含可直接照写示例:是
是否含不可照写反例:是
遇到不确定时:先按本页规则和示例继续判断;[05_functions_and_calls.md](05_functions_and_calls.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[15_debug_and_profiler.md](15_debug_and_profiler.md)、[11_pitfalls.md](11_pitfalls.md);仍在语法层但不命中时回到本 Skill 路由中心 [index.md](index.md);如果问题已经超出语法层,停止并交接给对应事实所有者
这一篇只收录流程控制与异常控制,不讨论金融语义。
## 本篇职责
回答“`if``case``for``while``repeat``break``continue``try``raise` 这些流程结构在 TSL 里到底怎么写,哪些写法可以直接生成”。
## 智能体控制流判断流程
1. 先判断任务需要条件分支、循环、`case`、异常处理还是调试跳转。
2. `if` / `for` / `while` / `repeat` 优先照本页文档骨架写,不要套用其他 Pascal 方言。
3. 生成带 `else` 的条件分支时,默认用 `begin ... end` 包住 `then``else` 分支,让分支内部语句正常以分号结尾;不要在 `else` 前提前加分号。
4. `case` 可写成语句形态,也可写成赋值右侧的表达式形态;表达式形态的分支只能放单条表达式/单条语句,不写 `begin ... end` 语句段。
5. 没有文档事实时不要发明控制流写法。
## 核心规则
- `if ... then ... else ...` 默认写成块式分支:`then begin ... end else begin ... end`
- 块式分支内部的普通语句必须用分号结尾。
- 控制流块的 `begin ... end` 后可以加分号也可以不加(语法都允许)。
- `for` 支持 `to``downto`、可选 `step`,以及 `for i, v in array` 遍历。
- `while``repeat ... until` 都可直接使用;`repeat` 至少会先执行一轮再判断结束条件。
- `break` 会跳出当前最近一层循环,`continue` 会跳过当前轮剩余语句。
- `case ... of ... else ... end` 可作为语句形态生成;`end` 后可以加分号也可以不加。
- `value := case ... of ... else ... end;` 可作为表达式形态生成;表达式形态赋值语句本身要用分号结尾。
- `case` 分支标签支持逗号并列和 `to` 区间。
- `try ... except ... end` 可以捕获 `raise` 产生的错误,并继续执行后续语句。
- `exceptObject.errInfo``except` 块中可读,能拿到当前错误信息。
- `exceptObject.errLine``exceptObject.errNo``except` 块中也可读。
- `try ... finally ... end` 无论是否报错,都会先执行 `finally`;如果没有 `except` 吞掉错误,脚本仍会在 `finally` 之后报错终止。
- `raise "message"` 是最小抛错写法。
- `goto``debugReturn``debugRunEnv`、计时和性能分析器这类“控制流补充工具”统一放到 [15_debug_and_profiler.md](15_debug_and_profiler.md)。
## 可直接照写示例
使用这些示例时遵守:
- 条件表达式、比较、布尔值和普通赋值回 [06_expressions_and_operators.md](06_expressions_and_operators.md)。
- 函数里的控制流只按控制流语法处理;函数文件模型、返回值和参数规则回 [05_functions_and_calls.md](05_functions_and_calls.md)。
- `goto``debugReturn`、计时和性能分析器不在本页生成,统一回 [15_debug_and_profiler.md](15_debug_and_profiler.md)。
### `if`、`while`、`repeat ... until`
代码块身份:可直接照写示例
```tsl
flag := 1;
if flag > 0 then
begin
value := 1;
end
else
begin
value := 0;
end
counter := 0;
while counter < 3 do
counter := counter + 1;
repeat
counter := counter - 1;
until counter = 0;
writeLn(value);
writeLn(counter);
```
代码块身份:输出片段
```text
1
0
```
### `for` 的几种主干写法
最基础的递增循环:
代码块身份:可直接照写示例
```tsl
sum := 0;
for i := 0 to 2 do
sum := sum + i;
writeLn(sum);
```
代码块身份:输出片段
```text
3
```
`step` 的递增循环:
代码块身份:可直接照写示例
```tsl
sum := 0;
for i := 1 to 5 step 2 do
sum := sum + i;
writeLn(sum);
```
输出说明:
- 输出 `9`
代码块身份:输出片段
```text
9
```
`step``downto` 递减循环:
代码块身份:可直接照写示例
```tsl
sum := 0;
for i := 5 downto 1 step 2 do
sum := sum + i;
writeLn(sum);
```
输出说明:
- 输出 `9`
代码块身份:输出片段
```text
9
```
数组遍历:
代码块身份:可直接照写示例
```tsl
numbers := array(10, 20, 30);
for i, value in numbers do
writeLn(i * 100 + value);
```
输出说明:
- 依次输出 `10``120``230`
- 这说明 `for i, value in numbers` 里的 `i``0` 开始
代码块身份:输出片段
```text
10
120
230
```
### `break` 与 `continue`
`break`
代码块身份:可直接照写示例
```tsl
i := 0;
sum := 0;
while true do
begin
i := i + 1;
if i > 3 then
break;
sum := sum + i;
end
writeLn(sum);
writeLn(i);
```
输出说明:
- `sum` 输出 `6`
- `i` 输出 `4`
代码块身份:输出片段
```text
6
4
```
`continue`
代码块身份:可直接照写示例
```tsl
i := 0;
sum := 0;
while i < 4 do
begin
i := i + 1;
if i = 2 then
continue;
sum := sum + i;
end
writeLn(sum);
```
输出说明:
- 输出 `8`
代码块身份:输出片段
```text
8
```
### `case` 语句形态
普通分支:
代码块身份:可直接照写示例
```tsl
a := 2;
case a of
1:
writeLn("one");
2:
writeLn("two");
else
writeLn("other");
end
```
输出说明:
- 输出 `two`
代码块身份:输出片段
```text
two
```
并列标签与区间:
代码块身份:可直接照写示例
```tsl
a := 4;
case a of
1, 2:
writeLn("small");
3 to 5:
writeLn("mid");
else
writeLn("other");
end
```
输出说明:
- 输出 `mid`
代码块身份:输出片段
```text
mid
```
`case` 表达式形态:
代码块身份:可直接照写示例
```tsl
a := 3;
label_value := case a of
1, 2:
"small";
3, 4:
"mid";
else
"other";
end;
writeLn(label_value);
```
输出说明:
- 输出 `mid`
代码块身份:输出片段
```text
mid
```
说明:
- 表达式形态可以放在赋值右侧。
- 表达式形态的每个分支只写单条表达式/单条语句,不写 `begin ... end` 语句段。
- 赋值语句整体以 `end;` 收尾。
### `try ... except`
代码块身份:可直接照写示例
```tsl
writeLn("before");
try
raise "boom";
except
writeLn("caught");
writeLn(exceptObject.errInfo);
end
writeLn("after");
```
输出说明:
- 先输出 `before`
- 再输出 `caught`
- `exceptObject.errInfo` 输出包含 `raise: boom` 的错误信息
- 最后继续输出 `after`
代码块身份:输出片段
```text
before
caught
raise: boom
after
```
`exceptObject` 的扩展字段:
代码块身份:可直接照写示例
```tsl
try
raise "boom";
except
writeLn(exceptObject.errLine);
writeLn(exceptObject.errNo);
end
```
输出说明:
- `exceptObject.errLine` 输出 `4`
- `exceptObject.errNo` 输出 `2`
- 说明异常对象除了 `errInfo` 以外,也能直接提供出错行号和错误号
代码块身份:输出片段
```text
4
2
```
### `try ... finally`
正常路径:
代码块身份:可直接照写示例
```tsl
writeLn("before");
try
writeLn("body");
finally
writeLn("finally");
end
writeLn("after");
```
输出说明:
- 依次输出 `before``body``finally``after`
代码块身份:输出片段
```text
before
body
finally
after
```
报错路径:
代码块身份:可直接照写示例
```tsl
writeLn("before");
try
writeLn("body");
raise "boom";
finally
writeLn("finally");
end
writeLn("after");
```
输出说明:
- 先输出 `before`
- 再输出 `body`
- 然后仍会输出 `finally`
- 随后脚本报错终止,`after` 不会执行
代码块身份:输出片段
```text
before
body
finally
```
### `raise`
代码块身份:可直接照写示例
```tsl
writeLn("before");
raise "boom";
writeLn("after");
```
输出说明:
- 先输出 `before`
- 随后脚本报错终止,`after` 不会执行
代码块身份:输出片段
```text
before
```
## 默认生成模板
最短条件分支的默认骨架如下:
代码块身份:可直接照写示例
```tsl
flag := 1;
if flag > 0 then
begin
value := 1;
end
else
begin
value := 0;
end
```
## 禁止项
-`else` 前面误加分号。
- 生成没有分号的裸分支赋值,例如 `then value := 1 else ...`;带 `else` 时用块式分支。
- 以为 `try ... finally` 会吞掉异常。
-`case` 写成赋值右侧表达式。
- 在还没搞清表达式规则前,先把复杂业务函数塞进条件里。
- 把控制流问题和函数文件模型问题混在一起排查。
代码块身份:反例 / 不可照写
```text
if flag > 0 then
value := 1;
else
value := 0;
```
上面这种写法会编译失败,因为 `else` 前面的分号会让 `if` 语句在上一行提前结束。生成带 `else` 的赋值分支时,不要改成省略分号的裸分支;使用前文的块式分支。