refactor: 优化 IRProgram 构建过程并完善结构体布局处理

- 简化 buildProgram 方法的注释,使流程描述更加清晰
-重写 preloadStructLayouts 方法,增加对结构体继承的支持
- 调整 globalConstPreload 方法的注释,明确其功能
- 在 buildScriptMainFunction 方法中添加占位符,避免依赖真实位置信息
This commit is contained in:
Luke 2025-09-01 11:03:21 +08:00
parent 04b43cbd5a
commit 9e322f3d87

View File

@ -34,24 +34,16 @@ public final class IRProgramBuilder {
/**
* 将解析生成的 AST 根节点列表转换为 IRProgram
*
* @param roots ModuleNodeFunctionNode StatementNode 的顶层 AST 根节点列表
* @return 包含所有转换后 IRFunction IRProgram 对象
* @param roots 顶层 AST 根节点列表ModuleNode / FunctionNode / StatementNode
* @return 构建好的 IRProgram
* @throws IllegalStateException 遇到不支持的顶层节点类型时抛出
*
* <p>
* 主流程为
* <p>主流程</p>
* <ol>
* <li>首先登记全局常量便于后续常量折叠优化</li>
* <li>再注册所有 struct 的字段布局为成员读写和 this.xx 做准备</li>
* <li>随后依次遍历各顶层节点根据类型进行分发处理</li>
* <ul>
* <li>ModuleNode: 先降级并注册 struct 方法/构造再处理普通函数</li>
* <li>FunctionNode: 直接构建为 IRFunction</li>
* <li>StatementNode: 作为脚本模式顶层语句包装进 "_start" 函数</li>
* <li>其他类型: 抛出异常</li>
* </ul>
* <li>登记全局常量便于后续常量折叠</li>
* <li>注册所有 struct 的字段布局为成员读写和 this.xx 做准备</li>
* <li>遍历根节点模块 先降级并注册 struct 的构造/方法再处理模块函数顶层函数直接构建顶层语句打包为 "_start" 构建</li>
* </ol>
* </p>
*/
public IRProgram buildProgram(List<Node> roots) {
// 1. 先登记全局常量便于后续常量折叠
@ -95,29 +87,49 @@ public final class IRProgramBuilder {
// ===================== 预扫描注册结构体字段布局 =====================
/**
* 遍历所有模块与结构体按字段声明顺序构建字段名 -> 槽位索引的映射
* 并注册到 {@link IRBuilderScope#registerStructLayout(String, Map)}
* 这样在构建任意函数/方法时成员访问 this.name就能查询到正确的字段索引
* 为每个结构体注册字段布局字段名 槽位索引并在有继承时将父类布局复制并续接
*
* <p>规则</p>
* <ol>
* <li>若存在父类先取到父类布局如果能找到将其按顺序复制到当前布局中起始索引 = 父类字段数</li>
* <li>再将当前结构体声明的字段按声明顺序追加如果字段名与父类重复跳过以避免覆盖</li>
* <li>最后将布局以 <code>StructName</code> 为键注册到 {@link IRBuilderScope} 的全局布局表</li>
* </ol>
* @param roots AST 顶层节点列表包含模块/结构体信息
*/
private void preloadStructLayouts(List<Node> roots) {
for (Node n : roots) {
// 只处理模块节点
if (!(n instanceof ModuleNode mod)) continue;
if (mod.structs() == null) continue;
// 遍历每个 struct收集字段布局
for (StructNode s : mod.structs()) {
List<DeclarationNode> fields = s.fields();
if (fields == null) continue;
Map<String, Integer> layout = new LinkedHashMap<>();
int idx = 0;
for (DeclarationNode d : fields) {
// 字段声明顺序决定槽位顺序如0,1,2,...
layout.put(d.getName(), idx++);
// 1. 若有父类先复制父类布局并将索引起点置为父类字段数
String parentName = s.parent();
if (parentName != null && !parentName.isBlank()) {
// 约定IRBuilderScope 内部维护一个结构体名 字段布局的全局表
// 这里假定提供静态查询方法 getStructLayout(String)
Map<String, Integer> parentLayout = IRBuilderScope.getStructLayout(parentName);
if (parentLayout != null && !parentLayout.isEmpty()) {
layout.putAll(parentLayout);
idx = parentLayout.size();
}
}
// 注册字段布局结构体名通常为简单名 Person类型系统如支持 Module.Struct IRBuilderScope 里兼容处理
// 2. 续接当前结构体声明的字段若与父类同名跳过避免覆盖父类槽位
for (DeclarationNode d : fields) {
String name = d.getName();
if (!layout.containsKey(name)) {
layout.put(name, idx++);
}
}
// 3. 注册 Person {name:0}Student(extends Person) {name:0, studentId:1}
IRBuilderScope.registerStructLayout(s.name(), layout);
}
}
@ -189,7 +201,7 @@ public final class IRProgramBuilder {
);
}
// ===================== 全局常量收集 =====================
// ===================== 预扫描全局常量收集 =====================
/**
* 扫描所有模块节点将其中声明的 const 全局变量即编译期常量
@ -355,6 +367,7 @@ public final class IRProgramBuilder {
List.of(),
"void",
List.of(stmt),
// (-1,-1,"")占位避免依赖真实位置信息
new NodeContext(-1, -1, "")
);
}