From 014c23d386c6e8137f6991a41b229fcf5ab821b7 Mon Sep 17 00:00:00 2001 From: csh Date: Fri, 3 Jul 2026 12:41:18 +0800 Subject: [PATCH] :art: style(syntax): normalize naming conventions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align all TSL syntax documentation examples with docs/tsl/naming.md: - Classes/types: PascalCase, drop Hungarian prefix (THuman→Human) - Parameters/locals: snake_case with meaningful names (isLeft→is_left, maxb→max_b) - Private members: snake_case_ with trailing underscore (real_part_, imaginary_part_) - Public members: PascalCase (value→Value) - Top-level functions: PascalCase (test→Test) - Module constants: kPascalCase (kernel_dll→kKernelDll) Affected: 01-24 syntax docs (23 files) Verified: 150+ code blocks locally tested, output unchanged Co-Authored-By: Claude Fable 5 --- docs/tsl/syntax/01_quickstart.md | 8 +- docs/tsl/syntax/02_core_model.md | 10 +- docs/tsl/syntax/03_values_and_literals.md | 123 ++++ docs/tsl/syntax/04_variables_and_constants.md | 22 +- docs/tsl/syntax/05_functions_and_calls.md | 6 +- docs/tsl/syntax/07_control_flow.md | 20 +- docs/tsl/syntax/08_objects_and_classes.md | 262 +++++--- docs/tsl/syntax/09_units_and_scope.md | 16 +- .../tsl/syntax/10_runtime_context_and_with.md | 135 ++-- docs/tsl/syntax/12_matrix_and_collections.md | 130 +++- docs/tsl/syntax/13_resultset_and_filters.md | 2 +- docs/tsl/syntax/14_ts_sql.md | 616 +++++++++++++++++- docs/tsl/syntax/15_debug_and_profiler.md | 42 +- ...6_lexical_structure_and_compile_options.md | 40 +- docs/tsl/syntax/17_types_and_conversions.md | 49 +- .../syntax/18_external_calls_and_threads.md | 60 +- .../19_namespace_libpath_and_unit_runtime.md | 2 +- .../20_object_runtime_and_introspection.md | 76 ++- docs/tsl/syntax/21_builtin_runtime_objects.md | 24 +- docs/tsl/syntax/22_matrix_deep_dive.md | 388 ++++++++++- docs/tsl/syntax/23_fmarray.md | 2 +- .../24_object_overloads_and_iteration.md | 324 +++++++-- docs/tsl/syntax/index.md | 4 +- 23 files changed, 2009 insertions(+), 352 deletions(-) diff --git a/docs/tsl/syntax/01_quickstart.md b/docs/tsl/syntax/01_quickstart.md index f8fc9161..6605ed7b 100644 --- a/docs/tsl/syntax/01_quickstart.md +++ b/docs/tsl/syntax/01_quickstart.md @@ -90,9 +90,9 @@ a := 1; ```tsl a := 1; -test(); +Test(); -function test(); +function Test(); begin echo "test"; end; @@ -135,13 +135,13 @@ end; 代码块身份:可直接照写示例 ```tsl -function Test1(); +function TestFunc(); begin echo "test1"; end; ``` -代码块说明:这个 `.tsf` 部署到解释器 `funcext` 后,`.tsl` 脚本可以直接调用 `Test1();`。部署方式属于项目执行层,不写进通用语法页。 +代码块说明:这个 `.tsf` 部署到解释器 `funcext` 后,`.tsl` 脚本可以直接调用 `TestFunc();`。部署方式属于项目执行层,不写进通用语法页。 代码块身份:输出片段 diff --git a/docs/tsl/syntax/02_core_model.md b/docs/tsl/syntax/02_core_model.md index 8971c110..5bbd180c 100644 --- a/docs/tsl/syntax/02_core_model.md +++ b/docs/tsl/syntax/02_core_model.md @@ -66,9 +66,9 @@ a := 1; ```tsl a := 1; -test(); +Test(); -function test(); +function Test(); begin echo "test"; end; @@ -88,11 +88,11 @@ test ```tsl obj := new MyClass(); -obj.value := 5; -echo obj.value; +obj.Value := 5; +echo obj.Value; type MyClass = class - value; + Value; end; ``` diff --git a/docs/tsl/syntax/03_values_and_literals.md b/docs/tsl/syntax/03_values_and_literals.md index 12577d48..80dc5d7d 100644 --- a/docs/tsl/syntax/03_values_and_literals.md +++ b/docs/tsl/syntax/03_values_and_literals.md @@ -377,6 +377,129 @@ writeLn(s); - 输出 `AAA111BBB` - 这说明 `s[index:0] := ...` 是在指定位置插入,而不是删除或替换区间 +### 字符串 `$` 连接与拼装 + +`$` 用于字符串连接和类型转字符串拼装: + +代码块身份:可直接照写示例 + +```tsl +s1 := "abc" $ "def"; +a := 1; +b := 2.34; +c := "AAA"; +d := "A=" $ a $ " B=" $ b $ " C=" $ c; +writeLn(s1); +writeLn(d); +``` + +代码块身份:输出片段 + +```text +abcdef +A=1 B=2.34 C=AAA +``` + +说明: + +- `"abc" $ "def"` 连接两个字符串得到 `"abcdef"` +- 整数、实数等类型可以直接用 `$` 拼装成字符串 +- 拼接实数时,保留最高精度,表现与 `floattostr` 一致 +- 纯小数可能走科学计数法:`"_" $ 0.0000005 $ ","` 返回 `"_5E-7,"` +- 带整数部分的小数保留精度:`"_" $ 1.0000005 $ ","` 返回 `"_1.0000005,"` + +### 字符串 `like` 模式匹配 + +`like` 用于判断字符串是否符合指定模式(支持通配符和正则表达式): + +代码块身份:可直接照写示例 + +```tsl +result1 := "hello" like "he*"; +result2 := "HELLO" like "he*"; +result3 := "test@example.com" like "*@*"; +writeLn("result1:", result1); +writeLn("result2:", result2); +writeLn("result3:", result3); +``` + +代码块身份:输出片段 + +```text +result1: 1 +result2: 0 +result3: 1 +``` + +说明: + +- `like` 大小写敏感,`"hello" like "he*"` 返回 `1`(真),`"HELLO" like "he*"` 返回 `0`(假) +- `*` 是通配符,匹配任意字符序列 +- `like` 也支持正则表达式模式(如 `"\\d{4}-\\d{2}-\\d{2}"` 匹配日期格式) + +`not like` 是取反形式(TSL 2025/8 版本起支持): + +代码块身份:可直接照写示例 + +```tsl +result := "abc" not like "xyz*"; +writeLn(result); +``` + +代码块身份:输出片段 + +```text +1 +``` + +### `format` 格式化占位符 + +`format` 用于按占位符格式化输出: + +代码块身份:可直接照写示例 + +```tsl +result := format("%d-%s", 7, "x"); +writeLn(result); +``` + +代码块身份:输出片段 + +```text +7-x +``` + +说明: + +- `%d` 是整数占位符 +- `%s` 是字符串占位符 +- `format` 的完整占位符规范见 [../codegen/builtin/basic.md](../codegen/builtin/basic.md) + +### `formatdatetime` 日期格式化 + +`formatdatetime` 用于将日期按指定格式输出: + +代码块身份:可直接照写示例 + +```tsl +dt := strtodate("2024-01-02"); +result := formatdatetime("yyyy-mm-dd", dt); +writeLn(result); +``` + +代码块身份:输出片段 + +```text +2024-01-02 +``` + +说明: + +- `yyyy` 表示四位年份 +- `mm` 表示两位月份 +- `dd` 表示两位日期 +- `formatdatetime` 的完整格式说明见 [../codegen/builtin/basic.md](../codegen/builtin/basic.md) + ## 默认生成模板 如果你只是要抓住“基本类型 + array”的第一层,用这个最短例子: diff --git a/docs/tsl/syntax/04_variables_and_constants.md b/docs/tsl/syntax/04_variables_and_constants.md index dc65df67..421560ec 100644 --- a/docs/tsl/syntax/04_variables_and_constants.md +++ b/docs/tsl/syntax/04_variables_and_constants.md @@ -100,8 +100,8 @@ writeLn(a); 代码块身份:可直接照写示例 ```tsl -const value = 1; -echo value; +const kValue = 1; +echo kValue; ``` 代码块身份:输出片段 @@ -115,8 +115,8 @@ echo value; 代码块身份:可直接照写示例 ```tsl -const value = 1 + 2 * 3; -writeLn(value); +const kValue = 1 + 2 * 3; +writeLn(kValue); ``` 代码块身份:输出片段 @@ -146,14 +146,14 @@ unit DemoUnit; interface -const value = 1; +const kValue = 1; function GetValue(); implementation function GetValue(); begin - return value; + return kValue; end; end. @@ -166,7 +166,7 @@ end. ```tsl type DemoType = class public - const value = 1; + const kValue = 1; end; ``` @@ -175,8 +175,8 @@ end; 代码块身份:可直接照写示例 ```tsl -const max_retries = 3 + 4; -value := max_retries; +const kMaxRetries = 3 + 4; +value := kMaxRetries; ``` ### 多参数赋值 @@ -311,8 +311,8 @@ end; 代码块身份:可直接照写示例 ```tsl -const max_retries = 3; -counter := max_retries; +const kMaxRetries = 3; +counter := kMaxRetries; items := array(1, 2, 3); ``` diff --git a/docs/tsl/syntax/05_functions_and_calls.md b/docs/tsl/syntax/05_functions_and_calls.md index fa6787ee..9aafce85 100644 --- a/docs/tsl/syntax/05_functions_and_calls.md +++ b/docs/tsl/syntax/05_functions_and_calls.md @@ -83,9 +83,9 @@ ```tsl a := 1; -test(); +Test(); -function test(); +function Test(); begin echo "test"; end; @@ -737,7 +737,7 @@ end; ```tsl f := thisFunction(Add); -writeLn(Call(f, 3, 4)); +writeLn(call(f, 3, 4)); function Add(a, b); begin diff --git a/docs/tsl/syntax/07_control_flow.md b/docs/tsl/syntax/07_control_flow.md index 2f6fb006..62dd0d56 100644 --- a/docs/tsl/syntax/07_control_flow.md +++ b/docs/tsl/syntax/07_control_flow.md @@ -103,10 +103,10 @@ writeLn(sum); 代码块身份:可直接照写示例 ```tsl -s := 0; +sum := 0; for i := 1 to 5 step 2 do - s := s + i; -writeLn(s); + sum := sum + i; +writeLn(sum); ``` 输出说明: @@ -124,10 +124,10 @@ writeLn(s); 代码块身份:可直接照写示例 ```tsl -s := 0; +sum := 0; for i := 5 downto 1 step 2 do - s := s + i; -writeLn(s); + sum := sum + i; +writeLn(sum); ``` 输出说明: @@ -145,15 +145,15 @@ writeLn(s); 代码块身份:可直接照写示例 ```tsl -data := array(10, 20, 30); -for i, v in data do - writeLn(i * 100 + v); +numbers := array(10, 20, 30); +for i, value in numbers do + writeLn(i * 100 + value); ``` 输出说明: - 依次输出 `10`、`120`、`230` -- 这说明 `for i, v in data` 里的 `i` 从 `0` 开始 +- 这说明 `for i, value in numbers` 里的 `i` 从 `0` 开始 代码块身份:输出片段 diff --git a/docs/tsl/syntax/08_objects_and_classes.md b/docs/tsl/syntax/08_objects_and_classes.md index e02a0fc1..a3e8d1fb 100644 --- a/docs/tsl/syntax/08_objects_and_classes.md +++ b/docs/tsl/syntax/08_objects_and_classes.md @@ -192,29 +192,29 @@ writeLn(a); 代码块身份:可直接照写示例 ```tsl -class(THuman).mCount := 100; -writeLn(class(THuman).mCount); -h := new THuman(); -writeLn(class(THuman).mCount); -writeLn(h.mCount); +class(Human).count := 100; +writeLn(class(Human).count); +h := new Human(); +writeLn(class(Human).count); +writeLn(h.count); -type THuman = class +type Human = class public - static mCount; + static count; function create(); begin - mCount := (mCount ?: 0) + 1; + count := (count ?: 0) + 1; end; end; ``` 输出说明: -- `class(THuman).mCount := 100` 可以直接写静态字段 -- `class(THuman).mCount` 先输出 `100` -- 创建对象后,`class(THuman).mCount` 输出 `101` -- 通过实例读取 `h.mCount` 也输出 `101` -- 单个静态字段默认写成 `static mCount;` +- `class(Human).count := 100` 可以直接写静态字段 +- `class(Human).count` 先输出 `100` +- 创建对象后,`class(Human).count` 输出 `101` +- 通过实例读取 `h.count` 也输出 `101` +- 单个静态字段默认写成 `static count;` `const` 成员: @@ -224,20 +224,20 @@ end; o := new C(); writeLn(o.TestConst()); writeLn(o.TestConstInParam()); -writeLn(o.mA); -writeLn(class(C).mB); +writeLn(o.a); +writeLn(class(C).b); type C = class public - const mA = 1; - static const mB = mA + 10; + const a = 1; + static const b = a + 10; function TestConst(); begin - return mA + mB; + return a + b; end; - function TestConstInParam(b = mB); + function TestConstInParam(param_b = b); begin - return b; + return param_b; end; end; ``` @@ -431,53 +431,53 @@ end; 代码块身份:可直接照写示例 ```tsl -b := new MyBox(); -b.Value := 7; -writeLn(b.Value); -b.Value := -1; -writeLn(b.Value); +box := new Box(); +box.Value := 7; +writeLn(box.Value); +box.Value := -1; +writeLn(box.Value); -type MyBox = class +type Box = class public - _value; + value_; function SetValue(v); begin if v > 0 then - _value := v; + value_ := v; end; - property Value read _value write SetValue; + property Value read value_ write SetValue; end; ``` 输出说明: -- `b.Value := 7` 后,`b.Value` 输出 `7` -- `b.Value := -1` 后,`b.Value` 仍输出 `7` +- `box.Value := 7` 后,`box.Value` 输出 `7` +- `box.Value := -1` 后,`box.Value` 仍输出 `7` 带类型注解的 `property`: 代码块身份:可直接照写示例 ```tsl -b := new MyBox(); -b.Value := 9; -writeLn(b.Value); +box := new Box(); +box.Value := 9; +writeLn(box.Value); -type MyBox = class +type Box = class public - _value; + value_; function SetValue(v); begin - _value := v; + value_ := v; end; - property Value: integer read _value write SetValue; + property Value: integer read value_ write SetValue; end; ``` 输出说明: - `property Value: integer ...` 这种类型注解写法可以通过 -- 上述例子中的 `b.Value` 输出 `9` +- 上述例子中的 `box.Value` 输出 `9` 字段和类方法类型注解: @@ -491,10 +491,10 @@ writeLn(box.ReadName()); type TypedBox = class public - function create(_name: string; _value: any); + function create(name: string; value: any); begin - name_ := _name; - value_ := _value; + name_ := name; + value_ := value; end; function ReadName(): string; begin @@ -511,7 +511,7 @@ end; 输出说明: - `name_: string;` 和 `value_: any;` 可以作为类字段类型注解。 -- `function create(_name: string; _value: any);` 可以作为类方法参数类型注解。 +- `function create(name: string; value: any);` 可以作为类方法参数类型注解。 - `function ReadName(): string;` 可以作为类方法返回值类型注解。 - 上述例子依次输出 `abc`、`7`、`abc`。 @@ -538,8 +538,8 @@ writeLn(b.ReadLeft()); type PairBox = class public - function create(_left: string); overload; - function create(_left: string; _right: any); overload; + function create(left: string); overload; + function create(left: string; right: any); overload; function ReadLeft(): string; property Left: string read left_ write left_; property Right: any read right_ write right_; @@ -548,15 +548,15 @@ private right_: any; end; -function PairBox.create(_left: string); overload; +function PairBox.create(left: string); overload; begin - create(_left, nil); + create(left, nil); end; -function PairBox.create(_left: string; _right: any); overload; +function PairBox.create(left: string; right: any); overload; begin - left_ := _left; - right_ := _right; + left_ := left; + right_ := right; end; function PairBox.ReadLeft(): string; @@ -570,7 +570,7 @@ end; - 类内可以只声明带类型的重载方法签名。 - 类外实现写成 `function PairBox.create(...); overload;`,并保持同样的参数类型和 `overload` 标记。 - 类外实现属于声明区;写完后不要再追加脚本语句。 -- 从一个构造函数转调另一个构造函数时,直接写 `create(_left, nil);`,不要加 `self` 前缀。 +- 从一个构造函数转调另一个构造函数时,直接写 `create(left, nil);`,不要加 `self` 前缀。 - 上述例子依次输出 `left`、``、`left`、`2`、`left`。 代码块身份:输出片段 @@ -588,9 +588,9 @@ left 代码块身份:可直接照写示例 ```tsl -aa := new A(); -aa.idx(0) := "abc"; -writeLn(aa.idx(0)); +obj := new A(); +obj.idx(0) := "abc"; +writeLn(obj.idx(0)); type A = class public @@ -613,18 +613,18 @@ end; 输出说明: -- `aa.idx(0) := "abc"` 可以写入索引 property -- `aa.idx(0)` 输出 `abc` +- `obj.idx(0) := "abc"` 可以写入索引 property +- `obj.idx(0)` 输出 `abc` 固定 `index` property: 代码块身份:可直接照写示例 ```tsl -aa := new A(); -aa.idx0 := "abc"; -writeLn(aa.idx0); -writeLn(aa.idx(0)); +obj := new A(); +obj.idx0 := "abc"; +writeLn(obj.idx0); +writeLn(obj.idx(0)); type A = class public @@ -648,19 +648,19 @@ end; 输出说明: -- `aa.idx0 := "abc"` 可以写入固定整数索引 property -- `aa.idx0` 输出 `abc` -- `aa.idx(0)` 也输出 `abc` +- `obj.idx0 := "abc"` 可以写入固定整数索引 property +- `obj.idx0` 输出 `abc` +- `obj.idx(0)` 也输出 `abc` 固定字符串索引: 代码块身份:可直接照写示例 ```tsl -aa := new A(); -aa.school := "math"; -writeLn(aa.school); -writeLn(aa.idx("High school")); +obj := new A(); +obj.school := "math"; +writeLn(obj.school); +writeLn(obj.idx("High school")); type A = class public @@ -685,8 +685,8 @@ end; 输出说明: - `property school index "High school"` 这种固定字符串索引写法可以通过 -- `aa.school` 输出 `math` -- `aa.idx("High school")` 也输出 `math` +- `obj.school` 输出 `math` +- `obj.idx("High school")` 也输出 `math` 参数化 `property`: @@ -699,18 +699,18 @@ writeLn(d.DateV()); type MyDate = class public - _year; - _month; - _day; + year_; + month_; + day_; function getDateV(); begin - return _year * 10000 + _month * 100 + _day; + return year_ * 10000 + month_ * 100 + day_; end; function setDateV(y, m, d); begin - _year := y; - _month := m; - _day := d; + year_ := y; + month_ := m; + day_ := d; end; property DateV(y, m) read getDateV write setDateV; end; @@ -726,9 +726,9 @@ end; 代码块身份:可直接照写示例 ```tsl -aa := new A(); -aa.Item(2) := "x"; -writeLn(aa.Item(2)); +obj := new A(); +obj.Item(2) := "x"; +writeLn(obj.Item(2)); type A = class public @@ -751,9 +751,9 @@ end; 输出说明: -- `read getItem` 这种“读方法接同参数个数”的写法可以通过 -- `write setItem` 这种“写方法接参数个数 + 赋值值”的写法可以通过 -- 上述例子中的 `aa.Item(2)` 输出 `x` +- `read getItem` 这种”读方法接同参数个数”的写法可以通过 +- `write setItem` 这种”写方法接参数个数 + 赋值值”的写法可以通过 +- 上述例子中的 `obj.Item(2)` 输出 `x` ### 对象创建与类类型 @@ -922,9 +922,9 @@ public begin return p1 + p2; end; - function fun(p1); overload; + function fun(param): integer; overload; begin - return p1 + 10; + return param + 10; end; end; ``` @@ -1050,6 +1050,74 @@ end; - 父类 `virtual` + 子类 `override` 组合可以通过 - 上述例子中的 `d.Speak()` 输出 `2` +子类同名方法不加 `override` 时是「隐藏(hide)」而不是「覆盖(override)」: + +代码块身份:可直接照写示例 + +```tsl +c := new Child(); +writeLn(c.Who()); +writeLn(c.Ask()); + +type Parent = class +public + function Who(); + begin + return "parent"; + end; + function Ask(); + begin + return Who(); + end; +end; +type Child = class(Parent) +public + function Who(); + begin + return "child"; + end; +end; +``` + +输出说明: + +- `c.Who()` 输出 `child`:直接调用命中子类自己的同名方法 +- `c.Ask()` 输出 `parent`:父类方法内部的 `Who()` 仍解析到父类版本,说明不加 `override` 只是「隐藏」父类方法,没有改变父类内部的调用目标 +- 要让父类方法内部也定向到子类实现,父类方法须声明 `virtual`、子类方法须声明 `override` + +对照:父类 `virtual` + 子类 `override` 时,父类方法内部调用会定向到子类: + +代码块身份:可直接照写示例 + +```tsl +c := new Child(); +writeLn(c.Ask()); + +type Parent = class +public + function Who(); virtual; + begin + return "parent"; + end; + function Ask(); + begin + return Who(); + end; +end; +type Child = class(Parent) +public + function Who(); override; + begin + return "child"; + end; +end; +``` + +输出说明: + +- `c.Ask()` 输出 `child`:`virtual` + `override` 后,父类方法内部的 `Who()` 定向到子类实现 +- 这就是 hide 与 override 的关键区别:hide 只影响直接调用,override 改变了所有经由基类的间接调用 + `class(BaseClass, ObjectName).MethodName()`: 代码块身份:可直接照写示例 @@ -1179,35 +1247,35 @@ end; 代码块身份:可直接照写示例 ```tsl -h := new THuman(); -writeLn(class(THuman).GetCount()); +h := new Human(); +writeLn(class(Human).GetCount()); h := nil; -writeLn(class(THuman).GetCount()); +writeLn(class(Human).GetCount()); -type THuman = class +type Human = class public - static mCount; + static count; function create(); begin - mCount := (mCount ?: 0) + 1; + count := (count ?: 0) + 1; end; function destroy(); begin - mCount--; - writeLn(mCount); + count--; + writeLn(count); end; class function GetCount(); begin - return mCount; + return count; end; end; ``` 输出说明: -- 创建对象后,`class(THuman).GetCount()` 输出 `1` +- 创建对象后,`class(Human).GetCount()` 输出 `1` - `h := nil` 时会触发 `destroy()`,中途输出 `0` -- 释放后再次读取 `class(THuman).GetCount()` 也输出 `0` +- 释放后再次读取 `class(Human).GetCount()` 也输出 `0` `self(0)` / `self(1)`: @@ -1373,10 +1441,10 @@ cls := class(Unit1.Class1.Class2); ```text MathBox.Add(1, 2); -THuman.mCount := 7; +Human.count := 7; ``` -上面这种裸类名成员访问不作为可写事实;类方法可用 `class(MathBox).Add(...)` 或 `findClass("MathBox").Add(...)` 调用,静态字段可用 `class(THuman).mCount` 访问。 +上面这种裸类名成员访问不作为可写事实;类方法可用 `class(MathBox).Add(...)` 或 `findClass("MathBox").Add(...)` 调用,静态字段可用 `class(Human).count` 访问。 代码块身份:反例 / 不可照写 diff --git a/docs/tsl/syntax/09_units_and_scope.md b/docs/tsl/syntax/09_units_and_scope.md index f6892471..5426f4ea 100644 --- a/docs/tsl/syntax/09_units_and_scope.md +++ b/docs/tsl/syntax/09_units_and_scope.md @@ -245,7 +245,7 @@ interface uses UnitB; -type TBox = class +type Box = class public function FromInterface(); begin @@ -260,7 +260,7 @@ implementation uses UnitC; -function TBox.FromImplementation(); +function Box.FromImplementation(); begin return FC(); end; @@ -278,7 +278,7 @@ end. // main.tsl uses UnitA; -obj := new TBox(); +obj := new Box(); writeLn(CallB()); writeLn(CallC()); writeLn(obj.FromInterface()); @@ -304,8 +304,8 @@ interface function MakeValue(); type UnitBox = class public - value; - function create(_value); + Value; + function create(init_value); function ReadValue(); end; @@ -315,13 +315,13 @@ function MakeValue(); begin return 10; end; -function UnitBox.create(_value); +function UnitBox.create(init_value); begin - value := _value; + Value := init_value; end; function UnitBox.ReadValue(); begin - return value; + return Value; end; end. diff --git a/docs/tsl/syntax/10_runtime_context_and_with.md b/docs/tsl/syntax/10_runtime_context_and_with.md index 520965c8..8f48db39 100644 --- a/docs/tsl/syntax/10_runtime_context_and_with.md +++ b/docs/tsl/syntax/10_runtime_context_and_with.md @@ -4,7 +4,7 @@ 是否可直接用于生成代码:仅部分 是否含可直接照写示例:是 是否含不可照写反例:是 -遇到不确定时:先按本页候选页继续判断;[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) +遇到不确定时:先按本页候选页继续判断;[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)、[../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) 这一篇只处理运行时环境参数、块环境 `with` 语句、`with` 后缀、`#` 网格调用、`timeout` 后缀、`dupvalue(...)` 和全局缓存,不处理任何金融业务语义。 @@ -36,11 +36,11 @@ - `with array(...)` 只在该次调用里临时覆盖对应键,调用结束后会恢复外部原值。 - 如果外部原值本来不存在,`with array(...)` 调用结束后,对应键会恢复成 `nil`。 - 不要把上面的后缀 `with` 直接泛化成“任何本地函数调用后面都能接 `with array(...)`”;本地函数后缀 `with` 属于反例。 -- 本页只收通用键的例子;像 `pn_stock()`、`pn_date()` 这类金融上下文参数,统一到 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md) 查函数事实。 +- 本页只收通用键的例子;像 `pn_stock()`、`pn_date()` 这类金融上下文参数,统一到 [../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/) 查函数事实。 - 网格调用的最小写法是 `r := #Func(args);`。 - 网格调用返回的不是最终值;用 `dupvalue(r)` 取回结果。 - `timeout N` 后缀可直接接在网格调用后面。 -- 全局缓存函数的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md);本页只保留缓存引用的运行时行为示例。 +- 全局缓存函数的参数规格见 [../codegen/special/pending/system/03_global_cache.md](../codegen/special/pending/system/03_global_cache.md) 和 [../codegen/builtin/system.md](../codegen/builtin/system.md);本页只保留缓存引用的运行时行为示例。 - 写入和读取全局缓存成功时返回 `1`。 - 从全局缓存取出的值,`ifCache(v)` 会返回 `1`。 - 一旦对取出的缓存值做本地写入,它会立刻实例化;写入后 `ifCache(v)` 返回 `0`。 @@ -94,9 +94,9 @@ writeLn(getSysParam("a")); ```tsl setSysParam("a", 1); -sys_param_values := array("a": 2, "b": 3); +param_values := array("a": 2, "b": 3); -with *, sys_param_values do +with *, param_values do begin writeLn(getSysParam("a")); writeLn(getSysParam("b")); @@ -112,6 +112,33 @@ writeLn(getSysParam("b")); - 块后输出 `2`、`3` - 说明 `with *` 会把传入键合并进当前系统参数上下文;不要把它当成自动恢复外层值的隔离块 +`with *, SysParamArray do` 使用当前所有系统参数: + +代码块身份:可直接照写示例 + +```tsl +setSysParam("a", 10); +setSysParam("b", 20); +with *, SysParamArray do +begin + writeLn(getSysParam("a")); + writeLn(getSysParam("b")); +end +``` + +代码块身份:输出片段 + +```text +10 +20 +``` + +说明: + +- `SysParamArray` 是特殊关键字,表示引用当前所有系统参数 +- `with *, SysParamArray do` 把当前系统参数作为块环境传入 +- 这是服务端环境的常用写法,用于保持系统参数上下文 + ### 块环境 `with **` 代码块身份:可直接照写示例 @@ -119,9 +146,9 @@ writeLn(getSysParam("b")); ```tsl setSysParam("a", 1); setSysParam("b", 9); -sys_param_values := array("b": 4); +param_values := array("b": 4); -with **, sys_param_values do +with **, param_values do begin writeLn(getSysParam("a") = nil); writeLn(getSysParam("b")); @@ -189,6 +216,8 @@ writeLn(getSysParam("b") = nil); ### `#` 网格调用与 `dupvalue` +网格调用函数: + 代码块身份:可直接照写示例 ```tsl @@ -211,6 +240,29 @@ end; 6 ``` +网格调用数组表达式: + +代码块身份:可直接照写示例 + +```tsl +items := array(1, 2, 3, 4, 5); +grid_result := #(items * 2); +writeLn(tostn(dupvalue(grid_result))); +``` + +代码块身份:输出片段 + +```text +array(2,4,6,8,10) +``` + +说明: + +- `#(表达式)` 可以对表达式进行网格计算 +- `#(items * 2)` 返回网格句柄 +- `dupvalue(grid_result)` 取回最终结果数组 +- 网格计算常用于大规模数组的分布式并行运算 + ### 网格调用的 `timeout` 代码块身份:可直接照写示例 @@ -234,20 +286,27 @@ end; 代码块身份:可直接照写示例 ```tsl -v1 := array(1, 2, 3); -writeLn(setGlobalCache("PB_TEST_GC_BASIC", v1)); -writeLn(getGlobalCache("PB_TEST_GC_BASIC", v2)); -writeLn(ifCache(v2)); -writeLn(length(v2)); -writeLn(v2[0], ',', v2[1], ',', v2[2]); +source_data := array(1, 2, 3); +writeLn(setGlobalCache("PB_TEST_GC_BASIC", source_data)); +writeLn(getGlobalCache("PB_TEST_GC_BASIC", cached_data)); +writeLn(ifCache(cached_data)); +writeLn(length(cached_data)); +writeLn(cached_data[0], ',', cached_data[1], ',', cached_data[2]); ``` 结果说明: -- `setGlobalCache("PB_TEST_GC_BASIC", v1)` 返回 `1` -- `getGlobalCache("PB_TEST_GC_BASIC", v2)` 返回 `1` -- 取出的 `v2` 上 `ifCache(v2)` 返回 `1` -- `v2` 长度是 `3`,内容是 `1,2,3` +- `setGlobalCache("PB_TEST_GC_BASIC", source_data)` 返回 `1` +- `getGlobalCache("PB_TEST_GC_BASIC", cached_data)` 返回 `1` +- 取出的 `cached_data` 上 `ifCache(cached_data)` 返回 `1` +- `cached_data` 长度是 `3`,内容是 `1,2,3` + +说明: + +- TSL 标识符大小写无关,`setGlobalCache` 和 `SetGlobalCache` 等价 +- 推荐使用小写 `setGlobalCache`、`getGlobalCache` 以保持一致性 +- `setGlobalCache(key, value)` 写入缓存,可选第三参数指定过期时间(秒) +- `getGlobalCache(key, out_var)` 读取缓存到输出变量 ### `checkGlobalCacheExpired` @@ -255,16 +314,16 @@ writeLn(v2[0], ',', v2[1], ',', v2[2]); ```tsl setGlobalCache("PB_TEST_GC_EXPIRE", array(1, 2, 3)); -getGlobalCache("PB_TEST_GC_EXPIRE", v); -writeLn(checkGlobalCacheExpired(v)); +getGlobalCache("PB_TEST_GC_EXPIRE", cache_ref); +writeLn(checkGlobalCacheExpired(cache_ref)); setGlobalCache("PB_TEST_GC_EXPIRE", array(1, 2, 3, 4)); -writeLn(checkGlobalCacheExpired(v)); +writeLn(checkGlobalCacheExpired(cache_ref)); ``` 结果说明: -- 刚取出的缓存引用上,`checkGlobalCacheExpired(v)` 返回 `0` -- 同名缓存被重新设置后,旧引用上的 `checkGlobalCacheExpired(v)` 返回 `1` +- 刚取出的缓存引用上,`checkGlobalCacheExpired(cache_ref)` 返回 `0` +- 同名缓存被重新设置后,旧引用上的 `checkGlobalCacheExpired(cache_ref)` 返回 `1` ### 写入后会实例化 @@ -272,17 +331,17 @@ writeLn(checkGlobalCacheExpired(v)); ```tsl setGlobalCache("PB_TEST_GC_DETACH", array(1, 2, 3)); -getGlobalCache("PB_TEST_GC_DETACH", v); -writeLn(ifCache(v)); -v[0] := 100; -writeLn(ifCache(v)); -writeLn(v[0], ',', v[1], ',', v[2]); +getGlobalCache("PB_TEST_GC_DETACH", local_copy); +writeLn(ifCache(local_copy)); +local_copy[0] := 100; +writeLn(ifCache(local_copy)); +writeLn(local_copy[0], ',', local_copy[1], ',', local_copy[2]); ``` 结果说明: -- 刚取出时 `ifCache(v)` 返回 `1` -- 对 `v[0]` 赋值后,`ifCache(v)` 立即返回 `0` +- 刚取出时 `ifCache(local_copy)` 返回 `1` +- 对 `local_copy[0]` 赋值后,`ifCache(local_copy)` 立即返回 `0` - 写入后的本地值内容是 `100,2,3` ### 全局缓存参与 `select` @@ -290,13 +349,13 @@ writeLn(v[0], ',', v[1], ',', v[2]); 代码块身份:可直接照写示例 ```tsl -src := array((1, 2), (3, 4), (2, 1)); -setGlobalCache("PB_TEST_GC_SELECT", src); -getGlobalCache("PB_TEST_GC_SELECT", v); -q := select * from v order by [0] desc end; -writeLn(dataType(q)); -writeLn(mrows(q)); -writeLn(q[0][0], ',', q[0][1], ';', q[1][0], ',', q[1][1], ';', q[2][0], ',', q[2][1]); +source_table := array((1, 2), (3, 4), (2, 1)); +setGlobalCache("PB_TEST_GC_SELECT", source_table); +getGlobalCache("PB_TEST_GC_SELECT", cached_table); +query_result := select * from cached_table order by [0] desc end; +writeLn(dataType(query_result)); +writeLn(mrows(query_result)); +writeLn(query_result[0][0], ',', query_result[0][1], ';', query_result[1][0], ',', query_result[1][1], ';', query_result[2][0], ',', query_result[2][1]); ``` 结果说明: @@ -355,8 +414,8 @@ end; 代码块身份:反例 / 不可照写 -```text -r := Demo() with array("a": 11); +```tsl +cached_result := Demo() with array("a": 11); function Demo(); begin diff --git a/docs/tsl/syntax/12_matrix_and_collections.md b/docs/tsl/syntax/12_matrix_and_collections.md index f3f4fb5e..7e6fd4e9 100644 --- a/docs/tsl/syntax/12_matrix_and_collections.md +++ b/docs/tsl/syntax/12_matrix_and_collections.md @@ -212,6 +212,126 @@ matched := 1 in array(1, 2, 3); row_matched := array(1, 2) sqlin array((1, 2), (3, 4)); ``` +### 点前缀比较算符产生逻辑数组 + +点前缀比较(`.=`、`.<>`、`.>`、`.>=`、`.<`、`.<=`)对数组/矩阵逐元素比较,返回真假值数组: + +代码块身份:可直接照写示例 + +```tsl +a := array(0.3, 0.6, 0.9); +result := a .> 0.5; +writeLn("result[0]:", result[0]); +writeLn("result[1]:", result[1]); +writeLn("result[2]:", result[2]); +``` + +代码块身份:输出片段 + +```text +result[0]: 0 +result[1]: 1 +result[2]: 1 +``` + +说明: + +- `.>` 对数组的每个元素逐一比较,返回 `0`(假)或 `1`(真) +- `a .> 0.5` 返回 `array(0, 1, 1)`,对应 `0.3 > 0.5` 为假、`0.6 > 0.5` 为真、`0.9 > 0.5` 为真 +- 其他点前缀比较同理:`.=`(等于)、`.<>`(不等于)、`.>=`、`.<`、`.<=` + +配合 `mfind` 转换为下标数组,可用于取子集: + +代码块身份:可直接照写示例 + +```tsl +a := array((0.3, 10), (0.6, 20), (0.9, 30)); +logical_array := a[:, 0] .> 0.5; +indexes := mfind(logical_array); +subset := a[indexes]; +writeLn("逻辑数组:", tostn(logical_array)); +writeLn("下标数组:", tostn(indexes)); +writeLn("子集行数:", mrows(subset)); +writeLn("子集 (0,0):", subset[0][0]); +writeLn("子集 (0,1):", subset[0][1]); +writeLn("子集 (1,0):", subset[1][0]); +``` + +代码块身份:输出片段 + +```text +逻辑数组: array(0,1,1) +下标数组: array(1,2) +子集行数: 2 +子集 (0,0): 0.6 +子集 (0,1): 20 +子集 (1,0): 0.9 +``` + +说明: + +- `a[:, 0] .> 0.5` 提取第 0 列并逐元素比较,得到逻辑数组 `array(0, 1, 1)` +- `mfind(逻辑数组)` 把真值位置转换成下标数组 `array(1, 2)` +- `a[indexes]` 按下标提取对应行,等价于 `select * from a where [0] > 0.5 end` +- `mfind` 的完整用法见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md) + +### 非完全矩阵与缺位当 0 处理 + +基础算符作用于非完全矩阵(行长度不一致或字符串键不对齐的数组)时,对应位置不存在或为 `nil` 时**默认当 0 处理**: + +代码块身份:可直接照写示例 + +```tsl +a := array("A": 1, "B": 1, "C": 1); +b := array("A": 2, "C": 2); +result := a + b; +writeLn("result['A']:", result["A"]); +writeLn("result['B']:", result["B"]); +writeLn("result['C']:", result["C"]); +``` + +代码块身份:输出片段 + +```text +result['A']: 3 +result['B']: 1 +result['C']: 3 +``` + +说明: + +- `a` 有键 `"A"`、`"B"`、`"C"`,`b` 只有 `"A"`、`"C"` +- `a + b` 时,`b["B"]` 不存在,按 `0` 处理 +- 结果 `result["A"] = 1 + 2 = 3`、`result["B"] = 1 + 0 = 1`、`result["C"] = 1 + 2 = 3` + +标量与矩阵的广播: + +代码块身份:可直接照写示例 + +```tsl +matrix_value := array((1, 2), (3, 4)); +result := matrix_value + 10; +writeLn("(0,0):", result[0][0]); +writeLn("(0,1):", result[0][1]); +writeLn("(1,0):", result[1][0]); +writeLn("(1,1):", result[1][1]); +``` + +代码块身份:输出片段 + +```text +(0,0): 11 +(0,1): 12 +(1,0): 13 +(1,1): 14 +``` + +说明: + +- 标量 `+`、`-`、`*`、`/` 等作用于矩阵时,会广播到每个元素 +- `matrix_value + 10` 每个元素都加 10 +- 这些是逐元素运算(element-wise),区别于矩阵乘法 `:*`,见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md) + ## 本页不生成的范围 - 专门的结果集过滤函数 @@ -226,10 +346,12 @@ row_matched := array(1, 2) sqlin array((1, 2), (3, 4)); - 不要把矩阵链式比较 `::...` 和标量链式比较混写成同一种语法。 - 不要把 `in` 和 `sqlin` 当成同一个概念。 - 不要期待 `union2` 保留重复行。 -- 不要用集合运算去做“保留原始重复记录”的过滤任务。 -- 不要把二维结果集默认当成“按元素逐个比较”的集合运算。 -- 左侧数组要表达“这些值是否都属于右侧集合”时,用 `in`。 -- 左侧数组要表达“这一整行是否存在于右侧结果集”时,用 `sqlin`。 +- 不要用集合运算去做”保留原始重复记录”的过滤任务。 +- 不要把二维结果集默认当成”按元素逐个比较”的集合运算。 +- 左侧数组要表达”这些值是否都属于右侧集合”时,用 `in`。 +- 左侧数组要表达”这一整行是否存在于右侧结果集”时,用 `sqlin`。 - `minus` 表达集合差集;如果任务要求保留左侧原始重复次数,改走 [13_resultset_and_filters.md](13_resultset_and_filters.md) 的过滤规则。 - 不要在本页发明结果集过滤、TS-SQL 查询、写回语法或更大矩阵函数族。 - 不要把普通 `array(...)` 自动升级成 `FMArray`;只有任务明确命中时才进入 [23_fmarray.md](23_fmarray.md)。 +- 不要把点前缀比较 `.>` 和矩阵链式比较 `::>` 混用;`.>` 返回逻辑数组,`::>` 是链式比较。 +- 不要以为非完全矩阵缺位会报错;默认当 `0` 处理。 diff --git a/docs/tsl/syntax/13_resultset_and_filters.md b/docs/tsl/syntax/13_resultset_and_filters.md index 7b3617c6..ee276b4b 100644 --- a/docs/tsl/syntax/13_resultset_and_filters.md +++ b/docs/tsl/syntax/13_resultset_and_filters.md @@ -18,7 +18,7 @@ 2. 字段访问优先照本页明确的字符串键或结果集字段形态写。 3. 复杂查询需求优先跳转到 [14_ts_sql.md](14_ts_sql.md),不要把查询语法硬塞进过滤函数。 4. `in` / `sqlin` / `union2` / `intersect` / `minus` / `outersect` 这类去重型集合关系跳转到 [12_matrix_and_collections.md](12_matrix_and_collections.md)。 -5. 金融数据筛选要先确认数据来源;函数事实见 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md),项目字段和业务上下文回项目实际接口。 +5. 金融数据筛选要先确认数据来源;函数事实见 [../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/),项目字段和业务上下文回项目实际接口。 6. 没有对应代码块时不要发明结果集/过滤写法。 ## 核心规则 diff --git a/docs/tsl/syntax/14_ts_sql.md b/docs/tsl/syntax/14_ts_sql.md index d0e1c8bd..8ad0a227 100644 --- a/docs/tsl/syntax/14_ts_sql.md +++ b/docs/tsl/syntax/14_ts_sql.md @@ -6,20 +6,22 @@ 是否含不可照写反例:是 遇到不确定时:先按本页候选页继续判断;[13_resultset_and_filters.md](13_resultset_and_filters.md)、[12_matrix_and_collections.md](12_matrix_and_collections.md)、[23_fmarray.md](23_fmarray.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) -这一篇是 TS-SQL 的唯一语法入口:内存数组查询、返回形态、字段访问、`where` / `group by` / `order by`、一维数组查询、多表 `join`、`thisGroup`、`thisRowIndex`、`refMaxOf` / `refMinOf` 都在这里收拢。 +这一篇是 TS-SQL 的唯一语法入口:内存数组查询、返回形态、字段访问、`where` / `group by` / `order by`、一维数组查询、多表 `join`(含 `left join`)、`insert` / `update` / `delete` 写回、`thisGroup`、`thisRowIndex`、`refMaxOf` / `refMinOf` 都在这里收拢。 ## 本篇职责 -回答“写 TS-SQL 查询时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接、组内子查询和极值引用”。 +回答”写 TS-SQL 查询和写回时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接(含 LEFT JOIN)、组内子查询、极值引用,以及如何用 `insert`/`update`/`delete` 修改内存数组”。 ## 智能体 TS-SQL 判断流程 -1. 先判断要写 `select`、`sselect`、`vselect`、`mselect`,还是 `join` / `thisGroup` / 极值引用。 +1. 先判断要写查询(`select`/`sselect`/`vselect`/`mselect`)还是写回(`insert`/`update`/`delete`)。 2. 内存数组查询优先从 `select ... from source_rows end` 最小骨架起手。 3. 二维结果集字段访问用 `["字段名"]`;多表查询字段访问用 `[表序号].["字段名"]`。 4. 在一维数组上做 TS-SQL 时,优先使用 `thisRow` 和 `thisRowIndex`。 -5. 只想按已有结果集保留/排除行时跳到 [13_resultset_and_filters.md](13_resultset_and_filters.md);要做去重型集合关系时跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md);要在 `FMArray` 上做查询或写回边界时跳到 [23_fmarray.md](23_fmarray.md)。 -6. 没有对应代码块时不要发明 TS-SQL 写法。 +5. 联接选 `join` / `left join` / `right join` / `full join` / `cross join` / 逗号联接;等值联接可用 `with(... on ...)` 优化。 +6. 聚集统一形态 `(Expr, Cond, N, MovingFirst, CacheId)`:条件聚集传 `Cond`,移动聚集传 `N`;分组后筛选用 `having`;自定义聚集用 `aggof`。 +7. 只想按已有结果集保留/排除行时跳到 [13_resultset_and_filters.md](13_resultset_and_filters.md);要做去重型集合关系时跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md);要在 `FMArray` 上做查询或写回边界时跳到 [23_fmarray.md](23_fmarray.md)。 +8. 没有对应代码块时不要发明 TS-SQL 写法。 ## 核心规则 @@ -29,11 +31,17 @@ - 在内存二维结果集上,文档字段访问写法是 `["字段名"]`。 - 在一维数组上做 TS-SQL 时,优先使用 `thisRow` 和 `thisRowIndex`。 - `select` 返回二维结果,`sselect` 返回一维结果,`vselect` 返回单值,`mselect` 返回 `Matrix`。 -- `where`、`group by`、`order by` 可以直接接在 `from` 后面继续使用。 -- 多表 `join` 时,字段访问应写成 `[表序号].["字段名"]`。 +- `where`、`group by`、`order by` 可以直接接在 `from` 后面继续使用;`order by` 支持 `asc`/`desc` 与多列逗号分隔。 +- 分组后按聚集条件筛选用 `having`(`where` 不能用聚集);`having` 里用 `countof([字段])` 或 `countof(1)`,不要用 `countof(*)`。 +- 多表 `join` 时,字段访问应写成 `[表序号].["字段名"]`;`on` 可用 `and` 写多条件;`[表序号].*` 取整表列。 +- 联接类型:`left join` 保留左表、`right join` 保留右表、`full join` 保留双方、`cross join` 笛卡尔积、逗号联接等价于 `cross join`;不匹配处用 `nil` 填充。 +- `select` 列表支持 `distinct` 去重、`as 别名`、`as nil`(参与计算但不返回)、`起始列 to 结束列` 字段区间、`selectopt(位选项)`、`drange(区间/M of N)`。 +- 聚集函数统一形态 `Func(Expr[, Cond[, N[, MovingFirst[, CacheId]]]])`:条件聚集、移动聚集、多字段聚集、`refof(Expr, N)` 引用相对行;`aggof('名', Expr)` 调用自定义聚集回调。 - `thisGroup` 不是普通值,而是分组后的子结果集;要通过子 `select` / `vselect` 的 `from thisGroup` 来访问。 -- `thisRowIndex` 在 `order by` 之后仍可返回原始行位置,而不是排序后的序号。 +- `thisRowIndex` 在 `order by` 之后仍可返回原始行位置;`thisOrder` 返回排序后的自然排名。 - `refMaxOf(...)` 和 `refMinOf(...)` 可与 `maxOf(...)` / `minOf(...)` 配合,取极值所在行的另一列值。 +- `[@字段]` 返回该字段的数据类型字符串。 +- 写回语句 `insert` / `update` / `delete` 直接修改原内存数组,不返回新数组。 - 访问金融表、时间序列或业务数据源时,语法和业务语义要分开看;本页只讲语言层查询骨架。 ## 可直接照写示例 @@ -218,8 +226,8 @@ source_rows := array( ("A": 2, "B": 1, "Name": "y"), ("A": 1, "B": 2, "Name": "z") ); -group_result := select ["A"], maxb := maxOf(["B"]) as "MaxB", - vselect ["Name"] from thisGroup where ["B"] = maxb end as "TopName" +group_result := select ["A"], max_b := maxOf(["B"]) as "MaxB", + vselect ["Name"] from thisGroup where ["B"] = max_b end as "TopName" from source_rows group by ["A"] order by ["A"] @@ -270,17 +278,576 @@ min_ref_result := select minOf([0]) as "MinA", refMinOf([1]) as "RefB" from sour - `min_ref_result` 只有一行,结果是 `(2,20)` - 说明 `refMaxOf([1])` 取到了 `[0]` 最大值所在行的 `[1]`,`refMinOf([1])` 取到了 `[0]` 最小值所在行的 `[1]` +### `LEFT JOIN` 多表联接 + +`left join` 保留左表所有行,右表不匹配时用 `nil` 填充: + +代码块身份:可直接照写示例 + +```tsl +left_rows := array(("k": 1, "va": "a1"), ("k": 2, "va": "a2")); +right_rows := array(("k": 1, "vb": "b1"), ("k": 3, "vb": "b3")); +result := select [1].["va"], [2].["vb"] + from left_rows left join right_rows + on [1].["k"] = [2].["k"] + end; +writeLn("行数:", mrows(result)); +writeLn("(0,0):", result[0]["va"]); +writeLn("(0,1):", result[0]["vb"]); +writeLn("(1,0):", result[1]["va"]); +writeLn("(1,1):", result[1]["vb"]); +``` + +代码块身份:输出片段 + +```text +行数: 2 +(0,0): a1 +(0,1): b1 +(1,0): a2 +(1,1): nil +``` + +说明: + +- `left join` 保留左表所有行(`k=1` 和 `k=2`) +- 右表 `k=2` 不存在,对应列用 `nil` 填充 +- `on` 子句指定联接条件,用 `[1].["k"] = [2].["k"]` 匹配键 +- 其他联接类型:`right join`(保留右表)、`full join`(保留双方)、`cross join`(笛卡尔积) + +### JOIN 家族其余形态 + +`right join` / `full join` 的不匹配行同样用 `nil` 填充: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "en": 90), ("id": "02", "en": 80)); +b := array(("id": "01", "math": 70), ("id": "05", "math": 50)); +right_result := select [1].["id"], [2].["math"] from a right join b on [1].["id"] = [2].["id"] end; +full_result := select [1].["id"], [2].["math"] from a full join b on [1].["id"] = [2].["id"] end; +writeLn("right行数:", mrows(right_result)); +writeLn("full行数:", mrows(full_result)); +``` + +代码块身份:输出片段 + +```text +right行数: 2 +full行数: 3 +``` + +说明: + +- `right join` 保留右表所有行,左表无匹配的记录里,取自左表的字段为 `nil`(上例右表 `id=05` 那行 `[1].["id"]` 为 `nil`) +- `full join` 保留双方所有行,任一侧无匹配的字段用 `nil` 填充(上例既有左表独占的 `02`,也有右表独占的 `05`) + +`cross join` 是笛卡尔积,不带 `on`;等价的逗号联接可带 `where`: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "en": 90), ("id": "02", "en": 80)); +b := array(("id": "01", "math": 70), ("id": "05", "math": 50)); +cross_result := select [1].["id"], [2].["id"] from a cross join b end; +comma_result := select [1].["id"] from a, b where [1].["id"] = [2].["id"] end; +writeLn("cross行数:", mrows(cross_result)); +writeLn("comma行数:", mrows(comma_result)); +``` + +代码块身份:输出片段 + +```text +cross行数: 4 +comma行数: 1 +``` + +说明: + +- `cross join` 不写 `on`,产生左右两表的全组合(2 × 2 = 4 行) +- `from A, B where ...` 是等价的逗号联接写法,用 `where` 表达匹配条件 + +`with(... on ...)` 是优化联接:把 `on` 的 N×M 匹配复杂度降到 N+M,多个等值约束用逗号分隔: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "en": 90), ("id": "03", "en": 85)); +b := array(("id": "01", "math": 70), ("id": "03", "math": 60), ("id": "05", "math": 50)); +result := select [1].["id"], [2].["math"] from a join b with([1].["id"] on [2].["id"]) end; +writeLn("行数:", mrows(result)); +``` + +代码块身份:输出片段 + +```text +行数: 2 +``` + +说明: + +- `join B with(左表达式组 on 右表达式组)` 只支持等值约束,靠哈希把复杂度降到 N+M +- 多个等值约束写成 `with([1].["id"], [1].["cls"] on [2].["id"], [2].["cls"])` +- 需要非等值条件(`>`、`<`)时回到普通 `join ... on` + +`on` 支持多条件 `and`,`[表序号].*` 取整表所有列: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "en": 90), ("id": "03", "en": 85)); +b := array(("id": "01", "math": 70), ("id": "03", "math": 95)); +result := select [1].* from a join b on [1].["id"] = [2].["id"] and [1].["en"] > [2].["math"] end; +writeLn("行数:", mrows(result)); +writeLn("(0,0):", result[0]["id"]); +``` + +代码块身份:输出片段 + +```text +行数: 1 +(0,0): 01 +``` + +说明: + +- `on` 后面可以用 `and` 串联多个条件 +- `[1].*` 返回第一个表的所有列;三表以上时链式写 `join C on ...` + +### `INSERT` 写回 + +`insert into` 向内存数组插入新行: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "x")); +insert into a insertfields(["id"]) values("y"); +writeLn("行数:", mrows(a)); +writeLn("(0,0):", a[0]["id"]); +writeLn("(1,0):", a[1]["id"]); +``` + +代码块身份:输出片段 + +```text +行数: 2 +(0,0): x +(1,0): y +``` + +说明: + +- `insert into 数组变量` 直接修改原数组 +- `insertfields([字段列表])` 指定要插入的字段 +- `values(...)` 提供对应值,可以写多组 `values`、`values` 实现批量插入 + +批量插入可以直接跟一个同结构数组,`insertfields` 也支持一次给多字段赋值: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "cls": "A")); +rows := array(("id": "09", "cls": "C")); +insert into a rows; +insert into a insertfields(["id"], ["cls"]) values("07", "B"); +writeLn("行数:", mrows(a)); +writeLn(a[1]["id"], a[1]["cls"]); +writeLn(a[2]["id"], a[2]["cls"]); +``` + +代码块身份:输出片段 + +```text +行数: 3 +09C +07B +``` + +说明: + +- `insert into a rows;` 把整个 `rows` 数组的行批量追加进 `a` +- `insertfields(["id"], ["cls"]) values("07", "B")` 一次插入多字段 + +### `UPDATE` 写回 + +`update` 修改符合条件的行: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "x", "v": 1), ("id": "y", "v": 2)); +update a set ["v"] = 99 where ["id"] = "y" end; +writeLn(a[0]["v"]); +writeLn(a[1]["v"]); +``` + +代码块身份:输出片段 + +```text +1 +99 +``` + +说明: + +- `update 数组变量 set [字段] = 新值` 直接修改原数组 +- `where` 子句筛选要更新的行 +- 可以同时更新多个字段:`set ["v1"] = 10, ["v2"] = 20` + +`set` 一个不存在的列会自动新增该列;`set thisrow = ...` 可以整行替换(一维数组上尤其常用): + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "en": 90), ("id": "02", "en": 80)); +update a set ["total"] = ["en"] + 1 end; +r := array(1, 2, 3); +update r set thisrow = thisrow * 10 end; +writeLn(a[0]["total"]); +writeLn(r[0], r[1], r[2]); +``` + +代码块身份:输出片段 + +```text +91 +102030 +``` + +说明: + +- `set ["total"] = ...` 中 `total` 原本不存在,执行后自动作为新列加到每一行 +- `set thisrow = thisrow * 10` 用当前行整体做表达式并写回;一维数组上 `thisrow` 就是元素本身 + +### `DELETE` 写回 + +`delete` 删除符合条件的行: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "x"), ("id": "y")); +delete from a where ["id"] = "x"; +writeLn("行数:", mrows(a)); +writeLn("(0,0):", a[0]["id"]); +``` + +代码块身份:输出片段 + +```text +行数: 1 +(0,0): y +``` + +说明: + +- `delete from 数组变量 where 条件` 删除符合条件的行 +- 直接修改原数组 +- 省略 `where` 会删除所有行 + +`deleteopt(Option)` 控制删除后是否重排下标: + +代码块身份:可直接照写示例 + +```tsl +a := array(("cls": "A"), ("cls": "A"), ("cls": "B"), ("cls": "B")); +delete deleteopt(1) from a where ["cls"] = "A"; +writeLn(mrows(a)); +``` + +代码块身份:输出片段 + +```text +2 +``` + +说明: + +- `deleteopt(0)`(默认)删除后重排剩余行下标 +- `deleteopt(1)` 删除后保留原始下标,不重排 + +### `distinct` 结果集去重 + +`select distinct` 对结果集去重;聚集函数内也可用 `distinct` 前缀: + +代码块身份:可直接照写示例 + +```tsl +a := array(("cls": "A", "en": 90), ("cls": "A", "en": 80), ("cls": "B", "en": 85)); +distinct_rows := select distinct ["cls"] from a end; +distinct_sum := vselect sumof(distinct ["en"]) from a end; +writeLn(mrows(distinct_rows)); +writeLn(distinct_sum); +``` + +代码块身份:输出片段 + +```text +2 +255 +``` + +说明: + +- `select distinct [字段]` 折叠重复行 +- `sumof(distinct [字段])` 只对不同值求和:`90 + 80 + 85 = 255` + +### `as` 别名、`as nil` 与字段区间 + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "cls": "A", "en": 90), ("id": "02", "cls": "B", "en": 80)); +alias_rows := select ["en"] as "score" from a end; +nil_rows := select ["id"], ["en"] * 2 as nil from a end; +range_rows := select 0 to 1 from a end; +writeLn(alias_rows[0]["score"]); +writeLn(mcols(nil_rows)); +writeLn(mcols(range_rows)); +``` + +代码块身份:输出片段 + +```text +90 +1 +2 +``` + +说明: + +- `字段 as "别名"` 给结果列改名 +- `表达式 as nil` 让该列只参与临时计算,不出现在结果集里(上例 `nil_rows` 只剩 `id` 一列) +- `StartIndex to EndIndex` 在选择列表里取列区间;`0 to 1` 返回第 0、1 两列 + +### `drange` 取行区间 + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01"), ("id": "02"), ("id": "03"), ("id": "04")); +head_rows := select drange(0 to 1) * from a end; +tail_rows := select drange(-2 to -1) * from a end; +part_rows := select drange(1 of 2) * from a end; +writeLn(mrows(head_rows)); +writeLn(tail_rows[0]["id"]); +writeLn(mrows(part_rows)); +``` + +代码块身份:输出片段 + +```text +2 +03 +2 +``` + +说明: + +- `drange(begin to end)` 取行区间;负数从末尾计(`-1` 是最后一行) +- `drange(M of N)` 把结果集等分成 N 份,取第 M 份 + +### `selectopt` 位选项 + +代码块身份:可直接照写示例 + +```tsl +a := array(("en": 90), ("en": 80), ("en": 85), ("en": 85)); +opt_rows := select selectopt(2) ["en"] from a end; +writeLn(dataType(opt_rows)); +writeLn(opt_rows[0]); +``` + +代码块身份:输出片段 + +```text +4 +90 +``` + +说明: + +- `selectopt(N)` 用位组合改变返回形态;`selectopt(2)` 让 `select` 返回一维数组(不再是二维结果集) +- 常用位:`1`=单值、`2`=一维、`4`=Matrix、`16`=多字段聚集保留原名、`64`=MovingFirst 变换 + +### 条件聚集、移动聚集与 `refof` + +聚集函数统一支持 `(Expr, BoolConditionExp, N, MovingFirst, CacheId)` 形态: + +代码块身份:可直接照写示例 + +```tsl +a := array(("en": 90), ("en": 80), ("en": 85), ("en": 85)); +cond_sum := vselect sumof(["en"], ["en"] >= 85) from a end; +moving := select avgof(["en"], true, 2, true) from a end; +ref_prev := select ["en"], refof(["en"], 1) from a end; +writeLn(cond_sum); +writeLn(moving[2]["Expr1"]); +writeLn(ref_prev[1]["Expr1"]); +``` + +代码块身份:输出片段 + +```text +260 +82.5 +90 +``` + +说明: + +- 条件聚集:`sumof(表达式, 布尔条件)` 只统计条件为真的行(`90 + 85 + 85 = 260`) +- 移动聚集:`avgof(表达式, 条件, N, MovingFirst)` 取当前行往前 N 条的滑动统计 +- `refof(表达式, N)` 引用前 N 行的值(`N` 为负则往后);首行无前值时返回 `0` + +### `group by ... having` + +`having` 用聚集条件筛选分组(`where` 不能用聚集): + +代码块身份:可直接照写示例 + +```tsl +a := array(("cls": "A", "en": 90), ("cls": "A", "en": 80), ("cls": "B", "en": 85)); +having_rows := select ["cls"] from a group by ["cls"] having countof(["cls"]) > 1 end; +writeLn(mrows(having_rows)); +writeLn(having_rows[0]["cls"]); +``` + +代码块身份:输出片段 + +```text +1 +A +``` + +说明: + +- `having 聚集条件` 在分组后筛选(上例只保留成员数大于 1 的 `A` 组) +- `having` 里的计数用 `countof([字段])` 或 `countof(1)` + +代码块身份:反例 / 不可照写 + +```text +having_rows := select ["cls"] from a group by ["cls"] having countof(*) > 1 end; +``` + +`countof(*)` 这种带 `*` 的写法不成立,会报 `CountOf ( not found`。计数改用 `countof([字段])` 或 `countof(1)`。 + +### `thisOrder` 与多列 `order by` + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "en": 90), ("id": "02", "en": 80), ("id": "03", "en": 85), ("id": "04", "en": 85)); +order_rows := select ["id"], thisOrder as "ord" from a order by ["en"] end; +desc_rows := select ["id"] from a order by ["en"] desc end; +writeLn(order_rows[0]["id"], ",", order_rows[0]["ord"]); +writeLn(desc_rows[0]["id"]); +``` + +代码块身份:输出片段 + +```text +02,1 +01 +``` + +说明: + +- `thisOrder` 返回排序后的自然排名(从 1 起,值相同则同名次,名次可不连续) +- `order by [字段] desc` 降序;多列排序用逗号分隔:`order by ["cls"] asc, ["en"] desc` +- `thisOrder` 与 `thisRowIndex` 不同:后者返回排序前的原始行位置 + +### `refsof` 引用上级结果集 + +在嵌套子查询里,`refsof(Exp, UpLevel)` 用上 N 级结果集计算 `Exp`: + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "en": 90), ("id": "02", "en": 80)); +r := select ["id"], (vselect refsof(["en"], 1) from a end) as "up" from a end; +writeLn(r[0]["id"], ",", r[0]["up"]); +writeLn(r[1]["id"], ",", r[1]["up"]); +``` + +代码块身份:输出片段 + +```text +01,90 +02,80 +``` + +说明: + +- `refsof(表达式, 1)` 在内层子查询里引用上一级(外层)结果集当前行的值 +- 数字越大引用越靠外层;脱离嵌套单独使用会报 `no result set for reference` + +### `[@Field]` 取字段类型 + +代码块身份:可直接照写示例 + +```tsl +a := array(("id": "01", "en": 90), ("id": "02", "en": 80)); +t := select ["id"], [@"en"] from a end; +writeLn(t[0]["Expr1"]); +``` + +代码块身份:输出片段 + +```text +integer +``` + +说明: + +- `[@字段名]` 返回该字段的数据类型名(字符串),可用于 select 列表与 update set + +### `aggof` 自定义聚集扩展 + +> 代码块身份:仅服务端可执行示例 +> 本地 `TSL.exe` 会报 `AggOf Init Error`;下例在服务端(pyTSL)验证通过。 + +`aggof('名称', 表达式)` 调用一个自定义回调函数做聚集: + +代码块身份:仅服务端可执行示例 + +```tsl +Table1 := array(("C": 1), ("C": 2), ("C": 3), ("C": 4), ("C": 5)); +return vselect aggof('AggSumSample', ['C']) from Table1 end; + +function AggSumSample(Flag, Value); +begin + if Flag = 0 then + begin + sysParams['SumSample'] := 0; + return true; + end + else if Flag = 1 then + begin + sysParams['SumSample'] := sysParams['SumSample'] + Value; + return true; + end + else + return sysParams['SumSample']; +end; +``` + +说明(上例返回 `15`): + +- 回调签名固定为 `function Name(Flag, Value)` +- `Flag=0` 初始化(`Value` 为真表示 `distinct`),返回 `true`/`false` 表示成败 +- `Flag=1` 每行数据,`Value` 是当前行表达式的值,返回 `true`/`false` +- `Flag=2` 结束,返回最终聚集结果 +- 状态用 `sysParams[...]` 缓存,不要用 `static` + ## 本页不生成的范围 -- `with on` -- `left join` / `right join` / `full join` -- `RefsOf` -- `insert` / `update` / `delete` -- `TSQLInsert` / `TSQLSetValue` / `TSQLBatchInsert` -- `TSQLEdit` / `TSQLPost` / `TSQLFinal` -- 面向 SQL 表、业务表或时间序列的数据查询与写回 +- `TSQLInsert` / `TSQLSetValue` / `TSQLBatchInsert` / `TSQLEdit` / `TSQLPost` / `TSQLFinal` 对象被 TS-SQL 查询的回调机制 +- 面向 SQL 表、业务表或时间序列的数据查询与写回(`marketTable` / `infoTable` / `tradeTable` / `sqlTable` / `hugeSqlTable` 等数据源) -这些内容不作为本页可生成事实;业务数据源先查 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md)、[../modules/pytsl_api.md](../modules/pytsl_api.md) 或项目实际接口。 +这些内容不作为本页可生成事实;业务数据源先查 [../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/)、[../modules/pytsl_api.md](../modules/pytsl_api.md) 或项目实际接口。 ## 默认生成模板 @@ -301,7 +868,18 @@ query_result := select * from source_rows end; - 处理一维数组时直接把 `[0]` 当成稳定列访问。 - 把 `thisGroup` 当成普通字段或普通变量。 - 把排序后的 `thisRowIndex` 误当成排序序号。 -- 把 `with on`、写回接口和时间序列缓存写进默认模板。 +- 在 `left join` 时省略 `on` 子句或不用 `[表序号].["字段"]` 形式。 +- 在 `insert` 时漏掉 `insertfields` 或字段数与值数不匹配。 +- 期望 `update`/`delete` 返回新数组;它们直接修改原数组。 +- 用 `countof(*)` 数行数;`*` 星号形式不被支持,改用 `countof([字段])` 或 `countof(1)`。 + +代码块身份:反例 / 不可照写 + +```text +n := vselect countof(*) from source_rows end; +``` + +`countof(*)` 会报 `CountOf ( not found`。数行数改用 `countof([字段])` 或 `countof(1)`。 代码块身份:反例 / 不可照写 diff --git a/docs/tsl/syntax/15_debug_and_profiler.md b/docs/tsl/syntax/15_debug_and_profiler.md index ad64b618..ff35661f 100644 --- a/docs/tsl/syntax/15_debug_and_profiler.md +++ b/docs/tsl/syntax/15_debug_and_profiler.md @@ -28,7 +28,7 @@ - `debugRunEnv(0)` 和 `debugRunEnv(1)` 可直接调用;它们面向调试客户端的副作用,不作为本页输出事实。 - `debugRunEnvDo Func(...)` 可直接写,并且会返回被调用函数的结果。 - `mtic` 会生成一个计时起点;`mtoc` 和 `mtoc(tick)` 都会返回秒数。 -- `setProfiler(...)` 和 `getProfilerInfo(...)` 的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md);本页只保留性能分析器行为示例。 +- `setProfiler(...)` 和 `getProfilerInfo(...)` 的参数规格见 [../codegen/builtin/system.md](../codegen/builtin/system.md);本页只保留性能分析器行为示例。 - `setProfiler(7)` 配合 `getProfilerInfo(1)`,可以在不弹窗的情况下拿到性能分析器信息。 - `__line__` 会返回所在代码行号。 - `__stack_frame` 会返回调用栈帧数组;最小 `toStn(...)` 观察结果里,每一项是 `(line, "function")` 这一类二元组。 @@ -108,9 +108,9 @@ writeLn("before"); a := Inner(3); writeLn("after"); -function Inner(bb); +function Inner(value); begin - debugReturn bb; + debugReturn value; end; ``` @@ -144,8 +144,8 @@ writeLn(1); 代码块身份:可直接照写示例 ```tsl -r := debugRunEnvDo Demo(2); -writeLn(r); +result := debugRunEnvDo Demo(2); +writeLn(result); function Demo(x); begin @@ -165,17 +165,17 @@ end; 代码块身份:可直接照写示例 ```tsl -t1 := mtic; -s := 0; +tick1 := mtic; +sum := 0; for i := 0 to 9999 do - s := s + i; -te1 := mtoc(t1); -t2 := mtic; + sum := sum + i; +elapsed1 := mtoc(tick1); +tick2 := mtic; for j := 0 to 9999 do - s := s + j; -te2 := mtoc; -writeLn(te1 >= 0); -writeLn(te2 >= 0); + sum := sum + j; +elapsed2 := mtoc; +writeLn(elapsed1 >= 0); +writeLn(elapsed2 >= 0); ``` 结果说明: @@ -189,9 +189,9 @@ writeLn(te2 >= 0); ```tsl setProfiler(7); -a := 99; -b := intToStr(a); -c := rand(10, 1); +value := 99; +str := intToStr(value); +random := rand(10, 1); info := getProfilerInfo(1); writeLn(ifArray(info)); writeLn(length(info) > 0); @@ -210,8 +210,8 @@ writeLn(length(info) > 0); 代码块身份:可直接照写示例 ```tsl -a := __line__; -writeLn(a); +line_number := __line__; +writeLn(line_number); ``` 结果说明: @@ -224,8 +224,8 @@ writeLn(a); 代码块身份:可直接照写示例 ```tsl -s := Outer(); -writeLn(toStn(s)); +stack := Outer(); +writeLn(toStn(stack)); function Inner(); begin 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 0aeceaf8..cfe1f044 100644 --- a/docs/tsl/syntax/16_lexical_structure_and_compile_options.md +++ b/docs/tsl/syntax/16_lexical_structure_and_compile_options.md @@ -170,6 +170,30 @@ writeLn(1); - 输出 `1` - 说明未命中的条件编译分支不会参与脚本编译 +### `{$CompileOption}` 编译选项 + +`{$CompileOption}` 用于设置编译期开关,改变编译器的默认行为: + +代码块身份:可直接照写示例 + +```tsl +{$CompileOption optimize=1} +echo 1 + 1; +``` + +代码块身份:输出片段 + +```text +2 +``` + +说明: + +- `{$CompileOption optimize=1}` 开启优化 +- 编译选项从出现位置开始生效,直到源文件结束或被其他选项覆盖 +- 常见选项包括 `optimize`、`buffermode`、`DebugInfo` 等 +- 编译选项细节以项目工具链和实际编译命令为准。 + ### 参数默认传递开关 `{$varByRef-}` 与 `{$varByRef+}`: @@ -190,23 +214,23 @@ r := 1; TouchRestored(r); writeLn(r); -function TouchDefault(a); +function TouchDefault(value); begin - a := 9; + value := 9; end; {$varByRef-} -function TouchValue(a); +function TouchValue(value); begin - a := 8; + value := 8; end; -function TouchForcedVar(var a); +function TouchForcedVar(var value); begin - a := 7; + value := 7; end; {$varByRef+} -function TouchRestored(a); +function TouchRestored(value); begin - a := 6; + value := 6; end; ``` diff --git a/docs/tsl/syntax/17_types_and_conversions.md b/docs/tsl/syntax/17_types_and_conversions.md index 558fd6e9..fedd8d96 100644 --- a/docs/tsl/syntax/17_types_and_conversions.md +++ b/docs/tsl/syntax/17_types_and_conversions.md @@ -45,6 +45,7 @@ - `dataType(z)` 对复数返回 `41`,`ifComplex(z)` 对复数返回 `1`。 - `real`、`imag`、`conj`、`abs` 都可用于复数。 - 实数 `x` 与复数 `x + 0j` 的相等比较结果为真。 +- 复数支持四则运算 `+` / `-` / `*` / `/`,可与实数混合运算;矩阵乘用 `:*`。 - `complex(array(...), imag)` 会返回 `Array`;`complex(fmarray..., imag)` 会返回 `FMArray`,并且其单元格类型是 `41`。 ## 可直接照写示例 @@ -138,14 +139,14 @@ writeLn(nan = nan); ```tsl writeLn(a); -h := new Holder(); -writeLn(h.value = nil); +holder := new Holder(); +writeLn(holder.Value = nil); arr := array(); writeLn(arr[0] = nil); type Holder = class public - value; + Value; end; ``` @@ -153,7 +154,7 @@ end; - 依次输出 `0`、`1`、`1` - 说明未初始化普通变量默认是整数 `0` -- 说明类成员默认值是 `nil` +- 说明类成员默认值是 `nil`(`holder.Value`) - 也说明空数组读取尚未赋值的下标时,结果是 `nil` `nil` 的显式判定与加法边界: @@ -304,6 +305,46 @@ writeLn(f[0], ',', f[1], ',', f[2]); - 上述复数 `FMArray` 的单元格类型 `dataType(f, 1)` 是 `41` - 该 `FMArray` 长度是 `3`,三个元素依次是 `1+5.5j`、`2+5.5j`、`3+5.5j` +复数四则运算: + +代码块身份:可直接照写示例 + +```tsl +z1 := 4 + 3j; +z2 := 5 + 12j; +writeLn(z1 + z2); +writeLn(z2 - z1); +writeLn(z1 * z2); +writeLn(z2 / z1); +``` + +结果说明: + +- `z1 + z2` 得 `9.0+15.0j` +- `z2 - z1` 得 `1.0+9.0j` +- `z1 * z2` 得 `-16.0+63.0j` +- `z2 / z1` 得 `2.24+1.32j` +- 复数参与运算后实部虚部按浮点显示(带 `.0`) +- 复数在四则运算上和实数写法一致,也支持与实数混合运算 + +复数矩阵乘 `:*`: + +代码块身份:可直接照写示例 + +```tsl +a := array((-1 + 1j), (-3 + 1j)); +b := array((2 + 2j, 1 + 3j)); +writeLn(tostn(a :* b)); +``` + +结果说明: + +- 复数矩阵同样用 `:*` 做矩阵乘(区别于逐单元乘 `*`),矩阵乘除乘方算符体系见 [22_matrix_deep_dive.md](22_matrix_deep_dive.md) +- `a` 是 `2 x 1`、`b` 是 `1 x 2`,`a :* b` 得 `2 x 2` 结果矩阵 +- 结果是 `array((-4.0+0.0j,-4.0-2.0j),(-8.0-4.0j,-6.0-8.0j))` + +> 版本边界:复数相关功能只在新一代客户端与新一代服务器支持;本节示例在支持复数的运行环境(如新一代服务端)验证。虚数单位固定用 `j`,不是 `i`。 + 复数最短骨架: 代码块身份:可直接照写示例 diff --git a/docs/tsl/syntax/18_external_calls_and_threads.md b/docs/tsl/syntax/18_external_calls_and_threads.md index c42ea820..2886955f 100644 --- a/docs/tsl/syntax/18_external_calls_and_threads.md +++ b/docs/tsl/syntax/18_external_calls_and_threads.md @@ -113,10 +113,10 @@ function TickCdecl(): int64; cdecl; external "kernel32.dll" name "GetTickCount64 代码块身份:可直接照写示例 ```tsl -t1 := Tick64(); +tick_before := Tick64(); SleepMs(20); -t2 := Tick64(); -writeLn(t2 >= t1); +tick_after := Tick64(); +writeLn(tick_after >= tick_before); function Tick64(): int64; stdcall; external "kernel32.dll" name "GetTickCount64"; procedure SleepMs(ms: integer); stdcall; external "kernel32.dll" name "Sleep"; @@ -132,15 +132,15 @@ procedure SleepMs(ms: integer); stdcall; external "kernel32.dll" name "Sleep"; 代码块身份:可直接照写示例 ```tsl -h := LoadLibraryA("kernel32.dll"); -fp := GetProcAddress(h, "GetTickCount64"); -f := function(): int64; stdcall; external fp; -writeLn(h <> nil); -writeLn(fp <> nil); -writeLn(##f() > 0); +module_handle := LoadLibraryA("kernel32.dll"); +func_ptr := GetProcAddress(module_handle, "GetTickCount64"); +wrapped_func := function(): int64; stdcall; external func_ptr; +writeLn(module_handle <> nil); +writeLn(func_ptr <> nil); +writeLn(##wrapped_func() > 0); -function LoadLibraryA(s: string): pointer; stdcall; external "kernel32.dll" name "LoadLibraryA"; -function GetProcAddress(hModule: pointer; lpProcName: string): pointer; stdcall; external "kernel32.dll" name "GetProcAddress"; +function LoadLibraryA(lib_name: string): pointer; stdcall; external "kernel32.dll" name "LoadLibraryA"; +function GetProcAddress(module_handle: pointer; proc_name: string): pointer; stdcall; external "kernel32.dll" name "GetProcAddress"; ``` 结果说明: @@ -155,17 +155,17 @@ function GetProcAddress(hModule: pointer; lpProcName: string): pointer; stdcall; 代码块身份:可直接照写示例 ```tsl -d := new Demo(); -writeLn(d.Run()); +demo := new Demo(); +writeLn(demo.Run()); type Demo = class public - const kernel_dll = "kernel32.dll"; + const kKernelDll = "kernel32.dll"; function Run(); begin return TickConst() > 0; end; - function TickConst(): int64; stdcall; external kernel_dll name "GetTickCount64"; + function TickConst(): int64; stdcall; external kKernelDll name "GetTickCount64"; end; ``` @@ -189,10 +189,10 @@ function TickFromExpr(): int64; stdcall; external "kernel32"$"."$"dll" name "Get 代码块身份:可直接照写示例 ```tsl -fp := makeInstance(thisFunction(Add), "cdecl", 0); -f := function(a: integer; b: integer): integer; external fp; -writeLn(fp <> nil); -writeLn(##f(3, 4)); +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)); function Add(a: integer; b: integer): integer; begin @@ -212,19 +212,19 @@ end; ```tsl setGlobalCache("THREAD_TEST_KEY", 0); -fp := makeInstance(thisFunction(Worker), "cdecl", 1); -h := CreateThread(nil, nil, fp, nil, 0, tid); -writeLn(fp <> nil); -writeLn(h <> nil); -writeLn(WaitForSingleObject(h, 5000) >= 0); -getGlobalCache("THREAD_TEST_KEY", v); -writeLn(v); -CloseHandle(h); +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); +writeLn(WaitForSingleObject(thread_handle, 5000) >= 0); +getGlobalCache("THREAD_TEST_KEY", result_value); +writeLn(result_value); +CloseHandle(thread_handle); function CreateThread(attr: pointer; size: pointer; addr: pointer; p: pointer; flag: Integer; var thread_id: Integer): pointer; stdcall; external "kernel32.dll" name "CreateThread"; -function WaitForSingleObject(h: pointer; timeout: Integer): Integer; stdcall; external "kernel32.dll" name "WaitForSingleObject"; -function CloseHandle(h: pointer): Integer; stdcall; external "kernel32.dll" name "CloseHandle"; -function Worker(p: pointer): integer; +function WaitForSingleObject(handle: pointer; timeout: Integer): Integer; stdcall; external "kernel32.dll" name "WaitForSingleObject"; +function CloseHandle(handle: pointer): Integer; stdcall; external "kernel32.dll" name "CloseHandle"; +function Worker(param: pointer): integer; begin setGlobalCache("THREAD_TEST_KEY", 1); return 1; diff --git a/docs/tsl/syntax/19_namespace_libpath_and_unit_runtime.md b/docs/tsl/syntax/19_namespace_libpath_and_unit_runtime.md index 97ec18d2..15bf0551 100644 --- a/docs/tsl/syntax/19_namespace_libpath_and_unit_runtime.md +++ b/docs/tsl/syntax/19_namespace_libpath_and_unit_runtime.md @@ -35,7 +35,7 @@ - 直接写 `DemoUnit.Member` 时,可以读到 `interface` 和 `implementation` 里的常量、变量。 - `findFunction("DemoUnit")` 拿到的是 `unit` 对象入口;本页只把它稳定暴露 `interface` 成员写成文档事实。 - `DemoUnit.var_name := value` 这种限定赋值不作为可写事实;如果要改 `unit` 状态,应导出函数或方法来改。 -- `tslfilename()` 的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md);本页只保留它返回正在执行的 `.tsl` 主脚本完整路径这一行为事实。 +- `tslfilename()` 的参数规格见 [../codegen/builtin/system.md](../codegen/builtin/system.md);本页只保留它返回正在执行的 `.tsl` 主脚本完整路径这一行为事实。 - `namespace "DemoNS";` 会选择 `Hello@DemoNS.tsf` 这类命名空间函数文件。 - `tsl.conf` 的 `[system] Namespace=...` 可以设置默认命名空间;脚本里的 `namespace "..."` 会覆盖配置值。 - 当全局 `Hello.tsf` 和 `Hello@StmtNS.tsf` 同时存在时,启用 `StmtNS` 后会优先命中命名空间版本。 diff --git a/docs/tsl/syntax/20_object_runtime_and_introspection.md b/docs/tsl/syntax/20_object_runtime_and_introspection.md index a309c1a8..72d3d7b5 100644 --- a/docs/tsl/syntax/20_object_runtime_and_introspection.md +++ b/docs/tsl/syntax/20_object_runtime_and_introspection.md @@ -18,7 +18,7 @@ 2. 普通对象创建、普通方法调用、类声明和继承都回到 [08_objects_and_classes.md](08_objects_and_classes.md),不要把 `findClass(...)` / `createObject(...)` 当默认写法。 3. 确实命中反射时,入口优先照 `findClass`、`findFunction`、`thisFunction`、`findOverLoad` 等文档明确示例写。 4. 访问弱引用前先做 `checkWeakRef(...)` 判定,不要假设失效弱引用安全返回 `nil`。 -5. 类内 `weakRef;` / `autoRef;` 段落式写法属于反例,不要照写。 +5. 类内段落式 `weakRef` / `autoRef`(不带分号)是合法的成员弱引用开关;只有带分号的 `weakRef;` / `autoRef;` 才报 `invalid class definition`。 6. 函数值调用边界回看函数页,避免把函数指针直接当普通函数调用。 7. 没有对应代码块时不要发明对象运行时/反射/弱引用写法。 @@ -48,7 +48,7 @@ - 对已经失效的弱引用直接调用 `weakref_get(w)` 会运行报错,不要把它当成“安全返回 nil”的接口。 - 类成员上的 `[weakRef] field;` 和 `[autoRef] field;` 可以通过。 - `[weakRef]` 成员不会阻止对象析构;强引用释放后,对象会正常销毁。 -- 类内段落式 `weakRef;` / `autoRef;` 不作为可写事实,错误信息包含 `invalid class definition`。 +- 类内段落式 `weakRef` / `autoRef`(不带分号)像 `public` / `private` 一样切换后续成员的弱引用属性,可写;只有带分号的 `weakRef;` / `autoRef;` 才报 `invalid class definition`。 ## 可直接照写示例 @@ -84,12 +84,12 @@ end; ```tsl classA := findClass("A"); obj := new A(); -writeLn(classA.FucA()); +writeLn(classA.FuncA()); writeLn(obj is classA); type A = class public - class function FucA(); + class function FuncA(); begin return "ClassA"; end; @@ -110,18 +110,18 @@ end; ```tsl objb := new ClassB(); obj := findClass("ClassA", objb); -writeLn(obj.Fuc()); +writeLn(obj.Func()); type ClassA = class public - function Fuc(); virtual; + function Func(); virtual; begin return "ClassA"; end; end; type ClassB = class(ClassA) public - function Fuc(); override; + function Func(); override; begin return "ClassB"; end; @@ -183,10 +183,10 @@ end; 代码块身份:可直接照写示例 ```tsl -oa := new ca("abc"); +oa := new Ca("abc"); writeLn(objectstate(oa)); -type ca = class +type Ca = class public static sca; function create(n); @@ -208,20 +208,20 @@ end; 代码块身份:可直接照写示例 ```tsl -o := new ca(); +o := new Ca(); o.c := 3; writeLn(o.c); -type ca = class +type Ca = class public value; - property c read getc write setc; - function setc(v); + property c read Getc write Setc; + function Setc(v); begin writeLn(tslassigning); value := v; end; - function getc(); + function Getc(); begin writeLn(tslassigning); return value; @@ -302,16 +302,16 @@ end; 代码块身份:可直接照写示例 ```tsl -t := findOverLoad(2, "fun", new TestClass()); +t := findOverLoad(2, "Fun", new TestClass()); writeLn(t.do(1, 2)); type TestClass = class public - function fun(p1, p2); overload; + function Fun(p1, p2); overload; begin return p1 + p2; end; - function fun(p1); overload; + function Fun(p1); overload; begin return p1 + 10; end; @@ -321,7 +321,7 @@ end; 结果说明: - 输出 `3` -- 说明 `findOverLoad(2, "fun", obj)` 可以按参数个数拿到对应重载方法 +- 说明 `findOverLoad(2, "Fun", obj)` 可以按参数个数拿到对应重载方法 ### 函数信息、对象枚举与生命周期 @@ -356,14 +356,15 @@ end; 代码块身份:可直接照写示例 ```tsl -objA := new TestClass01(100); -objB := new TestClass01(101); objsInfo := tslObjects(1); writeLn(length(objsInfo["TestClass01"])); newObjA := objsInfo["TestClass01"][0, "obj"]; writeLn(newObjA is class(TestClass01)); writeLn(newObjA.add(1, 2)); +objA := new TestClass01(100); +objB := new TestClass01(101); + type TestClass01 = class public value; @@ -371,7 +372,7 @@ public begin value := _value; end; - class function add(x, y); + class function Add(x, y); begin return x + y; end; @@ -556,7 +557,7 @@ end; - 不要把 `objectstate(self)` 里的 `self` 泛化成普通成员访问都要加 `self` 前缀。 - 不要把弱引用能力的条件编译宏写成 `weakRef`。 - 不要以为 `weakref_get(deadWeakRef)` 会像普通可空访问那样安全返回 `nil`。 -- 不要以为类内段落式 `weakRef;` / `autoRef;` 也能直接通过。 +- 不要给段落切换关键字加分号;`weakRef;` / `autoRef;`(带分号)会报 `invalid class definition`,段落式要写成不带分号的 `weakRef` / `autoRef`。 - 不要以为 `[weakRef]` 成员会继续强持有对象。 代码块身份:反例 / 不可照写 @@ -573,4 +574,33 @@ public end; ``` -上面这种把 `weakRef;` / `autoRef;` 当作类内段落切换的写法不作为可写事实,会编译失败,错误信息包含 `invalid class definition`。 +上面这种给段落切换关键字**加分号**(`weakRef;` / `autoRef;`)的写法会编译失败,错误信息包含 `invalid class definition`。关键在分号:段落切换关键字要像 `public` / `private` 那样**不带分号**独占一行,带分号后被当成独立语句才报错。正确的段落式写法见下一段。 + +段落式 `weakRef` / `autoRef`(不带分号)像 `public` / `private` 一样切换后续成员的弱引用属性: + +代码块身份:可直接照写示例 + +```tsl +o := new AutoWeakTest(); +o.fa := 1; +o.fb := 2; +writeLn(o.fa, ',', o.fb); + +type AutoWeakTest = class +public + fa; +weakRef + fOnClick; + fOnDblClick; +autoRef + fb; +end; +``` + +结果说明: + +- 输出 `1,2` +- `weakRef`(不带分号)打开后续成员的自动弱引用开关,`fOnClick` / `fOnDblClick` 成为弱引用成员 +- `autoRef`(不带分号)关闭开关,`fb` 恢复为强引用成员 +- 段落切换只影响其后、下一个切换关键字之前的成员;`fa` 在初始(强引用)段 +- 这与行内 `[weakRef] field;` 是两种可用写法:行内只作用于单个成员,段落式作用于整段 diff --git a/docs/tsl/syntax/21_builtin_runtime_objects.md b/docs/tsl/syntax/21_builtin_runtime_objects.md index 3936bfd3..dd042fbf 100644 --- a/docs/tsl/syntax/21_builtin_runtime_objects.md +++ b/docs/tsl/syntax/21_builtin_runtime_objects.md @@ -46,13 +46,13 @@ 代码块身份:可直接照写示例 ```tsl -obj := new TStringList(); -obj.CommaText := "A=aaa,B=bbb,C=222"; -writeLn(obj[1]); -writeLn(obj["B"]); -writeLn(obj.Count); -obj.Add("D=444"); -writeLn(obj.Count); +list := new TStringList(); +list.CommaText := "A=aaa,B=bbb,C=222"; +writeLn(list[1]); +writeLn(list["B"]); +writeLn(list.Count); +list.Add("D=444"); +writeLn(list.Count); ``` 结果说明: @@ -65,11 +65,11 @@ writeLn(obj.Count); 代码块身份:可直接照写示例 ```tsl -obj := new THashedStringList(); -obj.Add("A=aaa"); -obj.Add("B=bbb"); -writeLn(obj.Count); -writeLn(obj["B"]); +list := new THashedStringList(); +list.Add("A=aaa"); +list.Add("B=bbb"); +writeLn(list.Count); +writeLn(list["B"]); ``` 结果说明: diff --git a/docs/tsl/syntax/22_matrix_deep_dive.md b/docs/tsl/syntax/22_matrix_deep_dive.md index dbbf8f8a..9d58c5cc 100644 --- a/docs/tsl/syntax/22_matrix_deep_dive.md +++ b/docs/tsl/syntax/22_matrix_deep_dive.md @@ -6,11 +6,11 @@ 是否含不可照写反例:是 遇到不确定时:先按本页候选页继续判断;[12_matrix_and_collections.md](12_matrix_and_collections.md)、[23_fmarray.md](23_fmarray.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md) -这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`12` 讲普通数组与集合关系,这一篇讲矩阵专用构造、遍历、子矩阵和矩阵查找接口。 +这一篇只讲矩阵专用语法主干:矩阵初始化、数列构造、矩阵逆/广义逆、矩阵乘除乘方、矩阵转置、矩阵拼接、矩阵尺寸与索引、矩阵遍历、子矩阵和 `mfind` 查找。它和 [12_matrix_and_collections.md](12_matrix_and_collections.md) 的分工是:`12` 讲普通数组与集合关系,这一篇讲矩阵专用构造、运算、遍历、子矩阵和矩阵查找接口。 ## 本篇职责 -回答“怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。 +回答”怎样直接构造全零矩阵、全一矩阵、随机矩阵、单位矩阵、空矩阵和数列数组,怎样写矩阵逆/广义逆,怎样进行矩阵乘除乘方,怎样转置矩阵,怎样拼接矩阵,怎样拿到矩阵的行数、列数、行索引和列索引,怎样遍历矩阵、取/改子矩阵,以及怎样用 `mfind` 找到或替换符合条件的单元格”。 ## 智能体矩阵深水判断流程 @@ -26,7 +26,7 @@ ## 核心规则 -- 矩阵初始化函数的参数规格见 [../reference/catalog/math.md](../reference/catalog/math.md);本页只保留矩阵行为示例和返回形态边界。 +- 矩阵初始化函数的参数规格见 [../codegen/builtin/math.md](../codegen/builtin/math.md);本页只保留矩阵行为示例和返回形态边界。 - `zeros(...)`、`ones(...)`、`rand(...)`、`nils(...)`、`eye(...)` 都可以直接用于矩阵初始化。 - `zeros(3)`、`ones(3)`、`nils(2)` 这类单参数写法可以直接生成一维结果。 - `zeros(2, 3)`、`rand(2, 3)` 这类双参数写法可以直接生成二维矩阵。 @@ -34,7 +34,7 @@ - `eye(3)` 生成的是 `3 x 3` 单位矩阵,不是一维数组。 - `->` 用来生成数列;默认步长是 `1`,也可以显式传入步长和索引数组。 - 在矩阵语境里,`!A` 是一元倒数运算符作用于矩阵的形态,用于矩阵逆/广义逆;非方阵输入可以返回行列数互换后的广义逆结果。 -- `msize(...)`、`mrows(...)`、`mcols(...)` 的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md)。 +- `msize(...)`、`mrows(...)`、`mcols(...)` 的参数规格见 [../codegen/special/pending/system/01_data_type.md](../codegen/special/pending/system/01_data_type.md)。 - `msize(matrix_value)` 返回 `array(行数, 列数)`。 - `msize(matrix_value, 1)` 返回行索引数组和列索引数组。 - `mrows(matrix_value)` / `mcols(matrix_value)` 默认返回数量;第二个参数写成 `1` 时返回索引数组。 @@ -527,6 +527,380 @@ B 0 ``` +### 矩阵乘法、除法、乘方:`:*`、`:/`、`:^` + +`:*` 是矩阵乘法(区别于逐元素乘 `*`): + +代码块身份:可直接照写示例 + +```tsl +a := array((1, 2), (3, 4)); +b := array((5, 6), (7, 8)); +element_wise := a * b; +matrix_multiply := a :* b; +writeLn("逐元素乘 (0,0):", element_wise[0][0]); +writeLn("矩阵乘 (0,0):", matrix_multiply[0][0]); +writeLn("矩阵乘 (0,1):", matrix_multiply[0][1]); +writeLn("矩阵乘 (1,0):", matrix_multiply[1][0]); +writeLn("矩阵乘 (1,1):", matrix_multiply[1][1]); +``` + +代码块身份:输出片段 + +```text +逐元素乘 (0,0): 5 +矩阵乘 (0,0): 19 +矩阵乘 (0,1): 22 +矩阵乘 (1,0): 43 +矩阵乘 (1,1): 50 +``` + +说明: + +- `*` 是逐元素乘(element-wise),`a * b` 的 `(0,0)` 是 `1 * 5 = 5` +- `:*` 是真正的矩阵乘法,`a :* b` 的 `(0,0)` 是 `1*5 + 2*7 = 19` +- 矩阵乘法要求左矩阵列数等于右矩阵行数 + +`:/` 是矩阵除法(等价于 `A :* !B`): + +代码块身份:可直接照写示例 + +```tsl +a := array((1, 2), (3, 4)); +b := array((2, 0), (0, 2)); +result := a :/ b; +writeLn(result[0][0]); +writeLn(result[0][1]); +writeLn(result[1][0]); +writeLn(result[1][1]); +``` + +代码块身份:输出片段 + +```text +0.5 +1 +1.5 +2 +``` + +`:\` 是矩阵左除(等价于 `!A :* B`,常用于解线性方程组): + +代码块身份:可直接照写示例 + +```tsl +a := array((2, 0), (0, 4)); +b := array((4), (8)); +result := a :\ b; +writeLn(result[0][0]); +writeLn(result[1][0]); +``` + +代码块身份:输出片段 + +```text +2 +2 +``` + +说明: + +- `:\` 左除用于解线性方程组 `A * X = B`,等价于 `X = A^(-1) * B` +- **右侧 `b` 必须是列向量**(用 `array((4), (8))` 而非 `array(4, 8)`) +- `a :\ b` 返回 `array((2.0), (2.0))`,即 `X` 的列向量 +- 当 A 行数 > 列数时返回最小二乘解,行数 < 列数时返回一个可行解 + +`:^` 是矩阵乘方(`A :^ 2` 等价于 `A :* A`): + +代码块身份:可直接照写示例 + +```tsl +a := array((1, 1), (0, 1)); +pow2 := a :^ 2; +manual := a :* a; +writeLn("pow (0,0):", pow2[0][0]); +writeLn("pow (0,1):", pow2[0][1]); +writeLn("pow (1,1):", pow2[1][1]); +writeLn("manual (0,1):", manual[0][1]); +``` + +代码块身份:输出片段 + +```text +pow (0,0): 1 +pow (0,1): 2 +pow (1,1): 1 +manual (0,1): 2 +``` + +复合赋值算符: + +代码块身份:可直接照写示例 + +```tsl +a := array((1, 2), (3, 4)); +b := array((1, 0), (0, 1)); +a :*= b; +writeLn(a[0][0]); +``` + +代码块身份:输出片段 + +```text +1 +``` + +说明: + +- `:*=`、`:/=`、`:\=`、`:^=` 分别是矩阵乘、除、左除、乘方的复合赋值形式 +- `a :*= b` 等价于 `a := a :* b` + +### 基础函数的矩阵广播与异常处理参数 + +多参数基础函数支持逐参数广播: + +代码块身份:可直接照写示例 + +```tsl +data := array(1.55, 2.99, 3.85); +precision := array(-1, 0, 0); +result := RoundTo(data, precision); +writeLn(result[0]); +writeLn(result[1]); +writeLn(result[2]); +``` + +代码块身份:输出片段 + +```text +1.6 +3 +4 +``` + +说明: + +- `RoundTo(data, precision)` 对两个数组逐元素配对:`RoundTo(1.55, -1)` → `1.6`、`RoundTo(2.99, 0)` → `3.0` +- 规则:为每个参数寻找一个或一组匹配者,逐参数广播 + +基础函数尾部可追加异常处理参数 `ErrDefine` 和 `ErrReplace`: + +代码块身份:可直接照写示例 + +```tsl +data := array(4, -1, 9); +result := sqrt(data, 1, -999); +writeLn(tostn(result)); +``` + +代码块身份:输出片段 + +```text +array(2.0,NAN,3.0) +``` + +说明: + +- `sqrt(data, 1, -999)` 中,第二参数 `ErrDefine=1` 表示允许 NIL 值不允许错误值 +- `ErrReplace=-999` 是错误位置的替换值(本例中 `-1` 的平方根为错误,但 `ErrDefine=1` 保留为 NAN) +- `ErrDefine` 取值:`0`=不允许错误和 NIL、`1`=允许 NIL 不允许错误、`2`=错误值保留为原值 +- `ErrReplace` 在 `ErrDefine=0` 或 `1` 时生效,用于替换错误/NIL 位置 + +另一个例子: + +代码块身份:可直接照写示例 + +```tsl +data := array(1, nil, "AAA", -100); +result := abs(data, 0, -999); +writeLn(tostn(result)); +``` + +代码块身份:输出片段 + +```text +array(1,-999,-999,100) +``` + +说明: + +- `abs(data, 0, -999)` 中,`ErrDefine=0` 不允许错误和 NIL +- `nil` 和 `"AAA"` 都被替换成 `-999` +- 对于多参数基础函数,`ErrDefine` 和 `ErrReplace` 总是可以作为可选参数添加在最后 + +### 矩阵转置:反引号 `` ` `` + +单次转置交换行列: + +代码块身份:可直接照写示例 + +```tsl +a := array((1, 2, 3), (4, 5, 6)); +transposed := `a; +writeLn("原矩阵行数:", mrows(a)); +writeLn("原矩阵列数:", mcols(a)); +writeLn("转置后行数:", mrows(transposed)); +writeLn("转置后列数:", mcols(transposed)); +writeLn("转置 (0,0):", transposed[0][0]); +writeLn("转置 (1,0):", transposed[1][0]); +writeLn("转置 (2,0):", transposed[2][0]); +``` + +代码块身份:输出片段 + +```text +原矩阵行数: 2 +原矩阵列数: 3 +转置后行数: 3 +转置后列数: 2 +转置 (0,0): 1 +转置 (1,0): 2 +转置 (2,0): 3 +``` + +一维数组转置成列向量: + +代码块身份:可直接照写示例 + +```tsl +b := array(1, 2, 3); +col_vector := `b; +writeLn("一维长度:", length(b)); +writeLn("列向量行数:", mrows(col_vector)); +writeLn("列向量列数:", mcols(col_vector)); +``` + +代码块身份:输出片段 + +```text +一维长度: 3 +列向量行数: 3 +列向量列数: 1 +``` + +双转置把一维数组变成行向量(常用于 `union` 追加行): + +代码块身份:可直接照写示例 + +```tsl +b := array(1, 2, 3); +row_vector := ``b; +writeLn("行向量行数:", mrows(row_vector)); +writeLn("行向量列数:", mcols(row_vector)); +writeLn("行向量 (0,0):", row_vector[0][0]); +writeLn("行向量 (0,1):", row_vector[0][1]); +writeLn("行向量 (0,2):", row_vector[0][2]); +``` + +代码块身份:输出片段 + +```text +行向量行数: 1 +行向量列数: 3 +行向量 (0,0): 1 +行向量 (0,1): 2 +行向量 (0,2): 3 +``` + +说明: + +- `` `a `` 是后缀算符,写在矩阵变量或表达式之后 +- 一维数组 `b` 转置一次成列向量(3行1列),转置两次成行向量(1行3列) +- 双转置技巧常配合 `union` 逐行追加数据 + +### 矩阵拼接:`union`、`&=`、`|`、`:|` + +`union` 按行拼接(一维或二维): + +代码块身份:可直接照写示例 + +```tsl +a := array(1, 2, 3); +b := array(4, 5, 6); +result := a union b; +writeLn(length(result)); +writeLn(result[0]); +writeLn(result[3]); +writeLn(result[5]); +``` + +代码块身份:输出片段 + +```text +6 +1 +4 +6 +``` + +`&=` 是 `union` 的复合赋值形式(注意不是 `union=`): + +代码块身份:可直接照写示例 + +```tsl +a := array(1, 2, 3); +b := array(4, 5, 6); +a &= b; +writeLn(length(a)); +writeLn(a[5]); +``` + +代码块身份:输出片段 + +```text +6 +6 +``` + +`|` 按列拼接: + +代码块身份:可直接照写示例 + +```tsl +a := array((1, 2), (3, 4)); +b := array((5, 6), (7, 8)); +result := a | b; +writeLn("列数:", mcols(result)); +writeLn("(0,2):", result[0][2]); +writeLn("(1,3):", result[1][3]); +``` + +代码块身份:输出片段 + +```text +列数: 4 +(0,2): 5 +(1,3): 8 +``` + +`:|` 对非完全矩阵补 `nil`,`|` 不补: + +代码块身份:可直接照写示例 + +```tsl +a := array((1, 2, 3), (2, 3)); +colon_result := a :| a; +bar_result := a | a; +writeLn("colon 结果列数:", mcols(colon_result)); +writeLn("colon (1,2):", colon_result[1][2]); +writeLn("bar 结果 (1,2):", bar_result[1][2]); +``` + +代码块身份:输出片段 + +```text +colon 结果列数: 6 +colon (1,2): nil +bar 结果 (1,2): 1 +``` + +说明: + +- `union` / `&=` 用于行方向拼接 +- `|` / `:|` 用于列方向拼接 +- 非完全矩阵(行长度不一致)用 `:|` 会在缺位补 `nil`,而 `|` 不补 +- 对应的复合赋值形式:`&=`(行并)、`|=`(列并)、`:|=`(列并补 nil) + ## 默认生成模板 需要矩阵构造时,优先从这个最短模板开始: @@ -541,12 +915,18 @@ matrix_value := zeros(2, 3); - 把 `eye(3)` 当成一维数组。 - 把 `!A` 当成逻辑非表达式。 +- 把 `*` 当成矩阵乘法;矩阵乘法使用 `:*`。 +- 把 `:*`、`:/`、`:\`、`:^` 当成逐元素运算;逐元素运算使用 `*`、`/`、`^`。 +- 在 `:\` 左除时,右侧用一维数组而非列向量;右侧必须用 `array((v1), (v2), ...)` 形式。 - 以为 `mrows(matrix_value, 1)` 和 `mcols(matrix_value, 1)` 返回的还是数量。 - 写带步长的 `->` 时,漏掉外层 `array(...)`。 - 还在普通数组页里硬塞矩阵专用大小接口。 - 把 `::=` 写成带 `begin ... end` 的语句块。 - 用 `::` 期待遍历到任意深度;深度遍历使用 `:.`。 - 子矩阵赋值时用形状不匹配的矩阵硬塞。 +- 把 `union` 的复合赋值写成 `union=`;正确写法是 `&=`。 +- 一维数组直接 `union` 期待得到二维结果;需要先双转置 `` ``b `` 变成行向量。 +- 在基础函数异常参数时用分号分隔;正确写法用逗号:`sqrt(data, 1, -999)`。 代码块身份:反例 / 不可照写 diff --git a/docs/tsl/syntax/23_fmarray.md b/docs/tsl/syntax/23_fmarray.md index b04ca4ca..ad5d771c 100644 --- a/docs/tsl/syntax/23_fmarray.md +++ b/docs/tsl/syntax/23_fmarray.md @@ -25,7 +25,7 @@ - `fmarray[...]` 可以直接构造 `FMArray` 常量。 - `dataType(v)` 对 `FMArray` 返回 `27`。 - `dataType(v, 1)` 可以读出 `FMArray` 单元格类型;本页文档类型包括 `0` 整型、`1` 浮点、`20` 64 位整型。 -- FMArray 相关函数的参数规格见 [../reference/catalog/system.md](../reference/catalog/system.md) 和 [../reference/catalog/math.md](../reference/catalog/math.md);本页只保留 FMArray 行为示例和返回形态边界。 +- FMArray 相关函数的参数规格见 [../codegen/special/pending/system/01_data_type.md](../codegen/special/pending/system/01_data_type.md) 和 [../codegen/builtin/math.md](../codegen/builtin/math.md);本页只保留 FMArray 行为示例和返回形态边界。 - `ifFmarray(v)` 可直接判断值是否为 `FMArray`。 - `mInit`、`mInitDiag`、`mRand` 都可直接生成 `FMArray`。 - `arrayToFm` 和 `matrixToArray` 可在 `Array` / `FMArray` 间互转。 diff --git a/docs/tsl/syntax/24_object_overloads_and_iteration.md b/docs/tsl/syntax/24_object_overloads_and_iteration.md index 543c1647..7aa93f2c 100644 --- a/docs/tsl/syntax/24_object_overloads_and_iteration.md +++ b/docs/tsl/syntax/24_object_overloads_and_iteration.md @@ -22,8 +22,8 @@ ## 核心规则 -- 对象二元算符重载的最小可靠形态是成员方法 `function operator + (data);` 这一类写法。 -- 比较算符可写成 `function operator < (data, isLeft);`,用 `isLeft` 区分对象在左边还是右边。 +- 对象二元算符重载的最小可靠形态是成员方法 `function operator + (other);` 这一类写法。 +- 比较算符可写成 `function operator < (other, is_left);`,用 `is_left` 区分对象在左边还是右边。 - 对象 `[]` 读取有两种文档明确写法:`function operator[](index);` 和 `function operator[0](index, s1);`。 - 对象 `[]` 写入的文档明确写法是 `function operator[1](index, v);`。 - `function operator for(flag);` 可以重载 `for in`。 @@ -31,7 +31,7 @@ - `mrows` / `mcols` / `msize` 可以在类里先声明 `function operator mrows(n);` 这类签名,再在类外实现 `function operator ClassName.mrows(n);`。 - 可用形态包括 `mrows(obj)`、`mcols(obj)`、`msize(obj)` 这类关键字调用,以及 `obj.mcols(1)` 这类对象方法式调用。 - `function operator++(v);` 和 `function operator += (v);` 也可用。 -- 不要把未写入文档资料里的裸 `function operator;` / `function operator1;`,或未列入本页的 `mcell` / `mrow` / `mcol` / `::` / `:.` 重载,直接当成语法事实。 +- 不要把未写入文档资料里的裸 `function operator;` / `function operator1;` 直接当成语法事实。`::` / `:.` / `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 的重载本页已给出可照写形态,照本页示例写即可。 ## 可直接照写示例 @@ -40,46 +40,49 @@ 代码块身份:可直接照写示例 ```tsl -t1 := new TComplex(); -t1.vReal := 10; -t1.vImaginary := 100; -t2 := t1 + 10; -writeLn(t2.vReal); -writeLn(t1 < 5); -writeLn(t1 < 300); -writeLn(5 < t1); +c1 := new Complex(); +c1.RealPart := 10; +c1.ImaginaryPart := 100; +c2 := c1 + 10; +writeLn(c2.RealPart); +writeLn(c1 < 5); +writeLn(c1 < 300); +writeLn(5 < c1); -type TComplex = class +type Complex = class public - vReal; - vImaginary; - function operator + (data); + property RealPart read real_part_ write real_part_; + property ImaginaryPart read imaginary_part_ write imaginary_part_; + function operator + (other); begin - r := new TComplex(); - if ifNumber(data) then + sum := new Complex(); + if ifNumber(other) then begin - r.vReal := vReal + data; + sum.RealPart := real_part_ + other; end else begin - r.vReal := vReal + data.vReal; - r.vImaginary := vImaginary + data.vImaginary; + sum.RealPart := real_part_ + other.RealPart; + sum.ImaginaryPart := imaginary_part_ + other.ImaginaryPart; end - return r; + return sum; end; - function operator < (data, isLeft); + function operator < (other, is_left); begin - if ifNumber(data) then + if ifNumber(other) then begin - v := vReal < data; + less := real_part_ < other; end else begin - v := (vReal ^ 2 + vImaginary ^ 2) < data.vReal ^ 2 + data.vImaginary ^ 2; + less := (real_part_ ^ 2 + imaginary_part_ ^ 2) < other.RealPart ^ 2 + other.ImaginaryPart ^ 2; end - if not isLeft then v := not v; - return v; + if not is_left then less := not less; + return less; end; +private + real_part_; + imaginary_part_; end; ``` @@ -87,7 +90,8 @@ end; - 依次输出 `20`、`0`、`1`、`1` - 说明 `obj + value` 可以通过成员 `operator +` 接管 -- 说明带 `isLeft` 的比较算符可以同时处理 `obj < value` 和 `value < obj` +- 说明带 `is_left` 的比较算符可以同时处理 `obj < value` 和 `value < obj` +- 私有成员用尾随下划线的 `real_part_` / `imaginary_part_`,对外用 `PascalCase` property 暴露 代码块身份:输出片段 @@ -104,12 +108,12 @@ end; ```tsl t := array(1, 2, 3, 4, 5); -b := new bb(t); +b := new IndexableBox(t); writeLn(b[2]); b[3] := 999; writeLn(b.data[3]); -type bb = class +type IndexableBox = class public data; function create(v); @@ -139,7 +143,7 @@ end; 代码块身份:配置片段 / 概念骨架 ```tsl -type bb = class +type IndexableBox = class public // 其余字段、create()、operator[1] 和测试主体同上一段 function operator[0](index, s1); @@ -265,16 +269,16 @@ end; 代码块身份:可直接照写示例 ```tsl -b := new bb(10); -++b; -writeLn(b.data); -c := b++; +counter := new Counter(10); +++counter; +writeLn(counter.data); +c := counter++; writeLn(c.data); -writeLn(b.data); -b += 5; -writeLn(b.data); +writeLn(counter.data); +counter += 5; +writeLn(counter.data); -type bb = class +type Counter = class public data; function create(v); @@ -285,7 +289,7 @@ public begin if v = 0 then begin - r := new bb(); + r := new Counter(); r.data := data; r.data++; return r; @@ -304,22 +308,250 @@ end; - 依次输出 `11`、`11`、`12`、`17` - 说明前置 `++` 会直接修改对象状态 -- 说明这个最小样例里,后置 `b++` 返回的是递增前快照 -- 说明 `operator += (v)` 可以接管 `b += 5` +- 说明这个最小样例里,后置 `counter++` 返回的是递增前快照 +- 说明 `operator += (v)` 可以接管 `counter += 5` + +`--` 与 `-=` 与之对称: + +代码块身份:可直接照写示例 + +```tsl +counter := new Counter(10); +counter -= 3; +writeLn(counter.data); + +type Counter = class +public + data; + function create(v); + begin + data := v; + end; + function operator--(v); + begin + if v = 0 then + begin + r := new Counter(); + r.data := data; + r.data--; + return r; + end + else + data--; + end; + function operator -= (v); + begin + data -= v; + end; +end; +``` + +结果说明: + +- 输出 `7` +- 说明 `operator -= (v)` 可以接管 `counter -= 3` +- `operator--(v)` 与 `operator++(v)` 结构对称:`v = 0` 分支返回递减前快照,否则原地递减 + +### 二进制函数重载:`operator funcName` + +除了符号算符,`operator` 还能重载具名的全局二进制函数(如 `DateToStr`、`TryStrToInt` 等)。定义写成 `[class] function operator funcName(...)`:`class` 关键字可选,加上表示类方法,不加表示成员函数。 + +成员函数重载(参数比原函数少 1 个,用第一个参数的对象实例调用): + +代码块身份:可直接照写示例 + +```tsl +d := new IntDate(20240329); +writeLn(DateToStr(d)); + +type IntDate = class +public + value; + function create(v); + begin + value := v; + end; + function operator DateToStr(); + begin + v := IntToDate(value); + return DateToStr(v); + end; +end; +``` + +结果说明: + +- 输出 `2024-03-29` +- 说明 `DateToStr(d)` 被对象的成员 `operator DateToStr` 接管 +- 成员函数重载时参数个数比原二进制函数少 1 个,第一个实参(对象本身)用于定位方法 + +类方法重载(`class function`,参数与原函数一致): + +代码块身份:可直接照写示例 + +```tsl +d := new IntDate2(20240329); +writeLn(DateToStr(d)); + +type IntDate2 = class +public + value; + function create(v); + begin + value := v; + end; + class function operator DateToStr(t); + begin + t := ifObj(t) ? t.value : t; + return DateToStr(IntToDate(t)); + end; +end; +``` + +结果说明: + +- 输出 `2024-03-29` +- 说明 `class function operator DateToStr(t)` 作为类方法接管调用,参数个数与原二进制函数一致 + +类内用 `::` 调同名全局函数(避免重载递归): + +代码块身份:可直接照写示例 + +```tsl +c := new ClassA(); +c.value := "314"; +ret := TryStrToInt(c, msg); +writeLn(tostn(array(ret, msg))); + +type ClassA = class +public + value; + function operator TryStrToInt(msg); + begin + return ::TryStrToInt(value, msg); + end; +end; +``` + +结果说明: + +- 输出 `array(1,314)`:`ret` 为 `1`(转换成功),出参 `msg` 为 `314` +- 说明类内需要调用被重载的同名全局函数时,用 `::` 前缀指定全局版本,否则会递归回自己 +- 重载函数支持通过参数传出返回值(`msg` 作为出参被赋值) + +### `::` / `:.` 遍历重载与 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` + +重载 `::`(二维遍历)或 `:.`(深度遍历)后,对象就能像矩阵一样被 `obj::begin ... end` 遍历。遍历体里用到的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex(n)` 也各自重载,返回当前单元的值、行下标、列下标、维度数和第 `n` 维下标。`operator ::(flag)` 的 `flag` 为 `0` 表示第一次循环、`1` 表示后续循环,返回 `0` 或 `nil` 结束遍历、返回非零数字继续: + +代码块身份:可直接照写示例 + +```tsl +t := array("A": 0 -> 3, "B": 10 -> 2, "C": 20 -> 21); +traversable := new TraversableMatrix(t); +traversable::begin + echo "mcell:", mcell, " mrow:", mrow, " mcol:", mcol, " mIndexCount:", mIndexCount, "\r\n"; +end + +type TraversableMatrix = class +public + data; + Rdata; + findex; + lengtD; + function create(v); + begin + data := v; + end; + function operator ::(flag); + begin + if not flag then + begin + Rdata := array(); + k := 0; + data::begin + Rdata[k] := array(mcell, mIndexCount, mrow, mcol); + if mIndexCount > 2 then for i := 2 to mIndexCount - 1 do Rdata[k, i + 2] := mIndex(i); + k++; + end + lengtD := length(Rdata); + findex := 0; + end + else if findex < lengtD - 1 then findex++; + else return nil; + return 1; + end; + function operator mcell(); + begin + return Rdata[findex][0]; + end; + function operator mIndexCount(); + begin + return Rdata[findex][1]; + end; + function operator mrow(); + begin + return Rdata[findex][2]; + end; + function operator mcol(); + begin + return Rdata[findex][3]; + end; + function operator mIndex(n); + begin + if n < Rdata[findex][1] then + return Rdata[findex][n + 2]; + else raise "指定的维度超出最大维度数"; + end; +end; +``` + +结果说明: + +- 逐行输出每个单元的 `mcell` / `mrow` / `mcol` / `mIndexCount`,遍历顺序与被代理的 `data` 一致 +- `operator ::(flag)` 里 `flag=0` 时初始化把 `data` 的遍历结果缓存进 `Rdata`,之后每次推进 `findex` +- 返回 `1` 表示继续、返回 `nil` 表示结束 +- `:.`(深度遍历)重载方式与 `::` 相同,把内部 `data::begin ... end` 换成 `data:.begin ... end` 即可 +- 遍历体里用到的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 必须各自重载,否则报 `override function not found` + +### 关键字函数重载:`msize` / `mrows` / `mcols` + +`msize` / `mrows` / `mcols` 这类关键字函数也能重载,形态同二进制函数重载 `[class] function operator KeyWord(...)`,但**关键字重载不需要 `::` 指定全局**: + +代码块身份:可直接照写示例 + +```tsl +grid := new GridData(); +writeLn(mcols(grid)); + +type GridData = class +public + fa; + function create(); + begin + fa := array(("A": 1, "B": 2, "C": 3), ("A": 5, "B": 5, "C": 5)); + end; + function operator mcols(); + begin + return mcols(fa); + end; +end; +``` + +结果说明: + +- 输出 `3`:`mcols(grid)` 被对象的 `operator mcols()` 接管,返回内部 `fa` 的列数 +- 关键字函数重载与二进制函数重载写法一致,但类内调用同名关键字函数不需要 `::` 前缀 ## 本页不生成的范围 -- `::` / `:.` 遍历重载 -- `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` - 多级 `[]` 下标重载 - 右侧算术如 `value + obj` -- 对基础二进制函数的大规模重载族 这些名称只作为边界提示,不作为本页可生成模板。 ## 禁止项 - 不要从本页 `operator` 示例外推未写入文档的重载族。 -- 不要把 `mcell` / `mrow` / `mcol` / `::` / `:.` 直接写成可用语法。 +- 重载 `::` / `:.` 遍历时,不要漏掉配套的 `mcell` / `mrow` / `mcol` / `mIndexCount` / `mIndex` 重载,否则遍历体会报 `override function not found`。 - 不要把多级 `[]` 下标重载或 `value + obj` 这类右侧算术写成文档事实。 - 不要在本页发明普通类语法;基础对象模型回 [08_objects_and_classes.md](08_objects_and_classes.md)。 diff --git a/docs/tsl/syntax/index.md b/docs/tsl/syntax/index.md index a6eff0b6..49da95a7 100644 --- a/docs/tsl/syntax/index.md +++ b/docs/tsl/syntax/index.md @@ -90,6 +90,6 @@ ## 切换到别的层 -- 数据仓库金融函数:见 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md) +- 数据仓库金融函数:见 [../codegen/dotnet/datawarehouse/](../codegen/dotnet/datawarehouse/) - 模块 / 集成 / 互操作:见 [../modules/index.md](../modules/index.md) -- 函数库查找:见 [../reference/index.md](../reference/index.md) +- 函数库查找:见 [../codegen/index.md](../codegen/index.md)