diff --git a/AGENTS.md b/AGENTS.md index c9a2d320..b529db13 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,31 +1,32 @@ # TSL Agent Instructions -本文件不是语法手册,只放硬约束、首跳路由和阻断条件。 +本文件只保留 TSL 多领域首跳路由、优先级、事实边界和阻断条件,不保存具体语法实现。 -- 更靠近代码目录的规则可以更严格,但不能削弱文档事实和禁止发明语法规则。 -- TSL 事实以 `docs/tsl/**`、项目自身文档和块级 `代码块身份` 为准;本文件不复写完整语法。 -- 用户明确指令不能覆盖文档事实使用规则或禁止发明语法规则。 +## 范围与优先级 -## 代码生成协议 - -- 生成或修改代码前先判断交付目标与 `.tsl` / `.tsf` 文件模型;文件模型影响正确性且需求不明时先确认。 -- 禁止凭 Pascal、Python、JavaScript、TypeScript 或其他语言的相似写法补全 TSL 语法。 -- 无文档结论、文件模型不明或项目执行事实缺失时停止,不发明语法。 - -## TSL 核心事实 - -- `.tsl` / `.tsf` 后缀由用户指定时,后缀优先。 -- 未指定后缀时:入口流程、脚本任务或一次性任务初判 `.tsl`;可复用函数、过程、类、模块或扩展初判 `.tsf`。 -- `.tsl` 代码需要本文件内函数或类时,先写可执行语句区,再写声明区;声明区后不要继续追加脚本语句。 -- `.tsf` 只按可复用顶层声明或 `unit` 组织,不写顺序执行入口。 -- 对象创建、函数调用、`unit`、运行时上下文、TS-SQL 和矩阵等细节只从对应专题页取事实。 +- 更靠近目标代码的规则可以更严格,但不能削弱事实所有者给出的约束。 +- 用户明确要求优先;与仓库真实项目事实冲突时,先报告冲突并停止相关生成。 +- 只读取命中任务所需的事实所有者,不顺序通读全部文档,也不跨领域复制事实。 ## 文档首跳 -- 需要任何 TSL 语法、文件模型、函数、模块或金融数据事实时,第一跳统一进 `docs/tsl/index.md`,由它路由到具体页;不在本文件内猜文件路径,也不全目录搜索。 -- 查 API / 函数的名字、参数、返回值和示例时,使用 `tsl-api-reference` skill;已知名走 `--name`,未知名走 `--kw`。 +- TSL/TSF 语法、文件模型、语言规则、代码编写/修改/审查/解释和语法错误:使用 `tsl-syntax-reference` skill。 +- API/函数名称、签名、参数、返回值和金融取数:使用 `tsl-api-reference` skill。 +- 命名偏好:读取 `docs/tsl/naming.md`。 +- 代码风格:读取 `docs/tsl/code_style.md`。 +- 验证命令和工具链:读取 `docs/tsl/toolchain.md`、项目脚本或 CI。 +- Python 调 TSL、回测和通知等模块集成:读取 `docs/tsl/modules/index.md`。 +- 路径、数据结构、部署、运行参数和环境约束等项目事实:只读取目标项目的真实文档、配置和最近的 `AGENTS.md`。 -## 文档事实使用策略 +## 事实边界 -- 页面级元数据只做粗判断;生成代码时以块级 `代码块身份` 为准:只有 `可直接照写示例` 能当源码外形,`反例 / 不可照写`、`输出片段`、`配置片段 / 概念骨架` 不得照抄。 -- `code_style.md` 与 `naming.md` 只表达风格偏好,不代表 TSL 语法事实。 +- 语法 Skill 不拥有 API、命名、风格、工具链、模块或项目事实。 +- API Skill 不拥有语言语法、项目部署或模块集成事实。 +- 命名和风格文档只表达仓库偏好,不得替代语法事实。 +- 项目事实优先于通用示例;示例不得反推不存在的项目能力。 + +## Fail closed + +- `tsl-syntax-reference` 缺失或不可用时,停止生成或修改 TSL/TSF 代码,不凭相似语言补全语法。 +- `tsl-api-reference` 缺失或不可用时,停止猜测函数名、签名、参数和返回值。 +- 工具链、模块或项目事实缺失时,停止相关执行与集成判断,并明确报告缺失项。 diff --git a/docs/tsl/code_style.md b/docs/tsl/code_style.md index adc742fa..0afd2863 100644 --- a/docs/tsl/code_style.md +++ b/docs/tsl/code_style.md @@ -4,7 +4,7 @@ 是否可直接用于生成代码:仅部分 是否含可直接照写示例:否 是否含不可照写反例:否 -遇到不确定时:风格/命名看 [naming.md](naming.md);语法事实看 [syntax/index.md](syntax/index.md);验证命令或自动化入口只看项目脚本、CI,或目标项目已真实填写且没有 `<...>` 占位符的 [toolchain.md](toolchain.md) +遇到不确定时:风格/命名看 [naming.md](naming.md);语法事实使用 [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md);验证命令或自动化入口只看项目脚本、CI,或目标项目已真实填写且没有 `<...>` 占位符的 [toolchain.md](toolchain.md) 本页记录本仓库代码风格偏好,不代表 TSL 语法事实。 @@ -22,14 +22,14 @@ ### 1.1 单一职责 - 一个文件只做一件事;职责明确。 -- 文件模型和顶层声明规则以 `docs/tsl/syntax/02_core_model.md` 为准;本页只规定组织偏好。 +- 文件模型和顶层声明规则由 [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md) 管理;本页只规定组织偏好。 - 可复用逻辑优先集中到可复用声明文件;入口/编排层只保留必要流程。 - 当一个顶层声明同时承担“协议适配 + 业务计算 + I/O/环境依赖 + 临时代码”时,优先拆分边界:核心纯逻辑 → 工具函数 → 边界适配(I/O)。 ### 1.2 文件名与顶层声明 -- 文件模型和顶层声明规则以 `docs/tsl/syntax/02_core_model.md` 为准;文件和实体如何命名见 +- 文件模型和顶层声明规则由 [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md) 管理;文件和实体如何命名见 `docs/tsl/naming.md`。 - 文件名不强制表达完整职责,但应清晰可检索。 - 推荐文件名使用 `PascalCase` 以提升检索与协作一致性;扩展名按类型使用 @@ -91,7 +91,7 @@ end - 多语句分支使用 `begin/end` 包裹:在 `then/else` 后换行写 `begin`,`end` 单独成行。 - `else/elseif` 等分支关键字另起一行,与上一块的 `end` 对齐。 -- 控制流块(`if`/`while`/`for`/`case`/`try` 等)的 `end` 后不加分号;顶层声明(函数/过程/类/`unit`)的 `end` 后加分号(这是语法要求,见 `syntax/05_functions_and_calls.md` 和 `syntax/09_units_and_scope.md`)。 +- 控制流块与顶层声明的分号规则属于语法事实,使用 [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md) 核对;本页只规定风格偏好。 - 单语句分支可省略 `begin/end`(保持清晰优先;一旦分支变复杂就回退到块结构): 代码块身份:配置片段 / 概念骨架 diff --git a/docs/tsl/index.md b/docs/tsl/index.md index f93c8ac4..49897ddb 100644 --- a/docs/tsl/index.md +++ b/docs/tsl/index.md @@ -6,11 +6,11 @@ 本表只做「任务 → 文档区」分流;区内细分交给各区 `index.md`。多行命中时,自上而下取第一个命中行。 -| 任务信号 | 入口 | 阻断条件 | -| ---------------------------------------------------------- | ------------------------------------------------------------------------------ | ---------------------------------- | -| 要生成或编写 TSL 代码、先定文件模型与起手骨架 | [syntax/01_quickstart.md](syntax/01_quickstart.md) | 不写代码,只查语法、函数或命名事实 | -| 查语法写法、语言规则、排查语法错误 | [syntax/index.md](syntax/index.md) | 要找的是函数,不是语法 | -| 取金融数据:行情、财务、板块、选股 | 使用 `tsl-api-reference` skill 关键词查 API | 不是取数,是语法或语言规则 | -| 查 API/函数的名字、参数、返回值 | 使用 `tsl-api-reference` skill:已知名走 `--name`,未知名走 `--kw` | 要查的是语法,不是 API 事实 | -| 命名与代码风格:变量、函数、类型、文件取名,注释与代码组织 | 取名看 [naming.md](naming.md);注释与组织看 [code_style.md](code_style.md) | 要查的是语法或函数事实 | -| 具体模块能力:Python 调 TSL、策略回测、微信通知/告警 | [modules/index.md](modules/index.md) | 只是纯语法或普通取数 | +| 任务信号 | 入口 | 阻断条件 | +| ---------------------------------------------------------- | -------------------------------------------------------------------------- | ---------------------------------- | +| 要生成或编写 TSL 代码、先定文件模型与起手骨架 | [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md) | 不写代码,只查语法、函数或命名事实 | +| 查语法写法、语言规则、排查语法错误 | [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md) | 要找的是函数,不是语法 | +| 取金融数据:行情、财务、板块、选股 | 使用 [tsl-api-reference Skill](../../skills/tsl-api-reference/SKILL.md) | 不是取数,是语法或语言规则 | +| 查 API/函数的名字、参数、返回值 | 使用 [tsl-api-reference Skill](../../skills/tsl-api-reference/SKILL.md) | 要查的是语法,不是 API 事实 | +| 命名与代码风格:变量、函数、类型、文件取名,注释与代码组织 | 取名看 [naming.md](naming.md);注释与组织看 [code_style.md](code_style.md) | 要查的是语法或函数事实 | +| 具体模块能力:Python 调 TSL、策略回测、微信通知/告警 | [modules/index.md](modules/index.md) | 只是纯语法或普通取数 | diff --git a/docs/tsl/naming.md b/docs/tsl/naming.md index 385ae36c..48df00bb 100644 --- a/docs/tsl/naming.md +++ b/docs/tsl/naming.md @@ -4,7 +4,7 @@ 是否可直接用于生成代码:仅部分 是否含可直接照写示例:否 是否含不可照写反例:否 -遇到不确定时:命名对象不明看 [syntax/02_core_model.md](syntax/02_core_model.md);代码组织看 [code_style.md](code_style.md);语法事实看 [syntax/index.md](syntax/index.md) +遇到不确定时:命名对象或语法事实不明时使用 [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md);代码组织看 [code_style.md](code_style.md) 本页记录本仓库/作者的命名偏好,不代表 TSL 语法事实。本页只规定命名后的实体如何取名,不承担文件模型、顶层声明、执行顺序等语法判断。命名偏好与 Google C++ Style Guide 的实体形状思路对齐:通过名字的“形状”快速判断实体类型(类型/函数/变量/常量等),减少阅读成本。 @@ -48,16 +48,15 @@ `getSysParams("xxx")`;自定义 wrapper 仍按本指南使用 `PascalCase`。 - 常规自定义标识符不要使用 TSL 关键字、保留字或内置函数名。适用范围包括变量、 参数、函数/过程、类/类型、property、方法、字段、unit 名和文件基名。 -- 关键字和保留名清单以 - [16_lexical_structure_and_compile_options.md](syntax/16_lexical_structure_and_compile_options.md) - 为准;例如 `label` 是控制流保留名,不要作为普通变量、函数或属性名。 +- 关键字和保留名清单由 [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md) + 管理;需要判断具体名称时必须向该事实所有者查询,本页不枚举或判定具体保留名。 - 如果业务术语与关键字或内置名冲突,优先换成语义清楚的替代名称。只有明确需要 演示同名遮蔽、绑定外部接口或保持协议兼容时,才允许使用冲突名。 - 函数参数场景可以使用 5.1 中的前导下划线例外。 ## 3. 类型命名(Type Names) -文件模型和顶层声明规则以 `docs/tsl/syntax/02_core_model.md` 为准。本页只覆盖“需要命名的顶层实体”,不覆盖脚本语句本身。 +文件模型和顶层声明规则由 [tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md) 管理。本页只覆盖“需要命名的顶层实体”,不覆盖脚本语句本身。 - **类与单元**使用 `PascalCase`,不带下划线;名称应为名词/名词短语(通常单数),避免动词开头。 @@ -72,8 +71,8 @@ ## 4. 文件命名与顶层声明(File Names) -文件模型、可写顶层声明、声明与文件关系以 -`docs/tsl/syntax/02_core_model.md` 为准;本节只给已经确定要命名的文件/实体提供命名偏好。 +文件模型、可写顶层声明、声明与文件关系由 +[tsl-syntax-reference Skill](../../skills/tsl-syntax-reference/SKILL.md) 管理;本节只给已经确定要命名的文件/实体提供命名偏好。 - 先用核心模型页判断目标是否存在需要命名的顶层实体;不要从本页反推 `.tsl` / `.tsf` 可写结构。 diff --git a/docs/tsl/syntax/00_agent_index.json b/docs/tsl/syntax/00_agent_index.json deleted file mode 100644 index d1ba365a..00000000 --- a/docs/tsl/syntax/00_agent_index.json +++ /dev/null @@ -1,231 +0,0 @@ -{ - "version": "2.1", - "description": "Agent-optimized quick index for TSL syntax - read this FIRST", - "total_tokens_saved_per_query": "~2000-3000", - "changelog": { - "2.1": "Added naming/style routing for identifiers and TSF filename alignment", - "2.0": "Extended coverage from 7 to 14 scenarios, added understand_code and optimize_code decision paths", - "1.0": "Initial version with 7 high-frequency scenarios" - }, - - "intent_to_file": { - "hello_world": { - "file": "01_quickstart.md", - "line": 182, - "token_cost": 50, - "example": "echo \"hello\";" - }, - "function_basic": { - "file": "05_functions_and_calls.md", - "line": 103, - "token_cost": 100, - "example": "function Add(a, b);\nbegin\n return a + b;\nend;" - }, - "function_in_tsl": { - "file": "05_functions_and_calls.md", - "line": 82, - "token_cost": 150, - "example": "a := 1;\ntest();\n\nfunction test();\nbegin\n echo \"test\";\nend;" - }, - "procedure": { - "file": "05_functions_and_calls.md", - "line": 130, - "token_cost": 80, - "example": "procedure LogDone();\nbegin\nend;" - }, - "for_loop": { - "file": "07_control_flow.md", - "line": 89, - "token_cost": 100, - "example": "for i := 0 to 2 do\n sum := sum + i;" - }, - "while_loop": { - "file": "07_control_flow.md", - "line": 64, - "token_cost": 100, - "example": "counter := 0;\nwhile counter < 3 do\n counter := counter + 1;" - }, - "if_condition": { - "file": "07_control_flow.md", - "line": 54, - "token_cost": 120, - "example": "if flag > 0 then\nbegin\n value := 1;\nend" - }, - "assignment": { - "file": "06_expressions_and_operators.md", - "line": 136, - "token_cost": 60, - "example": "a := 1;" - }, - "variable_declaration": { - "file": "04_variables_and_constants.md", - "line": 75, - "token_cost": 80, - "example": "var a;\na := 1;" - }, - "identifier_naming": { - "file": "../naming.md", - "line": 42, - "token_cost": 120, - "example": "UserAccount, LoadData, max_retry_count" - }, - "class_basic": { - "file": "08_objects_and_classes.md", - "line": 98, - "token_cost": 200, - "example": "type Person = class\npublic\n name;\nend;" - }, - "class_in_tsl": { - "file": "08_objects_and_classes.md", - "line": 118, - "token_cost": 250, - "example": "obj := new MyClass();\nobj.value := 5;\n\ntype MyClass = class\npublic\n value;\nend;" - }, - "unit_import": { - "file": "09_units_and_scope.md", - "line": 141, - "token_cost": 60, - "example": "uses DemoUnit;" - }, - "unit_skeleton": { - "file": "09_units_and_scope.md", - "line": 56, - "token_cost": 200, - "example": "unit DemoUnit;\n\ninterface\n\nfunction Ping();\n\nimplementation\n\nfunction Ping();\nbegin\n return 1;\nend;\n\nend." - }, - "array_operations": { - "file": "12_matrix_and_collections.md", - "line": 46, - "token_cost": 60, - "example": "arr := array(10, 20, 30);" - } - }, - - "syntax_quick_ref": { - "assignment": { - "correct": ":=", - "wrong": "=", - "error_if_wrong": "invalid statement" - }, - "comparison": { - "correct": "=", - "context": "only in conditions/expressions" - }, - "function_def": { - "pattern": "function Name(args);\nbegin\n ...\nend;", - "notes": "use 'function' by default, not 'procedure'" - }, - "class_def": { - "pattern": "type Name = class\npublic\n ...\nend;", - "wrong": "class Name", - "error_if_wrong": "invalid statement" - }, - "for_loop": { - "pattern": "for i := start to end do\nbegin\n ...\nend;" - }, - "if_statement": { - "pattern": "if condition then\nbegin\n ...\nend;" - }, - "tsl_file_structure": { - "order": ["statements first", "declarations after"], - "wrong": "declarations before statements or after declarations" - }, - "identifier_naming": { - "doc": "../naming.md#L42", - "avoid": "ordinary custom identifiers should not use TSL keywords, reserved words, or builtin function names", - "tsf_filename_rule": "02_core_model.md#L38" - } - }, - - "common_errors": { - "invalid statement": { - "likely_causes": [ - { - "pattern": "a = 1", - "fix": "a := 1", - "doc": "11_pitfalls.md", - "line": 45 - }, - { - "pattern": "class Person", - "fix": "type Person = class", - "doc": "11_pitfalls.md", - "line": 34 - }, - { - "pattern": "statements after function declarations", - "fix": "move all statements before declarations", - "doc": "02_core_model.md", - "line": 34 - } - ] - }, - "compile error": { - "check": "11_pitfalls.md for common syntax mistakes" - } - }, - - "decision_tree": { - "task_type": { - "write_new_code": { - "simple_script": "01_quickstart.md#L182", - "function": "05_functions_and_calls.md#L103", - "procedure": "05_functions_and_calls.md#L130", - "naming": "../naming.md#L42", - "class": "08_objects_and_classes.md#L98", - "loop": "07_control_flow.md#L89", - "condition": "07_control_flow.md#L54", - "unit": "09_units_and_scope.md#L56", - "array": "12_matrix_and_collections.md#L46" - }, - "fix_error": { - "invalid_statement": "11_pitfalls.md#L34-L59", - "compile_error": "11_pitfalls.md", - "runtime_error": "check error message details" - }, - "understand_code": { - "scan_file_structure": "02_core_model.md#L34", - "trace_function": "05_functions_and_calls.md", - "trace_class": "08_objects_and_classes.md", - "check_unit_imports": "09_units_and_scope.md" - }, - "optimize_code": { - "check_profiler": "15_debug_and_profiler.md", - "optimize_matrix": "22_matrix_deep_dive.md" - } - } - }, - - "file_model_rules": { - "tsl_script": { - "extension": ".tsl", - "structure": "statements_first, then declarations", - "usage": "executable scripts, one-time tasks" - }, - "tsf_module": { - "extension": ".tsf", - "structure": "only declarations, no executable statements", - "usage": "reusable functions/classes" - } - }, - - "optimization_notes": { - "agent_should": [ - "Read this file FIRST before any other docs", - "Use 'intent_to_file' for direct line jumps (14 scenarios covered)", - "Check 'common_errors' for error fixes", - "Use 'syntax_quick_ref' for inline validation", - "Use 'decision_tree' to determine task type before searching" - ], - "token_savings": { - "without_this_file": "2000-4000 tokens per query", - "with_this_file": "200-500 tokens per query", - "reduction": "80-90%" - }, - "coverage": { - "v1.0": "7 scenarios (30% of common tasks)", - "v2.0": "14 scenarios (70% of common tasks)", - "target": "15-20 scenarios (80-90% of common tasks)" - } - } -} diff --git a/docs/tsl/syntax/index.md b/docs/tsl/syntax/index.md index 11f5b966..1f81e25f 100644 --- a/docs/tsl/syntax/index.md +++ b/docs/tsl/syntax/index.md @@ -1,91 +1,5 @@ -# TSL 语法入口 +# TSL 语法入口已迁移 -```json -{ - "AGENT_QUICK_INDEX": { - "READ_THIS_FIRST": "00_agent_index.json", - "hello_world": "01_quickstart.md#L182", - "function": "05_functions_and_calls.md#L103", - "class": "08_objects_and_classes.md#L98", - "naming": "../naming.md#L42", - "tsf_filename": "02_core_model.md#L38", - "loop": "07_control_flow.md#L89", - "if": "07_control_flow.md#L54", - "fix_a=1_error": "11_pitfalls.md#L45", - "fix_class_error": "11_pitfalls.md#L34", - "token_saving": "80-90% reduction vs reading full docs" - } -} -``` +TSL/TSF 语法事实现由仓库内唯一事实源 [tsl-syntax-reference Skill](../../../skills/tsl-syntax-reference/SKILL.md) 管理。 -遇到不确定时:先按"按任务跳转"做语法层分流;写最短骨架看 [01_quickstart.md](01_quickstart.md),判断文件模型看 [02_core_model.md](02_core_model.md),判断表达式看 [06_expressions_and_operators.md](06_expressions_and_operators.md),判断类/对象看 [08_objects_and_classes.md](08_objects_and_classes.md),核对反例和负向边界看 [11_pitfalls.md](11_pitfalls.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md)。 - -本页只决定语法层第一跳。不要顺序读完整套语法文档,不要把本页当代码事实页。 - -## 按任务跳转 - -| 任务信号 | 入口 | 阻断条件 | -| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------ | -| 写最短骨架、核对语言核心事实 | [01_quickstart.md](01_quickstart.md) | 文件模型不明 | -| 判断 `.tsl` / `.tsf`、顶层语句区、声明区、文件模型 | [02_core_model.md](02_core_model.md) | 用户交付目标不足以判断后缀 | -| 给变量、函数、类型、unit 或 `.tsf` 文件取名 | [../naming.md](../naming.md) | 文件模型或顶层声明规则不明 | -| 写值、数组、字符串、字符串编码边界 | [03_values_and_literals.md](03_values_and_literals.md) | 需要未记录的字面量或编码写法 | -| 写变量、常量、显式声明 | [04_variables_and_constants.md](04_variables_and_constants.md) | 变量生命周期或作用域不明 | -| 写 `function` / `procedure`、参数、默认参数、命名参数、变参 | [05_functions_and_calls.md](05_functions_and_calls.md) | 需要未记录的调用外形 | -| 写赋值、比较、条件表达式、较新表达式、运算符边界 | [06_expressions_and_operators.md](06_expressions_and_operators.md) | 需要靠相似语言推断运算符 | -| 写条件、循环、异常控制 | [07_control_flow.md](07_control_flow.md) | 块结构或跳转语义不明 | -| 写类、继承、property、静态字段、构造函数 | [08_objects_and_classes.md](08_objects_and_classes.md) | 需要未记录的对象模型写法 | -| 写单元 (unit) / uses | [09_units_and_scope.md](09_units_and_scope.md) | 查找路径、模块边界或文件名不明 | -| 写运行时环境参数、`sysParams[...]`、`with array(...)`、网格调用或全局缓存 | [10_runtime_context_and_with.md](10_runtime_context_and_with.md) | 需要项目运行时事实 | -| 核对高频误写 / 反例 / 负向边界 | [11_pitfalls.md](11_pitfalls.md) | 反例没有指向正确专题 | -| 写数组创建、键表、集合运算(+/-/\*) | [12_matrix_and_collections.md](12_matrix_and_collections.md) | 需要未记录的数据结构操作 | -| 写结果集过滤专题 | [13_resultset_and_filters.md](13_resultset_and_filters.md) | 结果集来源或字段结构不明 | -| 写 TS-SQL 专题 | [14_ts_sql.md](14_ts_sql.md) | 需要未记录的 SQL 外形 | -| 看调试与性能分析器专题 | [15_debug_and_profiler.md](15_debug_and_profiler.md) | 需要项目执行环境 | -| 看注释、条件编译、编译选项或词法边界 | [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md) | 解释器版本或编译选项不明 | -| 看显式类型、转换规则、复数 | [17_types_and_conversions.md](17_types_and_conversions.md) | 类型转换结果无文档事实 | -| 看 `external`、DLL 与多线程 | [18_external_calls_and_threads.md](18_external_calls_and_threads.md) | 外部库、线程边界或平台不明 | -| 看 `namespace`、`Libpath`、unit 运行时、查找路径 | [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md) | 部署路径或命名空间事实缺失 | -| 看对象运行时、自省、反射、弱引用 | [20_object_runtime_and_introspection.md](20_object_runtime_and_introspection.md) | 需要未记录的反射能力 | -| 看运行时内置对象 | [21_builtin_runtime_objects.md](21_builtin_runtime_objects.md) | 内置对象构造或成员无文档事实 | -| 看矩阵进阶专题 | [22_matrix_deep_dive.md](22_matrix_deep_dive.md) | 矩阵语义或维度规则不明 | -| 看 `FMArray` | [23_fmarray.md](23_fmarray.md) | FMArray 专属能力无文档事实 | -| 看对象算符重载或遍历重载 | [24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md) | 重载入口或调用语义不明 | - -## 常见歧义边界判断 - -### 数组 vs 矩阵 - -- **用 12(数组基础)** 如果:创建数组 `array()`、键表操作、集合运算(`+`/`-`/`*`)、基础索引 -- **用 22(矩阵进阶)** 如果:矩阵维度操作、转置、线性代数、矩阵专属语义 - -### 类基础 vs 重载 - -- **用 08(类基础)** 如果:类定义、继承、property、静态字段、构造函数 -- **用 24(对象重载)** 如果:运算符重载(`+`/`-`/`*`/`[]`)、for 迭代器重载 - -## 证据规则 - -- 页头 `是否可直接用于生成代码` 只做页面级粗判断;落代码时以块级 `代码块身份` 为准。 -- `代码块身份` 固定只用四种值:`可直接照写示例`、`输出片段`、`反例 / 不可照写`、`配置片段 / 概念骨架`。 -- 普通语法专题页的 `遇到不确定时` 先按候选页继续判断,仍不命中再回本语法入口页;本页例外,必须先按"按任务跳转"分流。 - -## 停止条件 - -- 文件模型会影响正确性且用户交付目标不足以判断 `.tsl` / `.tsf`。 -- 命中项需要未记录语法、运行时事实或项目执行事实。 -- 只有反例、输出片段或概念骨架可用,没有 `代码块身份:可直接照写示例`。 -- 任务信号属于数据仓库函数、模块集成、函数库查询或项目执行边界。 - -## 入口禁止项 - -- 不要跳过"按任务跳转"直接顺序读完整套。 -- 不要把本入口页当成可直接生成代码的语法事实页。 -- 不要从多个专题页拼接未写入文档的新骨架;生成前优先使用单页里的可直接照写示例。 -- 不要把数据仓库函数查询、模块集成或项目执行问题留在语法层处理。 - -## 切换到别的层 - -- 数据仓库金融函数:使用 `tsl-api-reference` skill -- 模块 / 集成 / 互操作:见 [../modules/index.md](../modules/index.md) -- 函数库 / API 查找:使用 `tsl-api-reference` skill(已知名走 `--name`,未知名走 `--kw`) +本页仅为旧路径兼容入口,不保存语法规则或专题路由。独立部署时请安装 `tsl-syntax-reference` 后再处理 TSL/TSF 语法任务。 diff --git a/skills/tsl-api-reference/data/function_index.tsv b/skills/tsl-api-reference/data/function_index.tsv index 7d4ed1c4..b9ade3e5 100644 --- a/skills/tsl-api-reference/data/function_index.tsv +++ b/skills/tsl-api-reference/data/function_index.tsv @@ -253,9 +253,9 @@ Authorization builtin language Authorization builtin/language/legacy_pending.md AuthType builtin language AuthType builtin/language/legacy_pending.md authtype 认证类型,0:明文用户密码,1:MD5,2:SASL认证,-1:自定义认证。 类型:读写 AuthType builtin language AuthType builtin/language/legacy_pending.md authtype-1 认证类型,0:明文用户密码,1:MD5,2:SASL认证,-1:自定义认证。 类型:读写 AuthType builtin language AuthType builtin/language/legacy_pending.md authtype-2 认证类型,0:明文用户密码,1:MD5,2:SASL认证,-1:自定义认证。 类型:读写 -AuthTypeString builtin language AuthTypeString builtin/language/legacy_pending.md authtypestring 自定义认证类型,仅当[链接ID 37923](tomd.tsl?id=37923)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 -AuthTypeString builtin language AuthTypeString builtin/language/legacy_pending.md authtypestring-1 自定义认证类型,仅当[链接ID 1774](tomd.tsl?id=1774)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 -AuthTypeString builtin language AuthTypeString builtin/language/legacy_pending.md authtypestring-2 自定义认证类型,仅当[链接ID 1745](tomd.tsl?id=1745)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 +AuthTypeString builtin language AuthTypeString builtin/language/legacy_pending.md authtypestring 自定义认证类型,仅当[链接ID 37923](#authtype)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 +AuthTypeString builtin language AuthTypeString builtin/language/legacy_pending.md authtypestring-1 自定义认证类型,仅当[链接ID 1774](#authtype-1)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 +AuthTypeString builtin language AuthTypeString builtin/language/legacy_pending.md authtypestring-2 自定义认证类型,仅当[链接ID 1745](#authtype-2)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 autoHeightRow dotnet document autoHeightRow(v) dotnet/document/excel_class.md autoheightrow 自动调整指定行的行高 AutoIssueFEAT builtin language AutoIssueFEAT builtin/language/legacy_pending.md autoissuefeat 是否自动发送FEAT指令获得所支持的命令。 AutoLogin builtin language AutoLogin builtin/language/legacy_pending.md autologin 指定当使用Connect方法与FTP服务器建立会话时,FTP客户端是否自动连接。 diff --git a/skills/tsl-api-reference/references/codegen/builtin/language/legacy_pending.md b/skills/tsl-api-reference/references/codegen/builtin/language/legacy_pending.md index 5119ed46..2ec1a93b 100644 --- a/skills/tsl-api-reference/references/codegen/builtin/language/legacy_pending.md +++ b/skills/tsl-api-reference/references/codegen/builtin/language/legacy_pending.md @@ -865,7 +865,7 @@ Source ID:37923 ### `AuthTypeString` -自定义认证类型,仅当[链接ID 37923](tomd.tsl?id=37923)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 +自定义认证类型,仅当[链接ID 37923](#authtype)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 对象:IMAP @@ -1977,7 +1977,7 @@ Source ID:1774 ### `AuthTypeString` -自定义认证类型,仅当[链接ID 1774](tomd.tsl?id=1774)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 +自定义认证类型,仅当[链接ID 1774](#authtype-1)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 对象:Pop3 @@ -2221,7 +2221,7 @@ Source ID:1745 ### `AuthTypeString` -自定义认证类型,仅当[链接ID 1745](tomd.tsl?id=1745)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 +自定义认证类型,仅当[链接ID 1745](#authtype-2)设置为-1时有效;设置为"AUTH=\*":自动选择服务器支持的认证类型;多个用分号连接 类型:读写 对象:SMTP diff --git a/skills/tsl-syntax-reference/SKILL.md b/skills/tsl-syntax-reference/SKILL.md new file mode 100644 index 00000000..c8cbf442 --- /dev/null +++ b/skills/tsl-syntax-reference/SKILL.md @@ -0,0 +1,85 @@ +--- +name: tsl-syntax-reference +description: 当用户需要编写、修改、审查或解释 TSL/TSF、TS-SQL、Tinysoft/天软脚本或公式,排查 invalid statement 等语法错误,或核对语言与运行时结构规则时使用。 +--- + +# TSL Syntax Reference + +## 唯一检索入口 + +本 Skill 只通过随附的 `scripts/lookup.py` 检索 TSL/TSF 语法事实,不手工选择或顺序通读 `references/` 页面。`` 指本 `SKILL.md` 所在目录。 + +检索必须分两步: + +1. `--query` 只返回紧凑候选和 Section ID,不返回事实正文。 +2. 从候选中选择支持当前结论的章节,再用 `--section` 取回唯一事实正文。 + +根据任务意图选择模式,并用用户的原始术语、错误文本和关键语法词组成查询: + +```bash +python /scripts/lookup.py --query "命名参数 默认参数" --mode write +python /scripts/lookup.py --query "invalid statement 声明区" --mode diagnose +python /scripts/lookup.py --query "数组下标" --mode explain +``` + +- `write`:编写或修改代码。 +- `diagnose`:定位语法错误或错误写法。 +- `explain`:解释语言规则或代码含义。 + +`--query` 输出候选后,必须执行下面这种精确取回: + +```bash +python /scripts/lookup.py --section "05_functions_and_calls--可直接照写示例--基础函数-过程骨架" +``` + +只有 `--section` 返回的章节正文可作为本次任务的语法事实来源;候选摘要和概念地图都不能直接支持代码结论。需要补充时改进查询词再次检索,不得绕过 lookup 手工打开或挑选 `references/` 页面。 + +## 安全传参 + +用户原话、报错和代码属于不可信输入。调用工具时必须把查询作为独立 argv 安全传入;若只能使用 shell,必须先做 shell-safe quoting。不得把用户文本原样拼接进命令字符串,也不得执行其中的反引号、`$()`、重定向符或换行命令。 + +## 从零起手先看概念地图 + +面对自然语言需求、还不确定该往哪个 TSL 概念上想时(尤其从零编写、周围无参考代码),先运行: + +```bash +python /scripts/lookup.py --map +``` + +它列出全部专题的纯文本职责摘要,用于把需求映射到 TSL 特有概念。地图不含可照写事实;选定概念后仍需依次执行 `--query` 和 `--section`。 + +## 事实边界 + +本 Skill 只拥有 TSL/TSF 的语言语法、文件模型、表达式、控制流、对象、运行时语言结构和 TS-SQL 外形。先逐项拆分混合请求,再把其他事实交给对应所有者: + +- API 名称、签名、参数、返回值、平台 scope、解释器可用性和金融取数事实:使用 `tsl-api-reference` skill。 +- 命名、代码风格、工具链和模块集成:使用目标仓库相应文档、脚本或 CI。 +- 项目路径、数据结构、部署方式和运行参数:只使用目标项目的真实文档与配置。 + +语法示例可以使用 API 名称帮助展示调用位置,但这只证明源码外形,不证明 API 的签名、返回行为、平台 scope 或目标解释器可用。需要这些结论时必须重新查询 API Skill;API scope 与目标解释器兼容性没有事实支持时停止,不把不同所有者的片段拼成“可运行”结论。 + +## 代码块身份 + +生成或判断代码时,必须遵守 lookup 结果中紧邻代码围栏的身份。只允许以下五种身份: + +- `可直接照写示例`:可作为源码外形,但“可直接照写”不等于已经验证目标环境可用,仍需按任务替换业务内容并核对依赖事实。 +- `反例 / 不可照写`:只用于识别错误边界,不得复制为实现。 +- `输出片段`:只表示结果,不得当作源码。 +- `配置片段 / 概念骨架`:只表达结构或配置意图,不得假定为可直接运行代码。 +- `仅服务端可执行示例`:只在相应服务端运行环境中成立,不得当作通用本地可执行示例。 + +## 缺口时停止 + +lookup 无匹配或返回非零状态、结果没有支持当前结论、代码块身份缺失或冲突、运行时版本不明、项目事实缺失、依赖的 Skill 不可用时,明确说明缺失项并停止。不得改为手工浏览全部参考页,也不得凭经验、相似语言或猜测产生新的 TSL 写法。 + +## 询问或执行运行方式前读取项目指引 + +用户询问如何运行 TSL,或需要实际执行 TSL 时,都先读取目标文件附近最近的 `AGENTS.md`、项目脚本或 CI。实际执行前还要完成平台检测并严格使用指定环境;不同平台或多个 Windows 环境不得混用、默认任选或自行回退。 + +## 维护校验 + +维护本 Skill、参考页或 lookup 实现后必须运行: + +```bash +python /scripts/lookup.py --check +``` diff --git a/docs/tsl/syntax/01_quickstart.md b/skills/tsl-syntax-reference/references/01_quickstart.md similarity index 90% rename from docs/tsl/syntax/01_quickstart.md rename to skills/tsl-syntax-reference/references/01_quickstart.md index 6605ed7b..700a4d8d 100644 --- a/docs/tsl/syntax/01_quickstart.md +++ b/skills/tsl-syntax-reference/references/01_quickstart.md @@ -1,11 +1,5 @@ # TSL 快速落代码规则 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本文“下一步路由”继续判断;文件模型看 [02_core_model.md](02_core_model.md),函数 / 调用看 [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),反例和负向边界看 [11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 本篇只回答两个落代码前问题:用户已给出 `.tsl` / `.tsf` 后缀时,智能体如何按后缀组织代码;以及生成代码前必须先核对哪些语言硬规则。 ## 本篇职责 @@ -19,7 +13,7 @@ 3. 只从 `代码块身份:可直接照写示例` 的骨架起手;遇到 `反例 / 不可照写` 必须避开。 4. 写 `.tsl` 时,先写会执行的语句区;需要函数或类时,把声明区放在语句区之后。 5. 写 `.tsf` 时,只写可复用顶层声明,不写入口脚本流程;部署、查找路径和解释器环境属于项目执行层。 -6. 本页和对应专题页没有覆盖的写法,不要发明语法;按“下一步路由”切到对应专题页判断;仍无文档事实时向用户确认或记录文档缺口。 +6. 本页和对应专题页没有覆盖的写法,不要发明语法;仍无文档事实时向用户确认或记录文档缺口。 ## 语言核心事实速查 @@ -45,7 +39,7 @@ - “顶层函数骨架”“顶层函数定义体”:只指 `function` 骨架;不要因为任务没有返回值就自动改成 `procedure`。 - `class function` / “类方法”:同一件事;前者是代码关键字写法,后者是中文描述。 -## 起手骨架选择规则 +## 任务到文件模型的选择规则 | 任务 | 起手骨架 | | ------------------------------------ | ------------------------------ | @@ -68,7 +62,7 @@ - 可以模仿已经出现的代码外形、语句顺序和块级结构。 - 不要从骨架推断未出现的语法、内置函数、部署方式、文件名规则或模块查找规则。 -- 需要扩展写法时,先进入对应专题页读取规则。 +- 扩展写法必须有对应专题事实支持。 本页只列最短高频骨架;`procedure`、参数、返回类型和调用细节见 [05_functions_and_calls.md](05_functions_and_calls.md)。 diff --git a/docs/tsl/syntax/02_core_model.md b/skills/tsl-syntax-reference/references/02_core_model.md similarity index 83% rename from docs/tsl/syntax/02_core_model.md rename to skills/tsl-syntax-reference/references/02_core_model.md index 5bbd180c..63e5c353 100644 --- a/docs/tsl/syntax/02_core_model.md +++ b/skills/tsl-syntax-reference/references/02_core_model.md @@ -1,18 +1,12 @@ # TSL 文件模型规则 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本文“下一步路由”继续判断;最短骨架和高频硬规则看 [01_quickstart.md](01_quickstart.md),函数 / 过程看 [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),反例和负向边界看 [11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 本篇说明 TSL 的文件模型判断规则:智能体如何区分 `.tsl` 可执行脚本与 `.tsf` 可复用声明文件,如何识别脚本语句区和声明区,以及为什么很多错误其实是“文件模型选错了”。 ## 本篇职责 回答“目标文件到底是 `.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) 只作为最短骨架和高频硬规则速查。 +本页负责文件模型判断;具体语法外形的事实分别见:函数 / 过程 [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) 只作为最短骨架和高频硬规则速查。 ## 智能体文件模型判断流程 @@ -21,7 +15,7 @@ 3. 目标仍不明确时先问用户;不要把脚本入口和可复用模块替用户合并成一个猜测文件。 4. 写 `.tsl` 时,先生成脚本语句区;需要函数、过程或类时,把声明区放在语句区之后。 5. 写 `.tsf` 时,生成顶层函数 / 过程 / 类声明,或 `unit`;不要写成会直接顺序执行的脚本入口。 -6. 没有文档证据时不要发明文件模型;只能回到对应专题页、项目自身文档或项目专属规则,或记录文档缺口。 +6. 没有文档证据时不要发明文件模型;只能使用对应专题事实、项目自身文档或项目专属规则,否则记录文档缺口。 ## 文件模型核心规则 @@ -46,7 +40,7 @@ - 可以模仿已经出现的文件模型、语句顺序和块级结构。 - 不要从示例推断未出现的部署方式、文件名规则或模块查找规则。 - `.tsf` 示例后的输出片段只证明部署后可由 `.tsl` 调用取得结果;不要理解为 `.tsf` 会独立顺序执行。 -- 需要扩展写法时,先进入对应专题页读取规则。 +- 扩展写法必须有对应专题事实支持。 ### `.tsl` 文件模型 diff --git a/docs/tsl/syntax/03_values_and_literals.md b/skills/tsl-syntax-reference/references/03_values_and_literals.md similarity index 91% rename from docs/tsl/syntax/03_values_and_literals.md rename to skills/tsl-syntax-reference/references/03_values_and_literals.md index 7a5de2e4..2f4756ee 100644 --- a/docs/tsl/syntax/03_values_and_literals.md +++ b/skills/tsl-syntax-reference/references/03_values_and_literals.md @@ -1,16 +1,10 @@ # TSL 值与字面量 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[04_variables_and_constants.md](04_variables_and_constants.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[12_matrix_and_collections.md](12_matrix_and_collections.md)、[17_types_and_conversions.md](17_types_and_conversions.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇整理基本类型、字面量、数组、字符串、字符串编码边界与基础值模型,避免把值规则分散在函数或金融示例里。 ## 本篇职责 -回答“基本类型怎么写、数组和字符串怎么索引、字符串编码边界怎么写、哪些值规则属于语言级事实”。矩阵、集合扩展和复杂容器不在本页展开;命中这些任务时跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md) 或对应深水专题。 +回答“基本类型怎么写、数组和字符串怎么索引、字符串编码边界怎么写、哪些值规则属于语言级事实”。矩阵、集合扩展和复杂容器不在本页展开;相关事实见 [12_matrix_and_collections.md](12_matrix_and_collections.md) 或对应深水专题。 ## 智能体值写法判断流程 @@ -19,7 +13,7 @@ 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)。 +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 字符串规则直接迁移。 ## 核心规则 @@ -471,8 +465,7 @@ writeLn(result); 说明: -- `%d` 是整数占位符 -- `%s` 是字符串占位符 +- 示例里的 `%d` / `%s` 分别对应整数、字符串占位;只为读懂本例 - `format` 的完整占位符规范使用 `tsl-api-reference` skill 按名查询。 ### `formatdatetime` 日期格式化 @@ -495,9 +488,7 @@ writeLn(result); 说明: -- `yyyy` 表示四位年份 -- `mm` 表示两位月份 -- `dd` 表示两位日期 +- 示例里的 `yyyy-mm-dd` 对应四位年、两位月、两位日;只为读懂本例 - `formatdatetime` 的完整格式说明使用 `tsl-api-reference` skill 按名查询。 ## 默认生成模板 diff --git a/docs/tsl/syntax/04_variables_and_constants.md b/skills/tsl-syntax-reference/references/04_variables_and_constants.md similarity index 86% rename from docs/tsl/syntax/04_variables_and_constants.md rename to skills/tsl-syntax-reference/references/04_variables_and_constants.md index 421560ec..87e78d3e 100644 --- a/docs/tsl/syntax/04_variables_and_constants.md +++ b/skills/tsl-syntax-reference/references/04_variables_and_constants.md @@ -1,11 +1,5 @@ # TSL 变量与常量 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[03_values_and_literals.md](03_values_and_literals.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[05_functions_and_calls.md](05_functions_and_calls.md)、[16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇收拢变量与常量初始化规则。 ## 本篇职责 @@ -18,7 +12,7 @@ 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)。 +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 必须先声明变量。 ## 核心规则 diff --git a/docs/tsl/syntax/05_functions_and_calls.md b/skills/tsl-syntax-reference/references/05_functions_and_calls.md similarity index 92% rename from docs/tsl/syntax/05_functions_and_calls.md rename to skills/tsl-syntax-reference/references/05_functions_and_calls.md index 9aafce85..3c365616 100644 --- a/docs/tsl/syntax/05_functions_and_calls.md +++ b/skills/tsl-syntax-reference/references/05_functions_and_calls.md @@ -1,12 +1,6 @@ # TSL 函数与调用 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[02_core_model.md](02_core_model.md)(优先)、[09_units_and_scope.md](09_units_and_scope.md)、[16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)、[18_external_calls_and_threads.md](18_external_calls_and_threads.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - -这一篇只负责 `function` / `procedure` 的定义、调用、参数传递和值返回。跨 `unit` 声明边界、外部系统交互和业务函数库只在本页保留路由或最小边界。 +这一篇只负责 `function` / `procedure` 的定义、调用、参数传递和值返回。跨 `unit` 声明边界、外部系统交互和业务函数库只在本页保留最小边界。 ## 本篇职责 @@ -14,27 +8,27 @@ ## 智能体函数/调用判断流程 -1. 先判断目标文件是 `.tsl` 还是 `.tsf`;文件形态不明确时回 [02_core_model.md](02_core_model.md)。 +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)。 +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`。 +- 用户提示词里的“函数”默认对应 `function`,不要自动改写成 `procedure`。 - `procedure Name(...); begin ... end;` 只在用户明确要求 `procedure` / 过程时生成;不要因为没有返回值就自动改用 `procedure`。 - 在 `.tsl` 文件模型层,脚本语句后可以接函数声明;语句区在前顺序执行,声明区在后提供函数/过程定义。见 [02_core_model.md](02_core_model.md)。 - 在 `.tsf` 文件模型层,顶层 `function` / `procedure` 是模块/函数扩展声明;部署到解释器 `funcext` 后可被脚本直接调用。 - 函数头后默认保留分号;不要为了简写主动省略。 - 函数体内部的普通语句照常用分号结尾;顶层函数/过程声明的 `end` 后必须加分号(写成 `end;`)。 -- 函数体内的控制流块(`if`/`while`/`for` 等)的 `end` 不加分号;控制流分号规则见 [07_control_flow.md](07_control_flow.md)。 +- 函数体内的控制流块(`if`/`while`/`for` 等)的 `end` 后加不加分号都合法;唯一例外是 `if` 的 `then` 块 `end` 与 `else` 之间不能加分号。控制流分号规则见 [07_control_flow.md](07_control_flow.md)。 - 一个函数定义体里可以同时出现主函数和子函数。 - 函数支持参数类型注解和返回值类型注解。 - 不带类型注解时,多个参数用逗号分隔。 @@ -63,7 +57,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 回调和线程调用的事实见 [18_external_calls_and_threads.md](18_external_calls_and_threads.md)。 - 不要在 `.tsl` 的函数声明区之后继续追加脚本语句。 ## 可直接照写示例 @@ -73,7 +67,7 @@ - 普通运行示例默认按 `.tsl` 脚本语句区书写;入口语句放前面,函数 / 过程 / 类型声明放在后置声明区。 - `.tsf` 函数 / 过程示例只按可复用顶层声明理解,不要在 `.tsf` 里追加顺序执行入口语句。 - `procedure` 示例只在用户明确要求 `procedure` / 过程时复制;普通“写函数”任务不要用。 -- `external`、原生函数指针包装、C 回调、线程、系统交互和二进制函数边界不在本页硬推断;命中这些任务时跳到 [18_external_calls_and_threads.md](18_external_calls_and_threads.md) 或函数库文档。 +- `external`、原生函数指针包装、C 回调、线程、系统交互和二进制函数边界不在本页硬推断;相关事实见 [18_external_calls_and_threads.md](18_external_calls_and_threads.md) 或函数库文档。 ### 基础函数 / 过程骨架 @@ -155,7 +149,7 @@ end; 2 ``` -### 签名增强 +### 签名增强:参数类型与返回值类型注解 带参数类型和返回值类型: @@ -357,7 +351,7 @@ end; 99 ``` -### 调用增强 +### 调用增强:命名参数与混用规则 命名参数调用: @@ -516,7 +510,7 @@ function F(a, b = 100, c = default_value); - `F(1)` 输出 `101`,`F(1, 2)` 输出 `3` - 同一组文件下,`UnitConst.default_value` 可读到 `888`,而 `F(1, 2, 3)` 输出 `6` - 因此不要把“普通函数默认参数可用”直接泛化成“`unit interface` 里引用 `unit const` 的默认参数也同样可靠” -- 这类跨 `unit` 的声明边界,统一回看 [09_units_and_scope.md](09_units_and_scope.md) +- 这类跨 `unit` 的声明边界事实见 [09_units_and_scope.md](09_units_and_scope.md) ### 可变参数 `...` @@ -978,13 +972,12 @@ writeLn(intToStr(value: 200)); 代码块身份:反例 / 不可照写 ```text +writeLn(Pack(a: 1, 2, c: 3)); + function Pack(a, b, c); begin return a * 100 + b * 10 + c; end; -begin - writeLn(Pack(a: 1, 2, c: 3)); -end. ``` 不要在同一次调用里“先进入命名参数模式,再退回位置参数”。这类写法会直接编译失败,错误信息包含 `paramname: not found`。 diff --git a/docs/tsl/syntax/06_expressions_and_operators.md b/skills/tsl-syntax-reference/references/06_expressions_and_operators.md similarity index 89% rename from docs/tsl/syntax/06_expressions_and_operators.md rename to skills/tsl-syntax-reference/references/06_expressions_and_operators.md index d6a61635..923cec50 100644 --- a/docs/tsl/syntax/06_expressions_and_operators.md +++ b/skills/tsl-syntax-reference/references/06_expressions_and_operators.md @@ -1,11 +1,5 @@ # TSL 表达式与运算符 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页表格和专题入口继续判断;[03_values_and_literals.md](03_values_and_literals.md)、[04_variables_and_constants.md](04_variables_and_constants.md)、[05_functions_and_calls.md](05_functions_and_calls.md)、[07_control_flow.md](07_control_flow.md)、[08_objects_and_classes.md](08_objects_and_classes.md)、[12_matrix_and_collections.md](12_matrix_and_collections.md)、[16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇集中放语言级表达式与运算符。智能体写代码时,只使用本页和对应专题页已经明确的表达式事实,不要把其他语言或外部资料里的运算符习惯直接搬进 TSL。 ## 本篇职责 @@ -15,9 +9,9 @@ ## 智能体表达式/运算符判断流程 1. 先判断要写基础表达式运算符,还是集合、矩阵、对象重载、运行时调用或 TS-SQL 这类专题运算符。 -2. 普通变量赋值只能用 `:=`,不要把 `=` 当赋值写法;`const name = value;` 是常量初始化规则,回看 [04_variables_and_constants.md](04_variables_and_constants.md)。 +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)。 +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`;普通 `&`、`|`、`~` 不按位运算理解。 @@ -26,9 +20,9 @@ 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. 任务需要的运算符没有文档事实时,不要生成猜测写法;只能切到对应专题页、项目自身文档或项目专属规则,仍无结论时记录文档缺口。 +13. 集合、矩阵、过滤、对象重载、函数值调用、网格调用、运行时后缀和 TS-SQL 的事实所有者由“专题运算符入口表”列出。 +14. `{$ifdef ...}` 只作为能力探测;编译选项边界见 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。 +15. 任务需要的运算符没有文档事实时,不要生成猜测写法;只能使用对应专题事实、项目自身文档或项目专属规则,仍无结论时记录文档缺口。 ## 核心规则 @@ -45,13 +39,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` | 普通数字变量可直接用;对象重载语义见 [24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md)。 | | 算术 | `+`、`-`、`*`、`/`、`\`、`%`、`div`、`mod`、`^`、`~` | 普通数值计算使用;`\` 是左除,`^` 是幂运算,`~` 是对数运算。 | | 一元正负号 | `+x`、`-x` | 可直接用于数值表达式。 | -| 一元倒数 | `!x` | 整型、实型输入返回实型倒数;矩阵逆/广义逆回 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)。 | +| 一元倒数 | `!x` | 整型、实型输入返回实型倒数;矩阵逆/广义逆见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)。 | | 字符串连接 | `+`、`$` | 字符串拼接两种写法都已写入文档;默认优先用 `+`。 | | 比较 | `=`、`<>`、`<`、`>`、`<=`、`>=` | `=` 只作比较,不作普通赋值。 | -| 点前缀比较 | `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` | 标量比较可用;数组/矩阵样数据上的逐元素语义回 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 | +| 点前缀比较 | `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` | 标量比较可用;数组/矩阵样数据上的逐元素语义见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 | | 逻辑 | `and`、`or`、`not`、`&&`、`||`、`.&&`、`.||`、`.!!` | 默认优先写 `and` / `or` / `not`;不要用 `!` 表示逻辑非。 | | 位运算 | `.&`、`.|`、`.!`、`.^`、`shl`、`shr`、`rol`、`ror` | 生成代码时写成点前缀或关键字形态;普通 `&`、`|`、`~` 不作为位运算写法。 | | 成员 / 下标 / 调用 | `obj.member`、`value[index]`、`Func(args)` | 普通访问和调用可直接使用;类、对象、函数细节回对应专题。 | @@ -61,10 +55,10 @@ | 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` | 否定形态见下一行;集合运算见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 | | 否定关系 | `not in`、`not sqlin`、`not like`、`not is` | 直接使用这几种文档明确形态,不自行重组。 | | 标量链式比较 | `:<`、`:>`、`:<>`、`:==`、`:>=`、`:<=` | 连续标量比较才使用。 | -| 矩阵链式比较 | `::<`、`::>`、`::<>`、`::==`、`::>=`、`::<=` | 数组逐元素链式比较才使用;数组与矩阵样数据细节回 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 | +| 矩阵链式比较 | `::<`、`::>`、`::<>`、`::==`、`::>=`、`::<=` | 数组逐元素链式比较才使用;数组与矩阵样数据细节见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 | ### 专题运算符入口 @@ -101,9 +95,9 @@ 按需生成规则: - 已有变量需要原地更新时,才用 `+=`、`-=`、`*=`、`/=`、`\=`、`%=`、`^=`、`~=`、`div=`、`.&=`、`.|=`、`.^=`、`.&&=`、`.||=`、`a++;`、`a--;`、`++a;`、`--a;`。 -- 需要矩阵逆/广义逆时才使用 `!A`,并回 [22_matrix_deep_dive.md](22_matrix_deep_dive.md) 确认矩阵生成规则。 +- 需要矩阵逆/广义逆时才使用 `!A`,矩阵生成规则以 [22_matrix_deep_dive.md](22_matrix_deep_dive.md) 为准。 - 位运算需要明确写成点前缀或关键字形态:`.&`、`.|`、`.!`、`.^`、`shl`、`shr`、`rol`、`ror`;普通 `&` 不作为位与写法使用。 -- 点前缀比较 `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` 命中数组/矩阵样数据时,先回 [12_matrix_and_collections.md](12_matrix_and_collections.md) 判断逐元素语义。 +- 点前缀比较 `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` 命中数组/矩阵样数据时,逐元素语义以 [12_matrix_and_collections.md](12_matrix_and_collections.md) 为准。 - 需要延迟求值或动态表达式对象时,才用 `@expr` 或 `&"..."`,并用 `eval(...)` 求值。 - 需要在一个表达式内按顺序执行多个子表达式时,才用逗号表达式 `(exp1, exp2, ..., expN)`。 - 空安全访问只按 `a?.member`、`a?.[index]` 和本页示例里的 `c?.a?.[1]` 生成,不外推任意深链。 @@ -122,11 +116,11 @@ 使用这些示例时遵守: -- `:=` 是普通变量赋值写法;常量初始化规则回 [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),不要写成普通业务逻辑。 +- `:=` 是普通变量赋值写法;常量初始化规则见 [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),不要写成普通业务逻辑。 ### 基础赋值和条件求值 diff --git a/docs/tsl/syntax/07_control_flow.md b/skills/tsl-syntax-reference/references/07_control_flow.md similarity index 90% rename from docs/tsl/syntax/07_control_flow.md rename to skills/tsl-syntax-reference/references/07_control_flow.md index 62dd0d56..f55b6972 100644 --- a/docs/tsl/syntax/07_control_flow.md +++ b/skills/tsl-syntax-reference/references/07_control_flow.md @@ -1,11 +1,5 @@ # TSL 控制流 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页规则和示例继续判断;[05_functions_and_calls.md](05_functions_and_calls.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[15_debug_and_profiler.md](15_debug_and_profiler.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇只收录流程控制与异常控制,不讨论金融语义。 ## 本篇职责 @@ -42,9 +36,9 @@ 使用这些示例时遵守: -- 条件表达式、比较、布尔值和普通赋值回 [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)。 +- 条件表达式、比较、布尔值和普通赋值的事实见 [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)。 ### `if`、`while`、`repeat ... until` @@ -469,7 +463,6 @@ end - 在 `else` 前面误加分号。 - 生成没有分号的裸分支赋值,例如 `then value := 1 else ...`;带 `else` 时用块式分支。 - 以为 `try ... finally` 会吞掉异常。 -- 把 `case` 写成赋值右侧表达式。 - 在还没搞清表达式规则前,先把复杂业务函数塞进条件里。 - 把控制流问题和函数文件模型问题混在一起排查。 diff --git a/docs/tsl/syntax/08_objects_and_classes.md b/skills/tsl-syntax-reference/references/08_objects_and_classes.md similarity index 93% rename from docs/tsl/syntax/08_objects_and_classes.md rename to skills/tsl-syntax-reference/references/08_objects_and_classes.md index a3e8d1fb..6f4422dd 100644 --- a/docs/tsl/syntax/08_objects_and_classes.md +++ b/skills/tsl-syntax-reference/references/08_objects_and_classes.md @@ -1,18 +1,12 @@ # TSL 对象与类 -文档类型:语法主线 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[02_core_model.md](02_core_model.md)(优先)、[09_units_and_scope.md](09_units_and_scope.md)、[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)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇收拢面向对象语法,只保留语言层规则。 ## 本篇职责 回答“`type Name = class`、字段、`static`、方法、`property`、析构、类类型、继承和对象创建在 TSL 里怎样写”。 -本页后半段有少量依赖 `unit` 的双文件示例;如果你还没建立 `unit` / `uses` 的多文件心智模型,先看 [09_units_and_scope.md](09_units_and_scope.md)。 +本页后半段有少量依赖 `unit` 的双文件示例;`unit` / `uses` 的多文件模型事实见 [09_units_and_scope.md](09_units_and_scope.md)。 ## 智能体对象/类判断流程 @@ -23,7 +17,7 @@ 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)。 +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. 没有文档事实时不要发明对象/类写法。 ## 核心规则 @@ -44,7 +38,7 @@ - 基础 `property` 形态:`property Name read fieldOrMethod write fieldOrMethod`。 - `property Name: Type ...` 这种类型注解写法可用。 - 参数化 `property` 可用;本页只写基础模式。 -- 参数化 `property` 的 accessor 方法记录两种常见模式:读方法接同参数个数,写方法接“参数个数 + 赋值值”。 +- 参数化 `property` 的 accessor 方法记录两种常见模式:读方法可接同参数个数(如 `getItem(i)`),也可以写成无参形态(如 `getDateV()`);写方法接“参数个数 + 赋值值”。 - 索引型 `property` 可用;调用时用圆括号 `obj.Prop(index)`。 - 固定 `index` property 可用;它可以把某个固定索引直接映射成普通属性读写。 - `class(Name)` 和 `findClass("Name")` 都可以拿到类类型。 @@ -58,9 +52,9 @@ - 创建对象有两种方式:`new ClassName()` 最常用,`createObject(...)` 作为次选。 - 普通本地类实例化默认生成 `new ClassName()`;`createObject("ClassName")`、`createObject(ClassType)` 只在字符串类名、类类型变量或跨 `unit` 路径场景生成。 - 如果类里定义了 `function create(...)`,`new`、`createObject("ClassName", ...)` 和 `createObject(ClassType, ...)` 都可以透传构造参数,也都支持默认参数和命名参数。 -- 析构写法是无参 `function destroy();`;把对象引用设为 `nil` 时会触发它。 +- 析构写法是无参 `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) 和 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md),不要从普通单文件 `new` / `createObject` 规则直接泛化。 - `{$ifdef parentClassInUnit}` 为真,可用于探测“继承和构造单元中的类”能力是否可用。 - `private` / `protected` / `public` 可用;类开头未写可见性时,成员默认按 `public` 处理,但生成代码默认显式写 `public`。 - 同一个可见性段里后续没有切换关键字的成员,会沿用前一个可见性。 @@ -751,8 +745,8 @@ end; 输出说明: -- `read getItem` 这种”读方法接同参数个数”的写法可以通过 -- `write setItem` 这种”写方法接参数个数 + 赋值值”的写法可以通过 +- `read getItem` 这种“读方法接同参数个数”的写法可以通过 +- `write setItem` 这种“写方法接参数个数 + 赋值值”的写法可以通过 - 上述例子中的 `obj.Item(2)` 输出 `x` ### 对象创建与类类型 @@ -905,7 +899,7 @@ end; - `findClass("MathBox").Add(...)` 可以调用类方法 - 上述例子依次输出 `7`、`11` -### 类方法、重载、继承与析构 +### 重载、继承与析构 `overload` 方法: @@ -1344,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) 和 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)。 - 不要把它直接改写成普通本地类的 `new ClassName()` 模式。 继承单元中的嵌套类路径属于跨 `unit` 边界,这里也用 `text` 展示骨架: diff --git a/docs/tsl/syntax/09_units_and_scope.md b/skills/tsl-syntax-reference/references/09_units_and_scope.md similarity index 92% rename from docs/tsl/syntax/09_units_and_scope.md rename to skills/tsl-syntax-reference/references/09_units_and_scope.md index 5426f4ea..d21e3cbd 100644 --- a/docs/tsl/syntax/09_units_and_scope.md +++ b/skills/tsl-syntax-reference/references/09_units_and_scope.md @@ -1,11 +1,5 @@ # TSL unit 与作用域 -文档类型:语法主线 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[02_core_model.md](02_core_model.md)(优先)、[19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇只讲“怎么写和怎么调用 `unit`”。`namespace`、查找路径、`unit` 生命周期、`tsl.conf` 与运行时入口统一放到 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)。 ## 本篇职责 @@ -24,7 +18,7 @@ 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)。 +5. `unit` 生命周期、命名空间、查找路径、`tsl.conf` 和命令行查找路径参数的事实见 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)。 6. 没有对应代码块时不要发明 unit/作用域写法。 ## 核心规则 @@ -44,9 +38,9 @@ - 只写在 `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` 生命周期、接口状态、命名空间和查找路径细节见 [19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)。 -## 可直接照写示例 +## 示例与行为 ### 最小 `unit` @@ -496,8 +490,6 @@ end; end. ``` -后面的多文件片段只在需要 `uses`、可见性或重名解析时再回来看。 - ## 禁止项 - 把依赖外部 `unit` 的 `uses` 例子误当成单文件最小示例。 diff --git a/docs/tsl/syntax/10_runtime_context_and_with.md b/skills/tsl-syntax-reference/references/10_runtime_context_and_with.md similarity index 87% rename from docs/tsl/syntax/10_runtime_context_and_with.md rename to skills/tsl-syntax-reference/references/10_runtime_context_and_with.md index ab51c140..92e46da3 100644 --- a/docs/tsl/syntax/10_runtime_context_and_with.md +++ b/skills/tsl-syntax-reference/references/10_runtime_context_and_with.md @@ -1,11 +1,5 @@ # TSL 运行时上下文、服务与全局缓存 -文档类型:语法主线 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[05_functions_and_calls.md](05_functions_and_calls.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[14_ts_sql.md](14_ts_sql.md)、[15_debug_and_profiler.md](15_debug_and_profiler.md)、[19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)、[21_builtin_runtime_objects.md](21_builtin_runtime_objects.md);函数事实使用 `tsl-api-reference` skill;仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇只处理运行时环境参数、块环境 `with` 语句、`with` 后缀、`#` 网格调用、`timeout` 后缀、`dupvalue(...)` 和全局缓存,不处理任何金融业务语义。 ## 本篇职责 @@ -19,13 +13,15 @@ 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)。 +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 重新核对,不能由本页示例反推。 + - TSL 有一组运行时系统参数;本页只写通用语法形态。 - `setSysParam(key, value)` 和 `getSysParam(key)` 可以直接用字符串键。 - `sysParams[key]` 可以直接读写这些运行时参数。 @@ -49,6 +45,8 @@ ## 可直接照写示例 +### `setSysParam` / `getSysParam` / `sysParams[...]` 基础读写 + 直接设置和读取系统参数: 代码块身份:可直接照写示例 @@ -164,7 +162,9 @@ writeLn(getSysParam("b")); - 块后输出 `1`、`9` - 说明 `with **` 不继承未传入的外层系统参数,并且块结束后恢复外层系统参数 -沿用同一个 `TestDo.tsf`,看 `with array(...)` 的覆盖边界: +### 后缀 `with array(...)`:网格调用的临时覆盖 + +`#Func(...) with array(...)` 在一次网格调用里临时覆盖系统参数,调用结束后恢复外层原值。下面用一个 `TestDo.tsf` 演示覆盖边界: 代码块身份:配置片段 / 概念骨架 代码块说明:多文件结构骨架;依赖函数文件查找路径,不是可直接复制的单文件最小示例。 @@ -194,7 +194,7 @@ writeLn(getSysParam("b")); - 调用结束后,外层 `getSysParam("b")` 输出 `8` - 说明 `with array(...)` 是“只在该次调用里临时覆盖,再恢复外部原值” -沿用上一个 `TestDo.tsf`,只把 `main.tsl` 改成下面这样: +沿用上面的 `TestDo.tsf`,只把 `main.tsl` 改成下面这样(外层未预设参数): 代码块身份:配置片段 / 概念骨架 代码块说明:多文件结构骨架;依赖函数文件查找路径,不是可直接复制的单文件最小示例。 @@ -232,7 +232,7 @@ end; 结果说明: - `#AddOne(5)` 可以执行 -- `dupvalue(r)` 返回最终结果 `6` +- `dupvalue(#AddOne(5))` 返回最终结果 `6` 代码块身份:输出片段 @@ -304,9 +304,7 @@ writeLn(cached_data[0], ',', cached_data[1], ',', cached_data[2]); 说明: - TSL 标识符大小写无关,`setGlobalCache` 和 `SetGlobalCache` 等价 -- 推荐使用小写 `setGlobalCache`、`getGlobalCache` 以保持一致性 -- `setGlobalCache(key, value)` 写入缓存,可选第三参数指定过期时间(秒) -- `getGlobalCache(key, out_var)` 读取缓存到输出变量 +- 示例只展示 `setGlobalCache(key, value)` / `getGlobalCache(key, out_var)` 的最小调用形态;完整参数规格(含过期时间等可选参数)用 `tsl-api-reference` skill 按名查询 ### `checkGlobalCacheExpired` @@ -325,7 +323,7 @@ writeLn(checkGlobalCacheExpired(cache_ref)); - 刚取出的缓存引用上,`checkGlobalCacheExpired(cache_ref)` 返回 `0` - 同名缓存被重新设置后,旧引用上的 `checkGlobalCacheExpired(cache_ref)` 返回 `1` -### 写入后会实例化 +### 缓存值本地写入后会实例化 代码块身份:可直接照写示例 @@ -399,7 +397,7 @@ begin end; ``` -需要缓存时,从 `setGlobalCache` / `getGlobalCache` 那一节选择模板。 +需要缓存时,默认模板是 `setGlobalCache(key, value)` 写入、`getGlobalCache(key, out_var)` 读取。 ## 禁止项 diff --git a/docs/tsl/syntax/11_pitfalls.md b/skills/tsl-syntax-reference/references/11_pitfalls.md similarity index 85% rename from docs/tsl/syntax/11_pitfalls.md rename to skills/tsl-syntax-reference/references/11_pitfalls.md index 699b3d92..f76aebc8 100644 --- a/docs/tsl/syntax/11_pitfalls.md +++ b/skills/tsl-syntax-reference/references/11_pitfalls.md @@ -1,11 +1,5 @@ # TSL 高频误写 -文档类型:反例索引页 -是否可直接用于生成代码:否 -是否含可直接照写示例:否 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[02_core_model.md](02_core_model.md)、[03_values_and_literals.md](03_values_and_literals.md)、[05_functions_and_calls.md](05_functions_and_calls.md)、[06_expressions_and_operators.md](06_expressions_and_operators.md)、[08_objects_and_classes.md](08_objects_and_classes.md)、[09_units_and_scope.md](09_units_and_scope.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇不讲新知识,只做反例索引。 ## 本篇职责 @@ -15,14 +9,14 @@ ## 智能体常见误写判断流程 1. 先识别用户写法属于值、变量、函数、表达式、对象、`unit`、TS-SQL 还是外部调用误区。 -2. 遇到本页反例时,不要修成相邻语言习惯,必须跳回对应语法页找可直接照写示例。 +2. 遇到本页反例时,不要修成相邻语言习惯,必须以对应语法页的可直接照写示例为准。 3. 反例只用于排错和避免误写,不作为可照写模板。 4. 修复时保留 `.tsl` / `.tsf` 文件模型判断,不要只改局部语句。 5. 没有对应条目时不要发明替代语法。 ## 这页怎么用 -- 先按主题扫一遍,再回到对应正文看正确写法。 +- 先按主题识别反例,再以对应正文的正确写法为准。 - 这里不重复讲完整规则,只保留“错法 -> 正确页”的索引。 - 只有已经有明确反例边界的误写,才会列在这里。 - 细节型边界放回对应专题页;本页只保留最容易诱导智能体写错的高频误写。 @@ -198,5 +192,5 @@ end; - 不要把本页任何 `反例 / 不可照写` 代码块改写成默认正向模板。 - 不要只凭 Pascal、JavaScript、Python 或 SQL 直觉修正 TSL 写法。 -- 不要在本页发明替代语法;每个反例都要回到条目末尾标出的正确专题页。 +- 不要在本页发明替代语法;每个反例都以条目末尾标出的正确专题页为准。 - 不要把反例边界写成可用语法。 diff --git a/docs/tsl/syntax/12_matrix_and_collections.md b/skills/tsl-syntax-reference/references/12_matrix_and_collections.md similarity index 84% rename from docs/tsl/syntax/12_matrix_and_collections.md rename to skills/tsl-syntax-reference/references/12_matrix_and_collections.md index 7e6fd4e9..a00a4de4 100644 --- a/docs/tsl/syntax/12_matrix_and_collections.md +++ b/skills/tsl-syntax-reference/references/12_matrix_and_collections.md @@ -1,11 +1,5 @@ # TSL 数组、键表、矩阵样数据与集合运算 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:否 -遇到不确定时:先按本页候选页继续判断;[13_resultset_and_filters.md](13_resultset_and_filters.md)、[22_matrix_deep_dive.md](22_matrix_deep_dive.md)、[23_fmarray.md](23_fmarray.md)、[14_ts_sql.md](14_ts_sql.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇收拢 `array(...)` 的扩展用法:顺序数组、字符串键表、嵌套数组、本页明确的矩阵样比较,以及 `in` / `sqlin` / `union2` / `intersect` / `minus` / `outersect` 这类去重型集合关系。 ## 本篇职责 @@ -15,10 +9,10 @@ ## 智能体数组/矩阵样数据判断流程 1. 先判断需要顺序数组、字符串键表、嵌套数组、矩阵样比较,还是去重型集合关系。 -2. 普通容器优先从 `array(...)` 起手;下标和键访问回看值语法页。 +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)。 +5. 结果集过滤和 TS-SQL 查询的事实分别见 [13_resultset_and_filters.md](13_resultset_and_filters.md) 和 [14_ts_sql.md](14_ts_sql.md)。 6. 没有对应代码块时不要发明数组/矩阵样数据/集合关系写法。 ## 核心规则 @@ -30,7 +24,7 @@ - `in` / `not in` 处理的是元素存在关系,以及左侧为数组时的子集关系。 - `sqlin` / `not sqlin` 处理的是行存在关系;左侧要当成一整行去匹配右侧结果集。 - `union2`、`intersect`、`minus`、`outersect` 都按“行”运算,而不是按单元格逐个运算。 -- 集合运算结果会折叠重复行;如果需求是保留重复记录,改看 [13_resultset_and_filters.md](13_resultset_and_filters.md)。 +- 集合运算结果会折叠重复行;保留重复记录的过滤规则见 [13_resultset_and_filters.md](13_resultset_and_filters.md)。 - 当数据本身就是一维数组时,按行集合运算和按元素集合运算是一致的。 - 左侧是数组时,先判定需求语义:子集关系用 `in`,整行存在关系用 `sqlin`。 @@ -138,6 +132,9 @@ writeLn(1 not in array(0, 2)); 0 1 1 +1 +0 +1 ``` `sqlin` 按整行判断左侧是否存在于右侧结果集中: @@ -199,7 +196,7 @@ outersect_rows := left_rows outersect right_rows; - 集合运算先把数据当成“行集合”来看,再做包含、并交差。 - 过滤运算先保留“原结果集里的每一条命中记录”;因此重复行会保留下来。 - 需要“集合关系”时留在本页。 -- 需要“从原表里筛出哪些行”时看 [13_resultset_and_filters.md](13_resultset_and_filters.md)。 +- “从原表里筛出哪些行”的过滤规则见 [13_resultset_and_filters.md](13_resultset_and_filters.md)。 ## 默认生成模板 @@ -212,7 +209,7 @@ matched := 1 in array(1, 2, 3); row_matched := array(1, 2) sqlin array((1, 2), (3, 4)); ``` -### 点前缀比较算符产生逻辑数组 +## 点前缀比较算符产生逻辑数组 点前缀比较(`.=`、`.<>`、`.>`、`.>=`、`.<`、`.<=`)对数组/矩阵逐元素比较,返回真假值数组: @@ -275,7 +272,7 @@ writeLn("子集 (1,0):", subset[1][0]); - `a[indexes]` 按下标提取对应行,等价于 `select * from a where [0] > 0.5 end` - `mfind` 的完整用法见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md) -### 非完全矩阵与缺位当 0 处理 +## 非完全矩阵缺位当 0 处理与标量广播 基础算符作用于非完全矩阵(行长度不一致或字符串键不对齐的数组)时,对应位置不存在或为 `nil` 时**默认当 0 处理**: @@ -338,20 +335,20 @@ 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),不再外跳到原目录。 +这些内容的事实分别见 [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)。 ## 禁止项 -- 不要把字符串下标按数组的 `0` 起始规则来写;字符串索引回看 [03_values_and_literals.md](03_values_and_literals.md)。 +- 不要把字符串下标按数组的 `0` 起始规则来写;字符串下标从 `1` 开始,详见 [03_values_and_literals.md](03_values_and_literals.md)。 - 不要把矩阵链式比较 `::...` 和标量链式比较混写成同一种语法。 - 不要把 `in` 和 `sqlin` 当成同一个概念。 - 不要期待 `union2` 保留重复行。 -- 不要用集合运算去做”保留原始重复记录”的过滤任务。 -- 不要把二维结果集默认当成”按元素逐个比较”的集合运算。 -- 左侧数组要表达”这些值是否都属于右侧集合”时,用 `in`。 -- 左侧数组要表达”这一整行是否存在于右侧结果集”时,用 `sqlin`。 -- `minus` 表达集合差集;如果任务要求保留左侧原始重复次数,改走 [13_resultset_and_filters.md](13_resultset_and_filters.md) 的过滤规则。 +- 不要用集合运算去做“保留原始重复记录”的过滤任务。 +- 不要把二维结果集默认当成“按元素逐个比较”的集合运算。 +- 左侧数组要表达“这些值是否都属于右侧集合”时,用 `in`。 +- 左侧数组要表达“这一整行是否存在于右侧结果集”时,用 `sqlin`。 +- `minus` 表达集合差集;保留左侧原始重复次数的过滤规则见 [13_resultset_and_filters.md](13_resultset_and_filters.md)。 - 不要在本页发明结果集过滤、TS-SQL 查询、写回语法或更大矩阵函数族。 -- 不要把普通 `array(...)` 自动升级成 `FMArray`;只有任务明确命中时才进入 [23_fmarray.md](23_fmarray.md)。 +- 不要把普通 `array(...)` 自动升级成 `FMArray`;`FMArray` 专属事实见 [23_fmarray.md](23_fmarray.md)。 - 不要把点前缀比较 `.>` 和矩阵链式比较 `::>` 混用;`.>` 返回逻辑数组,`::>` 是链式比较。 - 不要以为非完全矩阵缺位会报错;默认当 `0` 处理。 diff --git a/docs/tsl/syntax/13_resultset_and_filters.md b/skills/tsl-syntax-reference/references/13_resultset_and_filters.md similarity index 88% rename from docs/tsl/syntax/13_resultset_and_filters.md rename to skills/tsl-syntax-reference/references/13_resultset_and_filters.md index 0dc3bd1f..6f8ee1cf 100644 --- a/docs/tsl/syntax/13_resultset_and_filters.md +++ b/skills/tsl-syntax-reference/references/13_resultset_and_filters.md @@ -1,11 +1,5 @@ # TSL 结果集与过滤 -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[12_matrix_and_collections.md](12_matrix_and_collections.md)、[14_ts_sql.md](14_ts_sql.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇只讲结果集过滤语法:怎样按某一列过滤、怎样按整行过滤、怎样只返回行下标,以及怎样按字段列表过滤。它不负责 TS-SQL 查询语法,也不把去重型集合运算和业务选股逻辑混进来。 ## 本篇职责 @@ -16,9 +10,9 @@ 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 查询,项目字段和业务上下文回项目实际接口。 +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. 没有对应代码块时不要发明结果集/过滤写法。 ## 核心规则 @@ -169,8 +163,8 @@ sub_result := rows[keep_index, array("A", "C")]; - 过滤运算按“原结果集中的每一行是否命中”来决定保留或排除。 - 集合运算按“行集合”来做并、交、差;结果默认会折叠重复行。 -- 需要保留重复记录时,优先看这一篇。 -- 需要去重后的并集、交集、差集时,优先看 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 +- 保留重复记录的过滤规则由本页负责。 +- 去重后的并集、交集、差集事实见 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 ## 默认生成模板 diff --git a/docs/tsl/syntax/14_ts_sql.md b/skills/tsl-syntax-reference/references/14_ts_sql.md similarity index 94% rename from docs/tsl/syntax/14_ts_sql.md rename to skills/tsl-syntax-reference/references/14_ts_sql.md index 30f7698b..02f31661 100644 --- a/docs/tsl/syntax/14_ts_sql.md +++ b/skills/tsl-syntax-reference/references/14_ts_sql.md @@ -1,16 +1,10 @@ # TSL TS-SQL -文档类型:语法主线 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[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);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇是 TS-SQL 的唯一语法入口:内存数组查询、返回形态、字段访问、`where` / `group by` / `order by`、一维数组查询、多表 `join`(含 `left join`)、`insert` / `update` / `delete` 写回、`thisGroup`、`thisRowIndex`、`refMaxOf` / `refMinOf` 都在这里收拢。 ## 本篇职责 -回答”写 TS-SQL 查询和写回时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接(含 LEFT JOIN)、组内子查询、极值引用,以及如何用 `insert`/`update`/`delete` 修改内存数组”。 +回答“写 TS-SQL 查询和写回时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接(含 LEFT JOIN)、组内子查询、极值引用,以及如何用 `insert`/`update`/`delete` 修改内存数组”。 ## 智能体 TS-SQL 判断流程 @@ -20,7 +14,7 @@ 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. 只想按已有结果集保留/排除行时跳到 [13_resultset_and_filters.md](13_resultset_and_filters.md);要做去重型集合关系时跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md);要在 `FMArray` 上做查询或写回边界时跳到 [23_fmarray.md](23_fmarray.md)。 +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 写法。 ## 核心规则 @@ -28,7 +22,7 @@ - TS-SQL 是 TSL 自带的类 SQL 查询语法,不是金融业务函数库。 - 基础查询文档骨架是:以 `select` / `sselect` / `vselect` / `mselect` 开始,以 `end` 收尾。 - `from` 后面可以直接跟内存数组结果集。 -- 在内存二维结果集上,文档字段访问写法是 `["字段名"]`。 +- 在内存二维结果集上,文档字段访问写法是 `["字段名"]`;列没有名字(如直接来自数组)时用位置下标 `[0]`、`[1]` 访问。 - 在一维数组上做 TS-SQL 时,优先使用 `thisRow` 和 `thisRowIndex`。 - `select` 返回二维结果,`sselect` 返回一维结果,`vselect` 返回单值,`mselect` 返回 `Matrix`。 - `where`、`group by`、`order by` 可以直接接在 `from` 后面继续使用;`order by` 支持 `asc`/`desc` 与多列逗号分隔。 @@ -315,7 +309,7 @@ writeLn("(1,1):", result[1]["vb"]); - `on` 子句指定联接条件,用 `[1].["k"] = [2].["k"]` 匹配键 - 其他联接类型:`right join`(保留右表)、`full join`(保留双方)、`cross join`(笛卡尔积) -### JOIN 家族其余形态 +### `right join` / `full join` / `cross join` 与逗号联接 `right join` / `full join` 的不匹配行同样用 `nil` 填充: @@ -440,7 +434,7 @@ writeLn("(1,0):", a[1]["id"]); - `insert into 数组变量` 直接修改原数组 - `insertfields([字段列表])` 指定要插入的字段 -- `values(...)` 提供对应值,可以写多组 `values`、`values` 实现批量插入 +- `values(...)` 提供对应值,可以连续写多组 `values(...)` 实现批量插入 批量插入可以直接跟一个同结构数组,`insertfields` 也支持一次给多字段赋值: @@ -574,11 +568,13 @@ writeLn(mrows(a)); 代码块身份:可直接照写示例 ```tsl -a := array(("cls": "A", "en": 90), ("cls": "A", "en": 80), ("cls": "B", "en": 85)); +a := array(("cls": "A", "en": 90), ("cls": "A", "en": 80), ("cls": "A", "en": 90), ("cls": "B", "en": 85)); distinct_rows := select distinct ["cls"] from a end; distinct_sum := vselect sumof(distinct ["en"]) from a end; +plain_sum := vselect sumof(["en"]) from a end; writeLn(mrows(distinct_rows)); writeLn(distinct_sum); +writeLn(plain_sum); ``` 代码块身份:输出片段 @@ -586,12 +582,13 @@ writeLn(distinct_sum); ```text 2 255 +345 ``` 说明: - `select distinct [字段]` 折叠重复行 -- `sumof(distinct [字段])` 只对不同值求和:`90 + 80 + 85 = 255` +- `sumof(distinct [字段])` 只对不同值求和:`90 + 80 + 85 = 255`;不加 `distinct` 时重复的 `90` 计两次,得 `345` ### `as` 别名、`as nil` 与字段区间 @@ -806,10 +803,7 @@ integer ### `aggof` 自定义聚集扩展 -> 代码块身份:仅服务端可执行示例 -> 本地 `TSL.exe` 会报 `AggOf Init Error`;下例在服务端(pyTSL)验证通过。 - -`aggof('名称', 表达式)` 调用一个自定义回调函数做聚集: +`aggof('名称', 表达式)` 调用一个自定义回调函数做聚集。本地 `TSL.exe` 会报 `AggOf Init Error`;下例在服务端(pyTSL)验证通过: 代码块身份:仅服务端可执行示例 @@ -847,7 +841,7 @@ end; - `TSQLInsert` / `TSQLSetValue` / `TSQLBatchInsert` / `TSQLEdit` / `TSQLPost` / `TSQLFinal` 对象被 TS-SQL 查询的回调机制 - 面向 SQL 表、业务表或时间序列的数据查询与写回(`marketTable` / `infoTable` / `tradeTable` / `sqlTable` / `hugeSqlTable` 等数据源) -这些内容不作为本页可生成事实;业务数据源先查 `tsl-api-reference` skill、[../modules/pytsl_api.md](../modules/pytsl_api.md) 或项目实际接口。 +这些内容不作为本页可生成事实;业务数据源先交给 `tsl-api-reference` skill、pyTSL 模块事实所有者或项目实际接口。 ## 默认生成模板 @@ -856,6 +850,7 @@ TS-SQL 的最短默认骨架如下: 代码块身份:可直接照写示例 ```tsl +source_rows := array((1, 10), (2, 20)); query_result := select * from source_rows end; ``` @@ -895,7 +890,7 @@ query_result := select A from source_rows end; query_result := select [0] from values end; ``` -这种对一维数组直接用 `[0]` 的写法虽然返回长度为 `3` 的结果,但取到的值是 `nil`,不能当成可靠入口。对一维数组应改用 `thisRow` 和 `thisRowIndex`。 +这种对一维数组直接用 `[0]` 的写法虽然能返回与源数组等长的结果,但取到的值是 `nil`,不能当成可靠入口。对一维数组应改用 `thisRow` 和 `thisRowIndex`。 代码块身份:反例 / 不可照写 diff --git a/docs/tsl/syntax/15_debug_and_profiler.md b/skills/tsl-syntax-reference/references/15_debug_and_profiler.md similarity index 88% rename from docs/tsl/syntax/15_debug_and_profiler.md rename to skills/tsl-syntax-reference/references/15_debug_and_profiler.md index d5f1863f..197b4eb6 100644 --- a/docs/tsl/syntax/15_debug_and_profiler.md +++ b/skills/tsl-syntax-reference/references/15_debug_and_profiler.md @@ -1,11 +1,5 @@ # TSL 调试与性能分析器 -文档类型:语法主线 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[07_control_flow.md](07_control_flow.md)、[10_runtime_context_and_with.md](10_runtime_context_and_with.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇收拢本页明确的调试、计时、性能分析器和调用栈相关入口。 ## 本篇职责 @@ -15,13 +9,15 @@ ## 智能体调试/性能分析器判断流程 1. 先判断任务需要跳转、提前返回、运行环境调试、计时还是性能分析器。 -2. 普通控制流优先回到 [07_control_flow.md](07_control_flow.md),本页只处理调试补充工具。 +2. 普通控制流的事实见 [07_control_flow.md](07_control_flow.md),本页只处理调试补充工具。 3. `debugReturn` 会结束整段脚本,不能当成普通函数返回。 4. 计时和性能分析器只照文档最小调用写,不要补未写入文档参数。 5. 没有对应代码块时不要发明调试/性能分析器写法。 ## 核心规则 +本页示例只说明调试与分析结构中的调用位置和源码外形。相关 API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。 + - `goto label_name;` 属于文档明确写法,但目标位置以 `label label_name; statement` 这种内联形式作为默认生成形态。 - 本页正向边界只覆盖“跳到同一函数 / 同一脚本体后面的位置”,不要先把更复杂的跨层跳转边界写成事实。 - `debugReturn value;` 会直接结束整段脚本,后面的语句不会继续执行。 @@ -117,7 +113,7 @@ end; 结果说明: - 只输出 `before` -- 说明 `debugReturn bb;` 不只是结束 `Inner(...)`,而是直接让整段脚本提前返回 +- 说明 `debugReturn value;` 不只是结束 `Inner(...)`,而是直接让整段脚本提前返回 - 因此 `Inner(3)` 后面的 `writeLn("after")` 不会执行 ### `debugRunEnv` 与 `debugRunEnvDo` @@ -216,8 +212,8 @@ writeLn(line_number); 结果说明: -- 输出 `3` -- 说明 `__line__` 直接返回所在代码行号 +- 输出 `1` +- 说明 `__line__` 直接返回它所在的代码行号(这里 `__line__` 在脚本第 1 行) `__stack_frame`: @@ -243,12 +239,12 @@ end; ```text array( -(11,"__main__"), -(8,"Outer")) +(1,"__main__"), +(10,"Outer")) ``` - 说明 `__stack_frame` 返回的是调用栈帧数组 -- 在这个最小例子里,可以直接看到调用位置行号和调用者函数名 +- 在这个最小例子里,可以直接看到调用位置行号和调用者函数名:`__main__` 在第 1 行调用 `Outer()`,`Outer` 在第 10 行调用 `Inner()` ## 禁止项 diff --git a/docs/tsl/syntax/16_lexical_structure_and_compile_options.md b/skills/tsl-syntax-reference/references/16_lexical_structure_and_compile_options.md similarity index 88% rename from docs/tsl/syntax/16_lexical_structure_and_compile_options.md rename to skills/tsl-syntax-reference/references/16_lexical_structure_and_compile_options.md index cfe1f044..dcc1c039 100644 --- a/docs/tsl/syntax/16_lexical_structure_and_compile_options.md +++ b/skills/tsl-syntax-reference/references/16_lexical_structure_and_compile_options.md @@ -1,11 +1,5 @@ # TSL 词法结构与编译选项 -文档类型:语法深水专题 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[17_types_and_conversions.md](17_types_and_conversions.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇吸收语法手册里“词法层”和“编译期开关”相关内容:标识符、注释、条件编译和依赖编译选项。 ## 本篇职责 @@ -17,7 +11,7 @@ 1. 先判断要写注释、标识符、条件编译,还是编译选项。 2. 注释、大小写、条件编译指令只照本页文档明确形态写。 3. `{$explicit+}` 会改变变量声明要求,生成代码前先判断是否需要 `var`。 -4. `{$varByRef+}` / `{$varByRef-}` 会影响未修饰形参传递语义,细节回看函数页。 +4. `{$varByRef+}` / `{$varByRef-}` 会影响未修饰形参传递语义,细节以函数页事实为准。 5. 没有对应代码块时不要发明词法/编译选项写法。 ## 核心规则 @@ -40,17 +34,17 @@ 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)。 | -| 运算关键字 | `and`、`or`、`not`、`in`、`sqlin`、`like`、`is`、`div`、`mod`、`shl`、`shr`、`rol`、`ror` | 运算符规则回 [06_expressions_and_operators.md](06_expressions_and_operators.md)。 | +| 控制流 | `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)。 | +| 运算关键字 | `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);调试相关事实见 [15_debug_and_profiler.md](15_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)。 | +| 类与对象 | `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)。 | | 客户端远程调用与权限 | `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` | 查询语法见 [14_ts_sql.md](14_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` | 这些名称被系统保留,不作为普通标识符使用,也不作为可写语法模板。 | diff --git a/docs/tsl/syntax/17_types_and_conversions.md b/skills/tsl-syntax-reference/references/17_types_and_conversions.md similarity index 89% rename from docs/tsl/syntax/17_types_and_conversions.md rename to skills/tsl-syntax-reference/references/17_types_and_conversions.md index fedd8d96..d584a856 100644 --- a/docs/tsl/syntax/17_types_and_conversions.md +++ b/skills/tsl-syntax-reference/references/17_types_and_conversions.md @@ -1,24 +1,18 @@ # TSL 类型与转换 -文档类型:语法深水专题 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[03_values_and_literals.md](03_values_and_literals.md)、[04_variables_and_constants.md](04_variables_and_constants.md)、[23_fmarray.md](23_fmarray.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇吸收语言基础里“数据类型、初始值、弱类型行为、类型转换、复数类型”这一层。 ## 本篇职责 -回答“当问题不再是怎么声明变量或书写普通字面量,而是运行时值会变成什么类型、默认值是什么、怎样显式转换、复数怎样表示时,应该看哪里”。`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)。 +回答“当问题不再是怎么声明变量或书写普通字面量,而是运行时值会变成什么类型、默认值是什么、怎样显式转换、复数怎样表示时,应该看哪里”。`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` 声明选择跳转到 [04_variables_and_constants.md](04_variables_and_constants.md),遇到 `{$explicit+}` / `{$explicit-}` 等编译选项跳转到 [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)。 +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. 没有对应代码块时不要发明类型/转换写法。 ## 核心规则 @@ -257,6 +251,7 @@ writeLn(z2); 1 4 3 +5-2j ``` 共轭、模与等值比较: @@ -270,7 +265,7 @@ writeLn(abs(z)); writeLn(real(c)); writeLn(imag(c)); if 3.15 = 3.15 + 0j then - writeLn(1); + writeLn(1) else writeLn(0); ``` diff --git a/docs/tsl/syntax/18_external_calls_and_threads.md b/skills/tsl-syntax-reference/references/18_external_calls_and_threads.md similarity index 92% rename from docs/tsl/syntax/18_external_calls_and_threads.md rename to skills/tsl-syntax-reference/references/18_external_calls_and_threads.md index 2886955f..b9187ef4 100644 --- a/docs/tsl/syntax/18_external_calls_and_threads.md +++ b/skills/tsl-syntax-reference/references/18_external_calls_and_threads.md @@ -1,11 +1,5 @@ # TSL 外部调用与线程 -文档类型:语法深水专题 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[05_functions_and_calls.md](05_functions_and_calls.md)、[19_namespace_libpath_and_unit_runtime.md](19_namespace_libpath_and_unit_runtime.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇吸收函数专题里和外部系统交互有关的部分:`external`、动态库调用、原生函数指针包装、C 回调和线程调用。 ## 本篇职责 @@ -60,6 +54,7 @@ function Tick64Alias(): int64; stdcall; external "kernel32.dll" name "GetTickCou Linux / POSIX 环境的同类最小骨架: 代码块身份:可直接照写示例 +代码块说明:仅类 Unix 环境可执行(依赖 `libc.so.6`);Windows 下不可照抄,本块只演示 `.so` 库名写法。 ```tsl writeLn(getpid() > 0); @@ -172,7 +167,7 @@ end; 结果说明: - 输出 `1` -- 说明类常量字符串可以用于 `external kernel_dll` 这种 DLL 名位置 +- 说明类常量字符串(如 `kKernelDll`)可以用于 `external kKernelDll` 这种 DLL 名位置 不作为可写事实边界: @@ -202,8 +197,8 @@ end; 结果说明: -- `fp <> nil` 输出 `1` -- `##f(3, 4)` 输出 `7` +- `func_ptr <> nil` 输出 `1` +- `##wrapped_func(3, 4)` 输出 `7` - 说明 `makeInstance(...)` 生成的函数指针可以再通过 `function(...); external fp;` 包装回 TSL 侧调用 ### 线程模式最小正例 diff --git a/docs/tsl/syntax/19_namespace_libpath_and_unit_runtime.md b/skills/tsl-syntax-reference/references/19_namespace_libpath_and_unit_runtime.md similarity index 95% rename from docs/tsl/syntax/19_namespace_libpath_and_unit_runtime.md rename to skills/tsl-syntax-reference/references/19_namespace_libpath_and_unit_runtime.md index be313015..bc4b97ec 100644 --- a/docs/tsl/syntax/19_namespace_libpath_and_unit_runtime.md +++ b/skills/tsl-syntax-reference/references/19_namespace_libpath_and_unit_runtime.md @@ -1,11 +1,5 @@ # TSL 命名空间、Libpath 与 unit 运行时 -文档类型:语法深水专题 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[09_units_and_scope.md](09_units_and_scope.md)、[20_object_runtime_and_introspection.md](20_object_runtime_and_introspection.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇收拢 `unit` 的运行时行为,以及 `.tsf` / `namespace` / `libpath` 的查找规则。`unit` 的基础写法、`uses` 位置和重名解析,统一放在 [09_units_and_scope.md](09_units_and_scope.md)。 ## 本篇职责 diff --git a/docs/tsl/syntax/20_object_runtime_and_introspection.md b/skills/tsl-syntax-reference/references/20_object_runtime_and_introspection.md similarity index 89% rename from docs/tsl/syntax/20_object_runtime_and_introspection.md rename to skills/tsl-syntax-reference/references/20_object_runtime_and_introspection.md index 72d3d7b5..b420bd79 100644 --- a/docs/tsl/syntax/20_object_runtime_and_introspection.md +++ b/skills/tsl-syntax-reference/references/20_object_runtime_and_introspection.md @@ -1,25 +1,19 @@ # TSL 对象运行时与反射 -文档类型:语法深水专题 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[08_objects_and_classes.md](08_objects_and_classes.md)、[16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)、[21_builtin_runtime_objects.md](21_builtin_runtime_objects.md)、[24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇收拢对象模型里不适合继续堆在基础类主线里的运行时内容:类信息、函数句柄、对象状态、引用计数、运行时对象枚举、弱引用与自动弱引用。普通类声明、继承、构造和普通对象创建仍以 [08_objects_and_classes.md](08_objects_and_classes.md) 为主线;本页只在用户明确需要运行时反射、内省、对象生命周期或弱引用能力时进入。 ## 本篇职责 -回答“类已经会声明、继承、构造之后,怎样检查类信息、函数信息、对象运行时状态、弱引用创建和弱引用访问判定”。如果只是写一个类、创建一个对象、调用对象方法,回到 [08_objects_and_classes.md](08_objects_and_classes.md),不要因为本页存在反射或弱引用能力就改写成动态查找。 +回答“类已经会声明、继承、构造之后,怎样检查类信息、函数信息、对象运行时状态、弱引用创建和弱引用访问判定”。普通类编写、对象创建和对象方法调用的事实见 [08_objects_and_classes.md](08_objects_and_classes.md);不要因为本页存在反射或弱引用能力就改写成动态查找。 ## 智能体对象运行时/反射判断流程 1. 先判断用户是否明确要求运行时类类型、方法句柄、对象状态、对象枚举、反射信息或弱引用/自动弱引用。 -2. 普通对象创建、普通方法调用、类声明和继承都回到 [08_objects_and_classes.md](08_objects_and_classes.md),不要把 `findClass(...)` / `createObject(...)` 当默认写法。 +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. 函数值调用边界回看函数页,避免把函数指针直接当普通函数调用。 +6. 函数值调用边界以函数页事实为准,避免把函数指针直接当普通函数调用。 7. 没有对应代码块时不要发明对象运行时/反射/弱引用写法。 ## 核心规则 @@ -41,7 +35,7 @@ - `functionInfo` 至少可以读出 `functionname`、`returntype`、`classname` 这几个字段。 - `tslObjects(1)` 会按类名分组返回对象信息,并且分组项里的 `"obj"` 字段可以重新拿到可调用对象。 - 对象赋值会延长对象存活;只有最后一个引用清空后才会触发 `destroy()`。 -- `self` 在本页只用于需要本实例对象引用的运行时函数,例如 `objectstate(self)`;普通成员访问仍按 [08_objects_and_classes.md](08_objects_and_classes.md) 的规则,不加 `self` 前缀。 +- `self` 表示本实例对象引用;本页在需要该引用的场景使用它,如传给运行时函数(`objectstate(self)`)或保存自身引用(`sca := self;`)。普通成员访问仍按 [08_objects_and_classes.md](08_objects_and_classes.md) 的规则,不加 `self` 前缀。 - 弱引用能力的条件编译宏是 `weakptr`;自动弱引用相关宏是 `autoWeak`。 - `weakRef(obj)` 可以创建弱引用;对象仍存活时,`weakref_get(w)` 可以拿回强引用。 - `checkWeakRef(w)` 在对象仍存活时返回 `1`,对象已释放后返回 `-1`。 @@ -157,7 +151,7 @@ end; - 输出 `1` - 说明 `obj.classInfo(1)` 可以返回类类型 - 也说明这个类类型可以继续交给 `createObject(...)` -- 这个 `createObject(cls)` 只适用于“类类型来自运行时”的场景;普通本地类创建仍回 [08_objects_and_classes.md](08_objects_and_classes.md) 使用 `new ClassName()` +- 这个 `createObject(cls)` 只适用于“类类型来自运行时”的场景;普通本地类创建以 [08_objects_and_classes.md](08_objects_and_classes.md) 的 `new ClassName()` 规则为准 `classInfo()` 返回的映射字段: @@ -356,15 +350,15 @@ end; 代码块身份:可直接照写示例 ```tsl +objA := new TestClass01(100); +objB := new TestClass01(101); + objsInfo := tslObjects(1); writeLn(length(objsInfo["TestClass01"])); newObjA := objsInfo["TestClass01"][0, "obj"]; writeLn(newObjA is class(TestClass01)); writeLn(newObjA.add(1, 2)); -objA := new TestClass01(100); -objB := new TestClass01(101); - type TestClass01 = class public value; @@ -549,8 +543,8 @@ end; ## 禁止项 -- 不要在运行时/反射页发明类声明、继承或构造语法;类基础回 [08_objects_and_classes.md](08_objects_and_classes.md)。 -- 不要为了普通对象创建先写 `findClass(...)` / `createObject(...)`;普通本地类创建回 [08_objects_and_classes.md](08_objects_and_classes.md),默认用 `new ClassName()`。 +- 不要在运行时/反射页发明类声明、继承或构造语法;类基础事实见 [08_objects_and_classes.md](08_objects_and_classes.md)。 +- 不要为了普通对象创建先写 `findClass(...)` / `createObject(...)`;普通本地类创建以 [08_objects_and_classes.md](08_objects_and_classes.md) 为准,默认用 `new ClassName()`。 - 不要把函数句柄直接当普通函数直调;默认调用方式是 `f.do(...)`。 - 不要把 `functionInfo` 示例外推成所有字段都可读。 - 不要把引用计数样例泛化成所有对象销毁时机;只按本页文档行为描述。 @@ -576,6 +570,8 @@ end; 上面这种给段落切换关键字**加分号**(`weakRef;` / `autoRef;`)的写法会编译失败,错误信息包含 `invalid class definition`。关键在分号:段落切换关键字要像 `public` / `private` 那样**不带分号**独占一行,带分号后被当成独立语句才报错。正确的段落式写法见下一段。 +### 段落式 `weakRef` / `autoRef` 的正确写法 + 段落式 `weakRef` / `autoRef`(不带分号)像 `public` / `private` 一样切换后续成员的弱引用属性: 代码块身份:可直接照写示例 diff --git a/docs/tsl/syntax/21_builtin_runtime_objects.md b/skills/tsl-syntax-reference/references/21_builtin_runtime_objects.md similarity index 92% rename from docs/tsl/syntax/21_builtin_runtime_objects.md rename to skills/tsl-syntax-reference/references/21_builtin_runtime_objects.md index dd042fbf..ff6bf30d 100644 --- a/docs/tsl/syntax/21_builtin_runtime_objects.md +++ b/skills/tsl-syntax-reference/references/21_builtin_runtime_objects.md @@ -1,11 +1,5 @@ # TSL 内置运行时对象 -文档类型:语法深水专题 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[20_object_runtime_and_introspection.md](20_object_runtime_and_introspection.md)、[10_runtime_context_and_with.md](10_runtime_context_and_with.md)、[11_pitfalls.md](11_pitfalls.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇只收运行时内置对象的文档明确最小模型。这里讲的是语言运行时对象,不是金融业务 API。 ## 本篇职责 @@ -17,7 +11,7 @@ 1. 先判断要访问哪个内置运行时对象,以及它是不是语言对象而非业务 API。 2. 只照本页明确的最小读写路径使用内置对象。 3. 不要把金融业务上下文对象和语言运行时对象混在一起。 -4. 需要系统参数或 `with` 后缀时跳转到运行时上下文页。 +4. 系统参数和 `with` 后缀的事实见 [10_runtime_context_and_with.md](10_runtime_context_and_with.md)。 5. 没有对应代码块时不要发明内置运行时对象写法。 ## 核心规则 @@ -77,7 +71,7 @@ writeLn(list["B"]); - 依次输出 `2`、`bbb` - 说明 `THashedStringList` 可按 `Name=Value` 的名称键读取值 -### `TStream` 家族的最小可靠入口:`TMemoryStream` +### `TStream` 家族的最小可靠入口:`TMemoryStream` 与 `TFileStream` 代码块身份:可直接照写示例 diff --git a/docs/tsl/syntax/22_matrix_deep_dive.md b/skills/tsl-syntax-reference/references/22_matrix_deep_dive.md similarity index 88% rename from docs/tsl/syntax/22_matrix_deep_dive.md rename to skills/tsl-syntax-reference/references/22_matrix_deep_dive.md index 0915eaa1..254cfab9 100644 --- a/docs/tsl/syntax/22_matrix_deep_dive.md +++ b/skills/tsl-syntax-reference/references/22_matrix_deep_dive.md @@ -1,21 +1,15 @@ # TSL 矩阵深水专题 -文档类型:语法深水专题 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[12_matrix_and_collections.md](12_matrix_and_collections.md)、[23_fmarray.md](23_fmarray.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵乘除乘方、矩阵转置、矩阵拼接、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`12` 讲普通数组与集合关系,这一篇讲矩阵专用构造、运算、遍历、子矩阵和矩阵查找接口。 ## 本篇职责 -回答”怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样进行矩阵乘除乘方,怎样转置矩阵,怎样拼接矩阵,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。 +回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样进行矩阵乘除乘方,怎样转置矩阵,怎样拼接矩阵,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。 ## 智能体矩阵深水判断流程 1. 先判断要写矩阵初始化、数列构造、矩阵逆/广义逆、矩阵尺寸与索引读取、矩阵遍历、子矩阵,还是 `mfind` 查找/替换。 -2. 基础数组和矩阵样比较先回看 `12_matrix_and_collections.md`。 +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`。 @@ -26,8 +20,10 @@ ## 核心规则 -- 矩阵初始化函数的参数规格使用 `tsl-api-reference` skill 按名查询;本页只保留矩阵行为示例和返回形态边界。 -- `zeros(...)`、`ones(...)`、`rand(...)`、`nils(...)`、`eye(...)` 都可以直接用于矩阵初始化。 +本页示例只说明矩阵语法中的调用位置、运算结构和源码外形。矩阵 API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。 + +- 矩阵初始化和基础函数的具体参数规格使用 `tsl-api-reference` skill 按名查询;本页只保留矩阵行为示例、返回形态边界和跨函数通用的广播 / `ErrDefine` / `ErrReplace` 机制。 +- `zeros(...)`、`ones(...)`、`rand(...)`、`nils(...)`、`eye(...)` 都可以直接用于矩阵初始化;全 `nil` 单元的“空矩阵”用 `nils(...)` 构造。 - `zeros(3)`、`ones(3)`、`nils(2)` 这类单参数写法可以直接生成一维结果。 - `zeros(2, 3)`、`rand(2, 3)` 这类双参数写法可以直接生成二维矩阵。 - `zeros(2, array("A", "B"))` 这种写法可以直接生成带列名的二维结果。 @@ -192,7 +188,7 @@ writeLn(inverse_value[2][1]); - `array((1, 2, 3), (4, 5, 6))` 是 `2 x 3` 矩阵样数组。 - `!matrix_value` 返回的是 `3 x 2` 广义逆结果。 - 生成矩阵逆/广义逆时写 `!matrix_value`;不要把它改写成 `1 / matrix_value`。 -- `!` 不表示逻辑非;逻辑非回 [06_expressions_and_operators.md](06_expressions_and_operators.md) 使用 `not`。 +- `!` 不表示逻辑非;逻辑非以 [06_expressions_and_operators.md](06_expressions_and_operators.md) 的 `not` 规则为准。 ### `msize`、`mrows`、`mcols` @@ -526,7 +522,7 @@ B 0 ``` -### 矩阵乘法、除法、乘方:`:*`、`:/`、`:^` +### 矩阵乘法、除法、左除、乘方:`:*`、`:/`、`:\`、`:^` `:*` 是矩阵乘法(区别于逐元素乘 `*`): @@ -604,7 +600,7 @@ writeLn(result[1][0]); 说明: -- `:\` 左除用于解线性方程组 `A * X = B`,等价于 `X = A^(-1) * B` +- `:\` 左除用于解线性方程组 AX = B(数学记法),等价于先求逆再矩阵乘:`!a :* b` - **右侧 `b` 必须是列向量**(用 `array((4), (8))` 而非 `array(4, 8)`) - `a :\ b` 返回 `array((2.0), (2.0))`,即 `X` 的列向量 - 当 A 行数 > 列数时返回最小二乘解,行数 < 列数时返回一个可行解 @@ -700,10 +696,34 @@ array(2.0,NAN,3.0) 说明: -- `sqrt(data, 1, -999)` 中,第二参数 `ErrDefine=1` 表示允许 NIL 值不允许错误值 -- `ErrReplace=-999` 是错误位置的替换值(本例中 `-1` 的平方根为错误,但 `ErrDefine=1` 保留为 NAN) -- `ErrDefine` 取值:`0`=不允许错误和 NIL、`1`=允许 NIL 不允许错误、`2`=错误值保留为原值 -- `ErrReplace` 在 `ErrDefine=0` 或 `1` 时生效,用于替换错误/NIL 位置 +- `ErrDefine` 取值:`0`=不允许错误和 NIL(两者都替换为 `ErrReplace`)、`1`=允许 NIL 不允许错误(NIL 保留,错误替换为 `ErrReplace`)、`2`=错误和 NIL 都保留原值(`ErrReplace` 不生效) +- 「错误」指输入无效(如 NIL、类型不符);数学定义域产生的 `NAN` 结果(如 `sqrt(-1)`)不属于错误位置,任何 `ErrDefine` 档位下都不会被 `ErrReplace` 替换,本例输出保留 `NAN` 即因如此 +- 不带 `ErrDefine` / `ErrReplace` 时,无效输入会直接运行报错 + +无效输入在不同 `ErrDefine` 档位下的替换差异: + +代码块身份:可直接照写示例 + +```tsl +data := array(4, nil, "AAA", 9); +writeLn(tostn(sqrt(data, 0, -999))); +writeLn(tostn(sqrt(data, 1, -999))); +writeLn(tostn(sqrt(data, 2, -999))); +``` + +代码块身份:输出片段 + +```text +array(2.0,-999,-999,3.0) +array(2.0,NIL,-999,3.0) +array(2.0,NIL,"AAA",3.0) +``` + +说明: + +- `ErrDefine=0` 把 NIL 和错误值 `"AAA"` 都替换成 `-999` +- `ErrDefine=1` 保留 NIL、只替换错误值 +- `ErrDefine=2` 全部保留原值 另一个例子: @@ -872,7 +892,7 @@ writeLn("(1,3):", result[1][3]); (1,3): 8 ``` -`:|` 对非完全矩阵补 `nil`,`|` 不补: +普通 `array` 的非完全矩阵:`:|` 缺位补 `nil`,`|` 直接顺接不补位: 代码块身份:可直接照写示例 @@ -888,16 +908,17 @@ writeLn("bar 结果 (1,2):", bar_result[1][2]); 代码块身份:输出片段 ```text -colon 结果列数: 6 -colon (1,2): nil -bar 结果 (1,2): 1 +colon 结果列数:6 +colon (1,2): +bar 结果 (1,2):2 ``` 说明: - `union` / `&=` 用于行方向拼接 - `|` / `:|` 用于列方向拼接 -- 非完全矩阵(行长度不一致)用 `:|` 会在缺位补 `nil`,而 `|` 不补 +- 普通 `array` 的非完全矩阵(行长度不一致):`:|` 按原列位置对齐、缺位补 `nil`;`|` 把两行元素直接顺接(本例第 1 行变成 `(2,3,2,3)`,所以 `[1][2]` 是 `2`) +- 上述差异只适用于普通 `array`;`FMArray` 上 `|` 与 `:|` 行为一致且行数不齐时补 `0`,见 [23_fmarray.md](23_fmarray.md) - 对应的复合赋值形式:`&=`(行并)、`|=`(列并)、`:|=`(列并补 nil) ## 默认生成模板 @@ -924,7 +945,7 @@ matrix_value := zeros(2, 3); - 用 `::` 期待遍历到任意深度;深度遍历使用 `:.`。 - 子矩阵赋值时用形状不匹配的矩阵硬塞。 - 把 `union` 的复合赋值写成 `union=`;正确写法是 `&=`。 -- 一维数组直接 `union` 期待得到二维结果;需要先双转置 `` ``b `` 变成行向量。 +- 一维数组直接 `union` 期待得到二维结果;需要先对它连用两次转置前缀(双转置)变成行向量。 - 在基础函数异常参数时用分号分隔;正确写法用逗号:`sqrt(data, 1, -999)`。 代码块身份:反例 / 不可照写 diff --git a/docs/tsl/syntax/23_fmarray.md b/skills/tsl-syntax-reference/references/23_fmarray.md similarity index 95% rename from docs/tsl/syntax/23_fmarray.md rename to skills/tsl-syntax-reference/references/23_fmarray.md index fd3cdfa7..5e67bb46 100644 --- a/docs/tsl/syntax/23_fmarray.md +++ b/skills/tsl-syntax-reference/references/23_fmarray.md @@ -1,11 +1,5 @@ # TSL FMArray -文档类型:语法深水专题 -是否可直接用于生成代码:是 -是否含可直接照写示例:是 -是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[22_matrix_deep_dive.md](22_matrix_deep_dive.md)、[12_matrix_and_collections.md](12_matrix_and_collections.md)、[14_ts_sql.md](14_ts_sql.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇只讲 `FMArray` 文档主干能力:怎样构造 `FMArray`、怎样判断类型、怎样和 `Array` 互转、怎样读取尺寸、做基础运算、做多维转置与维度交换、做矩阵连接、参与 `select/mselect`,以及 `insert/delete/update` 语法边界。 ## 本篇职责 @@ -34,7 +28,7 @@ - `union2` 支持 `FMArray` / `Array` 混合运算;结果类型跟随左值。 - 对超过二维的 `FMArray`,反引号转置会把全部维度倒置;`mswap` 可只交换指定维度。 - `union` 可做按行连接且不去重,但列结构必须兼容。 -- `|` 和 `:|` 都可做矩阵并右方(按列连接);行数不一致时会用 `0` 补齐,并且两者表现一致。 +- `|` 和 `:|` 都可做矩阵并右方(按列连接);在 `FMArray` 上行数不一致时会用 `0` 补齐,并且两者表现一致(普通 `array` 上两者行为不同:`:|` 缺位补 `nil`、`|` 直接顺接,见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md))。 - 对 `FMArray` 做普通 `select` 不会保留 `FMArray` 类型;`mselect` 也不会返回 `dataType=27`。 - `insert into a array(...)`、`delete from a where ...;`、`update a set ... where ... end;` 都能作用于 `FMArray`,但三者的收尾形式并不完全相同。 @@ -77,6 +71,11 @@ writeLn(f2[0,0], ',', f2[0,1], ',', f2[1,0], ',', f2[1,1]); 0 1 1 +3 +1,2,3 +2 +2 +1,2,3,4 ``` ### `mInit`、`mInitDiag`、`mRand` diff --git a/docs/tsl/syntax/24_object_overloads_and_iteration.md b/skills/tsl-syntax-reference/references/24_object_overloads_and_iteration.md similarity index 87% rename from docs/tsl/syntax/24_object_overloads_and_iteration.md rename to skills/tsl-syntax-reference/references/24_object_overloads_and_iteration.md index 7aa93f2c..1d3b851e 100644 --- a/docs/tsl/syntax/24_object_overloads_and_iteration.md +++ b/skills/tsl-syntax-reference/references/24_object_overloads_and_iteration.md @@ -1,11 +1,5 @@ # TSL 对象重载与迭代 -文档类型:语法深水专题 -是否可直接用于生成代码:仅部分 -是否含可直接照写示例:是 -是否含不可照写反例:否 -遇到不确定时:先按本页候选页继续判断;[08_objects_and_classes.md](08_objects_and_classes.md)、[20_object_runtime_and_introspection.md](20_object_runtime_and_introspection.md)、[17_types_and_conversions.md](17_types_and_conversions.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) - 这一篇只讲对象直接参与语言级操作的文档能力:基础算符重载、`[]` 重载、`for in` 重载,以及 `mrows` / `mcols` / `msize` 这类矩阵关键字重载。 ## 本篇职责 @@ -16,7 +10,7 @@ 1. 先判断要重载二元算符、下标、`for in`,还是矩阵尺寸函数。 2. 对象重载只照本页明确的 `operator` 签名写,不要从未写入文档资料扩展未知重载。 -3. 普通对象模型先回看 `08_objects_and_classes.md`,不要在重载页发明类基础语法。 +3. 普通对象模型以 `08_objects_and_classes.md` 的事实为准,不要在重载页发明类基础语法。 4. 未列入本页主干的重载族不要写成语法事实。 5. 没有对应代码块时不要发明对象重载/迭代写法。 @@ -91,7 +85,7 @@ end; - 依次输出 `20`、`0`、`1`、`1` - 说明 `obj + value` 可以通过成员 `operator +` 接管 - 说明带 `is_left` 的比较算符可以同时处理 `obj < value` 和 `value < obj` -- 私有成员用尾随下划线的 `real_part_` / `imaginary_part_`,对外用 `PascalCase` property 暴露 +- 本例私有成员是 `real_part_` / `imaginary_part_`,对外通过 property 暴露(命名风格本身不属于本页事实) 代码块身份:输出片段 @@ -138,18 +132,32 @@ end; ### `[]` 重载:`operator[0]` / `operator[1]` -沿用上一段的 `bb` 类与测试主体,只把读取签名从 `function operator[](index);` 改成 `function operator[0](index, s1);`: +读取签名也可以写成 `function operator[0](index, s1);`(与上一段 `operator[]` 等价的另一组写法): -代码块身份:配置片段 / 概念骨架 +代码块身份:可直接照写示例 ```tsl +t := array(1, 2, 3, 4, 5); +b := new IndexableBox(t); +writeLn(b[2]); +b[3] := 999; +writeLn(b.data[3]); + type IndexableBox = class public - // 其余字段、create()、operator[1] 和测试主体同上一段 + data; + function create(v); + begin + data := v; + end; function operator[0](index, s1); begin return data[index]; end; + function operator[1](index, v); + begin + data[index] := v; + end; end; ``` @@ -208,7 +216,7 @@ end; - 说明 `operator for(flag)` 可以重载 `for in` - 也说明同一个对象可以按返回值形态同时支持“单变量遍历”和“索引 + 值遍历” -### `mrows` / `mcols` / `msize` 重载 +### `mrows` / `mcols` / `msize` 重载(带参形态,支持下标列表) 代码块身份:可直接照写示例 @@ -264,7 +272,7 @@ end; - 说明 `mrows(obj)`、`mcols(obj)`、`msize(obj)` 都可由对象重载接管 - 说明对象方法式调用 `obj.mcols(1)` 也可继续取得列下标列表 -### `++` 与 `+=` +### `++` / `+=` / `--` / `-=` 自增自减重载 代码块身份:可直接照写示例 @@ -307,8 +315,8 @@ end; 结果说明: - 依次输出 `11`、`11`、`12`、`17` -- 说明前置 `++` 会直接修改对象状态 -- 说明这个最小样例里,后置 `counter++` 返回的是递增前快照 +- 前置 `++counter` 走 `v` 非 `0` 分支,直接原地修改对象状态 +- 后置 `counter++` 走 `v = 0` 分支:分支构造并返回递增后的新对象,运行时用它更新 `counter` 本身,而后置表达式的取值是递增前的原对象(所以 `c.data` 是 `11`、`counter.data` 是 `12`) - 说明 `operator += (v)` 可以接管 `counter += 5` `--` 与 `-=` 与之对称: @@ -350,7 +358,7 @@ end; - 输出 `7` - 说明 `operator -= (v)` 可以接管 `counter -= 3` -- `operator--(v)` 与 `operator++(v)` 结构对称:`v = 0` 分支返回递减前快照,否则原地递减 +- `operator--(v)` 与 `operator++(v)` 结构对称:`v = 0`(后置)分支构造并返回递减后的新对象供运行时更新变量本身,后置表达式的取值是递减前的原对象;`v` 非 `0`(前置)时原地递减 ### 二进制函数重载:`operator funcName` @@ -436,7 +444,8 @@ end; 结果说明: - 输出 `array(1,314)`:`ret` 为 `1`(转换成功),出参 `msg` 为 `314` -- 说明类内需要调用被重载的同名全局函数时,用 `::` 前缀指定全局版本,否则会递归回自己 +- 重载的分派按实参类型决定:本类对象走重载版本,非对象实参(如 `value` 是字符串)走全局版本 +- 因此当被重载的实参已经不是本类对象(如上面 `DateToStr` 两例把对象拆成基础类型再调用)时,不加 `::` 也不会递归;只有当传给同名函数的实参仍是本类对象时才会递归回自己,这时用 `::` 前缀强制指定全局版本 - 重载函数支持通过参数传出返回值(`msg` 作为出参被赋值) ### `::` / `:.` 遍历重载与 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` @@ -513,7 +522,7 @@ end; - `:.`(深度遍历)重载方式与 `::` 相同,把内部 `data::begin ... end` 换成 `data:.begin ... end` 即可 - 遍历体里用到的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 必须各自重载,否则报 `override function not found` -### 关键字函数重载:`msize` / `mrows` / `mcols` +### `mrows` / `mcols` / `msize` 重载(无参形态,只取数量且免 `::`) `msize` / `mrows` / `mcols` 这类关键字函数也能重载,形态同二进制函数重载 `[class] function operator KeyWord(...)`,但**关键字重载不需要 `::` 指定全局**: @@ -554,4 +563,4 @@ end; - 不要从本页 `operator` 示例外推未写入文档的重载族。 - 重载 `::` / `:.` 遍历时,不要漏掉配套的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 重载,否则遍历体会报 `override function not found`。 - 不要把多级 `[]` 下标重载或 `value + obj` 这类右侧算术写成文档事实。 -- 不要在本页发明普通类语法;基础对象模型回 [08_objects_and_classes.md](08_objects_and_classes.md)。 +- 不要在本页发明普通类语法;基础对象模型事实见 [08_objects_and_classes.md](08_objects_and_classes.md)。 diff --git a/skills/tsl-syntax-reference/scripts/lookup.py b/skills/tsl-syntax-reference/scripts/lookup.py new file mode 100644 index 00000000..76d8fcc0 --- /dev/null +++ b/skills/tsl-syntax-reference/scripts/lookup.py @@ -0,0 +1,1020 @@ +#!/usr/bin/env python3 +import argparse +import difflib +import json +import re +import sys +import unicodedata +from dataclasses import dataclass +from pathlib import Path +from urllib.parse import unquote + + +SKILL_ROOT = Path(__file__).resolve().parents[1] +DEFAULT_REFERENCES_DIR = SKILL_ROOT / "references" +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]+") +INLINE_CODE_RE = re.compile(r"`([^`\n]+)`") +FENCED_CODE_RE = re.compile(r"```[^\n]*\n(.*?)```", re.DOTALL) +IDENTITY_PREFIX = "代码块身份:" +BLOCK_DESCRIPTION_PREFIX = "代码块说明:" +ALLOWED_IDENTITIES = { + "可直接照写示例", + "反例 / 不可照写", + "输出片段", + "配置片段 / 概念骨架", + "仅服务端可执行示例", +} +ROUTER_PHRASES = ("路由中心", "选择一个主专题", "候选页继续判断") +EXCLUDED_REFERENCE_FILES = {"index.md"} +DUTY_HEADING = "本篇职责" +SUSPICIOUS_FENCE_RE = re.compile(r"^(?:\s+`{3}|`{4,})") +WRITE_PRELUDE_ANCHORS = ( + ("02_core_model.md", "文件模型核心规则"), + ("01_quickstart.md", "语言核心事实速查"), +) + +HEADING_TOKEN_SCORE = 12 +HEADING_EXACT_SCORE = 20 +TERM_TOKEN_SCORE = 10 +TERM_EXACT_SCORE = 16 +PAGE_TITLE_TOKEN_SCORE = 5 +PAGE_TITLE_EXACT_SCORE = 8 +BODY_TOKEN_SCORE = 3 +BODY_EXACT_SCORE = 4 +DIRECT_EXAMPLE_BOOST = 8 +PITFALL_PAGE_BOOST = 30 +COUNTEREXAMPLE_BOOST = 8 +EXACT_ERROR_BOOST = 14 +MIXED_QUERY_MIN_SCORE = 10 +PAGE_INTENT_SCORE = 80 + +CHINESE_STOP_TOKENS = { + "一个", + "为什", + "什么", + "怎么", + "怎样", + "是否", + "能不", + "不能", + "帮我", + "想要", + "然后", + "里面", +} + +ASCII_FILTER_STOP_TOKENS = { + "debug", + "please", + "program", + "tinysoft", + "tsl", + "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",), +} + +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"), +} + + +@dataclass(frozen=True) +class Section: + id: str + page: Path + page_title: str + heading_path: tuple[str, ...] + body: str + local_body: str + identities: tuple[str, ...] + searchable_text: str + + +@dataclass(frozen=True) +class ValidationProblem: + page: Path + line: int + message: str + + +@dataclass(frozen=True) +class QueryMatch: + section: Section + score: int + priority: tuple[int, ...] = () + reasons: tuple[str, ...] = () + + +@dataclass(frozen=True) +class ScoreBreakdown: + intent: int + heading_path: int + exact_term: int + page_title: int + body: int + mode_boost: int + synonym_hits: int + diagnose_priority: bool = False + + @property + def lexical_total(self) -> int: + return ( + self.intent + + self.heading_path + + self.exact_term + + self.page_title + + self.body + ) + + @property + def total(self) -> int: + return self.lexical_total + self.mode_boost + + @property + def priority(self) -> tuple[int, ...]: + if self.diagnose_priority: + return ( + self.intent, + self.mode_boost, + self.heading_path, + self.exact_term, + self.page_title, + self.body, + ) + return ( + self.intent, + self.heading_path, + self.exact_term, + self.page_title, + self.mode_boost, + self.body, + ) + + +@dataclass +class QueryResult: + query: str + mode: str + matches: list[QueryMatch] + prelude: list[Section] + limit: int + + +def normalize(value: str) -> str: + return unicodedata.normalize("NFKC", value).casefold() + + +SYMBOL_SLUG_REPLACEMENTS = ( + ("**", " double-star "), + ("[]", " index "), + ("::", " double-colon "), + (":.", " colon-dot "), + ("*", " star "), +) + + +def _slug(value: str) -> str: + normalized = normalize(value) + for symbol, replacement in SYMBOL_SLUG_REPLACEMENTS: + normalized = normalized.replace(symbol, replacement) + slug = re.sub(r"[^\w]+", "-", normalized, flags=re.UNICODE).strip("-_") + return slug or "section" + + +def section_id(relative_page: Path | str, heading_path: tuple[str, ...]) -> str: + page = Path(relative_page) + parts = [_slug(page.with_suffix("").as_posix()), *(_slug(item) for item in heading_path)] + return "--".join(parts) + + +def _reference_pages(references_dir: Path) -> list[Path]: + return [ + page + for page in sorted(references_dir.glob("*.md"), key=lambda item: item.name) + if page.name not in EXCLUDED_REFERENCE_FILES + ] + + +def _heading_records(lines: list[str]) -> tuple[str, list[tuple[int, int, str]]]: + page_title = "" + records: list[tuple[int, int, str]] = [] + in_fence = False + for index, line in enumerate(lines): + if FENCE_RE.match(line.rstrip("\r\n")): + in_fence = not in_fence + continue + if in_fence: + continue + match = HEADING_RE.match(line.rstrip("\r\n")) + if not match: + continue + level = len(match.group(1)) + title = match.group(2) + if level == 1 and not page_title: + page_title = title + elif level in (2, 3, 4): + records.append((index, level, title)) + return page_title, records + + +def _associated_identity(lines: list[str], opening_fence: int) -> str | None: + previous = opening_fence - 1 + while previous >= 0 and not lines[previous].strip(): + previous -= 1 + while previous >= 0 and lines[previous].strip().startswith(BLOCK_DESCRIPTION_PREFIX): + previous -= 1 + while previous >= 0 and not lines[previous].strip(): + previous -= 1 + if previous < 0: + return None + metadata = lines[previous].strip() + if not metadata.startswith(IDENTITY_PREFIX): + return None + identity = metadata[len(IDENTITY_PREFIX) :].strip() + earlier = previous - 1 + while earlier >= 0 and not lines[earlier].strip(): + earlier -= 1 + if earlier >= 0 and lines[earlier].strip().startswith(IDENTITY_PREFIX): + return None + return identity if identity in ALLOWED_IDENTITIES else None + + +def _identities(body: str) -> tuple[str, ...]: + identities: list[str] = [] + lines = body.splitlines() + in_fence = False + for index, line in enumerate(lines): + if not FENCE_RE.match(line): + continue + if not in_fence: + identity = _associated_identity(lines, index) + if identity is not None: + identities.append(identity) + in_fence = not in_fence + return tuple(identities) + + +def load_sections(references_dir: Path = DEFAULT_REFERENCES_DIR) -> list[Section]: + sections: list[Section] = [] + for page in _reference_pages(Path(references_dir)): + text = page.read_text(encoding="utf-8") + lines = text.splitlines(keepends=True) + page_title, headings = _heading_records(lines) + heading_stack: dict[int, str] = {} + for position, (start, level, title) in enumerate(headings): + for stacked_level in tuple(heading_stack): + if stacked_level >= level: + del heading_stack[stacked_level] + heading_stack[level] = title + heading_path = tuple( + heading_stack[item] + for item in range(2, level + 1) + if item in heading_stack + ) + end = len(lines) + for next_start, next_level, _ in headings[position + 1 :]: + if next_level <= level: + end = next_start + break + body = "".join(lines[start:end]) + local_end = ( + headings[position + 1][0] + if position + 1 < len(headings) + else len(lines) + ) + local_body = "".join(lines[start:local_end]) + base_id = section_id(page.relative_to(references_dir), heading_path) + searchable_text = normalize( + "\n".join((page.stem, page_title, *heading_path, local_body)) + ) + sections.append( + Section( + id=base_id, + page=page, + page_title=page_title, + heading_path=heading_path, + body=body, + local_body=local_body, + identities=_identities(local_body), + searchable_text=searchable_text, + ) + ) + return sections + + +def _identity_problems(page: Path, lines: list[str]) -> list[ValidationProblem]: + problems: list[ValidationProblem] = [] + for index, line in enumerate(lines, start=1): + stripped = line.strip() + if stripped.startswith(IDENTITY_PREFIX): + identity = stripped[len(IDENTITY_PREFIX) :].strip() + if identity not in ALLOWED_IDENTITIES: + problems.append(ValidationProblem(page, index, f"未知身份:{identity}")) + in_fence = False + for index, line in enumerate(lines): + if FENCE_RE.match(line): + if in_fence: + in_fence = False + else: + if _associated_identity(lines, index) is None: + problems.append( + ValidationProblem( + page, index + 1, "每个代码围栏必须关联恰好一个代码块身份" + ) + ) + in_fence = True + continue + if not in_fence and SUSPICIOUS_FENCE_RE.match(line): + problems.append( + ValidationProblem( + page, index + 1, "不支持的代码围栏形态(缩进围栏或四个及以上反引号)" + ) + ) + if in_fence: + problems.append(ValidationProblem(page, len(lines), "代码围栏未闭合")) + return problems + + +def _local_link_problems( + page: Path, text: str, references_dir: Path +) -> list[ValidationProblem]: + problems: list[ValidationProblem] = [] + # Blank out fenced/inline code without changing line offsets, so reported + # line numbers line up with the original file. + without_fences = re.sub( + r"```.*?```", + lambda match: re.sub(r"[^\n]", " ", match.group(0)), + text, + flags=re.DOTALL, + ) + searchable_markdown = re.sub( + r"`[^`\n]*`", lambda match: " " * len(match.group(0)), without_fences + ) + for match in MARKDOWN_LINK_RE.finditer(searchable_markdown): + target = match.group(1).strip().split(maxsplit=1)[0].strip("<>") + if target.startswith(("#", "http://", "https://", "mailto:")): + continue + target_path = unquote(target.split("#", 1)[0].replace("\\", "/")) + resolved = (page.parent / target_path).resolve() + try: + resolved.relative_to(references_dir.resolve()) + except ValueError: + exists = False + else: + exists = resolved.is_file() + if not exists: + line = searchable_markdown.count("\n", 0, match.start()) + 1 + problems.append(ValidationProblem(page, line, f"本地链接不存在:{target}")) + return problems + + +def validate_references( + references_dir: Path = DEFAULT_REFERENCES_DIR, +) -> list[ValidationProblem]: + references_dir = Path(references_dir) + problems: list[ValidationProblem] = [] + index_page = references_dir / "index.md" + if index_page.exists(): + problems.append(ValidationProblem(index_page, 1, "references 中不得保留 index.md")) + for page in sorted(references_dir.glob("*.md"), key=lambda item: item.name): + text = page.read_text(encoding="utf-8") + lines = text.splitlines() + problems.extend(_identity_problems(page, lines)) + problems.extend(_local_link_problems(page, text, references_dir)) + page_title, headings = _heading_records(text.splitlines(keepends=True)) + h1_count = 0 + in_fence = False + previous_level = 1 + for index, line in enumerate(lines): + if FENCE_RE.match(line): + in_fence = not in_fence + continue + if in_fence: + continue + match = HEADING_RE.match(line) + if match is None: + continue + level = len(match.group(1)) + if level == 1: + h1_count += 1 + previous_level = 1 + continue + if level not in (2, 3, 4): + continue + if level > previous_level + 1: + problems.append( + ValidationProblem(page, index + 1, "H2/H3/H4 标题层级跳跃") + ) + previous_level = level + if h1_count != 1 or not page_title: + problems.append(ValidationProblem(page, 1, "每页必须有且仅有一个非空 H1")) + duty_sections = [] + for position, (start, level, title) in enumerate(headings): + if level != 2 or title != DUTY_HEADING: + continue + end = len(lines) + for next_start, next_level, _ in headings[position + 1 :]: + if next_level <= level: + end = next_start + break + body = "\n".join(lines[start + 1 : end]).strip() + duty_sections.append(body) + if len(duty_sections) != 1 or not duty_sections[0]: + problems.append( + ValidationProblem( + page, 1, "每页必须有且仅有一个非空「本篇职责」" + ) + ) + for phrase in ROUTER_PHRASES: + for index, line in enumerate(lines, start=1): + if phrase in line: + problems.append( + ValidationProblem(page, index, f"包含人工路由协议:{phrase}") + ) + sections = load_sections(references_dir) + ids: dict[str, Section] = {} + for section in sections: + if section.id in ids: + problems.append(ValidationProblem(section.page, 1, f"重复 section ID:{section.id}")) + ids[section.id] = section + for page_name, heading in WRITE_PRELUDE_ANCHORS: + page_sections = [ + section for section in sections if section.page.name == page_name + ] + # Only enforce the anchor when the page is present, so validating a + # synthetic references dir (tests) does not demand the bundled pages. + if page_sections and not any( + heading in section.heading_path for section in page_sections + ): + problems.append( + ValidationProblem( + references_dir / page_name, + 1, + f"write 模式前置章节缺失:{page_name} 的「{heading}」", + ) + ) + # 概念地图逐页从「本篇职责」段生成;有该段的页必须产出非空摘要, + # 否则某页职责段被清空/写坏时地图会静默缺页。 + mapped_pages = {page_name for page_name, _, _ in build_concept_map(references_dir)} + reference_pages = {page.name for page in _reference_pages(references_dir)} + if mapped_pages != reference_pages: + missing = ", ".join(sorted(reference_pages - mapped_pages)) or "none" + problems.append( + ValidationProblem( + references_dir, + 1, + f"概念地图页数与参考页不一致;缺失:{missing}", + ) + ) + for section in sections: + if section.heading_path != (DUTY_HEADING,): + continue + if section.page.name not in mapped_pages: + problems.append( + ValidationProblem( + section.page, + 1, + f"概念地图摘要为空:{section.page.name} 的「{DUTY_HEADING}」", + ) + ) + return problems + + +def _base_query_tokens(text: str) -> set[str]: + normalized = normalize(text) + tokens = set(ASCII_TOKEN_RE.findall(normalized)) + for run in CHINESE_RUN_RE.findall(normalized): + tokens.add(run) + tokens.update(run[index : index + 2] for index in range(len(run) - 1)) + return { + token + for token in tokens + if token.strip() and token not in CHINESE_STOP_TOKENS + } + + +def _ascii_token_sequence(text: str) -> list[str]: + return [ + token.rstrip(".$:+-") + for token in ASCII_TOKEN_RE.findall(normalize(text)) + if token.rstrip(".$:+-") + ] + + +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) + phrase_tokens = _ascii_token_sequence(phrase) + query_tokens_in_order = _ascii_token_sequence(query) + if not phrase_tokens: + return False + width = len(phrase_tokens) + return any( + query_tokens_in_order[index : index + width] == phrase_tokens + for index in range(len(query_tokens_in_order) - width + 1) + ) + + +def _synonym_tokens(text: str) -> set[str]: + tokens: set[str] = set() + for phrase, synonyms in QUERY_SYNONYMS.items(): + if not _query_contains_phrase(text, phrase): + continue + for synonym in synonyms: + tokens.update(_base_query_tokens(synonym)) + return tokens + + +def query_tokens(text: str) -> set[str]: + return _base_query_tokens(text) | _synonym_tokens(text) + + +def _text_contains_token(text: str, token: str) -> bool: + normalized_text = normalize(text) + if ASCII_TOKEN_RE.fullmatch(token): + text_tokens = _bare_tokens(set(ASCII_TOKEN_RE.findall(normalized_text))) + return token.rstrip(".$:+-") in text_tokens + return token in normalized_text + + +def _text_contains_exact_query(text: str, query: str) -> bool: + normalized_query = normalize(query).strip() + if ASCII_TOKEN_RE.fullmatch(normalized_query): + return _text_contains_token(text, normalized_query) + return bool(normalized_query and normalized_query in normalize(text)) + + +def _intent_score(section: Section, query: str) -> int: + aliases = PAGE_INTENT_ALIASES.get(section.page.name, ()) + return PAGE_INTENT_SCORE * sum( + _query_contains_phrase(query, alias) for alias in aliases + ) + + +def _has_chinese_context(section: Section, query: str) -> bool: + runs = CHINESE_RUN_RE.findall(normalize(query)) + for run in runs: + tokens = ( + [run] + if len(run) < 2 + else [run[index : index + 2] for index in range(len(run) - 1)] + ) + matched = sum(token in section.searchable_text for token in tokens) + if matched >= (len(tokens) + 1) // 2: + return True + return not runs + + +def _code_text(body: str) -> str: + inline = INLINE_CODE_RE.findall(body) + fenced = FENCED_CODE_RE.findall(body) + return normalize("\n".join((*inline, *fenced))) + + +def _score_section(section: Section, query: str, mode: str) -> ScoreBreakdown: + normalized_query = normalize(query).strip() + 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) + 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 token in expanded_only_tokens + ) + heading_score = 0 + term_score = 0 + page_title_score = 0 + body_score = 0 + for token in tokens: + if _text_contains_token(heading_text, token): + heading_score += HEADING_TOKEN_SCORE + if _text_contains_token(term_text, token): + term_score += TERM_TOKEN_SCORE + if _text_contains_token(page_title_text, token): + page_title_score += PAGE_TITLE_TOKEN_SCORE + if _text_contains_token(body_text, token): + body_score += BODY_TOKEN_SCORE + if _text_contains_exact_query(heading_text, query): + heading_score += HEADING_EXACT_SCORE + if _text_contains_exact_query(term_text, query): + term_score += TERM_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): + body_score += BODY_EXACT_SCORE + mode_boost = 0 + 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: + mode_boost += EXACT_ERROR_BOOST + return ScoreBreakdown( + intent=_intent_score(section, query), + heading_path=heading_score, + exact_term=term_score, + page_title=page_title_score, + body=body_score, + mode_boost=mode_boost, + synonym_hits=synonym_hits, + diagnose_priority=mode == "diagnose", + ) + + +def _score_reasons(score: ScoreBreakdown) -> tuple[str, ...]: + components = ( + ("intent", score.intent), + ("heading", score.heading_path), + ("identifier", score.exact_term), + ("page_title", score.page_title), + ("body", score.body), + ("mode", score.mode_boost), + ) + reasons = tuple(f"{name}={value}" for name, value in components if value) + if score.synonym_hits: + reasons += (f"synonym={score.synonym_hits}",) + return reasons + + +def _write_prelude(sections: list[Section]) -> list[Section]: + prelude: list[Section] = [] + for page_name, heading in WRITE_PRELUDE_ANCHORS: + match = next( + ( + section + for section in sections + if section.page.name == page_name and heading in section.heading_path + ), + None, + ) + if match is not None: + prelude.append(match) + return prelude + + +STRING_LITERAL_RE = re.compile(r'"[^"\n]*"|\'[^\'\n]*\'') + + +def _bare_tokens(tokens: set[str]) -> set[str]: + # ASCII_TOKEN_RE 的连续字符类会把尾缀符号吞进 token(如编译开关 + # `{$varByRef-}` 产出 `varbyref-`);按剥掉尾部符号的裸形态比较。 + return {token.rstrip(".$:+-") for token in tokens} - {""} + + +def _ascii_anchor(section: Section, ascii_tokens: set[str]) -> bool: + # 只有足够长的标识符按标识符位置命中(标题、行内代码或剥离字符串 + # 字面量后的围栏代码)才豁免中文门控;短 token 与字符串样例数据 + # (如 "XYZ"、"xyz*")不算点名,避免样例值驱动召回。 + anchor_tokens = { + token for token in _bare_tokens(ascii_tokens) if len(token) >= 4 + } + if not anchor_tokens: + return False + heading_tokens = set( + ASCII_TOKEN_RE.findall(normalize("\n".join(section.heading_path))) + ) + code_text = "\n".join( + ( + *INLINE_CODE_RE.findall(section.local_body), + *FENCED_CODE_RE.findall(section.local_body), + ) + ) + code_tokens = set( + ASCII_TOKEN_RE.findall(normalize(STRING_LITERAL_RE.sub(" ", code_text))) + ) + return bool(anchor_tokens & _bare_tokens(heading_tokens | code_tokens)) + + +def _related_sections(a: Section, b: Section) -> bool: + if a.page != b.page or len(a.heading_path) == len(b.heading_path): + return False + shorter, longer = sorted((a.heading_path, b.heading_path), key=len) + return longer[: len(shorter)] == shorter + + +def query_sections( + query: str, + mode: str, + limit: int = 5, + references_dir: Path = DEFAULT_REFERENCES_DIR, +) -> QueryResult: + if mode not in {"write", "diagnose", "explain"}: + raise ValueError(f"unsupported mode: {mode}") + if not 1 <= limit <= 10: + raise ValueError("limit must be between 1 and 10") + all_sections = load_sections(references_dir) + sections = all_sections + prelude = _write_prelude(all_sections) if mode == "write" else [] + required_ids = {section.id for section in prelude} + raw_ascii_tokens = { + token + for token in _base_query_tokens(query) + if ASCII_TOKEN_RE.fullmatch(token) + and token not in ASCII_FILTER_STOP_TOKENS + } + ascii_tokens = { + token + for token in raw_ascii_tokens + if any(_ascii_anchor(section, {token}) for section in all_sections) + } + if ascii_tokens: + sections = [ + section + for section in sections + if any( + _text_contains_token(section.searchable_text, token) + for token in ascii_tokens + ) + ] + has_chinese = bool(CHINESE_RUN_RE.search(normalize(query))) + minimum_score = MIXED_QUERY_MIN_SCORE if ascii_tokens and has_chinese else 1 + ranked: list[QueryMatch] = [] + for section in sections: + # 中文上下文门控只裁剪正文级 ASCII 噪声;标识符在标题或代码里 + # 精确命中的 section 不因中文措辞不同而被丢弃。 + if ( + ascii_tokens + and has_chinese + and not _ascii_anchor(section, ascii_tokens) + and not _has_chinese_context(section, query) + ): + continue + score = _score_section(section, query, mode) + if score.lexical_total < minimum_score: + continue + ranked.append( + QueryMatch( + section, + score.total, + score.priority, + _score_reasons(score), + ) + ) + ranked.sort( + key=lambda match: ( + -match.score, + *(-value for value in match.priority), + match.section.page.as_posix(), + match.section.id, + ) + ) + # H2 聚合 section 的正文逐字包含其 H3 子节;父子同时入选时只保留 + # 排名更高的一个,避免同一内容重复返回。 + matches: list[QueryMatch] = [] + page_counts: dict[Path, int] = {} + for match in ranked: + if match.section.id in required_ids: + continue + if any( + _related_sections(match.section, kept.section) for kept in matches + ): + continue + if page_counts.get(match.section.page, 0) >= 2: + continue + matches.append(match) + page_counts[match.section.page] = page_counts.get(match.section.page, 0) + 1 + if len(matches) == limit: + break + return QueryResult( + query=query, + mode=mode, + matches=matches, + prelude=prelude, + limit=limit, + ) + + +def _logical_source(section: Section) -> str: + return f"references/{section.page.name}" + + +def _safe_json_string(value: str) -> str: + encoded = json.dumps(value, ensure_ascii=False) + for separator in ("\u0085", "\u2028", "\u2029"): + encoded = encoded.replace(separator, f"\\u{ord(separator):04x}") + return encoded + + +def _plain_text_summary(body: str, limit: int = 180) -> str: + without_fences = FENCED_CODE_RE.sub(" ", body) + without_links = re.sub( + r"!?\[([^\]]*)\]\([^)]+\)", lambda match: match.group(1), without_fences + ) + without_inline_code = INLINE_CODE_RE.sub(lambda match: match.group(1), without_links) + content_lines = [] + for line in without_inline_code.splitlines(): + stripped = line.strip() + if not stripped or stripped.startswith(("#", IDENTITY_PREFIX, BLOCK_DESCRIPTION_PREFIX)): + continue + content_lines.append(stripped.lstrip("-* ")) + summary = re.sub(r"\s+", " ", " ".join(content_lines)).strip() + if len(summary) <= limit: + return summary + return summary[: limit - 1].rstrip() + "…" + + +def render_candidates(result: QueryResult) -> str: + lines = [ + "# TSL Syntax Candidates", + "", + f"Mode: `{result.mode}`", + f"Query: {_safe_json_string(result.query)}", + ] + candidates = [ + (section, 0, True, ("required=1",)) for section in result.prelude + ] + [ + (match.section, match.score, False, match.reasons) for match in result.matches + ] + for index, (section, score, required, reasons) in enumerate( + candidates[: result.limit], start=1 + ): + lines.extend( + [ + "", + f"## Candidate {index}", + "", + f"Score: {score}", + f"Required: {'yes' if required else 'no'}", + f"Section ID: `{section.id}`", + f"Source: `{_logical_source(section)}`", + f"Heading: `{' > '.join(section.heading_path)}`", + f"Why: `{', '.join(reasons) or 'lexical=1'}`", + f"Summary: {_plain_text_summary(section.local_body)}", + ] + ) + return "\n".join(lines).rstrip() + "\n" + + +def render_section(section: Section) -> str: + lines = [ + "# TSL Syntax Section", + "", + f"Section ID: `{section.id}`", + f"Source: `{_logical_source(section)}`", + "", + section.body.rstrip(), + ] + return "\n".join(lines).rstrip() + "\n" + + +def build_concept_map(references_dir: Path = DEFAULT_REFERENCES_DIR) -> list[tuple[str, str, str]]: + entries: list[tuple[str, str, str]] = [] + seen_pages: set[str] = set() + for section in load_sections(references_dir): + page_name = section.page.name + if page_name in seen_pages: + continue + if section.heading_path != (DUTY_HEADING,): + continue + summary = _plain_text_summary(section.local_body, limit=600) + if not summary: + continue + seen_pages.add(page_name) + entries.append((page_name, section.page_title, summary)) + entries.sort(key=lambda item: item[0]) + return entries + + +def render_concept_map(entries: list[tuple[str, str, str]]) -> str: + lines = [ + "# TSL 概念地图", + "", + "把自然语言需求映射到该查哪个 TSL 概念,随后仍用 --query 获取候选、用 --section 取回事实正文。", + "本清单不含可照写语法,也不替代精确章节取回。", + ] + for page_name, page_title, summary in entries: + lines.extend(["", f"## {page_title}", "", summary]) + return "\n".join(lines).rstrip() + "\n" + + +def _configure_utf8() -> None: + for stream in (sys.stdout, sys.stderr): + reconfigure = getattr(stream, "reconfigure", None) + if reconfigure is not None: + reconfigure(encoding="utf-8") + + +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) + return parser + + +def _nearest_section_ids( + requested: str, sections: list[Section], limit: int = 5 +) -> list[str]: + ranked = sorted( + sections, + key=lambda section: ( + -difflib.SequenceMatcher(None, requested, section.id).ratio(), + section.id, + ), + ) + return [section.id for section in ranked[:limit]] + + +def main(argv: list[str] | None = None) -> int: + _configure_utf8() + parser = _parser() + args = parser.parse_args(argv) + if not 1 <= args.limit <= 10: + parser.error("--limit must be between 1 and 10") + if args.query is not None and args.mode is None: + parser.error("--mode is required with --query") + if args.mode is not None and args.query is None: + parser.error("--mode only applies to --query") + if args.show_map: + print(render_concept_map(build_concept_map(args.references_dir)), end="") + return 0 + if args.check: + problems = validate_references(args.references_dir) + for problem in problems: + print(f"{problem.page}:{problem.line}: {problem.message}", file=sys.stderr) + 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, + ) + 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 + print(render_candidates(result), end="") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())