# 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)