📝 docs(tsl-syntax-reference): document verified facts from FAQ corpus

从 FAQ 语料(2018 篇镜像)与参考页做完 169 条逐条差集,补入 6 组此前未收录的语言
事实。每条先用 TSL.exe 实跑观察行为,再收敛成 39 条断言的回归门,在 TSLGen2、
AnalyseNG.NET、TSL 三个解释器上均通过后才写入。

- 16 页:0/0 得 nan、2/0 得 inf;nan 的 = > < >= <= 恒假而 <> 为真;nan 沿算术
  传播;nil 在乘除减里按 0 参与
- 04 页:整体赋值免声明,但对未建立的变量写单元格赋值会报「变量类型不是Array」
- 07 页:相邻两个 if 是两条独立语句都会执行;for..in 单控制变量拿到的是键不是值;
  二维数组按行推进,行本身是数组(新增 syntax-07-013)
- 21 页:子矩阵赋值语句求值为 0;t[:,:] 按位置复制不按列名对齐(新增
  syntax-21-019);| 列并时同名字符串列键由右操作数覆盖(新增 syntax-21-018)
- 13 页:select 输出列表同名列后者覆盖前者,须用 as 改名(新增 syntax-13-032)

三条 FAQ 说法实跑不复现,故未写入:12574 的括号消歧、19857 的 -2147483648
字面量限制、31474 的 :. bugfix 记录。15305/11045 的用户/公用/共享函数同名解析
优先级需要服务端多账号环境,本地无法验证,仍为已知缺口。

lexicon.json 为 16 页补两个页级 alias,使 nan/nil 语义能被自然语言查询命中。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
csh
2026-08-20 20:58:10 +08:00
co-authored by Claude Fable 5
parent cd0405d64b
commit 2e8c46e152
6 changed files with 393 additions and 1 deletions
@@ -33,6 +33,8 @@
- 遍历时需要维度信息可用 `mIndexCount`;需要第 `n` 维下标可用 `mIndex(n)`
- 子矩阵提取可以写 `matrix[row_start:row_end, col_start:col_end]``matrix[:, col_range]``matrix[row_index_array, col_index_array]`
- 子矩阵赋值可以写成单个标量,也可以写成同结构矩阵;赋值矩阵应和目标子矩阵形状匹配。
- 子矩阵赋值语句本身**没有返回值**:`(m[:, "a"] := v)` 求值为 `0`,而普通赋值 `(a := v)` 求值为被赋的值。不要把子矩阵赋值写在需要取值的位置。
- `t[:, :] := source` 按**位置**逐单元复制,不按列名对齐。`source` 里若有某行的列存储顺序与其它行不同,复制结果会静默错位;先用 `source[:, array("列1", "列2")]` 统一列序再赋值。
- 子矩阵也可以接 `::=` 做逐单元赋值。
- `mfind(matrix)` 返回真值单元格下标;一维数组的无条件 `mfind` 返回一维下标数组。
- `mfind(matrix, condition)` 返回符合条件的下标行;二维矩阵下每行形如 `array(row_index, col_index)`
@@ -424,6 +426,79 @@ writeLn(matrix_value[1][1]);
11
```
### 子矩阵赋值的返回值与对齐方式
<!-- section-id: syntax-21-019 -->
<!-- tags: 赋值返回0, 赋值没返回值, 重构数组错位, 按位置复制, 列顺序不一致 -->
子矩阵赋值不产生返回值,普通赋值才产生:
代码块身份:可直接照写示例
```tsl
source := array(1, 2, 3);
plain := (target := source);
writeLn("plain:", plain[0]);
matrix_value := zeros(3, "a");
sub := (matrix_value[:, "a"] := source);
writeLn("sub:", sub);
writeLn("written:", matrix_value[0]["a"]);
```
结果说明:
- `plain` 拿到被赋的数组,所以 `plain[0]` 输出 `1`
- `sub` 输出 `0`:子矩阵赋值语句本身求值为 `0`,不是被赋的值
- `written` 输出 `1`:赋值本身生效了,只是取不到返回值
- 所以 `return m[:, "a"] := v;` 这种写法会返回 `0`,要分成两句写
代码块身份:输出片段
```text
plain:1
sub:0
written:1
```
`t[:, :] := source` 按位置复制,不按列名对齐:
代码块身份:可直接照写示例
```tsl
source := array("k1": ("p": 651, "v": 637),
"k2": ("p": 599, "v": 170),
"k3": ("v": 200, "p": 607));
target := zeros(mRows(source), mCols(source, 1));
target[:, :] := source;
writeLn("row3 p:", target[2]["p"]);
writeLn("row3 v:", target[2]["v"]);
ordered := source[:, array("p", "v")];
fixed := zeros(mRows(ordered), mCols(ordered, 1));
fixed[:, :] := ordered;
writeLn("fixed p:", fixed[2]["p"]);
writeLn("fixed v:", fixed[2]["v"]);
```
结果说明:
- 第三行源数据的列存储顺序是 `v``p`,与前两行相反
- `row3 p` 输出 `200``row3 v` 输出 `607`:两个值互换了,因为复制按位置而不按列名
- 前两行看不出问题,所以这种错位不会报错,只会静默出现在个别行
- `ordered := source[:, array("p", "v")]` 先统一列序后,`fixed p` 输出 `607``fixed v` 输出 `200`,恢复正确
- 源数据由多个过程分别写入时,各行列序可能不一致,用 `[:, :]` 重构前先统一列序
代码块身份:输出片段
```text
row3 p:200
row3 v:607
fixed p:607
fixed v:200
```
### `mfind` 与 `mfindSparse`
<!-- section-id: syntax-21-011 -->
@@ -963,6 +1038,44 @@ bar 结果 (1,2):2
- 上述差异只适用于普通 `array``FMArray``|``:|` 行为一致且行数不齐时补 `0`,见 [22_fmarray.md](22_fmarray.md)
- 对应的复合赋值形式:`&=`(行并)、`|=`(列并)、`:|=`(列并补 nil
### 列并遇到同名字符串列键
<!-- section-id: syntax-21-018 -->
<!-- tags: 同名列合并, 列被覆盖, 合并后值变了, 相同列名, 列并覆盖 -->
两侧共有的字符串列键不会并成两列,而是被右操作数覆盖:
代码块身份:可直接照写示例
```tsl
left := ones(3, array("A", "B"));
right := zeros(3, array("A", "C"));
merged := left | right;
writeLn("A:", merged[0]["A"]);
writeLn("B:", merged[0]["B"]);
writeLn("C:", merged[0]["C"]);
reversed := right | left;
writeLn("reversed A:", reversed[0]["A"]);
```
结果说明:
- `A` 输出 `0``A` 两侧都有,取右操作数 `right` 的值,`left``1` 被覆盖
- `B` 输出 `1``C` 输出 `0`:只在一侧出现的列都原样保留
- `reversed A` 输出 `1`:换序后仍是右操作数胜出,说明规则是「右侧覆盖左侧」而非「零值覆盖」
- 默认数字列下标不会触发覆盖,只有字符串列键相同才会
代码块身份:输出片段
```text
A:0
B:1
C:0
reversed A:1
```
## 默认生成模板
<!-- section-id: syntax-21-016 -->
@@ -990,6 +1103,9 @@ matrix_value := zeros(2, 3);
-`::=` 写成带 `begin ... end` 的语句块。
-`::` 期待遍历到任意深度;深度遍历使用 `:.`
- 子矩阵赋值时用形状不匹配的矩阵硬塞。
- 把子矩阵赋值写在需要取值的位置,例如 `return m[:, "a"] := v;`;它求值为 `0`
-`t[:, :] := source` 重构下标时,假定它会按列名对齐;它按位置复制。
- 期待 `|` 把两侧同名字符串列键并成两列;同名键会被右操作数覆盖。
-`union` 的复合赋值写成 `union=`;正确写法是 `&=`
- 一维数组直接 `union` 期待得到二维结果;需要先对它连用两次转置前缀(双转置)变成行向量。
- 在基础函数异常参数时用分号分隔;正确写法用逗号:`sqrt(data, 1, -999)`