📝 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

View File

@ -22,8 +22,8 @@
### 1.1 单一职责 ### 1.1 单一职责
- 一个文件只做一件事;职责明确。 - 一个文件只做一件事;职责明确。
- `.tsl` 建议作为“入口/编排层”:聚合参数/配置、串起流程;可复用逻辑下沉到 - `.tsl` 作为可执行脚本:语句区在前并按顺序执行;需要本文件函数/类时,声明区放在语句区之后。
`.tsf``unit`/`class`/`function`)中 - `.tsf` 作为模块/函数扩展文件:可复用逻辑下沉到 `.tsf`,部署到解释器 `funcext` 后供脚本调用
- 当一个顶层声明同时承担“协议适配 + 业务计算 + - 当一个顶层声明同时承担“协议适配 + 业务计算 +
I/O/环境依赖 + 临时代码”时,优先拆分边界:核心纯逻辑 → 工具函数 → 边界适配I/O I/O/环境依赖 + 临时代码”时,优先拆分边界:核心纯逻辑 → 工具函数 → 边界适配I/O
@ -32,6 +32,7 @@
- TSL 语法要求(仅 `.tsf`):每个 `.tsf` - TSL 语法要求(仅 `.tsf`):每个 `.tsf`
文件只能有一个顶层声明,且文件基名必须与顶层声明同名。 文件只能有一个顶层声明,且文件基名必须与顶层声明同名。
- `.tsl` 允许直接写语句,不要求顶层声明;文件名不强制,但建议清晰可检索。 - `.tsl` 允许直接写语句,不要求顶层声明;文件名不强制,但建议清晰可检索。
- `.tsl` 中如果同时需要脚本语句和函数/类声明,先写语句区,再写声明区;不要在声明区后继续追加脚本语句。
- 推荐文件名使用 `PascalCase` 以提升检索与协作一致性;扩展名按类型使用 - 推荐文件名使用 `PascalCase` 以提升检索与协作一致性;扩展名按类型使用
`.tsl`/`.tsf`(两者都属于 TSL 源文件,风格规则一致)。 `.tsl`/`.tsf`(两者都属于 TSL 源文件,风格规则一致)。
- 详细约束与命名细则见 `docs/tsl/naming.md` - 详细约束与命名细则见 `docs/tsl/naming.md`

View File

@ -2,12 +2,17 @@
文档类型:业务骨架 文档类型:业务骨架
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:项目实际接口定义、[../modules/tsbacktesting.md](../modules/tsbacktesting.md)、[selection_and_signal_patterns.md](selection_and_signal_patterns.md)、[../syntax/index.md](../syntax/index.md) 遇到不确定时跳转到:项目实际接口定义、[../modules/tsbacktesting.md](../modules/tsbacktesting.md)、[selection_and_signal_patterns.md](selection_and_signal_patterns.md)、[../syntax/index.md](../syntax/index.md)
这一篇收拢回测、组合、交易与结果读取流程。 这一篇收拢回测、组合、交易与结果读取流程。
## Agent 回测/交易判断规则
- 先判断比例类组合还是数量类组合,再看交易输入和结果读取。
- 本页只给业务流程骨架,不给对象 API 真值。
- 对象创建方式、交易数据入口、结果接口和项目封装必须回项目实际接口定义。
- 不要发明项目实际接口、回测对象创建方式、交易入口或结果读取调用链。
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“回测对象如何组织、交易流程如何设置、结果怎样取出和解释”。 回答“回测对象如何组织、交易流程如何设置、结果怎样取出和解释”。

View File

@ -2,12 +2,16 @@
文档类型:检索页 文档类型:检索页
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:[market_data_context.md](market_data_context.md)、[../syntax/index.md](../syntax/index.md)、[../reference/index.md](../reference/index.md) 遇到不确定时跳转到:[market_data_context.md](market_data_context.md)、[../syntax/index.md](../syntax/index.md)、[../reference/index.md](../reference/index.md)
这里是金融层的入口决策页,不是代码页。它只解决“业务任务该往哪一层跳”,不重新定义语言基础语法。 这里是金融层的入口决策页,不是代码页。它只解决“业务任务该往哪一层跳”,不重新定义语言基础语法。
## Agent Finance Entry 判断规则
- 先判断任务属于市场数据、序列指标、选股信号还是回测交易。
- finance 只给业务组织方式;代码细节必须回 syntax、reference 或项目实际接口。
- 不要发明项目实际接口、数据字段、函数签名或业务上下文。
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“什么时候应该进入 finance 层、进入后先去哪个业务主题页,以及什么时候该回到 syntax / reference 层”。 回答“什么时候应该进入 finance 层、进入后先去哪个业务主题页,以及什么时候该回到 syntax / reference 层”。

View File

@ -2,12 +2,16 @@
文档类型:检索页 文档类型:检索页
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:[../syntax/index.md](../syntax/index.md)(优先)、[market_data_context.md](market_data_context.md)、[../reference/index.md](../reference/index.md) 遇到不确定时跳转到:[../syntax/index.md](../syntax/index.md)(优先)、[market_data_context.md](market_data_context.md)、[../reference/index.md](../reference/index.md)
这里是业务层入口。只讨论金融任务如何使用 TSL不重讲基础语法。 这里是业务层入口。只讨论金融任务如何使用 TSL不重讲基础语法。
## Agent Finance 路由规则
- 只用 finance 判断金融业务任务该怎么分层,不用 finance 重写语法规则。
- 金融任务需要真实数据字段、回测接口或项目封装时,先回项目实际接口定义。
- 不要发明项目实际接口、字段名、对象创建方式或函数签名。
## 先看这 5 条 ## 先看这 5 条
- 如果你的问题是“语言怎么写”,不要留在 finance回到 [../syntax/index.md](../syntax/index.md)。 - 如果你的问题是“语言怎么写”,不要留在 finance回到 [../syntax/index.md](../syntax/index.md)。

View File

@ -2,14 +2,19 @@
文档类型:业务骨架 文档类型:业务骨架
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:[series_and_indicator_model.md](series_and_indicator_model.md)、[../syntax/index.md](../syntax/index.md)、[../modules/tsbacktesting.md](../modules/tsbacktesting.md) 遇到不确定时跳转到:[series_and_indicator_model.md](series_and_indicator_model.md)、[../syntax/index.md](../syntax/index.md)、[../modules/tsbacktesting.md](../modules/tsbacktesting.md)
本页用于判断金融脚本运行时的数据语境,不提供独立语法模板。 本页用于判断金融脚本运行时的数据语境,不提供独立语法模板。
这一篇整理金融场景中的市场数据语境与执行环境。 这一篇整理金融场景中的市场数据语境与执行环境。
## Agent 市场数据判断规则
- 先确认脚本运行时是否已经有市场数据上下文。
- 只把本页用于判断业务语境,不把市场字段当成 TSL 通用语法。
- 如果字段来源、周期、复权口径或数据入口不明确,回项目实际接口定义。
- 不要发明项目实际接口、市场字段或默认数据上下文。
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“金融脚本运行时的数据上下文是什么、哪些概念属于业务层而不是语言层”。 回答“金融脚本运行时的数据上下文是什么、哪些概念属于业务层而不是语言层”。

View File

@ -2,12 +2,17 @@
文档类型:业务骨架 文档类型:业务骨架
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:[series_and_indicator_model.md](series_and_indicator_model.md)、[backtest_and_trade_flow.md](backtest_and_trade_flow.md)、[../syntax/index.md](../syntax/index.md) 遇到不确定时跳转到:[series_and_indicator_model.md](series_and_indicator_model.md)、[backtest_and_trade_flow.md](backtest_and_trade_flow.md)、[../syntax/index.md](../syntax/index.md)
这一篇收拢选股、筛选和信号生成的业务模式。 这一篇收拢选股、筛选和信号生成的业务模式。
## Agent 选股/信号判断规则
- 先确认任务输出是筛选结果、交易信号、评分排序还是回测输入。
- 条件表达的语法回 syntax金融任务组织留在 finance。
- 需要真实字段、信号函数或输出接口时,回项目实际接口定义。
- 不要发明项目实际接口、字段名、信号函数签名或输出结构。
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“如何把条件表达和金融筛选任务组织成稳定的选股/信号脚本”。 回答“如何把条件表达和金融筛选任务组织成稳定的选股/信号脚本”。

View File

@ -2,12 +2,17 @@
文档类型:业务骨架 文档类型:业务骨架
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:[market_data_context.md](market_data_context.md)、[selection_and_signal_patterns.md](selection_and_signal_patterns.md)、[../syntax/index.md](../syntax/index.md) 遇到不确定时跳转到:[market_data_context.md](market_data_context.md)、[selection_and_signal_patterns.md](selection_and_signal_patterns.md)、[../syntax/index.md](../syntax/index.md)
这一篇处理金融序列与指标计算模式。 这一篇处理金融序列与指标计算模式。
## Agent 序列/指标判断规则
- 先确认输入是单值还是逐 bar 序列。
- 指标公式只在业务上下文里成立,不替代 syntax 的表达式规则。
- 需要真实字段、指标函数或窗口口径时,回项目实际接口定义或 reference 参数事实页。
- 不要发明项目实际接口、字段名、指标函数签名或历史窗口语义。
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“指标、序列、逐 bar 计算和相关金融表达方式如何组织,以及 AI 应该先建立什么样的业务心智模型”。 回答“指标、序列、逐 bar 计算和相关金融表达方式如何组织,以及 AI 应该先建立什么样的业务心智模型”。

View File

@ -6,22 +6,26 @@
是否含已验证反例:否 是否含已验证反例:否
遇到不确定时跳转到:[syntax/index.md](syntax/index.md)、[finance/index.md](finance/index.md)、[reference/index.md](reference/index.md)、[modules/index.md](modules/index.md)、项目自身文档、`scripts/*` 入口脚本、CI 配置 遇到不确定时跳转到:[syntax/index.md](syntax/index.md)、[finance/index.md](finance/index.md)、[reference/index.md](reference/index.md)、[modules/index.md](modules/index.md)、项目自身文档、`scripts/*` 入口脚本、CI 配置
这个入口文件只负责一件事:让新 session 先判断主问题属于哪一层,再进入最相关的单个入口页。 这个入口文件只负责一件事:让 agent 先判断主问题属于哪一层,再进入最相关的单个入口页。这里的语法文档面向 agent 决策,不按人类教程组织;回答和生成代码时必须按流程读,不要凭语言相似性补全。
## 先记住这些规则 ## 先记住这些规则
- 先读本文件,不要默认通读全部 TSL 文档。 - 先读本文件,不要默认通读全部 TSL 文档。
- 用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;未给后缀时,再根据用户交付目标判断。
- `.tsl` 是可执行脚本;`.tsf` 是部署到解释器 `funcext` 的模块/函数扩展文件。
- 写 `.tsl` 时按两段理解:语句区在前并按顺序执行;函数/类声明区在后,供前面的语句调用或运行时解析。
- 写 `.tsf` 时按模块/扩展理解;顶层函数部署到 `funcext` 后,`.tsl` 脚本可以直接调用。
- 语言怎么写的问题,先从 `docs/tsl/syntax/` 开始。 - 语言怎么写的问题,先从 `docs/tsl/syntax/` 开始。
- 指标、选股、回测和策略流程的问题,先从 `docs/tsl/finance/` 开始;不要先把业务问题拆成纯语法问题。 - 指标、选股、回测和策略流程的问题,先从 `docs/tsl/finance/` 开始;不要先把业务问题拆成纯语法问题。
- 某个函数怎么用、属于哪个函数库分类或目录,先从 `docs/tsl/reference/` 开始。 - 某个函数怎么用、属于哪个函数库分类或目录,先从 `docs/tsl/reference/` 开始。
- 现成模块、外部集成和互操作问题,先从 [modules/index.md](modules/index.md) 开始。 - 现成模块、外部集成和互操作问题,先从 [modules/index.md](modules/index.md) 开始。
- 账户体系、真实接口名、部署方式、脚本入口、权限模型、环境变量、CI、验证命令这类问题先按“项目依赖 / 项目执行”处理;优先回项目自身文档、`scripts/*` 入口脚本、CI 配置。 - 账户体系、真实接口名、部署方式、脚本入口、权限模型、环境变量、CI、验证命令这类问题先按“项目依赖 / 项目执行”处理;优先回项目自身文档、`scripts/*` 入口脚本、CI 配置。
- [toolchain.md](toolchain.md) 不是 TSL 语法子类,而是项目执行类辅证页;只有当前项目已经补齐工具链与验证信息时才使用;如果这页仍是模板,不把它当主入口。 - [toolchain.md](toolchain.md) 不是 TSL 语法子类,而是项目执行类辅证页;只有当前项目已经补齐工具链与验证信息时才使用;如果这页仍是模板,不把它当主入口。
- 顶层主体优先按四类理解:松散语句、`function / procedure`、`type Name = class`、`unit` - 生成 `.tsl` 代码时,优先从脚本语句区开始;如果关键词要求函数或类,把声明放在语句区之后
- 不要把顶层 `function / procedure` 定义和松散语句混在同一个文件模型里 - 不要`.tsl` 的函数/类声明区之后再追加新的脚本语句
- 任何语法判断都先看正式语法页结论。 - 任何语法判断都先看正式语法页结论。
- 如果涉及较新写法、资料冲突或解释器差异,先回到 `docs/tsl/syntax/index.md`,再按主题跳到对应语法页;只有对应主题页仍然没有结论时,才本地用 `tsl` 验证 - 如果涉及较新写法、资料冲突或解释器差异,先回到 `docs/tsl/syntax/index.md`,再按主题跳到对应语法页;对应主题页仍然没有结论时,不要自行补语法
- 如果涉及高频误写、反例或负向边界,优先回到 `docs/tsl/syntax/12_pitfalls.md`只有结论缺失时,才本地用 `tsl` 验证 - 如果涉及高频误写、反例或负向边界,优先回到 `docs/tsl/syntax/12_pitfalls.md`结论缺失时不要把猜测写成语法事实
- 模板、错误示例和输出片段不算可独立编译代码。 - 模板、错误示例和输出片段不算可独立编译代码。
## 元数据与证据标签 ## 元数据与证据标签
@ -34,8 +38,27 @@
- 如果还需要补充用途、限制或复用建议,单独写 `代码块说明`,不要把说明文字继续拼进 `代码块身份` - 如果还需要补充用途、限制或复用建议,单独写 `代码块说明`,不要把说明文字继续拼进 `代码块身份`
- 如果页头里的 `遇到不确定时跳转到` 列出多个目标,默认第一项是优先入口,后面的目标只用于分流或补证。 - 如果页头里的 `遇到不确定时跳转到` 列出多个目标,默认第一项是优先入口,后面的目标只用于分流或补证。
## 维护者入文档前验证
- TSL 语法页面向 agent 生成代码;所有写成语法事实的代码库样例,必须先由维护者在项目验证环境中确认。
- 正向代码库样例只有在环境验证通过后,才能标成 `已验证可执行示例`;对应输出只能标成 `已验证输出片段`
- 负向代码库样例只有在环境中确认失败形态后,才能标成 `反例 / 不可照写`
- 未经过环境验证的写法不能写成语法事实;只能作为文档缺口、待验证项,或标成 `配置片段 / 概念骨架`
- 验证过程不写进语法页解释器路径、Docker、Windows、Ubuntu、环境变量和执行命令属于项目执行层不能混入通用语法事实。
- agent 不需要自行执行验证agent 只根据维护者已经写入文档的证据标签生成代码,遇到未覆盖写法时不要发明语法。
## 新 session 起手规则 ## 新 session 起手规则
### Agent 读取流程
1. 识别目标层:语法、金融业务、函数库、模块/集成、项目执行。
2. 识别用户指定的文件后缀;用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据。
3. 用户未给后缀时,按交付目标判断:可执行代码对应 `.tsl`,通用模块对应 `.tsf`;仍不明确时向用户确认。
4. 对 `.tsl`,先生成语句区;需要本文件函数/类时,再生成声明区。
5. 对 `.tsf`,生成模块/扩展声明;部署后的顶层函数可由脚本直接调用。
6. 只读取当前任务命中的单个入口页;不要同时展开语法、业务、函数库和工具链。
7. 生成代码前找 `代码块身份:已验证可执行示例`;遇到 `反例 / 不可照写` 必须避开。
### If / Then 路由 ### If / Then 路由
- If 问题在问“语言怎么写”then 先从 [syntax/index.md](syntax/index.md) 开始。 - If 问题在问“语言怎么写”then 先从 [syntax/index.md](syntax/index.md) 开始。
@ -57,17 +80,17 @@
### 语言事实 ### 语言事实
- 可以先把 TSL 当成 Pascal 风格语言去理解:`function`、`begin`、`end`、`unit`、`uses` 都很接近;但这里只借外形,不默认继承 Pascal 的全部语义、库习惯和文件模型。 - 可以先把 TSL 当成 Pascal 风格语言去理解:`function`、`begin`、`end`、`unit`、`uses` 都很接近;但这里只借外形,不默认继承 Pascal 的全部语义、库习惯和文件模型。
- 涉及赋值、`function / procedure` 外形、`unit` 骨架、命名参数、`type Name = class`、数组 / 字符串下标这类高频硬规则,统一以 [syntax/02_quickstart.md](syntax/02_quickstart.md) 的“语言核心事实速查”为准;当前页只保留跨层路由所需的最小提醒。 - 涉及赋值、`.tsl` 语句区 / 声明区、`.tsf` 模块、`function / procedure` 外形、`unit` 骨架、命名参数、`type Name = class`、数组 / 字符串下标这类高频硬规则,统一以 [syntax/02_quickstart.md](syntax/02_quickstart.md) 的“语言核心事实速查”为准;当前页只保留跨层路由所需的最小提醒。
#### 写代码前先记住 #### 写代码前先记住
- 写代码前先把高频硬规则收口到 [syntax/02_quickstart.md](syntax/02_quickstart.md),不要分别从入口页、介绍页和文件模型页拼接结论。 - 写代码前先把高频硬规则收口到 [syntax/02_quickstart.md](syntax/02_quickstart.md),不要分别从入口页、介绍页和文件模型页拼接结论。
- 顶层主体仍优先按四类理解:松散语句、`function / procedure`、`type Name = class`、`unit` - `.tsl` 仍优先按“语句区在前、声明区在后”的脚本模型理解;`.tsf` 仍优先按部署到 `funcext` 的模块/扩展理解
- 模板、错误示例和输出片段不算可独立编译代码;真正落代码时优先看块级 `代码块身份` - 模板、错误示例和输出片段不算可独立编译代码;真正落代码时优先看块级 `代码块身份`
### 手册建模规则 ### 手册建模规则
- 更可靠的识别方式是看顶层内容,而不是只看文件扩展名。 - 更可靠的识别方式是同时任务目标和顶层内容,而不是只看文件扩展名。
- 顶层允许出现 `uses`,但这里只把它当辅助语句,不把它当主体声明。 - 顶层允许出现 `uses`,但这里只把它当辅助语句,不把它当主体声明。
- 下游大量 `program test; begin ... end.` 形式,只作为自包含验证样例外壳,不作为这里归纳的正式顶层模型。 - 下游大量 `program test; begin ... end.` 形式,只作为自包含验证样例外壳,不作为这里归纳的正式顶层模型。
@ -108,4 +131,4 @@
4. 当前页如果已经给出结论,先采用;准备编写时优先找已验证正例,再落代码;只有需要补充时再跳到相邻页。 4. 当前页如果已经给出结论,先采用;准备编写时优先找已验证正例,再落代码;只有需要补充时再跳到相邻页。
5. 遇到“资料写法不一致”且偏较新写法、资料冲突或解释器差异时,先回 [syntax/index.md](syntax/index.md) 按主题跳到对应语法页。 5. 遇到“资料写法不一致”且偏较新写法、资料冲突或解释器差异时,先回 [syntax/index.md](syntax/index.md) 按主题跳到对应语法页。
6. 遇到“资料写法不一致”且偏高频误写、反例或负向边界时,先看 [syntax/12_pitfalls.md](syntax/12_pitfalls.md)。 6. 遇到“资料写法不一致”且偏高频误写、反例或负向边界时,先看 [syntax/12_pitfalls.md](syntax/12_pitfalls.md)。
7. 只有当前手册没有给出结论时,才写最小 `.tsl` / `.tsf` 例子并用 `tsl` 实测 7. 如果当前手册没有给出结论,不要发明语法;改为向用户确认、记录文档缺口,或等待维护者用项目环境补充已验证结论

View File

@ -2,14 +2,18 @@
文档类型:检索页 文档类型:检索页
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:[tsbacktesting.md](tsbacktesting.md)、[tsl_python_interop.md](tsl_python_interop.md)、[../finance/index.md](../finance/index.md)、项目自身文档、`scripts/*` 入口脚本、CI 配置 遇到不确定时跳转到:[tsbacktesting.md](tsbacktesting.md)、[tsl_python_interop.md](tsl_python_interop.md)、[../finance/index.md](../finance/index.md)、项目自身文档、`scripts/*` 入口脚本、CI 配置
这里处理“现成模块、外部集成和互操作”,不处理基础语法教学,也不替代金融业务主线。 这里处理“现成模块、外部集成和互操作”,不处理基础语法教学,也不替代金融业务主线。
模块摘要页只负责确认能力边界和选路,不负责给出项目账户体系、真实接口名、部署方式、权限模型或脚本入口的真值。 模块摘要页只负责确认能力边界和选路,不负责给出项目账户体系、真实接口名、部署方式、权限模型或脚本入口的真值。
## Agent Modules 路由规则
- 先判断任务是在问模块能力、业务流程、语法规则还是项目真实接入参数。
- modules 只给集成边界和选路;真实账号、部署入口、权限模型和接口细节必须回项目文档。
- 不要发明模块专属 API 参数、项目账号来源、部署路径或脚本入口。
## If / Then 路由 ## If / Then 路由
- If 问题在问“策略回测框架怎么组织、怎么取结果”then 先读 [tsbacktesting.md](tsbacktesting.md)。 - If 问题在问“策略回测框架怎么组织、怎么取结果”then 先读 [tsbacktesting.md](tsbacktesting.md)。

View File

@ -2,14 +2,18 @@
文档类型:模块摘要 文档类型:模块摘要
是否可直接用于生成代码:仅部分 是否可直接用于生成代码:仅部分
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:项目级部署文档、官方 pyTSL 详细接口文档、[tsl_python_interop.md](tsl_python_interop.md)、[index.md](index.md) 遇到不确定时跳转到:项目级部署文档、官方 pyTSL 详细接口文档、[tsl_python_interop.md](tsl_python_interop.md)、[index.md](index.md)
本页用于确认 pyTSL 的接入方向和最小链路,不替代项目级部署文档或完整接口手册。 本页用于确认 pyTSL 的接入方向和最小链路,不替代项目级部署文档或完整接口手册。
- 如果登录方式、凭证来源、环境变量、部署入口、连接上下文或返回结构没有确认,不继续生成接入代码,直接回项目级部署文档或官方 pyTSL 详细接口文档。 - 如果登录方式、凭证来源、环境变量、部署入口、连接上下文或返回结构没有确认,不继续生成接入代码,直接回项目级部署文档或官方 pyTSL 详细接口文档。
## Agent pyTSL 边界规则
- 先确认项目是否已经给出 pyTSL 安装方式、登录方式、凭证来源和返回结构。
- 本页只给 SDK 能力分类和最小链路,不替代官方接口手册。
- 不要发明登录参数、连接上下文、查询语句来源或返回数据结构。
## 定位 ## 定位
- 官方 Python SDK面向取数/执行/批量/异步与数据转换。 - 官方 Python SDK面向取数/执行/批量/异步与数据转换。
@ -73,8 +77,7 @@
示例里的 `"user"` / `"password"` 只表示调用外形,不代表项目里的真实登录方式或凭证来源。 示例里的 `"user"` / `"password"` 只表示调用外形,不代表项目里的真实登录方式或凭证来源。
代码块身份:配置片段 / 概念骨架 下面代码只表示调用外形;真实登录方式、凭证和查询来源以项目文档为准。
代码块说明:可参考最小链路,不是已验证可执行示例。
```python ```python
import pyTSL import pyTSL

View File

@ -2,14 +2,18 @@
文档类型:模块摘要 文档类型:模块摘要
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:项目实际接口定义、[../finance/backtest_and_trade_flow.md](../finance/backtest_and_trade_flow.md)、[index.md](index.md) 遇到不确定时跳转到:项目实际接口定义、[../finance/backtest_and_trade_flow.md](../finance/backtest_and_trade_flow.md)、[index.md](index.md)
本页不足以直接生成回测代码,只用于确认回测任务的组织顺序,以及哪些地方必须回到项目实际接口定义继续核对。 本页不足以直接生成回测代码,只用于确认回测任务的组织顺序,以及哪些地方必须回到项目实际接口定义继续核对。
- 只要任务已经进入对象创建、交易输入入口、结果读取方法或项目封装差异,就先停止生成,直接回项目实际接口定义,不要先拼调用链。 - 只要任务已经进入对象创建、交易输入入口、结果读取方法或项目封装差异,就先停止生成,直接回项目实际接口定义,不要先拼调用链。
## Agent TSBackTesting 边界规则
- 只把本页用于识别回测框架任务顺序和常见字段类别。
- 对象创建方式、最小必填字段、交易入口和结果接口都以项目实际接口定义为准。
- 不要发明 `TSBackTesting` 构造方式、交易输入函数或结果读取调用链。
## 适用场景 ## 适用场景
- 任务已经进入“回测框架怎么配置、怎么执行、怎么读结果”。 - 任务已经进入“回测框架怎么配置、怎么执行、怎么读结果”。

View File

@ -2,14 +2,18 @@
文档类型:模块摘要 文档类型:模块摘要
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:项目级部署文档、对应官方文档、[pytsl_api.md](pytsl_api.md)、[index.md](index.md) 遇到不确定时跳转到:项目级部署文档、对应官方文档、[pytsl_api.md](pytsl_api.md)、[index.md](index.md)
本页用于接入决策和最小链路确认,不替代项目级部署文档。 本页用于接入决策和最小链路确认,不替代项目级部署文档。
- 如果登录方式、凭证来源、位数、环境变量、连接通道或部署入口没有确认,不继续生成接入代码,直接回项目级部署文档或对应官方文档。 - 如果登录方式、凭证来源、位数、环境变量、连接通道或部署入口没有确认,不继续生成接入代码,直接回项目级部署文档或对应官方文档。
## Agent Python 互操作边界规则
- 先判断是 Python 调 TSL、TSL 调 Python还是服务器侧 Python 服务。
- 本页只给接入路径和接口类别;真实登录方式、位数、环境变量和部署入口必须回项目级部署文档。
- 不要发明凭证来源、连接通道、Python 路径或服务部署方式。
## 摘要 ## 摘要
- 覆盖三类交互Python 调用 TSL、TSL 调用 Python、落地服务器开启 Python 服务。 - 覆盖三类交互Python 调用 TSL、TSL 调用 Python、落地服务器开启 Python 服务。

View File

@ -2,12 +2,16 @@
文档类型:模块摘要 文档类型:模块摘要
是否可直接用于生成代码:仅部分 是否可直接用于生成代码:仅部分
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:调用侧账户体系文档、项目实际接口说明、[index.md](index.md) 遇到不确定时跳转到:调用侧账户体系文档、项目实际接口说明、[index.md](index.md)
本页用于确认接口名称、参数含义和风险边界,不替代项目级接入文档。 本页用于确认接口名称、参数含义和风险边界,不替代项目级接入文档。
## Agent 微信消息边界规则
- 先确认调用侧已经提供 `userid`、模板类型、关键字含义和必要的账户字段。
- 本页只给接口外形和参数含义;账户体系、授权关系和模板映射以项目实际接口说明为准。
- 不要发明 `username` 来源、模板关键字含义、项目封装函数或账户映射。
## 适用场景 ## 适用场景
- 通过“天软科技服务号”向微信客户端发送模板消息。 - 通过“天软科技服务号”向微信客户端发送模板消息。
@ -59,8 +63,7 @@
## 发送示例(配置片段,可参考参数组织) ## 发送示例(配置片段,可参考参数组织)
代码块身份:配置片段 / 概念骨架 下面代码只表示参数组织方式;真实账户、模板关键字和调用侧封装以项目实际接口说明为准。
代码块说明:可参考参数组织,不是已验证可执行示例。
```tsl ```tsl
// 定义参数 // 定义参数

View File

@ -50,8 +50,7 @@ Guide 对齐:通过名字的“形状”快速判断实体类型(类型/函
## 3. 类型命名Type Names ## 3. 类型命名Type Names
AI 先按四类顶层外形判断文件模型:顶层松散语句、顶层 `function / procedure` AI 先按 `.tsl` 可执行脚本与 `.tsf` 模块/函数扩展判断文件模型。`.tsl` 里的语句区按顺序执行,函数/类声明区放在语句区之后;`.tsf` 用于可复用顶层声明并部署到解释器 `funcext`。本页只覆盖“需要命名的顶层实体”,不覆盖脚本语句本身;文件模型判断本身以
顶层 `type Name = class`、顶层 `unit`。本页只覆盖“需要命名的顶层实体”,不覆盖松散语句本身;文件模型判断本身以
`docs/tsl/syntax/03_core_model.md` 为准。 `docs/tsl/syntax/03_core_model.md` 为准。
- **类与单元**使用 - **类与单元**使用
@ -76,7 +75,7 @@ TSL 的语法要求(仅 `.tsf`):每个 `.tsf`
`function / procedure`、`type Name = class`、`unit`,文件基名需与之同名。 `function / procedure`、`type Name = class`、`unit`,文件基名需与之同名。
- `.tsl` 脚本文件:用于入口/编排层;允许直接写语句(如 - `.tsl` 脚本文件:用于入口/编排层;允许直接写语句(如
`a := 1; echo a;`),也可能出现顶层 `function / procedure` 骨架或 `program test;` `a := 1; echo a;`),也可能出现顶层 `function / procedure` 骨架或 `program test;`
这类验证样例外壳;但风格上不把 `.tsl` 当成可复用顶层声明的默认落点,也不要求文件基名与函数名一致;可复用逻辑优先下沉到 这类验证样例外壳;如果同时出现脚本语句和函数/类声明,语句区在前,声明区在后;但风格上不把 `.tsl` 当成可复用顶层声明的默认落点,也不要求文件基名与函数名一致;可复用逻辑优先下沉到
`.tsf`(见 `docs/tsl/code_style.md`)。 `.tsf`(见 `docs/tsl/code_style.md`)。
- 注:`.tsf` 也是 TSL 源文件,命名/风格与 `.tsl` 遵循同一套规则。 - 注:`.tsf` 也是 TSL 源文件,命名/风格与 `.tsl` 遵循同一套规则。
- **硬规则(仅 - **硬规则(仅

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -1,13 +1,17 @@
# Function Catalog # Function Catalog
这里是 canonical 函数目录。它只回答“函数在哪个模块里”,不承担基础语法教学。 这里是候选函数索引。它只回答“函数名可能在哪个模块里”,不承担基础语法教学,也不证明函数在当前环境可用。
候选名没有进入 verified 函数页前不能当成可调用事实。agent 真正生成代码前,只从 verified 函数页读取参数类型。
## 使用顺序 ## 使用顺序
1. 不知道函数在哪个模块,先看下面的模块目录。 1. 不知道函数在哪个模块,先看下面的模块目录。
2. 进入模块页后,在页内搜索具体函数名。 2. 进入模块页后,在页内搜索具体候选函数名。
3. 如果问题是语法怎么写,回到 [../../syntax/index.md](../../syntax/index.md)。 3. 如果要生成代码,先看 [../verified/index.md](../verified/index.md),再进入具体函数页;当前核心函数页是 [../verified/core.md](../verified/core.md)。
4. 如果问题是金融场景如何组织,回到 [../../finance/index.md](../../finance/index.md)。 4. 如果候选函数没有进入 verified 函数页,不要生成调用代码。
5. 如果问题是语法怎么写,回到 [../../syntax/index.md](../../syntax/index.md)。
6. 如果问题是金融场景如何组织,回到 [../../finance/index.md](../../finance/index.md)。
## 模块目录 ## 模块目录
@ -27,4 +31,11 @@
## 说明 ## 说明
- 这套目录页由仓库内的函数语料自动整理生成。 - 这套目录页由仓库内的函数语料自动整理生成。
- 当前目标是先提供稳定检索层,再逐步补全更细的 canonical 说明。 - catalog 只保留候选函数索引,不写参数矩阵,不写可调用结论。
- 当前目标是先提供稳定检索层,再逐步补全 agent 可直接读取的参数事实。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,6 +2,12 @@
这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。 这一页只负责函数定位:先按主题找到模块,再在页内搜索函数名。
## 候选函数索引说明
- 本页是候选函数索引,只说明函数名被归入当前模块。
- 候选名没有进入 verified 函数页前不能当成可调用事实。
- 生成代码前必须先查 [../verified/index.md](../verified/index.md);只从 verified 函数页读取参数类型。
## 使用方式 ## 使用方式
- 返回总目录:[catalog/index.md](index.md) - 返回总目录:[catalog/index.md](index.md)

View File

@ -2,33 +2,37 @@
文档类型:检索页 文档类型:检索页
是否可直接用于生成代码:否 是否可直接用于生成代码:否
是否含已验证可执行示例:否
是否含已验证反例:否
遇到不确定时跳转到:[catalog/index.md](catalog/index.md)、[../syntax/index.md](../syntax/index.md)、[../finance/index.md](../finance/index.md) 遇到不确定时跳转到:[catalog/index.md](catalog/index.md)、[../syntax/index.md](../syntax/index.md)、[../finance/index.md](../finance/index.md)
这里是函数查阅层,不是默认通读入口。现在这一页本身就是函数总入口,不再要求先跳到额外的中转页。 这里是函数查阅层,不是默认通读入口。现在这一页本身就是函数总入口,不再要求先跳到额外的中转页。
## 先看这 5 条 reference 的目标是确认每个方法的参数类型,让 agent 写代码时知道该传什么。文档只保留 agent 生成代码需要的函数事实。
- 这里用于函数查找,不用于建立基础语法模型。 ## Agent 函数使用规则
- 不要把 reference 当成默认通读入口;如果任务就是查函数,可以直接从这里开始。
- 函数库规模很大,应先走索引,再做定向检索。 - 只从 verified 函数页读取参数类型、返回值和调用约束。
- 如果目录和定向检索都找不到函数,不要默认它是 TSL 内建函数;先回语法层、业务层、模块页或项目文档确认来源。 - catalog 只是候选函数索引,不能把 catalog 里的函数名直接当成可调用事实。
- 如果你还在问“语言怎么写”,先回 [../syntax/index.md](../syntax/index.md)。 - 函数没有进入 verified 函数页时,不要根据函数名猜参数,也不要生成调用代码。
- 函数参数必须按正确类型传入TSL 本身弱类型,不等于函数参数无类型。
- 如果函数被记录为当前测试环境不支持,不要使用该函数生成代码。
## 检索策略 ## 检索策略
1. 先看 [catalog/index.md](catalog/index.md) 的模块目录,确定大类。 1. 先看 [catalog/index.md](catalog/index.md) 的模块目录,确定候选大类。
2. 进入对应模块页,在页内搜索具体函数名。 2. 进入对应模块页,在页内搜索具体候选函数名。
3. 仍然不确定时,再用 `rg``docs/tsl/reference/catalog/` 做定向搜索。 3. 先看 [verified/index.md](verified/index.md),再进入具体 verified 函数页读取参数类型、返回值和调用约束;当前核心函数页是 [verified/core.md](verified/core.md)。
4. 如果目录和定向检索都找不到函数,不要发明函数名,也不要默认它是 TSL 内建函数;回 [../syntax/index.md](../syntax/index.md)、[../finance/index.md](../finance/index.md)、[../modules/index.md](../modules/index.md) 或项目文档确认来源。 4. 如果候选函数没有进入 verified 函数页,不要生成调用代码。
5. 当前测试环境不支持的方法见 [unavailable_methods.md](unavailable_methods.md)。
6. 如果目录和定向检索都找不到函数,不要发明函数名,也不要默认它是 TSL 内建函数;回 [../syntax/index.md](../syntax/index.md)、[../finance/index.md](../finance/index.md)、[../modules/index.md](../modules/index.md) 或项目文档确认来源。
## 按任务跳转 ## 按任务跳转
| 当前任务 | 先读哪里 | | 当前任务 | 先读哪里 |
| ---------------- | ------------------------------------------ | | ------------------------ | ------------------------------------------------ |
| 查函数库入口 | [catalog/index.md](catalog/index.md) | | 查函数库入口 | [catalog/index.md](catalog/index.md) |
| 直接按模块查函数 | [catalog/index.md](catalog/index.md) | | 直接按模块查函数 | [catalog/index.md](catalog/index.md) |
| 回到语法层 | [../syntax/index.md](../syntax/index.md) | | 查可调用函数参数类型 | [verified/index.md](verified/index.md) |
| 回到金融层 | [../finance/index.md](../finance/index.md) | | 查当前测试环境不支持方法 | [unavailable_methods.md](unavailable_methods.md) |
| 回到模块层 | [../modules/index.md](../modules/index.md) | | 回到语法层 | [../syntax/index.md](../syntax/index.md) |
| 回到金融层 | [../finance/index.md](../finance/index.md) |
| 回到模块层 | [../modules/index.md](../modules/index.md) |

View File

@ -0,0 +1,11 @@
# Reference Unavailable Methods
文档类型:当前测试环境不支持的方法清单
是否可直接用于生成代码:否
遇到不确定时跳转到:[verified/core.md](verified/core.md)、[catalog/index.md](catalog/index.md)
这里只记录方法不存在,或当前测试环境暂不支持的方法。参数类型事实写在 verified 函数页。
## 当前测试环境不支持的方法
暂无已入档记录。

View File

@ -0,0 +1,49 @@
# Verified Core Reference Functions
文档类型agent 参数事实表
是否可直接用于生成代码:是
遇到不确定时跳转到:[../catalog/index.md](../catalog/index.md)、[../../syntax/index.md](../../syntax/index.md)
本页只保留 agent 生成代码需要的函数事实:签名、接收类型、返回值和调用约束。
## 使用规则
- 只按“接收类型”传参。
- TSL 是弱类型语言,但函数参数不是任意类型。
- catalog 同名函数没有出现在 verified 页时,不要当作可调用事实。
## 函数参数
### `Abs(value)`
用途:返回数值绝对值。
| 参数 | 接收类型 | 返回 | 说明 |
| ------- | -------- | ---- | ---------- |
| `value` | 整数 | 数值 | 返回绝对值 |
| `value` | 实数 | 数值 | 返回绝对值 |
### `ifInt(value)`
用途:判断值当前是否按整数处理,返回 `1``0`
| 参数 | 接收类型 | 返回 | 说明 |
| ------- | --------------------------------------- | ---- | ---------------------- |
| `value` | 任意值;已记录整数、实数、字符串、`nil` | 整数 | 整数返回 `1`,否则 `0` |
### `DateToStr(value)`
用途:把日期时间值转成日期字符串。
| 参数 | 接收类型 | 返回 | 说明 |
| ------- | -------- | ------ | ------------------------------ |
| `value` | 日期时间 | 字符串 | 日期时间字面量可写 `20111231T` |
### `Length(value)`
用途:返回字符串或数组长度。
| 参数 | 接收类型 | 返回 | 说明 |
| ------- | -------- | ---- | ------------ |
| `value` | 字符串 | 整数 | 返回字符长度 |
| `value` | 数组 | 整数 | 返回元素个数 |

View File

@ -0,0 +1,19 @@
# Verified Reference Functions
文档类型agent 参数事实索引
是否可直接用于生成代码:否
遇到不确定时跳转到:[../catalog/index.md](../catalog/index.md)、[../../syntax/index.md](../../syntax/index.md)
本页只负责定位已经整理成参数事实表的函数页。生成调用代码时,进入具体函数页读取签名、接收类型、返回值和调用约束。
## 使用规则
- 只从具体函数页读取接收类型和返回值。
- catalog 里的候选名没有出现在具体函数页时,不要当作可调用事实。
- 不根据函数名猜参数。
## 参数事实页
| 范围 | 页面 | 当前函数 |
| -------- | ------------------ | ------------------------------------- |
| 核心函数 | [core.md](core.md) | `Abs`、`ifInt`、`DateToStr`、`Length` |

View File

@ -8,47 +8,61 @@
手册位置:第 1 篇,共 32 篇。上一篇:手册入口 [index.md](index.md)。下一篇:[02_quickstart.md](02_quickstart.md)。 手册位置:第 1 篇,共 32 篇。上一篇:手册入口 [index.md](index.md)。下一篇:[02_quickstart.md](02_quickstart.md)。
这一篇只做一件事:让新 session 在看到 TSL 时,先用正确的读法建立心智模型 这一篇只做一件事:给 agent 建立 TSL 的第一判断模型。它不是人类教程,不负责展开所有语法细节;它只告诉 agent 第一次看到 TSL 任务时先判断什么、按什么证据生成代码、哪些直觉不能继承
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“第一次读 TSL 时,应该先把它当成什么来理解,以及最容易和别的语言混淆的差异是什么”。 回答“agent 第一次读到 TSL 需求时,怎样先识别交付形态,再选择最小可靠代码结构”。
涉及赋值、命名参数、类外形、`unit` 骨架、数组 / 字符串下标这类高频硬规则时,统一以 [02_quickstart.md](02_quickstart.md) 的“语言核心事实速查”为准;这一页只负责建立第一印象 涉及赋值、命名参数、类外形、`unit` 骨架、数组 / 字符串下标这类高频硬规则时,统一以 [02_quickstart.md](02_quickstart.md) 的“语言核心事实速查”为准;这一页只负责建立第一判断模型
## 先用什么方式读 TSL ## Agent 第一判断流程
- 可以先按 Pascal 风格语言去读它:常见外形是 `function ... begin ... end;`、`unit ... interface ... implementation ... end.`、`type Name = class ... end;`;但这里只借外形,不默认继承 Pascal 的全部语义、库习惯和文件模型。 1. 用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据。
- 先看顶层主体,再看细节;不要先被文件扩展名带偏。 2. 用户未给后缀时,先看交付目标:可执行代码对应 `.tsl`,通用模块对应 `.tsf`
- 当前手册把顶层主体优先收敛成四类:松散语句、顶层 `function / procedure`、顶层 `type Name = class`、顶层 `unit` 3. 交付目标仍不明确时,向用户确认;不要替用户发明文件形态。
- 顶层 `uses` 可以出现,但这里只把它当成辅助组织语句,不把它当成主体声明。 4. 写 `.tsl` 时,先生成会顺序执行的语句区;如果需要函数或类,把声明区放在语句区之后。
5. 写 `.tsf` 时,只生成模块 / 函数扩展代码;部署后的顶层函数可被 `.tsl` 脚本直接调用。
6. 没有文档证据时不要发明语法;只能回到对应专题页、反例页、项目规则,或记录文档缺口。
## 先用什么方式理解 TSL
- TSL 可以借 Pascal 风格外形理解:`function ... begin ... end;`、`unit ... interface ... implementation ... end.`、`type Name = class ... end;` 都很接近。
- 这里只借外形,不默认继承 Pascal 的全部语义、库习惯和文件模型。
- `.tsl` / `.tsf` 首先是用户交付形态:`.tsl` 是可执行脚本,`.tsf` 是通用模块 / 函数扩展。
- 日常赋值先记 `:=`,不要把 `=` 当成普通赋值。 - 日常赋值先记 `:=`,不要把 `=` 当成普通赋值。
## 第一次写时最容易混淆的差异
- `array(...)` 既可以当顺序数组,也可以当字符串键表。
- 数组下标从 `0` 开始,字符串下标从 `1` 开始。
- 顶层类定义按 `type Name = class ... end;` 去写,不使用裸 `class Name`
- 调用函数时,命名参数写成 `name: value`,例如 `Demo(a: 1, b: 2)`
## 已验证的第一印象 ## 已验证的第一印象
最常见的 `function / procedure` 外形 `.tsl` 可执行脚本第一印象:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
function Demo(); a := 1;
begin test();
return 1;
end;
procedure LogDemo(msg); function test();
begin begin
WriteLn(msg); echo "test";
end; end;
``` ```
代码块说明:`.tsl` 的语句区在前,按顺序执行;函数声明区在后,供前面的脚本语句调用。
`.tsf` 通用模块第一印象:
代码块身份:已验证可执行示例
```tsl
function Test1();
begin
echo "test1";
end;
```
代码块说明:这个 `.tsf` 部署到解释器 `funcext` 后,`.tsl` 脚本可以直接调用 `Test1();`。文件部署方式属于项目执行层,不写进通用语法页。
赋值、数组、字符串下标的第一印象: 赋值、数组、字符串下标的第一印象:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -56,43 +70,25 @@ end;
```tsl ```tsl
items := array(10, 20, 30); items := array(10, 20, 30);
table_data := array("Code": "000001", "Name": "Demo"); table_data := array("Code": "000001", "Name": "Demo");
first_item := items[0]; echo items[0];
first_char := "ABC"[1]; echo table_data["Code"];
echo "ABC"[1];
``` ```
类的第一印象: 代码块说明:数组下标从 `0` 开始,字符串下标从 `1` 开始;更完整规则见 [04_values_and_literals.md](04_values_and_literals.md)。
代码块身份:已验证可执行示例 ## 第一次写时最容易混淆的边界
```tsl - 不要把 `.tsl` / `.tsf` 当成 agent 自行选择的纯语法分支;后缀和用户交付目标优先。
type DemoType = class - 不要把 Pascal 外形直接泛化成 Pascal 文件模型。
end; - 不要在 `.tsl` 的函数/类声明区之后继续追加脚本语句。
``` - 不要把未验证写法写成语法事实agent 生成代码时只模仿带证据标签的代码块。
`unit` 的第一印象:
代码块身份:已验证可执行示例
```tsl
unit DemoUnit;
interface
function Demo();
implementation
function Demo();
begin
return 1;
end;
end.
```
## 下一步怎么读 ## 下一步怎么读
- 需要立刻开始写代码:看 [02_quickstart.md](02_quickstart.md) - 需要立刻开始写代码:看 [02_quickstart.md](02_quickstart.md)
- 需要判断当前文件属于哪一种顶层模型:看 [03_core_model.md](03_core_model.md) - 需要判断当前文件组织方式:看 [03_core_model.md](03_core_model.md)
- 需要先写值、数组、字符串:看 [04_values_and_literals.md](04_values_and_literals.md) - 需要先写值、数组、字符串:看 [04_values_and_literals.md](04_values_and_literals.md)
- 需要先写变量、常量:看 [05_variables_and_constants.md](05_variables_and_constants.md) - 需要先写变量、常量:看 [05_variables_and_constants.md](05_variables_and_constants.md)
- 需要先写函数和调用:看 [06_functions_and_calls.md](06_functions_and_calls.md) - 需要先写函数和调用:看 [06_functions_and_calls.md](06_functions_and_calls.md)
- 需要先避开高频误写:看 [12_pitfalls.md](12_pitfalls.md)

View File

@ -8,19 +8,31 @@
手册位置:第 2 篇,共 32 篇。上一篇:[01_introduction.md](01_introduction.md)。下一篇:[03_core_model.md](03_core_model.md)。 手册位置:第 2 篇,共 32 篇。上一篇:[01_introduction.md](01_introduction.md)。下一篇:[03_core_model.md](03_core_model.md)。
这一篇集中回答两个紧邻问题:现在要写 TSL 时,应该从哪一种最短骨架起手;以及落代码前必须先核对哪些语言硬规则。 这一篇集中回答两个紧邻问题:用户已给出 `.tsl` / `.tsf` 后缀时agent 应该如何按后缀组织代码;以及落代码前必须先核对哪些语言硬规则。
## 这一篇解决什么问题 ## 这一篇解决什么问题
快速回答“当前任务应该从松散语句、函数、类还是 unit 开始”,并提供一份单点的语言核心事实速查。 快速回答“当前任务已经给出后缀或交付目标时,应该使用哪一种骨架”,并提供一份单点的语言核心事实速查。
## Agent 快速落代码流程
1. 先看用户有没有指定 `.tsl` / `.tsf` 后缀;指定后缀时,后缀就是文件形态判断依据。
2. 用户未指定后缀时,再根据交付目标判断 `.tsl``.tsf`:可执行脚本用 `.tsl`,通用模块 / 函数扩展用 `.tsf`
3. 只从 `代码块身份:已验证可执行示例` 的骨架起手;遇到 `反例 / 不可照写` 必须避开。
4. 写 `.tsl` 时,先写会执行的语句区;需要函数或类时,把声明区放在语句区之后。
5. 写 `.tsf` 时,只写模块 / 函数扩展内容;部署、查找路径和解释器环境属于项目执行层。
6. 当前页和对应专题页没有覆盖的写法,不要发明语法;改为跳转补证、向用户确认,或记录文档缺口。
## 语言核心事实速查 ## 语言核心事实速查
这一节是当前语法手册默认的语言硬规则收口点。涉及赋值、顶层外形、命名参数、类写法、`unit` 骨架和下标规则时,统一先看这里。 这一节是当前语法手册默认的语言硬规则收口点。涉及赋值、`.tsl` 语句区 / 声明区、`.tsf` 模块、命名参数、类写法、`unit` 骨架和下标规则时,统一先看这里。
- 普通赋值用 `:=`,不要把 `=` 当成普通赋值。 - 普通赋值用 `:=`,不要把 `=` 当成普通赋值。
- 顶层主体先按四类理解:松散语句、`function / procedure`、`type Name = class`、`unit`。 - 用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;用户未给后缀时,再按交付目标判断。
- 如果当前文件采用顶层 `function / procedure` 模型,就不要再混入松散语句。 - 未给后缀时,可执行代码对应 `.tsl`,通用模块对应 `.tsf`;仍不明确时向用户确认。
- `.tsl` 是可执行脚本:语句区在前并按顺序执行;函数/类声明区在后,供前面的语句调用或运行时解析。
- `.tsf` 是模块/函数扩展文件:部署到解释器 `funcext` 后,脚本可以直接调用其中暴露的顶层函数。
- 在 `.tsl` 中,如果需要函数或类,先写会执行的语句区,再写函数/类声明区;不要在声明区后面继续追加脚本语句。
- 无返回值时用 `procedure Name(...); begin ... end;`,不要勉强用 `function` - 无返回值时用 `procedure Name(...); begin ... end;`,不要勉强用 `function`
- 顶层类定义统一写成 `type Name = class ... end;`,不要写裸 `class Name` - 顶层类定义统一写成 `type Name = class ... end;`,不要写裸 `class Name`
- 多文件组织默认先按 `unit Name; interface ... implementation ... end.` 理解。 - 多文件组织默认先按 `unit Name; interface ... implementation ... end.` 理解。
@ -29,26 +41,30 @@
## 术语对照 ## 术语对照
- 文档里出现的“顶层 `function / procedure`”“顶层函数骨架”“顶层函数定义体”,指的是同一类顶层模型:文件以顶层 `function` / `procedure` 为主体。 - 文档里出现的“脚本语句区”,指 `.tsl` 文件开头会按顺序执行的语句。
- 文档里出现的“声明区”,指 `.tsl` 语句区之后的 `function / procedure``type Name = class` 声明。
- 文档里出现的“顶层 `function / procedure`”“顶层函数骨架”“顶层函数定义体”,在 `.tsf` 中指模块暴露的顶层函数,在 `.tsl` 中指脚本声明区里的函数。
- 文档里出现的 `class function` 和“类方法”,指的是同一件事:前者是代码关键字写法,后者是中文描述。 - 文档里出现的 `class function` 和“类方法”,指的是同一件事:前者是代码关键字写法,后者是中文描述。
## 先选哪一种骨架 ## 先选哪一种骨架
| 当前任务 | 起手骨架 | | 当前任务 | 起手骨架 |
| ------------------------------ | ------------------- | | -------------------------------- | --------------------------------- |
| 只写一段一次性脚本逻辑 | 顶层松散语句 | | 写一次性可执行逻辑 | `.tsl` 脚本语句区 |
| 先沉淀一个可复用逻辑块 | 顶层 `function` | | 脚本逻辑需要调用本文件内函数 | `.tsl` 语句区 + 后置函数声明区 |
| 需要对象状态、字段、方法 | `type Name = class` | | 脚本逻辑需要对象状态、字段、方法 | `.tsl` 语句区 + 后置类声明区 |
| 需要把接口和实现组织进一个模块 | `unit` | | 沉淀可复用函数并给脚本直接调用 | `.tsf` 顶层函数,部署到 `funcext` |
| 需要把接口和实现组织进一个模块 | `.tsf` `unit` |
默认建议: 默认建议:
- 如果你只是要让新 session 先写出一段最稳、最容易续写的基础语法,优先从顶层 `function` 开始。 - 如果你只是要让 agent 先写出一段最稳、最容易续写的可执行代码,优先从 `.tsl` 脚本语句区开始。
- 不要把 `unit` 当成最小起手骨架;只有用户明确要模块接口 / 实现组织,或项目已有 `unit` 边界时,才进入 `unit` 写法。
- `uses` 往往天然进入多文件查找路径问题,所以不放进这篇的最小起手骨架里。 - `uses` 往往天然进入多文件查找路径问题,所以不放进这篇的最小起手骨架里。
## 已验证最小骨架 ## 已验证最小骨架
顶层松散语句骨架: `.tsl` 脚本语句区骨架:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -56,27 +72,66 @@
a := 1; a := 1;
``` ```
顶层函数骨架 `.tsl` 语句区调用后置函数声明
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
function Demo(); a := 1;
test();
function test();
begin begin
return 1; echo "test";
end; end;
``` ```
顶层类骨架: 代码块身份:已验证输出片段
```text
test
```
`.tsl` 语句区调用后置类声明:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
type DemoType = class obj := CreateObject("MyClass");
obj.value := 5;
echo obj.value;
type MyClass = class
value;
end; end;
``` ```
顶层 `unit` 骨架: 代码块身份:已验证输出片段
```text
5
```
`.tsf` 顶层函数骨架:
代码块身份:已验证可执行示例
```tsl
function Test1();
begin
echo "test1";
end;
```
代码块说明:这个 `.tsf` 部署到解释器 `funcext` 后,`.tsl` 脚本可以直接调用 `Test1();`。部署方式属于项目执行层,不写进通用语法页。
代码块身份:已验证输出片段
```text
test1
```
`.tsf` `unit` 骨架:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -93,35 +148,50 @@ implementation
end. end.
``` ```
代码块说明:这个 `.tsf` 骨架用于模块接口 / 实现组织;已通过 `.tsl` 脚本 `uses DemoUnit` 调用 `Ping()` 验证返回值为 `1`。调用脚本和查找路径边界见 [10_units_and_scope.md](10_units_and_scope.md)。
## 最常用起手版本 ## 最常用起手版本
如果你现在没有明确的多文件或对象建模需求,直接从函数版本开始: 如果你现在没有明确的模块复用或对象建模需求,直接从 `.tsl` 脚本版本开始:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
function Hello(); echo "hello";
begin ```
return 1;
end; 代码块身份:已验证输出片段
```text
hello
``` ```
## 最容易写错的一件事 ## 最容易写错的一件事
- 不要把“顶层函数定义”和“顶层松散语句”混写在同一个最小文件里 - `.tsl` 可以同时有语句区和声明区;真正要避免的是在声明区后面继续追加脚本语句
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写
```text ```text
function Add(a, b); a := 1;
test();
function test();
begin begin
return a + b; echo "test";
end; end;
value := Add(1, 2); echo "after declaration";
``` ```
上面这种“先定义顶层函数,再接松散语句”的混合写法会编译失败。 上面最后一行属于“声明区之后继续写脚本语句”。写 `.tsl` 时先把会执行的语句放在前面,再把函数/类声明放在后面。
代码块身份:已验证输出片段
```text
Execute script error at Line:9
function:__main__:line 9: invalid statement
```
## 跳转指引 ## 跳转指引

View File

@ -8,26 +8,87 @@
手册位置:第 3 篇,共 32 篇。上一篇:[02_quickstart.md](02_quickstart.md)。下一篇:[04_values_and_literals.md](04_values_and_literals.md)。 手册位置:第 3 篇,共 32 篇。上一篇:[02_quickstart.md](02_quickstart.md)。下一篇:[04_values_and_literals.md](04_values_and_literals.md)。
这一篇说明 TSL 的文件模型判断规则:顶层主体是什么、辅助语句是什么、为什么很多错误其实是“文件模型选错了”。 这一篇说明 TSL 的文件模型判断规则:agent 如何区分 `.tsl` 可执行脚本与 `.tsf` 模块,如何识别脚本语句区和声明区,以及为什么很多错误其实是“文件模型选错了”。
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“当前文件到底属于哪一种顶层写法,以及哪些语句只是辅助组织,不应该被误当成主体声明”。 回答“当前文件到底`.tsl` 脚本还是 `.tsf` 模块,以及 `.tsl` 里的哪些内容会顺序执行、哪些内容只是后置声明”。
如果问题已经变成赋值、命名参数、类外形、`unit` 骨架或下标规则这类通用硬规则,统一回 [02_quickstart.md](02_quickstart.md) 的“语言核心事实速查”;这一页只处理文件模型判断。 如果问题已经变成赋值、命名参数、类外形、`unit` 骨架或下标规则这类通用硬规则,统一回 [02_quickstart.md](02_quickstart.md) 的“语言核心事实速查”;这一页只处理文件模型判断。
## Agent 文件模型判断流程
1. 后缀是第一证据:用户明确要求 `.tsl` 时,按可执行脚本写;用户明确要求 `.tsf` 时,按模块 / 函数扩展写。
2. 没有后缀时看交付目标:可执行交付对应 `.tsl`,可复用扩展交付对应 `.tsf`
3. 目标仍不明确时先问用户;不要把脚本入口和通用模块替用户合并成一个猜测文件。
4. 写 `.tsl` 时,先生成脚本语句区;需要函数、过程或类时,把声明区放在语句区之后。
5. 写 `.tsf` 时,生成顶层函数 / 过程或 `unit`;不要写成会直接顺序执行的脚本入口。
6. 没有文档证据时不要发明文件模型;只能回到对应专题页、项目规则,或记录文档缺口。
## 必须记住的规则 ## 必须记住的规则
- 比起扩展名,更可靠的判断方式是看顶层内容。 - 用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;未给后缀时,再按交付目标判断。
- 顶层主体在当前手册里优先按四种外形理解:顶层松散语句、`function / procedure`、`type Name = class`、`unit`。 - 未给后缀时,可执行代码对应 `.tsl`,通用模块对应 `.tsf`;仍不明确时向用户确认。
- `.tsl` 脚本按两段理解:语句区在前并按顺序执行;声明区在后,可放 `function / procedure``type Name = class`
- `.tsf` 模块按可部署扩展理解:顶层函数部署到解释器 `funcext` 后,`.tsl` 可以直接调用;`unit` 仍按模块组织理解。
- `uses` 可以出现在顶层,但这里只把它当成辅助语句,不把它当成主体声明;函数体和类定义体里的位置限制见 [10_units_and_scope.md](10_units_and_scope.md)。 - `uses` 可以出现在顶层,但这里只把它当成辅助语句,不把它当成主体声明;函数体和类定义体里的位置限制见 [10_units_and_scope.md](10_units_and_scope.md)。
- 裸 `class Name` 不作为类定义写法使用。 - 裸 `class Name` 不作为类定义写法使用。
- 如果一个文件已经采用“顶层 `function / procedure`”模型,就不要再混入松散语句。 - `.tsl` 中,不要在声明区之后继续追加脚本语句。
- `unit` 默认先按完整形态理解;它也可以省略 `interface` / `implementation` 写成简写形态,见 [10_units_and_scope.md](10_units_and_scope.md)。 - `unit` 默认先按完整形态理解;它也可以省略 `interface` / `implementation` 写成简写形态,见 [10_units_and_scope.md](10_units_and_scope.md)。
- 不要把 `.tsl` 写成只有顶层函数的模块;如果用户要通用可复用函数,优先写 `.tsf`
- 不要把 `.tsf` 写成会直接执行脚本语句的入口;如果用户要顺序执行入口,优先写 `.tsl`
## 已验证语法 ## 已验证语法
顶层主体的最小形态: `.tsl` 脚本语句区的最小形态:
代码块身份:已验证可执行示例
```tsl
a := 1;
```
`.tsl` 语句区后接函数声明区:
代码块身份:已验证可执行示例
```tsl
a := 1;
test();
function test();
begin
echo "test";
end;
```
代码块身份:已验证输出片段
```text
test
```
`.tsl` 语句区后接类声明区:
代码块身份:已验证可执行示例
```tsl
obj := CreateObject("MyClass");
obj.value := 5;
echo obj.value;
type MyClass = class
value;
end;
```
代码块身份:已验证输出片段
```text
5
```
`.tsf` 顶层函数的最小形态:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -38,35 +99,39 @@ begin
end; end;
``` ```
代码块身份:已验证可执行示例 代码块说明:这个 `.tsf` 部署为函数扩展后,可由 `.tsl` 脚本调用 `Demo()` 并取得返回值。
```tsl 代码块身份:已验证输出片段
procedure DemoProc();
begin ```text
end; 1
``` ```
代码块身份:已验证可执行示例 `.tsf` `unit` 的最小形态:
```tsl
type DemoType = class
end;
```
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
unit DemoUnit; unit DemoUnit;
interface interface
function Ping(); function Ping();
implementation implementation
function Ping(); function Ping();
begin begin
return 1; return 1;
end; end;
end. end.
``` ```
代码块说明:这个 `.tsf` `unit` 已通过 `.tsl` 脚本 `uses DemoUnit` 调用 `Ping()` 验证返回值为 `1`;调用脚本和查找路径边界见 [10_units_and_scope.md](10_units_and_scope.md)。
代码块身份:已验证输出片段
```text
1
```
已验证失败的形态: 已验证失败的形态:
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写
@ -78,14 +143,20 @@ end;
上面这种裸 `class` 顶层写法会编译失败。 上面这种裸 `class` 顶层写法会编译失败。
代码块身份:已验证输出片段
```text
invalid statement
```
## 最小可编译示例 ## 最小可编译示例
如果当前任务只是“先让 session 判断当前文件属于哪一种模型”,先记住下面这组归类: 如果当前任务只是“先让 agent 判断当前文件属于哪一种模型”,先记住下面这组归类:
- 顶层语句骨架:直接写松散语句。 - `.tsl` 脚本语句区:直接写会顺序执行的语句。
- 顶层函数 / 过程骨架:写 `function ... begin ... end;``procedure ... begin ... end;` - `.tsl` 声明区:在语句区之后写 `function ... begin ... end;`、`procedure ... begin ... end;` 或 `type Name = class ... end;`。
- 顶层类骨架:写 `type Name = class ... end;` - `.tsf` 顶层函数 / 过程:写可部署到 `funcext``function` / `procedure` 文件
- 顶层单元骨架:默认先写 `unit ... interface ... implementation ... end.`;简写形态见 [10_units_and_scope.md](10_units_and_scope.md)。 - `.tsf` 顶层单元:默认先写 `unit ... interface ... implementation ... end.`;简写形态见 [10_units_and_scope.md](10_units_and_scope.md)。
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -95,9 +166,10 @@ a := 1;
## 常见误写 ## 常见误写
- 误以为扩展名本身就完全决定能否写函数、类或 `unit` - 把 `.tsl` 当成 `.tsf` 来写,只给一个顶层函数,不写任何会执行的脚本语句。
- 把 `.tsf` 当成 `.tsl` 来写,在模块文件里直接堆顺序执行的脚本语句。
- 把 `uses` 当成主体声明,而不是辅助组织语句。 - 把 `uses` 当成主体声明,而不是辅助组织语句。
- `function / procedure` 定义体和松散语句混写 - `.tsl` 声明区之后继续追加脚本语句
## 跳转指引 ## 跳转指引

View File

@ -14,9 +14,18 @@
回答“基本类型怎么写、数组和字符串怎么索引、哪些值规则属于语言级事实”。 回答“基本类型怎么写、数组和字符串怎么索引、哪些值规则属于语言级事实”。
## Agent 值写法判断流程
1. 普通值优先从整数、实数、普通字符串、布尔和 `array(...)` 起手。
2. 字符串默认用普通字符串;`L""` / `U""` 只在编码或宽串场景,并且必须按本页已验证边界写。
3. 看到 `array(...)` 时,先判断要顺序数组还是字符串键表:顺序数组用位置元素,字符串键表用 `"Key": value`
4. 写下标前先判断对象类别:顺序数组和二进制缓冲区下标从 `0` 开始,字符串下标从 `1` 开始。
5. 写字符串区间前先记住 `s[start:end]``end` 会被包含;不要按半开区间推断。
6. 没有已验证代码块时不要发明值写法;尤其不要从 JSON、JavaScript、Pascal 或 C 字符串规则直接迁移。
## 必须记住的规则 ## 必须记住的规则
- 最先掌握的几类值是:整数、实数、字符串、布尔和 `array` - 最先掌握的几类值是:整数、实数、普通字符串、布尔和 `array(...)`。
- 普通字符串既可以用双引号,也可以用单引号。 - 普通字符串既可以用双引号,也可以用单引号。
- 同类引号本身可以通过连续写两个同类引号放进字符串里。 - 同类引号本身可以通过连续写两个同类引号放进字符串里。
- `\\`、`\"`、`\n` 这类基础转义已验证可用。 - `\\`、`\"`、`\n` 这类基础转义已验证可用。
@ -55,13 +64,26 @@ name := "ABC";
flag1 := true; flag1 := true;
flag2 := false; flag2 := false;
items := array(1, 2, 3); items := array(1, 2, 3);
WriteLn(count);
WriteLn(price);
WriteLn(name);
WriteLn(flag1);
WriteLn(flag2);
WriteLn(items[1]);
``` ```
其中已经验证: 代码块身份:已验证输出片段
- `true` 可以直接写成布尔值。 ```text
- `false` 可以直接写成布尔值。 1
- 运行输出里,`true` / `false` 分别表现为 `1` / `0` 12.5
ABC
1
0
2
```
代码块说明:`true` / `false` 可以直接写成布尔值;运行输出里分别表现为 `1` / `0`
普通字符串字面量: 普通字符串字面量:
@ -404,25 +426,29 @@ WriteLn("A"#13#10"B");
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
arr := array(10, 20, 30); items := array(10, 20, 30);
hash := array("Code": "0001", "Price": 12.3); row := array("Code": "0001", "Price": 12.3);
s := "ABC"; s := "ABC";
WriteLn("ARR0=", arr[0]); WriteLn(items[0]);
WriteLn("ARR1=", arr[1]); WriteLn(items[1]);
WriteLn("HASH=", hash["Code"]); WriteLn(row["Code"]);
WriteLn("STR1=", s[1]); WriteLn(s[1]);
WriteLn("STR2=", s[2]); WriteLn(s[2]);
WriteLn("STR3=", s[3]); WriteLn(s[3]);
``` ```
已验证运行结果对应关系: 代码块身份:已验证输出片段
- `arr[0] = 10` ```text
- `arr[1] = 20` 10
- `hash["Code"] = "0001"` 20
- `s[1] = "A"` 0001
- `s[2] = "B"` A
- `s[3] = "C"` B
C
```
代码块说明:顺序数组 `items``0` 开始,字符串键表 `row` 用字符串键访问,字符串 `s``1` 开始。
二进制缓冲区: 二进制缓冲区:
@ -456,10 +482,13 @@ s := "ABCDE";
WriteLn(s[2:4]); WriteLn(s[2:4]);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 输出 `BCD` ```text
- 这说明字符串区间 `2:4` 会包含结束位 `4` BCD
```
代码块说明:字符串区间 `2:4` 会包含结束位 `4`
字符串替换子串: 字符串替换子串:
@ -540,6 +569,12 @@ WriteLn(s[0]);
上面这类写法在运行时会报字符串下标越界。 上面这类写法在运行时会报字符串下标越界。
代码块身份:已验证输出片段
```text
String index out of bounds
```
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写
```text ```text

View File

@ -14,6 +14,15 @@
回答“普通变量怎样直接使用、`var` 在什么位置出现、常量有哪些基本写法、哪些名字一旦绑定就不能再赋值”。 回答“普通变量怎样直接使用、`var` 在什么位置出现、常量有哪些基本写法、哪些名字一旦绑定就不能再赋值”。
## Agent 变量/常量判断流程
1. 普通变量默认直接用 `:=` 首次赋值,不要先补一个没有需求证据的 `var` 段。
2. 只有用户要求显式声明或遇到 `{$Explicit+}` 时才优先写 `var`
3. 顶层脚本常量优先用 `const name := value;`;需要后续脚本语句时,仍按 `.tsl` 语句区规则组织。
4. `const Name = value;` 优先放在函数 `const` 段、`unit` 接口或类成员里;不要和顶层 `const :=` 任意互换。
5. 多参数赋值按 `[a, b] := array(...)` 写;单变量拆包必须写成 `[name, ] := array(...)`
6. 没有已验证代码块时不要发明变量/常量写法;尤其不要从 Pascal 的声明习惯反推 TSL 必须先声明变量。
## 必须记住的规则 ## 必须记住的规则
- 默认变量模型是“直接赋值即得到变量”,不要求先写 `var` - 默认变量模型是“直接赋值即得到变量”,不要求先写 `var`
@ -41,6 +50,15 @@
```tsl ```tsl
a := 1; a := 1;
b := array(1, 2, 3); b := array(1, 2, 3);
WriteLn(a);
WriteLn(b[1]);
```
代码块身份:已验证输出片段
```text
1
2
``` ```
显式 `var` 写法: 显式 `var` 写法:
@ -66,6 +84,12 @@ begin
end. end.
``` ```
代码块身份:已验证输出片段
```text
1
```
顶层最稳的常量写法: 顶层最稳的常量写法:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -83,6 +107,12 @@ const value := 1 + 2 * 3;
WriteLn(value); WriteLn(value);
``` ```
代码块身份:已验证输出片段
```text
7
```
函数内部 `const` 段: 函数内部 `const` 段:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -148,9 +178,12 @@ WriteLn(r1);
WriteLn(r2); WriteLn(r2);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 依次输出 `1`、`3` ```text
1
3
```
单变量拆包时,末尾逗号不能省略: 单变量拆包时,末尾逗号不能省略:
@ -161,9 +194,11 @@ WriteLn(r2);
WriteLn(re); WriteLn(re);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 输出 `1` ```text
1
```
左侧变量比右侧数组更长时,多出的变量为 `nil` 左侧变量比右侧数组更长时,多出的变量为 `nil`
@ -175,10 +210,12 @@ WriteLn(r1);
WriteLn(r2 = nil); WriteLn(r2 = nil);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `r1` 输出 `1` ```text
- `r2 = nil` 输出 `1` 1
1
```
右侧元素也可以是数组: 右侧元素也可以是数组:
@ -293,6 +330,12 @@ end.
上面这类写法在当前解释器里会编译失败,主因是 `variable not defined` 上面这类写法在当前解释器里会编译失败,主因是 `variable not defined`
代码块身份:已验证输出片段
```text
variable not defined
```
## 跳转指引 ## 跳转指引
- 回看基本类型:见 [04_values_and_literals.md](04_values_and_literals.md) - 回看基本类型:见 [04_values_and_literals.md](04_values_and_literals.md)

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;` - 最稳妥的函数骨架仍然是 `function Name(...); begin ... end;`
- 不需要返回值时,可以改用 `procedure 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(...)` 返回的函数指针,都不要默认写成直调。 - 当前解释器没有通过 `f(...)` 这种“函数变量直接调用”写法;无论 `f` 是匿名函数、`FindFunction(...)` 还是 `ThisFunction(...)` 返回的函数指针,都不要默认写成直调。
- 当前解释器接受 `::FuncName(...)` 指向全局/系统函数,用来绕过当前作用域里的同名局部函数。 - 当前解释器接受 `::FuncName(...)` 指向全局/系统函数,用来绕过当前作用域里的同名局部函数。
- `external`、`MakeInstance` 和线程调用统一移到 [21_external_calls_and_threads.md](21_external_calls_and_threads.md)。 - `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. end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `Bump(a)` 后输出 `2` ```text
2
```
### 签名增强 ### 签名增强
@ -316,10 +349,7 @@ end.
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
function NamedArgsDemo(); WriteLn(Pack(a: 1, b: 2));
begin
return Pack(a: 1, b: 2);
end;
function Pack(a, b); function Pack(a, b);
begin begin
@ -327,7 +357,13 @@ begin
end; end;
``` ```
已验证运行结果: 代码块身份:已验证输出片段
```text
12
```
已验证补充:
- `Pack(a: 1, b: 2)` 返回 `12` - `Pack(a: 1, b: 2)` 返回 `12`
- `Pack(b: 2, a: 1)` 返回 `12` - `Pack(b: 2, a: 1)` 返回 `12`
@ -820,12 +856,25 @@ end.
## 最小可编译示例 ## 最小可编译示例
如果你只是要写一个能被 session 稳定续写的函数 / 过程,从下面任一骨架起步 如果你只是要写一个能被 agent 稳定续写的 `.tsl` 脚本,从语句区起步,需要函数时把声明区放在后面
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
Hello();
function Hello(); function Hello();
begin
echo "hello";
end;
```
如果你要写 `.tsf` 模块/函数扩展,从下面任一骨架起步:
代码块身份:已验证可执行示例
```tsl
function HelloValue();
begin begin
return 1; return 1;
end; end;
@ -841,7 +890,7 @@ end;
## 常见误写 ## 常见误写
- 把顶层函数定义和松散语句混写 - `.tsl` 的声明区后面继续写脚本语句
- 以为函数头后的分号是当前解释器的硬性要求。 - 以为函数头后的分号是当前解释器的硬性要求。
- 以为 `procedure` 只是 `function` 的别名,不涉及参数传递语义。 - 以为 `procedure` 只是 `function` 的别名,不涉及参数传递语义。
- 带类型注解时仍然用逗号分隔参数。 - 带类型注解时仍然用逗号分隔参数。
@ -857,15 +906,24 @@ end;
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写
```text ```text
a := 1;
Add(1, 2);
function Add(a, b); function Add(a, b);
begin begin
return a + b; return a + b;
end; end;
value := Add(1, 2); echo "after function";
``` ```
上面这种混写方式会编译失败,问题不在 `Add` 本身,而在于文件模型混了“函数定义体”和“松散语句”两种写法。 上面的问题不在 `Add` 本身,而在于 `.tsl` 的函数声明区后面又继续出现脚本语句。正确做法是把会执行的语句全部放在声明区之前。
代码块身份:已验证输出片段
```text
invalid statement
```
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写
@ -884,7 +942,7 @@ end;
Pack(a = 1, b = 2) Pack(a = 1, b = 2)
``` ```
这类写法不要当成命名参数。它虽然可能编译通过,但在我于 `2026-04-09` 的实测里返回结果不对,不能当成可靠的命名参数语法。 这类写法不要当成命名参数。它虽然可能编译通过,但当前已验证返回结果不对,不能当成可靠的命名参数语法。
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写

View File

@ -8,31 +8,42 @@
手册位置:第 7 篇,共 32 篇。上一篇:[06_functions_and_calls.md](06_functions_and_calls.md)。下一篇:[08_control_flow.md](08_control_flow.md)。 手册位置:第 7 篇,共 32 篇。上一篇:[06_functions_and_calls.md](06_functions_and_calls.md)。下一篇:[08_control_flow.md](08_control_flow.md)。
这一篇集中放语言级表达式与运算符,避免与业务计算示例混用 这一篇集中放语言级表达式与运算符。agent 写代码时,只能从本页已验证代码块归纳表达式写法,不要把其他语言或外部资料里的运算符习惯直接搬进 TSL
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“赋值、比较、条件求值、可空访问和一部分新表达式在 TSL 里怎样写”。 回答“赋值、比较、条件求值、表达式对象、空安全访问和链式比较在 TSL 里怎样写”。
## Agent 表达式/运算符判断流程
1. 先判断要写赋值、比较、条件求值、表达式对象、空安全访问还是链式比较。
2. 普通赋值只能用 `:=`,不要把 `=` 当赋值写法。
3. 比较才用 `=`,并且把比较表达式放在 `WriteLn(...)`、条件或其他需要布尔值的位置。
4. 已有变量做复合运算时,才使用 `+=`、`-=`、`*=`、`/=`、`%=`、`a++;`、`a--;`。
5. 条件求值优先用 `flag ? true_value : false_value`;需要 Pascal 风格时可用 `if condition then true_value else false_value` 的形态,但必须带 `else`
6. 需要延迟求值或动态表达式对象时,才使用 `@expr``&"..."`,并用已验证的 `eval(...)` 形态求值。
7. 空安全访问只照本页已验证形态写:`a?.member`、`a?.[index]`、以及已验证的 `c?.a?.[1]`。不要外推成任意深度、任意组合都可写。
8. 需要连续比较时,标量用 `:<` / `:>` 这组链式比较;数组逐元素比较用 `::<` / `::>` 这组矩阵链式比较。
9. 没有已验证代码块时不要发明表达式/运算符写法。
## 必须记住的规则 ## 必须记住的规则
- 当前页只收已经单独验证过的基础表达式,不把未经逐条验证的扩展运算体系一次并进正文。 - 当前页只收已经单独验证过的基础表达式,不把未经逐条验证的扩展运算体系一次并进正文。
- 赋值使用 `:=` - 普通赋值使用 `:=`
- 当前解释器接受 `+=`、`-=`、`*=`、`/=`、`%=` 这几种基础运算赋值。 - 已验证支持 `+=`、`-=`、`*=`、`/=`、`%=` 这几种基础运算赋值。
- 当前解释器接受语句级 `a++;``a--;` - 已验证支持语句级 `a++;``a--;`
- `=` 用于比较,不用于赋值。 - `=` 用于比较,不用于赋值。
- 当前解释器接受字符串 `+` 拼接、字符串比较和 `like` 正则匹配。 - 已验证支持字符串 `+` 拼接、字符串比较和 `like` 正则匹配。
- 当前解释器同时接受 `flag ? true_value : false_value``if condition then true_value else false_value` 这两种条件求值写法。 - 已验证支持 `flag ? true_value : false_value``if condition then true_value else false_value` 这两种条件求值写法。
- 当前解释器接受 `@expr` 把后面的内容声明成表达式对象。 - 已验证支持 `@expr` 把后面的内容声明成表达式对象。
- 当前解释器接受 `&"..."` 把字符串编译成表达式对象。 - 已验证支持 `&"..."` 把字符串编译成表达式对象。
- 当前解释器接受逗号表达式 `(exp1, exp2, ..., expN)`,并按从左到右顺序求值。 - 已验证支持逗号表达式 `(exp1, exp2, ..., expN)`,并按从左到右顺序求值。
- 当前解释器接受空安全访问 `a?.member``a?.[index]` - 已验证支持空安全访问 `a?.member`、`a?.[index]` 和本页示例里的 `c?.a?.[1]`
- 当前解释器接受 `not in`、`not like`、`not sqlin`、`not is` 这几种否定形式运算。 - 已验证支持 `not in`、`not like`、`not sqlin`、`not is` 这几种否定形式运算。
- 当前解释器接受标量链式比较 `:>`、`:<`、`:<>`、`:==`、`:>=`、`:<=`。 - 已验证支持标量链式比较 `:>`、`:<`、`:<>`、`:==`、`:>=`、`:<=`。
- 当前解释器接受矩阵链式比较 `::>`、`::<`、`::<>`、`::==`、`::>=`、`::<=`。 - 已验证支持矩阵链式比较 `::>`、`::<`、`::<>`、`::==`、`::>=`、`::<=`。
- 当前环境里 `{$IFDEF ifexp}` 为真,可用于探测 `if ... then ... else ...` 表达式能力。 - `{$IFDEF ifexp}` 可用于探测 `if ... then ... else ...` 表达式能力。
- 当前环境里 `{$IFDEF nilinvoke}` 为真,可用于探测 nil 调用相关能力。 - `{$IFDEF nilinvoke}` 可用于探测 nil 调用相关能力。
- 不要把外部资料里的更深链式可空访问修正,直接当成当前解释器必然支持。
## 已验证语法 ## 已验证语法
@ -45,6 +56,13 @@ a := 1;
b := 2; b := 2;
flag := a < b; flag := a < b;
value := flag ? 10 : 20; value := flag ? 10 : 20;
WriteLn(value);
```
代码块身份:已验证输出片段
```text
10
``` ```
运算赋值: 运算赋值:
@ -57,35 +75,36 @@ a += 2;
WriteLn(a); WriteLn(a);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 输出 `3` ```text
3
```
基础算术复合赋值: 基础算术复合赋值:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
program test; a := 10;
begin a -= 3;
a := 10; WriteLn(a);
a -= 3; a *= 4;
WriteLn(a); WriteLn(a);
a *= 4; a /= 7;
WriteLn(a); WriteLn(a);
a /= 7; a %= 5;
WriteLn(a); WriteLn(a);
a %= 5;
WriteLn(a);
end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `a -= 3` 后输出 `7` ```text
- `a *= 4` 后输出 `28` 7
- `a /= 7` 后输出 `4` 28
- `a %= 5` 后输出 `4` 4
4
```
字符串同样支持 `+=` 字符串同样支持 `+=`
@ -97,49 +116,57 @@ s += "B";
WriteLn(s); WriteLn(s);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 输出 `AB` ```text
AB
```
字符串拼接、比较和 `like` 字符串拼接、比较和 `like`
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
program test; WriteLn("222" + "888");
begin WriteLn("A" < "a");
WriteLn("222" + "888"); WriteLn("AB" < "ABC");
WriteLn("A" < "a"); WriteLn("ABC" = "ABC");
WriteLn("AB" < "ABC"); WriteLn("2009-01-01" like "\\d{4}-\\d{2}-\\d{2}");
WriteLn("ABC" = "ABC");
WriteLn("2009-01-01" like "\\d{4}-\\d{2}-\\d{2}");
end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 依次输出 `222888`、`1`、`1`、`1`、`1` ```text
- 说明字符串可以直接用 `+` 拼接 222888
- 说明字符串比较区分字符序和大小写;当前例子里 `"A" < "a"` 为真 1
- 说明当前 `like` 的右侧可以直接写正则模式 1
1
1
```
说明:
- 字符串可以直接用 `+` 拼接。
- 字符串比较区分字符序和大小写;当前例子里 `"A" < "a"` 为真。
- `like` 的右侧可以直接写正则模式。
`like` 不要按 SQL `%` 通配去理解: `like` 不要按 SQL `%` 通配去理解:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
program test; WriteLn("abc" like "a.*");
begin WriteLn("abc" like "a%");
WriteLn("abc" like "a.*");
WriteLn("abc" like "a%");
end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 第一行输出 `1` ```text
- 第二行输出 `0` 1
- 因此当前解释器里的 `like` 更接近“正则匹配”,不是 SQL 那套 `%` / `_` 通配语义 0
```
因此 `like` 更接近“正则匹配”,不是 SQL 那套 `%` / `_` 通配语义。
自增与自减: 自增与自减:
@ -153,25 +180,30 @@ a--;
WriteLn(a); WriteLn(a);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 先输出 `2` ```text
- 再输出 `1` 2
1
```
`if` 表达式: `if` 表达式:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
program test; WriteLn(if 2 > 1 then 2 else 1);
begin
WriteLn(if 2 > 1 then 2 else 1);
end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `if 2 > 1 then 2 else 1` 返回 `2` ```text
2
```
`if condition then true_value else false_value` 必须带 `else`,否则不是本页可照写的表达式形态。
### 表达式对象
`@` 表达式前导: `@` 表达式前导:
@ -184,10 +216,13 @@ C := eval(B);
WriteLn(C); WriteLn(C);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 输出 `2` ```text
- 说明 `@A + 1` 会得到一个可交给 `eval(...)` 求值的表达式对象 2
```
`@A + 1` 会得到一个可交给 `eval(...)` 求值的表达式对象。
`&"..."` 表达式常量: `&"..."` 表达式常量:
@ -200,10 +235,13 @@ C := eval(B);
WriteLn(C); WriteLn(C);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 输出 `2` ```text
- 说明 `&"A + 1"` 会把字符串编译成表达式对象,再由 `eval(...)` 求值 2
```
`&"A + 1"` 会把字符串编译成表达式对象,再由 `eval(...)` 求值。
逗号表达式: 逗号表达式:
@ -220,10 +258,13 @@ begin
end. end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 输出 `6` ```text
- 说明逗号表达式会按从左到右顺序执行前面的赋值,再返回最后一个表达式结果 6
```
逗号表达式会按从左到右顺序执行前面的赋值,再返回最后一个表达式结果。
逗号表达式也可以继续参与外层计算: 逗号表达式也可以继续参与外层计算:
@ -234,10 +275,13 @@ A := (b := 2, c := 3, b * c) * c;
WriteLn(A); WriteLn(A);
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- 输出 `18` ```text
- 说明逗号表达式本身可以作为一个普通子表达式继续参与后续运算 18
```
逗号表达式本身可以作为一个普通子表达式继续参与后续运算。
### 空安全访问 ### 空安全访问
@ -259,11 +303,30 @@ begin
end. end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `a?.value = nil` 输出 `1` ```text
- `h?.value` 输出 `7` 1
- `arr?.[0] = nil` 输出 `1` 7
1
```
更深一层的混合空安全访问,本页只确认下面这个形态:
代码块身份:已验证可执行示例
```tsl
c := nil;
WriteLn(c?.a?.[1] = nil);
```
代码块身份:已验证输出片段
```text
1
```
不要从这一段外推任意深度、任意成员/下标混合都可写。
### 否定形式运算 ### 否定形式运算
@ -284,86 +347,92 @@ begin
end. end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `1 not in array(2, 3)` 输出 `1` ```text
- `"2009-1-1" not like "\\d{4}-\\d{2}-\\d{2}"` 输出 `1` 1
- `1 not sqlin array(2, 3)` 输出 `1` 1
- `obj not is class(B)` 输出 `1` 1
1
```
### 标量链式比较 ### 标量链式比较
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
program test; WriteLn(1 :< 2 :< 3);
begin WriteLn(3 :> 2 :> 1);
WriteLn(1 :< 2 :< 3); WriteLn(1 :== 1 :== 1);
WriteLn(3 :> 2 :> 1); WriteLn(3 :>= 2 :>= 2);
WriteLn(1 :== 1 :== 1); WriteLn(1 :<= 2 :<= 3);
WriteLn(3 :>= 2 :>= 2); WriteLn(1 :<> 2 :<> 3);
WriteLn(1 :<= 2 :<= 3);
WriteLn(1 :<> 2 :<> 3);
end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `1 :< 2 :< 3` 输出 `1` ```text
- `3 :> 2 :> 1` 输出 `1` 1
- `1 :== 1 :== 1` 输出 `1` 1
- `3 :>= 2 :>= 2` 输出 `1` 1
- `1 :<= 2 :<= 3` 输出 `1` 1
- `1 :<> 2 :<> 3` 输出 `1` 1
1
```
### 矩阵链式比较 ### 矩阵链式比较
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
program test; r := array(1, 2, -1) ::< array(2, 1, 0) ::< array(3, 2, 1);
begin WriteLn(r[0]);
r := array(1, 2, -1) ::< array(2, 1, 0) ::< array(3, 2, 1); WriteLn(r[1]);
WriteLn(r[0]); WriteLn(r[2]);
WriteLn(r[1]); s := array(1, 2, -1) ::< 2 ::< array(3, 2, 1);
WriteLn(r[2]); WriteLn(s[0]);
s := array(1, 2, -1) ::< 2 ::< array(3, 2, 1); WriteLn(s[1]);
WriteLn(s[0]); WriteLn(s[2]);
WriteLn(s[1]);
WriteLn(s[2]);
end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `array(1, 2, -1) ::< array(2, 1, 0) ::< array(3, 2, 1)` 的三个元素依次输出 `1`、`0`、`1` ```text
- `array(1, 2, -1) ::< 2 ::< array(3, 2, 1)` 的三个元素依次输出 `1`、`0`、`0` 1
- 说明矩阵链式比较会按元素位置分别得到结果数组,并且可以和标量混用 0
1
1
0
0
```
矩阵链式比较会按元素位置分别得到结果数组,并且可以和标量混用。
### 条件编译探测 ### 条件编译探测
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
```tsl ```tsl
program test;
begin
{$IFDEF ifexp} {$IFDEF ifexp}
WriteLn(1); WriteLn(1);
{$ELSE} {$ELSE}
WriteLn(0); WriteLn(0);
{$ENDIF} {$ENDIF}
{$IFDEF nilinvoke} {$IFDEF nilinvoke}
WriteLn(1); WriteLn(1);
{$ELSE} {$ELSE}
WriteLn(0); WriteLn(0);
{$ENDIF} {$ENDIF}
end.
``` ```
已验证运行结果: 代码块身份:已验证输出片段
- `{$IFDEF ifexp}` 输出 `1` ```text
- `{$IFDEF nilinvoke}` 输出 `1` 1
1
```
这只能作为能力探测示例使用agent 不要把条件编译探测写成普通业务逻辑。
## 最小可编译示例 ## 最小可编译示例
@ -374,13 +443,20 @@ end.
```tsl ```tsl
flag := 1 < 2; flag := 1 < 2;
value := flag ? 10 : 20; value := flag ? 10 : 20;
WriteLn(value);
```
代码块身份:已验证输出片段
```text
10
``` ```
## 常见误写 ## 常见误写
- 用 `=` 当赋值运算符。 - 用 `=` 当赋值运算符。
- 把 `if` 表达式写成没有 `else` 的半句。 - 把 `if` 表达式写成没有 `else` 的半句。
- 把更深链式可空访问 `c?.a?.[1]` 直接当成当前解释器已支持事实。 - 把已验证的 `c?.a?.[1]` 外推成所有深链式空安全访问都可靠
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写
@ -388,6 +464,12 @@ value := flag ? 10 : 20;
a = 1; a = 1;
``` ```
代码块身份:已验证输出片段
```text
invalid statement
```
上面这种写法会编译失败,因为单独的 `=` 在这里会被当成不成立的表达式。 上面这种写法会编译失败,因为单独的 `=` 在这里会被当成不成立的表达式。
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写
@ -396,16 +478,13 @@ a = 1;
v := if 2 > 1 then 2; v := if 2 > 1 then 2;
``` ```
上面这种写法也会编译失败;`if` 表达式当前必须带 `else` 代码块身份:已验证输出片段
代码块身份:反例 / 不可照写
```text ```text
c := nil; invalid statement
WriteLn(c?.a?.[1] = nil);
``` ```
上面这种更深的混合可空访问,在当前已记录验证里没有通过,不要提前把后续版本的修正结果写进结论 上面这种写法也会编译失败;`if` 表达式必须带 `else`
## 跳转指引 ## 跳转指引

View File

@ -14,6 +14,14 @@
回答“`if`、`case`、`for`、`while`、`repeat`、`break`、`continue`、`try`、`raise` 这些流程结构在 TSL 里到底怎么写,哪些写法已经被当前解释器实测验证过”。 回答“`if`、`case`、`for`、`while`、`repeat`、`break`、`continue`、`try`、`raise` 这些流程结构在 TSL 里到底怎么写,哪些写法已经被当前解释器实测验证过”。
## Agent 控制流判断流程
1. 先判断任务需要条件分支、循环、`case`、异常处理还是调试跳转。
2. `if` / `for` / `while` / `repeat` 优先照本页已验证骨架写,不要套用其他 Pascal 方言。
3. 需要多条语句时再补 `begin ... end`,不要在 `else` 前提前加分号。
4. `case` 表达式和 `case` 语句分开判断;`@case` 不作为默认主写法。
5. 没有已验证代码块时不要发明控制流写法。
## 必须记住的规则 ## 必须记住的规则
- `if ... then ... else ...` 可以直接跟单条语句;需要多条语句时再补 `begin ... end` - `if ... then ... else ...` 可以直接跟单条语句;需要多条语句时再补 `begin ... end`
@ -78,6 +86,12 @@ WriteLn(s);
- 输出 `9` - 输出 `9`
代码块身份:已验证输出片段
```text
9
```
`step``downto` 递减循环: `step``downto` 递减循环:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -365,7 +379,7 @@ end;
WriteLn(b); WriteLn(b);
``` ```
我在 `2026-04-13` 用当前解释器实测,上面这类最小例子输出的是 `<STREXP>`,不能把它当成普通 `case` 表达式的可靠主语法写进新 session 默认生成结果。 当前已验证结果显示,上面这类最小例子输出的是 `<STREXP>`,不能把它当成普通 `case` 表达式的可靠主语法写进新 session 默认生成结果。
## 跳转指引 ## 跳转指引

View File

@ -16,6 +16,14 @@
本页后半段有少量依赖 `unit` 的双文件示例;如果你还没建立 `unit` / `uses` 的多文件心智模型,先看 [10_units_and_scope.md](10_units_and_scope.md)。 本页后半段有少量依赖 `unit` 的双文件示例;如果你还没建立 `unit` / `uses` 的多文件心智模型,先看 [10_units_and_scope.md](10_units_and_scope.md)。
## Agent 对象/类判断流程
1. 先判断要写普通对象、继承、构造函数、类方法、静态字段还是运行时创建。
2. 对象声明优先使用本页已验证的 `type Name = class ... end;` 骨架。
3. 类方法和静态字段优先用 `class(Name).Member` 或已验证反射入口,不要裸写类名调用。
4. 构造函数默认保持 `public create`,不要把 `private` / `protected create` 当成会自动执行的构造函数。
5. 没有已验证代码块时不要发明对象/类写法。
## 必须记住的规则 ## 必须记住的规则
- 类定义统一按 `type Name = class ... end;` 写。 - 类定义统一按 `type Name = class ... end;` 写。
@ -49,7 +57,7 @@
- 工厂式 `self(0)` / `self(1)` 已验证可用;当前解释器没有通过 `self()` 这种无参工厂式写法。 - 工厂式 `self(0)` / `self(1)` 已验证可用;当前解释器没有通过 `self()` 这种无参工厂式写法。
- 已做双文件运行验证:如果类定义在 `unit` 的嵌套路径里,可以用 `CreateObject("Unit1.Class1.Class2")` 这种字符串路径创建对象。 - 已做双文件运行验证:如果类定义在 `unit` 的嵌套路径里,可以用 `CreateObject("Unit1.Class1.Class2")` 这种字符串路径创建对象。
- 已做双文件运行验证:可以写 `type MyNewClass = class(Unit1.Class1.Class2)` 直接继承单元里的嵌套类路径。 - 已做双文件运行验证:可以写 `type MyNewClass = class(Unit1.Class1.Class2)` 直接继承单元里的嵌套类路径。
- 当前环境里 `{$IFDEF ParentClassInUnit}` 为真,可用于探测“继承和构造单元中的类”能力是否可用。 - 已验证 `{$IFDEF ParentClassInUnit}` 为真,可用于探测“继承和构造单元中的类”能力是否可用。
- `private` / `protected` / `public` 已验证可用;类开头未写可见性时,成员默认按 `public` 处理。 - `private` / `protected` / `public` 已验证可用;类开头未写可见性时,成员默认按 `public` 处理。
- 同一个可见性段里后续没有切换关键字的成员,会沿用前一个可见性。 - 同一个可见性段里后续没有切换关键字的成员,会沿用前一个可见性。
- 外部访问 `private` / `protected` 字段或方法,会在执行时报对象成员访问错误。 - 外部访问 `private` / `protected` 字段或方法,会在执行时报对象成员访问错误。
@ -109,6 +117,12 @@ end;
- 说明在当前解释器里,顶层类声明可以放在松散语句之后 - 说明在当前解释器里,顶层类声明可以放在松散语句之后
- 同时也说明 `CreateObject("MyClass")` 可以解析到后面才出现的类声明 - 同时也说明 `CreateObject("MyClass")` 可以解析到后面才出现的类声明
代码块身份:已验证输出片段
```text
5
```
顶层函数后面也可以继续声明类: 顶层函数后面也可以继续声明类:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -1234,7 +1248,7 @@ end.
已验证运行结果: 已验证运行结果:
- 当前环境里 `{$IFDEF ParentClassInUnit}` 输出 `1` - `{$IFDEF ParentClassInUnit}` 输出 `1`
## 最小可编译示例 ## 最小可编译示例

View File

@ -20,6 +20,14 @@
- 多个 `unit` 里有同名接口时,未限定调用到底命中谁 - 多个 `unit` 里有同名接口时,未限定调用到底命中谁
- 怎样显式指定要调用哪个 `unit` 的接口 - 怎样显式指定要调用哪个 `unit` 的接口
## Agent unit/作用域判断流程
1. 先判断当前交付是 `.tsl` 可执行脚本、`.tsf` 扩展模块,还是 `unit` 文件。
2. `unit` 文件只描述可复用单元;脚本入口仍放在 `.tsl`
3. `uses` 必须放在普通语句之前;普通语句后不要再追加顶层 `uses`
4. 默认参数、接口段、实现段和作用域边界只照本页已验证形态写。
5. 没有已验证代码块时不要发明 unit/作用域写法。
## 必须记住的规则 ## 必须记住的规则
- `unit` 是完整的顶层主体;常见完整形态是 `unit Name; interface ... implementation ... end.` - `unit` 是完整的顶层主体;常见完整形态是 `unit Name; interface ... implementation ... end.`
@ -58,6 +66,14 @@ end.
- 上面这就是当前解释器可通过的最小完整 `unit` 骨架。 - 上面这就是当前解释器可通过的最小完整 `unit` 骨架。
- `unit` 文件结尾要用 `end.`,不是普通函数或类的 `end;` - `unit` 文件结尾要用 `end.`,不是普通函数或类的 `end;`
如果该 `unit` 被脚本 `uses DemoUnit;` 后调用 `WriteLn(Ping());`,可观察输出为:
代码块身份:已验证输出片段
```text
1
```
### 简写 `unit` ### 简写 `unit`
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“`SetSysParam` / `GetSysParam` 怎样用、`SysParams[...]` 是什么、`#Func() with array(...)` 这种后缀环境调用在当前解释器里怎样写”。 回答“`SetSysParam` / `GetSysParam` 怎样用、`SysParams[...]` 是什么、`#Func() with array(...)` 这种后缀环境调用在当前解释器里怎样写”。
## Agent 运行时上下文判断流程
1. 先判断要操作系统参数、运行时上下文对象,还是 `with` 后缀调用。
2. 系统参数优先用本页已验证的 `SetSysParam` / `GetSysParam` / `SysParams[...]` 形态。
3. `#Func() with array(...)` 只作为运行时环境调用写法,不要套到普通本地函数。
4. 本地函数后缀 `with` 属于反例时不要照写。
5. 没有已验证代码块时不要发明运行时上下文写法。
## 必须记住的规则 ## 必须记住的规则
- TSL 有一组运行时系统参数;当前页只写已经实际验证过的通用写法。 - TSL 有一组运行时系统参数;当前页只写已经实际验证过的通用写法。
@ -45,6 +53,13 @@ end.
- 依次输出 `123`、`XYZ` - 依次输出 `123`、`XYZ`
代码块身份:已验证输出片段
```text
123
XYZ
```
`SysParams[...]` 直接读写: `SysParams[...]` 直接读写:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“哪些写法最容易凭直觉写出来,但在 TSL 里会编译失败、运行出错,或语义并不可靠”。 回答“哪些写法最容易凭直觉写出来,但在 TSL 里会编译失败、运行出错,或语义并不可靠”。
## Agent 常见误写判断流程
1. 先识别用户写法属于值、变量、函数、表达式、对象、unit、TS-SQL 还是外部调用误区。
2. 遇到本页反例时,不要修成相邻语言习惯,必须跳回对应语法页找已验证正例。
3. 反例只用于排错和避免误写,不作为可照写模板。
4. 修复时保留 `.tsl` / `.tsf` 文件模型判断,不要只改局部语句。
5. 没有已验证代码块时不要发明替代语法。
## 这页怎么用 ## 这页怎么用
- 先按主题扫一遍,再回到对应正文看正确写法。 - 先按主题扫一遍,再回到对应正文看正确写法。
@ -43,6 +51,12 @@ end;
a = 1; a = 1;
``` ```
代码块身份:已验证输出片段
```text
invalid statement
```
这会编译失败。正确页:见 [07_expressions_and_operators.md](07_expressions_and_operators.md) 这会编译失败。正确页:见 [07_expressions_and_operators.md](07_expressions_and_operators.md)
#### 3. 把字符串当成 0 基下标 #### 3. 把字符串当成 0 基下标
@ -89,20 +103,23 @@ WriteLn(Length(s));
这不要按 C 风格字符串去理解。当前解释器里这里输出 `3`,说明 `#0` 仍是字符串内容的一部分。正确页:见 [04_values_and_literals.md](04_values_and_literals.md) 这不要按 C 风格字符串去理解。当前解释器里这里输出 `3`,说明 `#0` 仍是字符串内容的一部分。正确页:见 [04_values_and_literals.md](04_values_and_literals.md)
#### 7. 把顶层函数定义和松散语句混写 #### 7. `.tsl` 声明区后面继续写脚本语句
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写
```text ```text
function Add(a, b); a := 1;
test();
function test();
begin begin
return a + b; echo "test";
end; end;
value := Add(1, 2); echo "after declaration";
``` ```
这会编译失败。正确页:见 [03_core_model.md](03_core_model.md) `.tsl` 可以有语句区和声明区,但顺序必须清楚:语句区在前并按顺序执行,函数/类声明区在后。不要在声明区后面继续写脚本语句。正确页:见 [03_core_model.md](03_core_model.md)
#### 8. 顶层单独写 `const Name = value;` #### 8. 顶层单独写 `const Name = value;`

View File

@ -14,6 +14,14 @@
回答“`array(...)` 在 TSL 里除了最普通的一维数组,还能怎样组织数据;哪些矩阵样写法已经稳定验证过”。 回答“`array(...)` 在 TSL 里除了最普通的一维数组,还能怎样组织数据;哪些矩阵样写法已经稳定验证过”。
## Agent 矩阵/集合判断流程
1. 先判断需要顺序数组、字符串键表、嵌套数组,还是矩阵样比较。
2. 普通集合优先从 `array(...)` 起手;下标和键访问回看值语法页。
3. 矩阵链式比较只照 `::` 系列已验证示例写,不要混用标量链式比较。
4. 集合过滤或 TS-SQL 查询需求跳转到结果集/TS-SQL 页面。
5. 没有已验证代码块时不要发明矩阵/集合写法。
## 必须记住的规则 ## 必须记住的规则
- `array(...)` 既可以写顺序数组,也可以写字符串键表。 - `array(...)` 既可以写顺序数组,也可以写字符串键表。
@ -42,6 +50,15 @@ WriteLn("HASH=", hash["Code"]);
- `arr[1] = 20` - `arr[1] = 20`
- `hash["Code"] = "0001"` - `hash["Code"] = "0001"`
代码块身份:已验证输出片段
```text
1
2
3
4
```
嵌套数组: 嵌套数组:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -12,7 +12,15 @@
## 这一篇解决什么问题 ## 这一篇解决什么问题
回答“我已经有一个数组或二维结果集,想按某个过滤集保留命中的行、排除命中的行,或者只拿到符合条件的行下标时,应该怎么写”。 回答“已有数组或二维结果集时,想按某个过滤集保留命中的行、排除命中的行,或者只拿到符合条件的行下标时,应该怎么写”。
## Agent 结果集/过滤判断流程
1. 先判断任务是普通数组过滤、结果集字段访问,还是 TS-SQL 查询。
2. 字段访问优先照本页已验证的字符串键或结果集字段形态写。
3. 复杂查询需求优先跳转到 TS-SQL 页面,不要把业务过滤硬塞进基础表达式。
4. 金融业务筛选要回到 finance 层确认上下文。
5. 没有已验证代码块时不要发明结果集/过滤写法。
## 必须记住的规则 ## 必须记住的规则
@ -53,6 +61,15 @@ end.
- `FilterIn(R, CodeArr, "Code")` 返回两行:`0001`、`0003` - `FilterIn(R, CodeArr, "Code")` 返回两行:`0001`、`0003`
- `FilterNotIn(R, CodeArr, "Code")` 返回两行:`0002`、`0004` - `FilterNotIn(R, CodeArr, "Code")` 返回两行:`0002`、`0004`
代码块身份:已验证输出片段
```text
0001
0003
0002
0004
```
### 返回行下标 ### 返回行下标
第四个参数写成 `false` 时,返回行下标而不是子结果集: 第四个参数写成 `false` 时,返回行下标而不是子结果集:

View File

@ -14,6 +14,14 @@
回答“第一次进入 TS-SQL 时,应该先记住哪些固定骨架,怎样区分基础查询和高级查询,以及哪些内容属于语法、哪些已经属于业务层数据访问”。 回答“第一次进入 TS-SQL 时,应该先记住哪些固定骨架,怎样区分基础查询和高级查询,以及哪些内容属于语法、哪些已经属于业务层数据访问”。
## Agent TS-SQL 判断流程
1. 先判断是 TS-SQL 总览、核心查询,还是进阶查询。
2. 第一次落代码优先跳转到 `28_ts_sql_core.md` 的最小 `select ... from ... end` 骨架。
3. 需要 join、分组上下文或极值引用时再进入 `29_ts_sql_advanced.md`
4. 不要把 SQL 数据库语法直接当作 TS-SQL 语法。
5. 没有已验证代码块时不要发明 TS-SQL 写法。
## 必须记住的规则 ## 必须记住的规则
- TS-SQL 是 TSL 自带的类 SQL 查询语法,不是金融业务函数库。 - TS-SQL 是 TSL 自带的类 SQL 查询语法,不是金融业务函数库。
@ -38,6 +46,7 @@ begin
("A": 2, "B": 1) ("A": 2, "B": 1)
); );
R := select * from T end; R := select * from T end;
WriteLn(Length(R));
end. end.
``` ```
@ -47,6 +56,12 @@ end.
- 两行依次是 `(1,3)`、`(2,1)` - 两行依次是 `(1,3)`、`(2,1)`
- 说明 TS-SQL 的最短可靠入口就是“准备结果集,然后 `select ... from T end` - 说明 TS-SQL 的最短可靠入口就是“准备结果集,然后 `select ... from T end`
代码块身份:已验证输出片段
```text
2
```
### 四个查询入口怎样分工 ### 四个查询入口怎样分工
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“`goto`、`DebugReturn`、`DebugRunEnv`、`MTIC` / `MTOC`、`SetProfiler`、`__line__` 和 `__stack_frame` 在当前解释器里怎样写、会怎样表现”。 回答“`goto`、`DebugReturn`、`DebugRunEnv`、`MTIC` / `MTOC`、`SetProfiler`、`__line__` 和 `__stack_frame` 在当前解释器里怎样写、会怎样表现”。
## Agent 调试/Profiler 判断流程
1. 先判断任务需要跳转、提前返回、运行环境调试、计时还是 profiler。
2. 普通控制流优先回到 `08_control_flow.md`,本页只处理调试补充工具。
3. `DebugReturn` 会结束整段脚本,不能当成普通函数返回。
4. 计时和 profiler 只照已验证最小调用写,不要补未验证参数。
5. 没有已验证代码块时不要发明调试/Profiler 写法。
## 必须记住的规则 ## 必须记住的规则
- `goto label_name;` 当前已验证可用,但目标位置当前以 `label label_name; statement` 这种内联形式最稳。 - `goto label_name;` 当前已验证可用,但目标位置当前以 `label label_name; statement` 这种内联形式最稳。

View File

@ -14,6 +14,14 @@
回答“TSL 的词法层规则和编译期开关应该去哪里查,而不是把这些边界混进值、函数、类的正文里”。 回答“TSL 的词法层规则和编译期开关应该去哪里查,而不是把这些边界混进值、函数、类的正文里”。
## Agent 词法/编译选项判断流程
1. 先判断要写注释、标识符、条件编译,还是编译选项。
2. 注释、大小写、条件编译指令只照本页已验证形态写。
3. `{$Explicit+}` 会改变变量声明要求,生成代码前先判断是否需要 `var`
4. `{$VarByRef+}` / `{$VarByRef-}` 会影响未修饰形参传递语义,细节回看函数页。
5. 没有已验证代码块时不要发明词法/编译选项写法。
## 必须记住的规则 ## 必须记住的规则
- 标识符大小写无关;当前最小运行验证里,下划线也可以出现在标识符中。 - 标识符大小写无关;当前最小运行验证里,下划线也可以出现在标识符中。
@ -47,6 +55,13 @@ end.
- 说明当前解释器下标识符大小写无关 - 说明当前解释器下标识符大小写无关
- 也说明下划线可以出现在标识符中 - 也说明下划线可以出现在标识符中
代码块身份:已验证输出片段
```text
7
7
```
注释与条件编译: 注释与条件编译:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“当问题不再是怎么写字面量,而是变量在运行时会变成什么类型、怎样转换、怎样受编译选项影响时,应该看哪里”。 回答“当问题不再是怎么写字面量,而是变量在运行时会变成什么类型、怎样转换、怎样受编译选项影响时,应该看哪里”。
## Agent 类型/转换判断流程
1. 先判断要写数值字面量、日期时间、真假值、nil还是类型转换边界。
2. 整数、实数、日期时间和特殊实数只照本页已验证字面量写。
3. 不要把能编译的混合类型表达式误判为能按预期自动转换。
4. 遇到字符串细节跳转到 `20_strings_and_text.md`,遇到值基础跳转到 `04_values_and_literals.md`
5. 没有已验证代码块时不要发明类型/转换写法。
## 必须记住的规则 ## 必须记住的规则
- 当前解释器接受十进制、`0x` 十六进制、`0b` 二进制、`0o` 八进制整数常量。 - 当前解释器接受十进制、`0x` 十六进制、`0b` 二进制、`0o` 八进制整数常量。
@ -65,6 +73,14 @@ end.
- 说明 `100L` 在当前解释器里按 `Int64` 处理 - 说明 `100L` 在当前解释器里按 `Int64` 处理
- 也说明 `1E2` 当前按实数,不按整数处理 - 也说明 `1E2` 当前按实数,不按整数处理
代码块身份:已验证输出片段
```text
1
0
1
```
超 32 位整数与日期时间字面量: 超 32 位整数与日期时间字面量:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“当任务进入字符串和编码细节,而不是只写普通字面量时,应该进入哪一篇”。 回答“当任务进入字符串和编码细节,而不是只写普通字面量时,应该进入哪一篇”。
## Agent 字符串/文本判断流程
1. 先判断要写普通字符串、宽串/UTF8 前缀、原始字符串,还是字符串边界行为。
2. 默认优先普通字符串;只有编码或宽串需求明确时才使用 `L""` / `U""`
3. 字符串索引、切片、转义和 `#0` 行为只照已验证示例写。
4. 字符串表达式行为回看表达式页,不要在文本页发明运算规则。
5. 没有已验证代码块时不要发明字符串/文本写法。
## 必须记住的规则 ## 必须记住的规则
- 普通字符串、`L""` 宽串、`U""` UTF8 前缀串,以及 `%%` 原始字符串,当前解释器都接受。 - 普通字符串、`L""` 宽串、`U""` UTF8 前缀串,以及 `%%` 原始字符串,当前解释器都接受。
@ -56,6 +64,15 @@ end.
- 说明 `%%tag ...%%tag` 可以用标识符配对 - 说明 `%%tag ...%%tag` 可以用标识符配对
- 也说明 `%%` 原始字符串支持直接跨行 - 也说明 `%%` 原始字符串支持直接跨行
代码块身份:已验证输出片段
```text
ABC
A"B'C
A
B
```
带前缀的原始字符串: 带前缀的原始字符串:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“普通函数怎么写已经清楚后,外部 DLL、函数指针、多线程这些系统交互能力应该去哪里查”。 回答“普通函数怎么写已经清楚后,外部 DLL、函数指针、多线程这些系统交互能力应该去哪里查”。
## Agent 外部调用/线程判断流程
1. 先判断要声明外部函数、绑定函数指针,还是处理线程相关能力。
2. 外部函数声明只照已验证的调用约定、`external` 和可选 `name` 形态写。
3. DLL 名优先写字面量或已验证类常量,不要拼接表达式。
4. 函数指针包装和线程相关能力只照本页已验证边界写。
5. 没有已验证代码块时不要发明外部调用/线程写法。
## 必须记住的规则 ## 必须记住的规则
- 当前解释器接受 `function Name(...): Type; stdcall|cdecl; external "dll" [name "symbol"];` 这类外部函数声明。 - 当前解释器接受 `function Name(...): Type; stdcall|cdecl; external "dll" [name "symbol"];` 这类外部函数声明。
@ -24,6 +32,7 @@
- 当前已验证的 DLL 名写法包括字面量字符串和类常量字符串;不要把字符串拼接表达式直接当成稳定写法。 - 当前已验证的 DLL 名写法包括字面量字符串和类常量字符串;不要把字符串拼接表达式直接当成稳定写法。
- `MakeInstance(ThisFunction(Func), "cdecl", 0)` 当前可以把 TSL 函数包装成 C 调用约定函数指针。 - `MakeInstance(ThisFunction(Func), "cdecl", 0)` 当前可以把 TSL 函数包装成 C 调用约定函数指针。
- `MakeInstance(..., "cdecl", 1)` 当前在 `Win64` 下已经拿到最小线程正例,可以直接交给 `CreateThread` - `MakeInstance(..., "cdecl", 1)` 当前在 `Win64` 下已经拿到最小线程正例,可以直接交给 `CreateThread`
- 外部库名和调用约定要按目标平台选择;不要把 Windows 的 `kernel32.dll` 示例直接复制到 Linux或把 Linux 的 `.so` 示例直接复制到 Windows。
- 当前页的线程示例是 Windows 专题,用到了 `kernel32.dll` - 当前页的线程示例是 Windows 专题,用到了 `kernel32.dll`
## 已验证语法 ## 已验证语法
@ -46,6 +55,32 @@ end.
- 说明当前解释器接受 `stdcall` + `external "dll" name "symbol"` 这类外部函数声明骨架 - 说明当前解释器接受 `stdcall` + `external "dll" name "symbol"` 这类外部函数声明骨架
- 也说明 TSL 里的函数名可以和 DLL 导出名不同,再通过 `name "ExportName"` 绑定 - 也说明 TSL 里的函数名可以和 DLL 导出名不同,再通过 `name "ExportName"` 绑定
代码块身份:已验证输出片段
```text
1
```
Linux / POSIX 环境的同类最小骨架:
代码块身份:已验证可执行示例
```tsl
program test;
function getpid(): integer; cdecl; external "libc.so.6";
begin
WriteLn(getpid() > 0);
end.
```
代码块身份:已验证输出片段
```text
1
```
这段只说明 Linux / POSIX 目标下可以用 `.so` 库名声明外部函数;生成代码时仍要先判断用户的目标平台。
当本地函数名和 DLL 导出名一致时,`name` 可以省略: 当本地函数名和 DLL 导出名一致时,`name` 可以省略:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -21,6 +21,14 @@
- `NameSpace "..."`、`tsl.conf` 和 `-LIBPATH` 怎样影响 `.tsf` 查找 - `NameSpace "..."`、`tsl.conf` 和 `-LIBPATH` 怎样影响 `.tsf` 查找
- `syssettsllibpath()` / `sysgettsllibpath()` 怎样在运行时改查找路径 - `syssettsllibpath()` / `sysgettsllibpath()` 怎样在运行时改查找路径
## Agent 命名空间/Libpath 判断流程
1. 先判断任务是单元命名空间访问、`-LIBPATH` 查找,还是配置文件查找。
2. 路径和查找顺序只写平台中立规则,不写某个开发机或容器路径。
3. `-LIBPATH` 只作为运行时部署/查找规则,不写进普通语法示例。
4. 未验证的路径替换和父目录继承不要当成稳定规则。
5. 没有已验证代码块时不要发明命名空间/Libpath 写法。
## 必须记住的规则 ## 必须记住的规则
- 完整 `unit` 形态可以包含 `interface`、`implementation`、`initialization`、`finalization`,并以 `end.` 结束。 - 完整 `unit` 形态可以包含 `interface`、`implementation`、`initialization`、`finalization`,并以 `end.` 结束。
@ -86,6 +94,18 @@ end.
- 这说明顶层写了 `uses DemoUnit;` 之后,`initialization` 不是立刻执行,而是在第一次真正读 `DemoUnit` 成员时触发。 - 这说明顶层写了 `uses DemoUnit;` 之后,`initialization` 不是立刻执行,而是在第一次真正读 `DemoUnit` 成员时触发。
- `finalization` 在脚本主体输出结束后触发。 - `finalization` 在脚本主体输出结束后触发。
代码块身份:已验证输出片段
```text
BEFORE
INIT
7
1
101
11
FINAL
```
### `unit` 成员的读取边界 ### `unit` 成员的读取边界
直接限定读取: 直接限定读取:

View File

@ -14,6 +14,14 @@
回答“类已经会声明、继承、构造之后,怎样检查类信息、函数信息和对象运行时状态”。 回答“类已经会声明、继承、构造之后,怎样检查类信息、函数信息和对象运行时状态”。
## Agent 对象运行时/反射判断流程
1. 先判断要做类查找、函数查找、对象检查,还是运行时成员访问。
2. 反射入口优先照 `FindClass`、`FindFunction` 等已验证示例写。
3. 对象模型本身回看 `09_objects_and_classes.md`,不要在运行时页发明类声明语法。
4. 函数值调用边界回看函数页,避免把函数指针直接当普通函数调用。
5. 没有已验证代码块时不要发明对象运行时/反射写法。
## 必须记住的规则 ## 必须记住的规则
- 对象值当前可以用 `ifObj(...)` 做显式判定。 - 对象值当前可以用 `ifObj(...)` 做显式判定。
@ -52,6 +60,12 @@ end.
- 输出 `1` - 输出 `1`
- 说明 `CreateObject(...)` 得到的对象值当前可以用 `ifObj(...)` 判定 - 说明 `CreateObject(...)` 得到的对象值当前可以用 `ifObj(...)` 判定
代码块身份:已验证输出片段
```text
1
```
`FindClass(...)` 与类类型变量: `FindClass(...)` 与类类型变量:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“写普通 TSL/TSF 脚本时,哪些内置对象可以直接创建,最小可用接口是什么,哪些对象其实依赖特定运行上下文”。 回答“写普通 TSL/TSF 脚本时,哪些内置对象可以直接创建,最小可用接口是什么,哪些对象其实依赖特定运行上下文”。
## Agent 内置运行时对象判断流程
1. 先判断要访问哪个内置运行时对象,以及它是不是语言对象而非业务 API。
2. 只照本页已验证的最小读写路径使用内置对象。
3. 不要把金融业务上下文对象和语言运行时对象混在一起。
4. 需要系统参数或 `with` 后缀时跳转到运行时上下文页。
5. 没有已验证代码块时不要发明内置运行时对象写法。
## 必须记住的规则 ## 必须记住的规则
- 当前 CLI 里,`TStringList` 已验证可以直接 `CreateObject("TStringList")` 创建。 - 当前 CLI 里,`TStringList` 已验证可以直接 `CreateObject("TStringList")` 创建。
@ -50,6 +58,15 @@ end.
- 依次输出 `B=bbb`、`bbb`、`3`、`4` - 依次输出 `B=bbb`、`bbb`、`3`、`4`
- 说明当前既可以按数字下标取整行,也可以按键名取 `Name=Value` 里的值 - 说明当前既可以按数字下标取整行,也可以按键名取 `Name=Value` 里的值
代码块身份:已验证输出片段
```text
B=bbb
bbb
3
4
```
### `TStream` 家族的最小可靠入口:`TMemoryStream` ### `TStream` 家族的最小可靠入口:`TMemoryStream`
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“某个元素是否在数组里、某组元素是否构成子集、某一行是否存在于结果集中,以及两个结果集如何做并集、交集、差集和对称差集”。 回答“某个元素是否在数组里、某组元素是否构成子集、某一行是否存在于结果集中,以及两个结果集如何做并集、交集、差集和对称差集”。
## Agent 集合运算判断流程
1. 先判断要写 `in`、`sqlin`、否定集合判断,还是结果集集合操作。
2. 基础成员判断优先照表达式页和本页已验证示例写。
3. `not in``not sqlin` 是已验证否定写法,不要改成未验证组合。
4. 复杂查询或矩阵数据跳转到 TS-SQL / 矩阵页面。
5. 没有已验证代码块时不要发明集合运算写法。
## 必须记住的规则 ## 必须记住的规则
- `in` / `not in` 处理的是元素存在关系,以及左侧为数组时的子集关系。 - `in` / `not in` 处理的是元素存在关系,以及左侧为数组时的子集关系。
@ -54,6 +62,15 @@ end.
- `array(1, 2) in array(1)` 输出 `0` - `array(1, 2) in array(1)` 输出 `0`
- `1 not in array(0, 2)` 输出 `1` - `1 not in array(0, 2)` 输出 `1`
代码块身份:已验证输出片段
```text
1
0
1
1
```
### `sqlin``not sqlin` ### `sqlin``not sqlin`
`sqlin` 改成按整行判断左侧是否存在于右侧结果集中: `sqlin` 改成按整行判断左侧是否存在于右侧结果集中:

View File

@ -14,6 +14,14 @@
回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,以及怎样拿到矩阵的行数、列数、行索引和列索引”。 回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,以及怎样拿到矩阵的行数、列数、行索引和列索引”。
## Agent 矩阵深水判断流程
1. 先判断要读矩阵尺寸、列索引、矩阵选择,还是矩阵与数组转换。
2. 基础数组和矩阵样比较先回看 `13_matrix_and_collections.md`
3. `MRows` / `MCols` / `MSize` 等函数只照已验证返回形态写。
4. 不要把列索引数组误当成单个数字。
5. 没有已验证代码块时不要发明矩阵深水写法。
## 必须记住的规则 ## 必须记住的规则
- `Zeros(...)`、`Ones(...)`、`Rand(...)`、`Nils(...)`、`Eye(...)` 都可以直接用于矩阵初始化。 - `Zeros(...)`、`Ones(...)`、`Rand(...)`、`Nils(...)`、`Eye(...)` 都可以直接用于矩阵初始化。
@ -42,6 +50,9 @@ begin
E1 := Eye(3); E1 := Eye(3);
R1 := Rand(2, 3); R1 := Rand(2, 3);
T1 := Zeros(2, array("A", "B")); T1 := Zeros(2, array("A", "B"));
WriteLn(Length(Z1));
WriteLn(MRows(Z2));
WriteLn(MCols(Z2));
end. end.
``` ```
@ -55,6 +66,14 @@ end.
- `Rand(2, 3)` 的行数是 `2`、列数是 `3` - `Rand(2, 3)` 的行数是 `2`、列数是 `3`
- `Zeros(2, array("A", "B"))` 的行数是 `2`、列数是 `2`,并且 `T1[0]["A"]`、`T1[0]["B"]`、`T1[1]["A"]`、`T1[1]["B"]` 都是 `0` - `Zeros(2, array("A", "B"))` 的行数是 `2`、列数是 `2`,并且 `T1[0]["A"]`、`T1[0]["B"]`、`T1[1]["A"]`、`T1[1]["B"]` 都是 `0`
代码块身份:已验证输出片段
```text
3
2
3
```
### `->` 数列数组初始化 ### `->` 数列数组初始化
默认步长为 `1` 默认步长为 `1`

View File

@ -14,6 +14,14 @@
回答“什么时候该用 `FMArray` 而不是普通 `array`,以及当前解释器里最可靠的 `FMArray` 写法到底有哪些”。 回答“什么时候该用 `FMArray` 而不是普通 `array`,以及当前解释器里最可靠的 `FMArray` 写法到底有哪些”。
## Agent FMArray 判断流程
1. 先判断是否确实需要 `FMArray`,普通数组能解决时先用普通数组。
2. 构造、类型判断、尺寸读取、转置、连接和 TS-SQL 参与只照本页已验证形态写。
3. `insert`、`delete`、`update` 的收尾形式分别判断,不要互相套用。
4. FMArray 错误边界按本页反例处理,不要凭普通数组经验修写法。
5. 没有已验证代码块时不要发明 FMArray 写法。
## 必须记住的规则 ## 必须记住的规则
- `fmarray[...]` 可以直接构造 `FMArray` 常量。 - `fmarray[...]` 可以直接构造 `FMArray` 常量。
@ -66,6 +74,15 @@ end.
- `f2` 的行数是 `2`、列数是 `2` - `f2` 的行数是 `2`、列数是 `2`
- `f2` 四个单元依次是 `1`、`2`、`3`、`4` - `f2` 四个单元依次是 `1`、`2`、`3`、`4`
代码块身份:已验证输出片段
```text
27
0
1
1
```
### `MInit`、`MInitDiag`、`MRand` ### `MInit`、`MInitDiag`、`MRand`
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -516,7 +533,7 @@ WriteLn(f["A"]);
delete from d where [1] = 4 end; delete from d where [1] = 4 end;
``` ```
这类写法不要直接当成当前默认模板。当前解释器下,我实测 `delete ... end;` 会报 `Statement missing terminator`;已验证可用的是 `delete ...;` 这类写法不要直接当成当前默认模板。当前已验证结果显示,`delete ... end;` 会报 `Statement missing terminator`;已验证可用的是 `delete ...;`
代码块身份:反例 / 不可照写 代码块身份:反例 / 不可照写

View File

@ -14,6 +14,14 @@
回答“第一次写 TS-SQL 时,怎样在不碰 join、数据库表和对象化写回接口的前提下稳定写出最小查询”。 回答“第一次写 TS-SQL 时,怎样在不碰 join、数据库表和对象化写回接口的前提下稳定写出最小查询”。
## Agent TS-SQL Core 判断流程
1. 先判断要写 `select`、`sselect`、`vselect` 还是 `mselect`
2. 内存数组查询优先从 `select ... from T end` 最小骨架起手。
3. 二维结果集字段访问用 `["字段名"]`,一维数组优先用 `ThisRow``ThisRowIndex`
4. join 和进阶聚合跳转到 `29_ts_sql_advanced.md`,不要在核心页发明写法。
5. 没有已验证代码块时不要发明 TS-SQL Core 写法。
## 必须记住的规则 ## 必须记住的规则
- TS-SQL 查询以 `select`、`sselect`、`vselect` 或 `mselect` 开始,以 `end` 结束。 - TS-SQL 查询以 `select`、`sselect`、`vselect` 或 `mselect` 开始,以 `end` 结束。
@ -43,6 +51,7 @@ begin
("A": 1, "B": 2) ("A": 1, "B": 2)
); );
R := select ["A"], ["B"] from T end; R := select ["A"], ["B"] from T end;
WriteLn(Length(R));
end. end.
``` ```
@ -52,6 +61,12 @@ end.
- 三行依次是 `(1,3)`、`(2,1)`、`(1,2)` - 三行依次是 `(1,3)`、`(2,1)`、`(1,2)`
- 说明 `select ["A"], ["B"] from T end` 会按原顺序返回二维结果集 - 说明 `select ["A"], ["B"] from T end` 会按原顺序返回二维结果集
代码块身份:已验证输出片段
```text
3
```
`select *` 也已验证可用: `select *` 也已验证可用:
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例
@ -219,7 +234,7 @@ R := select A from T end;
R := select [0] from X end; R := select [0] from X end;
``` ```
我在 `2026-04-15` 的实测里,这种对一维数组直接用 `[0]` 的写法虽然返回了长度为 `3` 的结果,但取到的值是 `nil`,不能当成可靠入口。对一维数组应改用 `ThisRow``ThisRowIndex` 当前已验证结果显示,这种对一维数组直接用 `[0]` 的写法虽然返回了长度为 `3` 的结果,但取到的值是 `nil`,不能当成可靠入口。对一维数组应改用 `ThisRow``ThisRowIndex`
## 跳转指引 ## 跳转指引

View File

@ -14,6 +14,14 @@
回答“基础 `select` 已经会写以后,怎样继续处理多表联接、分组后组内再查、以及极值对应行的引用值”。 回答“基础 `select` 已经会写以后,怎样继续处理多表联接、分组后组内再查、以及极值对应行的引用值”。
## Agent TS-SQL Advanced 判断流程
1. 先确认核心 `select ... from ... end` 已能表达基础查询,再进入进阶语法。
2. 多表 join、`ThisGroup`、`ThisRowIndex` 和极值引用只照本页已验证示例写。
3. 字段访问和返回形态仍遵守核心 TS-SQL 页规则。
4. 不要把数据库 SQL 方言直接迁移到 TS-SQL。
5. 没有已验证代码块时不要发明 TS-SQL Advanced 写法。
## 必须记住的规则 ## 必须记住的规则
- 多表 `join` 时,字段访问应写成 `[表序号].["字段名"]` - 多表 `join` 时,字段访问应写成 `[表序号].["字段名"]`
@ -44,6 +52,10 @@ begin
R := select [1].["ID"], [1].["V1"], [2].["V2"] R := select [1].["ID"], [1].["V1"], [2].["V2"]
from A join B on [1].["ID"] = [2].["ID"] from A join B on [1].["ID"] = [2].["ID"]
end; end;
WriteLn(Length(R));
WriteLn(R[0]["ID"]);
WriteLn(R[0]["V1"]);
WriteLn(R[0]["V2"]);
end. end.
``` ```
@ -53,6 +65,15 @@ end.
- 唯一一行是 `(1,10,100)` - 唯一一行是 `(1,10,100)`
- 说明当前解释器接受 `from A join B on ...`,并接受 `[1].["字段"]`、`[2].["字段"]` 这种多表字段访问 - 说明当前解释器接受 `from A join B on ...`,并接受 `[1].["字段"]`、`[2].["字段"]` 这种多表字段访问
代码块身份:已验证输出片段
```text
1
1
10
100
```
### `ThisGroup` ### `ThisGroup`
分组后可在组内继续做子查询: 分组后可在组内继续做子查询:

View File

@ -14,6 +14,14 @@
回答“网格调用现在怎样写,全局缓存最稳的读写方式是什么,以及什么时候缓存值会失效或脱离缓存身份”。 回答“网格调用现在怎样写,全局缓存最稳的读写方式是什么,以及什么时候缓存值会失效或脱离缓存身份”。
## Agent 运行时服务/全局缓存判断流程
1. 先判断要用 `#` 网格调用、`timeout` 后缀,还是全局缓存函数。
2. 运行时服务只照本页已验证最小路径写,不要猜测隐藏参数。
3. 全局缓存读写要成对出现,并明确 key/value 生命周期。
4. 普通函数调用回到函数页,不要把运行时服务写成普通语法糖。
5. 没有已验证代码块时不要发明运行时服务/全局缓存写法。
## 必须记住的规则 ## 必须记住的规则
- 网格调用的最小写法是 `r := #Func(args);` - 网格调用的最小写法是 `r := #Func(args);`
@ -48,6 +56,12 @@ end.
- `#AddOne(5)` 可以执行 - `#AddOne(5)` 可以执行
- `dupvalue(r)` 返回最终结果 `6` - `dupvalue(r)` 返回最终结果 `6`
代码块身份:已验证输出片段
```text
6
```
### 网格调用的 `timeout` ### 网格调用的 `timeout`
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“复数现在到底怎样写,弱引用到底有哪些语法真的能用,哪些历史资料里的写法今天不能直接照抄”。 回答“复数现在到底怎样写,弱引用到底有哪些语法真的能用,哪些历史资料里的写法今天不能直接照抄”。
## Agent 复数/弱引用判断流程
1. 先判断任务需要复数,还是弱引用/自动弱引用。
2. 复数字面量和比较只照本页已验证示例写。
3. 访问弱引用前先做 `checkweakref(...)` 判定,不要假设失效弱引用安全返回 nil。
4. 类内 `WeakRef;` / `AutoRef;` 段落式写法属于反例,不要照写。
5. 没有已验证代码块时不要发明复数/弱引用写法。
## 必须记住的规则 ## 必须记住的规则
- 复数字面量可以直接写成 `a + bj`,也可以用 `complex(a, b)` 构造。 - 复数字面量可以直接写成 `a + bj`,也可以用 `complex(a, b)` 构造。
@ -56,6 +64,15 @@ end.
- `imag(4 + 3j)` 返回 `3` - `imag(4 + 3j)` 返回 `3`
- `complex(5, -2)` 打印结果是 `5-2j` - `complex(5, -2)` 打印结果是 `5-2j`
代码块身份:已验证输出片段
```text
41
1
4
3
```
### 共轭、模与等值比较 ### 共轭、模与等值比较
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -14,6 +14,14 @@
回答“当类不只是普通对象,而要直接参与 `obj + x`、`obj[index]`、`for v in obj`、`mrows(obj)` 这类语言级操作时,当前解释器到底支持哪些真实写法”。 回答“当类不只是普通对象,而要直接参与 `obj + x`、`obj[index]`、`for v in obj`、`mrows(obj)` 这类语言级操作时,当前解释器到底支持哪些真实写法”。
## Agent 对象重载/迭代判断流程
1. 先判断要重载二元算符、下标、`for in`,还是矩阵尺寸函数。
2. 对象重载只照本页已验证的 `operator` 签名写,不要从历史资料扩展未知重载。
3. 普通对象模型先回看 `09_objects_and_classes.md`,不要在重载页发明类基础语法。
4. 未列入本页主干的重载族先视为未验证。
5. 没有已验证代码块时不要发明对象重载/迭代写法。
## 必须记住的规则 ## 必须记住的规则
- 对象二元算符重载当前最小可靠形态是成员方法 `function operator + (data);` 这一类写法。 - 对象二元算符重载当前最小可靠形态是成员方法 `function operator + (data);` 这一类写法。
@ -78,6 +86,15 @@ end.
- 说明 `obj + value` 当前可以通过成员 `operator +` 接管 - 说明 `obj + value` 当前可以通过成员 `operator +` 接管
- 说明带 `isLeft` 的比较算符当前可以同时处理 `obj < value``value < obj` - 说明带 `isLeft` 的比较算符当前可以同时处理 `obj < value``value < obj`
代码块身份:已验证输出片段
```text
20
0
1
1
```
### `[]` 重载:`operator[]` / `operator[1]` ### `[]` 重载:`operator[]` / `operator[1]`
代码块身份:已验证可执行示例 代码块身份:已验证可执行示例

View File

@ -6,7 +6,7 @@
是否含已验证反例:否 是否含已验证反例:否
遇到不确定时跳转到:[02_quickstart.md](02_quickstart.md)(优先)、[03_core_model.md](03_core_model.md)、[07_expressions_and_operators.md](07_expressions_and_operators.md)、[09_objects_and_classes.md](09_objects_and_classes.md)、[12_pitfalls.md](12_pitfalls.md) 遇到不确定时跳转到:[02_quickstart.md](02_quickstart.md)(优先)、[03_core_model.md](03_core_model.md)、[07_expressions_and_operators.md](07_expressions_and_operators.md)、[09_objects_and_classes.md](09_objects_and_classes.md)、[12_pitfalls.md](12_pitfalls.md)
这里是 TSL 语法手册入口。只处理“语言怎么写”,不处理金融业务语义。 这里是 TSL 语法手册入口。只处理“agent 应该怎样识别并生成语言写”,不处理金融业务语义。本文档不是人类教程;它给 agent 提供判断顺序、关键词分流和可靠示例入口。
## 元数据读法 ## 元数据读法
@ -20,10 +20,20 @@
## 这本手册怎么读 ## 这本手册怎么读
- 默认先走“按任务跳转”,不要先顺序读完整套。 - 默认先走“Agent 判断流程”和“按任务跳转”,不要先顺序读完整套。
- 只有刻意系统学习时,才按下面的“推荐读法”顺序进入。 - 只有刻意系统学习时,才按下面的“推荐读法”顺序进入。
- 当前这套正式语法手册不再只覆盖主线入门,而是负责完整吸收旧 8 个语言章节。 - 当前这套正式语法手册不再只覆盖主线入门,而是负责完整吸收旧 8 个语言章节。
## Agent 判断流程
1. 先识别用户是否已经给出 `.tsl` / `.tsf` 后缀;给出后缀时,后缀就是判断依据。
2. 未给后缀时,再按交付目标判断:可执行代码对应 `.tsl`,通用模块对应 `.tsf`;仍不明确时向用户确认。
3. 如果是 `.tsl`,按可执行脚本处理:先写语句区,语句按顺序执行;需要函数/类时,把声明区放在语句区之后。
4. 如果是 `.tsf`,按模块/函数扩展处理:生成可部署到解释器 `funcext` 的声明;部署后脚本可以直接调用暴露的顶层函数。
5. 再识别关键词属于值/变量、函数、类、unit、表达式、控制流、运行时、TS-SQL 或其他专题。
6. 只进入关键词命中的最小页面;写代码前优先复制已验证可执行示例的结构,不要从多个页面拼接未经验证的新骨架。
7. 遇到反例、解释器差异或资料冲突时,先按 [12_pitfalls.md](12_pitfalls.md) 和对应专题页收口;仍无结论时不要发明语法。
## 如果你马上要写 TSL ## 如果你马上要写 TSL
1. [02_quickstart.md](02_quickstart.md)(先看语言核心事实速查和最短骨架) 1. [02_quickstart.md](02_quickstart.md)(先看语言核心事实速查和最短骨架)

View File

@ -16,10 +16,22 @@
## TSL 核心约定(不可违反) ## TSL 核心约定(不可违反)
- 文件结构:一文件一顶层声明;文件名 = 声明名;`.tsl` 仅 `function``.tsf` 可 `function/class/unit` - 用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;未给后缀时,再根据用户交付目标判断。
- `.tsl` 是可执行脚本:语句区按顺序执行;如果需要函数/类,放在脚本语句后的函数/类声明区。
- `.tsf` 是模块/函数扩展文件:部署到解释器 `funcext` 后,脚本可直接调用其中暴露的顶层函数。
- 格式4 空格缩进;关键字小写;多语句用 `begin/end` - 格式4 空格缩进;关键字小写;多语句用 `begin/end`
- 命名:类型/函数/property `PascalCase`;变量/参数 `snake_case`;私有 `snake_case_`;常量 `kPascalCase` - 命名:类型/函数/property `PascalCase`;变量/参数 `snake_case`;私有 `snake_case_`;常量 `kPascalCase`
## agent 判断流程
1. 用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据。
2. 用户未给后缀时,先判断交付目标是可执行代码还是通用模块;可执行代码对应 `.tsl`,通用模块对应 `.tsf`
3. 交付目标仍不明确时向用户确认,不要替用户发明文件形态。
4. 写 `.tsl` 时,先生成顺序执行的语句区;调用本脚本内函数时,函数声明写在语句区之后。
5. 写 `.tsf` 时,只生成模块/扩展声明;顶层函数部署到解释器 `funcext` 后才可被脚本直接调用。
6. 如果关键词命中业务、函数库、模块集成或项目执行信息,按 `docs/tsl/index.md` 分流,不把所有问题都当语法问题。
7. 不确定时先找已验证可执行示例、反例页和对应专题页;没有文档结论时不要发明语法,改为向用户确认或记录文档缺口。
## 安全红线(不可触碰) ## 安全红线(不可触碰)
- 不得在代码/日志/注释中写入明文密钥、密码、Token、API Key - 不得在代码/日志/注释中写入明文密钥、密码、Token、API Key

View File

@ -3,12 +3,54 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[1] ROOT = Path(__file__).resolve().parents[1]
RULESET_TSL = ROOT / "rulesets" / "tsl" / "index.md" RULESET_TSL = ROOT / "rulesets" / "tsl" / "index.md"
TSL_INTRODUCTION = ROOT / "docs" / "tsl" / "syntax" / "01_introduction.md"
TSL_QUICKSTART = ROOT / "docs" / "tsl" / "syntax" / "02_quickstart.md"
TSL_CORE_MODEL = ROOT / "docs" / "tsl" / "syntax" / "03_core_model.md"
TSL_VALUES = ROOT / "docs" / "tsl" / "syntax" / "04_values_and_literals.md"
TSL_VARIABLES = ROOT / "docs" / "tsl" / "syntax" / "05_variables_and_constants.md"
TSL_FUNCTIONS = ROOT / "docs" / "tsl" / "syntax" / "06_functions_and_calls.md"
TSL_EXPRESSIONS = ROOT / "docs" / "tsl" / "syntax" / "07_expressions_and_operators.md"
README = ROOT / "README.md" README = ROOT / "README.md"
PLAYBOOK_EXAMPLE = ROOT / "playbook.toml.example" PLAYBOOK_EXAMPLE = ROOT / "playbook.toml.example"
SKILLS_DOC = ROOT / "SKILLS.md" SKILLS_DOC = ROOT / "SKILLS.md"
TEMPLATES_CI_README = ROOT / "templates" / "ci" / "README.md" TEMPLATES_CI_README = ROOT / "templates" / "ci" / "README.md"
TEMPLATES_README = ROOT / "templates" / "README.md" TEMPLATES_README = ROOT / "templates" / "README.md"
REMOVED_TSL_GUIDE = ROOT / "skills" / "tsl-guide" REMOVED_TSL_GUIDE = ROOT / "skills" / "tsl-guide"
TSL_REFERENCE_INDEX = ROOT / "docs" / "tsl" / "reference" / "index.md"
TSL_REFERENCE_CATALOG_INDEX = ROOT / "docs" / "tsl" / "reference" / "catalog" / "index.md"
TSL_REFERENCE_VERIFIED_INDEX = ROOT / "docs" / "tsl" / "reference" / "verified" / "index.md"
TSL_REFERENCE_VERIFIED_CORE = ROOT / "docs" / "tsl" / "reference" / "verified" / "core.md"
TSL_REFERENCE_UNAVAILABLE = ROOT / "docs" / "tsl" / "reference" / "unavailable_methods.md"
TSL_FINANCE_INDEX = ROOT / "docs" / "tsl" / "finance" / "index.md"
TSL_MODULES_INDEX = ROOT / "docs" / "tsl" / "modules" / "index.md"
TSL_REMAINING_SYNTAX_AGENT_SECTIONS = {
"08_control_flow.md": "Agent 控制流判断流程",
"09_objects_and_classes.md": "Agent 对象/类判断流程",
"10_units_and_scope.md": "Agent unit/作用域判断流程",
"11_runtime_context_and_with.md": "Agent 运行时上下文判断流程",
"12_pitfalls.md": "Agent 常见误写判断流程",
"13_matrix_and_collections.md": "Agent 矩阵/集合判断流程",
"14_resultset_and_filters.md": "Agent 结果集/过滤判断流程",
"15_ts_sql.md": "Agent TS-SQL 判断流程",
"16_debug_and_profiler.md": "Agent 调试/Profiler 判断流程",
"18_lexical_structure_and_compile_options.md": "Agent 词法/编译选项判断流程",
"19_types_and_conversions.md": "Agent 类型/转换判断流程",
"20_strings_and_text.md": "Agent 字符串/文本判断流程",
"21_external_calls_and_threads.md": "Agent 外部调用/线程判断流程",
"22_namespace_libpath_and_unit_runtime.md": "Agent 命名空间/Libpath 判断流程",
"23_object_runtime_and_introspection.md": "Agent 对象运行时/反射判断流程",
"24_builtin_runtime_objects.md": "Agent 内置运行时对象判断流程",
"25_set_operations.md": "Agent 集合运算判断流程",
"26_matrix_deep_dive.md": "Agent 矩阵深水判断流程",
"27_fmarray.md": "Agent FMArray 判断流程",
"28_ts_sql_core.md": "Agent TS-SQL Core 判断流程",
"29_ts_sql_advanced.md": "Agent TS-SQL Advanced 判断流程",
"30_runtime_services_and_global_cache.md": "Agent 运行时服务/全局缓存判断流程",
"31_complex_and_weakref.md": "Agent 复数/弱引用判断流程",
"32_object_overloads_and_iteration.md": "Agent 对象重载/迭代判断流程",
}
class TslEntrypointsConsistencyTests(unittest.TestCase): class TslEntrypointsConsistencyTests(unittest.TestCase):
def test_ruleset_lists_canonical_tsl_layers(self): def test_ruleset_lists_canonical_tsl_layers(self):
@ -64,6 +106,512 @@ class TslEntrypointsConsistencyTests(unittest.TestCase):
self.assertNotIn("tsl-guide", SKILLS_DOC.read_text(encoding="utf-8")) self.assertNotIn("tsl-guide", SKILLS_DOC.read_text(encoding="utf-8"))
self.assertNotIn("$tsl-guide", RULESET_TSL.read_text(encoding="utf-8")) self.assertNotIn("$tsl-guide", RULESET_TSL.read_text(encoding="utf-8"))
def test_tsl_ruleset_describes_agent_first_file_model(self):
text = RULESET_TSL.read_text(encoding="utf-8")
self.assertIn("agent 判断流程", text)
self.assertIn("用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据", text)
self.assertIn("`.tsl` 是可执行脚本", text)
self.assertIn("语句区按顺序执行", text)
self.assertIn("函数/类声明区", text)
self.assertIn("`.tsf` 是模块/函数扩展文件", text)
self.assertIn("funcext", text)
self.assertIn("仍不明确时向用户确认", text)
self.assertNotIn("`.tsl` 仅 `function`", text)
self.assertNotIn("脚本优先 `.tsl`,可复用扩展优先 `.tsf`", text)
def test_tsl_syntax_docs_keep_script_then_declarations_model(self):
quickstart = (ROOT / "docs/tsl/syntax/02_quickstart.md").read_text(
encoding="utf-8"
)
core_model = (ROOT / "docs/tsl/syntax/03_core_model.md").read_text(
encoding="utf-8"
)
functions = (ROOT / "docs/tsl/syntax/06_functions_and_calls.md").read_text(
encoding="utf-8"
)
pitfalls = (ROOT / "docs/tsl/syntax/12_pitfalls.md").read_text(
encoding="utf-8"
)
for text in (quickstart, core_model, functions, pitfalls):
self.assertIn("语句区", text)
self.assertIn("声明区", text)
self.assertIn("test();", quickstart)
self.assertIn("function test();", quickstart)
self.assertIn("脚本语句后可以接函数声明", functions)
self.assertIn("不要在声明区后面继续写脚本语句", pitfalls)
self.assertNotIn("不要把顶层函数定义和松散语句混写", quickstart)
self.assertNotIn("不要把顶层函数定义和松散语句混写", core_model)
self.assertNotIn("不要把顶层函数定义和松散语句混在同一个文件模型里", functions)
self.assertIn("后缀就是判断依据", quickstart)
self.assertIn("未给后缀", quickstart)
def test_tsl_agent_entrypoints_do_not_require_runtime_verification(self):
entrypoints = [
RULESET_TSL,
ROOT / "docs/tsl/index.md",
ROOT / "docs/tsl/syntax/index.md",
]
forbidden_phrases = [
"用当前解释器验证",
"本地用 `tsl` 验证",
"用 `tsl` 实测",
"最小实测",
"才写最小 `.tsl` / `.tsf` 例子",
]
for path in entrypoints:
text = path.read_text(encoding="utf-8")
for phrase in forbidden_phrases:
self.assertNotIn(phrase, text, msg=f"{phrase!r} found in {path}")
def test_tsl_index_requires_maintainer_verified_examples_before_publication(self):
text = (ROOT / "docs/tsl/index.md").read_text(encoding="utf-8")
self.assertIn("维护者入文档前验证", text)
self.assertIn("代码库样例", text)
self.assertIn("环境验证通过", text)
self.assertIn("不能写成语法事实", text)
self.assertIn("验证过程不写进语法页", text)
self.assertIn("agent 不需要自行执行验证", text)
def test_tsl_introduction_is_agent_first_decision_model(self):
text = TSL_INTRODUCTION.read_text(encoding="utf-8")
self.assertIn("agent", text)
self.assertIn("后缀就是判断依据", text)
self.assertIn("用户未给后缀", text)
self.assertIn("可执行代码对应 `.tsl`", text)
self.assertIn("通用模块对应 `.tsf`", text)
self.assertIn("`.tsl` 可执行脚本第一印象", text)
self.assertIn("`.tsf` 通用模块第一印象", text)
self.assertIn("不要发明语法", text)
self.assertIn("test();", text)
self.assertIn("function test();", text)
self.assertIn("function Test1();", text)
self.assertNotIn("先看顶层主体", text)
self.assertNotIn("顶层主体优先收敛成四类", text)
def test_tsl_quickstart_is_agent_coding_gate(self):
text = TSL_QUICKSTART.read_text(encoding="utf-8")
self.assertIn("Agent 快速落代码流程", text)
self.assertIn("先看用户有没有指定 `.tsl` / `.tsf` 后缀", text)
self.assertIn("再根据交付目标判断 `.tsl` 或 `.tsf`", text)
self.assertIn("只从 `代码块身份:已验证可执行示例` 的骨架起手", text)
self.assertIn("不要发明语法", text)
self.assertIn("不要在声明区后面继续追加脚本语句", text)
def test_tsl_quickstart_labels_observable_outputs(self):
text = TSL_QUICKSTART.read_text(encoding="utf-8")
self.assertIn("代码块身份:已验证输出片段", text)
self.assertIn("```text\ntest\n```", text)
self.assertIn("```text\n5\n```", text)
self.assertIn("```text\ntest1\n```", text)
self.assertIn("```text\nhello\n```", text)
def test_tsl_quickstart_omits_environment_verification_details(self):
text = TSL_QUICKSTART.read_text(encoding="utf-8")
for phrase in [
"Docker",
"docker exec",
"LD_LIBRARY_PATH",
"/data/workspace",
"U22Cli",
"gitea-runner",
]:
self.assertNotIn(phrase, text)
def test_tsl_core_model_is_agent_file_model_decision_page(self):
text = TSL_CORE_MODEL.read_text(encoding="utf-8")
self.assertIn("Agent 文件模型判断流程", text)
self.assertIn("后缀是第一证据", text)
self.assertIn("可执行交付", text)
self.assertIn("可复用扩展交付", text)
self.assertIn("不要把 `.tsl` 写成只有顶层函数的模块", text)
self.assertIn("不要把 `.tsf` 写成会直接执行脚本语句的入口", text)
self.assertIn("没有文档证据时不要发明文件模型", text)
self.assertNotIn("误以为扩展名本身就完全决定能否写函数、类或 `unit`", text)
def test_tsl_core_model_examples_have_verified_outputs(self):
text = TSL_CORE_MODEL.read_text(encoding="utf-8")
self.assertIn("代码块身份:已验证输出片段", text)
self.assertIn("```text\ntest\n```", text)
self.assertIn("```text\n5\n```", text)
self.assertIn("```text\n1\n```", text)
self.assertIn("```text\ninvalid statement\n```", text)
def test_tsl_core_model_omits_environment_verification_details(self):
text = TSL_CORE_MODEL.read_text(encoding="utf-8")
for phrase in [
"Docker",
"docker exec",
"LD_LIBRARY_PATH",
"/data/workspace",
"U22Cli",
"gitea-runner",
]:
self.assertNotIn(phrase, text)
def test_tsl_values_page_is_agent_value_decision_page(self):
text = TSL_VALUES.read_text(encoding="utf-8")
self.assertIn("Agent 值写法判断流程", text)
self.assertIn("普通值优先从整数、实数、普通字符串、布尔和 `array(...)` 起手", text)
self.assertIn("字符串默认用普通字符串", text)
self.assertIn("`L\"\"` / `U\"\"` 只在编码或宽串场景", text)
self.assertIn("先判断要顺序数组还是字符串键表", text)
self.assertIn("顺序数组和二进制缓冲区下标从 `0` 开始", text)
self.assertIn("字符串下标从 `1` 开始", text)
self.assertIn("没有已验证代码块时不要发明值写法", text)
def test_tsl_values_key_examples_have_verified_output_snippets(self):
text = TSL_VALUES.read_text(encoding="utf-8")
self.assertIn("代码块身份:已验证输出片段", text)
self.assertIn("```text\n1\n12.5\nABC\n1\n0\n2\n```", text)
self.assertIn("```text\n10\n20\n0001\nA\nB\nC\n```", text)
self.assertIn("```text\nBCD\n```", text)
self.assertIn("```text\nString index out of bounds\n```", text)
def test_tsl_values_omits_environment_verification_details(self):
text = TSL_VALUES.read_text(encoding="utf-8")
for phrase in [
"Docker",
"docker exec",
"LD_LIBRARY_PATH",
"/data/workspace",
"U22Cli",
"gitea-runner",
]:
self.assertNotIn(phrase, text)
def test_tsl_variables_page_is_agent_binding_decision_page(self):
text = TSL_VARIABLES.read_text(encoding="utf-8")
self.assertIn("Agent 变量/常量判断流程", text)
self.assertIn("普通变量默认直接用 `:=` 首次赋值", text)
self.assertIn("只有用户要求显式声明或遇到 `{$Explicit+}` 时才优先写 `var`", text)
self.assertIn("顶层脚本常量优先用 `const name := value;`", text)
self.assertIn("`const Name = value;` 优先放在函数 `const` 段、`unit` 接口或类成员里", text)
self.assertIn("单变量拆包必须写成 `[name, ] := array(...)`", text)
self.assertIn("没有已验证代码块时不要发明变量/常量写法", text)
def test_tsl_variables_key_examples_have_verified_output_snippets(self):
text = TSL_VARIABLES.read_text(encoding="utf-8")
self.assertIn("代码块身份:已验证输出片段", text)
self.assertIn("```text\n1\n2\n```", text)
self.assertIn("```text\n7\n```", text)
self.assertIn("```text\n1\n3\n```", text)
self.assertIn("```text\n1\n1\n```", text)
self.assertIn("```text\nvariable not defined\n```", text)
def test_tsl_variables_omits_environment_verification_details(self):
text = TSL_VARIABLES.read_text(encoding="utf-8")
for phrase in [
"Docker",
"docker exec",
"LD_LIBRARY_PATH",
"/data/workspace",
"U22Cli",
"gitea-runner",
]:
self.assertNotIn(phrase, text)
def test_tsl_functions_page_is_agent_function_decision_page(self):
text = TSL_FUNCTIONS.read_text(encoding="utf-8")
self.assertIn("Agent 函数/调用判断流程", text)
self.assertIn("先判断当前文件是 `.tsl` 还是 `.tsf`", text)
self.assertIn("`.tsl` 中先写语句区,再把 `function` / `procedure` 声明放在后面", text)
self.assertIn("需要返回值时用 `function`,不需要返回值时用 `procedure`", text)
self.assertIn("命名参数只写 `name: value`", text)
self.assertIn("不要把 `name = value` 当成命名参数", text)
self.assertIn("没有已验证代码块时不要发明函数/调用写法", text)
self.assertNotIn("在我于", text)
def test_tsl_functions_key_examples_have_verified_output_snippets(self):
text = TSL_FUNCTIONS.read_text(encoding="utf-8")
self.assertIn("代码块身份:已验证输出片段", text)
self.assertIn("```text\ntest\n```", text)
self.assertIn("```text\n2\n```", text)
self.assertIn("```text\n12\n```", text)
self.assertIn("```text\ninvalid statement\n```", text)
def test_tsl_functions_omits_environment_verification_details(self):
text = TSL_FUNCTIONS.read_text(encoding="utf-8")
for phrase in [
"Docker",
"docker exec",
"LD_LIBRARY_PATH",
"/data/workspace",
"U22Cli",
"gitea-runner",
]:
self.assertNotIn(phrase, text)
def test_tsl_expressions_page_is_agent_expression_decision_page(self):
text = TSL_EXPRESSIONS.read_text(encoding="utf-8")
self.assertIn("Agent 表达式/运算符判断流程", text)
self.assertIn("先判断要写赋值、比较、条件求值、表达式对象、空安全访问还是链式比较", text)
self.assertIn("赋值只能用 `:=`", text)
self.assertIn("比较才用 `=`", text)
self.assertIn("条件求值优先用 `flag ? true_value : false_value`", text)
self.assertIn("`if condition then true_value else false_value` 必须带 `else`", text)
self.assertIn("没有已验证代码块时不要发明表达式/运算符写法", text)
self.assertNotIn("当前环境里", text)
def test_tsl_expressions_key_examples_have_verified_output_snippets(self):
text = TSL_EXPRESSIONS.read_text(encoding="utf-8")
self.assertIn("代码块身份:已验证输出片段", text)
self.assertIn("```text\n3\n```", text)
self.assertIn("```text\nAB\n```", text)
self.assertIn("```text\n222888\n1\n1\n1\n1\n```", text)
self.assertIn("```text\n1\n0\n```", text)
self.assertIn("```text\n2\n```", text)
self.assertIn("```text\n6\n```", text)
self.assertIn("```text\n1\n7\n1\n```", text)
self.assertIn("```text\ninvalid statement\n```", text)
def test_tsl_expressions_omits_environment_verification_details(self):
text = TSL_EXPRESSIONS.read_text(encoding="utf-8")
for phrase in [
"Docker",
"docker exec",
"LD_LIBRARY_PATH",
"/data/workspace",
"U22Cli",
"gitea-runner",
]:
self.assertNotIn(phrase, text)
def test_remaining_tsl_syntax_pages_are_agent_decision_pages(self):
syntax_root = ROOT / "docs" / "tsl" / "syntax"
for filename, section in TSL_REMAINING_SYNTAX_AGENT_SECTIONS.items():
with self.subTest(filename=filename):
text = (syntax_root / filename).read_text(encoding="utf-8")
self.assertIn(section, text)
self.assertIn("agent", text.lower())
self.assertIn("不要发明", text)
def test_remaining_tsl_syntax_pages_have_verified_output_snippets(self):
syntax_root = ROOT / "docs" / "tsl" / "syntax"
for filename in TSL_REMAINING_SYNTAX_AGENT_SECTIONS:
with self.subTest(filename=filename):
text = (syntax_root / filename).read_text(encoding="utf-8")
if (
"代码块身份:已验证可执行示例" in text
or "代码块身份:反例 / 不可照写" in text
):
self.assertIn("代码块身份:已验证输出片段", text)
def test_remaining_tsl_syntax_pages_omit_personal_and_environment_details(self):
syntax_root = ROOT / "docs" / "tsl" / "syntax"
forbidden_phrases = [
"我在",
"当前环境里",
"Docker",
"docker exec",
"LD_LIBRARY_PATH",
"/data/workspace",
"U22Cli",
"gitea-runner",
]
for filename in TSL_REMAINING_SYNTAX_AGENT_SECTIONS:
with self.subTest(filename=filename):
text = (syntax_root / filename).read_text(encoding="utf-8")
for phrase in forbidden_phrases:
self.assertNotIn(phrase, text)
def test_tsl_reference_index_requires_verified_function_workflow(self):
text = TSL_REFERENCE_INDEX.read_text(encoding="utf-8")
self.assertIn("Agent 函数使用规则", text)
self.assertIn("只从 verified 函数页读取参数类型", text)
self.assertIn("catalog 只是候选函数索引", text)
self.assertIn("确认每个方法的参数类型", text)
self.assertIn("verified/index.md", text)
self.assertIn("verified/core.md", text)
self.assertIn("unavailable_methods.md", text)
self.assertIn("不能把 catalog 里的函数名直接当成可调用事实", text)
self.assertNotIn("verification_failures", text)
self.assertNotIn("函数入库验证流程", text)
self.assertNotIn("验证过程", text)
self.assertNotIn("代码块身份", text)
self.assertNotIn("已验证输出片段", text)
self.assertNotIn("验证失败", text)
def test_tsl_reference_catalog_is_candidate_index_not_callable_fact(self):
catalog_index = TSL_REFERENCE_CATALOG_INDEX.read_text(encoding="utf-8")
self.assertIn("候选函数索引", catalog_index)
self.assertIn("候选名没有进入 verified 函数页前不能当成可调用事实", catalog_index)
self.assertIn("../verified/index.md", catalog_index)
self.assertIn("../verified/core.md", catalog_index)
self.assertIn("只从 verified 函数页读取参数类型", catalog_index)
self.assertNotIn("错误参数组合", catalog_index)
self.assertNotIn("参数验证", catalog_index)
for path in (ROOT / "docs" / "tsl" / "reference" / "catalog").glob("*.md"):
text = path.read_text(encoding="utf-8")
self.assertIn("候选函数索引", text, msg=f"{path.name} missing candidate warning")
self.assertIn("只从 verified 函数页读取参数类型", text)
def test_tsl_reference_verified_index_routes_to_parameter_fact_pages(self):
text = TSL_REFERENCE_VERIFIED_INDEX.read_text(encoding="utf-8")
self.assertIn("文档类型agent 参数事实索引", text)
self.assertIn("core.md", text)
self.assertIn("Abs", text)
self.assertIn("ifInt", text)
self.assertIn("DateToStr", text)
self.assertIn("Length", text)
self.assertIn("只从具体函数页读取接收类型", text)
self.assertNotIn("验证过程", text)
self.assertNotIn("代码块身份", text)
def test_tsl_reference_verified_core_records_agent_parameter_facts(self):
text = TSL_REFERENCE_VERIFIED_CORE.read_text(encoding="utf-8")
self.assertIn("文档类型agent 参数事实表", text)
self.assertIn("接收类型", text)
self.assertIn("返回", text)
self.assertIn("`Abs(value)`", text)
self.assertIn("`ifInt(value)`", text)
self.assertIn("`DateToStr(value)`", text)
self.assertIn("`Length(value)`", text)
self.assertIn("整数", text)
self.assertIn("实数", text)
self.assertIn("字符串", text)
self.assertIn("数组", text)
self.assertIn("日期时间", text)
self.assertNotIn("代码块身份", text)
self.assertNotIn("已验证输出片段", text)
self.assertNotIn("Function Abs execution error", text)
self.assertNotIn("错误参数", text)
def test_tsl_reference_all_markdown_avoid_verification_logs(self):
for path in (ROOT / "docs" / "tsl" / "reference").rglob("*.md"):
text = path.read_text(encoding="utf-8")
with self.subTest(path=path.relative_to(ROOT)):
self.assertNotIn("验证过程", text)
self.assertNotIn("函数入库验证流程", text)
self.assertNotIn("代码块身份", text)
self.assertNotIn("已验证输出片段", text)
self.assertNotIn("Function Abs execution error", text)
def test_tsl_reference_unavailable_records_only_unavailable_methods(self):
text = TSL_REFERENCE_UNAVAILABLE.read_text(encoding="utf-8")
self.assertIn("文档类型:当前测试环境不支持的方法清单", text)
self.assertIn("当前测试环境不支持的方法", text)
self.assertIn("暂无已入档记录", text)
self.assertNotIn("failure", text.lower())
self.assertNotIn("失败", text)
self.assertNotIn("验证过程", text)
self.assertNotIn("参数类型错误", text)
self.assertNotIn("`Abs(\"-3\")`", text)
self.assertNotIn("`Abs()`", text)
self.assertNotIn("`DateToStr(\"2011-12-31\")`", text)
self.assertNotIn("`DateToStr()`", text)
self.assertNotIn("`Length(123)`", text)
self.assertNotIn("Function Abs execution error", text)
def test_tsl_reference_docs_do_not_name_valid_parameter_mismatches_as_failures(self):
reference_root = ROOT / "docs" / "tsl" / "reference"
for path in reference_root.rglob("*.md"):
text = path.read_text(encoding="utf-8")
with self.subTest(path=path.relative_to(ROOT)):
self.assertNotIn("verification_failures", text)
self.assertNotIn("错误参数", text)
self.assertNotIn("验证失败", text)
self.assertNotIn("Abs(\"-3\")", text)
self.assertNotIn("DateToStr(\"2011-12-31\")", text)
self.assertNotIn("Length(123)", text)
def test_tsl_finance_docs_are_agent_business_decision_pages(self):
finance_root = ROOT / "docs" / "tsl" / "finance"
for path in finance_root.glob("*.md"):
text = path.read_text(encoding="utf-8")
with self.subTest(path=path.name):
self.assertIn("Agent", text)
self.assertIn("不要发明", text)
self.assertIn("项目实际接口", text)
self.assertNotIn("是否含已验证", text)
self.assertNotIn("代码块身份", text)
self.assertNotIn("验证过程", text)
def test_tsl_finance_index_routes_all_finance_pages(self):
text = TSL_FINANCE_INDEX.read_text(encoding="utf-8")
self.assertIn("Agent Finance 路由规则", text)
self.assertIn("entry_decision.md", text)
self.assertIn("market_data_context.md", text)
self.assertIn("series_and_indicator_model.md", text)
self.assertIn("selection_and_signal_patterns.md", text)
self.assertIn("backtest_and_trade_flow.md", text)
def test_tsl_modules_docs_are_agent_integration_boundary_pages(self):
modules_root = ROOT / "docs" / "tsl" / "modules"
for path in modules_root.glob("*.md"):
text = path.read_text(encoding="utf-8")
with self.subTest(path=path.name):
self.assertIn("Agent", text)
self.assertIn("不要发明", text)
self.assertNotIn("是否含已验证", text)
self.assertNotIn("代码块身份", text)
self.assertNotIn("验证过程", text)
def test_tsl_modules_index_routes_all_module_pages(self):
text = TSL_MODULES_INDEX.read_text(encoding="utf-8")
self.assertIn("Agent Modules 路由规则", text)
self.assertIn("tsbacktesting.md", text)
self.assertIn("tsl_python_interop.md", text)
self.assertIn("wechat_message.md", text)
self.assertIn("pytsl_api.md", text)
def test_tsl_finance_and_modules_omit_environment_verification_details(self):
forbidden_phrases = [
"Docker",
"docker exec",
"LD_LIBRARY_PATH",
"/data/workspace",
"U22Cli",
"gitea-runner",
"当前环境里",
"实测",
]
for root_name in ("finance", "modules"):
for path in (ROOT / "docs" / "tsl" / root_name).glob("*.md"):
text = path.read_text(encoding="utf-8")
for phrase in forbidden_phrases:
self.assertNotIn(phrase, text, msg=f"{phrase!r} found in {path}")
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()