# TSL 文件模型规则

本篇说明 TSL 的文件模型判断规则：智能体如何区分 `.tsl` 可执行脚本与 `.tsf` 可复用声明文件，如何识别脚本语句区和声明区，以及为什么很多错误其实是“文件模型选错了”。

## 本篇职责

<!-- section-id: syntax-02-001 -->

回答“目标文件到底是 `.tsl` 脚本还是 `.tsf` 可复用声明文件，`.tsl` 里的哪些内容会顺序执行、哪些内容只是后置声明，以及何时使用完整 `program ... begin ... end.` 入口形态”。

本页是文件模型的唯一事实源：后缀判断、语句区 / 声明区顺序、`.tsf` 顶层声明形态和文件名约束都在这里收口。函数体、类体、`unit` 内部的语法外形由各自专题页拥有。

## 文件模型核心规则

<!-- section-id: syntax-02-002 -->

<!-- tags: 该用哪种文件, tsl 还是 tsf, 后缀怎么选, 文件形态判断 -->

- 用户已给出 `.tsl` / `.tsf` 后缀时，后缀就是判断依据；未给后缀时，再按交付目标判断。

<!-- quickstart-rule: file-choice -->

- 未给后缀时，入口流程、脚本任务或一次性执行逻辑对应 `.tsl`；可复用交付物（函数、过程、类、模块或扩展文件）对应 `.tsf`；只是脚本内部封装函数或类时，仍按 `.tsl` 处理；仍不明确时向用户确认，不要把脚本入口和可复用模块合并成一个猜测文件。

<!-- quickstart-rule: tsl-layout -->

- `.tsl` 脚本按两段理解：语句区在前并按顺序执行；声明区在后，可放 `function / procedure` 或 `type Name = class`。写 `.tsl` 时先写语句区，需要函数、过程或类时把声明区放在语句区之后。

<!-- quickstart-rule: tsf-layout -->

- 写 `.tsf` 时只写顶层函数 / 过程 / 类声明，或 `unit`；不要写成会直接顺序执行的脚本入口。
- `.tsf` 里的非 `unit` 顶层函数 / 过程可按函数扩展理解：部署到解释器 `funcext` 后，`.tsl` 可以直接调用；顶层类声明只按可复用声明理解；`unit` 按模块组织理解。
- `uses` 可以出现在顶层，但这里只把它当成辅助语句，不把它当成主体声明；函数体和类定义体里的位置限制见 [09_units_and_scope.md](09_units_and_scope.md)。
- 裸 `class Name` 不作为类定义写法使用。
- 在 `.tsl` 中，不要在声明区之后继续追加脚本语句。
- `program Name; ... begin ... end.` 是完整程序入口形态；它可以在主 `begin` 前声明子函数，但不是普通 `.tsl` 脚本的默认起手式。
- `unit` 默认先按完整形态理解；它也可以省略 `interface` / `implementation` 写成简写形态，见 [09_units_and_scope.md](09_units_and_scope.md)。
- 不要把 `.tsl` 写成只有顶层函数的模块；如果用户要通用可复用函数，优先写 `.tsf`。
- 不要把 `.tsf` 写成会直接执行脚本语句的入口；如果用户要顺序执行入口，优先写 `.tsl`。

<!-- quickstart-rule: tsf-filename -->

- `.tsf` 文件名（不含扩展名）必须与第一个顶层声明同名；第一个声明可以是同名 `function`、`type Name = class` 或 `unit`。
- TSL 语言大小写无关，因此 `userAccount.tsf` 和 `UserAccount.tsf` 在语法层面都合法。

## 文件模型示例

<!-- section-id: syntax-02-003 -->

使用这些示例时遵守：

- 可以模仿已经出现的文件模型、语句顺序和块级结构。
- 不要从示例推断未出现的部署方式、文件名规则或模块查找规则。
- `.tsf` 示例后的输出片段只证明部署后可由 `.tsl` 调用取得结果；不要理解为 `.tsf` 会独立顺序执行。
- 扩展写法必须有对应专题事实支持。

### `.tsl` 文件模型

<!-- section-id: syntax-02-004 -->

<!-- tags: 可执行脚本, 顺序执行, 入口脚本, 语句区, 声明区, 脚本从哪开始跑 -->

`.tsl` 脚本语句区的最小形态：

代码块身份：可直接照写示例

```tsl
a := 1;
```

代码块说明：这是 `.tsl` 语句区最小形态，只证明脚本语句可以从文件开头顺序执行。

`.tsl` 语句区后接函数声明区：

代码块身份：可直接照写示例

```tsl
a := 1;
Test();

function Test();
begin
    echo "test";
end;
```

代码块身份：输出片段

```text
test
```

代码块说明：这个骨架证明 `.tsl` 语句区可以调用后置函数声明；不要在函数声明区之后继续追加脚本语句。

`.tsl` 语句区后接类声明区：

代码块身份：可直接照写示例

```tsl
obj := new MyClass();
obj.Value := 5;
echo obj.Value;

type MyClass = class
    Value;
end;
```

代码块身份：输出片段

```text
5
```

代码块说明：这个骨架证明 `.tsl` 语句区可以通过 `new MyClass()` 使用后置类声明；普通对象创建默认优先 `new ClassName()`。`createObject(...)` 也是对象创建方式，但作为次选；需要字符串类名、类类型变量或跨 `unit` 路径时，更适合用 `createObject(...)`，细节见 [08_objects_and_classes.md](08_objects_and_classes.md)。

### `.tsf` 文件模型

<!-- section-id: syntax-02-005 -->

<!-- tags: 可复用文件, 模块文件, 函数扩展, 别的脚本能调, funcext -->

`.tsf` 顶层函数的最小形态：

代码块身份：可直接照写示例

```tsl
function Demo();
begin
    return 1;
end;
```

代码块说明：这个 `.tsf` 部署为函数扩展后，可由 `.tsl` 脚本调用 `Demo()` 并取得返回值；部署方式属于项目执行层，不写进通用语法页。

代码块身份：输出片段

```text
1
```

`.tsf` 顶层类声明的最小形态：

代码块身份：可直接照写示例

```tsl
type UserAccount = class
public
    Name;
    function Describe();
    begin
        return Name;
    end;
end;
```

代码块说明：这个 `.tsf` 只按可复用类声明理解，不会自己顺序执行。文件必须命名为 `UserAccount.tsf`，因为文件名要与第一个顶层声明同名。类成员、可见性和继承的完整事实见 [08_objects_and_classes.md](08_objects_and_classes.md)。

`.tsf` `unit` 的最小形态：

代码块身份：可直接照写示例

```tsl
unit DemoUnit;

interface

function Ping();

implementation

function Ping();
begin
    return 1;
end;

end.
```

代码块说明：这个 `.tsf` `unit` 可由 `.tsl` 脚本 `uses DemoUnit` 后调用 `Ping()`，返回值为 `1`；调用脚本和查找路径边界见 [09_units_and_scope.md](09_units_and_scope.md)。

代码块身份：输出片段

```text
1
```

### 完整 `program` 入口形态

<!-- section-id: syntax-02-009 -->

<!-- tags: PROGRAM 入口, 完整程序, 独立脚本入口, CGI 入口, 主 begin 块 -->

普通 `.tsl` 默认仍使用前面的松散语句区模型。只有用户明确要求完整程序入口、独立脚本 / CGI 兼容形态，或现有代码已经使用 `program` 时，才写成下面的结构：

代码块身份：可直接照写示例

```tsl
program DemoProgram;

function DoubleValue(value);
begin
    return value * 2;
end;

begin
    echo "result:", DoubleValue(3);
end.
```

代码块身份：输出片段

```text
result:6
```

说明：

- `program Name;` 位于文件开头
- 子函数声明位于主 `begin ... end.` 之前
- 完整程序以 `end.` 结束，而普通函数声明仍以 `end;` 结束
- 不要把这套结构与“松散语句区在前、声明区在后”的默认 `.tsl` 模型混写

### `echo` 输出语句

<!-- section-id: syntax-02-010 -->

<!-- tags: echo 输出, 打印表达式, 输出多个值, 逗号输出, 控制台输出 -->

`echo expr1, expr2, ...;` 会按从左到右的顺序输出表达式列表。简单值直接输出；数组、对象等复杂值可能只显示类型摘要。具体输出目标由宿主环境决定，可能是控制台、Web 响应或客户端输出窗口。

代码块身份：可直接照写示例

```tsl
echo "A=", 1, ",B=", 2;
```

代码块身份：输出片段

```text
A=1,B=2
```

不要把 `echo` 的宿主输出位置或复杂对象的展示格式当成跨环境固定结果。

### 文件模型反例

<!-- section-id: syntax-02-006 -->

<!-- tags: 为什么编译失败, 顶层裸类, 文件写错了, invalid statement -->

顶层裸 `class` 声明：

代码块身份：反例 / 不可照写

```text
class DemoType
end;
```

上面这种裸 `class` 顶层写法会编译失败；顶层类声明必须写成 `type DemoType = class ... end;`。

代码块身份：输出片段

```text
invalid statement
```

在声明区之后继续写脚本语句：

代码块身份：反例 / 不可照写

```text
a := 1;
test();

function test();
begin
    echo "test";
end;

echo "after declaration";
```

上面最后一行属于「声明区之后继续写脚本语句」，会编译失败。正确做法是把所有会执行的脚本语句都放在声明区之前。

代码块身份：输出片段

```text
Execute script error at Line:9
function:__main__:line 9: invalid statement
```

## 任务到文件模型的选择规则

<!-- section-id: syntax-02-007 -->

<!-- tags: 任务对应哪种文件, 起手形态怎么选, 该建什么文件 -->

已经确定任务目标时，按下表选择起手形态：

| 任务                               | 起手形态                       | 写法                                                                                                                 |
| ---------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| 入口流程、脚本任务或一次性执行逻辑 | `.tsl` 脚本语句区              | 直接写会顺序执行的语句                                                                                               |
| 脚本逻辑需要调用本文件内函数       | `.tsl` 语句区 + 后置函数声明区 | 语句区之后写 `function ... begin ... end;` 或 `procedure ... begin ... end;`                                         |
| 脚本逻辑需要对象状态、字段、方法   | `.tsl` 语句区 + 后置类声明区   | 语句区之后写 `type Name = class ... end;`                                                                            |
| 沉淀可复用函数或过程               | `.tsf` 顶层函数 / 过程         | 写可部署到 `funcext` 的 `function` / `procedure` 文件                                                                |
| 沉淀可复用类                       | `.tsf` 顶层类声明              | 写 `type Name = class ... end;`，只按可复用声明理解；类细节见 [08_objects_and_classes.md](08_objects_and_classes.md) |
| 把接口和实现组织进一个模块         | `.tsf` `unit`                  | 默认先写 `unit ... interface ... implementation ... end.`；简写形态见 [09_units_and_scope.md](09_units_and_scope.md) |

补充判断：

- 不要因为代码里需要函数或类就自动升级成 `.tsf`；`.tsl` 也可以在语句区后放声明区。
- 不要把 `unit` 当成最小起手骨架；只有用户明确要模块接口 / 实现组织，或项目已有 `unit` 边界时，才进入 `unit` 写法。

## 文件模型禁止项

<!-- section-id: syntax-02-008 -->

<!-- tags: 不要这样写, 文件模型误用, 两种文件混着写 -->

- 把 `.tsl` 当成 `.tsf` 来写，只给一个顶层函数，不写任何会执行的脚本语句。
- 把 `.tsf` 当成 `.tsl` 来写，在模块文件里直接堆顺序执行的脚本语句。
- 把 `program ... begin ... end.` 与松散 `.tsl` 语句区 / 后置声明区混成一套文件结构。
- 把 `uses` 当成主体声明，而不是辅助组织语句。
- `.tsf` 文件名与顶层声明不一致：`UserAccount.tsf` 中写 `function GetUser` 或 `type Customer = class` 或 `unit CustomerModule` 会导致加载失败或检索混乱。
