Files
tsl-devkit/docs/tsl/syntax/08_control_flow.md
T
csh 3d83740f88 Squashed 'docs/standards/playbook/' changes from c3f8137..25d895d
25d895d 🐛 fix(gitea_workflow): clean up temp repos after job steps
2bc3b11 🐛 fix(gitea_workflow): clean up temporary repo dirs in workflows
98c3f30 📝 docs(agent_rules): allow plan execution on current branch
16c7230 📝 docs(prompts): define custom verify layering
8efc4dd 🐛 fix(skills): quote commit-message description
bc8498f 🐛 fix(ci): install tomli for gitea tests
55cda3b 🐛 fix(tests): report missing toml parser clearly
c0729c7 🐛 fix(playbook): import Optional for cli compatibility
63e24bf 📦 deps(skills): sync thirdparty skills
d2f9356 🐛 fix(ci): isolate gitea workflow repos
588b81d 🐛 fix(ci): inline gitea workflow bootstrap
e0b1c3a ♻️ refactor(skills): standardize first-party skill contracts
2c5050d ♻️ refactor(skills): rename repo skills source dir
f049dfb 📦 deps(skills): drop duplicate first-party superpowers skills
234b335  feat(workflow): add superpowers planning and execution state tracking
c1702a6 📝 docs(markdown): format tracked markdown and drop stale templates
2325409 📝 docs(markdown): clarify optional markdownlint usage
214c44e 🔧 chore(markdown): add markdownlint baseline and lint fixes
a22b324 📝 docs(templates): add execution and memory-bank prompt templates
223a797 📝 docs(templates): update README for Claude Code and current features
4ac8672 📝 docs: simplify README + platform-agnostic tools + auto-create local rules
2431c9d 📝 docs: add claude_md config and use cross-platform paths
d64b248 📝 docs: fix README.md inaccuracies and add Claude Code info
c8d6bf2 🐛 fix(playbook): use relative paths in CLAUDE.md when not at project root
6518f0f  feat(playbook): auto-create CLAUDE.md with path discovery
6ec9a45  feat(skills): add skill_link symlink support + platform-agnostic prompt
9f8b6b5 📝 docs: update README and config example for Claude Code support
79cff6c 📝 docs(skills): add Claude Code platform support
452c6f5  feat(playbook): auto-inject AGENTS.md into CLAUDE.md
e1dbf3c 🐛 fix(skills): remove dual-path from commit-message skill
f3a7259 🔧 chore(ci): use prepare_repo.sh in both workflows
da08212 🔧 chore(ci): extract prepare_repo.sh and clean up workflows
7ade85e 🗑️ remove(tsl): drop syntax_book/, data/ source and build script
f94dba0 ♻️ refactor(skills): update playbook.py and tests for thirdparty/ layout
b3df412 ♻️ refactor(skills): separate thirdparty skills into thirdparty/ subdirectory
64950e7 📦 deps(skills): sync thirdparty skills
a2e3cb0  feat(playbook): add no_backup deploy controls
8609d59 🐛 fix(docs): repair reference catalog source links
956da11 🐛 fix(playbook): publish hidden ci test fixes
3f67754 📦 deps(skills): sync thirdparty skills
08ca87b 📦 deps(skills): add karpathy thirdparty sync
96b705b 📝 docs(tsl): rebuild canonical syntax and routing manual
3ed5052 📦 deps(skills): sync thirdparty skills
60108dd 📦 deps(skills): sync thirdparty skills
da85d4e 🐛 fix(thirdparty): prune nested project snapshots
a2a697e 📦 deps(skills): sync thirdparty skills
9df610a 🐛 fix(thirdparty): exclude duplicated superpowers skills
33dd5bb 🐛 fix(thirdparty): preserve optional manifest fields
91b0ea7 🐛 fix(thirdparty): preserve manifest during snapshot update
2e26f98 🔧 chore(thirdparty): generalize skills sync pipeline
5b9c1e3 📦 deps(skills): sync superpowers
2f2d34a 📝 docs(readme): normalize subtree command spacing
62db7db 🐛 fix(ci): serialize superpowers update and sync
3463223 🐛 fix(ci): use literal superpowers sync paths
48f6de8 📦 deps(skills): sync superpowers
4b23529 🔧 chore(ci): merge superpowers update and sync workflow
a56d75b 📦 deps(skills): sync superpowers
84bcefa 🔧 chore(ci): use ci[bot] commit author name
00a07e5 📦 deps(skills): sync superpowers
7b84daf 🐛 fix(templates): enforce main loop progress tracking
51373d7 🔧 chore(ci): automate superpowers sync workflow
eaaa39c 🐛 fix(ci): prevent stale superpowers sync from restoring skills block
79755c6 📦 deps(skills): sync superpowers
836d878 📦 deps(skills): sync superpowers
8216c9f 📦 deps(skills): sync superpowers
9439505 🐛 fix(playbook): address reported repo issues

git-subtree-dir: docs/standards/playbook
git-subtree-split: 25d895d8b3f56624ccfe99ad7289e9eb49e0f316
2026-05-24 13:04:14 +08:00

375 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Control Flow
文档类型:语法主线
是否可直接用于生成代码:是
是否含已验证可执行示例:是
是否含已验证反例:是
遇到不确定时跳转到:[07_expressions_and_operators.md](07_expressions_and_operators.md)、[16_debug_and_profiler.md](16_debug_and_profiler.md)、[12_pitfalls.md](12_pitfalls.md)
手册位置:第 8 篇,共 32 篇。上一篇:[07_expressions_and_operators.md](07_expressions_and_operators.md)。下一篇:[09_objects_and_classes.md](09_objects_and_classes.md)。
这一篇只收录流程控制与异常控制,不讨论金融语义。
## 这一篇解决什么问题
回答“`if``case``for``while``repeat``break``continue``try``raise` 这些流程结构在 TSL 里到底怎么写,哪些写法已经被当前解释器实测验证过”。
## 必须记住的规则
- `if ... then ... else ...` 可以直接跟单条语句;需要多条语句时再补 `begin ... end`
- `for` 已验证支持 `to``downto`、可选 `step`,以及 `for i, v in array` 遍历。
- `while``repeat ... until` 都可直接使用;`repeat` 至少会先执行一轮再判断结束条件。
- `break` 会跳出当前最近一层循环,`continue` 会跳过当前轮剩余语句。
- `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`、计时和 profiler 这类“控制流补充工具”统一放到 [16_debug_and_profiler.md](16_debug_and_profiler.md)。
## 已验证语法
### `if`、`while`、`repeat ... until`
代码块身份:已验证可执行示例
```tsl
flag := 1;
if flag > 0 then
value := 1
else
value := 0;
counter := 0;
while counter < 3 do
counter := counter + 1;
repeat
counter := counter - 1;
until counter = 0;
```
### `for` 的几种主干写法
最基础的递增循环:
代码块身份:已验证可执行示例
```tsl
sum := 0;
for i := 0 to 2 do
sum := sum + i;
```
`step` 的递增循环:
代码块身份:已验证可执行示例
```tsl
s := 0;
for i := 1 to 5 step 2 do
s := s + i;
WriteLn(s);
```
已验证运行结果:
- 输出 `9`
`step``downto` 递减循环:
代码块身份:已验证可执行示例
```tsl
s := 0;
for i := 5 downto 1 step 2 do
s := s + i;
WriteLn(s);
```
已验证运行结果:
- 输出 `9`
数组遍历:
代码块身份:已验证可执行示例
```tsl
data := array(10, 20, 30);
for i, v in data do
WriteLn(i * 100 + v);
```
已验证运行结果:
- 依次输出 `10``120``230`
- 这说明 `for i, v in data` 里的 `i``0` 开始
### `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`
`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`
### `case` 语句形态
普通分支:
代码块身份:已验证可执行示例
```tsl
a := 2;
case a of
1:
WriteLn("one");
2:
WriteLn("two");
else
WriteLn("other");
end;
```
已验证运行结果:
- 输出 `two`
并列标签与区间:
代码块身份:已验证可执行示例
```tsl
a := 4;
case a of
1, 2:
WriteLn("small");
3 to 5:
WriteLn("mid");
else
WriteLn("other");
end;
```
已验证运行结果:
- 输出 `mid`
### `case` 表达式形态
代码块身份:已验证可执行示例
```tsl
a := 2;
b := case a of
1:
"one";
2:
"two";
else
"other";
end;
WriteLn(b);
```
已验证运行结果:
- 输出 `two`
### `try ... except`
代码块身份:已验证可执行示例
```tsl
WriteLn("before");
try
raise "boom";
except
WriteLn("caught");
WriteLn(ExceptObject.ErrInfo);
end;
WriteLn("after");
```
已验证运行结果:
- 先输出 `before`
- 再输出 `caught`
- `ExceptObject.ErrInfo` 输出包含 `raise: boom` 的错误信息
- 最后继续输出 `after`
`ExceptObject` 的扩展字段:
代码块身份:已验证可执行示例
```tsl
program test;
begin
try
raise "boom";
except
WriteLn(ExceptObject.ErrLine);
WriteLn(ExceptObject.ErrNo);
end;
end.
```
已验证运行结果:
- `ExceptObject.ErrLine` 输出 `4`
- `ExceptObject.ErrNo` 输出 `2`
- 说明当前解释器里,异常对象除了 `ErrInfo` 以外,也能直接提供出错行号和错误号
### `try ... finally`
正常路径:
代码块身份:已验证可执行示例
```tsl
WriteLn("before");
try
WriteLn("body");
finally
WriteLn("finally");
end;
WriteLn("after");
```
已验证运行结果:
- 依次输出 `before``body``finally``after`
报错路径:
代码块身份:已验证可执行示例
```tsl
WriteLn("before");
try
WriteLn("body");
raise "boom";
finally
WriteLn("finally");
end;
WriteLn("after");
```
已验证运行结果:
- 先输出 `before`
- 再输出 `body`
- 然后仍会输出 `finally`
- 随后脚本报错终止,`after` 不会执行
### `raise`
代码块身份:已验证可执行示例
```tsl
WriteLn("before");
raise "boom";
WriteLn("after");
```
已验证运行结果:
- 先输出 `before`
- 随后脚本报错终止,`after` 不会执行
## 最小可编译示例
如果你只想先写一个最短条件分支,从这个开始:
代码块身份:已验证可执行示例
```tsl
flag := 1;
if flag > 0 then
value := 1
else
value := 0;
```
## 常见误写
-`else` 前面误加分号。
- 以为 `try ... finally` 会吞掉异常。
-`@case` 直接当成普通 `case` 表达式主写法。
- 在还没搞清表达式规则前,先把复杂业务函数塞进条件里。
- 把控制流问题和函数文件模型问题混在一起排查。
代码块身份:反例 / 不可照写
```text
if flag > 0 then
value := 1;
else
value := 0;
```
上面这种写法会编译失败,因为 `else` 前面的分号会让 `if` 语句在上一行提前结束。
代码块身份:反例 / 不可照写
```text
b := @case a of
1:
"one";
2:
"two";
else
"other";
end;
WriteLn(b);
```
我在 `2026-04-13` 用当前解释器实测,上面这类最小例子输出的是 `<STREXP>`,不能把它当成普通 `case` 表达式的可靠主语法写进新 session 默认生成结果。
## 跳转指引
- 回看条件表达式:见 [07_expressions_and_operators.md](07_expressions_and_operators.md)
- 继续封装成函数:见 [06_functions_and_calls.md](06_functions_and_calls.md)
-`goto``DEBUGRETURN`、计时和 profiler:见 [16_debug_and_profiler.md](16_debug_and_profiler.md)