📝 docs(tsl): align agent-facing guidance

This commit is contained in:
csh
2026-05-28 19:12:34 +08:00
parent c48354e0cb
commit d8eb418277
63 changed files with 1921 additions and 371 deletions
+73 -15
View File
@@ -12,13 +12,24 @@
## 这一篇解决什么问题
回答“如何正确声明 `function``procedure`如何组织主函数和子函数、怎样使用参数修饰、默认参数与可变参数,以及哪些混写方式会直接编译失败”。
回答“如何正确声明 `function``procedure``.tsl` 脚本语句区如何调用后置函数声明、怎样使用参数修饰、默认参数与可变参数,以及哪些函数写法会直接编译失败”。
## Agent 函数/调用判断流程
1. 先判断当前文件是 `.tsl` 还是 `.tsf`;文件形态不明确时回 [03_core_model.md](03_core_model.md)。
2. `.tsl` 中先写语句区,再把 `function` / `procedure` 声明放在后面;不要在声明区后面追加脚本语句。
3. `.tsf` 中把顶层 `function` / `procedure` 当成模块 / 函数扩展声明;不要写成顺序执行入口。
4. 需要返回值时用 `function`,不需要返回值时用 `procedure`
5. 调用普通 TSL 函数时,命名参数只写 `name: value`;不要把 `name = value` 当成命名参数。
6. 参数是否写回调用方要看 `const` / `var` / `{$VarByRef-}` / `in` / `out`,不要默认按其他语言习惯推断。
7. 没有已验证代码块时不要发明函数/调用写法;尤其不要把二进制函数、系统函数、函数指针和匿名函数都套成同一种调用语法。
## 必须记住的规则
- 最稳妥的函数骨架仍然是 `function Name(...); begin ... end;`
- 不需要返回值时,可以改用 `procedure Name(...); begin ... end;`
-文件模型层,`function``procedure` 归同一类顶层外形;见 [03_core_model.md](03_core_model.md)。
- `.tsl` 文件模型层,脚本语句后可以接函数声明;语句区在前顺序执行,声明区在后提供函数/过程定义。见 [03_core_model.md](03_core_model.md)。
-`.tsf` 文件模型层,顶层 `function` / `procedure` 是模块/函数扩展声明;部署到解释器 `funcext` 后可被脚本直接调用。
- 当前解释器接受省略函数头后的分号,但文档默认仍保留这个分号。
- 一个函数定义体里可以同时出现主函数和子函数。
- 函数支持参数类型注解和返回值类型注解。
@@ -48,12 +59,32 @@
- 当前解释器没有通过 `f(...)` 这种“函数变量直接调用”写法;无论 `f` 是匿名函数、`FindFunction(...)` 还是 `ThisFunction(...)` 返回的函数指针,都不要默认写成直调。
- 当前解释器接受 `::FuncName(...)` 指向全局/系统函数,用来绕过当前作用域里的同名局部函数。
- `external``MakeInstance` 和线程调用统一移到 [21_external_calls_and_threads.md](21_external_calls_and_threads.md)。
- 不要把顶层函数定义和松散语句混在同一个文件模型里
- 不要`.tsl` 的函数声明区之后继续追加脚本语句
## 已验证语法
### 基础函数 / 过程骨架
`.tsl` 语句区调用后置函数声明:
代码块身份:已验证可执行示例
```tsl
a := 1;
test();
function test();
begin
echo "test";
end;
```
代码块身份:已验证输出片段
```text
test
```
最短函数骨架:
代码块身份:已验证可执行示例
@@ -121,9 +152,11 @@ begin
end.
```
已验证运行结果:
代码块身份:已验证输出片段
- `Bump(a)` 后输出 `2`
```text
2
```
### 签名增强
@@ -316,10 +349,7 @@ end.
代码块身份:已验证可执行示例
```tsl
function NamedArgsDemo();
begin
return Pack(a: 1, b: 2);
end;
WriteLn(Pack(a: 1, b: 2));
function Pack(a, b);
begin
@@ -327,7 +357,13 @@ begin
end;
```
已验证运行结果:
代码块身份:已验证输出片段
```text
12
```
已验证补充:
- `Pack(a: 1, b: 2)` 返回 `12`
- `Pack(b: 2, a: 1)` 返回 `12`
@@ -820,12 +856,25 @@ end.
## 最小可编译示例
如果你只是要写一个能被 session 稳定续写的函数 / 过程,从下面任一骨架起步
如果你只是要写一个能被 agent 稳定续写的 `.tsl` 脚本,从语句区起步,需要函数时把声明区放在后面
代码块身份:已验证可执行示例
```tsl
Hello();
function Hello();
begin
echo "hello";
end;
```
如果你要写 `.tsf` 模块/函数扩展,从下面任一骨架起步:
代码块身份:已验证可执行示例
```tsl
function HelloValue();
begin
return 1;
end;
@@ -841,7 +890,7 @@ end;
## 常见误写
- 把顶层函数定义和松散语句混写
- `.tsl` 的声明区后面继续写脚本语句
- 以为函数头后的分号是当前解释器的硬性要求。
- 以为 `procedure` 只是 `function` 的别名,不涉及参数传递语义。
- 带类型注解时仍然用逗号分隔参数。
@@ -857,15 +906,24 @@ end;
代码块身份:反例 / 不可照写
```text
a := 1;
Add(1, 2);
function Add(a, b);
begin
return a + b;
end;
value := Add(1, 2);
echo "after function";
```
上面这种混写方式会编译失败,问题不在 `Add` 本身,而在于文件模型混了“函数定义体”和“松散语句”两种写法
上面问题不在 `Add` 本身,而在于 `.tsl` 的函数声明区后面又继续出现脚本语句。正确做法是把会执行的语句全部放在声明区之前
代码块身份:已验证输出片段
```text
invalid statement
```
代码块身份:反例 / 不可照写
@@ -884,7 +942,7 @@ end;
Pack(a = 1, b = 2)
```
这类写法不要当成命名参数。它虽然可能编译通过,但在我于 `2026-04-09` 的实测里返回结果不对,不能当成可靠的命名参数语法。
这类写法不要当成命名参数。它虽然可能编译通过,但当前已验证返回结果不对,不能当成可靠的命名参数语法。
代码块身份:反例 / 不可照写