playbook/docs/tsl/syntax/16_debug_and_profiler.md

278 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Debug And Profiler
文档类型:语法主线
是否可直接用于生成代码:仅部分
是否含已验证可执行示例:是
是否含已验证反例:是
遇到不确定时跳转到:[08_control_flow.md](08_control_flow.md)、[30_runtime_services_and_global_cache.md](30_runtime_services_and_global_cache.md)、[12_pitfalls.md](12_pitfalls.md)
手册位置:第 16 篇,共 32 篇。上一篇:[15_ts_sql.md](15_ts_sql.md)。下一篇:[18_lexical_structure_and_compile_options.md](18_lexical_structure_and_compile_options.md)。
这一篇收拢当前已经验证过的调试、计时、profiler 和调用栈相关入口。
## 这一篇解决什么问题
回答“`goto`、`DebugReturn`、`DebugRunEnv`、`MTIC` / `MTOC`、`SetProfiler`、`__line__` 和 `__stack_frame` 在当前解释器里怎样写、会怎样表现”。
## 必须记住的规则
- `goto label_name;` 当前已验证可用,但目标位置当前以 `label label_name; statement` 这种内联形式最稳。
- 当前正向验证只覆盖“跳到同一函数 / 同一脚本体后面的位置”,不要先把更复杂的跨层跳转边界写成事实。
- `DebugReturn value;` 在当前解释器里会直接结束整段脚本,后面的语句不会继续执行。
- `DebugRunEnv(0)``DebugRunEnv(1)` 当前都可直接调用;它们面向调试客户端的副作用,在 CLI 里不直接可见。
- `DebugRunEnvDo Func(...)` 当前已验证可直接写,并且会返回被调用函数的结果。
- `MTIC` 会生成一个计时起点;`MTOC` 和 `MTOC(tick)` 当前都会返回秒数。
- `SetProfiler(7)` 配合 `GetProfilerInfo(1)`,当前可以在不弹窗的情况下拿到 profiler 信息。
- `__line__` 当前会返回所在代码行号。
- `__stack_frame` 当前会返回调用栈帧数组;最小 `ToSTN(...)` 观察结果里,每一项是 `(line, "function")` 这一类二元组。
## 已验证语法
### `goto`
代码块身份:已验证可执行示例
```tsl
program test;
begin
data := array((1, 2), (3, 4));
target := 3;
found := 0;
for i := 0 to Length(data) - 1 do
begin
for j := 0 to Length(data[i]) - 1 do
begin
if data[i][j] = target then
goto found_label;
end;
end;
WriteLn(0);
goto done_label;
label found_label; found := 1;
WriteLn(found);
label done_label; WriteLn(9);
end.
```
已验证运行结果:
- 依次输出 `1`、`9`
- 说明 `goto found_label;` 当前可以跳到后面的 `label found_label; ...`
- 也说明当前最稳的目标写法是把 `label` 和第一条目标语句放在同一行
跨函数跳转当前没有通过:
代码块身份:反例 / 不可照写
```text
program test;
function Inner();
begin
goto out_label;
end;
begin
Inner();
label out_label; WriteLn(1);
end.
```
已验证结果:
- 上面这段会运行报错,核心信息是 `Goto label can not found!`
- 当前正向验证只覆盖“同一函数 / 同一脚本体后面的位置”
- 不要把 `goto` 泛化成能跨函数跳到外层 `label`
目标 `label` 单独成行当前也没有通过:
代码块身份:反例 / 不可照写
```text
program test;
begin
goto done_label;
label done_label;
WriteLn("after");
end.
```
已验证结果:
- 上面这种把 `label` 单独放一行、下一行再写目标语句的最小例子,在当前解释器里会报 `Statement missing terminator`
- 因此当前手册只把 `label name; statement` 这种内联形式写成已验证事实
### `DEBUGRETURN`
代码块身份:已验证可执行示例
```tsl
program test;
function Inner(bb);
begin
DebugReturn bb;
end;
begin
WriteLn("before");
a := Inner(3);
WriteLn("after");
end.
```
已验证运行结果:
- 只输出 `before`
- 说明 `DebugReturn bb;` 不只是结束 `Inner(...)`,而是直接让整段脚本提前返回
- 因此 `Inner(3)` 后面的 `WriteLn("after")` 当前不会执行
### `DebugRunEnv` 与 `DebugRunEnvDo`
`DebugRunEnv(0)` / `DebugRunEnv(1)`
代码块身份:已验证可执行示例
```tsl
program test;
begin
a := 1;
DebugRunEnv(0);
DebugRunEnv(1);
WriteLn(1);
end.
```
已验证运行结果:
- 输出 `1`
- 说明这两个调用在当前 CLI 环境里至少能正常执行,不会中断后续语句
- 但它们把变量 / 系统参数送到调试窗口的效果,在 CLI 中不能直接观察到
`DebugRunEnvDo Func(...)`
代码块身份:已验证可执行示例
```tsl
program test;
function Demo(x);
begin
y := x + 1;
return y;
end;
begin
r := DebugRunEnvDo Demo(2);
WriteLn(r);
end.
```
已验证运行结果:
- 输出 `3`
- 说明 `DebugRunEnvDo Demo(2)` 当前可以直接写
- 也说明它当前会把被调用函数的结果继续返回给外层
### `MTIC` 与 `MTOC`
代码块身份:已验证可执行示例
```tsl
program test;
begin
t1 := MTIC;
s := 0;
for i := 0 to 9999 do
s := s + i;
te1 := MTOC(t1);
t2 := MTIC;
for j := 0 to 9999 do
s := s + j;
te2 := MTOC;
WriteLn(te1 >= 0);
WriteLn(te2 >= 0);
end.
```
已验证运行结果:
- 依次输出 `1`、`1`
- 说明 `MTOC(t1)` 和无参 `MTOC` 当前都能返回可用的秒数结果
### `SetProfiler` 与 `GetProfilerInfo`
代码块身份:已验证可执行示例
```tsl
program test;
begin
SetProfiler(7);
a := 99;
b := IntToStr(a);
c := rand(10, 1);
info := GetProfilerInfo(1);
WriteLn(IfArray(info));
WriteLn(Length(info) > 0);
end.
```
已验证运行结果:
- 依次输出 `1`、`1`
- 说明 `SetProfiler(7)` 当前可以开启 profiler 统计
- 说明 `GetProfilerInfo(1)` 当前会直接返回 profiler 信息,而且结果是非空数组
### `__line__` 与 `__stack_frame`
`__line__`
代码块身份:已验证可执行示例
```tsl
program test;
begin
a := __line__;
WriteLn(a);
end.
```
已验证运行结果:
- 输出 `3`
- 说明 `__line__` 当前直接返回所在代码行号
`__stack_frame`
代码块身份:已验证可执行示例
```tsl
program test;
function Inner();
begin
return __stack_frame;
end;
function Outer();
begin
return Inner();
end;
begin
s := Outer();
WriteLn(ToSTN(s));
end.
```
已验证运行结果:
代码块身份:已验证输出片段
```text
array(
(11,"__main__"),
(8,"Outer"))
```
- 说明 `__stack_frame` 当前返回的是调用栈帧数组
- 在这个最小例子里,可以直接看到调用位置行号和调用者函数名
## 跳转指引
- 回看主线流程控制:见 [08_control_flow.md](08_control_flow.md)
- 运行时环境参数:见 [11_runtime_context_and_with.md](11_runtime_context_and_with.md)
- 回看语法主入口:见 [index.md](index.md)
- 看运行时服务和全局缓存:见 [30_runtime_services_and_global_cache.md](30_runtime_services_and_global_cache.md)