📝 docs(tsl-syntax-reference): document external and remote calls
This commit is contained in:
@@ -24,7 +24,14 @@
|
||||
"方括号": ["operator", "下标"],
|
||||
"按引用传": ["varByRef", "var"],
|
||||
"引用传递": ["varByRef", "var"],
|
||||
"计时": ["mtic", "mtoc"]
|
||||
"计时": ["mtic", "mtoc"],
|
||||
"外部调用": ["external", "动态库", "函数指针"],
|
||||
"动态库常驻": ["KeepResident", "external"],
|
||||
"外部出参": ["external", "var", "ABI"],
|
||||
"函数指针释放": ["DeleteInstance", "MakeInstance"],
|
||||
"Linux 动态加载": ["dlopen", "dlsym", ".so"],
|
||||
"远程调用客户端": ["RDo", "RDo2", "客户端远程调用"],
|
||||
"本地弹窗": ["RDo2", "InputQuery", "客户端远程调用"]
|
||||
},
|
||||
"page_intent_aliases": {
|
||||
"01_quickstart.md": ["最简单能跑", "最简单的脚本", "天软脚本", "tinysoft"],
|
||||
@@ -77,7 +84,17 @@
|
||||
"注释怎么写"
|
||||
],
|
||||
"16_types_and_conversions.md": ["字符串转整数", "类型转换"],
|
||||
"17_external_calls_and_threads.md": ["调用 dll", "dll", "动态库", "开线程"],
|
||||
"17_external_calls_and_threads.md": [
|
||||
"调用 dll",
|
||||
"dll",
|
||||
"动态库",
|
||||
"外部调用",
|
||||
"KeepResident",
|
||||
"外部出参",
|
||||
"函数指针释放",
|
||||
"Linux 动态加载",
|
||||
"开线程"
|
||||
],
|
||||
"18_namespace_libpath_and_unit_runtime.md": ["找不到 tsf", "搜索路径"],
|
||||
"19_object_runtime_and_introspection.md": [
|
||||
"查看对象属于哪个类",
|
||||
@@ -93,6 +110,13 @@
|
||||
"运算符重载",
|
||||
"算符重载",
|
||||
"for in"
|
||||
],
|
||||
"24_client_remote_calls.md": [
|
||||
"客户端远程调用",
|
||||
"远程调用客户端",
|
||||
"rdo",
|
||||
"rdo2",
|
||||
"本地弹窗"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ TSL 关键字大小写无关;本表统一按文档推荐写法展示。生成
|
||||
| LIKE 精度 | `likeEps`、`likeEpsRate` | 只在需要调整 `like` 数值近似判断阈值时使用。 |
|
||||
| 类与对象 | `type`、`class`、`new`、`findClass`、`findFunction`、`fackClass`、`property`、`self`、`virtual`、`override`、`overload`、`Inherited`、`protected`、`public`、`private`、`published`、`static` | 类声明、对象创建和成员规则见 [08_objects_and_classes.md](08_objects_and_classes.md);`Inherited;` / `Inherited MethodName(...)` 是祖先类调用写法,同见该页。 |
|
||||
| 外部调用约定 | `external`、`cdecl`、`pascal`、`stdcall`、`safecall`、`fastcall`、`register` | 外部调用细节见 [17_external_calls_and_threads.md](17_external_calls_and_threads.md)。 |
|
||||
| 客户端远程调用与权限 | `rdo`、`rdo2`、`sudo`、`setUid` | 平台/客户端远程调用和权限语义不作为普通本地语法模板。 |
|
||||
| 客户端远程调用与权限 | `rdo`、`rdo2`、`sudo`、`setUid` | `rdo` / `rdo2` 见 [24_client_remote_calls.md](24_client_remote_calls.md);它们不能建模成普通函数。 |
|
||||
| TS-SQL 查询 | `select`、`vselect`、`sselect`、`mselect`、`distinct`、`selectOpt`、`dRange`、`as`、`from`、`marketTable`、`infoTable`、`tradeTable`、`sqlTable`、`hugeSqlTable`、`keepNull`、`dateKey`、`of`、`order`、`by`、`where`、`desc`、`asc`、`group`、`having` | 查询语法见 [13_ts_sql.md](13_ts_sql.md)。 |
|
||||
| TS-SQL 聚合与上下文 | `checksumOf`、`countOf`、`sumOf`、`maxOf`、`stdevOf`、`varOf`、`totalVarOf`、`normOf`、`medianOf`、`aveDevOf`、`geoMeanOf`、`skewOf`、`kurtosisOf`、`skew2Of`、`kurtosis2Of`、`largeOf`、`percentileOf`、`quartileOf`、`trimMeanOf`、`avgOf`、`minOf`、`aggOf`、`stdevpOf`、`varpOf`、`modeOf`、`devSqOf`、`harMeanOf`、`checksum_aggOf`、`smallOf`、`percentRankOf`、`rankOf`、`frequencyOf`、`productOf`、`refOf`、`refsOf`、`aggValue`、`thisGroup`、`thisRow`、`thisRowIndex`、`thisOrder` | 这些名称只在 TS-SQL 语境中生成。 |
|
||||
| TS-SQL 写入 | `insert`、`insertFields`、`values`、`update`、`set`、`delete`、`deleteOpt`、`fetchFirst`、`fetchNext` | 写回/变更型查询只按 TS-SQL 专题页生成。 |
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# TSL 外部调用与线程
|
||||
|
||||
这一篇吸收函数专题里和外部系统交互有关的部分:`external`、动态库调用、原生函数指针包装、C 回调和线程调用。
|
||||
本页说明动态库声明、原生函数指针、C 回调和线程调用。`MakeInstance`、`DeleteInstance` 是 builtin API;`external`、`name`、`KeepResident`、`cdecl`、`stdcall` 和外部参数声明是语法。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-17-001 -->
|
||||
|
||||
回答“外部 DLL 声明、原生函数指针包装、C 回调和多线程调用有哪些文档明确写法”。本页只覆盖系统交互能力,普通 TSL 函数的定义与调用不在本页收口。
|
||||
回答外部动态库、函数指针、C 回调和线程调用的写法。`LoadLibraryA`、`GetProcAddress`、`dlopen`、`dlsym` 是宿主 API;`TSL_ScriptGo` 等 `TSSVRAPI.h` 名称是 C/C++ SDK API,均不进入 TSL builtin 索引。
|
||||
|
||||
## 核心规则
|
||||
|
||||
@@ -14,14 +14,112 @@
|
||||
|
||||
- 外部函数声明的文档明确形态是 `function Name(...): Type; stdcall|cdecl; external "dll" [name "symbol"];`。
|
||||
- 当 TSL 函数名和 DLL 导出名一致时,`name "symbol"` 可以省略。
|
||||
- Windows 示例默认显式写调用约定;不要把省略调用约定当成跨平台默认规则。
|
||||
- Win32 下调用约定必须与宿主函数一致;Linux 与 Win64 下 `stdcall` 和 `cdecl` 使用相同调用模式。
|
||||
- 无返回值的外部接口可声明为 `procedure Name(...); ... external ...;`。
|
||||
- 外部函数需要写回调用方变量时,在参数名前写 `var`;TSL 参数类型必须与原生 ABI 的参数宽度和含义一致。
|
||||
- `KeepResident` 写在外部库声明末尾,用于保留动态库句柄。
|
||||
- `function(...): ...; external fp;` 可以把原生函数指针重新包装成 TSL 可调用对象。
|
||||
- DLL 名写法包括字面量字符串和类常量字符串;不要把字符串拼接表达式直接当成稳定写法。
|
||||
- `makeInstance(thisFunction(Func), "cdecl", 0)` 可以把 TSL 函数包装成 C 调用约定函数指针。
|
||||
- Windows 线程示例用 `makeInstance(..., "cdecl", 1)` 生成可交给 `CreateThread` 的回调指针。
|
||||
- 外部库名和调用约定要按目标平台选择;不要把 Windows 的 `kernel32.dll` 示例直接复制到 Linux,或把 Linux 的 `.so` 示例直接复制到 Windows。
|
||||
- 本页线程示例是 Windows 专题,用到了 `kernel32.dll`。
|
||||
- 库名可使用字面量字符串或类常量字符串,不能使用字符串拼接表达式。
|
||||
- `MakeInstance(thisFunction(Func), "cdecl", 0)` 或 `MakeInstance(findFunction("Func"), "cdecl", 0)` 可以把有完整参数及返回类型声明的 TSL 函数包装成 C 调用约定函数指针。
|
||||
- `DeleteInstance(ptr)` 用于删除 `MakeInstance` 生成的指针;包装出来的 TSL 函数变量应先解除引用,再删除原始指针。
|
||||
- Windows 线程示例用 `MakeInstance(..., "cdecl", 1)` 生成可交给 `CreateThread` 的回调指针。
|
||||
- 外部库名按目标平台选择:Windows 使用 DLL,Linux 使用对应 `.so`。
|
||||
- 文档列出的基础外部类型包括 `Integer`、`String`、`Double`、`Single`、`Boolean`、`Pointer`、`PChar`、`Int64`、`Short` 和 `Byte`,未列出的类型按 `String` 处理。结构体等复合类型仍须按原生 ABI 组装内存;不能直接导入 C++ 引出类。
|
||||
|
||||
## 外部 ABI 与动态库常驻
|
||||
|
||||
<!-- section-id: syntax-17-012 -->
|
||||
|
||||
<!-- tags: KeepResident 动态库常驻 external ABI 类型映射 -->
|
||||
|
||||
`external` 是 TSL 与宿主 ABI 的边界,不是 builtin 定义。参数类型、宽度、对齐和调用约定必须与原生函数一致;结构体等复合参数须自行封装内存布局。
|
||||
|
||||
`KeepResident` 放在 `external` 库声明末尾,用于要求动态库句柄在调用后保持常驻。例如:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:Linux 示例,依赖 `libc.so.6`。
|
||||
|
||||
```tsl
|
||||
writeLn(GetPidResident() > 0);
|
||||
|
||||
function GetPidResident(): integer; cdecl; external "libc.so.6" name "getpid" KeepResident;
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
```
|
||||
|
||||
## 外部出参与 ABI 写回
|
||||
|
||||
<!-- section-id: syntax-17-013 -->
|
||||
|
||||
<!-- tags: 外部出参 external var 出参 写回调用方 glibc libc time ABI -->
|
||||
|
||||
当外部函数需要通过指针写回调用方变量时,在参数名前使用 `var`。这条规则只说明 TSL 声明形态;具体类型、宽度、对齐和调用约定仍必须与原生函数一致。
|
||||
|
||||
下面用 libc `time` 演示 `var` 外部出参:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:Linux x86_64 示例,依赖 `libc.so.6`;`time_t` 按该 ABI 映射为 `int64`。
|
||||
|
||||
```tsl
|
||||
stamp := 0;
|
||||
result := UnixTime(stamp);
|
||||
writeLn(result > 0);
|
||||
writeLn(stamp = result);
|
||||
|
||||
function UnixTime(var stamp: int64): int64; cdecl; external "libc.so.6" name "time";
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
1
|
||||
```
|
||||
|
||||
`UnixTime` 是脚本别名,`time` 是 libc 导出符号,二者都不是 TSL builtin。
|
||||
|
||||
## Linux 动态加载与函数指针生命周期
|
||||
|
||||
<!-- section-id: syntax-17-014 -->
|
||||
|
||||
<!-- tags: Linux 动态加载 glibc dlsym dlopen external 原生指针 -->
|
||||
|
||||
Linux 可用 `dlopen` / `dlsym` 取得原生函数指针,再用 `external fp` 包装。Windows 对应使用 `LoadLibraryA` / `GetProcAddress`。这些名称都是宿主 API,不是 TSL builtin。
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:Linux 示例,依赖 `libdl.so.2` 和 `libc.so.6`;`1` 为该环境的 `RTLD_LAZY`。
|
||||
|
||||
```tsl
|
||||
module_handle := dlopen("libc.so.6", 1);
|
||||
func_ptr := dlsym(module_handle, "getpid");
|
||||
wrapped_func := function(): integer; cdecl; external func_ptr;
|
||||
writeLn(module_handle <> nil);
|
||||
writeLn(func_ptr <> nil);
|
||||
writeLn(##wrapped_func() > 0);
|
||||
wrapped_func := nil;
|
||||
writeLn(dlclose(module_handle) = 0);
|
||||
|
||||
function dlopen(filename: string; flags: integer): pointer; cdecl; external "libdl.so.2" name "dlopen";
|
||||
function dlsym(handle: pointer; symbol: string): pointer; cdecl; external "libdl.so.2" name "dlsym";
|
||||
function dlclose(handle: pointer): integer; cdecl; external "libdl.so.2" name "dlclose";
|
||||
```
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
```text
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
```
|
||||
|
||||
释放顺序是先将包装变量设为 `nil`,再调用 `dlclose`。
|
||||
|
||||
`MakeInstance` 生成的指针由 `DeleteInstance` 释放;若已包装为 TSL 函数变量,先将包装变量设为 `nil`。示例见 `syntax-17-008`,API 签名见 `tsl-api-reference`。
|
||||
|
||||
## 可直接照写示例
|
||||
|
||||
@@ -41,11 +139,7 @@ writeLn(Tick64Alias() > 0);
|
||||
function Tick64Alias(): int64; stdcall; external "kernel32.dll" name "GetTickCount64";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `1`
|
||||
- 说明 `stdcall` + `external "dll" name "symbol"` 是本页明确的外部函数声明骨架
|
||||
- 也说明 TSL 里的函数名可以和 DLL 导出名不同,再通过 `name "ExportName"` 绑定
|
||||
结果说明:输出 `1`;`name` 用于绑定不同名的导出符号。
|
||||
|
||||
代码块身份:输出片段
|
||||
|
||||
@@ -53,10 +147,10 @@ function Tick64Alias(): int64; stdcall; external "kernel32.dll" name "GetTickCou
|
||||
1
|
||||
```
|
||||
|
||||
Linux / POSIX 环境的同类最小骨架:
|
||||
Linux 的同类声明:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:仅类 Unix 环境可执行(依赖 `libc.so.6`);Windows 下不可照抄,本块只演示 `.so` 库名写法。
|
||||
代码块说明:依赖 `libc.so.6`。
|
||||
|
||||
```tsl
|
||||
writeLn(getpid() > 0);
|
||||
@@ -70,8 +164,6 @@ function getpid(): integer; cdecl; external "libc.so.6";
|
||||
1
|
||||
```
|
||||
|
||||
这段说明 Linux / POSIX 目标下可以用 `.so` 库名声明外部函数;生成代码时仍要先判断用户的目标平台。
|
||||
|
||||
当本地函数名和 DLL 导出名一致时,`name` 可以省略:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
@@ -82,12 +174,9 @@ writeLn(GetTickCount64() > 0);
|
||||
function GetTickCount64(): int64; stdcall; external "kernel32.dll";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
结果说明:输出 `1`。
|
||||
|
||||
- 输出 `1`
|
||||
- 说明当本地函数名和导出名一致时,`name "symbol"` 不是强制写法
|
||||
|
||||
Windows 的同一 API 示例里,省略调用约定与显式 `cdecl` 也列入文档边界:
|
||||
也可以省略调用约定或显式写 `cdecl`:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
@@ -102,8 +191,7 @@ function TickCdecl(): int64; cdecl; external "kernel32.dll" name "GetTickCount64
|
||||
结果说明:
|
||||
|
||||
- 依次输出 `1`、`1`
|
||||
- 这只说明 Windows 的同一 API 示例里,这两种写法属于文档边界
|
||||
- 不要把这个结果直接泛化成“所有平台、所有架构下调用约定都等价”
|
||||
- Win32 下仍须按原函数的真实调用约定声明
|
||||
|
||||
### `procedure external`
|
||||
|
||||
@@ -123,10 +211,7 @@ function Tick64(): int64; stdcall; external "kernel32.dll" name "GetTickCount64"
|
||||
procedure SleepMs(ms: integer); stdcall; external "kernel32.dll" name "Sleep";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `1`
|
||||
- 说明无返回值的外部过程可以直接声明为 `procedure`
|
||||
结果说明:输出 `1`;无返回值接口可声明为 `procedure`。
|
||||
|
||||
### 原生函数指针包装
|
||||
|
||||
@@ -148,10 +233,7 @@ function LoadLibraryA(lib_name: string): pointer; stdcall; external "kernel32.dl
|
||||
function GetProcAddress(module_handle: pointer; proc_name: string): pointer; stdcall; external "kernel32.dll" name "GetProcAddress";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 依次输出 `1`、`1`、`1`
|
||||
- 说明 `function(...); ... external fp;` 不只适用于 `makeInstance(...)` 的结果,也适用于 `GetProcAddress(...)` 返回的原生函数指针
|
||||
结果说明:依次输出 `1`、`1`、`1`;`GetProcAddress(...)` 返回的指针可用 `external fp` 包装。
|
||||
|
||||
### DLL 名的文档边界
|
||||
|
||||
@@ -159,8 +241,6 @@ function GetProcAddress(module_handle: pointer; proc_name: string): pointer; std
|
||||
|
||||
<!-- tags: dll 名写在哪, 库名怎么给, 常量放路径 -->
|
||||
|
||||
类常量字符串:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
@@ -178,12 +258,7 @@ public
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 输出 `1`
|
||||
- 说明类常量字符串(如 `kKernelDll`)可以用于 `external kKernelDll` 这种 DLL 名位置
|
||||
|
||||
不作为可写事实边界:
|
||||
结果说明:输出 `1`;类常量字符串可以用在 DLL 名位置。
|
||||
|
||||
代码块身份:反例 / 不可照写
|
||||
|
||||
@@ -191,21 +266,23 @@ end;
|
||||
function TickFromExpr(): int64; stdcall; external "kernel32"$"."$"dll" name "GetTickCount64";
|
||||
```
|
||||
|
||||
上面这种 DLL 名字符串拼接表达式不作为可写事实,会报 `dll filename const string not found after external`。本页只把字面量字符串和类常量字符串写成可靠规则。
|
||||
字符串拼接会报 `dll filename const string not found after external`。
|
||||
|
||||
### `makeInstance`
|
||||
### `MakeInstance`
|
||||
|
||||
<!-- section-id: syntax-17-008 -->
|
||||
|
||||
<!-- tags: 回调函数, 把 TSL 函数给 C 用, 生成函数实例 -->
|
||||
<!-- tags: 回调函数, 把 TSL 函数给 C 用, 生成函数实例, 函数指针释放, DeleteInstance, MakeInstance 生命周期 -->
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
func_ptr := makeInstance(thisFunction(Add), "cdecl", 0);
|
||||
func_ptr := MakeInstance(thisFunction(Add), "cdecl", 0);
|
||||
wrapped_func := function(a: integer; b: integer): integer; external func_ptr;
|
||||
writeLn(func_ptr <> nil);
|
||||
writeLn(##wrapped_func(3, 4));
|
||||
wrapped_func := nil;
|
||||
writeLn(DeleteInstance(func_ptr));
|
||||
|
||||
function Add(a: integer; b: integer): integer;
|
||||
begin
|
||||
@@ -213,11 +290,7 @@ begin
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- `func_ptr <> nil` 输出 `1`
|
||||
- `##wrapped_func(3, 4)` 输出 `7`
|
||||
- 说明 `makeInstance(...)` 生成的函数指针可以再通过 `function(...); external fp;` 包装回 TSL 侧调用
|
||||
结果说明:依次输出 `1`、`7`、`1`。
|
||||
|
||||
### 线程模式最小正例
|
||||
|
||||
@@ -229,7 +302,7 @@ end;
|
||||
|
||||
```tsl
|
||||
setGlobalCache("THREAD_TEST_KEY", 0);
|
||||
worker_ptr := makeInstance(thisFunction(Worker), "cdecl", 1);
|
||||
worker_ptr := MakeInstance(thisFunction(Worker), "cdecl", 1);
|
||||
thread_handle := CreateThread(nil, nil, worker_ptr, nil, 0, thread_id);
|
||||
writeLn(worker_ptr <> nil);
|
||||
writeLn(thread_handle <> nil);
|
||||
@@ -248,25 +321,13 @@ begin
|
||||
end;
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 依次输出 `1`、`1`、`1`、`1`
|
||||
- 说明 `makeInstance(..., "cdecl", 1)` 可以生成可用于 `CreateThread` 的回调指针
|
||||
- 也说明线程体里的 `setGlobalCache(...)` 可用于这个最小闭环
|
||||
结果说明:依次输出 `1`、`1`、`1`、`1`。
|
||||
|
||||
## 默认生成模板
|
||||
|
||||
<!-- section-id: syntax-17-010 -->
|
||||
|
||||
DLL 引入的最小默认骨架如下:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
|
||||
```tsl
|
||||
writeLn(Tick64Alias() > 0);
|
||||
|
||||
function Tick64Alias(): int64; stdcall; external "kernel32.dll" name "GetTickCount64";
|
||||
```
|
||||
默认使用 `syntax-17-004` 的显式调用约定、`external` 和 `name` 骨架。
|
||||
|
||||
## 禁止项
|
||||
|
||||
@@ -274,5 +335,5 @@ function Tick64Alias(): int64; stdcall; external "kernel32.dll" name "GetTickCou
|
||||
|
||||
- 把 `external` 的 DLL 名直接写成字符串拼接表达式。
|
||||
- 省略了外部函数的参数类型或返回类型。
|
||||
- 把 `makeInstance(...)` 生成的结果默认写成普通函数名直调,而不是先包装或用 `##f(...)`。
|
||||
- 直接把 Windows 线程示例当成跨平台事实。
|
||||
- 把 `MakeInstance(...)` 生成的结果默认写成普通函数名直调,而不是先包装或用 `##f(...)`。
|
||||
- 使用与目标平台不匹配的库名或调用约定。
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# TSL 客户端远程调用
|
||||
|
||||
这一篇只处理 `RDo` / `RDo2` 调用客户端本地函数的语法外形、等待行为、系统参数后缀和超时后缀。
|
||||
|
||||
## 本篇职责
|
||||
|
||||
<!-- section-id: syntax-24-001 -->
|
||||
|
||||
回答“怎样从平台调用客户端本地函数、`RDo` 与 `RDo2` 有什么区别、`With` 与 `TimeOut` 写在哪里,以及为什么不能写成 `RDo(...)` / `RDo2(...)`”。
|
||||
|
||||
## 核心规则
|
||||
|
||||
<!-- section-id: syntax-24-002 -->
|
||||
|
||||
<!-- tags: 客户端远程调用 本地函数 不等待 等待返回 rdo rdo2 -->
|
||||
|
||||
- `RDo` 和 `RDo2` 是客户端远程调用关键字,不是普通函数。
|
||||
- 两者都写在被调用的本地函数之前;圆括号属于本地函数调用,不属于 `RDo` / `RDo2`。
|
||||
- `RDo` 只提交任务,不等待本地函数执行完成,也不取得函数返回值。
|
||||
- `RDo2` 等待本地函数执行完成,并把该函数的结果作为整个表达式的值。
|
||||
- 本地函数需要系统参数时,在调用后追加 `With SysParams`。
|
||||
- `RDo2` 默认超时为 300 秒;需要自定义时,在末尾追加 `TimeOut Seconds`。文档定义的后缀顺序是先 `With`、后 `TimeOut`。
|
||||
- `RDo2` 在客户机执行时需要用户权限许可;依赖客户端资源的函数不能在无 GUI 的命令行解释器中验证其交互结果。
|
||||
- 被调用函数的精确签名、参数写回、返回值及运行时 scope 必须使用 `tsl-api-reference` skill 单独查询;本页只拥有 `RDo` / `RDo2` 的语法形态。
|
||||
|
||||
## `RDo` / `RDo2` 语法与示例
|
||||
|
||||
<!-- section-id: syntax-24-003 -->
|
||||
|
||||
<!-- tags: RDo写法 RDo2写法 InputQuery 客户端输入 对话框 远程调用超时 With系统参数 -->
|
||||
|
||||
原文定义使用下面的元语法;方括号表示可选部分,不是需要写进 TSL 源码的字符:
|
||||
|
||||
代码块身份:配置片段 / 概念骨架
|
||||
|
||||
```text
|
||||
RDo LocalFunctionName(P1; P2; …) [With SysParams];
|
||||
RDo2 LocalFunctionName(P1; P2; …) [With SysParams] [TimeOut Seconds]: Any;
|
||||
```
|
||||
|
||||
`RDo2` 调用客户端 `InputQuery` 的原文范例可整理为:
|
||||
|
||||
代码块身份:可直接照写示例
|
||||
代码块说明:需要平台客户端交互环境、用户权限许可,并要求目标环境提供 `InputQuery`;无 GUI 的命令行解释器不能验证弹窗结果。
|
||||
|
||||
```tsl
|
||||
value := "";
|
||||
if rdo2 InputQuery("Input", "Hint", value) then
|
||||
return value;
|
||||
else
|
||||
return "Canceled";
|
||||
```
|
||||
|
||||
结果说明:
|
||||
|
||||
- 用户确认时,`InputQuery` 返回真,输入内容写回 `value`,脚本返回该字符串。
|
||||
- 用户取消时,`InputQuery` 返回假,脚本返回 `Canceled`。
|
||||
- 这段代码证明的是前缀形态 `rdo2 InputQuery(...)`;`InputQuery` 的 API 事实仍需按目标 scope 单独查询。
|
||||
|
||||
## 禁止项
|
||||
|
||||
<!-- section-id: syntax-24-004 -->
|
||||
|
||||
- 把关键字建模成 `RDo()` 或 `RDo2(...)` 普通函数。
|
||||
- 把被调用本地函数的参数误写成 `RDo2` 自身的参数表。
|
||||
- 声称 `RDo` 会返回客户端函数结果。
|
||||
- 忽略 `RDo2` 的客户端权限与交互环境要求。
|
||||
@@ -316,6 +316,18 @@ class TslSyntaxReferenceTests(unittest.TestCase):
|
||||
self.assertEqual("syntax-05-008", write_result.matches[0].section.id)
|
||||
self.assertEqual("syntax-02-006", diagnose_result.matches[0].section.id)
|
||||
|
||||
def test_external_call_queries_retrieve_platform_and_abi_boundaries(self):
|
||||
cases = {
|
||||
"动态库常驻": "syntax-17-012",
|
||||
"外部出参": "syntax-17-013",
|
||||
"Linux 动态加载": "syntax-17-014",
|
||||
"函数指针释放": "syntax-17-008",
|
||||
}
|
||||
for query, expected_id in cases.items():
|
||||
with self.subTest(query=query):
|
||||
result = lookup.query_sections(query, "write", limit=1)
|
||||
self.assertEqual(expected_id, result.matches[0].section.id)
|
||||
|
||||
def test_index_origin_variants_rank_value_rules_first(self):
|
||||
for query in ("下标从几开始", "下标是从几开始", "请问下标是从几开始"):
|
||||
with self.subTest(query=query):
|
||||
|
||||
Reference in New Issue
Block a user