From c0c2ffb6eb62fc2248330a57fd116683194f9bae Mon Sep 17 00:00:00 2001 From: csh Date: Wed, 10 Jun 2026 15:25:42 +0800 Subject: [PATCH] :memo: docs(tsl): expand syntax operator and object coverage --- .../syntax/06_expressions_and_operators.md | 154 ++++++-- docs/tsl/syntax/07_control_flow.md | 38 +- .../tsl/syntax/10_runtime_context_and_with.md | 63 +++- ...6_lexical_structure_and_compile_options.md | 25 ++ docs/tsl/syntax/21_builtin_runtime_objects.md | 150 +++++++- docs/tsl/syntax/22_matrix_deep_dive.md | 335 +++++++++++++++++- 6 files changed, 715 insertions(+), 50 deletions(-) diff --git a/docs/tsl/syntax/06_expressions_and_operators.md b/docs/tsl/syntax/06_expressions_and_operators.md index 2f35d8b6..d6a61635 100644 --- a/docs/tsl/syntax/06_expressions_and_operators.md +++ b/docs/tsl/syntax/06_expressions_and_operators.md @@ -6,11 +6,11 @@ 是否含不可照写反例:是 遇到不确定时:先按本页表格和专题入口继续判断;[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。 +这一篇集中放语言级表达式与运算符。智能体写代码时,只使用本页和对应专题页已经明确的表达式事实,不要把其他语言或外部资料里的运算符习惯直接搬进 TSL。 ## 本篇职责 -回答“赋值、算术、比较、逻辑、位运算、集合/类型关系、条件求值、表达式对象、访问/调用和专题运算符入口在 TSL 里怎样写”。 +回答“赋值、算术、比较、逻辑、位运算、集合/类型关系、条件求值、表达式对象、访问/调用、点前缀运算符和专题运算符入口在 TSL 里怎样写”。 ## 智能体表达式/运算符判断流程 @@ -18,16 +18,17 @@ 2. 普通变量赋值只能用 `:=`,不要把 `=` 当赋值写法;`const name = value;` 是常量初始化规则,回看 [04_variables_and_constants.md](04_variables_and_constants.md)。 3. 在普通表达式里,比较才用 `=`,并且把比较表达式放在 `writeLn(...)`、条件或其他需要布尔值的位置。 4. 函数签名里的默认参数 `name = value` 不是比较表达式;默认参数规则回 [05_functions_and_calls.md](05_functions_and_calls.md)。 -5. 普通算术优先使用 `+`、`-`、`*`、`/`、`%`;整数除法和取模可用 `div`、`mod`;幂运算用 `^`;一元倒数用 `!x`。 -6. 逻辑表达式优先使用 `and`、`or`、`not`;`&&`、`||` 也已可用,但不要把 `!` 写成逻辑非。 -7. 已有变量做原地更新时,才使用 `+=`、`-=`、`*=`、`/=`、`%=`、`^=`、`.&=`、`.|=`、`.^=`、`a++;`、`a--;`、`++a;`、`--a;`。 -8. 条件求值优先用 `flag ? true_value : false_value`;需要 Pascal 风格时可用 `if condition then true_value else false_value` 的形态,但必须带 `else`。 -9. 需要延迟求值或动态表达式对象时,才使用 `@expr` 或 `&"..."`,并用本页明确的 `eval(...)` 形态求值。 -10. 空安全访问只照本页文档明确形态写:`a?.member`、`a?.[index]`、以及 `c?.a?.[1]`。不要外推成任意深度、任意组合都可写。 -11. 需要连续比较时,标量用 `:<` / `:>` 这组链式比较;数组逐元素比较用 `::<` / `::>` 这组矩阵链式比较。 -12. 命中集合、矩阵、对象重载、函数值调用、网格调用、运行时后缀或 TS-SQL 时,按“专题运算符入口表”跳到对应页面。 -13. `{$ifdef ...}` 只作为能力探测;编译选项边界回 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。 -14. 任务需要的运算符没有文档事实时,不要生成猜测写法;只能切到对应专题页、项目自身文档或项目专属规则,仍无结论时记录文档缺口。 +5. 普通算术优先使用 `+`、`-`、`*`、`/`、`%`;左除用 `\`;整数除法和取模可用 `div`、`mod`;幂运算用 `^`;对数用 `~`;一元倒数用 `!x`。 +6. 逻辑表达式优先使用 `and`、`or`、`not`;`&&`、`||`、`.&&`、`.||`、`.!!` 也已可用,但默认不作为主写法;不要把 `!` 写成逻辑非。 +7. 位运算使用点前缀或移位关键字:`.&`、`.|`、`.!`、`.^`、`shl`、`shr`、`rol`、`ror`;普通 `&`、`|`、`~` 不按位运算理解。 +8. 已有变量做原地更新时,才使用 `+=`、`-=`、`*=`、`/=`、`\=`、`%=`、`^=`、`~=`、`div=`、`.&=`、`.|=`、`.^=`、`.&&=`、`.||=`、`a++;`、`a--;`、`++a;`、`--a;`。 +9. 条件求值优先用 `flag ? true_value : false_value`;需要保留条件自身真值时可用 `value ?: fallback_value`;需要 Pascal 风格时可用 `if condition then true_value else false_value` 的形态,但必须带 `else`。 +10. 需要延迟求值或动态表达式对象时,才使用 `@expr` 或 `&"..."`,并用本页明确的 `eval(...)` 形态求值。 +11. 空安全访问只照本页文档明确形态写:`a?.member`、`a?.[index]`、以及 `c?.a?.[1]`。不要外推成任意深度、任意组合都可写。 +12. 需要连续比较时,标量用 `:<` / `:>` 这组链式比较;数组逐元素比较用 `::<` / `::>` 这组矩阵链式比较。 +13. 命中集合、矩阵、过滤、对象重载、函数值调用、网格调用、运行时后缀或 TS-SQL 时,按“专题运算符入口表”跳到对应页面。 +14. `{$ifdef ...}` 只作为能力探测;编译选项边界回 [16_lexical_structure_and_compile_options.md](16_lexical_structure_and_compile_options.md)。 +15. 任务需要的运算符没有文档事实时,不要生成猜测写法;只能切到对应专题页、项目自身文档或项目专属规则,仍无结论时记录文档缺口。 ## 核心规则 @@ -39,20 +40,24 @@ | 类别 | 运算符 / 形态 | 生成规则 | | --- | --- | --- | | 普通赋值 | `:=` | 变量赋值默认只用 `:=`。 | +| 多变量赋值 | `[a, b] := array(...)`、`[a, ] := array(...)` | 需要从数组按位置拆出多个值时使用;只有一个接收变量时保留末尾逗号。 | | 常量初始化 | `const name = value;` | 这是常量声明规则,不按普通赋值处理。 | | 函数默认参数 | `name = value` | 这是函数签名规则,不按比较表达式处理。 | -| 复合赋值 | `+=`、`-=`、`*=`、`/=`、`%=`、`^=`、`.&=`、`.|=`、`.^=` | 已有变量需要原地更新时使用。 | +| 算术复合赋值 | `+=`、`-=`、`*=`、`/=`、`\=`、`%=`、`^=`、`~=`、`div=` | 已有变量需要原地更新时使用;`div=` 是整除复合赋值。 | +| 点前缀复合赋值 | `.&=`、`.|=`、`.^=`、`.&&=`、`.||=` | 位运算或点前缀逻辑需要原地更新时使用。 | | 自增 / 自减 | `a++`、`a--`、`++a`、`--a` | 普通数字变量可直接用;对象重载语义回 [24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md)。 | -| 算术 | `+`、`-`、`*`、`/`、`%`、`div`、`mod`、`^` | 普通数值计算使用;`^` 是幂运算。 | +| 算术 | `+`、`-`、`*`、`/`、`\`、`%`、`div`、`mod`、`^`、`~` | 普通数值计算使用;`\` 是左除,`^` 是幂运算,`~` 是对数运算。 | | 一元正负号 | `+x`、`-x` | 可直接用于数值表达式。 | | 一元倒数 | `!x` | 整型、实型输入返回实型倒数;矩阵逆/广义逆回 [22_matrix_deep_dive.md](22_matrix_deep_dive.md)。 | | 字符串连接 | `+`、`$` | 字符串拼接两种写法都已写入文档;默认优先用 `+`。 | | 比较 | `=`、`<>`、`<`、`>`、`<=`、`>=` | `=` 只作比较,不作普通赋值。 | -| 逻辑 | `and`、`or`、`not`、`&&`、|| | 默认优先写 `and` / `or` / `not`;不要用 `!` 表示逻辑非。 | -| 位运算 | `.&`、`.|`、`.^` | 生成代码时写成无空格形态:`.&`、`.|`、`.^`。 | +| 点前缀比较 | `.=`、`.<>`、`.<`、`.>`、`.<=`、`.>=` | 标量比较可用;数组/矩阵样数据上的逐元素语义回 [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)` | 普通访问和调用可直接使用;类、对象、函数细节回对应专题。 | | 空安全访问 | `a?.member`、`a?.[index]`、`c?.a?.[1]` | 只按已写入文档形态生成。 | | 条件求值 | `flag ? true_value : false_value` | 普通条件表达式默认写法。 | +| 省略真值的条件求值 | `value ?: fallback_value` | 条件为真时返回条件自身的值;条件为假时返回后备值。 | | Pascal 风格条件表达式 | `if condition then true_value else false_value` | 必须带 `else`。 | | 表达式对象 | `@expr`、`&"..."` | 需要延迟求值或动态表达式对象时使用,并用 `eval(...)` 求值。 | | 逗号表达式 | `(exp1, exp2, ..., expN)` | 从左到右求值,返回最后一个表达式结果。 | @@ -69,9 +74,11 @@ | 调用点 `in` / `out`、变参 `...` | [05_functions_and_calls.md](05_functions_and_calls.md) | 这是参数传递 / 变参规则,不按普通表达式运算符处理。 | | `#Func() with array(...)` | [10_runtime_context_and_with.md](10_runtime_context_and_with.md) | 运行时环境参数调用只按运行时上下文页生成。 | | `#Func(args)`、`timeout N`、`dupvalue(...)` | [10_runtime_context_and_with.md](10_runtime_context_and_with.md) | 网格调用和运行时服务后缀只按运行时上下文页生成。 | -| `union2`、`intersect`、`minus`、`outersect` | [12_matrix_and_collections.md](12_matrix_and_collections.md) | 行集合并、交、差、对称差只按数组/集合页生成。 | -| `union`、|、`:|` | [23_fmarray.md](23_fmarray.md) | `FMArray` 行拼接和矩阵并右方(按列拼接)只按 `FMArray` 页生成。 | -| `->`、`!matrix` | [22_matrix_deep_dive.md](22_matrix_deep_dive.md) | 数列数组初始化、矩阵逆/广义逆只按矩阵深水页生成。 | +| `union2`、`intersect`、`minus`、`outersect`、`union2=`、`intersect=`、`minus=`、`outersect=` | [12_matrix_and_collections.md](12_matrix_and_collections.md) | 行集合并、交、差、对称差及其复合赋值只按数组/集合页生成。 | +| `filterIn(...)`、`filterNotIn(...)` | [13_resultset_and_filters.md](13_resultset_and_filters.md) | 结果集过滤只按过滤页生成,不当作去重型集合运算。 | +| `:*`、`:/`、`:\`、`:^`、`union`、|、`:|`、`|=`、`:|=`、`&=`、`:*=`、`:/=`、`:\=`、`:^=` | [22_matrix_deep_dive.md](22_matrix_deep_dive.md)、[23_fmarray.md](23_fmarray.md) | 矩阵乘除、左右拼接、下方拼接和矩阵复合赋值只按矩阵专题页生成。 | +| `->`、`!matrix`、`.?`、`.?:` | [22_matrix_deep_dive.md](22_matrix_deep_dive.md) | 数列数组初始化、矩阵逆/广义逆、矩阵条件求值只按矩阵深水页生成。 | +| `::`、`::=`、`:.`、`:.=` | [22_matrix_deep_dive.md](22_matrix_deep_dive.md)、[24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md) | 矩阵遍历/深度遍历和对象遍历重载只按专题页生成,不在普通表达式里自行套用。 | | 反引号转置 `` `value `` | [23_fmarray.md](23_fmarray.md) | `FMArray` 转置只按 `FMArray` 页生成。 | | `operator +`、`operator <`、`operator[]`、`operator[0]`、`operator[1]`、`operator for`、`operator mrows/mcols/msize`、`operator++`、`operator +=` | [24_object_overloads_and_iteration.md](24_object_overloads_and_iteration.md) | 对象运算符重载只按对象重载页生成。 | | `select` / `sselect` / `vselect` / `mselect`、`where`、`group by`、`order by`、`join` | [14_ts_sql.md](14_ts_sql.md) | TS-SQL 是查询语法,不按普通表达式拼接。 | @@ -82,25 +89,28 @@ - 普通变量赋值使用 `:=`;常量初始化不按普通赋值判断,见 [04_variables_and_constants.md](04_variables_and_constants.md)。 - `=` 在普通表达式里用于比较,不用于赋值。 - `const name = value;` 和函数签名默认参数 `name = value` 不按本页普通表达式比较判断。 -- 普通算术使用 `+`、`-`、`*`、`/`、`%`、`div`、`mod`、`^`。 +- 普通算术使用 `+`、`-`、`*`、`/`、`\`、`%`、`div`、`mod`、`^`、`~`。 - 需要数值倒数时用 `!x`;整型和实型输入都会得到实型结果。 - 普通逻辑优先使用 `and`、`or`、`not`;`&&`、`||` 已写入文档但不作为默认主写法。 - 普通条件求值默认用 `flag ? true_value : false_value`。 +- 需要把条件自身作为真值返回时,使用 `value ?: fallback_value`。 - 需要 Pascal 风格表达式时,才用 `if condition then true_value else false_value`,且必须带 `else`。 - 字符串拼接默认用 `+`;需要明确字符串连接时也可用 `$`。 - 字符串匹配用 `like` 时按正则理解,不按 SQL `%` 通配理解。 按需生成规则: -- 已有变量需要原地更新时,才用 `+=`、`-=`、`*=`、`/=`、`%=`、`^=`、`.&=`、`.|=`、`.^=`、`a++;`、`a--;`、`++a;`、`--a;`。 +- 已有变量需要原地更新时,才用 `+=`、`-=`、`*=`、`/=`、`\=`、`%=`、`^=`、`~=`、`div=`、`.&=`、`.|=`、`.^=`、`.&&=`、`.||=`、`a++;`、`a--;`、`++a;`、`--a;`。 - 需要矩阵逆/广义逆时才使用 `!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) 判断逐元素语义。 - 需要延迟求值或动态表达式对象时,才用 `@expr` 或 `&"..."`,并用 `eval(...)` 求值。 - 需要在一个表达式内按顺序执行多个子表达式时,才用逗号表达式 `(exp1, exp2, ..., expN)`。 - 空安全访问只按 `a?.member`、`a?.[index]` 和本页示例里的 `c?.a?.[1]` 生成,不外推任意深链。 - 否定形式只照 `not in`、`not like`、`not sqlin`、`not is` 这几种文档明确写法生成。 - 连续标量比较才用 `:>`、`:<`、`:<>`、`:==`、`:>=`、`:<=`。 - 数组逐元素链式比较才用 `::>`、`::<`、`::<>`、`::==`、`::>=`、`::<=`。 +- 混合两类以上运算符时,优先用括号明确分组,不依赖跨语言记忆里的优先级。 边界规则: @@ -136,6 +146,42 @@ writeLn(value); 10 ``` +省略真值的条件求值: + +代码块身份:可直接照写示例 + +```tsl +writeLn(2 ?: 9); +writeLn(0 ?: 9); +``` + +代码块身份:输出片段 + +```text +2 +9 +``` + +多变量赋值: + +代码块身份:可直接照写示例 + +```tsl +[a, b] := array(1, 2, 3); +writeLn(a); +writeLn(b); +[first_value, ] := array(4, 5); +writeLn(first_value); +``` + +代码块身份:输出片段 + +```text +1 +2 +4 +``` + 运算赋值: 代码块身份:可直接照写示例 @@ -161,10 +207,12 @@ writeLn(1 + 2); writeLn(5 - 2); writeLn(3 * 4); writeLn(8 / 2); +writeLn(3 \ 2); writeLn(9 % 4); writeLn(9 div 4); writeLn(9 mod 4); writeLn(2 ^ 3); +writeLn(8 ~ 2); writeLn(-3 + 5); writeLn(+3); ``` @@ -176,10 +224,12 @@ writeLn(+3); 3 12 4 +0.666666666666667 1 2 1 8 +3 2 3 ``` @@ -208,6 +258,30 @@ writeLn(2 <> 3); 1 ``` +点前缀比较: + +代码块身份:可直接照写示例 + +```tsl +writeLn(2 .= 2); +writeLn(2 .<> 3); +writeLn(1 .< 2); +writeLn(2 .> 1); +writeLn(2 .<= 2); +writeLn(2 .>= 2); +``` + +代码块身份:输出片段 + +```text +1 +1 +1 +1 +1 +1 +``` + 一元倒数: 代码块身份:可直接照写示例 @@ -245,8 +319,11 @@ writeLn(dataType(rb)); writeLn((1 < 2) and (2 < 3)); writeLn((1 > 2) or (2 < 3)); writeLn(not (1 > 2)); +writeLn(.!! 0); writeLn((1 < 2) && (2 < 3)); writeLn((1 > 2) || (2 < 3)); +writeLn(1 .&& 0); +writeLn(0 .|| 2); ``` 代码块身份:输出片段 @@ -257,6 +334,9 @@ writeLn((1 > 2) || (2 < 3)); 1 1 1 +1 +0 +1 ``` 位运算: @@ -267,6 +347,11 @@ writeLn((1 > 2) || (2 < 3)); writeLn(6 .& 3); writeLn(4 .| 1); writeLn(6 .^ 3); +writeLn(.! 1); +writeLn(1 shl 2); +writeLn(8 shr 1); +writeLn(1 rol 1); +writeLn(2 ror 1); ``` 代码块身份:输出片段 @@ -275,6 +360,11 @@ writeLn(6 .^ 3); 2 5 5 +-2 +4 +4 +2 +1 ``` 基础算术复合赋值: @@ -291,6 +381,15 @@ a /= 7; writeLn(a); a %= 5; writeLn(a); +b := 3; +b \= 2; +writeLn(b); +c := 8; +c ~= 2; +writeLn(c); +d := 7; +d div= 3; +writeLn(d); ``` 代码块身份:输出片段 @@ -300,6 +399,9 @@ writeLn(a); 28 4 4 +0.666666666666667 +3 +2 ``` 幂运算和位运算也可以使用复合赋值: @@ -319,6 +421,12 @@ writeLn(c); d := 6; d .^= 3; writeLn(d); +e := 0; +e .||= 2; +writeLn(e); +f := 1; +f .&&= 0; +writeLn(f); ``` 代码块身份:输出片段 @@ -328,6 +436,8 @@ writeLn(d); 2 5 5 +1 +0 ``` 字符串同样支持 `+=`: diff --git a/docs/tsl/syntax/07_control_flow.md b/docs/tsl/syntax/07_control_flow.md index cd8db1a0..086c44f7 100644 --- a/docs/tsl/syntax/07_control_flow.md +++ b/docs/tsl/syntax/07_control_flow.md @@ -17,7 +17,7 @@ 1. 先判断任务需要条件分支、循环、`case`、异常处理还是调试跳转。 2. `if` / `for` / `while` / `repeat` 优先照本页文档骨架写,不要套用其他 Pascal 方言。 3. 生成带 `else` 的条件分支时,默认用 `begin ... end` 包住 `then` 和 `else` 分支,让分支内部语句正常以分号结尾;控制流块的 `end` 默认不加分号,也不要在 `else` 前提前加分号。 -4. `case` 只按语句形态生成;不要把 `case` 放到赋值右侧生成表达式形态。 +4. `case` 可写成语句形态,也可写成赋值右侧的表达式形态;表达式形态的分支只能放单条表达式/单条语句,不写 `begin ... end` 语句段。 5. 没有文档事实时不要发明控制流写法。 ## 核心规则 @@ -27,7 +27,8 @@ - `for` 支持 `to`、`downto`、可选 `step`,以及 `for i, v in array` 遍历。 - `while` 和 `repeat ... until` 都可直接使用;`repeat` 至少会先执行一轮再判断结束条件。 - `break` 会跳出当前最近一层循环,`continue` 会跳过当前轮剩余语句。 -- `case ... of ... else ... end` 只作为语句形态生成;`end` 后默认不加分号。 +- `case ... of ... else ... end` 可作为语句形态生成;语句形态的 `end` 后默认不加分号。 +- `value := case ... of ... else ... end;` 可作为表达式形态生成;表达式形态赋值语句本身要用分号结尾。 - `case` 分支标签支持逗号并列和 `to` 区间。 - `try ... except ... end` 可以捕获 `raise` 产生的错误,并继续执行后续语句。 - `exceptObject.errInfo` 在 `except` 块中可读,能拿到当前错误信息。 @@ -274,6 +275,39 @@ end mid ``` +`case` 表达式形态: + +代码块身份:可直接照写示例 + +```tsl +a := 3; +label_value := case a of +1, 2: + "small"; +3, 4: + "mid"; +else + "other"; +end; +writeLn(label_value); +``` + +输出说明: + +- 输出 `mid` + +代码块身份:输出片段 + +```text +mid +``` + +说明: + +- 表达式形态可以放在赋值右侧。 +- 表达式形态的每个分支只写单条表达式/单条语句,不写 `begin ... end` 语句段。 +- 赋值语句整体以 `end;` 收尾。 + ### `try ... except` 代码块身份:可直接照写示例 diff --git a/docs/tsl/syntax/10_runtime_context_and_with.md b/docs/tsl/syntax/10_runtime_context_and_with.md index cd508310..520965c8 100644 --- a/docs/tsl/syntax/10_runtime_context_and_with.md +++ b/docs/tsl/syntax/10_runtime_context_and_with.md @@ -6,15 +6,15 @@ 是否含不可照写反例:是 遇到不确定时:先按本页候选页继续判断;[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)、[../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) -这一篇只处理运行时环境参数、`with` 后缀、`#` 网格调用、`timeout` 后缀、`dupvalue(...)` 和全局缓存,不处理任何金融业务语义。 +这一篇只处理运行时环境参数、块环境 `with` 语句、`with` 后缀、`#` 网格调用、`timeout` 后缀、`dupvalue(...)` 和全局缓存,不处理任何金融业务语义。 ## 本篇职责 -回答“`setSysParam` / `getSysParam` 怎样用、`sysParams[...]` 是什么、`#Func() with array(...)` 这种后缀环境调用怎样写,网格调用怎样取回结果,以及全局缓存最小读写规则是什么”。 +回答“`setSysParam` / `getSysParam` 怎样用、`sysParams[...]` 是什么、块环境 `with *, values do` / `with **, values do` 怎样写、`#Func() with array(...)` 这种后缀环境调用怎样写,网格调用怎样取回结果,以及全局缓存最小读写规则是什么”。 ## 智能体运行时上下文判断流程 -1. 先判断要操作系统参数、运行时上下文对象、`with` 后缀调用、`#` 网格调用、`timeout` 后缀,还是全局缓存函数。 +1. 先判断要操作系统参数、运行时上下文对象、块环境 `with` 语句、`with` 后缀调用、`#` 网格调用、`timeout` 后缀,还是全局缓存函数。 2. 系统参数优先用本页明确的 `setSysParam` / `getSysParam` / `sysParams[...]` 形态。 3. `#Func() with array(...)` 只作为运行时环境调用写法,不要套到普通本地函数。 4. 网格调用返回的不是最终值;需要最终结果时继续写 `dupvalue(...)`。 @@ -29,7 +29,10 @@ - TSL 有一组运行时系统参数;本页只写通用语法形态。 - `setSysParam(key, value)` 和 `getSysParam(key)` 可以直接用字符串键。 - `sysParams[key]` 可以直接读写这些运行时参数。 -- 本页明确的 `with` 形式,是写在函数文件调用后面:`#Func() with array(...)`。 +- 块环境语句可写成 `with *, sys_param_values do begin ... end` 或 `with **, sys_param_values do begin ... end`。 +- `with *` 会把提供的系统参数合并进当前运行时上下文;不要依赖它在块结束后自动恢复外层值。 +- `with **` 会用提供的系统参数建立隔离块环境;块结束后恢复外层系统参数。 +- 后缀 `with` 形式写在函数文件调用后面:`#Func() with array(...)`。 - `with array(...)` 只在该次调用里临时覆盖对应键,调用结束后会恢复外部原值。 - 如果外部原值本来不存在,`with array(...)` 调用结束后,对应键会恢复成 `nil`。 - 不要把上面的后缀 `with` 直接泛化成“任何本地函数调用后面都能接 `with array(...)`”;本地函数后缀 `with` 属于反例。 @@ -85,6 +88,55 @@ writeLn(getSysParam("a")); - 依次输出 `321`、`QQ`、`321` - 说明 `sysParams[...]` 和 `getSysParam(...)` / `setSysParam(...)` 指向的是同一组运行时环境参数 +### 块环境 `with *` + +代码块身份:可直接照写示例 + +```tsl +setSysParam("a", 1); +sys_param_values := array("a": 2, "b": 3); + +with *, sys_param_values do +begin + writeLn(getSysParam("a")); + writeLn(getSysParam("b")); +end + +writeLn(getSysParam("a")); +writeLn(getSysParam("b")); +``` + +结果说明: + +- 块内输出 `2`、`3` +- 块后输出 `2`、`3` +- 说明 `with *` 会把传入键合并进当前系统参数上下文;不要把它当成自动恢复外层值的隔离块 + +### 块环境 `with **` + +代码块身份:可直接照写示例 + +```tsl +setSysParam("a", 1); +setSysParam("b", 9); +sys_param_values := array("b": 4); + +with **, sys_param_values do +begin + writeLn(getSysParam("a") = nil); + writeLn(getSysParam("b")); +end + +writeLn(getSysParam("a")); +writeLn(getSysParam("b")); +``` + +结果说明: + +- 块内输出 `1`、`4` +- 块后输出 `1`、`9` +- 说明 `with **` 不继承未传入的外层系统参数,并且块结束后恢复外层系统参数 + 沿用同一个 `TestDo.tsf`,看 `with array(...)` 的覆盖边界: 代码块身份:配置片段 / 概念骨架 @@ -259,6 +311,8 @@ writeLn(q[0][0], ',', q[0][1], ';', q[1][0], ',', q[1][1], ';', q[2][0], ',', q[ - 网格超时触发错误时的完整边界 - `getGlobalCacheInfo`、`listGlobalCache`、`listGlobalCacheRemoved` - 初始化 TSL、监控线程、回收策略与兼容旧系统方案 +- `with [S => ..., T => ...] do` 块语句 +- `{$include ...}` 包含文件指令 这些名称只作为边界提示,不作为本页可生成模板。 @@ -292,6 +346,7 @@ end; - 把系统参数页直接写成金融函数页。 - 把 `#Func() with array(...)` 误判成也能直接套在本地函数 `Demo()` 后面。 +- 把 `with *` 误判成会自动恢复外层系统参数。 - 以为 `with array(...)` 改的是全局永久值,不会恢复外层原环境。 - 把网格句柄直接当最终值用,而不做 `dupvalue(...)`。 - 以为从全局缓存取出的值,本地写入后仍然保持缓存身份。 diff --git a/docs/tsl/syntax/16_lexical_structure_and_compile_options.md b/docs/tsl/syntax/16_lexical_structure_and_compile_options.md index 5981e617..0aeceaf8 100644 --- a/docs/tsl/syntax/16_lexical_structure_and_compile_options.md +++ b/docs/tsl/syntax/16_lexical_structure_and_compile_options.md @@ -28,9 +28,34 @@ - 条件编译只编译命中的分支;未命中的分支不参与脚本编译。 - `{$explicit+}` 开启后,后续变量必须先用 `var` 声明;`{$explicit-}` 可以在同一源文件里重新关闭这个要求。 - `{$varByRef-}` 与 `{$varByRef+}` 会切换“未修饰形参”的默认传递方式,细节见 [05_functions_and_calls.md](05_functions_and_calls.md)。 +- 保留字/关键字大小写无关,不要拿来当普通变量、函数或类名;例如 `params` 是函数参数访问关键字,不适合作为普通变量名。 - `{$i}` / `{$include}` 不作为本页可生成的默认能力。 - `{$dependency ...}` 这类编辑器辅助编译选项不作为本页正文事实。 +## 保留字/关键字速查 + +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)。 | +| 参数访问 | `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)。 | +| 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)。 | +| 客户端远程调用与权限 | `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 聚合与上下文 | `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/21_builtin_runtime_objects.md b/docs/tsl/syntax/21_builtin_runtime_objects.md index 97ad5058..3936bfd3 100644 --- a/docs/tsl/syntax/21_builtin_runtime_objects.md +++ b/docs/tsl/syntax/21_builtin_runtime_objects.md @@ -24,13 +24,19 @@ - `TStringList` 可以直接用 `new TStringList()` 创建。 - `TStringList` 支持数字下标、字符串键下标、`Count` 和 `Add(...)`。 +- `THashedStringList` 可以直接创建,最小用法与 `TStringList` 接近,适合按名称快速取值。 - 流对象应先按 `TStream` 家族理解;普通脚本里的最小可靠入口是 `TMemoryStream` 这种具体类型。 - 直接 `new TStream()` 会失败,错误信息包含 `function:TStream compile error or not found`。 - `TMemoryStream` 支持 `Write(...)`、`Read(...)`、`Position`、`Size`。 +- `TFileStream` 可以带目录别名、文件名和打开模式创建,并支持 `TStream` 的读写位置模型。 - `TCipher` 不是“无参即可创建”的对象;`new TCipher()` 会失败。 - `TCipher` 的最小写法是 `new TCipher(2)`,然后设置 `Password` 再做 `Encrypt(...)` / `Decrypt(...)`。 +- `TRsa` 可以直接创建;先 `GenerateKey(...)`,再读取 `PublicKey` / `PrivateKey` 或执行公私钥加解密。 +- `TIniFile` 适合读写磁盘 INI 文件;`TMemIniFile` 适合内存 INI 数据。 +- `MailMsg` 和 `MessagePart` 可以直接创建并设置消息字段,但发送邮件流程属于 SMTP 对象/外部服务边界。 - `TWebRequest` 和 `TWebResponse` 在普通脚本里不作为可直接 `new` 的对象。 - 因此,Web 请求 / 响应对象不要直接写进普通脚本模板;它们应视为特定运行上下文对象。 +- 本页不承担对象完整方法表;只收能让 agent 稳定生成代码的最小入口。 - 本页失败创建示例只用于边界判断,不作为业务代码模板复制。 ## 可直接照写示例 @@ -54,15 +60,23 @@ writeLn(obj.Count); - 依次输出 `B=bbb`、`bbb`、`3`、`4` - 说明既可以按数字下标取整行,也可以按键名取 `Name=Value` 里的值 -代码块身份:输出片段 +### `THashedStringList` -```text -B=bbb -bbb -3 -4 +代码块身份:可直接照写示例 + +```tsl +obj := new THashedStringList(); +obj.Add("A=aaa"); +obj.Add("B=bbb"); +writeLn(obj.Count); +writeLn(obj["B"]); ``` +结果说明: + +- 依次输出 `2`、`bbb` +- 说明 `THashedStringList` 可按 `Name=Value` 的名称键读取值 + ### `TStream` 家族的最小可靠入口:`TMemoryStream` 代码块身份:可直接照写示例 @@ -83,6 +97,27 @@ writeLn(mem.Size); - 依次输出 `ABC`、`3` - 说明普通脚本里应优先使用 `TMemoryStream` 这类具体流对象。 +`TFileStream` 可直接打开文件并沿用 `TStream` 的 `Write(...)` / `Read(...)` / `Position` / `Size` 模型: + +代码块身份:可直接照写示例 + +```tsl +file_name := "object_probe.txt"; +stream := new TFileStream("", file_name, 65535); +buffer := "ABC"; +stream.Write(buffer, 3); +writeLn(stream.Size); +stream.Position := 0; +outbuf := "xxx"; +stream.Read(outbuf, 3); +writeLn(outbuf); +``` + +结果说明: + +- 依次输出 `3`、`ABC` +- `TFileStream("", file_name, 65535)` 可作为最小读写文件流骨架 + 裸 `TStream` 创建反例: 代码块身份:反例 / 不可照写 @@ -130,6 +165,88 @@ writeLn(cipher.Decrypt(enc)); - 依次输出 `1`、`abc` - 说明 `TCipher` 必须按“带模式参数创建”来写,随后可稳定走 `Password -> Encrypt -> Decrypt` +### `TRsa` + +代码块身份:可直接照写示例 + +```tsl +rsa := new TRsa(); +rsa.GenerateKey(1024); +plain := "abc"; +enc := rsa.PubEncrypt(plain); +writeLn(rsa.PriDecrypt(enc)); +enc2 := rsa.PriEncrypt(plain); +writeLn(rsa.PubDecrypt(enc2)); +writeLn(length(rsa.PublicKey) > 0); +writeLn(length(rsa.PrivateKey) > 0); +``` + +结果说明: + +- 依次输出 `abc`、`abc`、`1`、`1` +- 说明 `TRsa` 先生成密钥,再用公钥加密 / 私钥解密,或私钥加密 / 公钥解密 + +### `TIniFile` 与 `TMemIniFile` + +磁盘 INI 文件: + +代码块身份:可直接照写示例 + +```tsl +ini := new TIniFile("", "object_probe.ini"); +ini.WriteString("S", "K", "V"); +writeLn(ini.ReadString("S", "K", "")); +ini.WriteInteger("S", "N", 123); +writeLn(ini.ReadInteger("S", "N", 0)); +``` + +结果说明: + +- 依次输出 `V`、`123` +- 说明 `TIniFile` 适合直接读写磁盘 INI 文件 + +内存 INI 数据: + +代码块身份:可直接照写示例 + +```tsl +ini := new TMemIniFile(); +ini.WriteString("S", "K", "V"); +writeLn(ini.ReadString("S", "K", "")); +``` + +结果说明: + +- 输出 `V` +- 说明 `TMemIniFile` 可不依赖磁盘文件,直接读写内存 INI 数据 + +### `MailMsg` 与 `MessagePart` + +代码块身份:可直接照写示例 + +```tsl +msg := new MailMsg(); +msg.Subject := "Hello"; +msg.Body := "BodyText"; +msg.Sender := "sender@example.com"; +msg.Recipients := "to@example.com"; +writeLn(msg.Subject); +writeLn(msg.Body); +writeLn(length(msg.AsString) > 0); + +part := new MessagePart(); +part.ContentType := "text/plain"; +part.Body := "PartBody"; +writeLn(part.ContentType); +writeLn(part.Body); +``` + +结果说明: + +- 依次输出 `Hello`、`BodyText`、`1`、`text/plain`、`PartBody` +- 说明 `MailMsg` / `MessagePart` 可作为消息数据对象使用 +- 发送邮件应回到 SMTP 对象和外部服务配置,不在本页生成连接/认证/发送模板 + ### `TWebRequest` / `TWebResponse` 的普通脚本边界 代码块身份:反例 / 不可照写 @@ -145,24 +262,23 @@ resp := new TWebResponse(); - `new TWebResponse()` 会报 `function:TWebResponse compile error or not found`。 - 普通脚本里,Web 请求 / 响应对象不能直接按普通 `new ...()` 脚本对象来写。 -## 本页不生成的对象 +## 本页不生成的范围 -- `TFileStream` -- `TIniFile` -- `TMemIniFile` -- `THashedStringList` -- `TRSA` -- `FTP` / `SMTP` / `POP3` -- `MailMsg` / `MessagePart` -- `TCookie` / `TCookieCollection` -- `TSessionMan` / `TSession` +- `FTP` / `SMTP` / `POP3` 的连接、认证、上传下载、发送邮件和收取邮件流程。 +- `TWebRequest` / `TWebResponse` 的 Web 请求响应流程。 +- `TCookie` / `TCookieCollection`。 +- `THandleStream`。 +- `TRegistryIniFile`。 +- `TSessionMan` / `TSession`。 -这些对象不作为本页可生成事实;不要因为未写入文档资料里出现过就默认使用。 +这些对象不作为本页可生成业务流程;不要因为源资料里出现过就默认生成连接、认证、网络访问、Web 请求响应或会话管理代码。 ## 禁止项 - 不要直接把 `new TStream()` 写成普通脚本里的可靠创建方式。 - 不要无参创建 `TCipher`;最小可靠写法是 `new TCipher(2)` 后再设置 `Password`。 - 不要把 `TWebRequest` / `TWebResponse` 写进普通脚本模板。 +- 不要把 `MailMsg.AddText(...)` 当成默认消息正文写法;普通正文优先设置 `Body`。 +- 不要在缺少主机、账号、密码、端口和协议要求时生成 `FTP` / `SMTP` / `POP3` 连接流程。 - 不要把未写入文档资料里的内置对象,当成语法事实。 - 不要把本页反例块里的失败创建代码包进 `try/except` 后当成业务模板。 diff --git a/docs/tsl/syntax/22_matrix_deep_dive.md b/docs/tsl/syntax/22_matrix_deep_dive.md index 0c789d34..dbbf8f8a 100644 --- a/docs/tsl/syntax/22_matrix_deep_dive.md +++ b/docs/tsl/syntax/22_matrix_deep_dive.md @@ -6,19 +6,23 @@ 是否含不可照写反例:是 遇到不确定时:先按本页候选页继续判断;[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) -这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆,以及怎样读取矩阵的行列大小和索引。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`13` 只讲数组与矩阵样数据,这一篇讲矩阵专用构造、运算与大小接口。 +这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`12` 讲普通数组与集合关系,这一篇讲矩阵专用构造、遍历、子矩阵和矩阵查找接口。 ## 本篇职责 -回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,以及怎样拿到矩阵的行数、列数、行索引和列索引”。 +回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。 ## 智能体矩阵深水判断流程 -1. 先判断要写矩阵初始化、数列构造、矩阵逆/广义逆,还是矩阵尺寸与索引读取。 +1. 先判断要写矩阵初始化、数列构造、矩阵逆/广义逆、矩阵尺寸与索引读取、矩阵遍历、子矩阵,还是 `mfind` 查找/替换。 2. 基础数组和矩阵样比较先回看 `12_matrix_and_collections.md`。 3. `mrows` / `mcols` / `msize` 等函数只照文档返回形态写。 -4. 不要把列索引数组误当成单个数字。 -5. 没有对应代码块时不要发明矩阵深水写法。 +4. 需要逐单元执行语句块时用 `matrix::begin ... end`;需要把表达式结果写回每个单元时用 `matrix ::= expression`。 +5. 需要遍历到嵌套数组最深层时用 `matrix:.begin ... end` 或 `matrix:.= expression`。 +6. 子矩阵范围使用 `row_start:row_end`、`:`、下标数组和列范围组合;不要把字符串键当作子矩阵范围序号。 +7. `mfind(...)` 用于把符合条件的单元格转换成下标列表,或同时返回原值/替换原值。 +8. 不要把列索引数组误当成单个数字。 +9. 没有对应代码块时不要发明矩阵深水写法。 ## 核心规则 @@ -35,6 +39,19 @@ - `msize(matrix_value, 1)` 返回行索引数组和列索引数组。 - `mrows(matrix_value)` / `mcols(matrix_value)` 默认返回数量;第二个参数写成 `1` 时返回索引数组。 - `mrows(matrix_value, 1)` / `mcols(matrix_value, 1)` 的返回值可用于索引匹配;不要把它们当成数量。 +- `matrix::begin ... end` 是矩阵遍历语句块,最多按二维遍历;语句块里可用 `mcell`、`mrow`、`mcol`。 +- `matrix ::= expression` 是矩阵遍历赋值,把表达式结果逐单元写回原矩阵;它不是语句块。 +- `matrix:.begin ... end` 是深度遍历语句块;对嵌套数组会遍历到最深节点。 +- `matrix:.= expression` 是深度遍历赋值;需要对不规则嵌套数组逐叶子节点写回时使用。 +- 遍历时需要维度信息可用 `mIndexCount`;需要第 `n` 维下标可用 `mIndex(n)`。 +- 子矩阵提取可以写 `matrix[row_start:row_end, col_start:col_end]`、`matrix[:, col_range]`、`matrix[row_index_array, col_index_array]`。 +- 子矩阵赋值可以写成单个标量,也可以写成同结构矩阵;赋值矩阵应和目标子矩阵形状匹配。 +- 子矩阵也可以接 `::=` 做逐单元赋值。 +- `mfind(matrix)` 返回真值单元格下标;一维数组的无条件 `mfind` 返回一维下标数组。 +- `mfind(matrix, condition)` 返回符合条件的下标行;二维矩阵下每行形如 `array(row_index, col_index)`。 +- `mfind(matrix, condition, 1)` 在每个下标行末尾追加原单元值。 +- `mfind(matrix, condition, ret_value, replacement)` 会把符合条件的单元格替换成 `replacement`,并返回替换前的匹配信息。 +- `mfindSparse(matrix, condition)` 用于嵌套数组或稀疏结构,返回包含完整深层路径的下标行。 ## 可直接照写示例 @@ -205,6 +222,311 @@ col_index := mcols(matrix_rows, 1); - `mcols(matrix_rows)` 返回 `2` - `mcols(matrix_rows, 1)` 返回 `array("A", "B")` +### 矩阵遍历:`::` 与 `::=` + +`::` 执行语句块: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 2, 3), (4, 5, 6)); +sum_value := 0; +matrix_value::begin + sum_value += mcell; +end +writeLn(sum_value); +``` + +代码块身份:输出片段 + +```text +21 +``` + +`::=` 把表达式结果逐单元写回: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 2), (3, 4)); +matrix_value ::= mrow * 10 + mcol; +writeLn(matrix_value[0][0]); +writeLn(matrix_value[0][1]); +writeLn(matrix_value[1][0]); +writeLn(matrix_value[1][1]); +``` + +代码块身份:输出片段 + +```text +0 +1 +10 +11 +``` + +说明: + +- `mcell` 是当前单元格值。 +- `mrow` 是当前行下标。 +- `mcol` 是当前列下标。 +- `::=` 右侧写表达式,不写 `begin ... end` 语句块。 + +### 深度遍历:`:.` 与 `:.=` + +`:.` 会遍历到嵌套数组的最深节点: + +代码块身份:可直接照写示例 + +```tsl +nested_value := array(10, 12, ("A": array(30), "B": 22), ("A": array(31, 32), "B": 23)); +deep_count := 0; +nested_value:.begin + deep_count += 1; +end +writeLn(deep_count); +``` + +代码块身份:输出片段 + +```text +7 +``` + +`:.=` 会把表达式结果写回最深节点: + +代码块身份:可直接照写示例 + +```tsl +values := array(-1, 2, -3); +values:.= abs(mcell); +writeLn(values[0]); +writeLn(values[1]); +writeLn(values[2]); +``` + +代码块身份:输出片段 + +```text +1 +2 +3 +``` + +### 子矩阵 + +按行列范围提取: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 2, 3), (4, 5, 6), (7, 8, 9)); +sub_value := matrix_value[1:2, 0:1]; +writeLn(mrows(sub_value)); +writeLn(mcols(sub_value)); +writeLn(sub_value[0][0]); +writeLn(sub_value[0][1]); +writeLn(sub_value[1][0]); +writeLn(sub_value[1][1]); +``` + +代码块身份:输出片段 + +```text +2 +2 +4 +5 +7 +8 +``` + +按下标数组提取: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 2, 3), (4, 5, 6), (7, 8, 9)); +sub_value := matrix_value[array(0, 2), array(1, 2)]; +writeLn(sub_value[0][0]); +writeLn(sub_value[0][1]); +writeLn(sub_value[1][0]); +writeLn(sub_value[1][1]); +``` + +代码块身份:输出片段 + +```text +2 +3 +8 +9 +``` + +子矩阵赋值: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 2, 3), (4, 5, 6), (7, 8, 9)); +matrix_value[0:1, 1:2] := array((10, 11), (12, 13)); +writeLn(matrix_value[0][1]); +writeLn(matrix_value[0][2]); +writeLn(matrix_value[1][1]); +writeLn(matrix_value[1][2]); +``` + +代码块身份:输出片段 + +```text +10 +11 +12 +13 +``` + +子矩阵逐单元赋值: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 2), (3, 4)); +matrix_value[0:1, 0:1] ::= mrow * 10 + mcol; +writeLn(matrix_value[0][0]); +writeLn(matrix_value[0][1]); +writeLn(matrix_value[1][0]); +writeLn(matrix_value[1][1]); +``` + +代码块身份:输出片段 + +```text +0 +1 +10 +11 +``` + +### `mfind` 与 `mfindSparse` + +一维数组无条件查找会返回一维下标数组: + +代码块身份:可直接照写示例 + +```tsl +values := array(1, 0, 2, 0, 3); +indexes := mfind(values); +writeLn(length(indexes)); +writeLn(indexes[0]); +writeLn(indexes[1]); +writeLn(indexes[2]); +``` + +代码块身份:输出片段 + +```text +3 +0 +2 +4 +``` + +二维矩阵按条件查找: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 0), (2, 3)); +indexes := mfind(matrix_value, mcell >= 2); +writeLn(length(indexes)); +writeLn(indexes[0][0]); +writeLn(indexes[0][1]); +writeLn(indexes[1][0]); +writeLn(indexes[1][1]); +``` + +代码块身份:输出片段 + +```text +2 +1 +0 +1 +1 +``` + +第三个参数写成 `1` 时,每行末尾追加原单元值: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 0), (2, 3)); +matches := mfind(matrix_value, mcell >= 2, 1); +writeLn(matches[0][0]); +writeLn(matches[0][1]); +writeLn(matches[0][2]); +writeLn(matches[1][0]); +writeLn(matches[1][1]); +writeLn(matches[1][2]); +``` + +代码块身份:输出片段 + +```text +1 +0 +2 +1 +1 +3 +``` + +第四个参数用于替换符合条件的单元格: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 0), (2, 3)); +matches := mfind(matrix_value, mcell >= 2, 1, 100); +writeLn(matches[0][2]); +writeLn(matches[1][2]); +writeLn(matrix_value[1][0]); +writeLn(matrix_value[1][1]); +``` + +代码块身份:输出片段 + +```text +2 +3 +100 +100 +``` + +`mfindSparse` 返回深层路径: + +代码块身份:可直接照写示例 + +```tsl +nested_value := array(10, ("A": 0, "B": array(2)), 0); +indexes := mfindSparse(nested_value, mcell = 2); +writeLn(length(indexes)); +writeLn(length(indexes[0])); +writeLn(indexes[0][0]); +writeLn(indexes[0][1]); +writeLn(indexes[0][2]); +``` + +代码块身份:输出片段 + +```text +1 +3 +1 +B +0 +``` + ## 默认生成模板 需要矩阵构造时,优先从这个最短模板开始: @@ -222,6 +544,9 @@ matrix_value := zeros(2, 3); - 以为 `mrows(matrix_value, 1)` 和 `mcols(matrix_value, 1)` 返回的还是数量。 - 写带步长的 `->` 时,漏掉外层 `array(...)`。 - 还在普通数组页里硬塞矩阵专用大小接口。 +- 把 `::=` 写成带 `begin ... end` 的语句块。 +- 用 `::` 期待遍历到任意深度;深度遍历使用 `:.`。 +- 子矩阵赋值时用形状不匹配的矩阵硬塞。 代码块身份:反例 / 不可照写