@@ -1,30 +1,81 @@
|
||||
# TSL 快速落代码规则
|
||||
|
||||
本篇提供一份单点的语言核心事实速查,以及没有任何复用或模块需求时的默认起手骨架。
|
||||
本篇提供一份由专题页逐条派生的语言核心事实速查,以及没有任何复用或模块需求时的默认起手骨架。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
在落代码前一次性给出跨专题的语言硬规则(赋值、文件形态、声明位置、命名参数、下标起点、类与 `unit` 外形),并提供术语对照和默认可执行脚本骨架。
|
||||
<!-- section-id: syntax-01-001 -->
|
||||
|
||||
在落代码前一次性汇总跨专题的语言硬规则(赋值、文件形态、声明位置、命名参数、下标起点、类与 `unit` 外形),并提供术语对照和默认脚本骨架。本页是强制读取的派生摘要,不独立拥有完整事实;每条规则的完整上下文仍由对应专题页拥有。
|
||||
|
||||
## 语言核心事实速查
|
||||
|
||||
<!-- section-id: syntax-01-002 -->
|
||||
|
||||
<!-- tags: 语法速查, 硬规则, 核心规则一览, 先看哪些, 常见规则汇总 -->
|
||||
|
||||
这一节是本语法手册默认的语言硬规则收口点。涉及赋值、`.tsl` 语句区 / 声明区、`.tsf` 模块、命名参数、类写法、`unit` 骨架和下标规则时,统一先看这里。
|
||||
这一节是专题事实的强制派生速查,不是第二份事实源。写代码时先核对这里,再按当前任务的语法要素取回对应专题 Section;`--check` 会逐条比较下面的摘要与专题页 canonical 规则。
|
||||
|
||||
- 赋值:普通赋值用 `:=`,不要把 `=` 当成普通赋值。
|
||||
- 后缀:用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;未给后缀时,入口流程、脚本任务或一次性执行逻辑对应 `.tsl`,可复用交付物(函数、过程、类、模块或扩展文件)对应 `.tsf`,只是脚本内部封装函数或类时仍按 `.tsl` 处理;仍不明确时向用户确认。
|
||||
- `.tsl`:可执行脚本,语句区在前并按顺序执行;函数 / 类声明区在后,供前面的语句调用或运行时解析。不要在声明区后面继续追加脚本语句。
|
||||
- `.tsf`:可复用模块 / 函数扩展文件;非 `unit` 顶层函数 / 过程部署到解释器 `funcext` 后,脚本可以直接调用;顶层类声明只按可复用声明理解;`unit` 按模块组织理解。
|
||||
- `.tsf` 文件名:文件名(不含扩展名)必须与第一个顶层声明同名,`UserAccount.tsf` 的顶层声明必须是 `function UserAccount`、`type UserAccount = class` 或 `unit UserAccount`。
|
||||
- `function` / `procedure`:用户只说“写一个函数”时默认用 `function`;只有用户明确要求 `procedure` / 过程时才用 `procedure Name(...); begin ... end;`。
|
||||
- 类:顶层类定义统一写成 `type Name = class ... end;`,不要写裸 `class Name`;创建对象有两种方式,`new ClassName()` 最常用,`createObject(...)` 作为次选;需要字符串类名、类类型变量或跨 `unit` 路径时,更适合用 `createObject(...)`。
|
||||
- `unit`:涉及多文件组织时,先按 `unit Name; interface ... implementation ... end.` 骨架理解;不要把 `unit` 当默认最小起手。
|
||||
- 命名参数:写法是 `Func(a:1, b:2)`,不要写成 `Func(a = 1, b = 2)`。
|
||||
- 下标:`array(...)` 既可以写顺序数组,也可以写字符串键表;顺序数组和 `binary(...)` 二进制缓冲区下标从 `0` 开始,字符串下标从 `1` 开始。
|
||||
<!-- quickstart-rule: assignment -->
|
||||
|
||||
- 普通变量赋值使用 `:=`;`=` 在普通表达式里用于比较,不用于赋值。
|
||||
|
||||
<!-- quickstart-rule: file-choice -->
|
||||
|
||||
- 未给后缀时,入口流程、脚本任务或一次性执行逻辑对应 `.tsl`;可复用交付物(函数、过程、类、模块或扩展文件)对应 `.tsf`;只是脚本内部封装函数或类时,仍按 `.tsl` 处理;仍不明确时向用户确认,不要把脚本入口和可复用模块合并成一个猜测文件。
|
||||
|
||||
<!-- quickstart-rule: tsl-layout -->
|
||||
|
||||
- `.tsl` 脚本按两段理解:语句区在前并按顺序执行;声明区在后,可放 `function / procedure` 或 `type Name = class`。写 `.tsl` 时先写语句区,需要函数、过程或类时把声明区放在语句区之后。
|
||||
|
||||
<!-- quickstart-rule: tsf-layout -->
|
||||
|
||||
- 写 `.tsf` 时只写顶层函数 / 过程 / 类声明,或 `unit`;不要写成会直接顺序执行的脚本入口。
|
||||
|
||||
<!-- quickstart-rule: tsf-filename -->
|
||||
|
||||
- `.tsf` 文件名(不含扩展名)必须与第一个顶层声明同名;第一个声明可以是同名 `function`、`type Name = class` 或 `unit`。
|
||||
|
||||
<!-- quickstart-rule: function-default -->
|
||||
|
||||
- 用户提示词里的“函数”默认对应 `function`,不要自动改写成 `procedure`。
|
||||
|
||||
<!-- quickstart-rule: procedure-explicit -->
|
||||
|
||||
- `procedure Name(...); begin ... end;` 只在用户明确要求 `procedure` / 过程时生成;不要因为没有返回值就自动改用 `procedure`。
|
||||
|
||||
<!-- quickstart-rule: class-shape -->
|
||||
|
||||
- 类定义统一按 `type Name = class ... end;` 写。
|
||||
|
||||
<!-- quickstart-rule: object-creation -->
|
||||
|
||||
- 普通本地类实例化默认生成 `new ClassName()`;`createObject("ClassName")`、`createObject(ClassType)` 只在字符串类名、类类型变量或跨 `unit` 路径场景生成。
|
||||
|
||||
<!-- quickstart-rule: unit-shape -->
|
||||
|
||||
- `unit` 是完整的顶层主体;常见完整形态是 `unit Name; interface ... implementation ... end.`。
|
||||
|
||||
<!-- quickstart-rule: unit-default -->
|
||||
|
||||
- 如果没有特殊需求,默认优先用完整形态;简写形态只在不需要显式区分 `interface` / `implementation` 时再用。
|
||||
|
||||
<!-- quickstart-rule: named-arguments -->
|
||||
|
||||
- 调用时支持命名参数,写法是 `name: value`。
|
||||
|
||||
<!-- quickstart-rule: named-argument-order -->
|
||||
|
||||
- 一旦某次调用里开始使用命名参数,后面的参数就不能再退回位置参数。
|
||||
|
||||
<!-- quickstart-rule: index-origins -->
|
||||
|
||||
- `array(...)` 既可以写顺序数组,也可以写字符串键表;顺序数组和 `binary(...)` 二进制缓冲区下标从 `0` 开始,字符串下标从 `1` 开始。
|
||||
|
||||
## 术语对照
|
||||
|
||||
<!-- section-id: syntax-01-003 -->
|
||||
|
||||
- “脚本语句区”:`.tsl` 文件开头会按顺序执行的语句。
|
||||
- “声明区”:`.tsl` 语句区之后的 `function / procedure` 或 `type Name = class` 声明。
|
||||
- “顶层 `function / procedure`”:在 `.tsf` 中指模块暴露的顶层函数 / 过程,在 `.tsl` 中指脚本声明区里的函数 / 过程。
|
||||
@@ -33,6 +84,8 @@
|
||||
|
||||
## 默认起手骨架
|
||||
|
||||
<!-- section-id: syntax-01-004 -->
|
||||
|
||||
<!-- tags: 起手模板, 从哪开始写, 最小可跑, 第一个脚本, hello world -->
|
||||
|
||||
如果用户只要求写一段代码、脚本或示例,且没有明确 `.tsf`、`unit`、模块复用或对象建模需求,直接从 `.tsl` 脚本版本开始:
|
||||
|
||||
@@ -4,17 +4,24 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-02-001 -->
|
||||
|
||||
回答“目标文件到底是 `.tsl` 脚本还是 `.tsf` 可复用声明文件,以及 `.tsl` 里的哪些内容会顺序执行、哪些内容只是后置声明”。
|
||||
|
||||
本页是文件模型的唯一事实源:后缀判断、语句区 / 声明区顺序、`.tsf` 顶层声明形态和文件名约束都在这里收口。函数体、类体、`unit` 内部的语法外形由各自专题页拥有。
|
||||
|
||||
## 文件模型核心规则
|
||||
|
||||
<!-- section-id: syntax-02-002 -->
|
||||
|
||||
<!-- tags: 该用哪种文件, tsl 还是 tsf, 后缀怎么选, 文件形态判断 -->
|
||||
|
||||
- 用户已给出 `.tsl` / `.tsf` 后缀时,后缀就是判断依据;未给后缀时,再按交付目标判断。
|
||||
<!-- quickstart-rule: file-choice -->
|
||||
- 未给后缀时,入口流程、脚本任务或一次性执行逻辑对应 `.tsl`;可复用交付物(函数、过程、类、模块或扩展文件)对应 `.tsf`;只是脚本内部封装函数或类时,仍按 `.tsl` 处理;仍不明确时向用户确认,不要把脚本入口和可复用模块合并成一个猜测文件。
|
||||
<!-- quickstart-rule: tsl-layout -->
|
||||
- `.tsl` 脚本按两段理解:语句区在前并按顺序执行;声明区在后,可放 `function / procedure` 或 `type Name = class`。写 `.tsl` 时先写语句区,需要函数、过程或类时把声明区放在语句区之后。
|
||||
<!-- quickstart-rule: tsf-layout -->
|
||||
- 写 `.tsf` 时只写顶层函数 / 过程 / 类声明,或 `unit`;不要写成会直接顺序执行的脚本入口。
|
||||
- `.tsf` 里的非 `unit` 顶层函数 / 过程可按函数扩展理解:部署到解释器 `funcext` 后,`.tsl` 可以直接调用;顶层类声明只按可复用声明理解;`unit` 按模块组织理解。
|
||||
- `uses` 可以出现在顶层,但这里只把它当成辅助语句,不把它当成主体声明;函数体和类定义体里的位置限制见 [09_units_and_scope.md](09_units_and_scope.md)。
|
||||
@@ -23,12 +30,14 @@
|
||||
- `unit` 默认先按完整形态理解;它也可以省略 `interface` / `implementation` 写成简写形态,见 [09_units_and_scope.md](09_units_and_scope.md)。
|
||||
- 不要把 `.tsl` 写成只有顶层函数的模块;如果用户要通用可复用函数,优先写 `.tsf`。
|
||||
- 不要把 `.tsf` 写成会直接执行脚本语句的入口;如果用户要顺序执行入口,优先写 `.tsl`。
|
||||
- `.tsf` 文件名(不含扩展名)必须与第一个顶层声明同名:
|
||||
- `UserAccount.tsf` 中的顶层声明必须是 `function UserAccount` 或 `type UserAccount = class` 或 `unit UserAccount`。
|
||||
- TSL 语言大小写无关,因此 `userAccount.tsf` 和 `UserAccount.tsf` 在语法层面都合法。
|
||||
<!-- quickstart-rule: tsf-filename -->
|
||||
- `.tsf` 文件名(不含扩展名)必须与第一个顶层声明同名;第一个声明可以是同名 `function`、`type Name = class` 或 `unit`。
|
||||
- TSL 语言大小写无关,因此 `userAccount.tsf` 和 `UserAccount.tsf` 在语法层面都合法。
|
||||
|
||||
## 文件模型示例
|
||||
|
||||
<!-- section-id: syntax-02-003 -->
|
||||
|
||||
使用这些示例时遵守:
|
||||
|
||||
- 可以模仿已经出现的文件模型、语句顺序和块级结构。
|
||||
@@ -38,6 +47,8 @@
|
||||
|
||||
### `.tsl` 文件模型
|
||||
|
||||
<!-- section-id: syntax-02-004 -->
|
||||
|
||||
<!-- tags: 可执行脚本, 顺序执行, 入口脚本, 语句区, 声明区, 脚本从哪开始跑 -->
|
||||
|
||||
`.tsl` 脚本语句区的最小形态:
|
||||
@@ -96,6 +107,8 @@ end;
|
||||
|
||||
### `.tsf` 文件模型
|
||||
|
||||
<!-- section-id: syntax-02-005 -->
|
||||
|
||||
<!-- tags: 可复用文件, 模块文件, 函数扩展, 别的脚本能调, funcext -->
|
||||
|
||||
`.tsf` 顶层函数的最小形态:
|
||||
@@ -165,6 +178,8 @@ end.
|
||||
|
||||
### 文件模型反例
|
||||
|
||||
<!-- section-id: syntax-02-006 -->
|
||||
|
||||
<!-- tags: 为什么编译失败, 顶层裸类, 文件写错了, invalid statement -->
|
||||
|
||||
顶层裸 `class` 声明:
|
||||
@@ -211,18 +226,20 @@ function:__main__:line 9: invalid statement
|
||||
|
||||
## 任务到文件模型的选择规则
|
||||
|
||||
<!-- section-id: syntax-02-007 -->
|
||||
|
||||
<!-- tags: 任务对应哪种文件, 起手形态怎么选, 该建什么文件 -->
|
||||
|
||||
已经确定任务目标时,按下表选择起手形态:
|
||||
|
||||
| 任务 | 起手形态 | 写法 |
|
||||
| --- | --- | --- |
|
||||
| 入口流程、脚本任务或一次性执行逻辑 | `.tsl` 脚本语句区 | 直接写会顺序执行的语句 |
|
||||
| 脚本逻辑需要调用本文件内函数 | `.tsl` 语句区 + 后置函数声明区 | 语句区之后写 `function ... begin ... end;` 或 `procedure ... begin ... end;` |
|
||||
| 脚本逻辑需要对象状态、字段、方法 | `.tsl` 语句区 + 后置类声明区 | 语句区之后写 `type Name = class ... end;` |
|
||||
| 沉淀可复用函数或过程 | `.tsf` 顶层函数 / 过程 | 写可部署到 `funcext` 的 `function` / `procedure` 文件 |
|
||||
| 沉淀可复用类 | `.tsf` 顶层类声明 | 写 `type Name = class ... end;`,只按可复用声明理解;类细节见 [08_objects_and_classes.md](08_objects_and_classes.md) |
|
||||
| 把接口和实现组织进一个模块 | `.tsf` `unit` | 默认先写 `unit ... interface ... implementation ... end.`;简写形态见 [09_units_and_scope.md](09_units_and_scope.md) |
|
||||
| 任务 | 起手形态 | 写法 |
|
||||
| ---------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| 入口流程、脚本任务或一次性执行逻辑 | `.tsl` 脚本语句区 | 直接写会顺序执行的语句 |
|
||||
| 脚本逻辑需要调用本文件内函数 | `.tsl` 语句区 + 后置函数声明区 | 语句区之后写 `function ... begin ... end;` 或 `procedure ... begin ... end;` |
|
||||
| 脚本逻辑需要对象状态、字段、方法 | `.tsl` 语句区 + 后置类声明区 | 语句区之后写 `type Name = class ... end;` |
|
||||
| 沉淀可复用函数或过程 | `.tsf` 顶层函数 / 过程 | 写可部署到 `funcext` 的 `function` / `procedure` 文件 |
|
||||
| 沉淀可复用类 | `.tsf` 顶层类声明 | 写 `type Name = class ... end;`,只按可复用声明理解;类细节见 [08_objects_and_classes.md](08_objects_and_classes.md) |
|
||||
| 把接口和实现组织进一个模块 | `.tsf` `unit` | 默认先写 `unit ... interface ... implementation ... end.`;简写形态见 [09_units_and_scope.md](09_units_and_scope.md) |
|
||||
|
||||
补充判断:
|
||||
|
||||
@@ -231,6 +248,8 @@ function:__main__:line 9: invalid statement
|
||||
|
||||
## 文件模型禁止项
|
||||
|
||||
<!-- section-id: syntax-02-008 -->
|
||||
|
||||
<!-- tags: 不要这样写, 文件模型误用, 两种文件混着写 -->
|
||||
|
||||
- 把 `.tsl` 当成 `.tsf` 来写,只给一个顶层函数,不写任何会执行的脚本语句。
|
||||
|
||||
@@ -4,20 +4,24 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-03-001 -->
|
||||
|
||||
回答“基本类型怎么写、数组和字符串怎么索引、字符串编码边界怎么写、哪些值规则属于语言级事实”。本页拥有整数、实数、字符串、布尔、`array(...)` 字面量和下标 / 区间规则;矩阵与集合扩展不在本页展开。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-03-002 -->
|
||||
|
||||
<!-- tags: 数组下标, 数组索引, 下标从几开始, 下标起点, 字符串下标, 二进制下标 -->
|
||||
|
||||
- 最先掌握的几类值是:整数、实数、普通字符串、布尔和 `array(...)`。
|
||||
- 普通字符串既可以用双引号,也可以用单引号。
|
||||
- 同类引号本身可以通过连续写两个同类引号放进字符串里。
|
||||
- `\\`、`\"`、`\n` 这类基础转义可用。
|
||||
- `\t` 和 `\xNN` 这类转义也可用。
|
||||
- `\r`、`\r\n`、`\a`、`\b`、`\f`、`\v` 这些经典转义也可用。
|
||||
- `array(...)` 既可以写顺序数组,也可以写字符串键表。
|
||||
- 顺序数组下标从 `0` 开始。
|
||||
- `binary(...)` 创建的二进制缓冲区也用 `[]` 访问,并且下标从 `0` 开始。
|
||||
- 字符串下标从 `1` 开始。
|
||||
<!-- quickstart-rule: index-origins -->
|
||||
- `array(...)` 既可以写顺序数组,也可以写字符串键表;顺序数组和 `binary(...)` 二进制缓冲区下标从 `0` 开始,字符串下标从 `1` 开始。
|
||||
- `s[0]` 在运行时会越界,不要把字符串当成 0 基下标。
|
||||
- 字符串取子串用 `s[start:end]`,并且 `end` 是包含在结果里的。
|
||||
- 字符串替换子串用 `s[start:end] := "..."`。
|
||||
@@ -33,6 +37,8 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-03-003 -->
|
||||
|
||||
使用这些示例时遵守:
|
||||
|
||||
- 只复制任务需要的值、字面量、下标或字符串片段,不要把多个示例拼成未写入文档的新语法。
|
||||
@@ -164,7 +170,9 @@ C
|
||||
|
||||
### 字符串边界规则
|
||||
|
||||
<!-- tags: 原始字符串, 多行字符串, 引号怎么转义, 字符串里带引号, 长文本 -->
|
||||
<!-- section-id: syntax-03-004 -->
|
||||
|
||||
<!-- tags: 原始字符串, 多行字符串, 引号怎么转义, 字符串里带引号, 长文本, 宽字符串, 宽串前缀, utf8 转换, 编码转换, 字符码拼接, 二进制缓冲区, 字节读写 -->
|
||||
|
||||
原始字符串 `%%` 的空白分隔、标识符和多行:
|
||||
|
||||
@@ -303,6 +311,14 @@ writeLn(b[1] = "1");
|
||||
- 说明二进制缓冲区的 `[]` 下标从 `0` 开始
|
||||
- 也说明二进制缓冲区项可以直接按单字节读写
|
||||
|
||||
### 字符串子串读写
|
||||
|
||||
<!-- section-id: syntax-03-005 -->
|
||||
|
||||
<!-- tags: 取子串, 截取子串, 字符串区间, 替换子串, 删除子串, 插入子串, 插入字符串, 取字符串的一段 -->
|
||||
|
||||
字符串子串统一用 `s[start:end]` 区间访问,`end` 包含在结果里;同一形态既能读取,也能替换、删除和插入。
|
||||
|
||||
字符串子串读取:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -365,6 +381,8 @@ writeLn(s);
|
||||
|
||||
### 字符串 `$` 连接与拼装
|
||||
|
||||
<!-- section-id: syntax-03-006 -->
|
||||
|
||||
<!-- tags: 拼字符串, 字符串相加, 连接字符串, 数字转字符串拼接 -->
|
||||
|
||||
`$` 用于字符串连接和类型转字符串拼装:
|
||||
@@ -398,7 +416,9 @@ A=1 B=2.34 C=AAA
|
||||
|
||||
### 字符串 `like` 模式匹配
|
||||
|
||||
<!-- tags: 通配符匹配, 正则匹配, 模糊匹配, 判断是否符合模式 -->
|
||||
<!-- section-id: syntax-03-007 -->
|
||||
|
||||
<!-- tags: 通配符匹配, 正则匹配, 正则表达式, 模糊匹配, 判断是否符合模式 -->
|
||||
|
||||
`like` 用于判断字符串是否符合指定模式(支持通配符和正则表达式):
|
||||
|
||||
@@ -444,6 +464,8 @@ writeLn(result);
|
||||
|
||||
### `format` 格式化占位符
|
||||
|
||||
<!-- section-id: syntax-03-008 -->
|
||||
|
||||
<!-- tags: 格式化输出, 占位符, 补零, 保留小数, 拼装带格式的串 -->
|
||||
|
||||
`format` 用于按占位符格式化输出:
|
||||
@@ -468,6 +490,8 @@ writeLn(result);
|
||||
|
||||
### `formatdatetime` 日期格式化
|
||||
|
||||
<!-- section-id: syntax-03-009 -->
|
||||
|
||||
<!-- tags: 日期转字符串, 时间格式化, 年月日怎么输出, 日期显示格式 -->
|
||||
|
||||
`formatdatetime` 用于将日期按指定格式输出:
|
||||
@@ -493,6 +517,8 @@ writeLn(result);
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-03-010 -->
|
||||
|
||||
如果你只是要抓住“基本类型 + array”的第一层,用这个最短例子:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -507,9 +533,12 @@ items := array(1, 2, 3);
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-03-011 -->
|
||||
|
||||
- 用 `s[0]` 访问字符串首字符。
|
||||
- 误以为 `array(...)` 只能写顺序数组,不能写字符串键表。
|
||||
- 误以为字符串区间和数组一样从 `0` 开始。
|
||||
- 把字符串区间当成数组切片式的半开区间;`s[1:3]` 返回 `ABC` 而不是 `AB`,结束位会被包含进结果,正向示例见本页“字符串子串读写”。
|
||||
- 把 `s[index:0] := ...` 误解成“替换到第 0 位”。
|
||||
- 把二进制缓冲区也按字符串的 `1` 基下标去理解。
|
||||
- 在普通字符串示例里默认切到原始字符串、宽串 / UTF8 前缀、字符码或编码转换,却没有按本页字符串边界规则确认。
|
||||
@@ -531,18 +560,3 @@ writeLn(s[0]);
|
||||
```text
|
||||
String index out of bounds
|
||||
```
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
s := "ABCDE";
|
||||
writeLn(s[1:3]);
|
||||
```
|
||||
|
||||
不要把上面这个区间访问类比成数组切片的半开区间。按文档输出,它返回 `ABC`,不是 `AB`;字符串区间的结束位会被包含进结果。
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
ABC
|
||||
```
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-04-001 -->
|
||||
|
||||
回答“普通变量怎样直接使用、`var` 在什么位置出现、常量必须怎样初始化、哪些名字一旦绑定就不能再赋值”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-04-002 -->
|
||||
|
||||
- 默认变量模型是“直接赋值即得到变量”,不要求先写 `var`。
|
||||
- 例如:`a := 1; b := array(1, 2, 3);` 这种写法可直接编译。
|
||||
- `var name;` 只作为显式声明写法,不能当成默认必需步骤。
|
||||
@@ -26,6 +30,8 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-04-003 -->
|
||||
|
||||
使用这些示例时遵守:
|
||||
|
||||
- 默认生成普通变量时直接用 `:=`;只有用户明确要求或 `{$explicit+}` 场景才复制 `var`。
|
||||
@@ -34,6 +40,8 @@
|
||||
|
||||
### 普通变量与显式声明
|
||||
|
||||
<!-- section-id: syntax-04-004 -->
|
||||
|
||||
<!-- tags: 怎么声明变量, 变量要不要先定义, 直接赋值, var 用不用写 -->
|
||||
|
||||
默认变量模型:
|
||||
@@ -82,6 +90,8 @@ writeLn(a);
|
||||
|
||||
### 常量初始化
|
||||
|
||||
<!-- section-id: syntax-04-005 -->
|
||||
|
||||
<!-- tags: 定义常量, 只读的值, 不能改的值, const 怎么写 -->
|
||||
|
||||
顶层最稳的常量写法:
|
||||
@@ -170,6 +180,8 @@ value := kMaxRetries;
|
||||
|
||||
### 多参数赋值
|
||||
|
||||
<!-- section-id: syntax-04-006 -->
|
||||
|
||||
<!-- tags: 一次赋多个变量, 解构赋值, 拆数组到变量, 同时取两个值 -->
|
||||
|
||||
多参数赋值:
|
||||
@@ -297,6 +309,8 @@ end;
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-04-007 -->
|
||||
|
||||
普通变量和顶层常量的默认骨架如下:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -309,6 +323,8 @@ items := array(1, 2, 3);
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-04-008 -->
|
||||
|
||||
- 以为普通变量必须先写 `var` 才能使用。
|
||||
- 把常量初始化写成普通变量赋值风格。
|
||||
- 以为 `const =` 顶层单独写一行就一定成立。
|
||||
|
||||
@@ -4,12 +4,18 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-05-001 -->
|
||||
|
||||
回答“如何正确声明 `function` 和 `procedure`、`.tsl` 脚本语句区如何调用后置函数声明、怎样使用参数修饰、普通函数默认参数与可变参数,以及哪些函数写法会直接编译失败”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-05-002 -->
|
||||
|
||||
- 最稳妥的函数骨架仍然是 `function Name(...); begin ... end;`。
|
||||
<!-- quickstart-rule: function-default -->
|
||||
- 用户提示词里的“函数”默认对应 `function`,不要自动改写成 `procedure`。
|
||||
<!-- quickstart-rule: procedure-explicit -->
|
||||
- `procedure Name(...); begin ... end;` 只在用户明确要求 `procedure` / 过程时生成;不要因为没有返回值就自动改用 `procedure`。
|
||||
- `procedure` 头后不允许写返回类型;返回类型注解只用于 `function`。
|
||||
- 在 `.tsl` 文件模型层,脚本语句后可以接函数声明;语句区在前顺序执行,声明区在后提供函数/过程定义。见 [02_core_model.md](02_core_model.md)。
|
||||
@@ -29,8 +35,10 @@
|
||||
- 如果不确定任务是否需要写回语义,优先显式用 `const` 形参,或先切到 `{$varByRef-}`;不要依赖未修饰参数的运行时默认行为。
|
||||
- `return expr;` 会直接返回当前函数结果。
|
||||
- `exit;` 会立即结束当前函数;在本页最小样例里,如果此前没有写入返回结果,调用方观察到的是默认值 `0`。
|
||||
<!-- quickstart-rule: named-arguments -->
|
||||
- 调用时支持命名参数,写法是 `name: value`。
|
||||
- 命名参数也支持 `call(...)` 这类按函数名或函数指针转调的模型。
|
||||
<!-- quickstart-rule: named-argument-order -->
|
||||
- 一旦某次调用里开始使用命名参数,后面的参数就不能再退回位置参数。
|
||||
- 对二进制函数 / 系统函数直接使用命名参数,会报 `named parameter mode can't support here`;这类函数要先用 TSL 再封一层。
|
||||
- 函数参数支持默认值。
|
||||
@@ -50,6 +58,8 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-05-003 -->
|
||||
|
||||
使用这些示例时遵守:
|
||||
|
||||
- 普通运行示例默认按 `.tsl` 脚本语句区书写;入口语句放前面,函数 / 过程 / 类型声明放在后置声明区。
|
||||
@@ -59,6 +69,8 @@
|
||||
|
||||
### 基础函数 / 过程骨架
|
||||
|
||||
<!-- section-id: syntax-05-004 -->
|
||||
|
||||
<!-- tags: 定义函数, 怎么写函数, 函数骨架, 最少几行, procedure 怎么写, 函数放哪里, 先调用后声明 -->
|
||||
|
||||
`.tsl` 语句区调用后置函数声明:
|
||||
@@ -141,6 +153,8 @@ end;
|
||||
|
||||
### 签名增强:参数类型与返回值类型注解
|
||||
|
||||
<!-- section-id: syntax-05-005 -->
|
||||
|
||||
<!-- tags: 返回值类型, 声明返回类型, 参数标类型, 类型注解, 函数签名 -->
|
||||
|
||||
带参数类型和返回值类型:
|
||||
@@ -200,6 +214,8 @@ end;
|
||||
|
||||
### 参数传递方式
|
||||
|
||||
<!-- section-id: syntax-05-006 -->
|
||||
|
||||
<!-- tags: 传引用, 按引用传, 引用传递, 传值, 按值传递, 改形参影响外面, 写回调用方, 出参, 入参, 只读参数, 不让函数改 -->
|
||||
|
||||
未修饰参数默认写回调用方:
|
||||
@@ -317,6 +333,8 @@ end;
|
||||
|
||||
### `return` 与 `exit`
|
||||
|
||||
<!-- section-id: syntax-05-007 -->
|
||||
|
||||
<!-- tags: 返回值, 怎么返回结果, 结果返回, 提前结束, 提前返回, 中途退出函数, 无返回值退出 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -349,6 +367,8 @@ end;
|
||||
|
||||
### 调用增强:命名参数与混用规则
|
||||
|
||||
<!-- section-id: syntax-05-008 -->
|
||||
|
||||
<!-- tags: 按参数名传, 命名实参, 关键字参数, 指定参数名, 位置参数混用 -->
|
||||
|
||||
命名参数调用:
|
||||
@@ -428,6 +448,8 @@ end;
|
||||
|
||||
### 默认参数
|
||||
|
||||
<!-- section-id: syntax-05-009 -->
|
||||
|
||||
<!-- tags: 默认值, 可选参数, 参数省略, 不传就用默认 -->
|
||||
|
||||
默认值参数:
|
||||
@@ -514,6 +536,8 @@ function F(a, b = 100, c = default_value);
|
||||
|
||||
### 可变参数 `...`
|
||||
|
||||
<!-- section-id: syntax-05-010 -->
|
||||
|
||||
<!-- tags: 任意多个参数, 不定参数, 变长参数, 参数个数不固定, 参数转发 -->
|
||||
|
||||
尾部可变参数:
|
||||
@@ -652,6 +676,8 @@ end;
|
||||
|
||||
### 匿名函数与函数指针
|
||||
|
||||
<!-- section-id: syntax-05-011 -->
|
||||
|
||||
<!-- tags: lambda, 闭包, 函数当变量, 函数当参数, 回调, 函数指针, 把函数存起来 -->
|
||||
|
||||
匿名函数变量:
|
||||
@@ -775,6 +801,8 @@ writeLn(a(7, 8));
|
||||
|
||||
### `::` 指向全局函数
|
||||
|
||||
<!-- section-id: syntax-05-012 -->
|
||||
|
||||
<!-- tags: 重名, 同名函数, 调全局的那个, 作用域冲突, 指定全局函数 -->
|
||||
|
||||
当当前作用域里有同名局部函数时,可以用 `::FuncName(...)` 指定去调全局/系统函数:
|
||||
@@ -813,10 +841,14 @@ end;
|
||||
|
||||
### 系统交互专题
|
||||
|
||||
<!-- section-id: syntax-05-013 -->
|
||||
|
||||
`external`、原生函数指针包装、`makeInstance` / C 回调和线程调用,统一见 [17_external_calls_and_threads.md](17_external_calls_and_threads.md)。这一篇只保留“普通函数怎样定义和调用”的主线。
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-05-014 -->
|
||||
|
||||
如果你只是要写一个能被智能体稳定续写的 `.tsl` 脚本,从语句区起步,需要函数时把声明区放在后面:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -853,6 +885,8 @@ end;
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-05-015 -->
|
||||
|
||||
- 在 `.tsl` 的声明区后面继续写脚本语句。
|
||||
- 用户只说“写一个函数”时,默认改成 `procedure`。
|
||||
- 因为任务没有返回值,就自动改成 `procedure`。
|
||||
|
||||
@@ -4,14 +4,20 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-06-001 -->
|
||||
|
||||
回答“赋值、算术、比较、逻辑、位运算、集合/类型关系、条件求值、表达式对象、访问/调用、点前缀运算符和专题运算符入口在 TSL 里怎样写”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-06-002 -->
|
||||
|
||||
- 本页是 TSL 表达式与运算符的生成规则页;写代码时只使用本页或对应专题页明确记录的运算符和表达式形态。
|
||||
|
||||
### 本页直接生成的运算符
|
||||
|
||||
<!-- section-id: syntax-06-003 -->
|
||||
|
||||
<!-- tags: 运算符一览, 位运算, 逻辑运算, 算术运算, 比较运算, 移位, 按位与或 -->
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
@@ -46,6 +52,8 @@
|
||||
|
||||
### 专题运算符入口
|
||||
|
||||
<!-- section-id: syntax-06-004 -->
|
||||
|
||||
<!-- tags: 运算符去哪查, 特殊符号归属 -->
|
||||
|
||||
| 运算符 / 形态 | 责任页 | 生成规则 |
|
||||
@@ -66,8 +74,10 @@
|
||||
|
||||
默认生成规则:
|
||||
|
||||
- 普通变量赋值使用 `:=`;常量初始化不按普通赋值判断,见 [04_variables_and_constants.md](04_variables_and_constants.md)。
|
||||
- `=` 在普通表达式里用于比较,不用于赋值。
|
||||
<!-- quickstart-rule: assignment -->
|
||||
|
||||
- 普通变量赋值使用 `:=`;`=` 在普通表达式里用于比较,不用于赋值。
|
||||
- 常量初始化不按普通赋值判断,见 [04_variables_and_constants.md](04_variables_and_constants.md)。
|
||||
- `const name = value;` 和函数签名默认参数 `name = value` 不按本页普通表达式比较判断。
|
||||
- 普通算术使用 `+`、`-`、`*`、`/`、`\`、`%`、`div`、`mod`、`^`、`~`。
|
||||
- 需要数值倒数时用 `!x`;整型和实型输入都会得到实型结果。
|
||||
@@ -100,6 +110,8 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-06-005 -->
|
||||
|
||||
使用这些示例时遵守:
|
||||
|
||||
- `:=` 是普通变量赋值写法;常量初始化规则见 [04_variables_and_constants.md](04_variables_and_constants.md)。
|
||||
@@ -110,6 +122,8 @@
|
||||
|
||||
### 基础赋值和条件求值
|
||||
|
||||
<!-- section-id: syntax-06-006 -->
|
||||
|
||||
<!-- tags: 三目运算, 问号冒号, 条件表达式, 一行判断取值 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -554,6 +568,8 @@ writeLn(if 2 > 1 then 2 else 1);
|
||||
|
||||
### 表达式对象
|
||||
|
||||
<!-- section-id: syntax-06-007 -->
|
||||
|
||||
<!-- tags: 延迟求值, 表达式当值传, eval, 把式子存起来 -->
|
||||
|
||||
`@` 表达式前导:
|
||||
@@ -634,6 +650,8 @@ writeLn(result_value);
|
||||
|
||||
### 空安全访问
|
||||
|
||||
<!-- section-id: syntax-06-008 -->
|
||||
|
||||
<!-- tags: 对象可能为空, 判空取属性, nil 安全, 避免空指针 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -679,6 +697,8 @@ writeLn(c?.a?.[1] = nil);
|
||||
|
||||
### 否定形式运算
|
||||
|
||||
<!-- section-id: syntax-06-009 -->
|
||||
|
||||
<!-- tags: 取反, 不包含, 不匹配, not in 怎么写 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -707,6 +727,8 @@ end;
|
||||
|
||||
### 标量链式比较
|
||||
|
||||
<!-- section-id: syntax-06-010 -->
|
||||
|
||||
<!-- tags: 连续比较, 区间判断, 夹在中间, 大小连写 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -733,6 +755,8 @@ writeLn(1 :<> 2 :<> 3);
|
||||
|
||||
### 矩阵链式比较
|
||||
|
||||
<!-- section-id: syntax-06-011 -->
|
||||
|
||||
<!-- tags: 数组逐元素比较, 整列比较, 批量比较 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -763,6 +787,8 @@ writeLn(s[2]);
|
||||
|
||||
### 条件编译探测
|
||||
|
||||
<!-- section-id: syntax-06-012 -->
|
||||
|
||||
<!-- tags: 判断支持哪些特性, 版本探测, ifdef 怎么用 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -791,6 +817,8 @@ writeLn(0);
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-06-013 -->
|
||||
|
||||
如果你只需要最小的“比较 + 三目”例子,直接用这个:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -809,6 +837,8 @@ writeLn(value);
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-06-014 -->
|
||||
|
||||
- 用 `=` 当赋值运算符。
|
||||
- 把 `==` / `!=` 当成等值 / 不等值比较;本页比较使用 `=` / `<>`。
|
||||
- 把 `!` 当成逻辑非;本页逻辑非使用 `not`,`!` 是一元倒数/矩阵逆相关运算符。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-07-001 -->
|
||||
|
||||
回答“`if`、`case`、`for`、`while`、`repeat`、`break`、`continue`、`try`、`raise` 这些流程结构在 TSL 里到底怎么写,哪些写法可以直接生成”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-07-002 -->
|
||||
|
||||
- `if ... then ... else ...` 默认写成块式分支:`then begin ... end else begin ... end`。
|
||||
- 块式分支内部的普通语句必须用分号结尾。
|
||||
- 控制流块的 `begin ... end` 后可以加分号也可以不加(语法都允许)。
|
||||
@@ -26,6 +30,8 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-07-003 -->
|
||||
|
||||
使用这些示例时遵守:
|
||||
|
||||
- 条件表达式、比较、布尔值和普通赋值的事实见 [06_expressions_and_operators.md](06_expressions_and_operators.md)。
|
||||
@@ -34,6 +40,8 @@
|
||||
|
||||
### `if`、`while`、`repeat ... until`
|
||||
|
||||
<!-- section-id: syntax-07-004 -->
|
||||
|
||||
<!-- tags: 条件判断, 循环, 判断语句, 直到满足, 反复执行 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -69,6 +77,8 @@ writeLn(counter);
|
||||
|
||||
### `for` 的几种主干写法
|
||||
|
||||
<!-- section-id: syntax-07-005 -->
|
||||
|
||||
<!-- tags: 循环写法, 遍历数组, 计数循环, 倒着循环, 遍历键值 -->
|
||||
|
||||
最基础的递增循环:
|
||||
@@ -155,6 +165,8 @@ for i, value in numbers do
|
||||
|
||||
### `break` 与 `continue`
|
||||
|
||||
<!-- section-id: syntax-07-006 -->
|
||||
|
||||
<!-- tags: 跳出循环, 提前退出循环, 跳过本次, 结束循环 -->
|
||||
|
||||
`break`:
|
||||
@@ -216,6 +228,8 @@ writeLn(sum);
|
||||
|
||||
### `case` 语句形态
|
||||
|
||||
<!-- section-id: syntax-07-007 -->
|
||||
|
||||
<!-- tags: 多分支, 分支判断, switch 怎么写, 多条件选择 -->
|
||||
|
||||
普通分支:
|
||||
@@ -305,7 +319,9 @@ mid
|
||||
|
||||
### `try ... except`
|
||||
|
||||
<!-- tags: 捕获异常, 出错处理, 抓错误, 异常不中断 -->
|
||||
<!-- section-id: syntax-07-008 -->
|
||||
|
||||
<!-- tags: 捕获异常, 异常处理, 出错处理, 抓错误, 异常不中断 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
@@ -364,6 +380,8 @@ end
|
||||
|
||||
### `try ... finally`
|
||||
|
||||
<!-- section-id: syntax-07-009 -->
|
||||
|
||||
<!-- tags: 收尾处理, 无论如何都执行, 释放资源, 清理动作 -->
|
||||
|
||||
正常路径:
|
||||
@@ -425,6 +443,8 @@ finally
|
||||
|
||||
### `raise`
|
||||
|
||||
<!-- section-id: syntax-07-010 -->
|
||||
|
||||
<!-- tags: 抛异常, 主动报错, 中断执行, 扔错误 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -448,6 +468,8 @@ before
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-07-011 -->
|
||||
|
||||
最短条件分支的默认骨架如下:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -466,6 +488,8 @@ end
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-07-012 -->
|
||||
|
||||
- 在 `else` 前面误加分号。
|
||||
- 生成没有分号的裸分支赋值,例如 `then value := 1 else ...`;带 `else` 时用块式分支。
|
||||
- 以为 `try ... finally` 会吞掉异常。
|
||||
|
||||
@@ -4,10 +4,16 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-08-001 -->
|
||||
|
||||
回答“`type Name = class`、字段、`static`、方法、`property`、析构、类类型、继承和对象创建在 TSL 里怎样写”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-08-002 -->
|
||||
|
||||
<!-- quickstart-rule: class-shape -->
|
||||
|
||||
- 类定义统一按 `type Name = class ... end;` 写。
|
||||
- 顶层类声明可以放在松散语句之后(单向允许)。
|
||||
- 顶层类声明也可以放在顶层 `function / procedure` 之后。
|
||||
@@ -36,6 +42,7 @@
|
||||
- 基础覆盖写法是:父类方法声明为 `virtual`,子类对应方法声明为 `override`。
|
||||
- 基础祖先类调用:可以用 `Inherited;`、`Inherited MethodName(...)` 或 `class(BaseClass, ObjectName).MethodName()`。
|
||||
- 创建对象有两种方式:`new ClassName()` 最常用,`createObject(...)` 作为次选。
|
||||
<!-- quickstart-rule: object-creation -->
|
||||
- 普通本地类实例化默认生成 `new ClassName()`;`createObject("ClassName")`、`createObject(ClassType)` 只在字符串类名、类类型变量或跨 `unit` 路径场景生成。
|
||||
- 如果类里定义了 `function create(...)`,`new`、`createObject("ClassName", ...)` 和 `createObject(ClassType, ...)` 都可以透传构造参数,也都支持默认参数和命名参数。
|
||||
- 析构写法是无参 `function destroy();`;对象的最后一个引用被清空(如设为 `nil`)时会触发它。存在别名引用时,只清空其中一个引用不会触发。
|
||||
@@ -51,6 +58,8 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-08-003 -->
|
||||
|
||||
使用这些示例时遵守:
|
||||
|
||||
- 普通本地类创建优先复制 `new ClassName()` 形态。
|
||||
@@ -59,7 +68,9 @@
|
||||
|
||||
### 最小类与声明位置
|
||||
|
||||
<!-- tags: 定义一个类, 类怎么写, 最短类, 类放在哪, 类骨架 -->
|
||||
<!-- section-id: syntax-08-004 -->
|
||||
|
||||
<!-- tags: 定义一个类, 定义类, 类怎么写, 最短类, 类放在哪, 类骨架 -->
|
||||
|
||||
最短类骨架:
|
||||
|
||||
@@ -169,6 +180,8 @@ writeLn(a);
|
||||
|
||||
### 字段、静态成员、常量与可见性
|
||||
|
||||
<!-- section-id: syntax-08-005 -->
|
||||
|
||||
<!-- tags: 成员变量, 静态成员, 类常量, 私有公开, 属性可见性, 只有类自己能访问 -->
|
||||
|
||||
`static` 字段:
|
||||
@@ -383,6 +396,8 @@ end;
|
||||
|
||||
### 构造函数边界
|
||||
|
||||
<!-- section-id: syntax-08-006 -->
|
||||
|
||||
<!-- tags: 构造方法, 新建时初始化, create 怎么写, 带参数创建 -->
|
||||
|
||||
`create` 建议保持 `public`:
|
||||
@@ -412,6 +427,8 @@ end;
|
||||
|
||||
### 属性、类型注解与类外实现
|
||||
|
||||
<!-- section-id: syntax-08-007 -->
|
||||
|
||||
<!-- tags: property, 读写属性, getter setter, 方法写在类外 -->
|
||||
|
||||
基础 `property`:
|
||||
@@ -745,6 +762,8 @@ end;
|
||||
|
||||
### 对象创建与类类型
|
||||
|
||||
<!-- section-id: syntax-08-008 -->
|
||||
|
||||
<!-- tags: 创建对象, 实例化, new 怎么用, 拿到类本身, 动态建对象 -->
|
||||
|
||||
`new` 关键字:
|
||||
@@ -897,7 +916,9 @@ end;
|
||||
|
||||
### 重载、继承与析构
|
||||
|
||||
<!-- tags: 继承, 父类子类, 方法重载, 同名不同参, 析构, 对象销毁时 -->
|
||||
<!-- section-id: syntax-08-009 -->
|
||||
|
||||
<!-- tags: 继承, 父类子类, 方法重载, 同名不同参, 析构, 对象销毁时, 调用父类方法, 父类同名方法, inherited -->
|
||||
|
||||
`overload` 方法:
|
||||
|
||||
@@ -1302,6 +1323,8 @@ end;
|
||||
|
||||
### 跨 unit 类路径
|
||||
|
||||
<!-- section-id: syntax-08-010 -->
|
||||
|
||||
<!-- tags: 跨文件的类, 跨文件继承, 类的完整路径 -->
|
||||
|
||||
`unit` 中的嵌套类路径创建属于跨 `unit` 边界,这里用 `text` 展示骨架:
|
||||
@@ -1396,6 +1419,8 @@ writeLn(0);
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-08-011 -->
|
||||
|
||||
最短类骨架直接复用本页开头的“最短类骨架”。
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -1407,6 +1432,8 @@ end;
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-08-012 -->
|
||||
|
||||
- 以下误写不可照写;本节只收容易被智能体从相近语言或相邻 TSL 写法外推出来的边界,不重复列已经在核心规则里明确的普通规则。
|
||||
- 不把裸类名成员访问当成文档事实;类方法和静态字段默认用 `class(Name).Member` 或文档明确反射入口。
|
||||
- 把 `self()` 当成本页明确的工厂式写法。
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-09-001 -->
|
||||
|
||||
回答下面几类最常见的问题:
|
||||
|
||||
- 什么时候该把一组函数写成 `unit`
|
||||
@@ -14,8 +16,13 @@
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-09-002 -->
|
||||
|
||||
<!-- quickstart-rule: unit-shape -->
|
||||
|
||||
- `unit` 是完整的顶层主体;常见完整形态是 `unit Name; interface ... implementation ... end.`。
|
||||
- `unit` 也可以省略 `interface` / `implementation` 写成简写形态;这种简写里定义的函数对外可调用。
|
||||
<!-- quickstart-rule: unit-default -->
|
||||
- 如果没有特殊需求,默认优先用完整形态;简写形态只在不需要显式区分 `interface` / `implementation` 时再用。
|
||||
- 完整 `unit` 示例中,`implementation` 前保留空行,避免接口段和实现段挤在一起。
|
||||
- `unit` 允许接口声明与实现段分离:`interface` 段可以只声明函数签名或类方法签名,函数体和类方法体放到 `implementation` 段。
|
||||
@@ -33,8 +40,12 @@
|
||||
|
||||
## 示例与行为
|
||||
|
||||
<!-- section-id: syntax-09-003 -->
|
||||
|
||||
### 最小 `unit`
|
||||
|
||||
<!-- section-id: syntax-09-004 -->
|
||||
|
||||
<!-- tags: 怎么写 unit, 模块怎么定义, unit 骨架, 接口段实现段 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -71,6 +82,8 @@ end.
|
||||
|
||||
### 简写 `unit`
|
||||
|
||||
<!-- section-id: syntax-09-005 -->
|
||||
|
||||
<!-- tags: 省略 interface, 最简 unit, 不写接口段 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -104,6 +117,8 @@ end.
|
||||
|
||||
### 顶层、函数体、类体里的 `uses`
|
||||
|
||||
<!-- section-id: syntax-09-006 -->
|
||||
|
||||
<!-- tags: 怎么引入别的文件, 导入模块, uses 写在哪, 引用其他 unit -->
|
||||
|
||||
沿用同一个 `DemoUnit.tsf`,分别看顶层、函数体、类体三种 `uses` 位置:
|
||||
@@ -159,6 +174,8 @@ end;
|
||||
|
||||
### `uses` 的位置限制
|
||||
|
||||
<!-- section-id: syntax-09-007 -->
|
||||
|
||||
<!-- tags: uses 放错地方, 为什么导入失败, 引入语句必须第一行 -->
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
@@ -208,6 +225,8 @@ end;
|
||||
|
||||
### `interface` 段 `uses` 和 `implementation` 段 `uses`
|
||||
|
||||
<!-- section-id: syntax-09-008 -->
|
||||
|
||||
<!-- tags: 接口段导入, 实现段导入, 导入放哪一段 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -289,6 +308,8 @@ writeLn(obj.FromImplementation());
|
||||
|
||||
### 接口声明与实现段分离
|
||||
|
||||
<!-- section-id: syntax-09-009 -->
|
||||
|
||||
<!-- tags: 声明和实现分开, 对外暴露哪些, 接口里写什么 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -332,6 +353,8 @@ end.
|
||||
|
||||
### 实现段私有函数
|
||||
|
||||
<!-- section-id: syntax-09-010 -->
|
||||
|
||||
<!-- tags: 内部函数, 不对外暴露, 私有函数怎么写 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -380,6 +403,8 @@ writeLn(PrivateFunc());
|
||||
|
||||
### 重名解析与限定调用
|
||||
|
||||
<!-- section-id: syntax-09-011 -->
|
||||
|
||||
<!-- tags: 两个模块同名函数, 冲突了怎么调, 限定名调用, 指定哪个 unit -->
|
||||
|
||||
重名函数最小对照:
|
||||
@@ -476,6 +501,8 @@ writeLn(objB.value);
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-09-012 -->
|
||||
|
||||
如果你只是要先写出一个最小、可被其他文件引用的 `unit`,从下面这个骨架起步:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -499,6 +526,8 @@ end.
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-09-013 -->
|
||||
|
||||
- 把依赖外部 `unit` 的 `uses` 例子误当成单文件最小示例。
|
||||
- 在还没把目标 `unit` 放进查找路径前,就把“找不到接口”误判成 `uses` 语法错。
|
||||
- 把函数体或类定义体里的 `uses` 写在第一条语句之后。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-10-001 -->
|
||||
|
||||
回答“`setSysParam` / `getSysParam` 怎样用、`sysParams[...]` 是什么、块环境 `with *, values do` / `with **, values do` 怎样写、`#Func() with array(...)` 这种后缀环境调用怎样写,网格调用怎样取回结果,以及全局缓存最小读写规则是什么”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-10-002 -->
|
||||
|
||||
本页示例只说明运行时上下文语法中的调用位置和源码外形。API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。
|
||||
|
||||
- TSL 有一组运行时系统参数;本页只写通用语法形态。
|
||||
@@ -33,8 +37,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-10-003 -->
|
||||
|
||||
### `setSysParam` / `getSysParam` / `sysParams[...]` 基础读写
|
||||
|
||||
<!-- section-id: syntax-10-004 -->
|
||||
|
||||
<!-- tags: 系统参数, 读写运行参数, 环境设置, 全局设置项 -->
|
||||
|
||||
直接设置和读取系统参数:
|
||||
@@ -78,6 +86,8 @@ writeLn(getSysParam("a"));
|
||||
|
||||
### 块环境 `with *`
|
||||
|
||||
<!-- section-id: syntax-10-005 -->
|
||||
|
||||
<!-- tags: 临时改参数, 局部生效, 一段代码内有效, 块内覆盖 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -131,6 +141,8 @@ end
|
||||
|
||||
### 块环境 `with **`
|
||||
|
||||
<!-- section-id: syntax-10-006 -->
|
||||
|
||||
<!-- tags: 嵌套覆盖, 深层块环境, 多层 with -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -158,6 +170,8 @@ writeLn(getSysParam("b"));
|
||||
|
||||
### 后缀 `with array(...)`:网格调用的临时覆盖
|
||||
|
||||
<!-- section-id: syntax-10-007 -->
|
||||
|
||||
<!-- tags: 调用时临时改参数, 单次覆盖, 调用完恢复 -->
|
||||
|
||||
`#Func(...) with array(...)` 在一次网格调用里临时覆盖系统参数,调用结束后恢复外层原值。下面用一个 `TestDo.tsf` 演示覆盖边界:
|
||||
@@ -212,6 +226,8 @@ writeLn(getSysParam("b") = nil);
|
||||
|
||||
### `#` 网格调用与 `dupvalue`
|
||||
|
||||
<!-- section-id: syntax-10-008 -->
|
||||
|
||||
<!-- tags: 网格调用, 分布式执行, 井号调用, 取回结果 -->
|
||||
|
||||
网格调用函数:
|
||||
@@ -263,6 +279,8 @@ array(2,4,6,8,10)
|
||||
|
||||
### 网格调用的 `timeout`
|
||||
|
||||
<!-- section-id: syntax-10-009 -->
|
||||
|
||||
<!-- tags: 超时, 限制执行时间, 多久不返回就断 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -283,6 +301,8 @@ end;
|
||||
|
||||
### `setGlobalCache`、`getGlobalCache` 与 `ifCache`
|
||||
|
||||
<!-- section-id: syntax-10-010 -->
|
||||
|
||||
<!-- tags: 全局缓存, 缓存数据, 跨脚本共享, 存起来下次用 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -310,6 +330,8 @@ writeLn(cached_data[0], ',', cached_data[1], ',', cached_data[2]);
|
||||
|
||||
### `checkGlobalCacheExpired`
|
||||
|
||||
<!-- section-id: syntax-10-011 -->
|
||||
|
||||
<!-- tags: 缓存过期, 缓存失效判断, 什么时候要重算 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -329,6 +351,8 @@ writeLn(checkGlobalCacheExpired(cache_ref));
|
||||
|
||||
### 缓存值本地写入后会实例化
|
||||
|
||||
<!-- section-id: syntax-10-012 -->
|
||||
|
||||
<!-- tags: 改缓存内容, 缓存副本, 写回不影响原缓存 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -350,6 +374,8 @@ writeLn(local_copy[0], ',', local_copy[1], ',', local_copy[2]);
|
||||
|
||||
### 全局缓存参与 `select`
|
||||
|
||||
<!-- section-id: syntax-10-013 -->
|
||||
|
||||
<!-- tags: 对缓存做查询, 缓存当表查 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -373,6 +399,8 @@ writeLn(query_result[0][0], ',', query_result[0][1], ';', query_result[1][0], ',
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
<!-- section-id: syntax-10-014 -->
|
||||
|
||||
- 网格超时触发错误时的完整边界
|
||||
- `getGlobalCacheInfo`、`listGlobalCache`、`listGlobalCacheRemoved`
|
||||
- 初始化 TSL、监控线程、回收策略与兼容旧系统方案
|
||||
@@ -383,6 +411,8 @@ writeLn(query_result[0][0], ',', query_result[0][1], ';', query_result[1][0], ',
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-10-015 -->
|
||||
|
||||
最小运行时环境入口的默认骨架如下:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -409,6 +439,8 @@ end;
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-10-016 -->
|
||||
|
||||
- 把系统参数页直接写成金融函数页。
|
||||
- 把 `#Func() with array(...)` 误判成也能直接套在本地函数 `Demo()` 后面。
|
||||
- 把 `with *` 误判成会自动恢复外层系统参数。
|
||||
@@ -420,7 +452,7 @@ end;
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
```tsl
|
||||
```text
|
||||
cached_result := Demo() with array("a": 11);
|
||||
|
||||
function Demo();
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-11-001 -->
|
||||
|
||||
回答“`array(...)` 在 TSL 里除了最普通的一维数组,还能怎样组织数据;哪些矩阵样写法属于本页文档明确形态;元素、子集、整行和行集合关系应该怎样判断”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-11-002 -->
|
||||
|
||||
- `array(...)` 既可以写顺序数组,也可以写字符串键表。
|
||||
- 顺序数组下标从 `0` 开始;字符串仍然从 `1` 开始。
|
||||
- `array(...)` 可以继续嵌套,形成二维或矩阵样数据。
|
||||
@@ -21,9 +25,13 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-11-003 -->
|
||||
|
||||
### 基础数组与键表
|
||||
|
||||
<!-- tags: 建数组, 字典, 键值对, 二维数组, 嵌套数组, 按名字取值 -->
|
||||
<!-- section-id: syntax-11-004 -->
|
||||
|
||||
<!-- tags: 建数组, 数组下标, 数组索引, array 下标, 字典, 键值对, 二维数组, 嵌套数组, 按名字取值 -->
|
||||
|
||||
顺序数组与字符串键表:
|
||||
|
||||
@@ -71,6 +79,8 @@ writeLn(r2[1]);
|
||||
|
||||
### 矩阵样比较
|
||||
|
||||
<!-- section-id: syntax-11-005 -->
|
||||
|
||||
<!-- tags: 数组比大小, 链式比较, 整体比较 -->
|
||||
|
||||
矩阵链式比较:
|
||||
@@ -96,6 +106,8 @@ writeLn(s[2]);
|
||||
|
||||
### `in`、`not in`、`sqlin`、`not sqlin`
|
||||
|
||||
<!-- section-id: syntax-11-006 -->
|
||||
|
||||
<!-- tags: 判断存在, 是否包含, 在不在里面, 子集判断 -->
|
||||
|
||||
`in` 既可以判断单个元素是否存在,也可以判断左侧数组是否是右侧结果集的子集:
|
||||
@@ -156,6 +168,8 @@ writeLn(array(5, 6) not sqlin array((1, 2), (3, 4)));
|
||||
|
||||
### 行集合并、交、差、对称差
|
||||
|
||||
<!-- section-id: syntax-11-007 -->
|
||||
|
||||
<!-- tags: 交集, 并集, 差集, 合并两个数组, 去重合并, 共同部分 -->
|
||||
|
||||
下面这组最小例子展示“按行运算”和“结果会折叠重复行”:
|
||||
@@ -192,6 +206,8 @@ outersect_rows := left_rows outersect right_rows;
|
||||
|
||||
## 和过滤运算的区别
|
||||
|
||||
<!-- section-id: syntax-11-008 -->
|
||||
|
||||
<!-- tags: 集合还是过滤, 重复行怎么办, 两种运算怎么选 -->
|
||||
|
||||
- 集合运算先把数据当成“行集合”来看,再做包含、并交差。
|
||||
@@ -201,6 +217,8 @@ outersect_rows := left_rows outersect right_rows;
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-11-009 -->
|
||||
|
||||
按需求语义从下面两种模板中选择:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -212,6 +230,8 @@ row_matched := array(1, 2) sqlin array((1, 2), (3, 4));
|
||||
|
||||
## 点前缀比较算符产生逻辑数组
|
||||
|
||||
<!-- section-id: syntax-11-010 -->
|
||||
|
||||
<!-- tags: 逐元素比较, 得到真假数组, 批量判断, 掩码 -->
|
||||
|
||||
点前缀比较(`.=`、`.<>`、`.>`、`.>=`、`.<`、`.<=`)对数组/矩阵逐元素比较,返回真假值数组:
|
||||
@@ -277,6 +297,8 @@ writeLn("子集 (1,0):", subset[1][0]);
|
||||
|
||||
## 非完全矩阵缺位当 0 处理与标量广播
|
||||
|
||||
<!-- section-id: syntax-11-011 -->
|
||||
|
||||
<!-- tags: 长度不一致, 缺位补零, 标量广播, 数组和数字运算 -->
|
||||
|
||||
基础算符作用于非完全矩阵(行长度不一致或字符串键不对齐的数组)时,对应位置不存在或为 `nil` 时**默认当 0 处理**:
|
||||
@@ -336,6 +358,8 @@ writeLn("(1,1):", result[1][1]);
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
<!-- section-id: syntax-11-012 -->
|
||||
|
||||
- 专门的结果集过滤函数
|
||||
- TS-SQL 查询与写回
|
||||
- 更大范围的矩阵函数族
|
||||
@@ -344,6 +368,8 @@ writeLn("(1,1):", result[1][1]);
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-11-013 -->
|
||||
|
||||
- 不要把字符串下标按数组的 `0` 起始规则来写;字符串下标从 `1` 开始,详见 [03_values_and_literals.md](03_values_and_literals.md)。
|
||||
- 不要把矩阵链式比较 `::...` 和标量链式比较混写成同一种语法。
|
||||
- 不要把 `in` 和 `sqlin` 当成同一个概念。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-12-001 -->
|
||||
|
||||
回答“已有数组或二维结果集时,想按某个过滤集保留命中的行、排除命中的行,或者只拿到符合条件的行下标时,应该怎么写”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-12-002 -->
|
||||
|
||||
- 结果集过滤主函数是 `filterIn(...)` 和 `filterNotIn(...)`。
|
||||
- `filterIn(rows, filter_array, field)` 返回命中的子结果集;`filterNotIn(...)` 返回未命中的子结果集。
|
||||
- 第四个参数写成 `false` 时,返回值不再是子结果集,而是符合条件的行下标数组。
|
||||
@@ -20,8 +24,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-12-003 -->
|
||||
|
||||
### 按单列过滤
|
||||
|
||||
<!-- section-id: syntax-12-004 -->
|
||||
|
||||
<!-- tags: 筛选行, 按某列筛, 只要满足条件的, 排除某些行 -->
|
||||
|
||||
按 `"Code"` 列做包含与排除:
|
||||
@@ -60,6 +68,8 @@ writeLn(drop_rows[1]["Code"]);
|
||||
|
||||
### 返回行下标
|
||||
|
||||
<!-- section-id: syntax-12-005 -->
|
||||
|
||||
<!-- tags: 拿到行号, 返回位置, 只要下标不要数据 -->
|
||||
|
||||
第四个参数写成 `false` 时,返回行下标而不是子结果集:
|
||||
@@ -101,6 +111,8 @@ picked := rows[keep_index, array("Code", "V1")];
|
||||
|
||||
### `Field = nil` 时按整行过滤
|
||||
|
||||
<!-- section-id: syntax-12-006 -->
|
||||
|
||||
<!-- tags: 整行匹配, 一维数组过滤, 不指定列筛 -->
|
||||
|
||||
整行过滤与一维数组过滤都走 `Field = nil`:
|
||||
@@ -131,6 +143,8 @@ left_only := filterNotIn(array(1, 2, 3, 4, 5, 5, 6, 7), array(1, 2, 3, 4), nil);
|
||||
|
||||
### 按字段列表过滤
|
||||
|
||||
<!-- section-id: syntax-12-007 -->
|
||||
|
||||
<!-- tags: 多列判断, 按几个字段筛, 指定字段范围 -->
|
||||
|
||||
如果只想按部分列判断是否命中,把 `Field` 写成字段名数组:
|
||||
@@ -161,6 +175,8 @@ sub_result := rows[keep_index, array("A", "C")];
|
||||
|
||||
## 和集合运算的区别
|
||||
|
||||
<!-- section-id: syntax-12-008 -->
|
||||
|
||||
<!-- tags: 过滤还是集合, 重复记录保留, 两种运算怎么选 -->
|
||||
|
||||
- 过滤运算按“原结果集中的每一行是否命中”来决定保留或排除。
|
||||
@@ -170,6 +186,8 @@ sub_result := rows[keep_index, array("A", "C")];
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-12-009 -->
|
||||
|
||||
结果集过滤的默认骨架如下:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -185,6 +203,8 @@ keep_rows := filterIn(rows, code_arr, "Code");
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-12-010 -->
|
||||
|
||||
- 把 `filterIn(...)` 当成去重工具。
|
||||
- 过滤整行时忘了把 `Field` 写成 `nil`。
|
||||
- 需要返回下标时漏掉第四个参数 `false`。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-13-001 -->
|
||||
|
||||
回答“写 TS-SQL 查询和写回时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接(含 LEFT JOIN)、组内子查询、极值引用,以及如何用 `insert`/`update`/`delete` 修改内存数组”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-13-002 -->
|
||||
|
||||
- TS-SQL 是 TSL 自带的类 SQL 查询语法,不是金融业务函数库。
|
||||
- 基础查询文档骨架是:以 `select` / `sselect` / `vselect` / `mselect` 开始,以 `end` 收尾。
|
||||
- `from` 后面可以直接跟内存数组结果集。
|
||||
@@ -29,8 +33,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-13-003 -->
|
||||
|
||||
### 最小查询骨架
|
||||
|
||||
<!-- section-id: syntax-13-004 -->
|
||||
|
||||
<!-- tags: 怎么写查询, 最简 select, 查数组, 内存表查询 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -58,6 +66,8 @@ writeLn(length(query_result));
|
||||
|
||||
### 字段选择
|
||||
|
||||
<!-- section-id: syntax-13-005 -->
|
||||
|
||||
<!-- tags: 选哪些列, 只取部分字段, 指定列, 输出字段 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -80,6 +90,8 @@ writeLn(length(query_result));
|
||||
|
||||
### 四个查询入口怎样分工
|
||||
|
||||
<!-- section-id: syntax-13-006 -->
|
||||
|
||||
<!-- tags: select 和 sselect 区别, vselect, mselect, 返回什么形态, 该用哪个查询 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -106,6 +118,8 @@ col_index := mcols(matrix_result, 1);
|
||||
|
||||
### `where` 和 `order by`
|
||||
|
||||
<!-- section-id: syntax-13-007 -->
|
||||
|
||||
<!-- tags: 条件筛选, 排序, 按某列排, 倒序, 只要满足条件的行 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -127,6 +141,8 @@ query_result := select * from source_rows where ["B"] > 1 order by ["B"] end;
|
||||
|
||||
### `group by`
|
||||
|
||||
<!-- section-id: syntax-13-008 -->
|
||||
|
||||
<!-- tags: 分组, 汇总, 聚合统计, 按类别合计 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -153,6 +169,8 @@ group_result := select ["A"], sumOf(["B"]) as "SumB"
|
||||
|
||||
### 一维数组上的 `thisRow` 与 `thisRowIndex`
|
||||
|
||||
<!-- section-id: syntax-13-009 -->
|
||||
|
||||
<!-- tags: 当前行, 当前行号, 一维数组查询 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -176,6 +194,8 @@ query_result := select thisRow as "Value", thisRowIndex as "Idx"
|
||||
|
||||
### `join`
|
||||
|
||||
<!-- section-id: syntax-13-010 -->
|
||||
|
||||
<!-- tags: 两表关联, 表连接, 按键匹配, 拼接两张表 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -215,6 +235,8 @@ writeLn(join_result[0]["V2"]);
|
||||
|
||||
### `thisGroup`
|
||||
|
||||
<!-- section-id: syntax-13-011 -->
|
||||
|
||||
<!-- tags: 组内数据, 分组明细, 取当前组 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -242,6 +264,8 @@ group_result := select ["A"], max_b := maxOf(["B"]) as "MaxB",
|
||||
|
||||
### `thisRowIndex` 在排序后仍指向原始位置
|
||||
|
||||
<!-- section-id: syntax-13-012 -->
|
||||
|
||||
<!-- tags: 排序后原始行号, 原位置, 排序不改下标 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -265,6 +289,8 @@ query_result := select thisRowIndex as "Idx", ["B"]
|
||||
|
||||
### `refMaxOf` 与 `refMinOf`
|
||||
|
||||
<!-- section-id: syntax-13-013 -->
|
||||
|
||||
<!-- tags: 取最大值那行, 取最小值对应字段, 谁最大, 极值行 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -283,6 +309,8 @@ min_ref_result := select minOf([0]) as "MinA", refMinOf([1]) as "RefB" from sour
|
||||
|
||||
### `LEFT JOIN` 多表联接
|
||||
|
||||
<!-- section-id: syntax-13-014 -->
|
||||
|
||||
<!-- tags: 左连接, 左联接, 保留左表, 右边没有就空 -->
|
||||
|
||||
`left join` 保留左表所有行,右表不匹配时用 `nil` 填充:
|
||||
@@ -322,6 +350,8 @@ writeLn("(1,1):", result[1]["vb"]);
|
||||
|
||||
### `right join` / `full join` / `cross join` 与逗号联接
|
||||
|
||||
<!-- section-id: syntax-13-015 -->
|
||||
|
||||
<!-- tags: 右连接, 全连接, 笛卡尔积, 交叉联接 -->
|
||||
|
||||
`right join` / `full join` 的不匹配行同样用 `nil` 填充:
|
||||
@@ -423,6 +453,8 @@ writeLn("(0,0):", result[0]["id"]);
|
||||
|
||||
### `INSERT` 写回
|
||||
|
||||
<!-- section-id: syntax-13-016 -->
|
||||
|
||||
<!-- tags: 插入行, 新增记录, 往数组加数据 -->
|
||||
|
||||
`insert into` 向内存数组插入新行:
|
||||
@@ -480,6 +512,8 @@ writeLn(a[2]["id"], a[2]["cls"]);
|
||||
|
||||
### `UPDATE` 写回
|
||||
|
||||
<!-- section-id: syntax-13-017 -->
|
||||
|
||||
<!-- tags: 更新行, 改字段值, 批量修改 -->
|
||||
|
||||
`update` 修改符合条件的行:
|
||||
@@ -533,6 +567,8 @@ writeLn(r[0], r[1], r[2]);
|
||||
|
||||
### `DELETE` 写回
|
||||
|
||||
<!-- section-id: syntax-13-018 -->
|
||||
|
||||
<!-- tags: 删除行, 删掉记录, 按条件删 -->
|
||||
|
||||
`delete` 删除符合条件的行:
|
||||
@@ -582,6 +618,8 @@ writeLn(mrows(a));
|
||||
|
||||
### `distinct` 结果集去重
|
||||
|
||||
<!-- section-id: syntax-13-019 -->
|
||||
|
||||
<!-- tags: 去重, 不要重复行, 唯一值 -->
|
||||
|
||||
`select distinct` 对结果集去重;聚集函数内也可用 `distinct` 前缀:
|
||||
@@ -613,6 +651,8 @@ writeLn(plain_sum);
|
||||
|
||||
### `as` 别名、`as nil` 与字段区间
|
||||
|
||||
<!-- section-id: syntax-13-020 -->
|
||||
|
||||
<!-- tags: 改列名, 起别名, 丢弃字段, 字段区间 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -643,6 +683,8 @@ writeLn(mcols(range_rows));
|
||||
|
||||
### `drange` 取行区间
|
||||
|
||||
<!-- section-id: syntax-13-021 -->
|
||||
|
||||
<!-- tags: 取前几行, 分页, 行区间, 只要一段 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -672,6 +714,8 @@ writeLn(mrows(part_rows));
|
||||
|
||||
### `selectopt` 位选项
|
||||
|
||||
<!-- section-id: syntax-13-022 -->
|
||||
|
||||
<!-- tags: 查询选项, 返回形态控制, 位标志 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -697,6 +741,8 @@ writeLn(opt_rows[0]);
|
||||
|
||||
### 条件聚集、移动聚集与 `refof`
|
||||
|
||||
<!-- section-id: syntax-13-023 -->
|
||||
|
||||
<!-- tags: 条件求和, 滑动窗口, 移动平均, 带条件的聚合 -->
|
||||
|
||||
聚集函数统一支持 `(Expr, BoolConditionExp, N, MovingFirst, CacheId)` 形态:
|
||||
@@ -729,6 +775,8 @@ writeLn(ref_prev[1]["Expr1"]);
|
||||
|
||||
### `group by ... having`
|
||||
|
||||
<!-- section-id: syntax-13-024 -->
|
||||
|
||||
<!-- tags: 分组后筛选, 聚合条件, 组级过滤 -->
|
||||
|
||||
`having` 用聚集条件筛选分组(`where` 不能用聚集):
|
||||
@@ -764,6 +812,8 @@ having_rows := select ["cls"] from a group by ["cls"] having countof(*) > 1 end;
|
||||
|
||||
### `thisOrder` 与多列 `order by`
|
||||
|
||||
<!-- section-id: syntax-13-025 -->
|
||||
|
||||
<!-- tags: 多列排序, 排名, 序号, 先按 A 再按 B -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -791,6 +841,8 @@ writeLn(desc_rows[0]["id"]);
|
||||
|
||||
### `refsof` 引用上级结果集
|
||||
|
||||
<!-- section-id: syntax-13-026 -->
|
||||
|
||||
<!-- tags: 子查询取外层, 嵌套查询, 引用上一层 -->
|
||||
|
||||
在嵌套子查询里,`refsof(Exp, UpLevel)` 用上 N 级结果集计算 `Exp`:
|
||||
@@ -818,6 +870,8 @@ writeLn(r[1]["id"], ",", r[1]["up"]);
|
||||
|
||||
### `[@Field]` 取字段类型
|
||||
|
||||
<!-- section-id: syntax-13-027 -->
|
||||
|
||||
<!-- tags: 字段类型, 列的数据类型 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -840,6 +894,8 @@ integer
|
||||
|
||||
### `aggof` 自定义聚集扩展
|
||||
|
||||
<!-- section-id: syntax-13-028 -->
|
||||
|
||||
<!-- tags: 自定义聚合, 自己写聚集函数 -->
|
||||
|
||||
`aggof('名称', 表达式)` 调用一个自定义回调函数做聚集。本地 `TSL.exe` 会报 `AggOf Init Error`;下例在服务端(pyTSL)验证通过:
|
||||
@@ -877,6 +933,8 @@ end;
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
<!-- section-id: syntax-13-029 -->
|
||||
|
||||
- `TSQLInsert` / `TSQLSetValue` / `TSQLBatchInsert` / `TSQLEdit` / `TSQLPost` / `TSQLFinal` 对象被 TS-SQL 查询的回调机制
|
||||
- 面向 SQL 表、业务表或时间序列的数据查询与写回(`marketTable` / `infoTable` / `tradeTable` / `sqlTable` / `hugeSqlTable` 等数据源)
|
||||
|
||||
@@ -884,6 +942,8 @@ end;
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-13-030 -->
|
||||
|
||||
TS-SQL 的最短默认骨架如下:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -895,6 +955,8 @@ query_result := select * from source_rows end;
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-13-031 -->
|
||||
|
||||
- 不要把数据库 SQL 方言直接迁移成 TS-SQL 代码。
|
||||
- 不要把 `select` 当成普通函数调用,忘了以 `end` 收尾。
|
||||
- 在二维结果集里直接写 `A` 而不是 `["A"]`。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-14-001 -->
|
||||
|
||||
回答“`goto`、`debugReturn`、`debugRunEnv`、`mtic` / `mtoc`、`setProfiler`、`__line__` 和 `__stack_frame` 怎样写、会怎样表现”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-14-002 -->
|
||||
|
||||
本页示例只说明调试与分析结构中的调用位置和源码外形。相关 API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。
|
||||
|
||||
- `goto label_name;` 属于文档明确写法,但目标位置以 `label label_name; statement` 这种内联形式作为默认生成形态。
|
||||
@@ -23,8 +27,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-14-003 -->
|
||||
|
||||
### `goto`
|
||||
|
||||
<!-- section-id: syntax-14-004 -->
|
||||
|
||||
<!-- tags: 跳转, 跳出多重循环, 标签跳转 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -91,6 +99,8 @@ writeLn("after");
|
||||
|
||||
### `debugReturn`
|
||||
|
||||
<!-- section-id: syntax-14-005 -->
|
||||
|
||||
<!-- tags: 中途看返回值, 调试返回, 提前打断 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -114,6 +124,8 @@ end;
|
||||
|
||||
### `debugRunEnv` 与 `debugRunEnvDo`
|
||||
|
||||
<!-- section-id: syntax-14-006 -->
|
||||
|
||||
<!-- tags: 调试环境, 运行环境切换, 调试开关 -->
|
||||
|
||||
`debugRunEnv(0)` / `debugRunEnv(1)`:
|
||||
@@ -156,6 +168,8 @@ end;
|
||||
|
||||
### `mtic` 与 `mtoc`
|
||||
|
||||
<!-- section-id: syntax-14-007 -->
|
||||
|
||||
<!-- tags: 计时, 测耗时, 跑了多久, 秒表, 执行时间 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -181,6 +195,8 @@ writeLn(elapsed2 >= 0);
|
||||
|
||||
### `setProfiler` 与 `getProfilerInfo`
|
||||
|
||||
<!-- section-id: syntax-14-008 -->
|
||||
|
||||
<!-- tags: 性能分析, 找瓶颈, profiler, 哪段最慢 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -203,6 +219,8 @@ writeLn(length(info) > 0);
|
||||
|
||||
### `__line__` 与 `__stack_frame`
|
||||
|
||||
<!-- section-id: syntax-14-009 -->
|
||||
|
||||
<!-- tags: 当前行号, 调用栈, 堆栈信息, 报错在哪一行 -->
|
||||
|
||||
`__line__`:
|
||||
@@ -252,6 +270,8 @@ array(
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-14-010 -->
|
||||
|
||||
- 不要把 `debugReturn` 当成普通函数 `return` 使用。
|
||||
- 不要假设 `goto` 可以跨函数、跨脚本体或跳到单独成行的 `label`。
|
||||
- 不要给计时或性能分析器调用补未写入文档参数。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-15-001 -->
|
||||
|
||||
回答“TSL 的词法层规则和编译期开关有哪些”:标识符与大小写、注释形态、保留字清单,以及 `{$...}` 编译开关的书写位置和作用范围。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-15-002 -->
|
||||
|
||||
- 标识符大小写无关;下划线可出现在标识符中。
|
||||
- `//` 是行注释;首行 `#!` 可作为 CGI 风格注释;`{ ... }` 与 `(* ... *)` 是块注释。
|
||||
- 条件编译指令使用 `{$define}`、`{$undef}`、`{$ifdef}`、`{$ifndef}`、`{$else}`、`{$endif}`。
|
||||
@@ -20,6 +24,8 @@
|
||||
|
||||
## 保留字/关键字速查
|
||||
|
||||
<!-- section-id: syntax-15-003 -->
|
||||
|
||||
<!-- tags: 关键字列表, 保留字, 哪些名字不能用 -->
|
||||
|
||||
TSL 关键字大小写无关;本表统一按文档推荐写法展示。生成代码时不要把这些名称用作普通标识符。
|
||||
@@ -35,19 +41,23 @@ TSL 关键字大小写无关;本表统一按文档推荐写法展示。生成
|
||||
| 参数访问 | `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);调试相关事实见 [14_debug_and_profiler.md](14_debug_and_profiler.md)。 |
|
||||
| LIKE 精度 | `likeEps`、`likeEpsRate` | 只在需要调整 `like` 数值近似判断阈值时使用。 |
|
||||
| 类与对象 | `type`、`class`、`new`、`findClass`、`findFunction`、`fackClass`、`property`、`self`、`virtual`、`override`、`overload`、`protected`、`public`、`private`、`published`、`static` | 类声明、对象创建和成员规则见 [08_objects_and_classes.md](08_objects_and_classes.md)。 |
|
||||
| 类与对象 | `type`、`class`、`new`、`findClass`、`findFunction`、`fackClass`、`property`、`self`、`virtual`、`override`、`overload`、`Inherited`、`protected`、`public`、`private`、`published`、`static` | 类声明、对象创建和成员规则见 [08_objects_and_classes.md](08_objects_and_classes.md);`Inherited;` / `Inherited MethodName(...)` 是祖先类调用写法,同见该页。 |
|
||||
| 外部调用约定 | `external`、`cdecl`、`pascal`、`stdcall`、`safecall`、`fastcall`、`register` | 外部调用细节见 [17_external_calls_and_threads.md](17_external_calls_and_threads.md)。 |
|
||||
| 客户端远程调用与权限 | `rdo`、`rdo2`、`sudo`、`setUid` | 平台/客户端远程调用和权限语义不作为普通本地语法模板。 |
|
||||
| 客户端远程调用与权限 | `rdo`、`rdo2`、`sudo`、`setUid` | `rdo` / `rdo2` 见 [24_client_remote_calls.md](24_client_remote_calls.md);它们不能建模成普通函数。 |
|
||||
| TS-SQL 查询 | `select`、`vselect`、`sselect`、`mselect`、`distinct`、`selectOpt`、`dRange`、`as`、`from`、`marketTable`、`infoTable`、`tradeTable`、`sqlTable`、`hugeSqlTable`、`keepNull`、`dateKey`、`of`、`order`、`by`、`where`、`desc`、`asc`、`group`、`having` | 查询语法见 [13_ts_sql.md](13_ts_sql.md)。 |
|
||||
| TS-SQL 聚合与上下文 | `checksumOf`、`countOf`、`sumOf`、`maxOf`、`stdevOf`、`varOf`、`totalVarOf`、`normOf`、`medianOf`、`aveDevOf`、`geoMeanOf`、`skewOf`、`kurtosisOf`、`skew2Of`、`kurtosis2Of`、`largeOf`、`percentileOf`、`quartileOf`、`trimMeanOf`、`avgOf`、`minOf`、`aggOf`、`stdevpOf`、`varpOf`、`modeOf`、`devSqOf`、`harMeanOf`、`checksum_aggOf`、`smallOf`、`percentRankOf`、`rankOf`、`frequencyOf`、`productOf`、`refOf`、`refsOf`、`aggValue`、`thisGroup`、`thisRow`、`thisRowIndex`、`thisOrder` | 这些名称只在 TS-SQL 语境中生成。 |
|
||||
| TS-SQL 写入 | `insert`、`insertFields`、`values`、`update`、`set`、`delete`、`deleteOpt`、`fetchFirst`、`fetchNext` | 写回/变更型查询只按 TS-SQL 专题页生成。 |
|
||||
| 系统保留未使用 | `exports`、`dispInterface`、`library`、`asm`、`record`、`resourceString`、`threadVar`、`constructor`、`destructor`、`inline`、`packed`、`abstract`、`inherited` | 这些名称被系统保留,不作为普通标识符使用,也不作为可写语法模板。 |
|
||||
| 系统保留未使用 | `exports`、`dispInterface`、`library`、`asm`、`record`、`resourceString`、`threadVar`、`constructor`、`destructor`、`inline`、`packed`、`abstract` | 这些名称被系统保留,不作为普通标识符使用,也不作为可写语法模板。 |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-15-004 -->
|
||||
|
||||
### 标识符、注释与条件编译
|
||||
|
||||
<!-- section-id: syntax-15-005 -->
|
||||
|
||||
<!-- tags: 注释怎么写, 大小写敏感吗, 变量命名, 下划线 -->
|
||||
|
||||
大小写无关与下划线标识符:
|
||||
@@ -106,6 +116,8 @@ writeLn(40);
|
||||
|
||||
### 显式变量声明开关
|
||||
|
||||
<!-- section-id: syntax-15-006 -->
|
||||
|
||||
<!-- tags: 强制声明变量, explicit, 必须先 var -->
|
||||
|
||||
`{$explicit+}` 的文档明确形态:
|
||||
@@ -144,6 +156,8 @@ writeLn(a + b);
|
||||
|
||||
### 条件编译分支边界
|
||||
|
||||
<!-- section-id: syntax-15-007 -->
|
||||
|
||||
<!-- tags: 条件编译, 未命中分支, ifdef 不编译 -->
|
||||
|
||||
条件编译不会去编译未命中的坏代码分支:
|
||||
@@ -166,6 +180,8 @@ writeLn(1);
|
||||
|
||||
### `{$CompileOption}` 编译选项
|
||||
|
||||
<!-- section-id: syntax-15-008 -->
|
||||
|
||||
<!-- tags: 编译开关, 编译器选项, 改默认行为 -->
|
||||
|
||||
`{$CompileOption}` 用于设置编译期开关,改变编译器的默认行为:
|
||||
@@ -192,6 +208,8 @@ echo 1 + 1;
|
||||
|
||||
### 参数默认传递开关
|
||||
|
||||
<!-- section-id: syntax-15-009 -->
|
||||
|
||||
<!-- tags: 全局改传参方式, varByRef 开关, 默认按值还是按引用 -->
|
||||
|
||||
`{$varByRef-}` 与 `{$varByRef+}`:
|
||||
@@ -242,6 +260,8 @@ end;
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-15-010 -->
|
||||
|
||||
- 不要在 `{$explicit+}` 后继续直接使用未声明变量。
|
||||
- 不要把 `{$i ...}` / `{$include ...}` 包含文件写法当成可用能力。
|
||||
- 不要把 `反例 / 不可照写` 代码块复制进正向示例。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-16-001 -->
|
||||
|
||||
回答“运行时值会变成什么类型、默认值是什么、怎样显式转换、复数怎样表示”。本页拥有数值 / 日期时间 / 真假值 / nil / 复数字面量与类型转换边界;变量声明形式和编译期开关不在本页收口。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-16-002 -->
|
||||
|
||||
- 整数常量支持十进制、`0x` 十六进制、`0b` 二进制和 `0o` 八进制。
|
||||
- `100L` 这类后缀写法表示 `Int64` 常量。
|
||||
- 超过 32 位整数范围的十进制整数字面量 `2147483648` 按 `Int64`,不按实数处理。
|
||||
@@ -35,8 +39,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-16-003 -->
|
||||
|
||||
### 数值、日期与真值
|
||||
|
||||
<!-- section-id: syntax-16-004 -->
|
||||
|
||||
<!-- tags: 整数小数, 十六进制, 日期字面量, 真假值, 判断类型 -->
|
||||
|
||||
基础数字字面量与类型判定:
|
||||
@@ -68,6 +76,12 @@ writeLn(ifReal(1E2));
|
||||
|
||||
```text
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
0
|
||||
1
|
||||
```
|
||||
@@ -120,6 +134,8 @@ writeLn(nan = nan);
|
||||
|
||||
### 初始值与空值
|
||||
|
||||
<!-- section-id: syntax-16-005 -->
|
||||
|
||||
<!-- tags: 变量默认值, nil, 空值, 没赋值是什么 -->
|
||||
|
||||
变量初始值与缺失值:
|
||||
@@ -199,6 +215,8 @@ writeLn(ifNumber("100"));
|
||||
|
||||
### 显式类型转换
|
||||
|
||||
<!-- section-id: syntax-16-006 -->
|
||||
|
||||
<!-- tags: 转整数, 转字符串, 类型互转, strToInt -->
|
||||
|
||||
显式类型转换的正向例子:
|
||||
@@ -219,6 +237,8 @@ writeLn(c);
|
||||
|
||||
### 复数
|
||||
|
||||
<!-- section-id: syntax-16-007 -->
|
||||
|
||||
<!-- tags: 复数, 虚数, 实部虚部 -->
|
||||
|
||||
复数常量、类型与基础读取:
|
||||
@@ -351,6 +371,8 @@ writeLn(imag(z));
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-16-008 -->
|
||||
|
||||
- 不要把“能编译”误解成“会自动按期望类型转换”。
|
||||
- 不要把数字字符串直接当成数值参与算术;需要数值语义时先显式转换。
|
||||
- 不要从其他语言的 truthy/falsy 或隐式转换规则反推 TSL。
|
||||
|
||||
@@ -1,28 +1,134 @@
|
||||
# TSL 外部调用与线程
|
||||
|
||||
这一篇吸收函数专题里和外部系统交互有关的部分:`external`、动态库调用、原生函数指针包装、C 回调和线程调用。
|
||||
本页说明动态库声明、原生函数指针、C 回调和线程调用。`MakeInstance`、`DeleteInstance` 是 builtin API;`external`、`name`、`KeepResident`、`cdecl`、`stdcall` 和外部参数声明是语法。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
回答“外部 DLL 声明、原生函数指针包装、C 回调和多线程调用有哪些文档明确写法”。本页只覆盖系统交互能力,普通 TSL 函数的定义与调用不在本页收口。
|
||||
<!-- section-id: syntax-17-001 -->
|
||||
|
||||
回答外部动态库、函数指针、C 回调和线程调用的写法。`LoadLibraryA`、`GetProcAddress`、`dlopen`、`dlsym` 是宿主 API;`TSL_ScriptGo` 等 `TSSVRAPI.h` 名称是 C/C++ SDK API,均不进入 TSL builtin 索引。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-17-002 -->
|
||||
|
||||
- 外部函数声明的文档明确形态是 `function Name(...): Type; stdcall|cdecl; external "dll" [name "symbol"];`。
|
||||
- 当 TSL 函数名和 DLL 导出名一致时,`name "symbol"` 可以省略。
|
||||
- Windows 示例默认显式写调用约定;不要把省略调用约定当成跨平台默认规则。
|
||||
- Win32 下调用约定必须与宿主函数一致;Linux 与 Win64 下 `stdcall` 和 `cdecl` 使用相同调用模式。
|
||||
- 无返回值的外部接口可声明为 `procedure Name(...); ... external ...;`。
|
||||
- 外部函数需要写回调用方变量时,在参数名前写 `var`;TSL 参数类型必须与原生 ABI 的参数宽度和含义一致。
|
||||
- `KeepResident` 写在外部库声明末尾,用于保留动态库句柄。
|
||||
- `function(...): ...; external fp;` 可以把原生函数指针重新包装成 TSL 可调用对象。
|
||||
- DLL 名写法包括字面量字符串和类常量字符串;不要把字符串拼接表达式直接当成稳定写法。
|
||||
- `makeInstance(thisFunction(Func), "cdecl", 0)` 可以把 TSL 函数包装成 C 调用约定函数指针。
|
||||
- Windows 线程示例用 `makeInstance(..., "cdecl", 1)` 生成可交给 `CreateThread` 的回调指针。
|
||||
- 外部库名和调用约定要按目标平台选择;不要把 Windows 的 `kernel32.dll` 示例直接复制到 Linux,或把 Linux 的 `.so` 示例直接复制到 Windows。
|
||||
- 本页线程示例是 Windows 专题,用到了 `kernel32.dll`。
|
||||
- 库名可使用字面量字符串或类常量字符串,不能使用字符串拼接表达式。
|
||||
- `MakeInstance(thisFunction(Func), "cdecl", 0)` 或 `MakeInstance(findFunction("Func"), "cdecl", 0)` 可以把有完整参数及返回类型声明的 TSL 函数包装成 C 调用约定函数指针。
|
||||
- `DeleteInstance(ptr)` 用于删除 `MakeInstance` 生成的指针;包装出来的 TSL 函数变量应先解除引用,再删除原始指针。
|
||||
- Windows 线程示例用 `MakeInstance(..., "cdecl", 1)` 生成可交给 `CreateThread` 的回调指针。
|
||||
- 外部库名按目标平台选择:Windows 使用 DLL,Linux 使用对应 `.so`。
|
||||
- 文档列出的基础外部类型包括 `Integer`、`String`、`Double`、`Single`、`Boolean`、`Pointer`、`PChar`、`Int64`、`Short` 和 `Byte`,未列出的类型按 `String` 处理。结构体等复合类型仍须按原生 ABI 组装内存;不能直接导入 C++ 引出类。
|
||||
|
||||
## 外部 ABI 与动态库常驻
|
||||
|
||||
<!-- section-id: syntax-17-012 -->
|
||||
|
||||
<!-- tags: KeepResident 动态库常驻 external ABI 类型映射 -->
|
||||
|
||||
`external` 是 TSL 与宿主 ABI 的边界,不是 builtin 定义。参数类型、宽度、对齐和调用约定必须与原生函数一致;结构体等复合参数须自行封装内存布局。
|
||||
|
||||
`KeepResident` 放在 `external` 库声明末尾,用于要求动态库句柄在调用后保持常驻。例如:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:Linux 示例,依赖 `libc.so.6`。
|
||||
|
||||
```tsl
|
||||
writeLn(GetPidResident() > 0);
|
||||
|
||||
function GetPidResident(): integer; cdecl; external "libc.so.6" name "getpid" KeepResident;
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
```
|
||||
|
||||
## 外部出参与 ABI 写回
|
||||
|
||||
<!-- section-id: syntax-17-013 -->
|
||||
|
||||
<!-- tags: 外部出参 external var 出参 写回调用方 glibc libc time ABI -->
|
||||
|
||||
当外部函数需要通过指针写回调用方变量时,在参数名前使用 `var`。这条规则只说明 TSL 声明形态;具体类型、宽度、对齐和调用约定仍必须与原生函数一致。
|
||||
|
||||
下面用 libc `time` 演示 `var` 外部出参:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:Linux x86_64 示例,依赖 `libc.so.6`;`time_t` 按该 ABI 映射为 `int64`。
|
||||
|
||||
```tsl
|
||||
stamp := 0;
|
||||
result := UnixTime(stamp);
|
||||
writeLn(result > 0);
|
||||
writeLn(stamp = result);
|
||||
|
||||
function UnixTime(var stamp: int64): int64; cdecl; external "libc.so.6" name "time";
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
1
|
||||
```
|
||||
|
||||
`UnixTime` 是脚本别名,`time` 是 libc 导出符号,二者都不是 TSL builtin。
|
||||
|
||||
## Linux 动态加载与函数指针生命周期
|
||||
|
||||
<!-- section-id: syntax-17-014 -->
|
||||
|
||||
<!-- tags: Linux 动态加载 glibc dlsym dlopen external 原生指针 -->
|
||||
|
||||
Linux 可用 `dlopen` / `dlsym` 取得原生函数指针,再用 `external fp` 包装。Windows 对应使用 `LoadLibraryA` / `GetProcAddress`。这些名称都是宿主 API,不是 TSL builtin。
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:Linux 示例,依赖 `libdl.so.2` 和 `libc.so.6`;`1` 为该环境的 `RTLD_LAZY`。
|
||||
|
||||
```tsl
|
||||
module_handle := dlopen("libc.so.6", 1);
|
||||
func_ptr := dlsym(module_handle, "getpid");
|
||||
wrapped_func := function(): integer; cdecl; external func_ptr;
|
||||
writeLn(module_handle <> nil);
|
||||
writeLn(func_ptr <> nil);
|
||||
writeLn(##wrapped_func() > 0);
|
||||
wrapped_func := nil;
|
||||
writeLn(dlclose(module_handle) = 0);
|
||||
|
||||
function dlopen(filename: string; flags: integer): pointer; cdecl; external "libdl.so.2" name "dlopen";
|
||||
function dlsym(handle: pointer; symbol: string): pointer; cdecl; external "libdl.so.2" name "dlsym";
|
||||
function dlclose(handle: pointer): integer; cdecl; external "libdl.so.2" name "dlclose";
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
```
|
||||
|
||||
释放顺序是先将包装变量设为 `nil`,再调用 `dlclose`。
|
||||
|
||||
`MakeInstance` 生成的指针由 `DeleteInstance` 释放;若已包装为 TSL 函数变量,先将包装变量设为 `nil`。示例见 `syntax-17-008`,API 签名见 `tsl-api-reference`。
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-17-003 -->
|
||||
|
||||
### 最小 `external` 声明
|
||||
|
||||
<!-- section-id: syntax-17-004 -->
|
||||
|
||||
<!-- tags: 调外部函数, 声明外部函数, 绑 dll 函数, 导入系统函数 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -33,11 +139,7 @@ writeLn(Tick64Alias() > 0);
|
||||
function Tick64Alias(): int64; stdcall; external "kernel32.dll" name "GetTickCount64";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `1`
|
||||
- 说明 `stdcall` + `external "dll" name "symbol"` 是本页明确的外部函数声明骨架
|
||||
- 也说明 TSL 里的函数名可以和 DLL 导出名不同,再通过 `name "ExportName"` 绑定
|
||||
结果说明:输出 `1`;`name` 用于绑定不同名的导出符号。
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
@@ -45,10 +147,10 @@ function Tick64Alias(): int64; stdcall; external "kernel32.dll" name "GetTickCou
|
||||
1
|
||||
```
|
||||
|
||||
Linux / POSIX 环境的同类最小骨架:
|
||||
Linux 的同类声明:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:仅类 Unix 环境可执行(依赖 `libc.so.6`);Windows 下不可照抄,本块只演示 `.so` 库名写法。
|
||||
代码块说明:依赖 `libc.so.6`。
|
||||
|
||||
```tsl
|
||||
writeLn(getpid() > 0);
|
||||
@@ -62,8 +164,6 @@ function getpid(): integer; cdecl; external "libc.so.6";
|
||||
1
|
||||
```
|
||||
|
||||
这段说明 Linux / POSIX 目标下可以用 `.so` 库名声明外部函数;生成代码时仍要先判断用户的目标平台。
|
||||
|
||||
当本地函数名和 DLL 导出名一致时,`name` 可以省略:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -74,12 +174,9 @@ writeLn(GetTickCount64() > 0);
|
||||
function GetTickCount64(): int64; stdcall; external "kernel32.dll";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
结果说明:输出 `1`。
|
||||
|
||||
- 输出 `1`
|
||||
- 说明当本地函数名和导出名一致时,`name "symbol"` 不是强制写法
|
||||
|
||||
Windows 的同一 API 示例里,省略调用约定与显式 `cdecl` 也列入文档边界:
|
||||
也可以省略调用约定或显式写 `cdecl`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
@@ -94,11 +191,12 @@ function TickCdecl(): int64; cdecl; external "kernel32.dll" name "GetTickCount64
|
||||
结果说明:
|
||||
|
||||
- 依次输出 `1`、`1`
|
||||
- 这只说明 Windows 的同一 API 示例里,这两种写法属于文档边界
|
||||
- 不要把这个结果直接泛化成“所有平台、所有架构下调用约定都等价”
|
||||
- Win32 下仍须按原函数的真实调用约定声明
|
||||
|
||||
### `procedure external`
|
||||
|
||||
<!-- section-id: syntax-17-005 -->
|
||||
|
||||
<!-- tags: 外部过程, 无返回值的外部函数, 调系统 API -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -113,13 +211,12 @@ function Tick64(): int64; stdcall; external "kernel32.dll" name "GetTickCount64"
|
||||
procedure SleepMs(ms: integer); stdcall; external "kernel32.dll" name "Sleep";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `1`
|
||||
- 说明无返回值的外部过程可以直接声明为 `procedure`
|
||||
结果说明:输出 `1`;无返回值接口可声明为 `procedure`。
|
||||
|
||||
### 原生函数指针包装
|
||||
|
||||
<!-- section-id: syntax-17-006 -->
|
||||
|
||||
<!-- tags: LoadLibrary, 拿函数地址, 动态加载, GetProcAddress -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -136,16 +233,13 @@ function LoadLibraryA(lib_name: string): pointer; stdcall; external "kernel32.dl
|
||||
function GetProcAddress(module_handle: pointer; proc_name: string): pointer; stdcall; external "kernel32.dll" name "GetProcAddress";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 依次输出 `1`、`1`、`1`
|
||||
- 说明 `function(...); ... external fp;` 不只适用于 `makeInstance(...)` 的结果,也适用于 `GetProcAddress(...)` 返回的原生函数指针
|
||||
结果说明:依次输出 `1`、`1`、`1`;`GetProcAddress(...)` 返回的指针可用 `external fp` 包装。
|
||||
|
||||
### DLL 名的文档边界
|
||||
|
||||
<!-- tags: dll 名写在哪, 库名怎么给, 常量放路径 -->
|
||||
<!-- section-id: syntax-17-007 -->
|
||||
|
||||
类常量字符串:
|
||||
<!-- tags: dll 名写在哪, 库名怎么给, 常量放路径 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
@@ -164,12 +258,7 @@ public
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `1`
|
||||
- 说明类常量字符串(如 `kKernelDll`)可以用于 `external kKernelDll` 这种 DLL 名位置
|
||||
|
||||
不作为可写事实边界:
|
||||
结果说明:输出 `1`;类常量字符串可以用在 DLL 名位置。
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
@@ -177,19 +266,23 @@ end;
|
||||
function TickFromExpr(): int64; stdcall; external "kernel32"$"."$"dll" name "GetTickCount64";
|
||||
```
|
||||
|
||||
上面这种 DLL 名字符串拼接表达式不作为可写事实,会报 `dll filename const string not found after external`。本页只把字面量字符串和类常量字符串写成可靠规则。
|
||||
字符串拼接会报 `dll filename const string not found after external`。
|
||||
|
||||
### `makeInstance`
|
||||
### `MakeInstance`
|
||||
|
||||
<!-- tags: 回调函数, 把 TSL 函数给 C 用, 生成函数实例 -->
|
||||
<!-- section-id: syntax-17-008 -->
|
||||
|
||||
<!-- tags: 回调函数, 把 TSL 函数给 C 用, 生成函数实例, 函数指针释放, DeleteInstance, MakeInstance 生命周期 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
func_ptr := makeInstance(thisFunction(Add), "cdecl", 0);
|
||||
func_ptr := MakeInstance(thisFunction(Add), "cdecl", 0);
|
||||
wrapped_func := function(a: integer; b: integer): integer; external func_ptr;
|
||||
writeLn(func_ptr <> nil);
|
||||
writeLn(##wrapped_func(3, 4));
|
||||
wrapped_func := nil;
|
||||
writeLn(DeleteInstance(func_ptr));
|
||||
|
||||
function Add(a: integer; b: integer): integer;
|
||||
begin
|
||||
@@ -197,21 +290,19 @@ begin
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- `func_ptr <> nil` 输出 `1`
|
||||
- `##wrapped_func(3, 4)` 输出 `7`
|
||||
- 说明 `makeInstance(...)` 生成的函数指针可以再通过 `function(...); external fp;` 包装回 TSL 侧调用
|
||||
结果说明:依次输出 `1`、`7`、`1`。
|
||||
|
||||
### 线程模式最小正例
|
||||
|
||||
<!-- section-id: syntax-17-009 -->
|
||||
|
||||
<!-- tags: 开线程, 多线程, 并发执行, 后台跑 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
setGlobalCache("THREAD_TEST_KEY", 0);
|
||||
worker_ptr := makeInstance(thisFunction(Worker), "cdecl", 1);
|
||||
worker_ptr := MakeInstance(thisFunction(Worker), "cdecl", 1);
|
||||
thread_handle := CreateThread(nil, nil, worker_ptr, nil, 0, thread_id);
|
||||
writeLn(worker_ptr <> nil);
|
||||
writeLn(thread_handle <> nil);
|
||||
@@ -230,27 +321,19 @@ begin
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 依次输出 `1`、`1`、`1`、`1`
|
||||
- 说明 `makeInstance(..., "cdecl", 1)` 可以生成可用于 `CreateThread` 的回调指针
|
||||
- 也说明线程体里的 `setGlobalCache(...)` 可用于这个最小闭环
|
||||
结果说明:依次输出 `1`、`1`、`1`、`1`。
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
DLL 引入的最小默认骨架如下:
|
||||
<!-- section-id: syntax-17-010 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
writeLn(Tick64Alias() > 0);
|
||||
|
||||
function Tick64Alias(): int64; stdcall; external "kernel32.dll" name "GetTickCount64";
|
||||
```
|
||||
默认使用 `syntax-17-004` 的显式调用约定、`external` 和 `name` 骨架。
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-17-011 -->
|
||||
|
||||
- 把 `external` 的 DLL 名直接写成字符串拼接表达式。
|
||||
- 省略了外部函数的参数类型或返回类型。
|
||||
- 把 `makeInstance(...)` 生成的结果默认写成普通函数名直调,而不是先包装或用 `##f(...)`。
|
||||
- 直接把 Windows 线程示例当成跨平台事实。
|
||||
- 把 `MakeInstance(...)` 生成的结果默认写成普通函数名直调,而不是先包装或用 `##f(...)`。
|
||||
- 使用与目标平台不匹配的库名或调用约定。
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-18-001 -->
|
||||
|
||||
回答下面这些“写法已经会了,但运行起来为什么这样”的问题:
|
||||
|
||||
- `unit` 什么时候进入 `initialization`
|
||||
@@ -15,6 +17,8 @@
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-18-002 -->
|
||||
|
||||
- 完整 `unit` 形态可以包含 `interface`、`implementation`、`initialization`、`finalization`,并以 `end.` 结束。
|
||||
- `initialization` 在 `unit` 第一次被实际使用时触发,不是只因为顶层写了 `uses` 就立刻执行。
|
||||
- `finalization` 会在脚本结束前触发。
|
||||
@@ -33,8 +37,12 @@
|
||||
|
||||
## 示例与行为
|
||||
|
||||
<!-- section-id: syntax-18-003 -->
|
||||
|
||||
### `unit` 生命周期
|
||||
|
||||
<!-- section-id: syntax-18-004 -->
|
||||
|
||||
<!-- tags: 模块什么时候初始化, unit 状态, 加载时机, 只初始化一次 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -99,6 +107,8 @@ FINAL
|
||||
|
||||
### `unit` 成员的读取边界
|
||||
|
||||
<!-- section-id: syntax-18-005 -->
|
||||
|
||||
<!-- tags: 读模块常量, 访问 unit 成员, 限定名读取 -->
|
||||
|
||||
直接限定读取:
|
||||
@@ -242,6 +252,8 @@ DemoUnit.unit_counter := 13;
|
||||
|
||||
### `tslfilename()`
|
||||
|
||||
<!-- section-id: syntax-18-006 -->
|
||||
|
||||
<!-- tags: 当前脚本路径, 我在哪个文件, 取自身文件名 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -257,6 +269,8 @@ writeLn(tslfilename());
|
||||
|
||||
### `namespace` 与默认命名空间
|
||||
|
||||
<!-- section-id: syntax-18-007 -->
|
||||
|
||||
<!-- tags: 命名空间, 同名函数归属, 默认空间, 全局与命名空间冲突 -->
|
||||
|
||||
把默认命名空间、脚本覆盖、以及“全局函数与命名空间函数同名”的三组结论压成同一套最小实验:
|
||||
@@ -304,6 +318,8 @@ writeLn(Hello());
|
||||
|
||||
### `-LIBPATH`
|
||||
|
||||
<!-- section-id: syntax-18-008 -->
|
||||
|
||||
<!-- tags: 查找路径, 找不到文件, 搜索顺序, 命令行指定路径 -->
|
||||
|
||||
查找顺序:
|
||||
@@ -359,6 +375,8 @@ tsl .\main.tsl -LIBPATH "D:\libA\,D:\libB\"
|
||||
|
||||
### `syssettsllibpath()` 与 `sysgettsllibpath()`
|
||||
|
||||
<!-- section-id: syntax-18-009 -->
|
||||
|
||||
<!-- tags: 运行时改查找路径, 读取库路径 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -378,6 +396,8 @@ writeLn(call("FnB"));
|
||||
|
||||
### `tsl.conf` 的 `Libpath=`
|
||||
|
||||
<!-- section-id: syntax-18-010 -->
|
||||
|
||||
<!-- tags: 配置文件, 配路径, tsl.conf 怎么写 -->
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
@@ -468,6 +488,8 @@ writeLn(Hello());
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-18-011 -->
|
||||
|
||||
- 把 `DemoUnit.var_name := value` 当成可用的限定赋值。
|
||||
- 以为 `implementation` 里的常量和变量一定都不能从 `DemoUnit.Member` 读到。
|
||||
- 以为 `findFunction("DemoUnit")` 暴露的成员范围和 `DemoUnit.Member` 完全相同。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-19-001 -->
|
||||
|
||||
回答“怎样检查类信息、函数信息、对象运行时状态、弱引用创建和弱引用访问判定”。本页拥有反射与运行时状态查询;普通类编写、对象创建和方法调用不在本页收口,也不要因为本页存在反射能力就把普通调用改写成动态查找。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-19-002 -->
|
||||
|
||||
- 对象值可以用 `ifObj(...)` 做显式判定。
|
||||
- 普通本地类创建仍默认使用 `new ClassName()`;本页的 `createObject(cls)` 只用于运行时已经拿到类类型变量后的创建场景。
|
||||
- `class(Name)` 和 `findClass("Name")` 都可以拿到类类型。
|
||||
@@ -36,8 +40,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-19-003 -->
|
||||
|
||||
### 对象值与类类型
|
||||
|
||||
<!-- section-id: syntax-19-004 -->
|
||||
|
||||
<!-- tags: 判断是不是对象, 取类类型, 类型识别 -->
|
||||
|
||||
对象值的最小显式判定:
|
||||
@@ -122,6 +130,8 @@ end;
|
||||
|
||||
### 类信息与对象状态
|
||||
|
||||
<!-- section-id: syntax-19-005 -->
|
||||
|
||||
<!-- tags: 对象属于哪个类, 反射, 类名, 运行时看类信息 -->
|
||||
|
||||
`classInfo(1)` 返回类类型:
|
||||
@@ -225,6 +235,8 @@ end;
|
||||
|
||||
### 函数句柄与重载
|
||||
|
||||
<!-- section-id: syntax-19-006 -->
|
||||
|
||||
<!-- tags: 按名字找函数, 动态调用方法, 拿方法引用 -->
|
||||
|
||||
`findFunction(...)` 查找实例方法和类方法:
|
||||
@@ -315,6 +327,8 @@ end;
|
||||
|
||||
### 函数信息、对象枚举与生命周期
|
||||
|
||||
<!-- section-id: syntax-19-007 -->
|
||||
|
||||
<!-- tags: 列出所有对象, 引用计数, 对象什么时候释放, 函数元信息 -->
|
||||
|
||||
`functionInfo` 的文档字段:
|
||||
@@ -406,6 +420,8 @@ end;
|
||||
|
||||
### 弱引用与自动弱引用
|
||||
|
||||
<!-- section-id: syntax-19-008 -->
|
||||
|
||||
<!-- tags: 循环引用, 弱引用, 自动释放, 内存泄漏 -->
|
||||
|
||||
弱引用能力的条件编译判定:
|
||||
@@ -543,6 +559,8 @@ end;
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-19-009 -->
|
||||
|
||||
- 不要在运行时/反射页发明类声明、继承或构造语法;类基础事实见 [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(...)`。
|
||||
@@ -572,6 +590,8 @@ end;
|
||||
|
||||
### 段落式 `weakRef` / `autoRef` 的正确写法
|
||||
|
||||
<!-- section-id: syntax-19-010 -->
|
||||
|
||||
<!-- tags: 弱引用段落写法, weakRef 不带分号 -->
|
||||
|
||||
段落式 `weakRef` / `autoRef`(不带分号)像 `public` / `private` 一样切换后续成员的弱引用属性:
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-20-001 -->
|
||||
|
||||
回答“写普通 TSL/TSF 脚本时,哪些内置对象可以直接创建,最小可用接口是什么,哪些对象其实依赖特定运行上下文”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-20-002 -->
|
||||
|
||||
- `TStringList` 可以直接用 `new TStringList()` 创建。
|
||||
- `TStringList` 支持数字下标、字符串键下标、`Count` 和 `Add(...)`。
|
||||
- `THashedStringList` 可以直接创建,最小用法与 `TStringList` 接近,适合按名称快速取值。
|
||||
@@ -27,8 +31,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-20-003 -->
|
||||
|
||||
### `TStringList`
|
||||
|
||||
<!-- section-id: syntax-20-004 -->
|
||||
|
||||
<!-- tags: 字符串列表, 存一批字符串, 键值文本, 逗号文本 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -50,6 +58,8 @@ writeLn(list.Count);
|
||||
|
||||
### `THashedStringList`
|
||||
|
||||
<!-- section-id: syntax-20-005 -->
|
||||
|
||||
<!-- tags: 哈希列表, 快速查名字, 大量键查找 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -69,6 +79,8 @@ writeLn(list["B"]);
|
||||
|
||||
### `TStream` 家族的最小可靠入口:`TMemoryStream` 与 `TFileStream`
|
||||
|
||||
<!-- section-id: syntax-20-006 -->
|
||||
|
||||
<!-- tags: 内存流, 文件流, 读写文件, 二进制读写, 存到文件 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -126,6 +138,8 @@ writeLn(ifObj(base));
|
||||
|
||||
### `TCipher`
|
||||
|
||||
<!-- section-id: syntax-20-007 -->
|
||||
|
||||
<!-- tags: 加密解密, 对称加密, 密文 -->
|
||||
|
||||
无参创建反例:
|
||||
@@ -161,6 +175,8 @@ writeLn(cipher.Decrypt(enc));
|
||||
|
||||
### `TRsa`
|
||||
|
||||
<!-- section-id: syntax-20-008 -->
|
||||
|
||||
<!-- tags: 非对称加密, 公钥私钥, 签名, RSA -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -184,6 +200,8 @@ writeLn(length(rsa.PrivateKey) > 0);
|
||||
|
||||
### `TIniFile` 与 `TMemIniFile`
|
||||
|
||||
<!-- section-id: syntax-20-009 -->
|
||||
|
||||
<!-- tags: 配置文件读写, ini, 读配置项 -->
|
||||
|
||||
磁盘 INI 文件:
|
||||
@@ -220,6 +238,8 @@ writeLn(ini.ReadString("S", "K", ""));
|
||||
|
||||
### `MailMsg` 与 `MessagePart`
|
||||
|
||||
<!-- section-id: syntax-20-010 -->
|
||||
|
||||
<!-- tags: 发邮件, 邮件正文, 附件 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -249,6 +269,8 @@ writeLn(part.Body);
|
||||
|
||||
### `TWebRequest` / `TWebResponse` 的普通脚本边界
|
||||
|
||||
<!-- section-id: syntax-20-011 -->
|
||||
|
||||
<!-- tags: 网页请求, http 对象, web 环境限制 -->
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
@@ -266,6 +288,8 @@ resp := new TWebResponse();
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
<!-- section-id: syntax-20-012 -->
|
||||
|
||||
- `FTP` / `SMTP` / `POP3` 的连接、认证、上传下载、发送邮件和收取邮件流程。
|
||||
- `TWebRequest` / `TWebResponse` 的 Web 请求响应流程。
|
||||
- `TCookie` / `TCookieCollection`。
|
||||
@@ -277,6 +301,8 @@ resp := new TWebResponse();
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-20-013 -->
|
||||
|
||||
- 不要直接把 `new TStream()` 写成普通脚本里的可靠创建方式。
|
||||
- 不要无参创建 `TCipher`;最小可靠写法是 `new TCipher(2)` 后再设置 `Password`。
|
||||
- 不要把 `TWebRequest` / `TWebResponse` 写进普通脚本模板。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-21-001 -->
|
||||
|
||||
回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样进行矩阵乘除乘方,怎样转置矩阵,怎样拼接矩阵,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-21-002 -->
|
||||
|
||||
本页示例只说明矩阵语法中的调用位置、运算结构和源码外形。矩阵 API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。
|
||||
|
||||
- 矩阵初始化和基础函数的具体参数规格使用 `tsl-api-reference` skill 按名查询;本页只保留矩阵行为示例、返回形态边界和跨函数通用的广播 / `ErrDefine` / `ErrReplace` 机制。
|
||||
@@ -38,8 +42,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-21-003 -->
|
||||
|
||||
### 矩阵初始化
|
||||
|
||||
<!-- section-id: syntax-21-004 -->
|
||||
|
||||
<!-- tags: 建矩阵, 全零矩阵, 全一矩阵, 单位阵, 初始化二维 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -77,6 +85,8 @@ writeLn(mcols(zeros_2d));
|
||||
|
||||
### `->` 数列数组初始化
|
||||
|
||||
<!-- section-id: syntax-21-005 -->
|
||||
|
||||
<!-- tags: 生成序列, 等差数列, 从几到几, 连续数字 -->
|
||||
|
||||
默认步长为 `1`:
|
||||
@@ -119,6 +129,8 @@ seq_indexed := array(0, 1, array("A", "B", "C", "D", "E", "F")) -> 5;
|
||||
|
||||
### 矩阵一元倒数 / 逆 / 广义逆:`!A`
|
||||
|
||||
<!-- section-id: syntax-21-006 -->
|
||||
|
||||
<!-- tags: 求逆, 逆矩阵, 广义逆, 解方程 -->
|
||||
|
||||
方阵输入返回普通矩阵逆:
|
||||
@@ -186,6 +198,8 @@ writeLn(inverse_value[2][1]);
|
||||
|
||||
### `msize`、`mrows`、`mcols`
|
||||
|
||||
<!-- section-id: syntax-21-007 -->
|
||||
|
||||
<!-- tags: 矩阵几行几列, 尺寸, 维度大小, 行数列数 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -215,6 +229,8 @@ col_index := mcols(matrix_rows, 1);
|
||||
|
||||
### 矩阵遍历:`::` 与 `::=`
|
||||
|
||||
<!-- section-id: syntax-21-008 -->
|
||||
|
||||
<!-- tags: 遍历矩阵, 逐格处理, 二维循环, 批量赋值 -->
|
||||
|
||||
`::` 执行语句块:
|
||||
@@ -267,6 +283,8 @@ writeLn(matrix_value[1][1]);
|
||||
|
||||
### 深度遍历:`:.` 与 `:.=`
|
||||
|
||||
<!-- section-id: syntax-21-009 -->
|
||||
|
||||
<!-- tags: 遍历嵌套数组, 递归遍历, 最深层元素 -->
|
||||
|
||||
`:.` 会遍历到嵌套数组的最深节点:
|
||||
@@ -310,6 +328,8 @@ writeLn(values[2]);
|
||||
|
||||
### 子矩阵
|
||||
|
||||
<!-- section-id: syntax-21-010 -->
|
||||
|
||||
<!-- tags: 取一块, 切片, 按行列范围取, 局部矩阵 -->
|
||||
|
||||
按行列范围提取:
|
||||
@@ -406,6 +426,8 @@ writeLn(matrix_value[1][1]);
|
||||
|
||||
### `mfind` 与 `mfindSparse`
|
||||
|
||||
<!-- section-id: syntax-21-011 -->
|
||||
|
||||
<!-- tags: 在矩阵里查找, 找位置, 满足条件的下标, 稀疏查找 -->
|
||||
|
||||
一维数组无条件查找会返回一维下标数组:
|
||||
@@ -528,6 +550,8 @@ B
|
||||
|
||||
### 矩阵乘法、除法、左除、乘方:`:*`、`:/`、`:\`、`:^`
|
||||
|
||||
<!-- section-id: syntax-21-012 -->
|
||||
|
||||
<!-- tags: 矩阵相乘, 矩阵乘方, 左除, 区别于逐元素乘 -->
|
||||
|
||||
`:*` 是矩阵乘法(区别于逐元素乘 `*`):
|
||||
@@ -656,9 +680,11 @@ writeLn(a[0][0]);
|
||||
- `:*=`、`:/=`、`:\=`、`:^=` 分别是矩阵乘、除、左除、乘方的复合赋值形式
|
||||
- `a :*= b` 等价于 `a := a :* b`
|
||||
|
||||
### 基础函数的矩阵广播与异常处理参数
|
||||
### 基础函数的矩阵广播与无效输入替换参数
|
||||
|
||||
<!-- tags: 对整个矩阵取整, 函数作用于每个元素, 广播, 出错时给默认值 -->
|
||||
<!-- section-id: syntax-21-013 -->
|
||||
|
||||
<!-- tags: 对整个矩阵取整, 函数作用于每个元素, 广播, 出错时给默认值, 无效输入替换, errdefine, errreplace -->
|
||||
|
||||
多参数基础函数支持逐参数广播:
|
||||
|
||||
@@ -757,6 +783,8 @@ array(1,-999,-999,100)
|
||||
|
||||
### 矩阵转置:反引号 `` ` ``
|
||||
|
||||
<!-- section-id: syntax-21-014 -->
|
||||
|
||||
<!-- tags: 转置, 行列互换, 翻转矩阵 -->
|
||||
|
||||
单次转置交换行列:
|
||||
@@ -839,6 +867,8 @@ writeLn("行向量 (0,2):", row_vector[0][2]);
|
||||
|
||||
### 矩阵拼接:`union`、`&=`、`|`、`:|`
|
||||
|
||||
<!-- section-id: syntax-21-015 -->
|
||||
|
||||
<!-- tags: 拼接矩阵, 上下合并, 左右合并, 追加行 -->
|
||||
|
||||
`union` 按行拼接(一维或二维):
|
||||
@@ -935,6 +965,8 @@ bar 结果 (1,2):2
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-21-016 -->
|
||||
|
||||
需要矩阵构造时,优先从这个最短模板开始:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -945,6 +977,8 @@ matrix_value := zeros(2, 3);
|
||||
|
||||
## 决策边界和禁止项
|
||||
|
||||
<!-- section-id: syntax-21-017 -->
|
||||
|
||||
- 把 `eye(3)` 当成一维数组。
|
||||
- 把 `!A` 当成逻辑非表达式。
|
||||
- 把 `*` 当成矩阵乘法;矩阵乘法使用 `:*`。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-22-001 -->
|
||||
|
||||
回答“什么时候该用 `FMArray` 而不是普通 `array`,以及文档明确 `FMArray` 写法有哪些”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-22-002 -->
|
||||
|
||||
- `fmarray[...]` 可以直接构造 `FMArray` 常量。
|
||||
- `dataType(v)` 对 `FMArray` 返回 `27`。
|
||||
- `dataType(v, 1)` 可以读出 `FMArray` 单元格类型;本页文档类型包括 `0` 整型、`1` 浮点、`20` 64 位整型。
|
||||
@@ -26,8 +30,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-22-003 -->
|
||||
|
||||
### 常量构造与类型判断
|
||||
|
||||
<!-- section-id: syntax-22-004 -->
|
||||
|
||||
<!-- tags: 建 FMArray, 高性能数组, 字面量写法 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -74,6 +82,8 @@ writeLn(f2[0,0], ',', f2[0,1], ',', f2[1,0], ',', f2[1,1]);
|
||||
|
||||
### `mInit`、`mInitDiag`、`mRand`
|
||||
|
||||
<!-- section-id: syntax-22-005 -->
|
||||
|
||||
<!-- tags: 初始化 FMArray, 对角阵, 随机矩阵 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -105,6 +115,8 @@ writeLn(mcols(fr1));
|
||||
|
||||
### `arrayToFm`、`matrixToArray` 与单元格类型转换
|
||||
|
||||
<!-- section-id: syntax-22-006 -->
|
||||
|
||||
<!-- tags: 普通数组转 FMArray, 互转, 单元格类型 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -135,6 +147,8 @@ writeLn(a2[0][0], ',', a2[0][1], ',', a2[1][0], ',', a2[1][1]);
|
||||
|
||||
### 尺寸与重构
|
||||
|
||||
<!-- section-id: syntax-22-007 -->
|
||||
|
||||
<!-- tags: FMArray 尺寸, 改形状, reshape, 三维 -->
|
||||
|
||||
二维和三维尺寸:
|
||||
@@ -173,6 +187,8 @@ writeLn(r1[0], ',', r1[1], ',', r1[2], ',', r1[3], ',', r1[4], ',', r1[5]);
|
||||
|
||||
### 标量运算与基础算符
|
||||
|
||||
<!-- section-id: syntax-22-008 -->
|
||||
|
||||
<!-- tags: FMArray 加减乘除, 和数字运算 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -200,6 +216,8 @@ writeLn(s2[0], ',', s2[1], ',', s2[2]);
|
||||
|
||||
### `union2` 与左值类型
|
||||
|
||||
<!-- section-id: syntax-22-009 -->
|
||||
|
||||
<!-- tags: FMArray 合并, 左值类型决定结果 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -228,6 +246,8 @@ writeLn(u2[0], ',', u2[1], ',', u2[2], ',', u2[3], ',', u2[4], ',', u2[5]);
|
||||
|
||||
### 多维转置与维度交换
|
||||
|
||||
<!-- section-id: syntax-22-010 -->
|
||||
|
||||
<!-- tags: 三维转置, 换维度, 维度倒置 -->
|
||||
|
||||
三维 `FMArray` 上,反引号转置会把全部维度倒置:
|
||||
@@ -272,6 +292,8 @@ writeLn(t[0,0,0], ',', t[0,1,0], ',', t[0,2,0], ';', t[1,0,0], ',', t[1,1,0], ',
|
||||
|
||||
### 矩阵连接 / 矩阵并右方:`union`、`|`、`:|`
|
||||
|
||||
<!-- section-id: syntax-22-011 -->
|
||||
|
||||
<!-- tags: FMArray 拼接, 按列连接, 补零对齐 -->
|
||||
|
||||
`union` 会按行拼接,不做去重:
|
||||
@@ -366,6 +388,8 @@ writeLn(m2[2,0], ',', m2[2,1], ',', m2[2,2], ',', m2[2,3]);
|
||||
|
||||
### 排序
|
||||
|
||||
<!-- section-id: syntax-22-012 -->
|
||||
|
||||
<!-- tags: 排序, 从小到大, 按列排, sortArray -->
|
||||
|
||||
一维排序:
|
||||
@@ -398,6 +422,8 @@ writeLn(f1[0,0], ',', f1[0,1], ';', f1[1,0], ',', f1[1,1], ';', f1[2,0], ',', f1
|
||||
|
||||
### TS-SQL 对 `FMArray` 的支持
|
||||
|
||||
<!-- section-id: syntax-22-013 -->
|
||||
|
||||
<!-- tags: 对 FMArray 做查询, mselect -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -422,6 +448,8 @@ writeLn(mcols(q2));
|
||||
|
||||
### `insert` / `delete` / `update`
|
||||
|
||||
<!-- section-id: syntax-22-014 -->
|
||||
|
||||
<!-- tags: FMArray 增删改, 写回 -->
|
||||
|
||||
`insert`:
|
||||
@@ -482,6 +510,8 @@ writeLn(u[0,0], ',', u[0,1], ';', u[1,0], ',', u[1,1], ';', u[2,0], ',', u[2,1])
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
<!-- section-id: syntax-22-015 -->
|
||||
|
||||
- `mInitDiag` 更高维行为
|
||||
- `mRand` 的随机分布参数变体
|
||||
- `union` / `|` / `:|` 与普通 `array` 的更多混合边界
|
||||
@@ -492,6 +522,8 @@ writeLn(u[0,0], ',', u[0,1], ';', u[1,0], ',', u[1,1], ';', u[2,0], ',', u[2,1])
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-22-016 -->
|
||||
|
||||
需要 `FMArray` 常量时,优先从这个最短模板开始:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -502,6 +534,8 @@ f := fmarray[1, 2, 3];
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-22-017 -->
|
||||
|
||||
- 在一个 `FMArray` 常量里混用不同单元格类型。
|
||||
- 把 `FMArray` 当成支持字符串下标的 `array`。
|
||||
- 以为对 `FMArray` 做普通 `select` 后,结果还是 `dataType=27`。
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-23-001 -->
|
||||
|
||||
回答“当类不只是普通对象,而要直接参与 `obj + x`、`obj[index]`、`for v in obj`、`mrows(obj)` 这类语言级操作时,支持哪些文档明确写法”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-23-002 -->
|
||||
|
||||
- 对象二元算符重载的最小可靠形态是成员方法 `function operator + (other);` 这一类写法。
|
||||
- 比较算符可写成 `function operator < (other, is_left);`,用 `is_left` 区分对象在左边还是右边。
|
||||
- 对象 `[]` 读取有两种文档明确写法:`function operator[](index);` 和 `function operator[0](index, s1);`。
|
||||
@@ -21,8 +25,12 @@
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
<!-- section-id: syntax-23-003 -->
|
||||
|
||||
### 二元算符重载
|
||||
|
||||
<!-- section-id: syntax-23-004 -->
|
||||
|
||||
<!-- tags: 让对象支持加号, 自定义加减, 对象相加, 运算符重载 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -92,6 +100,8 @@ end;
|
||||
|
||||
### `[]` 重载:`operator[]` / `operator[1]`
|
||||
|
||||
<!-- section-id: syntax-23-005 -->
|
||||
|
||||
<!-- tags: 中括号取值, 方括号访问, 对象当数组用, 下标读写 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -128,6 +138,8 @@ end;
|
||||
|
||||
### `[]` 重载:`operator[0]` / `operator[1]`
|
||||
|
||||
<!-- section-id: syntax-23-006 -->
|
||||
|
||||
<!-- tags: 中括号读写分离, 取值和赋值签名 -->
|
||||
|
||||
读取签名也可以写成 `function operator[0](index, s1);`(与上一段 `operator[]` 等价的另一组写法):
|
||||
@@ -166,6 +178,8 @@ end;
|
||||
|
||||
### `for in` 重载
|
||||
|
||||
<!-- section-id: syntax-23-007 -->
|
||||
|
||||
<!-- tags: 让对象可遍历, 自定义迭代, 支持 for in -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -218,6 +232,8 @@ end;
|
||||
|
||||
### `mrows` / `mcols` / `msize` 重载(带参形态,支持下标列表)
|
||||
|
||||
<!-- section-id: syntax-23-008 -->
|
||||
|
||||
<!-- tags: 对象当矩阵, 自定义行列数, 带下标查询 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -276,6 +292,8 @@ end;
|
||||
|
||||
### `++` / `+=` / `--` / `-=` 自增自减重载
|
||||
|
||||
<!-- section-id: syntax-23-009 -->
|
||||
|
||||
<!-- tags: 自增自减, 加等于, 对象累加 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -366,6 +384,8 @@ end;
|
||||
|
||||
### 二进制函数重载:`operator funcName`
|
||||
|
||||
<!-- section-id: syntax-23-010 -->
|
||||
|
||||
<!-- tags: 重载具名函数, 让内置函数认识我的对象 -->
|
||||
|
||||
除了符号算符,`operator` 还能重载具名的全局二进制函数(如 `DateToStr`、`TryStrToInt` 等)。定义写成 `[class] function operator funcName(...)`:`class` 关键字可选,加上表示类方法,不加表示成员函数。
|
||||
@@ -456,6 +476,8 @@ end;
|
||||
|
||||
### `::` / `:.` 遍历重载与 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex`
|
||||
|
||||
<!-- section-id: syntax-23-011 -->
|
||||
|
||||
<!-- tags: 对象支持矩阵遍历, 自定义单元访问 -->
|
||||
|
||||
重载 `::`(二维遍历)或 `:.`(深度遍历)后,对象就能像矩阵一样被 `obj::begin ... end` 遍历。遍历体里用到的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex(n)` 也各自重载,返回当前单元的值、行下标、列下标、维度数和第 `n` 维下标。`operator ::(flag)` 的 `flag` 为 `0` 表示第一次循环、`1` 表示后续循环,返回 `0` 或 `nil` 结束遍历、返回非零数字继续:
|
||||
@@ -532,6 +554,8 @@ end;
|
||||
|
||||
### `mrows` / `mcols` / `msize` 重载(无参形态,只取数量且免 `::`)
|
||||
|
||||
<!-- section-id: syntax-23-012 -->
|
||||
|
||||
<!-- tags: 只取数量, 无参形态, 免遍历取行列数 -->
|
||||
|
||||
`msize` / `mrows` / `mcols` 这类关键字函数也能重载,形态同二进制函数重载 `[class] function operator KeyWord(...)`,但**关键字重载不需要 `::` 指定全局**:
|
||||
@@ -563,6 +587,8 @@ end;
|
||||
|
||||
## 本页不生成的范围
|
||||
|
||||
<!-- section-id: syntax-23-013 -->
|
||||
|
||||
- 多级 `[]` 下标重载
|
||||
- 右侧算术如 `value + obj`
|
||||
|
||||
@@ -570,6 +596,8 @@ end;
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-23-014 -->
|
||||
|
||||
- 不要从本页 `operator` 示例外推未写入文档的重载族。
|
||||
- 重载 `::` / `:.` 遍历时,不要漏掉配套的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 重载,否则遍历体会报 `override function not found`。
|
||||
- 不要把多级 `[]` 下标重载或 `value + obj` 这类右侧算术写成文档事实。
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# TSL 客户端远程调用
|
||||
|
||||
这一篇只处理 `RDo` / `RDo2` 调用客户端本地函数的语法外形、等待行为、系统参数后缀和超时后缀。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-24-001 -->
|
||||
|
||||
回答“怎样从平台调用客户端本地函数、`RDo` 与 `RDo2` 有什么区别、`With` 与 `TimeOut` 写在哪里,以及为什么不能写成 `RDo(...)` / `RDo2(...)`”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-24-002 -->
|
||||
|
||||
<!-- tags: 客户端远程调用 本地函数 不等待 等待返回 rdo rdo2 -->
|
||||
|
||||
- `RDo` 和 `RDo2` 是客户端远程调用关键字,不是普通函数。
|
||||
- 两者都写在被调用的本地函数之前;圆括号属于本地函数调用,不属于 `RDo` / `RDo2`。
|
||||
- `RDo` 只提交任务,不等待本地函数执行完成,也不取得函数返回值。
|
||||
- `RDo2` 等待本地函数执行完成,并把该函数的结果作为整个表达式的值。
|
||||
- 本地函数需要系统参数时,在调用后追加 `With SysParams`。
|
||||
- `RDo2` 默认超时为 300 秒;需要自定义时,在末尾追加 `TimeOut Seconds`。文档定义的后缀顺序是先 `With`、后 `TimeOut`。
|
||||
- `RDo2` 在客户机执行时需要用户权限许可;依赖客户端资源的函数不能在无 GUI 的命令行解释器中验证其交互结果。
|
||||
- 被调用函数的精确签名、参数写回、返回值及运行时 scope 必须使用 `tsl-api-reference` skill 单独查询;本页只拥有 `RDo` / `RDo2` 的语法形态。
|
||||
|
||||
## `RDo` / `RDo2` 语法与示例
|
||||
|
||||
<!-- section-id: syntax-24-003 -->
|
||||
|
||||
<!-- tags: RDo写法 RDo2写法 InputQuery 客户端输入 对话框 远程调用超时 With系统参数 -->
|
||||
|
||||
原文定义使用下面的元语法;方括号表示可选部分,不是需要写进 TSL 源码的字符:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
|
||||
```text
|
||||
RDo LocalFunctionName(P1; P2; …) [With SysParams];
|
||||
RDo2 LocalFunctionName(P1; P2; …) [With SysParams] [TimeOut Seconds]: Any;
|
||||
```
|
||||
|
||||
`RDo2` 调用客户端 `InputQuery` 的原文范例可整理为:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:需要平台客户端交互环境、用户权限许可,并要求目标环境提供 `InputQuery`;无 GUI 的命令行解释器不能验证弹窗结果。
|
||||
|
||||
```tsl
|
||||
value := "";
|
||||
if rdo2 InputQuery("Input", "Hint", value) then
|
||||
return value;
|
||||
else
|
||||
return "Canceled";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 用户确认时,`InputQuery` 返回真,输入内容写回 `value`,脚本返回该字符串。
|
||||
- 用户取消时,`InputQuery` 返回假,脚本返回 `Canceled`。
|
||||
- 这段代码证明的是前缀形态 `rdo2 InputQuery(...)`;`InputQuery` 的 API 事实仍需按目标 scope 单独查询。
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-24-004 -->
|
||||
|
||||
- 把关键字建模成 `RDo()` 或 `RDo2(...)` 普通函数。
|
||||
- 把被调用本地函数的参数误写成 `RDo2` 自身的参数表。
|
||||
- 声称 `RDo` 会返回客户端函数结果。
|
||||
- 忽略 `RDo2` 的客户端权限与交互环境要求。
|
||||
Reference in New Issue
Block a user