✨ feat(tsl-syntax-reference): harden retrieval and restructure pages
- flag weak candidates (no intent/heading/identifier/tag hit) and exit 2 when every candidate is weak: mis-hits used to be indistinguishable from real hits, so the retry-with-better-terms loop never fired - accept multiple ids per --section for batch fetch, failing atomically on any unknown id so a partial fetch cannot pass as complete - move query synonyms and page intent aliases to data/lexicon.json and enforce alias/page correspondence in --check; curation data no longer lives in the engine - document the weak-hit rule, batch fetch and prelude-once guidance in SKILL.md, with curation discipline in data/README.md - drop 11_pitfalls.md, renumber the trailing pages and spread retrieval tags across topics; lexicon keys are page filenames, so the renumbering and the new --check rule cannot land in separate commits
This commit is contained in:
@@ -1,20 +1,27 @@
|
||||
---
|
||||
name: tsl-syntax-reference
|
||||
description: 当用户需要编写、修改、审查或解释 TSL/TSF、TS-SQL、Tinysoft/天软脚本或公式,排查 invalid statement 等语法错误,或核对语言与运行时结构规则时使用。
|
||||
description: 当用户需要编写、修改、审查或解释 TSL/TSF、TS-SQL、Tinysoft/天软脚本或公式,涉及 `.tsl` / `.tsf` 文件,排查 invalid statement 等语法错误,或核对语言与运行时结构规则时使用。
|
||||
---
|
||||
|
||||
# TSL Syntax Reference
|
||||
|
||||
## 唯一检索入口
|
||||
|
||||
本 Skill 只通过随附的 `scripts/lookup.py` 检索 TSL/TSF 语法事实,不手工选择或顺序通读 `references/` 页面。`<this-skill-dir>` 指本 `SKILL.md` 所在目录。
|
||||
输出任何 TSL/TSF 代码、或修改任何 `.tsl` / `.tsf` 文件前,先用随附的
|
||||
`scripts/lookup.py` 取回事实。记忆里的 TSL 写法不构成依据,赋值符号、声明位置和
|
||||
下标起点这类"看起来确定"的规则同样要取回。`<this-skill-dir>` 指本 `SKILL.md`
|
||||
所在目录。
|
||||
|
||||
检索必须分两步:
|
||||
|
||||
1. `--query` 只返回紧凑候选和 Section ID,不返回事实正文。
|
||||
2. 从候选中选择支持当前结论的章节,再用 `--section` 取回唯一事实正文。
|
||||
|
||||
根据任务意图选择模式,并用用户的原始术语、错误文本和关键语法词组成查询:
|
||||
一次 `--query` 只覆盖一个语法要素。一段代码涉及多个要素时(如文件模型、函数
|
||||
骨架、赋值运算符),逐个要素分别执行 `--query`;不用一个要素的取回结果推断另
|
||||
一个要素。各要素选定的 Section ID 可以合并成一次 `--section` 批量取回。
|
||||
|
||||
根据任务意图选择模式:
|
||||
|
||||
```bash
|
||||
python <this-skill-dir>/scripts/lookup.py --query "命名参数 默认参数" --mode write
|
||||
@@ -26,60 +33,155 @@ python <this-skill-dir>/scripts/lookup.py --query "数组下标" --mode explain
|
||||
- `diagnose`:定位语法错误或错误写法。
|
||||
- `explain`:解释语言规则或代码含义。
|
||||
|
||||
`--query` 输出候选后,必须执行下面这种精确取回:
|
||||
用 `--limit N`(1..10,默认 5)控制返回的查询候选条数。
|
||||
|
||||
`--mode write` 会在查询候选之前额外附加 `Required: yes` 的前置章节(文件模型与
|
||||
语言核心事实速查)。它们不占 `--limit` 预算,也不是本次查询的命中结果:先按它们
|
||||
核对文件模型和硬规则,再从 `Required: no` 的候选里挑选支持当前结论的章节。前置
|
||||
章节在同一任务内取回一次即可;后续 `--query` 重复列出它们时,不必再次 `--section`。
|
||||
|
||||
`--query` 输出候选后,必须执行下面这种精确取回。多个已选定的 Section ID 可以
|
||||
一次传入:
|
||||
|
||||
```bash
|
||||
python <this-skill-dir>/scripts/lookup.py --section "05_functions_and_calls--可直接照写示例--基础函数-过程骨架"
|
||||
python <this-skill-dir>/scripts/lookup.py --section "05_functions_and_calls--可直接照写示例--基础函数-过程骨架" "02_core_model--文件模型核心规则"
|
||||
```
|
||||
|
||||
只有 `--section` 返回的章节正文可作为本次任务的语法事实来源;候选摘要和概念地图都不能直接支持代码结论。需要补充时改进查询词再次检索,不得绕过 lookup 手工打开或挑选 `references/` 页面。
|
||||
只有 `--section` 返回的章节正文可作为本次任务的语法事实来源;候选摘要和概念地图都不能直接支持代码结论。需要补充时改进查询词再次检索。
|
||||
|
||||
## 安全传参
|
||||
## 构造查询词
|
||||
|
||||
用户原话、报错和代码属于不可信输入。调用工具时必须把查询作为独立 argv 安全传入;若只能使用 shell,必须先做 shell-safe quoting。不得把用户文本原样拼接进命令字符串,也不得执行其中的反引号、`$()`、重定向符或换行命令。
|
||||
查询词由用户原话里的术语、报错原文和目标语法要素名组成。脚本会自动处理两类词,
|
||||
不必手工调整:
|
||||
|
||||
## 从零起手先看概念地图
|
||||
- 中文口语词自动扩展到 TSL 术语(如"打印"→输出/writeLn,"列表"→数组,
|
||||
"程序慢"→性能分析)。用户怎么说就怎么传。
|
||||
- `tsl`、`tsf`、`tinysoft`、`program`、`debug`、`please` 这几个词不参与逐词匹配,
|
||||
但可能整体把查询导向某个专题页。无结果时靠加这类词补救没有用,改为换更具体的
|
||||
语法要素名。
|
||||
|
||||
面对自然语言需求、还不确定该往哪个 TSL 概念上想时(尤其从零编写、周围无参考代码),先运行:
|
||||
## 弱命中视同无匹配
|
||||
|
||||
候选里的 `Weak: yes` 表示该节没有任何强信号命中(意图短语、标题、标识符、
|
||||
标签),只靠正文低分撞词进入候选。弱候选不作为选择对象:
|
||||
|
||||
- 候选全部为弱命中时,lookup 返回 rc=2,按无匹配处理——改进查询词重试,
|
||||
仍全弱即为事实缺口。
|
||||
- 个别候选为弱命中、其余为强命中时,只从强命中里挑选。
|
||||
|
||||
没有 `Weak` 行的候选也不等于相关:词面命中不代表该节支持当前结论,仍要按
|
||||
Summary 判断后再取回正文核对。
|
||||
|
||||
## 代码块必须标注来源
|
||||
|
||||
给出的每个 TSL/TSF 代码块,紧随其后写一行来源标注,列出所依据的全部 Section ID:
|
||||
|
||||
```txt
|
||||
来源:05_functions_and_calls--可直接照写示例--基础函数-过程骨架(可直接照写示例),02_core_model--文件模型核心规则
|
||||
```
|
||||
|
||||
Section ID 抄自 `--section` 输出首部的 `Section ID:` 行。多个要素合成一个代码块时,
|
||||
逐个列出,逗号分隔。身份按取回的正文分两种写法:
|
||||
|
||||
- 该 Section ID 提供了照写的代码围栏:在 ID 后用括号写出紧邻该围栏的
|
||||
`代码块身份:` 值。
|
||||
- 该 Section ID 只提供散文规则、正文里没有代码围栏(如
|
||||
`02_core_model--文件模型核心规则`):只写 ID,不加括号。规则段落没有身份行,
|
||||
这不是缺口。
|
||||
|
||||
写不出某个要素的 Section ID,说明该要素还没有取回:先补齐检索,再给代码。
|
||||
|
||||
## 代码块身份
|
||||
|
||||
`--section` 正文里每个代码围栏前有一行 `代码块身份:`。身份决定这段代码能否进入
|
||||
你的输出:
|
||||
|
||||
| 身份 | 允许的用法 |
|
||||
| --- | --- |
|
||||
| `可直接照写示例` | 作为源码外形照写,替换业务内容后使用;依赖的 API 仍按事实边界另行核对 |
|
||||
| `反例 / 不可照写` | 只用于说明错误边界,不得作为实现出现在输出里 |
|
||||
| `输出片段` | 只用于说明运行结果,不得当作源码 |
|
||||
| `配置片段 / 概念骨架` | 只用于表达结构或配置意图,不得当作可运行代码 |
|
||||
| `仅服务端可执行示例` | 只在对应服务端环境成立,不得当作通用本地示例 |
|
||||
|
||||
`--query` 的候选摘要不含身份行,身份只能从 `--section` 正文读取。这是必须走完第
|
||||
二步的另一个原因。
|
||||
|
||||
同一个 section 常同时含多种身份(如示例代码后紧跟 `输出片段`)。身份按围栏逐个
|
||||
对应,不按 section 整体判断;一个代码块的依据跨越多种身份时,按最严格的那条处理
|
||||
——只要含 `反例 / 不可照写`,就不能照写。
|
||||
|
||||
## 缺口时停止
|
||||
|
||||
出现下列任一情形,即为事实缺口:
|
||||
|
||||
**检索缺口** —— `--query` 改进查询词后仍无匹配;lookup 返回非零状态;`--section`
|
||||
取回的正文没有支持当前结论;`--section` 正文里目标围栏前没有 `代码块身份:` 行。
|
||||
|
||||
**环境缺口** —— 目标运行时版本不明;项目路径、数据结构或运行参数等项目事实缺失;
|
||||
`tsl-api-reference` 等依赖的 Skill 不可用。
|
||||
|
||||
缺口时的输出由三部分组成,按此顺序:
|
||||
|
||||
1. 已取回并可用的事实,只列 Section ID,不复述正文。
|
||||
2. 缺失的具体要素,以及为它试过的查询词。
|
||||
3. 需要用户提供什么,或需要哪个 Skill、哪份项目文档补齐。
|
||||
|
||||
不输出包含缺口要素的 TSL 代码,注释掉的、标 TODO 的和「仅供参考」的版本同样不
|
||||
输出。一段代码里只要有一个要素没取回,整段都不给出,不交付「其余部分已验证」的
|
||||
半成品。
|
||||
|
||||
不得改为下列任一做法:
|
||||
|
||||
- 手工浏览或顺序通读 `references/` 页面。
|
||||
- 凭记忆、相似语言或猜测产生新的 TSL 写法。
|
||||
- 用候选摘要或概念地图代替章节正文。
|
||||
- 给出未标注来源的代码块。
|
||||
|
||||
## 查询词无从下手时先取概念地图
|
||||
|
||||
若需求只有自然语言、无法从中取出 TSL 概念词或错误文本来构造 `--query`,先运行:
|
||||
|
||||
```bash
|
||||
python <this-skill-dir>/scripts/lookup.py --map
|
||||
```
|
||||
|
||||
它列出全部专题的纯文本职责摘要,用于把需求映射到 TSL 特有概念。地图不含可照写事实;选定概念后仍需依次执行 `--query` 和 `--section`。
|
||||
它列出全部专题的纯文本职责摘要,用于把需求映射到 TSL 特有概念。地图不含可照写事实;从地图取得概念词后,仍按上面的两步执行 `--query` 和 `--section`。
|
||||
|
||||
## 退出码
|
||||
|
||||
| 退出码 | 含义 | 处理方式 |
|
||||
| --- | --- | --- |
|
||||
| 0 | 查询或取回成功 | 读取输出并继续两步流程 |
|
||||
| 1 | `--check` 发现参考页问题,或参考目录内没有可校验的参考页 | 修复参考页,或检查 `--references-dir` 路径与 skill 安装 |
|
||||
| 2 | 参数不合法、`--query` 无匹配或候选全部为弱命中、`--section` ID 不存在 | 见下 |
|
||||
|
||||
`--section` ID 不存在时,脚本会在 stderr 打印最接近的若干 Section ID;从中挑选正确 ID 重试,不要凭猜测拼写 ID。一次传入多个 ID 时只要有一个不存在就不返回任何正文,修正后整批重试。
|
||||
|
||||
`--query` 无匹配或候选全部为 `Weak: yes` 时改进查询词重试。仍无强命中即为事实缺口:按上面「缺口时停止」处理。
|
||||
|
||||
## 事实边界
|
||||
|
||||
本 Skill 只拥有 TSL/TSF 的语言语法、文件模型、表达式、控制流、对象、运行时语言结构和 TS-SQL 外形。先逐项拆分混合请求,再把其他事实交给对应所有者:
|
||||
本 Skill 只拥有 TSL/TSF 的语言语法、文件模型、表达式、控制流、对象、运行时语言
|
||||
结构和 TS-SQL 外形。混合请求先逐项拆分,只回答其中的语法部分。
|
||||
|
||||
- API 名称、签名、参数、返回值、平台 scope、解释器可用性和金融取数事实:使用 `tsl-api-reference` skill。
|
||||
- 命名、代码风格、工具链和模块集成:使用目标仓库相应文档、脚本或 CI。
|
||||
- 项目路径、数据结构、部署方式和运行参数:只使用目标项目的真实文档与配置。
|
||||
API 名称、签名、参数、返回值、平台 scope、解释器可用性和金融取数事实属于
|
||||
`tsl-api-reference` skill。语法示例里可以出现 API 名称来展示调用位置,但这只证明
|
||||
源码外形,不证明该 API 的签名、返回行为、平台 scope 或在目标解释器上可用;需要这
|
||||
些结论时查 API skill,没有事实支持时按「缺口时停止」处理,不把两个 skill 的片段
|
||||
拼成「可运行」结论。
|
||||
|
||||
语法示例可以使用 API 名称帮助展示调用位置,但这只证明源码外形,不证明 API 的签名、返回行为、平台 scope 或目标解释器可用。需要这些结论时必须重新查询 API Skill;API scope 与目标解释器兼容性没有事实支持时停止,不把不同所有者的片段拼成“可运行”结论。
|
||||
## 运行方式不属于本 Skill
|
||||
|
||||
## 代码块身份
|
||||
TSL 的运行方式、解释器路径、平台检测和环境选择都不是本 Skill 的事实。用户询问
|
||||
如何运行 TSL,或需要实际执行 TSL 时,读取目标文件附近最近的 `AGENTS.md`、项目
|
||||
脚本或 CI,并严格照其规定执行。
|
||||
|
||||
生成或判断代码时,必须遵守 lookup 结果中紧邻代码围栏的身份。只允许以下五种身份:
|
||||
|
||||
- `可直接照写示例`:可作为源码外形,但“可直接照写”不等于已经验证目标环境可用,仍需按任务替换业务内容并核对依赖事实。
|
||||
- `反例 / 不可照写`:只用于识别错误边界,不得复制为实现。
|
||||
- `输出片段`:只表示结果,不得当作源码。
|
||||
- `配置片段 / 概念骨架`:只表达结构或配置意图,不得假定为可直接运行代码。
|
||||
- `仅服务端可执行示例`:只在相应服务端运行环境中成立,不得当作通用本地可执行示例。
|
||||
|
||||
## 缺口时停止
|
||||
|
||||
lookup 无匹配或返回非零状态、结果没有支持当前结论、代码块身份缺失或冲突、运行时版本不明、项目事实缺失、依赖的 Skill 不可用时,明确说明缺失项并停止。不得改为手工浏览全部参考页,也不得凭经验、相似语言或猜测产生新的 TSL 写法。
|
||||
|
||||
## 询问或执行运行方式前读取项目指引
|
||||
|
||||
用户询问如何运行 TSL,或需要实际执行 TSL 时,都先读取目标文件附近最近的 `AGENTS.md`、项目脚本或 CI。实际执行前还要完成平台检测并严格使用指定环境;不同平台或多个 Windows 环境不得混用、默认任选或自行回退。
|
||||
本 Skill 只能确认语法外形正确,不能确认代码在目标解释器上可运行。给出未经执行的
|
||||
代码时,据此区分「语法已取回」与「运行时未验证」。
|
||||
|
||||
## 维护校验
|
||||
|
||||
维护本 Skill、参考页或 lookup 实现后必须运行:
|
||||
|
||||
```bash
|
||||
python <this-skill-dir>/scripts/lookup.py --check
|
||||
```
|
||||
改动本 Skill、参考页、`data/` 词表或 lookup 实现后运行 `scripts/lookup.py --check`
|
||||
校验参考页结构与词表覆盖,rc=0 才算通过。口语同义词和页级意图短语维护在
|
||||
`data/lexicon.json`,策展纪律见 `data/README.md`。
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# 检索词表(lexicon.json)
|
||||
|
||||
`lexicon.json` 是 `scripts/lookup.py` 的策展检索数据,与引擎逻辑分离维护。
|
||||
两张表都只影响检索,不是事实正文。
|
||||
|
||||
## query_synonyms —— 口语同义词
|
||||
|
||||
中文口语词 → TSL 术语的展开(如「打印」→ 输出 / writeLn)。策展纪律:
|
||||
|
||||
- 同义词必须落在**目标章节已有的词面**上,否则不产生区分度。用户说的词在
|
||||
参考页正文里出现 0 次时,页级 alias 只能把整页抬起来,页内仍需要词法
|
||||
信号才能选中正确章节——节级词汇桥(如「交集」→ `intersect`)补的就是
|
||||
这一层。
|
||||
- 不要展开成泛化的中文概念词(如「集合运算」会命中别页交叉引用小节标题)。
|
||||
|
||||
## page_intent_aliases —— 页级意图短语
|
||||
|
||||
整句口语短语 → 参考页文件名的路由(命中一条 +80 分,是页级路由的唯一强
|
||||
信号)。约束:
|
||||
|
||||
- 键必须与 `references/` 下的文件名完全一致;每个参考页至少一条短语。
|
||||
键写错或参考页改名后 `_intent_score` 会静默返回 0 分,该页失去自然语言
|
||||
入口——`lookup.py --check` 和回归测试会拦住这两种漂移。
|
||||
|
||||
## 改动后的校验
|
||||
|
||||
```bash
|
||||
python scripts/lookup.py --check
|
||||
python -m unittest test.test_tsl_syntax_lookup_recall # 在仓库根目录运行
|
||||
```
|
||||
|
||||
新增参考页时,除补词表外还须在回归测试里补一条真实问法
|
||||
(`test/test_tsl_syntax_lookup_recall.py` 的 `RECALL_CASES`)。
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"query_synonyms": {
|
||||
"打印": ["输出", "writeLn"],
|
||||
"打出来": ["输出", "writeLn"],
|
||||
"左连接": ["左联接", "left join", "TS-SQL"],
|
||||
"左外连接": ["左联接", "left join", "TS-SQL"],
|
||||
"left outer join": ["left join", "左联接", "TS-SQL"],
|
||||
"列表": ["数组"],
|
||||
"复用文件": ["tsf", "unit"],
|
||||
"多个文件": ["unit", "uses", "作用域"],
|
||||
"跳出去": ["break", "控制流"],
|
||||
"程序慢": ["性能分析", "计时", "profiler"],
|
||||
"瓶颈": ["性能分析", "profiler"],
|
||||
"debug": ["调试", "性能分析"],
|
||||
"program": ["脚本"],
|
||||
"tinysoft": ["天软", "TSL"],
|
||||
"字符串转整数": ["类型转换", "strToInt"],
|
||||
"高性能矩阵": ["FMArray"],
|
||||
"交集": ["intersect"],
|
||||
"并集": ["union2"],
|
||||
"差集": ["minus"],
|
||||
"对称差": ["outersect"],
|
||||
"中括号": ["operator", "下标"],
|
||||
"方括号": ["operator", "下标"],
|
||||
"按引用传": ["varByRef", "var"],
|
||||
"引用传递": ["varByRef", "var"],
|
||||
"计时": ["mtic", "mtoc"]
|
||||
},
|
||||
"page_intent_aliases": {
|
||||
"01_quickstart.md": ["最简单能跑", "最简单的脚本", "天软脚本", "tinysoft"],
|
||||
"02_core_model.md": ["脚本和可复用", "可复用函数文件", "声明函数后面写代码"],
|
||||
"03_values_and_literals.md": ["字符串和数组下标", "下标从几开始", "下标起点"],
|
||||
"04_variables_and_constants.md": ["常量怎么声明", "变量能不能直接赋值"],
|
||||
"05_functions_and_calls.md": ["默认参数", "函数怎么带"],
|
||||
"06_expressions_and_operators.md": ["赋值和相等比较"],
|
||||
"07_control_flow.md": [
|
||||
"跳出去",
|
||||
"循环里满足条件",
|
||||
"跳过这一次",
|
||||
"跳过本次",
|
||||
"捕获异常",
|
||||
"抛异常"
|
||||
],
|
||||
"08_objects_and_classes.md": ["定义类", "创建对象"],
|
||||
"09_units_and_scope.md": ["多个文件", "复用一组函数"],
|
||||
"10_runtime_context_and_with.md": ["临时切换系统参数"],
|
||||
"11_matrix_and_collections.md": ["某行存在", "二维数组怎么判断"],
|
||||
"12_resultset_and_filters.md": ["保留匹配行", "按某一列"],
|
||||
"13_ts_sql.md": ["左连接", "左外连接", "左联接", "数据库", "分组排序", "聚合排序"],
|
||||
"14_debug_and_profiler.md": [
|
||||
"程序慢",
|
||||
"计时找瓶颈",
|
||||
"性能瓶颈",
|
||||
"性能问题",
|
||||
"执行了多久",
|
||||
"执行时间",
|
||||
"耗时",
|
||||
"debug"
|
||||
],
|
||||
"15_lexical_structure_and_compile_options.md": ["变量名区分大小写", "注释怎么写"],
|
||||
"16_types_and_conversions.md": ["字符串转整数", "类型转换"],
|
||||
"17_external_calls_and_threads.md": ["调用 dll", "dll", "动态库", "开线程"],
|
||||
"18_namespace_libpath_and_unit_runtime.md": ["找不到 tsf", "搜索路径"],
|
||||
"19_object_runtime_and_introspection.md": ["查看对象属于哪个类", "运行时对象"],
|
||||
"20_builtin_runtime_objects.md": ["内存流"],
|
||||
"21_matrix_deep_dive.md": ["矩阵求逆", "矩阵转置", "求逆和转置"],
|
||||
"22_fmarray.md": ["高性能矩阵", "fmarray"],
|
||||
"23_object_overloads_and_iteration.md": [
|
||||
"自定义对象支持下标",
|
||||
"中括号",
|
||||
"方括号",
|
||||
"运算符重载",
|
||||
"算符重载",
|
||||
"for in"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,27 @@
|
||||
# TSL 快速落代码规则
|
||||
|
||||
本篇只回答两个落代码前问题:用户已给出 `.tsl` / `.tsf` 后缀时,智能体如何按后缀组织代码;以及生成代码前必须先核对哪些语言硬规则。
|
||||
本篇提供一份单点的语言核心事实速查,以及没有任何复用或模块需求时的默认起手骨架。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
快速回答“任务已经给出后缀或交付目标时,应该选择哪一种可直接照写骨架”,并提供一份单点的语言核心事实速查。
|
||||
|
||||
## 智能体快速落代码流程
|
||||
|
||||
1. 先看用户有没有指定 `.tsl` / `.tsf` 后缀;指定后缀时,后缀就是文件形态判断依据。
|
||||
2. 用户未指定后缀时,再根据交付目标判断 `.tsl` 或 `.tsf`:入口流程、脚本任务或一次性执行逻辑用 `.tsl`;可复用交付物(函数、过程、类、模块或扩展文件)用 `.tsf`;如果只是脚本内部封装函数或类,仍按 `.tsl` 处理。
|
||||
3. 只从 `代码块身份:可直接照写示例` 的骨架起手;遇到 `反例 / 不可照写` 必须避开。
|
||||
4. 写 `.tsl` 时,先写会执行的语句区;需要函数或类时,把声明区放在语句区之后。
|
||||
5. 写 `.tsf` 时,只写可复用顶层声明,不写入口脚本流程;部署、查找路径和解释器环境属于项目执行层。
|
||||
6. 本页和对应专题页没有覆盖的写法,不要发明语法;仍无文档事实时向用户确认或记录文档缺口。
|
||||
在落代码前一次性给出跨专题的语言硬规则(赋值、文件形态、声明位置、命名参数、下标起点、类与 `unit` 外形),并提供术语对照和默认可执行脚本骨架。
|
||||
|
||||
## 语言核心事实速查
|
||||
|
||||
<!-- tags: 语法速查, 硬规则, 核心规则一览, 先看哪些, 常见规则汇总 -->
|
||||
|
||||
这一节是本语法手册默认的语言硬规则收口点。涉及赋值、`.tsl` 语句区 / 声明区、`.tsf` 模块、命名参数、类写法、`unit` 骨架和下标规则时,统一先看这里。
|
||||
|
||||
- 赋值:普通赋值用 `:=`,不要把 `=` 当成普通赋值。
|
||||
- 后缀:用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;用户未给后缀时,再按交付目标判断。
|
||||
- 无后缀:入口流程、脚本任务或一次性执行逻辑对应 `.tsl`;可复用交付物(函数、过程、类、模块或扩展文件)对应 `.tsf`;只是脚本内部封装函数或类时,仍按 `.tsl` 处理;仍不明确时向用户确认。
|
||||
- `.tsl`:可执行脚本,语句区在前并按顺序执行;函数 / 类声明区在后,供前面的语句调用或运行时解析。
|
||||
- 后缀:用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;未给后缀时,入口流程、脚本任务或一次性执行逻辑对应 `.tsl`,可复用交付物(函数、过程、类、模块或扩展文件)对应 `.tsf`,只是脚本内部封装函数或类时仍按 `.tsl` 处理;仍不明确时向用户确认。
|
||||
- `.tsl`:可执行脚本,语句区在前并按顺序执行;函数 / 类声明区在后,供前面的语句调用或运行时解析。不要在声明区后面继续追加脚本语句。
|
||||
- `.tsf`:可复用模块 / 函数扩展文件;非 `unit` 顶层函数 / 过程部署到解释器 `funcext` 后,脚本可以直接调用;顶层类声明只按可复用声明理解;`unit` 按模块组织理解。
|
||||
- `.tsl` 声明区:如果需要函数或类,先写会执行的语句区,再写函数 / 类声明区;不要在声明区后面继续追加脚本语句。
|
||||
- `function` / `procedure`:用户只说“写一个函数”时默认用 `function`;只有用户明确要求 `procedure` / 过程时才用 `procedure Name(...); begin ... end;`;`procedure` 头后不允许写返回类型。
|
||||
- `.tsf` 文件名:文件名(不含扩展名)必须与第一个顶层声明同名,`UserAccount.tsf` 的顶层声明必须是 `function UserAccount`、`type UserAccount = class` 或 `unit UserAccount`。
|
||||
- `function` / `procedure`:用户只说“写一个函数”时默认用 `function`;只有用户明确要求 `procedure` / 过程时才用 `procedure Name(...); begin ... end;`。
|
||||
- 类:顶层类定义统一写成 `type Name = class ... end;`,不要写裸 `class Name`;创建对象有两种方式,`new ClassName()` 最常用,`createObject(...)` 作为次选;需要字符串类名、类类型变量或跨 `unit` 路径时,更适合用 `createObject(...)`。
|
||||
- `unit`:涉及多文件组织时,先按 `unit Name; interface ... implementation ... end.` 骨架理解;不要把 `unit` 当默认最小起手。
|
||||
- 命名参数:写法是 `Func(a:1, b:2)`,不要写成 `Func(a = 1, b = 2)`。
|
||||
- 下标:`array(...)` 既可以写顺序数组,也可以写字符串键表;数组下标从 `0` 开始,字符串下标从 `1` 开始。
|
||||
- 下标:`array(...)` 既可以写顺序数组,也可以写字符串键表;顺序数组和 `binary(...)` 二进制缓冲区下标从 `0` 开始,字符串下标从 `1` 开始。
|
||||
|
||||
## 术语对照
|
||||
|
||||
@@ -39,135 +31,10 @@
|
||||
- “顶层函数骨架”“顶层函数定义体”:只指 `function` 骨架;不要因为任务没有返回值就自动改成 `procedure`。
|
||||
- `class function` / “类方法”:同一件事;前者是代码关键字写法,后者是中文描述。
|
||||
|
||||
## 任务到文件模型的选择规则
|
||||
|
||||
| 任务 | 起手骨架 |
|
||||
| ------------------------------------ | ------------------------------ |
|
||||
| 写入口流程、脚本任务或一次性执行逻辑 | `.tsl` 脚本语句区 |
|
||||
| 脚本逻辑需要调用本文件内函数 | `.tsl` 语句区 + 后置函数声明区 |
|
||||
| 脚本逻辑需要对象状态、字段、方法 | `.tsl` 语句区 + 后置类声明区 |
|
||||
| 沉淀可复用函数、过程或类 | `.tsf` 可复用顶层声明 |
|
||||
| 需要把接口和实现组织进一个模块 | `.tsf` `unit` |
|
||||
|
||||
默认建议:
|
||||
|
||||
- 用户只要求写一段代码、脚本或示例,且没有明确复用、模块或 `.tsf` 交付需求时,优先从 `.tsl` 脚本语句区开始。
|
||||
- 不要因为代码里需要函数或类就自动升级成 `.tsf`;`.tsl` 也可以在语句区后放声明区。
|
||||
- 不要把 `unit` 当成最小起手骨架;只有用户明确要模块接口 / 实现组织,或项目已有 `unit` 边界时,才进入 `unit` 写法。
|
||||
- `uses` 往往天然进入多文件查找路径问题,所以不放进这篇的最小起手骨架里。
|
||||
|
||||
## 最小骨架
|
||||
|
||||
使用这些骨架时遵守:
|
||||
|
||||
- 可以模仿已经出现的代码外形、语句顺序和块级结构。
|
||||
- 不要从骨架推断未出现的语法、内置函数、部署方式、文件名规则或模块查找规则。
|
||||
- 扩展写法必须有对应专题事实支持。
|
||||
|
||||
本页只列最短高频骨架;`procedure`、参数、返回类型和调用细节见 [05_functions_and_calls.md](05_functions_and_calls.md)。
|
||||
|
||||
### `.tsl` 脚本骨架
|
||||
|
||||
`.tsl` 脚本语句区骨架:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := 1;
|
||||
```
|
||||
|
||||
代码块说明:这是 `.tsl` 语句区最小形态,只证明脚本语句可以从文件开头顺序执行。
|
||||
|
||||
`.tsl` 语句区调用后置函数声明:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
a := 1;
|
||||
Test();
|
||||
|
||||
function Test();
|
||||
begin
|
||||
echo "test";
|
||||
end;
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
test
|
||||
```
|
||||
|
||||
代码块说明:这个骨架证明 `.tsl` 语句区可以调用后置函数声明;不要在函数声明区之后继续追加脚本语句。
|
||||
|
||||
`.tsl` 语句区调用后置类声明:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
obj := new MyClass();
|
||||
obj.value := 5;
|
||||
echo obj.value;
|
||||
|
||||
type MyClass = class
|
||||
value;
|
||||
end;
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
5
|
||||
```
|
||||
|
||||
代码块说明:这个骨架证明 `.tsl` 语句区可以通过 `new MyClass()` 使用后置类声明;普通对象创建默认优先 `new ClassName()`。`createObject(...)` 也是对象创建方式,但作为次选;需要字符串类名、类类型变量或跨 `unit` 路径时,更适合用 `createObject(...)`,细节见 [08_objects_and_classes.md](08_objects_and_classes.md)。
|
||||
|
||||
### `.tsf` 可复用骨架
|
||||
|
||||
`.tsf` 顶层函数骨架:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
function TestFunc();
|
||||
begin
|
||||
echo "test1";
|
||||
end;
|
||||
```
|
||||
|
||||
代码块说明:这个 `.tsf` 部署到解释器 `funcext` 后,`.tsl` 脚本可以直接调用 `TestFunc();`。部署方式属于项目执行层,不写进通用语法页。
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
test1
|
||||
```
|
||||
|
||||
`.tsf` `unit` 骨架:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
unit DemoUnit;
|
||||
|
||||
interface
|
||||
|
||||
function Ping();
|
||||
|
||||
implementation
|
||||
|
||||
function Ping();
|
||||
begin
|
||||
return 1;
|
||||
end;
|
||||
|
||||
end.
|
||||
```
|
||||
|
||||
代码块说明:这个 `.tsf` 骨架用于模块接口 / 实现组织;`.tsl` 脚本 `uses DemoUnit` 后可调用 `Ping()`,返回值为 `1`。调用脚本和查找路径边界见 [09_units_and_scope.md](09_units_and_scope.md)。
|
||||
|
||||
## 默认起手骨架
|
||||
|
||||
<!-- tags: 起手模板, 从哪开始写, 最小可跑, 第一个脚本, hello world -->
|
||||
|
||||
如果用户只要求写一段代码、脚本或示例,且没有明确 `.tsf`、`unit`、模块复用或对象建模需求,直接从 `.tsl` 脚本版本开始:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -182,31 +49,4 @@ echo "hello";
|
||||
hello
|
||||
```
|
||||
|
||||
代码块说明:这是默认可执行脚本骨架;没有复用或模块需求时,不要主动改成 `.tsf`。
|
||||
|
||||
## 最高频禁止项
|
||||
|
||||
- `.tsl` 可以同时有语句区和声明区;真正要避免的是在声明区后面继续追加脚本语句。
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
a := 1;
|
||||
test();
|
||||
|
||||
function test();
|
||||
begin
|
||||
echo "test";
|
||||
end;
|
||||
|
||||
echo "after declaration";
|
||||
```
|
||||
|
||||
代码块说明:这是不可照写的错误形态;最后一行属于“声明区之后继续写脚本语句”。正确做法是把所有会执行的脚本语句放在声明区之前。
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
Execute script error at Line:9
|
||||
function:__main__:line 9: invalid statement
|
||||
```
|
||||
代码块说明:这是默认可执行脚本骨架;没有复用或模块需求时,不要主动改成 `.tsf`。需要在语句区之后接函数或类声明区时,骨架见 [02_core_model.md](02_core_model.md)。
|
||||
|
||||
@@ -6,22 +6,16 @@
|
||||
|
||||
回答“目标文件到底是 `.tsl` 脚本还是 `.tsf` 可复用声明文件,以及 `.tsl` 里的哪些内容会顺序执行、哪些内容只是后置声明”。
|
||||
|
||||
本页负责文件模型判断;具体语法外形的事实分别见:函数 / 过程 [05_functions_and_calls.md](05_functions_and_calls.md),类 [08_objects_and_classes.md](08_objects_and_classes.md),`unit` / `uses` [09_units_and_scope.md](09_units_and_scope.md),赋值和表达式 [06_expressions_and_operators.md](06_expressions_and_operators.md)。[01_quickstart.md](01_quickstart.md) 只作为最短骨架和高频硬规则速查。
|
||||
|
||||
## 智能体文件模型判断流程
|
||||
|
||||
1. 后缀是第一证据:用户明确要求 `.tsl` 时,按可执行脚本写;用户明确要求 `.tsf` 时,按可复用声明文件写。
|
||||
2. 没有后缀时看交付目标:入口流程、脚本任务或一次性执行逻辑对应 `.tsl`;可复用交付物(函数、过程、类、模块或扩展文件)对应 `.tsf`;如果只是脚本内部封装函数或类,仍按 `.tsl` 处理。
|
||||
3. 目标仍不明确时先问用户;不要把脚本入口和可复用模块替用户合并成一个猜测文件。
|
||||
4. 写 `.tsl` 时,先生成脚本语句区;需要函数、过程或类时,把声明区放在语句区之后。
|
||||
5. 写 `.tsf` 时,生成顶层函数 / 过程 / 类声明,或 `unit`;不要写成会直接顺序执行的脚本入口。
|
||||
6. 没有文档证据时不要发明文件模型;只能使用对应专题事实、项目自身文档或项目专属规则,否则记录文档缺口。
|
||||
本页是文件模型的唯一事实源:后缀判断、语句区 / 声明区顺序、`.tsf` 顶层声明形态和文件名约束都在这里收口。函数体、类体、`unit` 内部的语法外形由各自专题页拥有。
|
||||
|
||||
## 文件模型核心规则
|
||||
|
||||
<!-- tags: 该用哪种文件, tsl 还是 tsf, 后缀怎么选, 文件形态判断 -->
|
||||
|
||||
- 用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;未给后缀时,再按交付目标判断。
|
||||
- 未给后缀时,入口流程、脚本任务或一次性执行逻辑对应 `.tsl`;可复用交付物(函数、过程、类、模块或扩展文件)对应 `.tsf`;只是脚本内部封装函数或类时,仍按 `.tsl` 处理;仍不明确时向用户确认。
|
||||
- `.tsl` 脚本按两段理解:语句区在前并按顺序执行;声明区在后,可放 `function / procedure` 或 `type Name = class`。
|
||||
- 未给后缀时,入口流程、脚本任务或一次性执行逻辑对应 `.tsl`;可复用交付物(函数、过程、类、模块或扩展文件)对应 `.tsf`;只是脚本内部封装函数或类时,仍按 `.tsl` 处理;仍不明确时向用户确认,不要把脚本入口和可复用模块合并成一个猜测文件。
|
||||
- `.tsl` 脚本按两段理解:语句区在前并按顺序执行;声明区在后,可放 `function / procedure` 或 `type Name = class`。写 `.tsl` 时先写语句区,需要函数、过程或类时把声明区放在语句区之后。
|
||||
- 写 `.tsf` 时只写顶层函数 / 过程 / 类声明,或 `unit`;不要写成会直接顺序执行的脚本入口。
|
||||
- `.tsf` 里的非 `unit` 顶层函数 / 过程可按函数扩展理解:部署到解释器 `funcext` 后,`.tsl` 可以直接调用;顶层类声明只按可复用声明理解;`unit` 按模块组织理解。
|
||||
- `uses` 可以出现在顶层,但这里只把它当成辅助语句,不把它当成主体声明;函数体和类定义体里的位置限制见 [09_units_and_scope.md](09_units_and_scope.md)。
|
||||
- 裸 `class Name` 不作为类定义写法使用。
|
||||
@@ -44,6 +38,8 @@
|
||||
|
||||
### `.tsl` 文件模型
|
||||
|
||||
<!-- tags: 可执行脚本, 顺序执行, 入口脚本, 语句区, 声明区, 脚本从哪开始跑 -->
|
||||
|
||||
`.tsl` 脚本语句区的最小形态:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -100,6 +96,8 @@ end;
|
||||
|
||||
### `.tsf` 文件模型
|
||||
|
||||
<!-- tags: 可复用文件, 模块文件, 函数扩展, 别的脚本能调, funcext -->
|
||||
|
||||
`.tsf` 顶层函数的最小形态:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -119,6 +117,23 @@ end;
|
||||
1
|
||||
```
|
||||
|
||||
`.tsf` 顶层类声明的最小形态:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
type UserAccount = class
|
||||
public
|
||||
Name;
|
||||
function Describe();
|
||||
begin
|
||||
return Name;
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
代码块说明:这个 `.tsf` 只按可复用类声明理解,不会自己顺序执行。文件必须命名为 `UserAccount.tsf`,因为文件名要与第一个顶层声明同名。类成员、可见性和继承的完整事实见 [08_objects_and_classes.md](08_objects_and_classes.md)。
|
||||
|
||||
`.tsf` `unit` 的最小形态:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -150,7 +165,9 @@ end.
|
||||
|
||||
### 文件模型反例
|
||||
|
||||
不可照写形态:
|
||||
<!-- tags: 为什么编译失败, 顶层裸类, 文件写错了, invalid statement -->
|
||||
|
||||
顶层裸 `class` 声明:
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
@@ -159,7 +176,7 @@ class DemoType
|
||||
end;
|
||||
```
|
||||
|
||||
上面这种裸 `class` 顶层写法会编译失败。
|
||||
上面这种裸 `class` 顶层写法会编译失败;顶层类声明必须写成 `type DemoType = class ... end;`。
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
@@ -167,22 +184,56 @@ end;
|
||||
invalid statement
|
||||
```
|
||||
|
||||
## 文件模型归类速查
|
||||
在声明区之后继续写脚本语句:
|
||||
|
||||
任务目标是判断文件属于哪一种模型时,使用下面这组归类:
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
- `.tsl` 脚本语句区:直接写会顺序执行的语句。
|
||||
- `.tsl` 声明区:在语句区之后写 `function ... begin ... end;`、`procedure ... begin ... end;` 或 `type Name = class ... end;`。
|
||||
- `.tsf` 顶层函数 / 过程:写可部署到 `funcext` 的 `function` / `procedure` 文件。
|
||||
- `.tsf` 顶层类声明:写 `type Name = class ... end;`,只按可复用声明理解;类细节见 [08_objects_and_classes.md](08_objects_and_classes.md)。
|
||||
- `.tsf` 顶层单元:默认先写 `unit ... interface ... implementation ... end.`;简写形态见 [09_units_and_scope.md](09_units_and_scope.md)。
|
||||
```text
|
||||
a := 1;
|
||||
test();
|
||||
|
||||
function test();
|
||||
begin
|
||||
echo "test";
|
||||
end;
|
||||
|
||||
echo "after declaration";
|
||||
```
|
||||
|
||||
上面最后一行属于「声明区之后继续写脚本语句」,会编译失败。正确做法是把所有会执行的脚本语句都放在声明区之前。
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
Execute script error at Line:9
|
||||
function:__main__:line 9: invalid statement
|
||||
```
|
||||
|
||||
## 任务到文件模型的选择规则
|
||||
|
||||
<!-- tags: 任务对应哪种文件, 起手形态怎么选, 该建什么文件 -->
|
||||
|
||||
已经确定任务目标时,按下表选择起手形态:
|
||||
|
||||
| 任务 | 起手形态 | 写法 |
|
||||
| --- | --- | --- |
|
||||
| 入口流程、脚本任务或一次性执行逻辑 | `.tsl` 脚本语句区 | 直接写会顺序执行的语句 |
|
||||
| 脚本逻辑需要调用本文件内函数 | `.tsl` 语句区 + 后置函数声明区 | 语句区之后写 `function ... begin ... end;` 或 `procedure ... begin ... end;` |
|
||||
| 脚本逻辑需要对象状态、字段、方法 | `.tsl` 语句区 + 后置类声明区 | 语句区之后写 `type Name = class ... end;` |
|
||||
| 沉淀可复用函数或过程 | `.tsf` 顶层函数 / 过程 | 写可部署到 `funcext` 的 `function` / `procedure` 文件 |
|
||||
| 沉淀可复用类 | `.tsf` 顶层类声明 | 写 `type Name = class ... end;`,只按可复用声明理解;类细节见 [08_objects_and_classes.md](08_objects_and_classes.md) |
|
||||
| 把接口和实现组织进一个模块 | `.tsf` `unit` | 默认先写 `unit ... interface ... implementation ... end.`;简写形态见 [09_units_and_scope.md](09_units_and_scope.md) |
|
||||
|
||||
补充判断:
|
||||
|
||||
- 不要因为代码里需要函数或类就自动升级成 `.tsf`;`.tsl` 也可以在语句区后放声明区。
|
||||
- 不要把 `unit` 当成最小起手骨架;只有用户明确要模块接口 / 实现组织,或项目已有 `unit` 边界时,才进入 `unit` 写法。
|
||||
|
||||
## 文件模型禁止项
|
||||
|
||||
<!-- tags: 不要这样写, 文件模型误用, 两种文件混着写 -->
|
||||
|
||||
- 把 `.tsl` 当成 `.tsf` 来写,只给一个顶层函数,不写任何会执行的脚本语句。
|
||||
- 因为 `.tsl` 脚本内部需要函数或类,就自动改成 `.tsf`。
|
||||
- 把 `.tsf` 当成 `.tsl` 来写,在模块文件里直接堆顺序执行的脚本语句。
|
||||
- 把 `.tsf` 顶层类声明写成裸 `class Name ... end;`;类声明必须使用 `type Name = class ... end;`。
|
||||
- 把 `uses` 当成主体声明,而不是辅助组织语句。
|
||||
- 在 `.tsl` 声明区之后继续追加脚本语句。
|
||||
- `.tsf` 文件名与顶层声明不一致:`UserAccount.tsf` 中写 `function GetUser` 或 `type Customer = class` 或 `unit CustomerModule` 会导致加载失败或检索混乱。
|
||||
|
||||
@@ -4,17 +4,7 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“基本类型怎么写、数组和字符串怎么索引、字符串编码边界怎么写、哪些值规则属于语言级事实”。矩阵、集合扩展和复杂容器不在本页展开;相关事实见 [12_matrix_and_collections.md](12_matrix_and_collections.md) 或对应深水专题。
|
||||
|
||||
## 智能体值写法判断流程
|
||||
|
||||
1. 普通值优先从整数、实数、普通字符串、布尔和 `array(...)` 起手。
|
||||
2. 字符串默认用普通字符串;只有编码、宽串、UTF8、原始字符串、字符码或 ASCII `0` 需求明确时,才使用本页字符串边界规则里的文档明确形态。
|
||||
3. 看到 `array(...)` 时,先判断要顺序数组还是字符串键表:顺序数组用位置元素,字符串键表用 `"Key": value`。
|
||||
4. 写下标前先判断对象类别:顺序数组和二进制缓冲区下标从 `0` 开始,字符串下标从 `1` 开始。
|
||||
5. 写字符串区间前先确认 `s[start:end]` 的 `end` 会被包含;不要按半开区间推断。
|
||||
6. 矩阵、集合扩展、结果集过滤和 TS-SQL 数据形态的事实分别见 [12_matrix_and_collections.md](12_matrix_and_collections.md)、[13_resultset_and_filters.md](13_resultset_and_filters.md) 和 [14_ts_sql.md](14_ts_sql.md);本页不硬拼这些写法。
|
||||
7. 没有对应代码块时不要发明值写法;尤其不要从 JSON、JavaScript、Pascal 或 C 字符串规则直接迁移。
|
||||
回答“基本类型怎么写、数组和字符串怎么索引、字符串编码边界怎么写、哪些值规则属于语言级事实”。本页拥有整数、实数、字符串、布尔、`array(...)` 字面量和下标 / 区间规则;矩阵与集合扩展不在本页展开。
|
||||
|
||||
## 核心规则
|
||||
|
||||
@@ -174,6 +164,8 @@ C
|
||||
|
||||
### 字符串边界规则
|
||||
|
||||
<!-- tags: 原始字符串, 多行字符串, 引号怎么转义, 字符串里带引号, 长文本 -->
|
||||
|
||||
原始字符串 `%%` 的空白分隔、标识符和多行:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -373,6 +365,8 @@ writeLn(s);
|
||||
|
||||
### 字符串 `$` 连接与拼装
|
||||
|
||||
<!-- tags: 拼字符串, 字符串相加, 连接字符串, 数字转字符串拼接 -->
|
||||
|
||||
`$` 用于字符串连接和类型转字符串拼装:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -404,6 +398,8 @@ A=1 B=2.34 C=AAA
|
||||
|
||||
### 字符串 `like` 模式匹配
|
||||
|
||||
<!-- tags: 通配符匹配, 正则匹配, 模糊匹配, 判断是否符合模式 -->
|
||||
|
||||
`like` 用于判断字符串是否符合指定模式(支持通配符和正则表达式):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -448,6 +444,8 @@ writeLn(result);
|
||||
|
||||
### `format` 格式化占位符
|
||||
|
||||
<!-- tags: 格式化输出, 占位符, 补零, 保留小数, 拼装带格式的串 -->
|
||||
|
||||
`format` 用于按占位符格式化输出:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -470,6 +468,8 @@ writeLn(result);
|
||||
|
||||
### `formatdatetime` 日期格式化
|
||||
|
||||
<!-- tags: 日期转字符串, 时间格式化, 年月日怎么输出, 日期显示格式 -->
|
||||
|
||||
`formatdatetime` 用于将日期按指定格式输出:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
@@ -6,15 +6,6 @@
|
||||
|
||||
回答“普通变量怎样直接使用、`var` 在什么位置出现、常量必须怎样初始化、哪些名字一旦绑定就不能再赋值”。
|
||||
|
||||
## 智能体变量/常量判断流程
|
||||
|
||||
1. 普通变量默认直接用 `:=` 首次赋值,不要先补一个没有需求证据的 `var` 段。
|
||||
2. 只有用户要求显式声明或遇到 `{$explicit+}` 时才优先写 `var`。
|
||||
3. 常量声明必须同时初始化;默认只生成 `const name = value;`,顶层脚本常量需要后续脚本语句时,仍按 `.tsl` 语句区规则组织。
|
||||
4. 多参数赋值按 `[a, b] := array(...)` 写;单变量拆包必须写成 `[name, ] := array(...)`。
|
||||
5. 表达式求值、函数参数、运行时类型 / 转换和 `{$explicit+}` 之外的编译选项事实分别见 [06_expressions_and_operators.md](06_expressions_and_operators.md)、[05_functions_and_calls.md](05_functions_and_calls.md)、[17_types_and_conversions.md](17_types_and_conversions.md) 和 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md);本页不硬推断这些规则。
|
||||
6. 没有对应代码块时不要发明变量/常量写法;尤其不要从 Pascal 的声明习惯反推 TSL 必须先声明变量。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 默认变量模型是“直接赋值即得到变量”,不要求先写 `var`。
|
||||
@@ -43,6 +34,8 @@
|
||||
|
||||
### 普通变量与显式声明
|
||||
|
||||
<!-- tags: 怎么声明变量, 变量要不要先定义, 直接赋值, var 用不用写 -->
|
||||
|
||||
默认变量模型:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -89,6 +82,8 @@ writeLn(a);
|
||||
|
||||
### 常量初始化
|
||||
|
||||
<!-- tags: 定义常量, 只读的值, 不能改的值, const 怎么写 -->
|
||||
|
||||
顶层最稳的常量写法:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -175,6 +170,8 @@ value := kMaxRetries;
|
||||
|
||||
### 多参数赋值
|
||||
|
||||
<!-- tags: 一次赋多个变量, 解构赋值, 拆数组到变量, 同时取两个值 -->
|
||||
|
||||
多参数赋值:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
@@ -6,24 +6,12 @@
|
||||
|
||||
回答“如何正确声明 `function` 和 `procedure`、`.tsl` 脚本语句区如何调用后置函数声明、怎样使用参数修饰、普通函数默认参数与可变参数,以及哪些函数写法会直接编译失败”。
|
||||
|
||||
## 智能体函数/调用判断流程
|
||||
|
||||
1. 先判断目标文件是 `.tsl` 还是 `.tsf`;文件模型事实见 [02_core_model.md](02_core_model.md)。
|
||||
2. `.tsl` 中先写语句区,再把 `function` / `procedure` 声明放在后面;不要在声明区后面追加脚本语句。
|
||||
3. `.tsf` 中把顶层 `function` / `procedure` 当成模块 / 函数扩展声明;不要写成顺序执行入口。
|
||||
4. 用户只说“写一个函数”且没有指定 `procedure` 时,默认用 `function`。
|
||||
5. 只有用户明确要求 `procedure` / 过程时,才用 `procedure`;即使任务没有返回值,也默认用 `function`。
|
||||
6. 调用普通 TSL 函数时,命名参数只写 `name: value`;不要把 `name = value` 当成命名参数。
|
||||
7. 参数是否写回调用方要看 `const` / `var` / `{$varByRef-}` / `in` / `out`,不要默认按其他语言习惯推断。
|
||||
8. 默认参数先按普通函数规则处理;`unit interface` 或 `unit const` 默认值的事实见 [09_units_and_scope.md](09_units_and_scope.md)。
|
||||
9. 匿名函数和 TSL 函数值只按本页明确的 `call(f, ...)` / `##f(...)` 生成;`external`、原生函数指针包装、C 回调、线程和系统交互的事实见 [18_external_calls_and_threads.md](18_external_calls_and_threads.md)。
|
||||
10. 没有对应代码块时不要发明函数/调用写法;尤其不要把二进制函数、系统函数、TSL 函数值、原生函数指针和匿名函数都套成同一种调用语法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 最稳妥的函数骨架仍然是 `function Name(...); begin ... end;`。
|
||||
- 用户提示词里的“函数”默认对应 `function`,不要自动改写成 `procedure`。
|
||||
- `procedure Name(...); begin ... end;` 只在用户明确要求 `procedure` / 过程时生成;不要因为没有返回值就自动改用 `procedure`。
|
||||
- `procedure` 头后不允许写返回类型;返回类型注解只用于 `function`。
|
||||
- 在 `.tsl` 文件模型层,脚本语句后可以接函数声明;语句区在前顺序执行,声明区在后提供函数/过程定义。见 [02_core_model.md](02_core_model.md)。
|
||||
- 在 `.tsf` 文件模型层,顶层 `function` / `procedure` 是模块/函数扩展声明;部署到解释器 `funcext` 后可被脚本直接调用。
|
||||
- 函数头后默认保留分号;不要为了简写主动省略。
|
||||
@@ -57,7 +45,7 @@
|
||||
- 匿名函数和 TSL 函数值的稳定调用方式仍是 `call(f, ...)` 或 `##f(...)`。
|
||||
- `f(...)` 这种“函数变量直接调用”写法不作为可写事实;无论 `f` 是匿名函数、`findFunction(...)` 还是 `thisFunction(...)` 返回的函数指针,都不要默认写成直调。
|
||||
- `::FuncName(...)` 可以指向全局/系统函数,用来绕过当前作用域里的同名局部函数。
|
||||
- `external`、原生函数指针包装、`makeInstance` / C 回调和线程调用的事实见 [18_external_calls_and_threads.md](18_external_calls_and_threads.md)。
|
||||
- `external`、原生函数指针包装、`makeInstance` / C 回调和线程调用的事实见 [17_external_calls_and_threads.md](17_external_calls_and_threads.md)。
|
||||
- 不要在 `.tsl` 的函数声明区之后继续追加脚本语句。
|
||||
|
||||
## 可直接照写示例
|
||||
@@ -67,10 +55,12 @@
|
||||
- 普通运行示例默认按 `.tsl` 脚本语句区书写;入口语句放前面,函数 / 过程 / 类型声明放在后置声明区。
|
||||
- `.tsf` 函数 / 过程示例只按可复用顶层声明理解,不要在 `.tsf` 里追加顺序执行入口语句。
|
||||
- `procedure` 示例只在用户明确要求 `procedure` / 过程时复制;普通“写函数”任务不要用。
|
||||
- `external`、原生函数指针包装、C 回调、线程、系统交互和二进制函数边界不在本页硬推断;相关事实见 [18_external_calls_and_threads.md](18_external_calls_and_threads.md) 或函数库文档。
|
||||
- `external`、原生函数指针包装、C 回调、线程、系统交互和二进制函数边界不在本页硬推断;相关事实见 [17_external_calls_and_threads.md](17_external_calls_and_threads.md) 或函数库文档。
|
||||
|
||||
### 基础函数 / 过程骨架
|
||||
|
||||
<!-- tags: 定义函数, 怎么写函数, 函数骨架, 最少几行, procedure 怎么写, 函数放哪里, 先调用后声明 -->
|
||||
|
||||
`.tsl` 语句区调用后置函数声明:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -151,6 +141,8 @@ end;
|
||||
|
||||
### 签名增强:参数类型与返回值类型注解
|
||||
|
||||
<!-- tags: 返回值类型, 声明返回类型, 参数标类型, 类型注解, 函数签名 -->
|
||||
|
||||
带参数类型和返回值类型:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -208,6 +200,8 @@ end;
|
||||
|
||||
### 参数传递方式
|
||||
|
||||
<!-- tags: 传引用, 按引用传, 引用传递, 传值, 按值传递, 改形参影响外面, 写回调用方, 出参, 入参, 只读参数, 不让函数改 -->
|
||||
|
||||
未修饰参数默认写回调用方:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -323,6 +317,8 @@ end;
|
||||
|
||||
### `return` 与 `exit`
|
||||
|
||||
<!-- tags: 返回值, 怎么返回结果, 结果返回, 提前结束, 提前返回, 中途退出函数, 无返回值退出 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -353,6 +349,8 @@ end;
|
||||
|
||||
### 调用增强:命名参数与混用规则
|
||||
|
||||
<!-- tags: 按参数名传, 命名实参, 关键字参数, 指定参数名, 位置参数混用 -->
|
||||
|
||||
命名参数调用:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -430,6 +428,8 @@ end;
|
||||
|
||||
### 默认参数
|
||||
|
||||
<!-- tags: 默认值, 可选参数, 参数省略, 不传就用默认 -->
|
||||
|
||||
默认值参数:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -514,6 +514,8 @@ function F(a, b = 100, c = default_value);
|
||||
|
||||
### 可变参数 `...`
|
||||
|
||||
<!-- tags: 任意多个参数, 不定参数, 变长参数, 参数个数不固定, 参数转发 -->
|
||||
|
||||
尾部可变参数:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -650,6 +652,8 @@ end;
|
||||
|
||||
### 匿名函数与函数指针
|
||||
|
||||
<!-- tags: lambda, 闭包, 函数当变量, 函数当参数, 回调, 函数指针, 把函数存起来 -->
|
||||
|
||||
匿名函数变量:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -771,6 +775,8 @@ writeLn(a(7, 8));
|
||||
|
||||
### `::` 指向全局函数
|
||||
|
||||
<!-- tags: 重名, 同名函数, 调全局的那个, 作用域冲突, 指定全局函数 -->
|
||||
|
||||
当当前作用域里有同名局部函数时,可以用 `::FuncName(...)` 指定去调全局/系统函数:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -807,7 +813,7 @@ end;
|
||||
|
||||
### 系统交互专题
|
||||
|
||||
`external`、原生函数指针包装、`makeInstance` / C 回调和线程调用,统一见 [18_external_calls_and_threads.md](18_external_calls_and_threads.md)。这一篇只保留“普通函数怎样定义和调用”的主线。
|
||||
`external`、原生函数指针包装、`makeInstance` / C 回调和线程调用,统一见 [17_external_calls_and_threads.md](17_external_calls_and_threads.md)。这一篇只保留“普通函数怎样定义和调用”的主线。
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
|
||||
@@ -6,30 +6,14 @@
|
||||
|
||||
回答“赋值、算术、比较、逻辑、位运算、集合/类型关系、条件求值、表达式对象、访问/调用、点前缀运算符和专题运算符入口在 TSL 里怎样写”。
|
||||
|
||||
## 智能体表达式/运算符判断流程
|
||||
|
||||
1. 先判断要写基础表达式运算符,还是集合、矩阵、对象重载、运行时调用或 TS-SQL 这类专题运算符。
|
||||
2. 普通变量赋值只能用 `:=`,不要把 `=` 当赋值写法;`const name = value;` 是常量初始化规则,相关事实见 [04_variables_and_constants.md](04_variables_and_constants.md)。
|
||||
3. 在普通表达式里,比较才用 `=`,并且把比较表达式放在 `writeLn(...)`、条件或其他需要布尔值的位置。
|
||||
4. 函数签名里的默认参数 `name = value` 不是比较表达式;默认参数规则见 [05_functions_and_calls.md](05_functions_and_calls.md)。
|
||||
5. 普通算术优先使用 `+`、`-`、`*`、`/`、`%`;左除用 `\`;整数除法和取模可用 `div`、`mod`;幂运算用 `^`;对数用 `~`;一元倒数用 `!x`。
|
||||
6. 逻辑表达式优先使用 `and`、`or`、`not`;`&&`、`||`、`.&&`、`.||`、`.!!` 也已可用,但默认不作为主写法;不要把 `!` 写成逻辑非。
|
||||
7. 位运算使用点前缀或移位关键字:`.&`、`.|`、`.!`、`.^`、`shl`、`shr`、`rol`、`ror`;普通 `&`、`|`、`~` 不按位运算理解。
|
||||
8. 已有变量做原地更新时,才使用 `+=`、`-=`、`*=`、`/=`、`\=`、`%=`、`^=`、`~=`、`div=`、`.&=`、`.|=`、`.^=`、`.&&=`、`.||=`、`a++;`、`a--;`、`++a;`、`--a;`。
|
||||
9. 条件求值优先用 `flag ? true_value : false_value`;需要保留条件自身真值时可用 `value ?: fallback_value`;需要 Pascal 风格时可用 `if condition then true_value else false_value` 的形态,但必须带 `else`。
|
||||
10. 需要延迟求值或动态表达式对象时,才使用 `@expr` 或 `&"..."`,并用本页明确的 `eval(...)` 形态求值。
|
||||
11. 空安全访问只照本页文档明确形态写:`a?.member`、`a?.[index]`、以及 `c?.a?.[1]`。不要外推成任意深度、任意组合都可写。
|
||||
12. 需要连续比较时,标量用 `:<` / `:>` 这组链式比较;数组逐元素比较用 `::<` / `::>` 这组矩阵链式比较。
|
||||
13. 集合、矩阵、过滤、对象重载、函数值调用、网格调用、运行时后缀和 TS-SQL 的事实所有者由“专题运算符入口表”列出。
|
||||
14. `{$ifdef ...}` 只作为能力探测;编译选项边界见 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。
|
||||
15. 任务需要的运算符没有文档事实时,不要生成猜测写法;只能使用对应专题事实、项目自身文档或项目专属规则,仍无结论时记录文档缺口。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 本页是 TSL 表达式与运算符的生成规则页;写代码时只使用本页或对应专题页明确记录的运算符和表达式形态。
|
||||
|
||||
### 本页直接生成的运算符
|
||||
|
||||
<!-- tags: 运算符一览, 位运算, 逻辑运算, 算术运算, 比较运算, 移位, 按位与或 -->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| 类别 | 运算符 / 形态 | 生成规则 |
|
||||
| --- | --- | --- |
|
||||
@@ -39,13 +23,13 @@
|
||||
| 函数默认参数 | `name = value` | 这是函数签名规则,不按比较表达式处理。 |
|
||||
| 算术复合赋值 | `+=`、`-=`、`*=`、`/=`、`\=`、`%=`、`^=`、`~=`、`div=` | 已有变量需要原地更新时使用;`div=` 是整除复合赋值。 |
|
||||
| 点前缀复合赋值 | `.&=`、`.|=`、`.^=`、`.&&=`、`.||=` | 位运算或点前缀逻辑需要原地更新时使用。 |
|
||||
| 自增 / 自减 | `a++`、`a--`、`++a`、`--a` | 普通数字变量可直接用;对象重载语义见 [24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md)。 |
|
||||
| 自增 / 自减 | `a++`、`a--`、`++a`、`--a` | 普通数字变量可直接用;对象重载语义见 [23_object_overloads_and_iteration.md](23_object_overloads_and_iteration.md)。 |
|
||||
| 算术 | `+`、`-`、`*`、`/`、`\`、`%`、`div`、`mod`、`^`、`~` | 普通数值计算使用;`\` 是左除,`^` 是幂运算,`~` 是对数运算。 |
|
||||
| 一元正负号 | `+x`、`-x` | 可直接用于数值表达式。 |
|
||||
| 一元倒数 | `!x` | 整型、实型输入返回实型倒数;矩阵逆/广义逆见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)。 |
|
||||
| 一元倒数 | `!x` | 整型、实型输入返回实型倒数;矩阵逆/广义逆见 [21_matrix_deep_dive.md](21_matrix_deep_dive.md)。 |
|
||||
| 字符串连接 | `+`、`$` | 字符串拼接两种写法都已写入文档;默认优先用 `+`。 |
|
||||
| 比较 | `=`、`<>`、`<`、`>`、`<=`、`>=` | `=` 只作比较,不作普通赋值。 |
|
||||
| 点前缀比较 | `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` | 标量比较可用;数组/矩阵样数据上的逐元素语义见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 |
|
||||
| 点前缀比较 | `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` | 标量比较可用;数组/矩阵样数据上的逐元素语义见 [11_matrix_and_collections.md](11_matrix_and_collections.md)。 |
|
||||
| 逻辑 | `and`、`or`、`not`、`&&`、`||`、`.&&`、`.||`、`.!!` | 默认优先写 `and` / `or` / `not`;不要用 `!` 表示逻辑非。 |
|
||||
| 位运算 | `.&`、`.|`、`.!`、`.^`、`shl`、`shr`、`rol`、`ror` | 生成代码时写成点前缀或关键字形态;普通 `&`、`|`、`~` 不作为位运算写法。 |
|
||||
| 成员 / 下标 / 调用 | `obj.member`、`value[index]`、`Func(args)` | 普通访问和调用可直接使用;类、对象、函数细节回对应专题。 |
|
||||
@@ -55,27 +39,29 @@
|
||||
| Pascal 风格条件表达式 | `if condition then true_value else false_value` | 必须带 `else`。 |
|
||||
| 表达式对象 | `@expr`、`&"..."` | 需要延迟求值或动态表达式对象时使用,并用 `eval(...)` 求值。 |
|
||||
| 逗号表达式 | `(exp1, exp2, ..., expN)` | 从左到右求值,返回最后一个表达式结果。 |
|
||||
| 集合 / 匹配 / 类型关系 | `in`、`sqlin`、`like`、`is` | 否定形态见下一行;集合运算见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 |
|
||||
| 集合 / 匹配 / 类型关系 | `in`、`sqlin`、`like`、`is` | 否定形态见下一行;集合运算见 [11_matrix_and_collections.md](11_matrix_and_collections.md)。 |
|
||||
| 否定关系 | `not in`、`not sqlin`、`not like`、`not is` | 直接使用这几种文档明确形态,不自行重组。 |
|
||||
| 标量链式比较 | `:<`、`:>`、`:<>`、`:==`、`:>=`、`:<=` | 连续标量比较才使用。 |
|
||||
| 矩阵链式比较 | `::<`、`::>`、`::<>`、`::==`、`::>=`、`::<=` | 数组逐元素链式比较才使用;数组与矩阵样数据细节见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 |
|
||||
| 矩阵链式比较 | `::<`、`::>`、`::<>`、`::==`、`::>=`、`::<=` | 数组逐元素链式比较才使用;数组与矩阵样数据细节见 [11_matrix_and_collections.md](11_matrix_and_collections.md)。 |
|
||||
|
||||
### 专题运算符入口
|
||||
|
||||
<!-- tags: 运算符去哪查, 特殊符号归属 -->
|
||||
|
||||
| 运算符 / 形态 | 责任页 | 生成规则 |
|
||||
| --- | --- | --- |
|
||||
| `call(f, ...)`、`##f(...)`、`::FuncName(...)` | [05_functions_and_calls.md](05_functions_and_calls.md) | 函数值调用、变参转发和全局函数限定调用只按函数页生成。 |
|
||||
| 调用点 `in` / `out`、变参 `...` | [05_functions_and_calls.md](05_functions_and_calls.md) | 这是参数传递 / 变参规则,不按普通表达式运算符处理。 |
|
||||
| `#Func() with array(...)` | [10_runtime_context_and_with.md](10_runtime_context_and_with.md) | 运行时环境参数调用只按运行时上下文页生成。 |
|
||||
| `#Func(args)`、`timeout N`、`dupvalue(...)` | [10_runtime_context_and_with.md](10_runtime_context_and_with.md) | 网格调用和运行时服务后缀只按运行时上下文页生成。 |
|
||||
| `union2`、`intersect`、`minus`、`outersect`、`union2=`、`intersect=`、`minus=`、`outersect=` | [12_matrix_and_collections.md](12_matrix_and_collections.md) | 行集合并、交、差、对称差及其复合赋值只按数组/集合页生成。 |
|
||||
| `filterIn(...)`、`filterNotIn(...)` | [13_resultset_and_filters.md](13_resultset_and_filters.md) | 结果集过滤只按过滤页生成,不当作去重型集合运算。 |
|
||||
| `:*`、`:/`、`:\`、`:^`、`union`、|、`:|`、`|=`、`:|=`、`&=`、`:*=`、`:/=`、`:\=`、`:^=` | [22_matrix_deep_dive.md](22_matrix_deep_dive.md)、[23_fmarray.md](23_fmarray.md) | 矩阵乘除、左右拼接、下方拼接和矩阵复合赋值只按矩阵专题页生成。 |
|
||||
| `->`、`!matrix`、`.?`、`.?:` | [22_matrix_deep_dive.md](22_matrix_deep_dive.md) | 数列数组初始化、矩阵逆/广义逆、矩阵条件求值只按矩阵深水页生成。 |
|
||||
| `::`、`::=`、`:.`、`:.=` | [22_matrix_deep_dive.md](22_matrix_deep_dive.md)、[24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md) | 矩阵遍历/深度遍历和对象遍历重载只按专题页生成,不在普通表达式里自行套用。 |
|
||||
| 反引号转置 `` `value `` | [23_fmarray.md](23_fmarray.md) | `FMArray` 转置只按 `FMArray` 页生成。 |
|
||||
| `operator +`、`operator <`、`operator[]`、`operator[0]`、`operator[1]`、`operator for`、`operator mrows/mcols/msize`、`operator++`、`operator +=` | [24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md) | 对象运算符重载只按对象重载页生成。 |
|
||||
| `select` / `sselect` / `vselect` / `mselect`、`where`、`group by`、`order by`、`join` | [14_ts_sql.md](14_ts_sql.md) | TS-SQL 是查询语法,不按普通表达式拼接。 |
|
||||
| `union2`、`intersect`、`minus`、`outersect`、`union2=`、`intersect=`、`minus=`、`outersect=` | [11_matrix_and_collections.md](11_matrix_and_collections.md) | 行集合并、交、差、对称差及其复合赋值只按数组/集合页生成。 |
|
||||
| `filterIn(...)`、`filterNotIn(...)` | [12_resultset_and_filters.md](12_resultset_and_filters.md) | 结果集过滤只按过滤页生成,不当作去重型集合运算。 |
|
||||
| `:*`、`:/`、`:\`、`:^`、`union`、|、`:|`、`|=`、`:|=`、`&=`、`:*=`、`:/=`、`:\=`、`:^=` | [21_matrix_deep_dive.md](21_matrix_deep_dive.md)、[22_fmarray.md](22_fmarray.md) | 矩阵乘除、左右拼接、下方拼接和矩阵复合赋值只按矩阵专题页生成。 |
|
||||
| `->`、`!matrix`、`.?`、`.?:` | [21_matrix_deep_dive.md](21_matrix_deep_dive.md) | 数列数组初始化、矩阵逆/广义逆、矩阵条件求值只按矩阵深水页生成。 |
|
||||
| `::`、`::=`、`:.`、`:.=` | [21_matrix_deep_dive.md](21_matrix_deep_dive.md)、[23_object_overloads_and_iteration.md](23_object_overloads_and_iteration.md) | 矩阵遍历/深度遍历和对象遍历重载只按专题页生成,不在普通表达式里自行套用。 |
|
||||
| 反引号转置 `` `value `` | [22_fmarray.md](22_fmarray.md) | `FMArray` 转置只按 `FMArray` 页生成。 |
|
||||
| `operator +`、`operator <`、`operator[]`、`operator[0]`、`operator[1]`、`operator for`、`operator mrows/mcols/msize`、`operator++`、`operator +=` | [23_object_overloads_and_iteration.md](23_object_overloads_and_iteration.md) | 对象运算符重载只按对象重载页生成。 |
|
||||
| `select` / `sselect` / `vselect` / `mselect`、`where`、`group by`、`order by`、`join` | [13_ts_sql.md](13_ts_sql.md) | TS-SQL 是查询语法,不按普通表达式拼接。 |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
默认生成规则:
|
||||
@@ -95,9 +81,9 @@
|
||||
按需生成规则:
|
||||
|
||||
- 已有变量需要原地更新时,才用 `+=`、`-=`、`*=`、`/=`、`\=`、`%=`、`^=`、`~=`、`div=`、`.&=`、`.|=`、`.^=`、`.&&=`、`.||=`、`a++;`、`a--;`、`++a;`、`--a;`。
|
||||
- 需要矩阵逆/广义逆时才使用 `!A`,矩阵生成规则以 [22_matrix_deep_dive.md](22_matrix_deep_dive.md) 为准。
|
||||
- 需要矩阵逆/广义逆时才使用 `!A`,矩阵生成规则以 [21_matrix_deep_dive.md](21_matrix_deep_dive.md) 为准。
|
||||
- 位运算需要明确写成点前缀或关键字形态:`.&`、`.|`、`.!`、`.^`、`shl`、`shr`、`rol`、`ror`;普通 `&` 不作为位与写法使用。
|
||||
- 点前缀比较 `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` 命中数组/矩阵样数据时,逐元素语义以 [12_matrix_and_collections.md](12_matrix_and_collections.md) 为准。
|
||||
- 点前缀比较 `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` 命中数组/矩阵样数据时,逐元素语义以 [11_matrix_and_collections.md](11_matrix_and_collections.md) 为准。
|
||||
- 需要延迟求值或动态表达式对象时,才用 `@expr` 或 `&"..."`,并用 `eval(...)` 求值。
|
||||
- 需要在一个表达式内按顺序执行多个子表达式时,才用逗号表达式 `(exp1, exp2, ..., expN)`。
|
||||
- 空安全访问只按 `a?.member`、`a?.[index]` 和本页示例里的 `c?.a?.[1]` 生成,不外推任意深链。
|
||||
@@ -110,7 +96,7 @@
|
||||
|
||||
- 没有文档事实的运算符,不生成猜测写法,也不从其他语言习惯反推 TSL 语法。
|
||||
- `{$ifdef ifexp}` 可用于探测 `if ... then ... else ...` 表达式能力;不要写成普通业务分支。
|
||||
- `{$ifdef nilinvoke}` 可用于探测 nil 调用相关能力;编译选项细节见 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。
|
||||
- `{$ifdef nilinvoke}` 可用于探测 nil 调用相关能力;编译选项细节见 [15_lexical_structure_and_compile_options.md](15_lexical_structure_and_compile_options.md)。
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
@@ -119,11 +105,13 @@
|
||||
- `:=` 是普通变量赋值写法;常量初始化规则见 [04_variables_and_constants.md](04_variables_and_constants.md)。
|
||||
- 函数调用、命名参数、默认参数和函数值调用边界见 [05_functions_and_calls.md](05_functions_and_calls.md);不要把函数签名里的 `name = value` 当成比较表达式。
|
||||
- 分支/循环语句见 [07_control_flow.md](07_control_flow.md);对象成员和类相关表达式见 [08_objects_and_classes.md](08_objects_and_classes.md)。
|
||||
- 字符串字面量、拼接与文本边界见 [03_values_and_literals.md](03_values_and_literals.md);数组扩展和矩阵样数据见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。
|
||||
- `{$ifdef ...}` 能力探测见 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md),不要写成普通业务逻辑。
|
||||
- 字符串字面量、拼接与文本边界见 [03_values_and_literals.md](03_values_and_literals.md);数组扩展和矩阵样数据见 [11_matrix_and_collections.md](11_matrix_and_collections.md)。
|
||||
- `{$ifdef ...}` 能力探测见 [15_lexical_structure_and_compile_options.md](15_lexical_structure_and_compile_options.md),不要写成普通业务逻辑。
|
||||
|
||||
### 基础赋值和条件求值
|
||||
|
||||
<!-- tags: 三目运算, 问号冒号, 条件表达式, 一行判断取值 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -566,6 +554,8 @@ writeLn(if 2 > 1 then 2 else 1);
|
||||
|
||||
### 表达式对象
|
||||
|
||||
<!-- tags: 延迟求值, 表达式当值传, eval, 把式子存起来 -->
|
||||
|
||||
`@` 表达式前导:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -644,6 +634,8 @@ writeLn(result_value);
|
||||
|
||||
### 空安全访问
|
||||
|
||||
<!-- tags: 对象可能为空, 判空取属性, nil 安全, 避免空指针 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -687,6 +679,8 @@ writeLn(c?.a?.[1] = nil);
|
||||
|
||||
### 否定形式运算
|
||||
|
||||
<!-- tags: 取反, 不包含, 不匹配, not in 怎么写 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -713,6 +707,8 @@ end;
|
||||
|
||||
### 标量链式比较
|
||||
|
||||
<!-- tags: 连续比较, 区间判断, 夹在中间, 大小连写 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -737,6 +733,8 @@ writeLn(1 :<> 2 :<> 3);
|
||||
|
||||
### 矩阵链式比较
|
||||
|
||||
<!-- tags: 数组逐元素比较, 整列比较, 批量比较 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -765,6 +763,8 @@ writeLn(s[2]);
|
||||
|
||||
### 条件编译探测
|
||||
|
||||
<!-- tags: 判断支持哪些特性, 版本探测, ifdef 怎么用 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
|
||||
@@ -6,14 +6,6 @@
|
||||
|
||||
回答“`if`、`case`、`for`、`while`、`repeat`、`break`、`continue`、`try`、`raise` 这些流程结构在 TSL 里到底怎么写,哪些写法可以直接生成”。
|
||||
|
||||
## 智能体控制流判断流程
|
||||
|
||||
1. 先判断任务需要条件分支、循环、`case`、异常处理还是调试跳转。
|
||||
2. `if` / `for` / `while` / `repeat` 优先照本页文档骨架写,不要套用其他 Pascal 方言。
|
||||
3. 生成带 `else` 的条件分支时,默认用 `begin ... end` 包住 `then` 和 `else` 分支,让分支内部语句正常以分号结尾;不要在 `else` 前提前加分号。
|
||||
4. `case` 可写成语句形态,也可写成赋值右侧的表达式形态;表达式形态的分支只能放单条表达式/单条语句,不写 `begin ... end` 语句段。
|
||||
5. 没有文档事实时不要发明控制流写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- `if ... then ... else ...` 默认写成块式分支:`then begin ... end else begin ... end`。
|
||||
@@ -30,7 +22,7 @@
|
||||
- `exceptObject.errLine` 和 `exceptObject.errNo` 在 `except` 块中也可读。
|
||||
- `try ... finally ... end` 无论是否报错,都会先执行 `finally`;如果没有 `except` 吞掉错误,脚本仍会在 `finally` 之后报错终止。
|
||||
- `raise "message"` 是最小抛错写法。
|
||||
- `goto`、`debugReturn`、`debugRunEnv`、计时和性能分析器这类“控制流补充工具”统一放到 [15_debug_and_profiler.md](15_debug_and_profiler.md)。
|
||||
- `goto`、`debugReturn`、`debugRunEnv`、计时和性能分析器这类“控制流补充工具”统一放到 [14_debug_and_profiler.md](14_debug_and_profiler.md)。
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
@@ -38,10 +30,12 @@
|
||||
|
||||
- 条件表达式、比较、布尔值和普通赋值的事实见 [06_expressions_and_operators.md](06_expressions_and_operators.md)。
|
||||
- 函数里的控制流只按控制流语法处理;函数文件模型、返回值和参数规则见 [05_functions_and_calls.md](05_functions_and_calls.md)。
|
||||
- `goto`、`debugReturn`、计时和性能分析器不在本页生成,相关事实见 [15_debug_and_profiler.md](15_debug_and_profiler.md)。
|
||||
- `goto`、`debugReturn`、计时和性能分析器不在本页生成,相关事实见 [14_debug_and_profiler.md](14_debug_and_profiler.md)。
|
||||
|
||||
### `if`、`while`、`repeat ... until`
|
||||
|
||||
<!-- tags: 条件判断, 循环, 判断语句, 直到满足, 反复执行 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -75,6 +69,8 @@ writeLn(counter);
|
||||
|
||||
### `for` 的几种主干写法
|
||||
|
||||
<!-- tags: 循环写法, 遍历数组, 计数循环, 倒着循环, 遍历键值 -->
|
||||
|
||||
最基础的递增循环:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -159,6 +155,8 @@ for i, value in numbers do
|
||||
|
||||
### `break` 与 `continue`
|
||||
|
||||
<!-- tags: 跳出循环, 提前退出循环, 跳过本次, 结束循环 -->
|
||||
|
||||
`break`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -218,6 +216,8 @@ writeLn(sum);
|
||||
|
||||
### `case` 语句形态
|
||||
|
||||
<!-- tags: 多分支, 分支判断, switch 怎么写, 多条件选择 -->
|
||||
|
||||
普通分支:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -305,6 +305,8 @@ mid
|
||||
|
||||
### `try ... except`
|
||||
|
||||
<!-- tags: 捕获异常, 出错处理, 抓错误, 异常不中断 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -362,6 +364,8 @@ end
|
||||
|
||||
### `try ... finally`
|
||||
|
||||
<!-- tags: 收尾处理, 无论如何都执行, 释放资源, 清理动作 -->
|
||||
|
||||
正常路径:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -421,6 +425,8 @@ finally
|
||||
|
||||
### `raise`
|
||||
|
||||
<!-- tags: 抛异常, 主动报错, 中断执行, 扔错误 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
|
||||
@@ -6,20 +6,6 @@
|
||||
|
||||
回答“`type Name = class`、字段、`static`、方法、`property`、析构、类类型、继承和对象创建在 TSL 里怎样写”。
|
||||
|
||||
本页后半段有少量依赖 `unit` 的双文件示例;`unit` / `uses` 的多文件模型事实见 [09_units_and_scope.md](09_units_and_scope.md)。
|
||||
|
||||
## 智能体对象/类判断流程
|
||||
|
||||
1. 先判断要写普通对象、继承、构造函数、类方法、静态字段还是运行时创建。
|
||||
2. 对象声明优先使用本页明确的 `type Name = class ... end;` 骨架。
|
||||
3. 普通本地类创建默认用 `new ClassName()`;只有需要字符串类名、类类型变量或跨 `unit` 路径时,才用 `createObject(...)`。
|
||||
4. 类方法和静态字段优先用 `class(Name).Member` 或文档明确反射入口,不要裸写类名调用。
|
||||
5. 构造函数默认保持 `public create`,不要把 `private` / `protected create` 当成会自动执行的构造函数。
|
||||
6. 普通类成员默认显式写 `public` 段,不依赖隐式 public。
|
||||
7. 方法体内访问当前实例成员默认直接写成员名;成员读写为了性能不加 `self` 前缀。
|
||||
8. 对象反射 / 运行时状态、内置运行时对象、对象重载 / 迭代的事实分别见 [20_object_runtime_and_introspection.md](20_object_runtime_and_introspection.md)、[21_builtin_runtime_objects.md](21_builtin_runtime_objects.md)、[24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md)。
|
||||
9. 没有文档事实时不要发明对象/类写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 类定义统一按 `type Name = class ... end;` 写。
|
||||
@@ -54,7 +40,7 @@
|
||||
- 如果类里定义了 `function create(...)`,`new`、`createObject("ClassName", ...)` 和 `createObject(ClassType, ...)` 都可以透传构造参数,也都支持默认参数和命名参数。
|
||||
- 析构写法是无参 `function destroy();`;对象的最后一个引用被清空(如设为 `nil`)时会触发它。存在别名引用时,只清空其中一个引用不会触发。
|
||||
- 工厂式 `self(0)` / `self(1)` 可用;不要生成 `self()` 这种无参工厂式写法。
|
||||
- 跨 `unit` 类路径创建和继承属于多文件边界;相关事实见 [09_units_and_scope.md](09_units_and_scope.md) 和 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md),不要从普通单文件 `new` / `createObject` 规则直接泛化。
|
||||
- 跨 `unit` 类路径创建和继承属于多文件边界;相关事实见 [09_units_and_scope.md](09_units_and_scope.md) 和 [18_namespace_libpath_and_unit_runtime.md](18_namespace_libpath_and_unit_runtime.md),不要从普通单文件 `new` / `createObject` 规则直接泛化。
|
||||
- `{$ifdef parentClassInUnit}` 为真,可用于探测“继承和构造单元中的类”能力是否可用。
|
||||
- `private` / `protected` / `public` 可用;类开头未写可见性时,成员默认按 `public` 处理,但生成代码默认显式写 `public`。
|
||||
- 同一个可见性段里后续没有切换关键字的成员,会沿用前一个可见性。
|
||||
@@ -73,6 +59,8 @@
|
||||
|
||||
### 最小类与声明位置
|
||||
|
||||
<!-- tags: 定义一个类, 类怎么写, 最短类, 类放在哪, 类骨架 -->
|
||||
|
||||
最短类骨架:
|
||||
|
||||
如果任务只是要“先写出一个类”,先从这个骨架起手;后面的例子再逐步进入字段、工厂函数和声明位置边界。
|
||||
@@ -181,6 +169,8 @@ writeLn(a);
|
||||
|
||||
### 字段、静态成员、常量与可见性
|
||||
|
||||
<!-- tags: 成员变量, 静态成员, 类常量, 私有公开, 属性可见性, 只有类自己能访问 -->
|
||||
|
||||
`static` 字段:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -393,6 +383,8 @@ end;
|
||||
|
||||
### 构造函数边界
|
||||
|
||||
<!-- tags: 构造方法, 新建时初始化, create 怎么写, 带参数创建 -->
|
||||
|
||||
`create` 建议保持 `public`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -420,6 +412,8 @@ end;
|
||||
|
||||
### 属性、类型注解与类外实现
|
||||
|
||||
<!-- tags: property, 读写属性, getter setter, 方法写在类外 -->
|
||||
|
||||
基础 `property`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -751,6 +745,8 @@ end;
|
||||
|
||||
### 对象创建与类类型
|
||||
|
||||
<!-- tags: 创建对象, 实例化, new 怎么用, 拿到类本身, 动态建对象 -->
|
||||
|
||||
`new` 关键字:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -901,6 +897,8 @@ end;
|
||||
|
||||
### 重载、继承与析构
|
||||
|
||||
<!-- tags: 继承, 父类子类, 方法重载, 同名不同参, 析构, 对象销毁时 -->
|
||||
|
||||
`overload` 方法:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -1304,6 +1302,8 @@ end;
|
||||
|
||||
### 跨 unit 类路径
|
||||
|
||||
<!-- tags: 跨文件的类, 跨文件继承, 类的完整路径 -->
|
||||
|
||||
`unit` 中的嵌套类路径创建属于跨 `unit` 边界,这里用 `text` 展示骨架:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -1338,7 +1338,7 @@ writeLn(obj.value);
|
||||
输出说明:
|
||||
|
||||
- 这个骨架只说明字符串路径创建需要按跨 `unit` 边界处理。
|
||||
- 生成实际代码所需的多文件事实见 [09_units_and_scope.md](09_units_and_scope.md) 和 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)。
|
||||
- 生成实际代码所需的多文件事实见 [09_units_and_scope.md](09_units_and_scope.md) 和 [18_namespace_libpath_and_unit_runtime.md](18_namespace_libpath_and_unit_runtime.md)。
|
||||
- 不要把它直接改写成普通本地类的 `new ClassName()` 模式。
|
||||
|
||||
继承单元中的嵌套类路径属于跨 `unit` 边界,这里也用 `text` 展示骨架:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# TSL unit 与作用域
|
||||
|
||||
这一篇只讲“怎么写和怎么调用 `unit`”。`namespace`、查找路径、`unit` 生命周期、`tsl.conf` 与运行时入口统一放到 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)。
|
||||
这一篇只讲“怎么写和怎么调用 `unit`”。`namespace`、查找路径、`unit` 生命周期、`tsl.conf` 与运行时入口统一放到 [18_namespace_libpath_and_unit_runtime.md](18_namespace_libpath_and_unit_runtime.md)。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
@@ -12,15 +12,6 @@
|
||||
- 多个 `unit` 里有同名接口时,未限定调用到底命中谁
|
||||
- 怎样显式指定要调用哪个 `unit` 的接口
|
||||
|
||||
## 智能体 unit/作用域判断流程
|
||||
|
||||
1. 先判断当前交付是 `.tsl` 可执行脚本、`.tsf` 扩展模块,还是 `unit` 文件。
|
||||
2. `unit` 文件只描述可复用单元;脚本入口仍放在 `.tsl`。
|
||||
3. `uses` 必须放在普通语句之前;普通语句后不要再追加顶层 `uses`。
|
||||
4. 默认参数、接口段、实现段和作用域边界只照本页文档明确形态写。
|
||||
5. `unit` 生命周期、命名空间、查找路径、`tsl.conf` 和命令行查找路径参数的事实见 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)。
|
||||
6. 没有对应代码块时不要发明 unit/作用域写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- `unit` 是完整的顶层主体;常见完整形态是 `unit Name; interface ... implementation ... end.`。
|
||||
@@ -38,12 +29,14 @@
|
||||
- 只写在 `implementation` 里的函数,对 `unit` 外部不可见。
|
||||
- 出现重名接口时,未限定调用按 `uses` 从后往前解析;最后一个 `uses` 的同名接口优先。
|
||||
- 要显式指定某个 `unit` 的接口,可以用 `UnitA.Ping()`、`unit(UnitA).Ping()` 或 `call("UnitA.Ping")`。
|
||||
- `unit` 生命周期、接口状态、命名空间和查找路径细节见 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)。
|
||||
- `unit` 生命周期、接口状态、命名空间和查找路径细节见 [18_namespace_libpath_and_unit_runtime.md](18_namespace_libpath_and_unit_runtime.md)。
|
||||
|
||||
## 示例与行为
|
||||
|
||||
### 最小 `unit`
|
||||
|
||||
<!-- tags: 怎么写 unit, 模块怎么定义, unit 骨架, 接口段实现段 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -78,6 +71,8 @@ end.
|
||||
|
||||
### 简写 `unit`
|
||||
|
||||
<!-- tags: 省略 interface, 最简 unit, 不写接口段 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -109,6 +104,8 @@ end.
|
||||
|
||||
### 顶层、函数体、类体里的 `uses`
|
||||
|
||||
<!-- tags: 怎么引入别的文件, 导入模块, uses 写在哪, 引用其他 unit -->
|
||||
|
||||
沿用同一个 `DemoUnit.tsf`,分别看顶层、函数体、类体三种 `uses` 位置:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -162,6 +159,8 @@ end;
|
||||
|
||||
### `uses` 的位置限制
|
||||
|
||||
<!-- tags: uses 放错地方, 为什么导入失败, 引入语句必须第一行 -->
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
@@ -209,6 +208,8 @@ end;
|
||||
|
||||
### `interface` 段 `uses` 和 `implementation` 段 `uses`
|
||||
|
||||
<!-- tags: 接口段导入, 实现段导入, 导入放哪一段 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
代码块说明:多文件结构骨架;依赖 `unit` 查找路径,不是可直接复制的单文件最小示例。
|
||||
|
||||
@@ -288,6 +289,8 @@ writeLn(obj.FromImplementation());
|
||||
|
||||
### 接口声明与实现段分离
|
||||
|
||||
<!-- tags: 声明和实现分开, 对外暴露哪些, 接口里写什么 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -329,6 +332,8 @@ end.
|
||||
|
||||
### 实现段私有函数
|
||||
|
||||
<!-- tags: 内部函数, 不对外暴露, 私有函数怎么写 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
代码块说明:多文件结构骨架;依赖 `unit` 查找路径,不是可直接复制的单文件最小示例。
|
||||
|
||||
@@ -375,6 +380,8 @@ writeLn(PrivateFunc());
|
||||
|
||||
### 重名解析与限定调用
|
||||
|
||||
<!-- tags: 两个模块同名函数, 冲突了怎么调, 限定名调用, 指定哪个 unit -->
|
||||
|
||||
重名函数最小对照:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
|
||||
@@ -6,18 +6,6 @@
|
||||
|
||||
回答“`setSysParam` / `getSysParam` 怎样用、`sysParams[...]` 是什么、块环境 `with *, values do` / `with **, values do` 怎样写、`#Func() with array(...)` 这种后缀环境调用怎样写,网格调用怎样取回结果,以及全局缓存最小读写规则是什么”。
|
||||
|
||||
## 智能体运行时上下文判断流程
|
||||
|
||||
1. 先判断要操作系统参数、运行时上下文对象、块环境 `with` 语句、`with` 后缀调用、`#` 网格调用、`timeout` 后缀,还是全局缓存函数。
|
||||
2. 系统参数优先用本页明确的 `setSysParam` / `getSysParam` / `sysParams[...]` 形态。
|
||||
3. `#Func() with array(...)` 只作为运行时环境调用写法,不要套到普通本地函数。
|
||||
4. 网格调用返回的不是最终值;需要最终结果时继续写 `dupvalue(...)`。
|
||||
5. 全局缓存读写要成对出现,并明确键和值的生命周期。
|
||||
6. 普通函数调用的事实见 [05_functions_and_calls.md](05_functions_and_calls.md),不要把运行时服务写成普通语法糖;缓存值参与 `select` 时,查询语法事实见 [14_ts_sql.md](14_ts_sql.md)。
|
||||
7. 内置运行时对象本身的事实见 [21_builtin_runtime_objects.md](21_builtin_runtime_objects.md)。
|
||||
8. 本地函数后缀 `with` 属于反例时不要照写。
|
||||
9. 没有对应代码块时不要发明运行时上下文/运行时服务/全局缓存写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
本页示例只说明运行时上下文语法中的调用位置和源码外形。API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。
|
||||
@@ -47,6 +35,8 @@
|
||||
|
||||
### `setSysParam` / `getSysParam` / `sysParams[...]` 基础读写
|
||||
|
||||
<!-- tags: 系统参数, 读写运行参数, 环境设置, 全局设置项 -->
|
||||
|
||||
直接设置和读取系统参数:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -88,6 +78,8 @@ writeLn(getSysParam("a"));
|
||||
|
||||
### 块环境 `with *`
|
||||
|
||||
<!-- tags: 临时改参数, 局部生效, 一段代码内有效, 块内覆盖 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -139,6 +131,8 @@ end
|
||||
|
||||
### 块环境 `with **`
|
||||
|
||||
<!-- tags: 嵌套覆盖, 深层块环境, 多层 with -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -164,6 +158,8 @@ writeLn(getSysParam("b"));
|
||||
|
||||
### 后缀 `with array(...)`:网格调用的临时覆盖
|
||||
|
||||
<!-- tags: 调用时临时改参数, 单次覆盖, 调用完恢复 -->
|
||||
|
||||
`#Func(...) with array(...)` 在一次网格调用里临时覆盖系统参数,调用结束后恢复外层原值。下面用一个 `TestDo.tsf` 演示覆盖边界:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -216,6 +212,8 @@ writeLn(getSysParam("b") = nil);
|
||||
|
||||
### `#` 网格调用与 `dupvalue`
|
||||
|
||||
<!-- tags: 网格调用, 分布式执行, 井号调用, 取回结果 -->
|
||||
|
||||
网格调用函数:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -265,6 +263,8 @@ array(2,4,6,8,10)
|
||||
|
||||
### 网格调用的 `timeout`
|
||||
|
||||
<!-- tags: 超时, 限制执行时间, 多久不返回就断 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -283,6 +283,8 @@ end;
|
||||
|
||||
### `setGlobalCache`、`getGlobalCache` 与 `ifCache`
|
||||
|
||||
<!-- tags: 全局缓存, 缓存数据, 跨脚本共享, 存起来下次用 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -308,6 +310,8 @@ writeLn(cached_data[0], ',', cached_data[1], ',', cached_data[2]);
|
||||
|
||||
### `checkGlobalCacheExpired`
|
||||
|
||||
<!-- tags: 缓存过期, 缓存失效判断, 什么时候要重算 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -325,6 +329,8 @@ writeLn(checkGlobalCacheExpired(cache_ref));
|
||||
|
||||
### 缓存值本地写入后会实例化
|
||||
|
||||
<!-- tags: 改缓存内容, 缓存副本, 写回不影响原缓存 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -344,6 +350,8 @@ writeLn(local_copy[0], ',', local_copy[1], ',', local_copy[2]);
|
||||
|
||||
### 全局缓存参与 `select`
|
||||
|
||||
<!-- tags: 对缓存做查询, 缓存当表查 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
|
||||
+21
-16
@@ -6,15 +6,6 @@
|
||||
|
||||
回答“`array(...)` 在 TSL 里除了最普通的一维数组,还能怎样组织数据;哪些矩阵样写法属于本页文档明确形态;元素、子集、整行和行集合关系应该怎样判断”。
|
||||
|
||||
## 智能体数组/矩阵样数据判断流程
|
||||
|
||||
1. 先判断需要顺序数组、字符串键表、嵌套数组、矩阵样比较,还是去重型集合关系。
|
||||
2. 普通容器优先从 `array(...)` 起手;下标和键访问以值语法事实为准。
|
||||
3. 矩阵链式比较只照 `::` 系列文档明确示例写,不要混用标量链式比较。
|
||||
4. 基础成员判断用 `in` / `not in`;整行存在判断用 `sqlin` / `not sqlin`;去重型行集合并、交、差、对称差用 `union2` / `intersect` / `minus` / `outersect`。
|
||||
5. 结果集过滤和 TS-SQL 查询的事实分别见 [13_resultset_and_filters.md](13_resultset_and_filters.md) 和 [14_ts_sql.md](14_ts_sql.md)。
|
||||
6. 没有对应代码块时不要发明数组/矩阵样数据/集合关系写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- `array(...)` 既可以写顺序数组,也可以写字符串键表。
|
||||
@@ -24,7 +15,7 @@
|
||||
- `in` / `not in` 处理的是元素存在关系,以及左侧为数组时的子集关系。
|
||||
- `sqlin` / `not sqlin` 处理的是行存在关系;左侧要当成一整行去匹配右侧结果集。
|
||||
- `union2`、`intersect`、`minus`、`outersect` 都按“行”运算,而不是按单元格逐个运算。
|
||||
- 集合运算结果会折叠重复行;保留重复记录的过滤规则见 [13_resultset_and_filters.md](13_resultset_and_filters.md)。
|
||||
- 集合运算结果会折叠重复行;保留重复记录的过滤规则见 [12_resultset_and_filters.md](12_resultset_and_filters.md)。
|
||||
- 当数据本身就是一维数组时,按行集合运算和按元素集合运算是一致的。
|
||||
- 左侧是数组时,先判定需求语义:子集关系用 `in`,整行存在关系用 `sqlin`。
|
||||
|
||||
@@ -32,6 +23,8 @@
|
||||
|
||||
### 基础数组与键表
|
||||
|
||||
<!-- tags: 建数组, 字典, 键值对, 二维数组, 嵌套数组, 按名字取值 -->
|
||||
|
||||
顺序数组与字符串键表:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -78,6 +71,8 @@ writeLn(r2[1]);
|
||||
|
||||
### 矩阵样比较
|
||||
|
||||
<!-- tags: 数组比大小, 链式比较, 整体比较 -->
|
||||
|
||||
矩阵链式比较:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -101,6 +96,8 @@ writeLn(s[2]);
|
||||
|
||||
### `in`、`not in`、`sqlin`、`not sqlin`
|
||||
|
||||
<!-- tags: 判断存在, 是否包含, 在不在里面, 子集判断 -->
|
||||
|
||||
`in` 既可以判断单个元素是否存在,也可以判断左侧数组是否是右侧结果集的子集:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -159,6 +156,8 @@ writeLn(array(5, 6) not sqlin array((1, 2), (3, 4)));
|
||||
|
||||
### 行集合并、交、差、对称差
|
||||
|
||||
<!-- tags: 交集, 并集, 差集, 合并两个数组, 去重合并, 共同部分 -->
|
||||
|
||||
下面这组最小例子展示“按行运算”和“结果会折叠重复行”:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -193,10 +192,12 @@ outersect_rows := left_rows outersect right_rows;
|
||||
|
||||
## 和过滤运算的区别
|
||||
|
||||
<!-- tags: 集合还是过滤, 重复行怎么办, 两种运算怎么选 -->
|
||||
|
||||
- 集合运算先把数据当成“行集合”来看,再做包含、并交差。
|
||||
- 过滤运算先保留“原结果集里的每一条命中记录”;因此重复行会保留下来。
|
||||
- 需要“集合关系”时留在本页。
|
||||
- “从原表里筛出哪些行”的过滤规则见 [13_resultset_and_filters.md](13_resultset_and_filters.md)。
|
||||
- “从原表里筛出哪些行”的过滤规则见 [12_resultset_and_filters.md](12_resultset_and_filters.md)。
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
@@ -211,6 +212,8 @@ row_matched := array(1, 2) sqlin array((1, 2), (3, 4));
|
||||
|
||||
## 点前缀比较算符产生逻辑数组
|
||||
|
||||
<!-- tags: 逐元素比较, 得到真假数组, 批量判断, 掩码 -->
|
||||
|
||||
点前缀比较(`.=`、`.<>`、`.>`、`.>=`、`.<`、`.<=`)对数组/矩阵逐元素比较,返回真假值数组:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -270,10 +273,12 @@ writeLn("子集 (1,0):", subset[1][0]);
|
||||
- `a[:, 0] .> 0.5` 提取第 0 列并逐元素比较,得到逻辑数组 `array(0, 1, 1)`
|
||||
- `mfind(逻辑数组)` 把真值位置转换成下标数组 `array(1, 2)`
|
||||
- `a[indexes]` 按下标提取对应行,等价于 `select * from a where [0] > 0.5 end`
|
||||
- `mfind` 的完整用法见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)
|
||||
- `mfind` 的完整用法见 [21_matrix_deep_dive.md](21_matrix_deep_dive.md)
|
||||
|
||||
## 非完全矩阵缺位当 0 处理与标量广播
|
||||
|
||||
<!-- tags: 长度不一致, 缺位补零, 标量广播, 数组和数字运算 -->
|
||||
|
||||
基础算符作用于非完全矩阵(行长度不一致或字符串键不对齐的数组)时,对应位置不存在或为 `nil` 时**默认当 0 处理**:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -327,7 +332,7 @@ writeLn("(1,1):", result[1][1]);
|
||||
|
||||
- 标量 `+`、`-`、`*`、`/` 等作用于矩阵时,会广播到每个元素
|
||||
- `matrix_value + 10` 每个元素都加 10
|
||||
- 这些是逐元素运算(element-wise),区别于矩阵乘法 `:*`,见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)
|
||||
- 这些是逐元素运算(element-wise),区别于矩阵乘法 `:*`,见 [21_matrix_deep_dive.md](21_matrix_deep_dive.md)
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
@@ -335,7 +340,7 @@ writeLn("(1,1):", result[1][1]);
|
||||
- TS-SQL 查询与写回
|
||||
- 更大范围的矩阵函数族
|
||||
|
||||
这些内容的事实分别见 [13_resultset_and_filters.md](13_resultset_and_filters.md)、[14_ts_sql.md](14_ts_sql.md)、[22_matrix_deep_dive.md](22_matrix_deep_dive.md) 和 [23_fmarray.md](23_fmarray.md)。
|
||||
这些名称只作为边界提示,不作为本页可生成模板。
|
||||
|
||||
## 禁止项
|
||||
|
||||
@@ -347,8 +352,8 @@ writeLn("(1,1):", result[1][1]);
|
||||
- 不要把二维结果集默认当成“按元素逐个比较”的集合运算。
|
||||
- 左侧数组要表达“这些值是否都属于右侧集合”时,用 `in`。
|
||||
- 左侧数组要表达“这一整行是否存在于右侧结果集”时,用 `sqlin`。
|
||||
- `minus` 表达集合差集;保留左侧原始重复次数的过滤规则见 [13_resultset_and_filters.md](13_resultset_and_filters.md)。
|
||||
- `minus` 表达集合差集;保留左侧原始重复次数的过滤规则见 [12_resultset_and_filters.md](12_resultset_and_filters.md)。
|
||||
- 不要在本页发明结果集过滤、TS-SQL 查询、写回语法或更大矩阵函数族。
|
||||
- 不要把普通 `array(...)` 自动升级成 `FMArray`;`FMArray` 专属事实见 [23_fmarray.md](23_fmarray.md)。
|
||||
- 不要把普通 `array(...)` 自动升级成 `FMArray`;`FMArray` 专属事实见 [22_fmarray.md](22_fmarray.md)。
|
||||
- 不要把点前缀比较 `.>` 和矩阵链式比较 `::>` 混用;`.>` 返回逻辑数组,`::>` 是链式比较。
|
||||
- 不要以为非完全矩阵缺位会报错;默认当 `0` 处理。
|
||||
@@ -1,196 +0,0 @@
|
||||
# TSL 高频误写
|
||||
|
||||
这一篇不讲新知识,只做反例索引。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“哪些写法最容易凭直觉写出来,但在 TSL 里会编译失败、运行出错,或语义并不可靠”。
|
||||
|
||||
## 智能体常见误写判断流程
|
||||
|
||||
1. 先识别用户写法属于值、变量、函数、表达式、对象、`unit`、TS-SQL 还是外部调用误区。
|
||||
2. 遇到本页反例时,不要修成相邻语言习惯,必须以对应语法页的可直接照写示例为准。
|
||||
3. 反例只用于排错和避免误写,不作为可照写模板。
|
||||
4. 修复时保留 `.tsl` / `.tsf` 文件模型判断,不要只改局部语句。
|
||||
5. 没有对应条目时不要发明替代语法。
|
||||
|
||||
## 这页怎么用
|
||||
|
||||
- 先按主题识别反例,再以对应正文的正确写法为准。
|
||||
- 这里不重复讲完整规则,只保留“错法 -> 正确页”的索引。
|
||||
- 只有已经有明确反例边界的误写,才会列在这里。
|
||||
- 细节型边界放回对应专题页;本页只保留最容易诱导智能体写错的高频误写。
|
||||
|
||||
## 反例索引
|
||||
|
||||
### 文件模型与基础值
|
||||
|
||||
#### 1. 把裸 `class Name` 当成顶层类声明
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
class Person
|
||||
end;
|
||||
```
|
||||
|
||||
这会编译失败。正确页:见 [08_objects_and_classes.md](08_objects_and_classes.md)
|
||||
|
||||
#### 2. 把 `=` 当成赋值
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
a = 1;
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
invalid statement
|
||||
```
|
||||
|
||||
这会编译失败。正确页:见 [06_expressions_and_operators.md](06_expressions_and_operators.md)
|
||||
|
||||
#### 3. 把字符串当成 0 基下标
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
s := "ABC";
|
||||
writeLn(s[0]);
|
||||
```
|
||||
|
||||
这会在运行时报字符串下标越界。正确页:见 [03_values_and_literals.md](03_values_and_literals.md)
|
||||
|
||||
#### 4. 在 `.tsl` 声明区后面继续写脚本语句
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
a := 1;
|
||||
test();
|
||||
|
||||
function test();
|
||||
begin
|
||||
echo "test";
|
||||
end;
|
||||
|
||||
echo "after declaration";
|
||||
```
|
||||
|
||||
`.tsl` 可以有语句区和声明区,但顺序必须清楚:语句区在前并按顺序执行,函数 / 类声明区在后。不要在声明区后面继续写脚本语句。正确页:见 [02_core_model.md](02_core_model.md)
|
||||
|
||||
### 函数与调用
|
||||
|
||||
#### 5. 把 `a = 1` 当成命名参数
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
Pack(a = 1, b = 2);
|
||||
```
|
||||
|
||||
不要把这当成可靠的命名参数写法。它虽然可能编译通过,但返回结果不符合命名参数预期。正确页:见 [05_functions_and_calls.md](05_functions_and_calls.md)
|
||||
|
||||
#### 6. 把 `like` 当成 SQL `%` / `_` 通配
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
writeLn("abc" like "a%");
|
||||
```
|
||||
|
||||
这里输出 `0`,不要按 SQL `LIKE` 去理解。本手册中,`like` 的右侧按正则模式解释。正确页:见 [06_expressions_and_operators.md](06_expressions_and_operators.md)
|
||||
|
||||
### `unit` / `uses`
|
||||
|
||||
#### 7. 把函数体或类定义体里的 `uses` 写错位置,或重复写第二个 `uses`
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
function Run();
|
||||
begin
|
||||
a := 1;
|
||||
uses DemoUnit;
|
||||
return Ping();
|
||||
end;
|
||||
|
||||
type Worker = class
|
||||
uses UnitA;
|
||||
uses UnitB;
|
||||
end;
|
||||
```
|
||||
|
||||
上面这两类写法都会失败。函数里的错法会报 `invalid statement`,类里的错法会报 `invalid class definition`。失败点分别是:函数体里的 `uses` 不是第一条语句;类定义体里出现了第二条 `uses`。
|
||||
|
||||
注意:这个反例只针对函数体和类定义体里的 `uses`;需要多个 `unit` 时,默认回到顶层写成单条 `uses UnitA, UnitB;`。正确页:见 [09_units_and_scope.md](09_units_and_scope.md)
|
||||
|
||||
### 类与对象
|
||||
|
||||
#### 8. 把裸类名当成 `class function` 或静态字段的直接访问入口
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
MathBox.Add(1, 2);
|
||||
|
||||
THuman.mCount := 7;
|
||||
```
|
||||
|
||||
这两种写法都不作为可写事实。可用写法是先拿到类类型,再用 `class(MathBox).Add(...)` / `findClass("MathBox").Add(...)` 调类方法,以及 `class(THuman).mCount` 访问静态字段。正确页:见 [08_objects_and_classes.md](08_objects_and_classes.md)
|
||||
|
||||
#### 9. 把 `private` / `protected create` 当成一定会执行的构造函数
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
a := new A(111);
|
||||
writeLn(a.value);
|
||||
|
||||
type A = class
|
||||
public
|
||||
value;
|
||||
private
|
||||
function create(v);
|
||||
begin
|
||||
value := v;
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
这不会报“不能创建对象”,但 `create` 不会执行;上面的 `a.value` 输出 `<NIL>`。正确页:见 [08_objects_and_classes.md](08_objects_and_classes.md)
|
||||
|
||||
#### 10. 在子类里把父类 `private` 成员当成 `protected` 成员用
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
b := new B();
|
||||
writeLn(b.TryCall());
|
||||
|
||||
type A = class
|
||||
private
|
||||
function Hidden();
|
||||
begin
|
||||
return 77;
|
||||
end;
|
||||
end;
|
||||
type B = class(A)
|
||||
public
|
||||
function TryCall();
|
||||
begin
|
||||
return Hidden();
|
||||
end;
|
||||
end;
|
||||
```
|
||||
|
||||
这会在执行时报父类 `private` 方法不可访问。正确页:见 [08_objects_and_classes.md](08_objects_and_classes.md)
|
||||
|
||||
## 禁止项收口
|
||||
|
||||
- 不要把本页任何 `反例 / 不可照写` 代码块改写成默认正向模板。
|
||||
- 不要只凭 Pascal、JavaScript、Python 或 SQL 直觉修正 TSL 写法。
|
||||
- 不要在本页发明替代语法;每个反例都以条目末尾标出的正确专题页为准。
|
||||
- 不要把反例边界写成可用语法。
|
||||
+13
-11
@@ -6,15 +6,6 @@
|
||||
|
||||
回答“已有数组或二维结果集时,想按某个过滤集保留命中的行、排除命中的行,或者只拿到符合条件的行下标时,应该怎么写”。
|
||||
|
||||
## 智能体结果集/过滤判断流程
|
||||
|
||||
1. 先判断任务是 `filterIn(...)` / `filterNotIn(...)` 过滤、结果集字段访问、去重型集合运算,还是 TS-SQL 查询。
|
||||
2. 字段访问优先照本页明确的字符串键或结果集字段形态写。
|
||||
3. 复杂查询的语法事实见 [14_ts_sql.md](14_ts_sql.md),不要把查询语法硬塞进过滤函数。
|
||||
4. `in` / `sqlin` / `union2` / `intersect` / `minus` / `outersect` 这类去重型集合关系的事实见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。
|
||||
5. 金融数据筛选要先确认数据来源;函数事实使用 `tsl-api-reference` skill 查询,项目字段和业务上下文以项目实际接口为准。
|
||||
6. 没有对应代码块时不要发明结果集/过滤写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 结果集过滤主函数是 `filterIn(...)` 和 `filterNotIn(...)`。
|
||||
@@ -24,12 +15,15 @@
|
||||
- `Field` 写成 `nil` 时,表示按整行过滤;一维数组也走这个入口。
|
||||
- `Field` 写成 `array("A", "B")` 这类字段名数组时,表示只按这些列做匹配。
|
||||
- 过滤运算不会自动去重;原结果集里有重复行时,命中的重复行会原样保留下来。
|
||||
- 去重型的并、交、差运算不放在这一篇,见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。
|
||||
- 去重型的并、交、差运算不放在这一篇,见 [11_matrix_and_collections.md](11_matrix_and_collections.md)。
|
||||
- 本页只拥有过滤语法外形。金融数据筛选要先确认数据来源:取数函数的签名和返回结构属于 `tsl-api-reference` skill,项目字段和业务上下文以项目实际接口为准,不要从过滤示例里的字段名反推真实数据结构。
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
### 按单列过滤
|
||||
|
||||
<!-- tags: 筛选行, 按某列筛, 只要满足条件的, 排除某些行 -->
|
||||
|
||||
按 `"Code"` 列做包含与排除:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -66,6 +60,8 @@ writeLn(drop_rows[1]["Code"]);
|
||||
|
||||
### 返回行下标
|
||||
|
||||
<!-- tags: 拿到行号, 返回位置, 只要下标不要数据 -->
|
||||
|
||||
第四个参数写成 `false` 时,返回行下标而不是子结果集:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -105,6 +101,8 @@ picked := rows[keep_index, array("Code", "V1")];
|
||||
|
||||
### `Field = nil` 时按整行过滤
|
||||
|
||||
<!-- tags: 整行匹配, 一维数组过滤, 不指定列筛 -->
|
||||
|
||||
整行过滤与一维数组过滤都走 `Field = nil`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -133,6 +131,8 @@ left_only := filterNotIn(array(1, 2, 3, 4, 5, 5, 6, 7), array(1, 2, 3, 4), nil);
|
||||
|
||||
### 按字段列表过滤
|
||||
|
||||
<!-- tags: 多列判断, 按几个字段筛, 指定字段范围 -->
|
||||
|
||||
如果只想按部分列判断是否命中,把 `Field` 写成字段名数组:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -161,10 +161,12 @@ sub_result := rows[keep_index, array("A", "C")];
|
||||
|
||||
## 和集合运算的区别
|
||||
|
||||
<!-- tags: 过滤还是集合, 重复记录保留, 两种运算怎么选 -->
|
||||
|
||||
- 过滤运算按“原结果集中的每一行是否命中”来决定保留或排除。
|
||||
- 集合运算按“行集合”来做并、交、差;结果默认会折叠重复行。
|
||||
- 保留重复记录的过滤规则由本页负责。
|
||||
- 去重后的并集、交集、差集事实见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。
|
||||
- 去重后的并集、交集、差集事实见 [11_matrix_and_collections.md](11_matrix_and_collections.md)。
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
+50
-11
@@ -6,17 +6,6 @@
|
||||
|
||||
回答“写 TS-SQL 查询和写回时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接(含 LEFT JOIN)、组内子查询、极值引用,以及如何用 `insert`/`update`/`delete` 修改内存数组”。
|
||||
|
||||
## 智能体 TS-SQL 判断流程
|
||||
|
||||
1. 先判断要写查询(`select`/`sselect`/`vselect`/`mselect`)还是写回(`insert`/`update`/`delete`)。
|
||||
2. 内存数组查询优先从 `select ... from source_rows end` 最小骨架起手。
|
||||
3. 二维结果集字段访问用 `["字段名"]`;多表查询字段访问用 `[表序号].["字段名"]`。
|
||||
4. 在一维数组上做 TS-SQL 时,优先使用 `thisRow` 和 `thisRowIndex`。
|
||||
5. 联接选 `join` / `left join` / `right join` / `full join` / `cross join` / 逗号联接;等值联接可用 `with(... on ...)` 优化。
|
||||
6. 聚集统一形态 `(Expr, Cond, N, MovingFirst, CacheId)`:条件聚集传 `Cond`,移动聚集传 `N`;分组后筛选用 `having`;自定义聚集用 `aggof`。
|
||||
7. 按已有结果集保留/排除行、去重型集合关系、`FMArray` 查询或写回边界的事实分别见 [13_resultset_and_filters.md](13_resultset_and_filters.md)、[12_matrix_and_collections.md](12_matrix_and_collections.md)、[23_fmarray.md](23_fmarray.md)。
|
||||
8. 没有对应代码块时不要发明 TS-SQL 写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- TS-SQL 是 TSL 自带的类 SQL 查询语法,不是金融业务函数库。
|
||||
@@ -42,6 +31,8 @@
|
||||
|
||||
### 最小查询骨架
|
||||
|
||||
<!-- tags: 怎么写查询, 最简 select, 查数组, 内存表查询 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -67,6 +58,8 @@ writeLn(length(query_result));
|
||||
|
||||
### 字段选择
|
||||
|
||||
<!-- tags: 选哪些列, 只取部分字段, 指定列, 输出字段 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -87,6 +80,8 @@ writeLn(length(query_result));
|
||||
|
||||
### 四个查询入口怎样分工
|
||||
|
||||
<!-- tags: select 和 sselect 区别, vselect, mselect, 返回什么形态, 该用哪个查询 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -111,6 +106,8 @@ col_index := mcols(matrix_result, 1);
|
||||
|
||||
### `where` 和 `order by`
|
||||
|
||||
<!-- tags: 条件筛选, 排序, 按某列排, 倒序, 只要满足条件的行 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -130,6 +127,8 @@ query_result := select * from source_rows where ["B"] > 1 order by ["B"] end;
|
||||
|
||||
### `group by`
|
||||
|
||||
<!-- tags: 分组, 汇总, 聚合统计, 按类别合计 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -154,6 +153,8 @@ group_result := select ["A"], sumOf(["B"]) as "SumB"
|
||||
|
||||
### 一维数组上的 `thisRow` 与 `thisRowIndex`
|
||||
|
||||
<!-- tags: 当前行, 当前行号, 一维数组查询 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -175,6 +176,8 @@ query_result := select thisRow as "Value", thisRowIndex as "Idx"
|
||||
|
||||
### `join`
|
||||
|
||||
<!-- tags: 两表关联, 表连接, 按键匹配, 拼接两张表 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -212,6 +215,8 @@ writeLn(join_result[0]["V2"]);
|
||||
|
||||
### `thisGroup`
|
||||
|
||||
<!-- tags: 组内数据, 分组明细, 取当前组 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -237,6 +242,8 @@ group_result := select ["A"], max_b := maxOf(["B"]) as "MaxB",
|
||||
|
||||
### `thisRowIndex` 在排序后仍指向原始位置
|
||||
|
||||
<!-- tags: 排序后原始行号, 原位置, 排序不改下标 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -258,6 +265,8 @@ query_result := select thisRowIndex as "Idx", ["B"]
|
||||
|
||||
### `refMaxOf` 与 `refMinOf`
|
||||
|
||||
<!-- tags: 取最大值那行, 取最小值对应字段, 谁最大, 极值行 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -274,6 +283,8 @@ min_ref_result := select minOf([0]) as "MinA", refMinOf([1]) as "RefB" from sour
|
||||
|
||||
### `LEFT JOIN` 多表联接
|
||||
|
||||
<!-- tags: 左连接, 左联接, 保留左表, 右边没有就空 -->
|
||||
|
||||
`left join` 保留左表所有行,右表不匹配时用 `nil` 填充:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -311,6 +322,8 @@ writeLn("(1,1):", result[1]["vb"]);
|
||||
|
||||
### `right join` / `full join` / `cross join` 与逗号联接
|
||||
|
||||
<!-- tags: 右连接, 全连接, 笛卡尔积, 交叉联接 -->
|
||||
|
||||
`right join` / `full join` 的不匹配行同样用 `nil` 填充:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -410,6 +423,8 @@ writeLn("(0,0):", result[0]["id"]);
|
||||
|
||||
### `INSERT` 写回
|
||||
|
||||
<!-- tags: 插入行, 新增记录, 往数组加数据 -->
|
||||
|
||||
`insert into` 向内存数组插入新行:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -465,6 +480,8 @@ writeLn(a[2]["id"], a[2]["cls"]);
|
||||
|
||||
### `UPDATE` 写回
|
||||
|
||||
<!-- tags: 更新行, 改字段值, 批量修改 -->
|
||||
|
||||
`update` 修改符合条件的行:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -516,6 +533,8 @@ writeLn(r[0], r[1], r[2]);
|
||||
|
||||
### `DELETE` 写回
|
||||
|
||||
<!-- tags: 删除行, 删掉记录, 按条件删 -->
|
||||
|
||||
`delete` 删除符合条件的行:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -563,6 +582,8 @@ writeLn(mrows(a));
|
||||
|
||||
### `distinct` 结果集去重
|
||||
|
||||
<!-- tags: 去重, 不要重复行, 唯一值 -->
|
||||
|
||||
`select distinct` 对结果集去重;聚集函数内也可用 `distinct` 前缀:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -592,6 +613,8 @@ writeLn(plain_sum);
|
||||
|
||||
### `as` 别名、`as nil` 与字段区间
|
||||
|
||||
<!-- tags: 改列名, 起别名, 丢弃字段, 字段区间 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -620,6 +643,8 @@ writeLn(mcols(range_rows));
|
||||
|
||||
### `drange` 取行区间
|
||||
|
||||
<!-- tags: 取前几行, 分页, 行区间, 只要一段 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -647,6 +672,8 @@ writeLn(mrows(part_rows));
|
||||
|
||||
### `selectopt` 位选项
|
||||
|
||||
<!-- tags: 查询选项, 返回形态控制, 位标志 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -670,6 +697,8 @@ writeLn(opt_rows[0]);
|
||||
|
||||
### 条件聚集、移动聚集与 `refof`
|
||||
|
||||
<!-- tags: 条件求和, 滑动窗口, 移动平均, 带条件的聚合 -->
|
||||
|
||||
聚集函数统一支持 `(Expr, BoolConditionExp, N, MovingFirst, CacheId)` 形态:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -700,6 +729,8 @@ writeLn(ref_prev[1]["Expr1"]);
|
||||
|
||||
### `group by ... having`
|
||||
|
||||
<!-- tags: 分组后筛选, 聚合条件, 组级过滤 -->
|
||||
|
||||
`having` 用聚集条件筛选分组(`where` 不能用聚集):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -733,6 +764,8 @@ having_rows := select ["cls"] from a group by ["cls"] having countof(*) > 1 end;
|
||||
|
||||
### `thisOrder` 与多列 `order by`
|
||||
|
||||
<!-- tags: 多列排序, 排名, 序号, 先按 A 再按 B -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -758,6 +791,8 @@ writeLn(desc_rows[0]["id"]);
|
||||
|
||||
### `refsof` 引用上级结果集
|
||||
|
||||
<!-- tags: 子查询取外层, 嵌套查询, 引用上一层 -->
|
||||
|
||||
在嵌套子查询里,`refsof(Exp, UpLevel)` 用上 N 级结果集计算 `Exp`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -783,6 +818,8 @@ writeLn(r[1]["id"], ",", r[1]["up"]);
|
||||
|
||||
### `[@Field]` 取字段类型
|
||||
|
||||
<!-- tags: 字段类型, 列的数据类型 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -803,6 +840,8 @@ integer
|
||||
|
||||
### `aggof` 自定义聚集扩展
|
||||
|
||||
<!-- tags: 自定义聚合, 自己写聚集函数 -->
|
||||
|
||||
`aggof('名称', 表达式)` 调用一个自定义回调函数做聚集。本地 `TSL.exe` 会报 `AggOf Init Error`;下例在服务端(pyTSL)验证通过:
|
||||
|
||||
代码块身份:仅服务端可执行示例
|
||||
+12
-8
@@ -6,14 +6,6 @@
|
||||
|
||||
回答“`goto`、`debugReturn`、`debugRunEnv`、`mtic` / `mtoc`、`setProfiler`、`__line__` 和 `__stack_frame` 怎样写、会怎样表现”。
|
||||
|
||||
## 智能体调试/性能分析器判断流程
|
||||
|
||||
1. 先判断任务需要跳转、提前返回、运行环境调试、计时还是性能分析器。
|
||||
2. 普通控制流的事实见 [07_control_flow.md](07_control_flow.md),本页只处理调试补充工具。
|
||||
3. `debugReturn` 会结束整段脚本,不能当成普通函数返回。
|
||||
4. 计时和性能分析器只照文档最小调用写,不要补未写入文档参数。
|
||||
5. 没有对应代码块时不要发明调试/性能分析器写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
本页示例只说明调试与分析结构中的调用位置和源码外形。相关 API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。
|
||||
@@ -33,6 +25,8 @@
|
||||
|
||||
### `goto`
|
||||
|
||||
<!-- tags: 跳转, 跳出多重循环, 标签跳转 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -97,6 +91,8 @@ writeLn("after");
|
||||
|
||||
### `debugReturn`
|
||||
|
||||
<!-- tags: 中途看返回值, 调试返回, 提前打断 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -118,6 +114,8 @@ end;
|
||||
|
||||
### `debugRunEnv` 与 `debugRunEnvDo`
|
||||
|
||||
<!-- tags: 调试环境, 运行环境切换, 调试开关 -->
|
||||
|
||||
`debugRunEnv(0)` / `debugRunEnv(1)`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -158,6 +156,8 @@ end;
|
||||
|
||||
### `mtic` 与 `mtoc`
|
||||
|
||||
<!-- tags: 计时, 测耗时, 跑了多久, 秒表, 执行时间 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -181,6 +181,8 @@ writeLn(elapsed2 >= 0);
|
||||
|
||||
### `setProfiler` 与 `getProfilerInfo`
|
||||
|
||||
<!-- tags: 性能分析, 找瓶颈, profiler, 哪段最慢 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -201,6 +203,8 @@ writeLn(length(info) > 0);
|
||||
|
||||
### `__line__` 与 `__stack_frame`
|
||||
|
||||
<!-- tags: 当前行号, 调用栈, 堆栈信息, 报错在哪一行 -->
|
||||
|
||||
`__line__`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
+17
-13
@@ -4,15 +4,7 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“TSL 的词法层规则和编译期开关应该去哪里查,而不是把这些边界混进值、函数、类的正文里”。
|
||||
|
||||
## 智能体词法/编译选项判断流程
|
||||
|
||||
1. 先判断要写注释、标识符、条件编译,还是编译选项。
|
||||
2. 注释、大小写、条件编译指令只照本页文档明确形态写。
|
||||
3. `{$explicit+}` 会改变变量声明要求,生成代码前先判断是否需要 `var`。
|
||||
4. `{$varByRef+}` / `{$varByRef-}` 会影响未修饰形参传递语义,细节以函数页事实为准。
|
||||
5. 没有对应代码块时不要发明词法/编译选项写法。
|
||||
回答“TSL 的词法层规则和编译期开关有哪些”:标识符与大小写、注释形态、保留字清单,以及 `{$...}` 编译开关的书写位置和作用范围。
|
||||
|
||||
## 核心规则
|
||||
|
||||
@@ -28,6 +20,8 @@
|
||||
|
||||
## 保留字/关键字速查
|
||||
|
||||
<!-- tags: 关键字列表, 保留字, 哪些名字不能用 -->
|
||||
|
||||
TSL 关键字大小写无关;本表统一按文档推荐写法展示。生成代码时不要把这些名称用作普通标识符。
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
@@ -36,15 +30,15 @@ TSL 关键字大小写无关;本表统一按文档推荐写法展示。生成
|
||||
| 程序与函数结构 | `program`、`function`、`procedure`、`begin`、`end`、`return`、`exit` | 默认写函数时使用 `function`;`procedure` 只在用户明确要求时使用。 |
|
||||
| 控制流 | `if`、`then`、`else`、`case`、`of`、`for`、`to`、`downto`、`step`、`while`、`do`、`repeat`、`until`、`break`、`continue`、`goto`、`label` | 具体语句形态见 [07_control_flow.md](07_control_flow.md)。 |
|
||||
| 异常控制 | `try`、`except`、`finally`、`raise`、`exceptObject` | 异常语法见 [07_control_flow.md](07_control_flow.md)。 |
|
||||
| 值与容器 | `nil`、`true`、`false`、`nan`、`inf`、`array` | 字面量与数组基础见 [03_values_and_literals.md](03_values_and_literals.md) 和 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 |
|
||||
| 值与容器 | `nil`、`true`、`false`、`nan`、`inf`、`array` | 字面量与数组基础见 [03_values_and_literals.md](03_values_and_literals.md) 和 [11_matrix_and_collections.md](11_matrix_and_collections.md)。 |
|
||||
| 运算关键字 | `and`、`or`、`not`、`in`、`sqlin`、`like`、`is`、`div`、`mod`、`shl`、`shr`、`rol`、`ror` | 运算符规则见 [06_expressions_and_operators.md](06_expressions_and_operators.md)。 |
|
||||
| 参数访问 | `params`、`paramCount`、`realParamCount`、`var`、`out`、`const` | 普通参数优先写具名形参;`params` / `paramCount` / `realParamCount` 只用于变参或参数个数判断。 |
|
||||
| 运行时上下文 | `sysParams`、`system`、`debugReturn`、`debugRunEnv`、`debugRunEnvDo`、`echo`、`global`、`static`、`thisFunction`、`_myMem_`、`_maxMem_`、`__line__`、`__stack_frame` | 运行时系统参数见 [10_runtime_context_and_with.md](10_runtime_context_and_with.md);调试相关事实见 [15_debug_and_profiler.md](15_debug_and_profiler.md)。 |
|
||||
| 运行时上下文 | `sysParams`、`system`、`debugReturn`、`debugRunEnv`、`debugRunEnvDo`、`echo`、`global`、`static`、`thisFunction`、`_myMem_`、`_maxMem_`、`__line__`、`__stack_frame` | 运行时系统参数见 [10_runtime_context_and_with.md](10_runtime_context_and_with.md);调试相关事实见 [14_debug_and_profiler.md](14_debug_and_profiler.md)。 |
|
||||
| LIKE 精度 | `likeEps`、`likeEpsRate` | 只在需要调整 `like` 数值近似判断阈值时使用。 |
|
||||
| 类与对象 | `type`、`class`、`new`、`findClass`、`findFunction`、`fackClass`、`property`、`self`、`virtual`、`override`、`overload`、`protected`、`public`、`private`、`published`、`static` | 类声明、对象创建和成员规则见 [08_objects_and_classes.md](08_objects_and_classes.md)。 |
|
||||
| 外部调用约定 | `external`、`cdecl`、`pascal`、`stdcall`、`safecall`、`fastcall`、`register` | 外部调用细节见 [18_external_calls_and_threads.md](18_external_calls_and_threads.md)。 |
|
||||
| 外部调用约定 | `external`、`cdecl`、`pascal`、`stdcall`、`safecall`、`fastcall`、`register` | 外部调用细节见 [17_external_calls_and_threads.md](17_external_calls_and_threads.md)。 |
|
||||
| 客户端远程调用与权限 | `rdo`、`rdo2`、`sudo`、`setUid` | 平台/客户端远程调用和权限语义不作为普通本地语法模板。 |
|
||||
| TS-SQL 查询 | `select`、`vselect`、`sselect`、`mselect`、`distinct`、`selectOpt`、`dRange`、`as`、`from`、`marketTable`、`infoTable`、`tradeTable`、`sqlTable`、`hugeSqlTable`、`keepNull`、`dateKey`、`of`、`order`、`by`、`where`、`desc`、`asc`、`group`、`having` | 查询语法见 [14_ts_sql.md](14_ts_sql.md)。 |
|
||||
| TS-SQL 查询 | `select`、`vselect`、`sselect`、`mselect`、`distinct`、`selectOpt`、`dRange`、`as`、`from`、`marketTable`、`infoTable`、`tradeTable`、`sqlTable`、`hugeSqlTable`、`keepNull`、`dateKey`、`of`、`order`、`by`、`where`、`desc`、`asc`、`group`、`having` | 查询语法见 [13_ts_sql.md](13_ts_sql.md)。 |
|
||||
| TS-SQL 聚合与上下文 | `checksumOf`、`countOf`、`sumOf`、`maxOf`、`stdevOf`、`varOf`、`totalVarOf`、`normOf`、`medianOf`、`aveDevOf`、`geoMeanOf`、`skewOf`、`kurtosisOf`、`skew2Of`、`kurtosis2Of`、`largeOf`、`percentileOf`、`quartileOf`、`trimMeanOf`、`avgOf`、`minOf`、`aggOf`、`stdevpOf`、`varpOf`、`modeOf`、`devSqOf`、`harMeanOf`、`checksum_aggOf`、`smallOf`、`percentRankOf`、`rankOf`、`frequencyOf`、`productOf`、`refOf`、`refsOf`、`aggValue`、`thisGroup`、`thisRow`、`thisRowIndex`、`thisOrder` | 这些名称只在 TS-SQL 语境中生成。 |
|
||||
| TS-SQL 写入 | `insert`、`insertFields`、`values`、`update`、`set`、`delete`、`deleteOpt`、`fetchFirst`、`fetchNext` | 写回/变更型查询只按 TS-SQL 专题页生成。 |
|
||||
| 系统保留未使用 | `exports`、`dispInterface`、`library`、`asm`、`record`、`resourceString`、`threadVar`、`constructor`、`destructor`、`inline`、`packed`、`abstract`、`inherited` | 这些名称被系统保留,不作为普通标识符使用,也不作为可写语法模板。 |
|
||||
@@ -54,6 +48,8 @@ TSL 关键字大小写无关;本表统一按文档推荐写法展示。生成
|
||||
|
||||
### 标识符、注释与条件编译
|
||||
|
||||
<!-- tags: 注释怎么写, 大小写敏感吗, 变量命名, 下划线 -->
|
||||
|
||||
大小写无关与下划线标识符:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -110,6 +106,8 @@ writeLn(40);
|
||||
|
||||
### 显式变量声明开关
|
||||
|
||||
<!-- tags: 强制声明变量, explicit, 必须先 var -->
|
||||
|
||||
`{$explicit+}` 的文档明确形态:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -146,6 +144,8 @@ writeLn(a + b);
|
||||
|
||||
### 条件编译分支边界
|
||||
|
||||
<!-- tags: 条件编译, 未命中分支, ifdef 不编译 -->
|
||||
|
||||
条件编译不会去编译未命中的坏代码分支:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -166,6 +166,8 @@ writeLn(1);
|
||||
|
||||
### `{$CompileOption}` 编译选项
|
||||
|
||||
<!-- tags: 编译开关, 编译器选项, 改默认行为 -->
|
||||
|
||||
`{$CompileOption}` 用于设置编译期开关,改变编译器的默认行为:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -190,6 +192,8 @@ echo 1 + 1;
|
||||
|
||||
### 参数默认传递开关
|
||||
|
||||
<!-- tags: 全局改传参方式, varByRef 开关, 默认按值还是按引用 -->
|
||||
|
||||
`{$varByRef-}` 与 `{$varByRef+}`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
+10
-11
@@ -4,16 +4,7 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“当问题不再是怎么声明变量或书写普通字面量,而是运行时值会变成什么类型、默认值是什么、怎样显式转换、复数怎样表示时,应该看哪里”。`var` / `const` 声明选择和编译期开关的事实分别见 [04_variables_and_constants.md](04_variables_and_constants.md)、[16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。
|
||||
|
||||
## 智能体类型/转换判断流程
|
||||
|
||||
1. 先判断要写数值字面量、日期时间、真假值、nil、复数,还是类型转换边界。
|
||||
2. 整数、实数、日期时间、特殊实数和复数只照本页文档字面量写。
|
||||
3. 不要把能编译的混合类型表达式误判为能按预期自动转换。
|
||||
4. `var` / `const` 声明选择和 `{$explicit+}` / `{$explicit-}` 等编译选项的事实分别见 [04_variables_and_constants.md](04_variables_and_constants.md)、[16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。
|
||||
5. 字符串字面量、编码和文本边界的事实见 [03_values_and_literals.md](03_values_and_literals.md)。
|
||||
6. 没有对应代码块时不要发明类型/转换写法。
|
||||
回答“运行时值会变成什么类型、默认值是什么、怎样显式转换、复数怎样表示”。本页拥有数值 / 日期时间 / 真假值 / nil / 复数字面量与类型转换边界;变量声明形式和编译期开关不在本页收口。
|
||||
|
||||
## 核心规则
|
||||
|
||||
@@ -46,6 +37,8 @@
|
||||
|
||||
### 数值、日期与真值
|
||||
|
||||
<!-- tags: 整数小数, 十六进制, 日期字面量, 真假值, 判断类型 -->
|
||||
|
||||
基础数字字面量与类型判定:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -127,6 +120,8 @@ writeLn(nan = nan);
|
||||
|
||||
### 初始值与空值
|
||||
|
||||
<!-- tags: 变量默认值, nil, 空值, 没赋值是什么 -->
|
||||
|
||||
变量初始值与缺失值:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -204,6 +199,8 @@ writeLn(ifNumber("100"));
|
||||
|
||||
### 显式类型转换
|
||||
|
||||
<!-- tags: 转整数, 转字符串, 类型互转, strToInt -->
|
||||
|
||||
显式类型转换的正向例子:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -222,6 +219,8 @@ writeLn(c);
|
||||
|
||||
### 复数
|
||||
|
||||
<!-- tags: 复数, 虚数, 实部虚部 -->
|
||||
|
||||
复数常量、类型与基础读取:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -334,7 +333,7 @@ writeLn(tostn(a :* b));
|
||||
|
||||
结果说明:
|
||||
|
||||
- 复数矩阵同样用 `:*` 做矩阵乘(区别于逐单元乘 `*`),矩阵乘除乘方算符体系见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)
|
||||
- 复数矩阵同样用 `:*` 做矩阵乘(区别于逐单元乘 `*`),矩阵乘除乘方算符体系见 [21_matrix_deep_dive.md](21_matrix_deep_dive.md)
|
||||
- `a` 是 `2 x 1`、`b` 是 `1 x 2`,`a :* b` 得 `2 x 2` 结果矩阵
|
||||
- 结果是 `array((-4.0+0.0j,-4.0-2.0j),(-8.0-4.0j,-6.0-8.0j))`
|
||||
|
||||
+13
-9
@@ -4,15 +4,7 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“普通函数怎么写已经清楚后,外部 DLL、原生函数指针、C 回调、多线程这些系统交互能力应该去哪里查”。
|
||||
|
||||
## 智能体外部调用/线程判断流程
|
||||
|
||||
1. 先判断要声明外部函数、包装原生函数指针、生成 C 回调,还是处理线程相关能力。
|
||||
2. 外部函数声明只照本页明确的调用约定、`external` 和可选 `name` 形态写。
|
||||
3. DLL 名优先写字面量或文档中的类常量,不要拼接表达式。
|
||||
4. 原生函数指针包装、C 回调和线程相关能力只照本页文档边界写。
|
||||
5. 没有对应代码块时不要发明外部调用/线程写法。
|
||||
回答“外部 DLL 声明、原生函数指针包装、C 回调和多线程调用有哪些文档明确写法”。本页只覆盖系统交互能力,普通 TSL 函数的定义与调用不在本页收口。
|
||||
|
||||
## 核心规则
|
||||
|
||||
@@ -31,6 +23,8 @@
|
||||
|
||||
### 最小 `external` 声明
|
||||
|
||||
<!-- tags: 调外部函数, 声明外部函数, 绑 dll 函数, 导入系统函数 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -105,6 +99,8 @@ function TickCdecl(): int64; cdecl; external "kernel32.dll" name "GetTickCount64
|
||||
|
||||
### `procedure external`
|
||||
|
||||
<!-- tags: 外部过程, 无返回值的外部函数, 调系统 API -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -124,6 +120,8 @@ procedure SleepMs(ms: integer); stdcall; external "kernel32.dll" name "Sleep";
|
||||
|
||||
### 原生函数指针包装
|
||||
|
||||
<!-- tags: LoadLibrary, 拿函数地址, 动态加载, GetProcAddress -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -145,6 +143,8 @@ function GetProcAddress(module_handle: pointer; proc_name: string): pointer; std
|
||||
|
||||
### DLL 名的文档边界
|
||||
|
||||
<!-- tags: dll 名写在哪, 库名怎么给, 常量放路径 -->
|
||||
|
||||
类常量字符串:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -181,6 +181,8 @@ function TickFromExpr(): int64; stdcall; external "kernel32"$"."$"dll" name "Get
|
||||
|
||||
### `makeInstance`
|
||||
|
||||
<!-- tags: 回调函数, 把 TSL 函数给 C 用, 生成函数实例 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -203,6 +205,8 @@ end;
|
||||
|
||||
### 线程模式最小正例
|
||||
|
||||
<!-- tags: 开线程, 多线程, 并发执行, 后台跑 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
+14
-8
@@ -13,14 +13,6 @@
|
||||
- `namespace "..."`、`tsl.conf` 和 `-LIBPATH` 怎样影响 `.tsf` 查找
|
||||
- `syssettsllibpath()` / `sysgettsllibpath()` 怎样在运行时改查找路径
|
||||
|
||||
## 智能体命名空间/Libpath 判断流程
|
||||
|
||||
1. 先判断任务是单元命名空间访问、`-LIBPATH` 查找,还是配置文件查找。
|
||||
2. 路径和查找顺序只写平台中立规则,不写某个开发机或容器路径。
|
||||
3. `-LIBPATH` 只作为运行时部署/查找规则,不写进普通语法示例。
|
||||
4. `Libpath={$P}...` 和 `InheritParent=1` 不作为本页文档能力。
|
||||
5. 没有对应代码块时不要发明命名空间/Libpath 写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 完整 `unit` 形态可以包含 `interface`、`implementation`、`initialization`、`finalization`,并以 `end.` 结束。
|
||||
@@ -43,6 +35,8 @@
|
||||
|
||||
### `unit` 生命周期
|
||||
|
||||
<!-- tags: 模块什么时候初始化, unit 状态, 加载时机, 只初始化一次 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
|
||||
```text
|
||||
@@ -105,6 +99,8 @@ FINAL
|
||||
|
||||
### `unit` 成员的读取边界
|
||||
|
||||
<!-- tags: 读模块常量, 访问 unit 成员, 限定名读取 -->
|
||||
|
||||
直接限定读取:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -246,6 +242,8 @@ DemoUnit.unit_counter := 13;
|
||||
|
||||
### `tslfilename()`
|
||||
|
||||
<!-- tags: 当前脚本路径, 我在哪个文件, 取自身文件名 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -259,6 +257,8 @@ writeLn(tslfilename());
|
||||
|
||||
### `namespace` 与默认命名空间
|
||||
|
||||
<!-- tags: 命名空间, 同名函数归属, 默认空间, 全局与命名空间冲突 -->
|
||||
|
||||
把默认命名空间、脚本覆盖、以及“全局函数与命名空间函数同名”的三组结论压成同一套最小实验:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -304,6 +304,8 @@ writeLn(Hello());
|
||||
|
||||
### `-LIBPATH`
|
||||
|
||||
<!-- tags: 查找路径, 找不到文件, 搜索顺序, 命令行指定路径 -->
|
||||
|
||||
查找顺序:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -357,6 +359,8 @@ tsl .\main.tsl -LIBPATH "D:\libA\,D:\libB\"
|
||||
|
||||
### `syssettsllibpath()` 与 `sysgettsllibpath()`
|
||||
|
||||
<!-- tags: 运行时改查找路径, 读取库路径 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
|
||||
```text
|
||||
@@ -374,6 +378,8 @@ writeLn(call("FnB"));
|
||||
|
||||
### `tsl.conf` 的 `Libpath=`
|
||||
|
||||
<!-- tags: 配置文件, 配路径, tsl.conf 怎么写 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
|
||||
```text
|
||||
+13
-11
@@ -4,17 +4,7 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“类已经会声明、继承、构造之后,怎样检查类信息、函数信息、对象运行时状态、弱引用创建和弱引用访问判定”。普通类编写、对象创建和对象方法调用的事实见 [08_objects_and_classes.md](08_objects_and_classes.md);不要因为本页存在反射或弱引用能力就改写成动态查找。
|
||||
|
||||
## 智能体对象运行时/反射判断流程
|
||||
|
||||
1. 先判断用户是否明确要求运行时类类型、方法句柄、对象状态、对象枚举、反射信息或弱引用/自动弱引用。
|
||||
2. 普通对象创建、普通方法调用、类声明和继承的事实见 [08_objects_and_classes.md](08_objects_and_classes.md),不要把 `findClass(...)` / `createObject(...)` 当默认写法。
|
||||
3. 确实命中反射时,入口优先照 `findClass`、`findFunction`、`thisFunction`、`findOverLoad` 等文档明确示例写。
|
||||
4. 访问弱引用前先做 `checkWeakRef(...)` 判定,不要假设失效弱引用安全返回 `nil`。
|
||||
5. 类内段落式 `weakRef` / `autoRef`(不带分号)是合法的成员弱引用开关;只有带分号的 `weakRef;` / `autoRef;` 才报 `invalid class definition`。
|
||||
6. 函数值调用边界以函数页事实为准,避免把函数指针直接当普通函数调用。
|
||||
7. 没有对应代码块时不要发明对象运行时/反射/弱引用写法。
|
||||
回答“怎样检查类信息、函数信息、对象运行时状态、弱引用创建和弱引用访问判定”。本页拥有反射与运行时状态查询;普通类编写、对象创建和方法调用不在本页收口,也不要因为本页存在反射能力就把普通调用改写成动态查找。
|
||||
|
||||
## 核心规则
|
||||
|
||||
@@ -48,6 +38,8 @@
|
||||
|
||||
### 对象值与类类型
|
||||
|
||||
<!-- tags: 判断是不是对象, 取类类型, 类型识别 -->
|
||||
|
||||
对象值的最小显式判定:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -130,6 +122,8 @@ end;
|
||||
|
||||
### 类信息与对象状态
|
||||
|
||||
<!-- tags: 对象属于哪个类, 反射, 类名, 运行时看类信息 -->
|
||||
|
||||
`classInfo(1)` 返回类类型:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -231,6 +225,8 @@ end;
|
||||
|
||||
### 函数句柄与重载
|
||||
|
||||
<!-- tags: 按名字找函数, 动态调用方法, 拿方法引用 -->
|
||||
|
||||
`findFunction(...)` 查找实例方法和类方法:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -319,6 +315,8 @@ end;
|
||||
|
||||
### 函数信息、对象枚举与生命周期
|
||||
|
||||
<!-- tags: 列出所有对象, 引用计数, 对象什么时候释放, 函数元信息 -->
|
||||
|
||||
`functionInfo` 的文档字段:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -408,6 +406,8 @@ end;
|
||||
|
||||
### 弱引用与自动弱引用
|
||||
|
||||
<!-- tags: 循环引用, 弱引用, 自动释放, 内存泄漏 -->
|
||||
|
||||
弱引用能力的条件编译判定:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -572,6 +572,8 @@ end;
|
||||
|
||||
### 段落式 `weakRef` / `autoRef` 的正确写法
|
||||
|
||||
<!-- tags: 弱引用段落写法, weakRef 不带分号 -->
|
||||
|
||||
段落式 `weakRef` / `autoRef`(不带分号)像 `public` / `private` 一样切换后续成员的弱引用属性:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
+16
-8
@@ -6,14 +6,6 @@
|
||||
|
||||
回答“写普通 TSL/TSF 脚本时,哪些内置对象可以直接创建,最小可用接口是什么,哪些对象其实依赖特定运行上下文”。
|
||||
|
||||
## 智能体内置运行时对象判断流程
|
||||
|
||||
1. 先判断要访问哪个内置运行时对象,以及它是不是语言对象而非业务 API。
|
||||
2. 只照本页明确的最小读写路径使用内置对象。
|
||||
3. 不要把金融业务上下文对象和语言运行时对象混在一起。
|
||||
4. 系统参数和 `with` 后缀的事实见 [10_runtime_context_and_with.md](10_runtime_context_and_with.md)。
|
||||
5. 没有对应代码块时不要发明内置运行时对象写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- `TStringList` 可以直接用 `new TStringList()` 创建。
|
||||
@@ -37,6 +29,8 @@
|
||||
|
||||
### `TStringList`
|
||||
|
||||
<!-- tags: 字符串列表, 存一批字符串, 键值文本, 逗号文本 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -56,6 +50,8 @@ writeLn(list.Count);
|
||||
|
||||
### `THashedStringList`
|
||||
|
||||
<!-- tags: 哈希列表, 快速查名字, 大量键查找 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -73,6 +69,8 @@ writeLn(list["B"]);
|
||||
|
||||
### `TStream` 家族的最小可靠入口:`TMemoryStream` 与 `TFileStream`
|
||||
|
||||
<!-- tags: 内存流, 文件流, 读写文件, 二进制读写, 存到文件 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -128,6 +126,8 @@ writeLn(ifObj(base));
|
||||
|
||||
### `TCipher`
|
||||
|
||||
<!-- tags: 加密解密, 对称加密, 密文 -->
|
||||
|
||||
无参创建反例:
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
@@ -161,6 +161,8 @@ writeLn(cipher.Decrypt(enc));
|
||||
|
||||
### `TRsa`
|
||||
|
||||
<!-- tags: 非对称加密, 公钥私钥, 签名, RSA -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -182,6 +184,8 @@ writeLn(length(rsa.PrivateKey) > 0);
|
||||
|
||||
### `TIniFile` 与 `TMemIniFile`
|
||||
|
||||
<!-- tags: 配置文件读写, ini, 读配置项 -->
|
||||
|
||||
磁盘 INI 文件:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -216,6 +220,8 @@ writeLn(ini.ReadString("S", "K", ""));
|
||||
|
||||
### `MailMsg` 与 `MessagePart`
|
||||
|
||||
<!-- tags: 发邮件, 邮件正文, 附件 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -243,6 +249,8 @@ writeLn(part.Body);
|
||||
|
||||
### `TWebRequest` / `TWebResponse` 的普通脚本边界
|
||||
|
||||
<!-- tags: 网页请求, http 对象, web 环境限制 -->
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```text
|
||||
+26
-14
@@ -1,23 +1,11 @@
|
||||
# TSL 矩阵深水专题
|
||||
|
||||
这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵乘除乘方、矩阵转置、矩阵拼接、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`12` 讲普通数组与集合关系,这一篇讲矩阵专用构造、运算、遍历、子矩阵和矩阵查找接口。
|
||||
这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵乘除乘方、矩阵转置、矩阵拼接、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [11_matrix_and_collections.md](11_matrix_and_collections.md) 的分工是:`11` 讲普通数组与集合关系,这一篇讲矩阵专用构造、运算、遍历、子矩阵和矩阵查找接口。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样进行矩阵乘除乘方,怎样转置矩阵,怎样拼接矩阵,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。
|
||||
|
||||
## 智能体矩阵深水判断流程
|
||||
|
||||
1. 先判断要写矩阵初始化、数列构造、矩阵逆/广义逆、矩阵尺寸与索引读取、矩阵遍历、子矩阵,还是 `mfind` 查找/替换。
|
||||
2. 基础数组与矩阵样比较的事实在 [12_matrix_and_collections.md](12_matrix_and_collections.md)。
|
||||
3. `mrows` / `mcols` / `msize` 等函数只照文档返回形态写。
|
||||
4. 需要逐单元执行语句块时用 `matrix::begin ... end`;需要把表达式结果写回每个单元时用 `matrix ::= expression`。
|
||||
5. 需要遍历到嵌套数组最深层时用 `matrix:.begin ... end` 或 `matrix:.= expression`。
|
||||
6. 子矩阵范围使用 `row_start:row_end`、`:`、下标数组和列范围组合;不要把字符串键当作子矩阵范围序号。
|
||||
7. `mfind(...)` 用于把符合条件的单元格转换成下标列表,或同时返回原值/替换原值。
|
||||
8. 不要把列索引数组误当成单个数字。
|
||||
9. 没有对应代码块时不要发明矩阵深水写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
本页示例只说明矩阵语法中的调用位置、运算结构和源码外形。矩阵 API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。
|
||||
@@ -52,6 +40,8 @@
|
||||
|
||||
### 矩阵初始化
|
||||
|
||||
<!-- tags: 建矩阵, 全零矩阵, 全一矩阵, 单位阵, 初始化二维 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -87,6 +77,8 @@ writeLn(mcols(zeros_2d));
|
||||
|
||||
### `->` 数列数组初始化
|
||||
|
||||
<!-- tags: 生成序列, 等差数列, 从几到几, 连续数字 -->
|
||||
|
||||
默认步长为 `1`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -127,6 +119,8 @@ seq_indexed := array(0, 1, array("A", "B", "C", "D", "E", "F")) -> 5;
|
||||
|
||||
### 矩阵一元倒数 / 逆 / 广义逆:`!A`
|
||||
|
||||
<!-- tags: 求逆, 逆矩阵, 广义逆, 解方程 -->
|
||||
|
||||
方阵输入返回普通矩阵逆:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -192,6 +186,8 @@ writeLn(inverse_value[2][1]);
|
||||
|
||||
### `msize`、`mrows`、`mcols`
|
||||
|
||||
<!-- tags: 矩阵几行几列, 尺寸, 维度大小, 行数列数 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -219,6 +215,8 @@ col_index := mcols(matrix_rows, 1);
|
||||
|
||||
### 矩阵遍历:`::` 与 `::=`
|
||||
|
||||
<!-- tags: 遍历矩阵, 逐格处理, 二维循环, 批量赋值 -->
|
||||
|
||||
`::` 执行语句块:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -269,6 +267,8 @@ writeLn(matrix_value[1][1]);
|
||||
|
||||
### 深度遍历:`:.` 与 `:.=`
|
||||
|
||||
<!-- tags: 遍历嵌套数组, 递归遍历, 最深层元素 -->
|
||||
|
||||
`:.` 会遍历到嵌套数组的最深节点:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -310,6 +310,8 @@ writeLn(values[2]);
|
||||
|
||||
### 子矩阵
|
||||
|
||||
<!-- tags: 取一块, 切片, 按行列范围取, 局部矩阵 -->
|
||||
|
||||
按行列范围提取:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -404,6 +406,8 @@ writeLn(matrix_value[1][1]);
|
||||
|
||||
### `mfind` 与 `mfindSparse`
|
||||
|
||||
<!-- tags: 在矩阵里查找, 找位置, 满足条件的下标, 稀疏查找 -->
|
||||
|
||||
一维数组无条件查找会返回一维下标数组:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -524,6 +528,8 @@ B
|
||||
|
||||
### 矩阵乘法、除法、左除、乘方:`:*`、`:/`、`:\`、`:^`
|
||||
|
||||
<!-- tags: 矩阵相乘, 矩阵乘方, 左除, 区别于逐元素乘 -->
|
||||
|
||||
`:*` 是矩阵乘法(区别于逐元素乘 `*`):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -652,6 +658,8 @@ writeLn(a[0][0]);
|
||||
|
||||
### 基础函数的矩阵广播与异常处理参数
|
||||
|
||||
<!-- tags: 对整个矩阵取整, 函数作用于每个元素, 广播, 出错时给默认值 -->
|
||||
|
||||
多参数基础函数支持逐参数广播:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -749,6 +757,8 @@ array(1,-999,-999,100)
|
||||
|
||||
### 矩阵转置:反引号 `` ` ``
|
||||
|
||||
<!-- tags: 转置, 行列互换, 翻转矩阵 -->
|
||||
|
||||
单次转置交换行列:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -829,6 +839,8 @@ writeLn("行向量 (0,2):", row_vector[0][2]);
|
||||
|
||||
### 矩阵拼接:`union`、`&=`、`|`、`:|`
|
||||
|
||||
<!-- tags: 拼接矩阵, 上下合并, 左右合并, 追加行 -->
|
||||
|
||||
`union` 按行拼接(一维或二维):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -918,7 +930,7 @@ bar 结果 (1,2):2
|
||||
- `union` / `&=` 用于行方向拼接
|
||||
- `|` / `:|` 用于列方向拼接
|
||||
- 普通 `array` 的非完全矩阵(行长度不一致):`:|` 按原列位置对齐、缺位补 `nil`;`|` 把两行元素直接顺接(本例第 1 行变成 `(2,3,2,3)`,所以 `[1][2]` 是 `2`)
|
||||
- 上述差异只适用于普通 `array`;`FMArray` 上 `|` 与 `:|` 行为一致且行数不齐时补 `0`,见 [23_fmarray.md](23_fmarray.md)
|
||||
- 上述差异只适用于普通 `array`;`FMArray` 上 `|` 与 `:|` 行为一致且行数不齐时补 `0`,见 [22_fmarray.md](22_fmarray.md)
|
||||
- 对应的复合赋值形式:`&=`(行并)、`|=`(列并)、`:|=`(列并补 nil)
|
||||
|
||||
## 默认生成模板
|
||||
+23
-9
@@ -6,14 +6,6 @@
|
||||
|
||||
回答“什么时候该用 `FMArray` 而不是普通 `array`,以及文档明确 `FMArray` 写法有哪些”。
|
||||
|
||||
## 智能体 FMArray 判断流程
|
||||
|
||||
1. 先判断是否确实需要 `FMArray`,普通数组能解决时先用普通数组。
|
||||
2. 构造、类型判断、尺寸读取、转置、连接和 TS-SQL 参与只照本页文档明确形态写。
|
||||
3. `insert`、`delete`、`update` 的收尾形式分别判断,不要互相套用。
|
||||
4. FMArray 错误边界按本页反例处理,不要凭普通数组经验修写法。
|
||||
5. 没有对应代码块时不要发明 FMArray 写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- `fmarray[...]` 可以直接构造 `FMArray` 常量。
|
||||
@@ -28,7 +20,7 @@
|
||||
- `union2` 支持 `FMArray` / `Array` 混合运算;结果类型跟随左值。
|
||||
- 对超过二维的 `FMArray`,反引号转置会把全部维度倒置;`mswap` 可只交换指定维度。
|
||||
- `union` 可做按行连接且不去重,但列结构必须兼容。
|
||||
- `|` 和 `:|` 都可做矩阵并右方(按列连接);在 `FMArray` 上行数不一致时会用 `0` 补齐,并且两者表现一致(普通 `array` 上两者行为不同:`:|` 缺位补 `nil`、`|` 直接顺接,见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md))。
|
||||
- `|` 和 `:|` 都可做矩阵并右方(按列连接);在 `FMArray` 上行数不一致时会用 `0` 补齐,并且两者表现一致(普通 `array` 上两者行为不同:`:|` 缺位补 `nil`、`|` 直接顺接,见 [21_matrix_deep_dive.md](21_matrix_deep_dive.md))。
|
||||
- 对 `FMArray` 做普通 `select` 不会保留 `FMArray` 类型;`mselect` 也不会返回 `dataType=27`。
|
||||
- `insert into a array(...)`、`delete from a where ...;`、`update a set ... where ... end;` 都能作用于 `FMArray`,但三者的收尾形式并不完全相同。
|
||||
|
||||
@@ -36,6 +28,8 @@
|
||||
|
||||
### 常量构造与类型判断
|
||||
|
||||
<!-- tags: 建 FMArray, 高性能数组, 字面量写法 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -80,6 +74,8 @@ writeLn(f2[0,0], ',', f2[0,1], ',', f2[1,0], ',', f2[1,1]);
|
||||
|
||||
### `mInit`、`mInitDiag`、`mRand`
|
||||
|
||||
<!-- tags: 初始化 FMArray, 对角阵, 随机矩阵 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -109,6 +105,8 @@ writeLn(mcols(fr1));
|
||||
|
||||
### `arrayToFm`、`matrixToArray` 与单元格类型转换
|
||||
|
||||
<!-- tags: 普通数组转 FMArray, 互转, 单元格类型 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -137,6 +135,8 @@ writeLn(a2[0][0], ',', a2[0][1], ',', a2[1][0], ',', a2[1][1]);
|
||||
|
||||
### 尺寸与重构
|
||||
|
||||
<!-- tags: FMArray 尺寸, 改形状, reshape, 三维 -->
|
||||
|
||||
二维和三维尺寸:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -173,6 +173,8 @@ writeLn(r1[0], ',', r1[1], ',', r1[2], ',', r1[3], ',', r1[4], ',', r1[5]);
|
||||
|
||||
### 标量运算与基础算符
|
||||
|
||||
<!-- tags: FMArray 加减乘除, 和数字运算 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -198,6 +200,8 @@ writeLn(s2[0], ',', s2[1], ',', s2[2]);
|
||||
|
||||
### `union2` 与左值类型
|
||||
|
||||
<!-- tags: FMArray 合并, 左值类型决定结果 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -224,6 +228,8 @@ writeLn(u2[0], ',', u2[1], ',', u2[2], ',', u2[3], ',', u2[4], ',', u2[5]);
|
||||
|
||||
### 多维转置与维度交换
|
||||
|
||||
<!-- tags: 三维转置, 换维度, 维度倒置 -->
|
||||
|
||||
三维 `FMArray` 上,反引号转置会把全部维度倒置:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -266,6 +272,8 @@ writeLn(t[0,0,0], ',', t[0,1,0], ',', t[0,2,0], ';', t[1,0,0], ',', t[1,1,0], ',
|
||||
|
||||
### 矩阵连接 / 矩阵并右方:`union`、`|`、`:|`
|
||||
|
||||
<!-- tags: FMArray 拼接, 按列连接, 补零对齐 -->
|
||||
|
||||
`union` 会按行拼接,不做去重:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -358,6 +366,8 @@ writeLn(m2[2,0], ',', m2[2,1], ',', m2[2,2], ',', m2[2,3]);
|
||||
|
||||
### 排序
|
||||
|
||||
<!-- tags: 排序, 从小到大, 按列排, sortArray -->
|
||||
|
||||
一维排序:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -388,6 +398,8 @@ writeLn(f1[0,0], ',', f1[0,1], ';', f1[1,0], ',', f1[1,1], ';', f1[2,0], ',', f1
|
||||
|
||||
### TS-SQL 对 `FMArray` 的支持
|
||||
|
||||
<!-- tags: 对 FMArray 做查询, mselect -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -410,6 +422,8 @@ writeLn(mcols(q2));
|
||||
|
||||
### `insert` / `delete` / `update`
|
||||
|
||||
<!-- tags: FMArray 增删改, 写回 -->
|
||||
|
||||
`insert`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
+18
-8
@@ -6,14 +6,6 @@
|
||||
|
||||
回答“当类不只是普通对象,而要直接参与 `obj + x`、`obj[index]`、`for v in obj`、`mrows(obj)` 这类语言级操作时,支持哪些文档明确写法”。
|
||||
|
||||
## 智能体对象重载/迭代判断流程
|
||||
|
||||
1. 先判断要重载二元算符、下标、`for in`,还是矩阵尺寸函数。
|
||||
2. 对象重载只照本页明确的 `operator` 签名写,不要从未写入文档资料扩展未知重载。
|
||||
3. 普通对象模型以 `08_objects_and_classes.md` 的事实为准,不要在重载页发明类基础语法。
|
||||
4. 未列入本页主干的重载族不要写成语法事实。
|
||||
5. 没有对应代码块时不要发明对象重载/迭代写法。
|
||||
|
||||
## 核心规则
|
||||
|
||||
- 对象二元算符重载的最小可靠形态是成员方法 `function operator + (other);` 这一类写法。
|
||||
@@ -31,6 +23,8 @@
|
||||
|
||||
### 二元算符重载
|
||||
|
||||
<!-- tags: 让对象支持加号, 自定义加减, 对象相加, 运算符重载 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -98,6 +92,8 @@ end;
|
||||
|
||||
### `[]` 重载:`operator[]` / `operator[1]`
|
||||
|
||||
<!-- tags: 中括号取值, 方括号访问, 对象当数组用, 下标读写 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -132,6 +128,8 @@ end;
|
||||
|
||||
### `[]` 重载:`operator[0]` / `operator[1]`
|
||||
|
||||
<!-- tags: 中括号读写分离, 取值和赋值签名 -->
|
||||
|
||||
读取签名也可以写成 `function operator[0](index, s1);`(与上一段 `operator[]` 等价的另一组写法):
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -168,6 +166,8 @@ end;
|
||||
|
||||
### `for in` 重载
|
||||
|
||||
<!-- tags: 让对象可遍历, 自定义迭代, 支持 for in -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -218,6 +218,8 @@ end;
|
||||
|
||||
### `mrows` / `mcols` / `msize` 重载(带参形态,支持下标列表)
|
||||
|
||||
<!-- tags: 对象当矩阵, 自定义行列数, 带下标查询 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -274,6 +276,8 @@ end;
|
||||
|
||||
### `++` / `+=` / `--` / `-=` 自增自减重载
|
||||
|
||||
<!-- tags: 自增自减, 加等于, 对象累加 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -362,6 +366,8 @@ end;
|
||||
|
||||
### 二进制函数重载:`operator funcName`
|
||||
|
||||
<!-- tags: 重载具名函数, 让内置函数认识我的对象 -->
|
||||
|
||||
除了符号算符,`operator` 还能重载具名的全局二进制函数(如 `DateToStr`、`TryStrToInt` 等)。定义写成 `[class] function operator funcName(...)`:`class` 关键字可选,加上表示类方法,不加表示成员函数。
|
||||
|
||||
成员函数重载(参数比原函数少 1 个,用第一个参数的对象实例调用):
|
||||
@@ -450,6 +456,8 @@ end;
|
||||
|
||||
### `::` / `:.` 遍历重载与 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex`
|
||||
|
||||
<!-- tags: 对象支持矩阵遍历, 自定义单元访问 -->
|
||||
|
||||
重载 `::`(二维遍历)或 `:.`(深度遍历)后,对象就能像矩阵一样被 `obj::begin ... end` 遍历。遍历体里用到的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex(n)` 也各自重载,返回当前单元的值、行下标、列下标、维度数和第 `n` 维下标。`operator ::(flag)` 的 `flag` 为 `0` 表示第一次循环、`1` 表示后续循环,返回 `0` 或 `nil` 结束遍历、返回非零数字继续:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -524,6 +532,8 @@ end;
|
||||
|
||||
### `mrows` / `mcols` / `msize` 重载(无参形态,只取数量且免 `::`)
|
||||
|
||||
<!-- tags: 只取数量, 无参形态, 免遍历取行列数 -->
|
||||
|
||||
`msize` / `mrows` / `mcols` 这类关键字函数也能重载,形态同二进制函数重载 `[class] function operator KeyWord(...)`,但**关键字重载不需要 `::` 指定全局**:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -12,13 +12,20 @@ from urllib.parse import unquote
|
||||
|
||||
SKILL_ROOT = Path(__file__).resolve().parents[1]
|
||||
DEFAULT_REFERENCES_DIR = SKILL_ROOT / "references"
|
||||
DEFAULT_LEXICON_PATH = SKILL_ROOT / "data" / "lexicon.json"
|
||||
HEADING_RE = re.compile(r"^(#{1,6})(?!#)\s+(.+?)\s*$")
|
||||
FENCE_RE = re.compile(r"^```([^`]*)$")
|
||||
MARKDOWN_LINK_RE = re.compile(r"!?\[[^\]]*\]\(([^)]+)\)")
|
||||
ASCII_TOKEN_RE = re.compile(r"[a-z_][a-z0-9_.$:+-]*", re.IGNORECASE)
|
||||
CHINESE_RUN_RE = re.compile(r"[\u3400-\u9fff]+")
|
||||
_WHITESPACE_RE = re.compile(r"\s+")
|
||||
INLINE_CODE_RE = re.compile(r"`([^`\n]+)`")
|
||||
FENCED_CODE_RE = re.compile(r"```[^\n]*\n(.*?)```", re.DOTALL)
|
||||
# 章节级检索标签:写在标题下方的 HTML 注释里,渲染后不可见。
|
||||
# 用途是补用户侧说法与正文词面之间的缺口(正文写 `var` / `operator[]`,
|
||||
# 用户说"传引用" / "中括号")。逗号或顿号分隔,只影响检索,不是事实正文。
|
||||
SECTION_TAG_RE = re.compile(r"<!--\s*tags?\s*:\s*(.*?)\s*-->", re.DOTALL | re.IGNORECASE)
|
||||
TAG_SEPARATOR_RE = re.compile(r"[,,、]\s*")
|
||||
IDENTITY_PREFIX = "代码块身份:"
|
||||
BLOCK_DESCRIPTION_PREFIX = "代码块说明:"
|
||||
ALLOWED_IDENTITIES = {
|
||||
@@ -31,6 +38,21 @@ ALLOWED_IDENTITIES = {
|
||||
ROUTER_PHRASES = ("路由中心", "选择一个主专题", "候选页继续判断")
|
||||
EXCLUDED_REFERENCE_FILES = {"index.md"}
|
||||
DUTY_HEADING = "本篇职责"
|
||||
# 这些标题在多页重复出现,不承载单一事实,不参与「必须有 tag」的约束。
|
||||
GENERIC_HEADINGS = frozenset(
|
||||
{
|
||||
"本篇职责",
|
||||
"核心规则",
|
||||
"禁止项",
|
||||
"可直接照写示例",
|
||||
"默认生成模板",
|
||||
"本页不生成的范围",
|
||||
"示例与行为",
|
||||
"决策边界和禁止项",
|
||||
"文件模型示例",
|
||||
"术语对照",
|
||||
}
|
||||
)
|
||||
SUSPICIOUS_FENCE_RE = re.compile(r"^(?:\s+`{3}|`{4,})")
|
||||
WRITE_PRELUDE_ANCHORS = (
|
||||
("02_core_model.md", "文件模型核心规则"),
|
||||
@@ -39,6 +61,15 @@ WRITE_PRELUDE_ANCHORS = (
|
||||
|
||||
HEADING_TOKEN_SCORE = 12
|
||||
HEADING_EXACT_SCORE = 20
|
||||
# 标签是人工策展的检索意图,权重与标识符同级:足以在页内区分章节,
|
||||
# 但压不过标题精确命中,避免标签写宽了就绑架整页。
|
||||
TAG_TOKEN_SCORE = 10
|
||||
TAG_EXACT_SCORE = 16
|
||||
# 标签按「被查询覆盖的比例」判命中,而不是逐 token 累加。中文按 2-gram 切分,
|
||||
# 逐 token 累加会让「参数」「函数」这类泛化词命中一整页的标签,把整页抬起来;
|
||||
# 要求覆盖过半,则「只读参数」不会被「临时改系统参数」点亮,而单 token 的
|
||||
# 精确标签(lambda)仍然 100% 覆盖、照常命中。
|
||||
TAG_COVERAGE_THRESHOLD = 0.5
|
||||
TERM_TOKEN_SCORE = 10
|
||||
TERM_EXACT_SCORE = 16
|
||||
PAGE_TITLE_TOKEN_SCORE = 5
|
||||
@@ -46,11 +77,14 @@ PAGE_TITLE_EXACT_SCORE = 8
|
||||
BODY_TOKEN_SCORE = 3
|
||||
BODY_EXACT_SCORE = 4
|
||||
DIRECT_EXAMPLE_BOOST = 8
|
||||
PITFALL_PAGE_BOOST = 30
|
||||
COUNTEREXAMPLE_BOOST = 8
|
||||
COUNTEREXAMPLE_BOOST = 30
|
||||
EXACT_ERROR_BOOST = 14
|
||||
MIXED_QUERY_MIN_SCORE = 10
|
||||
PAGE_INTENT_SCORE = 80
|
||||
# 单页最多贡献几条候选。上限保证候选跨页分散,但页级 intent 命中(+80)会把
|
||||
# 整页抬起来,页内只剩十几分的词法差异在排序;上限过小时正确章节会被同页
|
||||
# 邻居挤掉,且加大 --limit 也救不回来。3 是实测下节级准确率与跨页分散的平衡点。
|
||||
PAGE_MATCH_CAP = 3
|
||||
|
||||
CHINESE_STOP_TOKENS = {
|
||||
"一个",
|
||||
@@ -76,51 +110,45 @@ ASCII_FILTER_STOP_TOKENS = {
|
||||
"tsf",
|
||||
}
|
||||
|
||||
QUERY_SYNONYMS = {
|
||||
"打印": ("输出", "writeLn"),
|
||||
"打出来": ("输出", "writeLn"),
|
||||
"左连接": ("左联接", "left join", "TS-SQL"),
|
||||
"左外连接": ("左联接", "left join", "TS-SQL"),
|
||||
"left outer join": ("left join", "左联接", "TS-SQL"),
|
||||
"列表": ("数组",),
|
||||
"复用文件": ("tsf", "unit"),
|
||||
"多个文件": ("unit", "uses", "作用域"),
|
||||
"跳出去": ("break", "控制流"),
|
||||
"程序慢": ("性能分析", "计时", "profiler"),
|
||||
"瓶颈": ("性能分析", "profiler"),
|
||||
"debug": ("调试", "性能分析"),
|
||||
"program": ("脚本",),
|
||||
"tinysoft": ("天软", "TSL"),
|
||||
"字符串转整数": ("类型转换", "strToInt"),
|
||||
"高性能矩阵": ("FMArray",),
|
||||
}
|
||||
QUERY_SYNONYMS: dict[str, tuple[str, ...]]
|
||||
PAGE_INTENT_ALIASES: dict[str, tuple[str, ...]]
|
||||
|
||||
PAGE_INTENT_ALIASES = {
|
||||
"01_quickstart.md": ("最简单能跑", "天软脚本", "tinysoft"),
|
||||
"02_core_model.md": ("脚本和可复用", "可复用函数文件"),
|
||||
"03_values_and_literals.md": ("字符串和数组下标",),
|
||||
"04_variables_and_constants.md": ("常量怎么声明", "变量能不能直接赋值"),
|
||||
"05_functions_and_calls.md": ("默认参数", "函数怎么带"),
|
||||
"06_expressions_and_operators.md": ("赋值和相等比较",),
|
||||
"07_control_flow.md": ("跳出去", "循环里满足条件"),
|
||||
"08_objects_and_classes.md": ("定义类", "创建对象"),
|
||||
"09_units_and_scope.md": ("多个文件", "复用一组函数"),
|
||||
"10_runtime_context_and_with.md": ("临时切换系统参数",),
|
||||
"11_pitfalls.md": ("声明函数后面写代码", "语法报错"),
|
||||
"12_matrix_and_collections.md": ("某行存在", "二维数组怎么判断"),
|
||||
"13_resultset_and_filters.md": ("保留匹配行", "按某一列"),
|
||||
"14_ts_sql.md": ("左连接", "左外连接", "左联接", "数据库", "分组排序", "聚合排序"),
|
||||
"15_debug_and_profiler.md": ("程序慢", "计时找瓶颈", "性能瓶颈", "性能问题", "debug"),
|
||||
"16_lexical_structure_and_compile_options.md": ("变量名区分大小写", "注释怎么写"),
|
||||
"17_types_and_conversions.md": ("字符串转整数", "类型转换"),
|
||||
"18_external_calls_and_threads.md": ("调用 dll", "开线程"),
|
||||
"19_namespace_libpath_and_unit_runtime.md": ("找不到 tsf", "搜索路径"),
|
||||
"20_object_runtime_and_introspection.md": ("查看对象属于哪个类", "运行时对象"),
|
||||
"21_builtin_runtime_objects.md": ("内存流",),
|
||||
"22_matrix_deep_dive.md": ("矩阵求逆", "矩阵转置", "求逆和转置"),
|
||||
"23_fmarray.md": ("高性能矩阵", "fmarray"),
|
||||
"24_object_overloads_and_iteration.md": ("自定义对象支持下标", "for in"),
|
||||
}
|
||||
|
||||
def _load_lexicon(
|
||||
path: Path = DEFAULT_LEXICON_PATH,
|
||||
) -> tuple[dict[str, tuple[str, ...]], dict[str, tuple[str, ...]]]:
|
||||
"""加载策展词表(口语同义词与页级意图短语)。
|
||||
|
||||
词表是持续生长的策展数据,与检索引擎分离维护在 data/lexicon.json;
|
||||
策展纪律见 data/README.md。加载失败必须响亮报错——静默回退为空表
|
||||
会让全部自然语言入口消失而检索仍然"正常"返回。
|
||||
"""
|
||||
try:
|
||||
data = json.loads(path.read_text(encoding="utf-8"))
|
||||
except FileNotFoundError:
|
||||
raise SystemExit(f"词表文件缺失:{path};检查 skill 安装是否完整")
|
||||
except json.JSONDecodeError as error:
|
||||
raise SystemExit(f"词表文件不是合法 JSON:{path}:{error}")
|
||||
|
||||
def _table(name: str) -> dict[str, tuple[str, ...]]:
|
||||
table = data.get(name)
|
||||
if not isinstance(table, dict):
|
||||
raise SystemExit(f"{path}: 缺少 {name} 表或不是对象")
|
||||
result: dict[str, tuple[str, ...]] = {}
|
||||
for key, values in table.items():
|
||||
if (
|
||||
not isinstance(values, list)
|
||||
or not values
|
||||
or not all(isinstance(item, str) and item.strip() for item in values)
|
||||
):
|
||||
raise SystemExit(f"{path}: {name}[{key!r}] 必须是非空字符串数组")
|
||||
result[key] = tuple(values)
|
||||
return result
|
||||
|
||||
return _table("query_synonyms"), _table("page_intent_aliases")
|
||||
|
||||
|
||||
QUERY_SYNONYMS, PAGE_INTENT_ALIASES = _load_lexicon()
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -132,6 +160,7 @@ class Section:
|
||||
body: str
|
||||
local_body: str
|
||||
identities: tuple[str, ...]
|
||||
tags: tuple[str, ...]
|
||||
searchable_text: str
|
||||
|
||||
|
||||
@@ -148,6 +177,7 @@ class QueryMatch:
|
||||
score: int
|
||||
priority: tuple[int, ...] = ()
|
||||
reasons: tuple[str, ...] = ()
|
||||
weak: bool = False
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -155,6 +185,7 @@ class ScoreBreakdown:
|
||||
intent: int
|
||||
heading_path: int
|
||||
exact_term: int
|
||||
tag: int
|
||||
page_title: int
|
||||
body: int
|
||||
mode_boost: int
|
||||
@@ -167,10 +198,19 @@ class ScoreBreakdown:
|
||||
self.intent
|
||||
+ self.heading_path
|
||||
+ self.exact_term
|
||||
+ self.tag
|
||||
+ self.page_title
|
||||
+ self.body
|
||||
)
|
||||
|
||||
@property
|
||||
def weak(self) -> bool:
|
||||
# 没有任何强字段命中(意图短语、标题、标识符、标签),只靠正文 /
|
||||
# 页标题的低分撞词进入候选。实测这是"查询根本不在本 skill 事实域"
|
||||
# 时的典型形态(如通用词二字撞上正文),而策展用例从不落进来;
|
||||
# 全部候选皆弱时按无匹配处理。
|
||||
return self.intent + self.heading_path + self.exact_term + self.tag == 0
|
||||
|
||||
@property
|
||||
def total(self) -> int:
|
||||
return self.lexical_total + self.mode_boost
|
||||
@@ -183,6 +223,7 @@ class ScoreBreakdown:
|
||||
self.mode_boost,
|
||||
self.heading_path,
|
||||
self.exact_term,
|
||||
self.tag,
|
||||
self.page_title,
|
||||
self.body,
|
||||
)
|
||||
@@ -190,6 +231,7 @@ class ScoreBreakdown:
|
||||
self.intent,
|
||||
self.heading_path,
|
||||
self.exact_term,
|
||||
self.tag,
|
||||
self.page_title,
|
||||
self.mode_boost,
|
||||
self.body,
|
||||
@@ -299,6 +341,16 @@ def _identities(body: str) -> tuple[str, ...]:
|
||||
return tuple(identities)
|
||||
|
||||
|
||||
def _section_tags(body: str) -> tuple[str, ...]:
|
||||
tags: list[str] = []
|
||||
for block in SECTION_TAG_RE.findall(body):
|
||||
for tag in TAG_SEPARATOR_RE.split(block.replace("\n", " ")):
|
||||
tag = tag.strip()
|
||||
if tag and tag not in tags:
|
||||
tags.append(tag)
|
||||
return tuple(tags)
|
||||
|
||||
|
||||
def load_sections(references_dir: Path = DEFAULT_REFERENCES_DIR) -> list[Section]:
|
||||
sections: list[Section] = []
|
||||
for page in _reference_pages(Path(references_dir)):
|
||||
@@ -329,8 +381,9 @@ def load_sections(references_dir: Path = DEFAULT_REFERENCES_DIR) -> list[Section
|
||||
)
|
||||
local_body = "".join(lines[start:local_end])
|
||||
base_id = section_id(page.relative_to(references_dir), heading_path)
|
||||
tags = _section_tags(local_body)
|
||||
searchable_text = normalize(
|
||||
"\n".join((page.stem, page_title, *heading_path, local_body))
|
||||
"\n".join((page.stem, page_title, *heading_path, *tags, local_body))
|
||||
)
|
||||
sections.append(
|
||||
Section(
|
||||
@@ -341,6 +394,7 @@ def load_sections(references_dir: Path = DEFAULT_REFERENCES_DIR) -> list[Section
|
||||
body=body,
|
||||
local_body=local_body,
|
||||
identities=_identities(local_body),
|
||||
tags=tags,
|
||||
searchable_text=searchable_text,
|
||||
)
|
||||
)
|
||||
@@ -413,11 +467,61 @@ def _local_link_problems(
|
||||
return problems
|
||||
|
||||
|
||||
def _tag_problems(sections: list[Section]) -> list[ValidationProblem]:
|
||||
"""章节 tag 的结构校验。
|
||||
|
||||
tag 是页内区分章节的主要信号,写空、漏写或页内重复都会静默削弱检索,
|
||||
而其余校验一概发现不了。含代码围栏的具体章节是事实落点,必须可被
|
||||
自然语言命中;纯交接说明(正文只指向别页、没有围栏)反而不该有 tag,
|
||||
否则会和真正拥有事实的那一页抢候选。
|
||||
"""
|
||||
problems: list[ValidationProblem] = []
|
||||
seen_per_page: dict[str, dict[str, str]] = {}
|
||||
for section in sections:
|
||||
if not section.heading_path:
|
||||
continue
|
||||
heading = section.heading_path[-1]
|
||||
has_fence = bool(FENCED_CODE_RE.search(section.local_body))
|
||||
if has_fence and heading not in GENERIC_HEADINGS and not section.tags:
|
||||
problems.append(
|
||||
ValidationProblem(
|
||||
section.page, 1, f"含代码围栏的章节缺少检索 tag:{heading}"
|
||||
)
|
||||
)
|
||||
for tag in section.tags:
|
||||
if not tag.strip():
|
||||
problems.append(
|
||||
ValidationProblem(section.page, 1, f"空 tag:{heading}")
|
||||
)
|
||||
continue
|
||||
owners = seen_per_page.setdefault(section.page.name, {})
|
||||
if tag in owners:
|
||||
problems.append(
|
||||
ValidationProblem(
|
||||
section.page,
|
||||
1,
|
||||
f"页内 tag 重复:「{tag}」同时属于「{owners[tag]}」和「{heading}」",
|
||||
)
|
||||
)
|
||||
else:
|
||||
owners[tag] = heading
|
||||
return problems
|
||||
|
||||
|
||||
def validate_references(
|
||||
references_dir: Path = DEFAULT_REFERENCES_DIR,
|
||||
) -> list[ValidationProblem]:
|
||||
references_dir = Path(references_dir)
|
||||
problems: list[ValidationProblem] = []
|
||||
# 逐页校验在零页时全部静默通过;参考页缺失属于安装/路径错误,必须报错,
|
||||
# 否则 --check 会为一个空目录返回成功。
|
||||
if not _reference_pages(references_dir):
|
||||
problems.append(
|
||||
ValidationProblem(
|
||||
references_dir, 1, "references 中没有可校验的参考页;检查路径或重新安装 skill"
|
||||
)
|
||||
)
|
||||
return problems
|
||||
index_page = references_dir / "index.md"
|
||||
if index_page.exists():
|
||||
problems.append(ValidationProblem(index_page, 1, "references 中不得保留 index.md"))
|
||||
@@ -477,6 +581,7 @@ def validate_references(
|
||||
ValidationProblem(page, index, f"包含人工路由协议:{phrase}")
|
||||
)
|
||||
sections = load_sections(references_dir)
|
||||
problems.extend(_tag_problems(sections))
|
||||
ids: dict[str, Section] = {}
|
||||
for section in sections:
|
||||
if section.id in ids:
|
||||
@@ -522,6 +627,26 @@ def validate_references(
|
||||
f"概念地图摘要为空:{section.page.name} 的「{DUTY_HEADING}」",
|
||||
)
|
||||
)
|
||||
# 词表校验只对内置参考目录有意义:alias 键指向的是内置页文件名,
|
||||
# 用 --references-dir 校验合成目录(测试)时跳过,避免整表误报。
|
||||
if references_dir.resolve() == DEFAULT_REFERENCES_DIR.resolve():
|
||||
page_names = {page.name for page in _reference_pages(references_dir)}
|
||||
for stale in sorted(set(PAGE_INTENT_ALIASES) - page_names):
|
||||
problems.append(
|
||||
ValidationProblem(
|
||||
DEFAULT_LEXICON_PATH,
|
||||
1,
|
||||
f"page_intent_aliases 指向不存在的参考页:{stale}",
|
||||
)
|
||||
)
|
||||
for missing in sorted(page_names - set(PAGE_INTENT_ALIASES)):
|
||||
problems.append(
|
||||
ValidationProblem(
|
||||
DEFAULT_LEXICON_PATH,
|
||||
1,
|
||||
f"参考页缺少 page_intent_aliases 自然语言入口:{missing}",
|
||||
)
|
||||
)
|
||||
return problems
|
||||
|
||||
|
||||
@@ -549,7 +674,12 @@ def _ascii_token_sequence(text: str) -> list[str]:
|
||||
def _query_contains_phrase(query: str, phrase: str) -> bool:
|
||||
normalized_phrase = normalize(phrase)
|
||||
if CHINESE_RUN_RE.search(normalized_phrase):
|
||||
return normalized_phrase in normalize(query)
|
||||
# 含中文的短语按去空白后的串比较。SKILL.md 要求智能体传「术语」而不是
|
||||
# 用户原话,术语常以空格分隔(「数组 下标 起点」),逐字子串匹配会
|
||||
# 整条落空;去空白后 phrase 仍要求连续出现,不放宽词序。
|
||||
return _WHITESPACE_RE.sub("", normalized_phrase) in _WHITESPACE_RE.sub(
|
||||
"", normalize(query)
|
||||
)
|
||||
phrase_tokens = _ascii_token_sequence(phrase)
|
||||
query_tokens_in_order = _ascii_token_sequence(query)
|
||||
if not phrase_tokens:
|
||||
@@ -611,6 +741,23 @@ def _has_chinese_context(section: Section, query: str) -> bool:
|
||||
return not runs
|
||||
|
||||
|
||||
def _tag_matched_tokens(tags: tuple[str, ...], query_token_set: set[str]) -> int:
|
||||
"""标签命中的 token 数;覆盖率不过门槛的标签整条不计分。
|
||||
|
||||
覆盖率只做门控,计分仍按命中 token 数——否则一条深度吻合的标签
|
||||
(命中 4 个 token)和一条勉强擦边的标签得分相同,信号被抹平。
|
||||
"""
|
||||
matched = 0
|
||||
for tag in tags:
|
||||
tag_tokens = _base_query_tokens(tag)
|
||||
if not tag_tokens:
|
||||
continue
|
||||
covered = sum(1 for token in tag_tokens if token in query_token_set)
|
||||
if covered / len(tag_tokens) >= TAG_COVERAGE_THRESHOLD:
|
||||
matched += covered
|
||||
return matched
|
||||
|
||||
|
||||
def _code_text(body: str) -> str:
|
||||
inline = INLINE_CODE_RE.findall(body)
|
||||
fenced = FENCED_CODE_RE.findall(body)
|
||||
@@ -622,18 +769,20 @@ def _score_section(section: Section, query: str, mode: str) -> ScoreBreakdown:
|
||||
tokens = query_tokens(query)
|
||||
heading_text = normalize("\n".join(section.heading_path))
|
||||
page_title_text = normalize(section.page_title)
|
||||
body_text = normalize(section.local_body)
|
||||
body_text = normalize(SECTION_TAG_RE.sub(" ", section.local_body))
|
||||
tag_text = normalize("\n".join(section.tags))
|
||||
term_text = _code_text(section.local_body)
|
||||
expanded_only_tokens = _synonym_tokens(query) - _base_query_tokens(query)
|
||||
synonym_hits = sum(
|
||||
any(
|
||||
_text_contains_token(text, token)
|
||||
for text in (heading_text, term_text, page_title_text, body_text)
|
||||
for text in (heading_text, term_text, tag_text, page_title_text, body_text)
|
||||
)
|
||||
for token in expanded_only_tokens
|
||||
)
|
||||
heading_score = 0
|
||||
term_score = 0
|
||||
tag_score = TAG_TOKEN_SCORE * _tag_matched_tokens(section.tags, tokens)
|
||||
page_title_score = 0
|
||||
body_score = 0
|
||||
for token in tokens:
|
||||
@@ -649,6 +798,10 @@ def _score_section(section: Section, query: str, mode: str) -> ScoreBreakdown:
|
||||
heading_score += HEADING_EXACT_SCORE
|
||||
if _text_contains_exact_query(term_text, query):
|
||||
term_score += TERM_EXACT_SCORE
|
||||
if section.tags and any(
|
||||
normalize(tag) == normalize(query).strip() for tag in section.tags
|
||||
):
|
||||
tag_score += TAG_EXACT_SCORE
|
||||
if _text_contains_exact_query(page_title_text, query):
|
||||
page_title_score += PAGE_TITLE_EXACT_SCORE
|
||||
if _text_contains_exact_query(body_text, query):
|
||||
@@ -657,8 +810,8 @@ def _score_section(section: Section, query: str, mode: str) -> ScoreBreakdown:
|
||||
if mode == "write" and "可直接照写示例" in section.identities:
|
||||
mode_boost += DIRECT_EXAMPLE_BOOST
|
||||
if mode == "diagnose":
|
||||
if section.page.name == "11_pitfalls.md":
|
||||
mode_boost += PITFALL_PAGE_BOOST
|
||||
# 反例按代码块身份加分,不按页名。反例分散在各专题页里,
|
||||
# 没有一页专门收口它们。
|
||||
if "反例 / 不可照写" in section.identities:
|
||||
mode_boost += COUNTEREXAMPLE_BOOST
|
||||
if normalized_query and normalized_query in section.searchable_text:
|
||||
@@ -667,6 +820,7 @@ def _score_section(section: Section, query: str, mode: str) -> ScoreBreakdown:
|
||||
intent=_intent_score(section, query),
|
||||
heading_path=heading_score,
|
||||
exact_term=term_score,
|
||||
tag=tag_score,
|
||||
page_title=page_title_score,
|
||||
body=body_score,
|
||||
mode_boost=mode_boost,
|
||||
@@ -680,6 +834,7 @@ def _score_reasons(score: ScoreBreakdown) -> tuple[str, ...]:
|
||||
("intent", score.intent),
|
||||
("heading", score.heading_path),
|
||||
("identifier", score.exact_term),
|
||||
("tag", score.tag),
|
||||
("page_title", score.page_title),
|
||||
("body", score.body),
|
||||
("mode", score.mode_boost),
|
||||
@@ -802,6 +957,7 @@ def query_sections(
|
||||
score.total,
|
||||
score.priority,
|
||||
_score_reasons(score),
|
||||
score.weak,
|
||||
)
|
||||
)
|
||||
ranked.sort(
|
||||
@@ -823,7 +979,7 @@ def query_sections(
|
||||
_related_sections(match.section, kept.section) for kept in matches
|
||||
):
|
||||
continue
|
||||
if page_counts.get(match.section.page, 0) >= 2:
|
||||
if page_counts.get(match.section.page, 0) >= PAGE_MATCH_CAP:
|
||||
continue
|
||||
matches.append(match)
|
||||
page_counts[match.section.page] = page_counts.get(match.section.page, 0) + 1
|
||||
@@ -850,7 +1006,9 @@ def _safe_json_string(value: str) -> str:
|
||||
|
||||
|
||||
def _plain_text_summary(body: str, limit: int = 180) -> str:
|
||||
without_fences = FENCED_CODE_RE.sub(" ", body)
|
||||
# 标签是检索元数据,不是事实正文;不能泄进候选摘要。
|
||||
without_tags = SECTION_TAG_RE.sub(" ", body)
|
||||
without_fences = FENCED_CODE_RE.sub(" ", without_tags)
|
||||
without_links = re.sub(
|
||||
r"!?\[([^\]]*)\]\([^)]+\)", lambda match: match.group(1), without_fences
|
||||
)
|
||||
@@ -875,12 +1033,16 @@ def render_candidates(result: QueryResult) -> str:
|
||||
f"Query: {_safe_json_string(result.query)}",
|
||||
]
|
||||
candidates = [
|
||||
(section, 0, True, ("required=1",)) for section in result.prelude
|
||||
(section, 0, True, ("required=1",), False) for section in result.prelude
|
||||
] + [
|
||||
(match.section, match.score, False, match.reasons) for match in result.matches
|
||||
(match.section, match.score, False, match.reasons, match.weak)
|
||||
for match in result.matches
|
||||
]
|
||||
for index, (section, score, required, reasons) in enumerate(
|
||||
candidates[: result.limit], start=1
|
||||
# --limit is the budget for query matches only; write 模式的前置章节额外附加,
|
||||
# 否则 limit 小于前置章节数时会一条真实候选都不返回。
|
||||
budget = result.limit + len(result.prelude)
|
||||
for index, (section, score, required, reasons, weak) in enumerate(
|
||||
candidates[:budget], start=1
|
||||
):
|
||||
lines.extend(
|
||||
[
|
||||
@@ -889,6 +1051,13 @@ def render_candidates(result: QueryResult) -> str:
|
||||
"",
|
||||
f"Score: {score}",
|
||||
f"Required: {'yes' if required else 'no'}",
|
||||
]
|
||||
)
|
||||
if weak:
|
||||
# 只在弱命中时输出该行:没有 Weak 行即为强命中。
|
||||
lines.append("Weak: yes")
|
||||
lines.extend(
|
||||
[
|
||||
f"Section ID: `{section.id}`",
|
||||
f"Source: `{_logical_source(section)}`",
|
||||
f"Heading: `{' > '.join(section.heading_path)}`",
|
||||
@@ -948,16 +1117,72 @@ def _configure_utf8() -> None:
|
||||
reconfigure(encoding="utf-8")
|
||||
|
||||
|
||||
HELP_EPILOG = """\
|
||||
检索分两步,缺一步都不算取回事实:
|
||||
|
||||
1. 先取候选(只有摘要和 Section ID,不含事实正文)
|
||||
lookup.py --query "命名参数 默认参数" --mode write
|
||||
2. 再按候选里的 Section ID 取回正文;多个要素各自跑完第 1 步后,
|
||||
选定的 Section ID 可以合并成一次取回
|
||||
lookup.py --section "05_functions_and_calls--可直接照写示例--基础函数-过程骨架" \\
|
||||
"02_core_model--文件模型核心规则"
|
||||
|
||||
查询词无从下手时先 --map 把需求映射到 TSL 概念;改动参考页或 data/ 词表后用 --check 校验。
|
||||
"""
|
||||
|
||||
|
||||
def _parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(description="Search TSL syntax reference sections")
|
||||
action = parser.add_mutually_exclusive_group(required=True)
|
||||
action.add_argument("--query")
|
||||
action.add_argument("--section")
|
||||
action.add_argument("--map", dest="show_map", action="store_true")
|
||||
action.add_argument("--check", action="store_true")
|
||||
parser.add_argument("--mode", choices=("write", "diagnose", "explain"))
|
||||
parser.add_argument("--limit", type=int, default=5)
|
||||
parser.add_argument("--references-dir", type=Path, default=DEFAULT_REFERENCES_DIR)
|
||||
parser = argparse.ArgumentParser(
|
||||
description="检索 TSL 语法参考页,取回可照写的语法事实。",
|
||||
epilog=HELP_EPILOG,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
action = parser.add_argument_group("动作(必选其一)").add_mutually_exclusive_group(
|
||||
required=True
|
||||
)
|
||||
action.add_argument(
|
||||
"--query", help="按用户原话、报错原文或语法要素名检索候选章节;需配合 --mode"
|
||||
)
|
||||
action.add_argument(
|
||||
"--section",
|
||||
nargs="+",
|
||||
metavar="SECTION_ID",
|
||||
help="按 Section ID 取回章节正文,可一次传多个 ID 批量取回"
|
||||
"(ID 抄自 --query 输出);这是唯一的事实来源",
|
||||
)
|
||||
action.add_argument(
|
||||
"--map",
|
||||
dest="show_map",
|
||||
action="store_true",
|
||||
help="输出各专题的职责摘要,用于把自然语言需求映射到 TSL 概念;不含可照写事实",
|
||||
)
|
||||
action.add_argument(
|
||||
"--check",
|
||||
action="store_true",
|
||||
help="校验参考页的结构、代码块身份和本地链接;发现问题时退出码为 1",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mode",
|
||||
choices=("write", "diagnose", "explain"),
|
||||
help="检索意图,仅用于 --query:"
|
||||
"write 编写或修改代码,额外附加文件模型与核心事实速查;"
|
||||
"diagnose 定位语法错误,优先易错点与反例;"
|
||||
"explain 解释语言规则或代码含义",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--limit",
|
||||
type=int,
|
||||
default=5,
|
||||
help="--query 返回的候选条数上限,取值 1..10(默认 %(default)s);"
|
||||
"write 模式的前置章节不占该预算",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--references-dir",
|
||||
type=Path,
|
||||
default=DEFAULT_REFERENCES_DIR,
|
||||
metavar="DIR",
|
||||
help="参考页目录(默认为本 skill 内置的 references/)",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
@@ -979,11 +1204,11 @@ def main(argv: list[str] | None = None) -> int:
|
||||
parser = _parser()
|
||||
args = parser.parse_args(argv)
|
||||
if not 1 <= args.limit <= 10:
|
||||
parser.error("--limit must be between 1 and 10")
|
||||
parser.error("--limit 取值必须在 1..10 之间")
|
||||
if args.query is not None and args.mode is None:
|
||||
parser.error("--mode is required with --query")
|
||||
parser.error("--query 必须同时指定 --mode")
|
||||
if args.mode is not None and args.query is None:
|
||||
parser.error("--mode only applies to --query")
|
||||
parser.error("--mode 仅用于 --query")
|
||||
if args.show_map:
|
||||
print(render_concept_map(build_concept_map(args.references_dir)), end="")
|
||||
return 0
|
||||
@@ -994,25 +1219,35 @@ def main(argv: list[str] | None = None) -> int:
|
||||
return 1 if problems else 0
|
||||
if args.section is not None:
|
||||
sections = load_sections(args.references_dir)
|
||||
section = next(
|
||||
(item for item in sections if item.id == args.section),
|
||||
None,
|
||||
by_id = {item.id: item for item in sections}
|
||||
requested = list(dict.fromkeys(args.section))
|
||||
missing = [item for item in requested if item not in by_id]
|
||||
if missing:
|
||||
# 原子失败:只要有一个 ID 不存在就不输出任何正文,
|
||||
# 避免智能体把"部分取回"误当作全部要素已取回。
|
||||
for requested_id in missing:
|
||||
print(f"section not found: {requested_id}", file=sys.stderr)
|
||||
print("Nearest section IDs:", file=sys.stderr)
|
||||
for candidate in _nearest_section_ids(requested_id, sections):
|
||||
print(f"- {candidate}", file=sys.stderr)
|
||||
return 2
|
||||
print(
|
||||
"\n".join(render_section(by_id[item]) for item in requested),
|
||||
end="",
|
||||
)
|
||||
if section is None:
|
||||
print(f"section not found: {args.section}", file=sys.stderr)
|
||||
print("Nearest section IDs:", file=sys.stderr)
|
||||
for candidate in _nearest_section_ids(args.section, sections):
|
||||
print(f"- {candidate}", file=sys.stderr)
|
||||
return 2
|
||||
print(render_section(section), end="")
|
||||
return 0
|
||||
else:
|
||||
result = query_sections(args.query, args.mode, args.limit, args.references_dir)
|
||||
if not result.matches:
|
||||
print(render_candidates(result), end="")
|
||||
print("no matching sections", file=sys.stderr)
|
||||
return 2
|
||||
result = query_sections(args.query, args.mode, args.limit, args.references_dir)
|
||||
print(render_candidates(result), end="")
|
||||
if not result.matches:
|
||||
print("no matching sections", file=sys.stderr)
|
||||
return 2
|
||||
if all(match.weak for match in result.matches):
|
||||
print(
|
||||
"only weak candidates (no intent/heading/identifier/tag hit); "
|
||||
"视同无匹配,改进查询词后重试",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 2
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user