CodePlanet Platform

CodePlanet 软件帮助

在页面内直接阅读项目文档,支持目录导航与原文下载。

CodePlanet AST 逻辑架构(维护参考)

下载原文

CodePlanet AST 逻辑架构(维护参考)

> 版本:2026-05-21(P5 遗留清理 + Lexer/Catalog 统一) > 状态:F5/F6/F10/Shift+F11 调试主路径;最小 Qt Test 回归 > 维护要求:改动 src/core/runtime/ast/ControlLogiLib 或调试 UI 时须同步更新本文档。

---

1. 架构概览

CodeEditorWidget
  ├─ gutter 断点(红色圆点,0-based 行号)
  ├─ F5 Continue / F6 Step Over / F10 Step Into / Shift+F11 Step Out
  └─ Ctrl+B BuildProgram 门禁
        │
        ▼
ControlLogiLib → ast::AstRuntime
        ├─ Lexer(**FunctionCatalog::keywordTokenType**)→ Parser → Program (AST + FunctionDecl 表)
        ├─ AstInterpreter(帧栈执行)
        │     ├─ ExprParser → ExprEvaluator(表达式 **单轨 AST**)
        │     ├─ 用户 function 调用栈 + 局部作用域
        │     └─ switch 控制帧 + case 块帧(可单步)
        └─ FunctionDispatcher(插件库函数,evaluateExpression → ExprEvaluator)

parameterparser.cpp 仅保留 参数读写 facadeReadParameter / WriteParameter / Create* / DeleteParameter)。行扫描 FunctionParsReturnValueUnitCodeSource P5 已删除控制流仅走 AST。

FunctionCatalog 数据流(P2 + P5 Lexer 统一)

FunctionLib.ini (FileService)
       │
       ▼
FunctionCatalog::instance()  ← Application::initializeServices
       ├─► FunctionLib(CodeEditor 函数元数据 / 签名)
       ├─► YsHighlightScanner(控制流/类型/库名高亮)
       ├─► CodeEditor::loadFunctionLibrary / updateCompletionList
       ├─► Lexer::identifierOrKeyword → keywordTokenType(end_* 不映射)
       └─► Application::validateFunctionCatalogPlugins(对比 PluginManager)
  • 编辑器与运行时关键字 单一来源FunctionLib.iniFunctionCatalog
  • end_if / end_for / end_switch 仅编辑器补全/高亮;Parser 仍用 {/} 块语法

---

2. 模块与文件

文件 职责
ast/Lexer.cpp 词法分析;关键字来自 FunctionCatalog::keywordTokenType
ast/Parser.cpp 语法分析 → AST;顶层 function 声明
ast/ExprParser.cpp 表达式 → ExprNode
ast/ExprEvaluator.cpp 表达式求值;evaluateExpressionAst 供插件/legacy
ast/AstInterpreter.cpp 执行引擎、调试帧栈、断点、Step Into/Out
ast/AstRuntime.cpp 对外门面
logic/controllogilib.cpp 主线程编排、冲突守卫、DB 会话
logic/RuntimeWorker.cpp Ops 运行线程、AstRuntime 串行执行(F5 调试)
logic/MainTaskWorker.cpp / SubTaskWorker.cpp R2 产线主/子任务循环(RuntimeOrchestrator 调度)
core/runtime/MainTaskTimerService.cpp R2 主任务 timer API;MainTaskWorker 每 tick 调用 tick()
core/functions/FunctionCatalog.cpp INI 单一解析:函数 CSV + 控制流/高亮/插件元数据
core/functions/basefunction.cpp FunctionLib facade,委托 Catalog

---

3. 语句与节点

节点 语法
FunctionDeclStmt function name(a, b) { ... }
ReturnStmt return; / return expr;
VarDeclStmt int/static/array
IfStmt / ForStmt / WhileStmt / SwitchStmt 控制流
SwitchStmt::CaseArm 每 case/default 含独立 Block(P1)

表达式:Expr { source, ast },由 makeExpr() 在解析时填充。

---

4. 变量作用域

类型 写法 存储(R1)
局部 int x = 0; sourceParameterL[1] 或 function 内 m_localScopes
任务内 static static int s = 0; RuntimeWorker 会话 QHash(不进 scope 0)
跨任务 global global int g = 0; ProjectGlobalStore(按 yslib 路径)
import import "path.ys"; R2executeImport 合并模块 functions;静态 analyzeProjectImports + 跨模块 call(YS405)
#include #include "rel/path.ys" R2AppPaths::resolveIncludeRelative(path, sourceFilePath) 相对脚本目录
函数参数 function f(a,b) 调用时压入 m_localScopes

---

5. 调试模型(VSCode 对齐)

快捷键 DebugMode 行为
F5 Continue 运行至结束、断点或 Stop
F5(运行中) requestStop() 终止
F6 Step Over 前进 一行源码(含空行/注释行);若该行有语句则执行一条
F10 Step Into 单步;遇用户 function 时进入函数体首行;插件函数print 等,FunctionCatalog 注册)整句执行不进入
Shift+F11 Step Out 运行至当前 function 返回

箭头:始终指向 待运行行m_nextRunLine,1-based)。F5 连续运行时箭头跟随当前执行行;F6 每按一次前进一行源码。

5.1 断点(P3)

  • 设置:行号 gutter 第二列(15–30px)左键添加红色圆点
  • 取消:再次左键红色圆点
  • 行号:编辑器内 0-basedblockNumber);AST 源码 1-based,在 UpdateCodeStepLine 转换
  • 生效:F5/F6/F10/Shift+F11 运行前 setBreakpoints() 注入解释器

5.2 执行帧栈

FrameKind 说明
Block 普通块 / case 块 / function 体
ForLoop / WhileLoop 循环体,块结束自动 update/条件
SwitchControl switch 控制;case 块结束后 fall-through

5.3 行号约定

  • AST SourceSpan.line1-based
  • CodeEditor::UpdateCodeStepLine(line):内部转为 debugArrowLine = line - 1
  • 解释器 currentLine() 返回 待运行行(非上一句已执行行)

箭头:始终指向 待运行行m_nextRunLine,1-based)。F2/F3 重置后箭头对准 第 1 行。F5 连续运行时箭头跟随当前执行行;F6/F10 每按一次前进一步(物理源码行优先,仅 line == stmtLine 时执行语句)。

5.4 单步指针(stepOnce

场景 箭头行为
普通语句执行后 指向 lastExecutedLine + 1(逐行推进)
空行 / 注释 仅前进一行,不执行
函数声明扫描(未进入该函数) function 头行单步跳到函数体闭合 }
顶层 foo();(ExprStmt)F6 进入 foofunction 头行逐步执行
表达式内嵌用户函数调用 F6 Step Over,不进入被调函数
F10 进入用户函数 function 头行暂停
函数返回(调试模式) 暂停在 executingStatementLineForFrame(caller) + 1
for/while 体结束于 } 执行迭代尾步(update + 条件);条件仍真 → 箭头回到 for(...){ / while(...){
循环条件为假 弹出循环帧,箭头指向 } 下一行
break / continue 弹出至最近 loop/switch 控制帧;continue 将 index 置为体末尾以触发尾步

5.5 循环与副作用

  • forupdatewhile/for 体内的 i = i + 1 等表达式语句经 executeSideEffect 执行赋值(executeExprStmt 识别 =/++/--
  • F6 单步for/while 体执行完后,在 }再按 F6 执行迭代尾步(update + 条件判断)
  • executeNext 每次最多执行 一条语句,不在一次 F6 内连跳多次循环

5.6 用户自定义 function 与插件函数(F10)

  • 用户 functionfunction add(...) { ... }m_functions 表):F6/F5 跑完;F10 停在函数体第一条语句m_stepIntoPauseRequested),赋值/return 等宿主语句尚未完成
  • 插件 functionFunctionCatalog 注册、print 等):F10 与 F6 相同,整句执行,不进入 DLL 实现
  • int c = add(10, 20);:F10 在 add 入口暂停;F6 一次执行完 add 并写入 c
  • 插件函数仍走 FunctionDispatcher;未找到时提示 Function not found:

5.7 Call Stack 面板

  • 入口:调试工具栏 「栈」 按钮 → QStackedWidget 第 3 页
  • # / 名称 / 行号 / 类型(function / block / for / while)
  • 数据源AstInterpreter::debugFrameSnapshot()RuntimeWorker::stackChangedCodeEditorWidget::updateDebugStack
  • 当前帧:栈顶行浅蓝底 + 粗体
  • 双击:编辑器跳转到对应行(只读,不改变调试箭头/运行状态)

5.7 线程编排(P0)

脚本执行与调试 不再 使用 QtConcurrent 线程池,改为 专用运行线程 串行化所有 AstRuntime mutate。

三层线程模型

线程 对象 职责
主线程 ControlLogiLib UI 请求、DB 会话、UpdateCodeStepLine / UpdatePara / SendDebugMessage
运行线程 RuntimeWorker + ast::AstRuntime loadSourcerunContinuestep*resetDebugclearGlobals
全局参数线程 sourceParameterL[0]SourceParameter(true) 全局/static 参数读写删(QueuedConnection)

请求路径:主线程 RunCodeEditor / RunStep / Resetworker* 信号 → Qt::QueuedConnectionRuntimeWorker 槽;worker 完成后通过 runFinished / stepFinished / resetFinished 等信号回到主线程。

冲突策略

  • F5 运行中再 F5 → requestStop(),等 runFinished,不启动第二个 full run
  • F5 运行中 F6/F10/Shift+F11 → 忽略并提示「运行中,请先停止 (F5)」
  • 连续 F6 → m_stepInProgress 门卫 + m_debugStepToken 丢弃过期行更新

调试 UI 回传

  • postDebugLineUpdateQueuedConnection + stepToken,丢弃过期箭头
  • P4 调试日志单路径:所有调试文本经 ControlLogiLib::publishDebugMessage(msg, lineNo)DebugLogService::log(SQLite,需活跃 debug session)+ emit SendDebugMessage(msg)MainWindowReceiverDebugMessage
  • 生产者:Init_DebugMessage 全局回调(parameterparser / FunctionDispatcher)、ReviceMessage(参数 SendMessage)、RuntimeWorker::debugMessage(含 (at line:col) 行号解析)、逻辑层直接提示(停止/改参等)
  • 全局 SendDebugMessage 回调已 deprecated;新代码勿绕过 publishDebugMessage
flowchart LR
  UI[MainThread_UI] --> CL[ControlLogiLib]
  CL -->|QueuedConnection| RW[RuntimeWorker]
  RW --> AR[AstRuntime]
  RW -->|signals_Queued| CL
  AR -->|Write_Delete_Clear| SP0[GlobalParameterThread]

断点(P3 后):命中断点时尚未执行该行,红色箭头指向即将执行的语句;F5 再次按下从当前位置 Continue(不重置会话),F2/F3 复位调试状态。

  • finalizeDebugSession:F5 runFinished 后于主线程写 DB

Debug 日志 UI(P4)

flowchart LR
  PP[parameterparser_FunctionDispatcher] --> Init[Init_DebugMessage]
  RW[RuntimeWorker_debugMessage] --> Pub[publishDebugMessage]
  Init --> Pub
  Rev[ReviceMessage] --> Pub
  Pub --> DLS[DebugLogService_log]
  Pub --> Sig[SendDebugMessage]
  Sig -->|QueuedConnection| RCV[ReceiverDebugMessage]
  RCV --> DE[m_debugEdit_append]

---

6. 表达式 AST(P2)

ExprParser 支持:+ - * / %、比较、逻辑、()、数组下标、成员(.L/.Length/.Rad 等)、++/--、函数调用。

6.1 + 运算符(JavaScript/C# 风格)

左/右类型 结果
任一侧为 string 文本拼接(int"1"float"1.0" 一位小数)
均为数值 数值相加;有 float 则结果为 float(如 int+float2.0
结合性 左结合,(i+f)+si+(f+s) 按 AST 树求值

print(expr) 由 AST 先求值再输出;不再对参数二次调用 ReturnValue

表达式求值数据流(单轨):

flowchart LR
  makeExpr --> ExprParser --> ExprNode
  ExprNode --> ExprEvaluator
  ExprEvaluator --> ReadParameter
  ExprEvaluator --> WriteParameter
  ExprEvaluator --> FunctionDispatcher
  FunctionDispatcher_plugins[插件 evaluateExpression] --> evaluateExpressionAst
  evaluateExpressionAst --> ExprEvaluator

1. makeExpr / ExprParser::parse 构建 ExprNode 树 2. ExprEvaluator 求值(无 ReturnValue fallback;失败返回 %Err%) 3. 插件侧 FunctionCallContext::evaluateExpressionevaluateExpressionAst 4. 插件 evaluateExpressionevaluateExpressionAst(无 ReturnValue 路径)

---

7. P5 遗留清理(2026-05-21)

处置
FunctionPars / ReturnValueUnit parameterparser.cpp 物理删除(src 无调用)
CodeSource / codeSourcesL 删除;#includeAstInterpreter::executeInclude
Lexer 关键字 删除 kKeywords[];改查 FunctionCatalog::keywordTokenType
modifyPara 全局参数(id=0)经 BlockingQueuedConnectionSourceParameter 所属线程读写
deletePara 参数面板 → DeleteParameterupdateParameters
插件调试 FunctionDispatcher::setDebugMessageSinkpublishDebugMessage;全局 SendDebugMessageInit_DebugMessage deprecated 转发
自动化 tests/ Qt Test + scripts/run_all_checks.ps1

局部参数(id=1)与 worker 并发写入仍为已知限制;全局参数线程亲和性已在 P5 闭环。

---

8. 用户自定义函数(P4)

function add(int a, int b) {
    int sum = a + b;
    print(sum);
    return sum;
}
  • 解析:Program.functions + Parser.parseFunctionDecl
  • 调用:优先查 m_functions,否则 FunctionDispatcher
  • Step Over:一次执行完整个 function 体
  • Step Into:停在 function 第一行
  • Step Out:运行至 return 或块结束

插件函数(print 等)不可 Step Into。

---

8. 测试脚本

examples/ast_debug.ys — 覆盖 if/for/while/switch/function/static/print。 自动化:tests/test_script_analyzer.cpp 对全文件 ScriptAnalyzer::analyze 期望 0 error。

---

9. 已知限制

  • 插件函数无 Step Into
  • Build 错误高亮仍依赖 buildprogram.cpp 字符串解析 (at line:col)(结构化 Diagnostic 待 P4+ 技术债)
  • BuildProgram(Ctrl+B)已改为 ScriptAnalyzer 结构化诊断(词法/语法/语义);问题面板四列,编辑器内波浪下划线;F5/F6 预检静默、有错才切面板

---

10. 扩展指南

1. 新语句AstNodes.hParserAstInterpreter → 更新本文档 2. 新库函数:插件 + FunctionLib.ini(AST 无改动) 3. 新表达式运算符ExprParser + ExprEvaluator

---

11. R2 产线 Runtime(2026-05-24)

CodePlanetLauncher → CodePlanetRuntime.exe
  ParentProcessGuard + --project <yslib>
  RuntimeOrchestrator
    ├─ MainTaskWorker(QTimer loopIntervalMs → runContinue 一轮 + timerService.tick())
    └─ SubTaskWorker[](simulateTrigger 队列;R3 接硬触发)
  RuntimeMainWindow(日志 / global 表 / processGroups 树,150ms 刷新)
  • import 运行时AstInterpreter::executeImport 解析路径同 ScriptAnalyzer::resolveImportPath;仅合并 functions;同名冲突运行期报错
  • global 跨脚本:每变量仅在一个脚本 global 声明;ProjectValidator + analyzeProjectGlobals → YS408;其他脚本经 ProjectGlobalStore 读写
  • timerFunctionLib.ini 登记 timer_*FunctionDispatcher 内置 dispatch(非插件);子任务脚本静态 YS406
  • Ops 与产线并存RuntimeWorker 不变;产线用 MainTaskWorker/SubTaskWorker

---

帮助阅读建议

  • 左侧目录可快速切换文档,右侧区域支持长文滚动阅读。
  • 遇到复杂流程,建议先阅读“项目目标与架构终点”再看部署规范。
  • 每份文档都保留原文入口,便于下载归档或离线传阅。