Files
playbook/skills/tsl-syntax-reference/references/14_debug_and_profiler.md
T
csh 40a9885eb4 feat(tsl-syntax-reference): harden retrieval and restructure pages
- flag weak candidates (no intent/heading/identifier/tag hit) and exit 2
  when every candidate is weak: mis-hits used to be indistinguishable
  from real hits, so the retry-with-better-terms loop never fired
- accept multiple ids per --section for batch fetch, failing atomically
  on any unknown id so a partial fetch cannot pass as complete
- move query synonyms and page intent aliases to data/lexicon.json and
  enforce alias/page correspondence in --check; curation data no longer
  lives in the engine
- document the weak-hit rule, batch fetch and prelude-once guidance in
  SKILL.md, with curation discipline in data/README.md
- drop 11_pitfalls.md, renumber the trailing pages and spread retrieval
  tags across topics; lexicon keys are page filenames, so the renumbering
  and the new --check rule cannot land in separate commits
2026-07-29 15:45:47 +08:00

259 lines
6.5 KiB
Markdown
Raw 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.
# TSL 调试与性能分析器
这一篇收拢本页明确的调试、计时、性能分析器和调用栈相关入口。
## 本篇职责
回答“`goto``debugReturn``debugRunEnv``mtic` / `mtoc``setProfiler``__line__``__stack_frame` 怎样写、会怎样表现”。
## 核心规则
本页示例只说明调试与分析结构中的调用位置和源码外形。相关 API 的精确签名、参数、返回行为、平台 scope、目标环境或解释器可用性必须使用 `tsl-api-reference` skill 重新核对,不能由本页示例反推。
- `goto label_name;` 属于文档明确写法,但目标位置以 `label label_name; statement` 这种内联形式作为默认生成形态。
- 本页正向边界只覆盖“跳到同一函数 / 同一脚本体后面的位置”,不要先把更复杂的跨层跳转边界写成事实。
- `debugReturn value;` 会直接结束整段脚本,后面的语句不会继续执行。
- `debugRunEnv(0)``debugRunEnv(1)` 可直接调用;它们面向调试客户端的副作用,不作为本页输出事实。
- `debugRunEnvDo Func(...)` 可直接写,并且会返回被调用函数的结果。
- `mtic` 会生成一个计时起点;`mtoc``mtoc(tick)` 都会返回秒数。
- `setProfiler(...)``getProfilerInfo(...)` 的参数规格使用 `tsl-api-reference` skill 按名查询;本页只保留性能分析器行为示例。
- `setProfiler(7)` 配合 `getProfilerInfo(1)`,可以在不弹窗的情况下拿到性能分析器信息。
- `__line__` 会返回所在代码行号。
- `__stack_frame` 会返回调用栈帧数组;最小 `toStn(...)` 观察结果里,每一项是 `(line, "function")` 这一类二元组。
## 可直接照写示例
### `goto`
<!-- tags: 跳转, 跳出多重循环, 标签跳转 -->
代码块身份:可直接照写示例
```tsl
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);
```
结果说明:
- 依次输出 `1``9`
- 说明 `goto found_label;` 可以跳到后面的 `label found_label; ...`
- 也说明默认目标写法是把 `label` 和第一条目标语句放在同一行
跨函数跳转不作为可写事实:
代码块身份:反例 / 不可照写
```text
Inner();
label out_label; writeLn(1);
function Inner();
begin
goto out_label;
end;
```
结果说明:
- 上面这段会运行报错,核心信息是 `Goto label can not found!`
- 本页正向边界只覆盖“同一函数 / 同一脚本体后面的位置”
- 不要把 `goto` 泛化成能跨函数跳到外层 `label`
目标 `label` 单独成行不作为可写事实:
代码块身份:反例 / 不可照写
```text
goto done_label;
label done_label;
writeLn("after");
```
结果说明:
- 上面这种把 `label` 单独放一行、下一行再写目标语句的最小例子,会报 `Statement missing terminator`
- 因此本页只把 `label name; statement` 这种内联形式写成文档事实
### `debugReturn`
<!-- tags: 中途看返回值, 调试返回, 提前打断 -->
代码块身份:可直接照写示例
```tsl
writeLn("before");
a := Inner(3);
writeLn("after");
function Inner(value);
begin
debugReturn value;
end;
```
结果说明:
- 只输出 `before`
- 说明 `debugReturn value;` 不只是结束 `Inner(...)`,而是直接让整段脚本提前返回
- 因此 `Inner(3)` 后面的 `writeLn("after")` 不会执行
### `debugRunEnv` 与 `debugRunEnvDo`
<!-- tags: 调试环境, 运行环境切换, 调试开关 -->
`debugRunEnv(0)` / `debugRunEnv(1)`
代码块身份:可直接照写示例
```tsl
a := 1;
debugRunEnv(0);
debugRunEnv(1);
writeLn(1);
```
结果说明:
- 输出 `1`
- 说明这两个调用能正常执行,不会中断后续语句
- 但它们把变量 / 系统参数送到调试窗口的效果,不作为本页输出事实
`debugRunEnvDo Func(...)`
代码块身份:可直接照写示例
```tsl
result := debugRunEnvDo Demo(2);
writeLn(result);
function Demo(x);
begin
y := x + 1;
return y;
end;
```
结果说明:
- 输出 `3`
- 说明 `debugRunEnvDo Demo(2)` 可以直接写
- 也说明它会把被调用函数的结果继续返回给外层
### `mtic` 与 `mtoc`
<!-- tags: 计时, 测耗时, 跑了多久, 秒表, 执行时间 -->
代码块身份:可直接照写示例
```tsl
tick1 := mtic;
sum := 0;
for i := 0 to 9999 do
sum := sum + i;
elapsed1 := mtoc(tick1);
tick2 := mtic;
for j := 0 to 9999 do
sum := sum + j;
elapsed2 := mtoc;
writeLn(elapsed1 >= 0);
writeLn(elapsed2 >= 0);
```
结果说明:
- 依次输出 `1``1`
- 说明 `mtoc(t1)` 和无参 `mtoc` 都能返回可用的秒数结果
### `setProfiler` 与 `getProfilerInfo`
<!-- tags: 性能分析, 找瓶颈, profiler, 哪段最慢 -->
代码块身份:可直接照写示例
```tsl
setProfiler(7);
value := 99;
str := intToStr(value);
random := rand(10, 1);
info := getProfilerInfo(1);
writeLn(ifArray(info));
writeLn(length(info) > 0);
```
结果说明:
- 依次输出 `1``1`
- 说明 `setProfiler(7)` 可以开启性能分析器统计
- 说明 `getProfilerInfo(1)` 会直接返回性能分析器信息,而且结果是非空数组
### `__line__` 与 `__stack_frame`
<!-- tags: 当前行号, 调用栈, 堆栈信息, 报错在哪一行 -->
`__line__`
代码块身份:可直接照写示例
```tsl
line_number := __line__;
writeLn(line_number);
```
结果说明:
- 输出 `1`
- 说明 `__line__` 直接返回它所在的代码行号(这里 `__line__` 在脚本第 1 行)
`__stack_frame`
代码块身份:可直接照写示例
```tsl
stack := Outer();
writeLn(toStn(stack));
function Inner();
begin
return __stack_frame;
end;
function Outer();
begin
return Inner();
end;
```
结果说明:
代码块身份:输出片段
```text
array(
(1,"__main__"),
(10,"Outer"))
```
- 说明 `__stack_frame` 返回的是调用栈帧数组
- 在这个最小例子里,可以直接看到调用位置行号和调用者函数名:`__main__` 在第 1 行调用 `Outer()``Outer` 在第 10 行调用 `Inner()`
## 禁止项
- 不要把 `debugReturn` 当成普通函数 `return` 使用。
- 不要假设 `goto` 可以跨函数、跨脚本体或跳到单独成行的 `label`
- 不要给计时或性能分析器调用补未写入文档参数。
- 不要把调试客户端副作用写成普通输出事实。