From 9e322f3d87edf9c8b7f74b4b75d316ca9455f13a Mon Sep 17 00:00:00 2001
From: Luke
Date: Mon, 1 Sep 2025 11:03:21 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=20IRProgram=20?=
=?UTF-8?q?=E6=9E=84=E5=BB=BA=E8=BF=87=E7=A8=8B=E5=B9=B6=E5=AE=8C=E5=96=84?=
=?UTF-8?q?=E7=BB=93=E6=9E=84=E4=BD=93=E5=B8=83=E5=B1=80=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 简化 buildProgram 方法的注释,使流程描述更加清晰
-重写 preloadStructLayouts 方法,增加对结构体继承的支持
- 调整 globalConstPreload 方法的注释,明确其功能
- 在 buildScriptMainFunction 方法中添加占位符,避免依赖真实位置信息
---
.../compiler/ir/builder/IRProgramBuilder.java | 61 +++++++++++--------
1 file changed, 37 insertions(+), 24 deletions(-)
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java
index dd1c5a3..ac5f2b4 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java
@@ -34,24 +34,16 @@ public final class IRProgramBuilder {
/**
* 将解析生成的 AST 根节点列表转换为 IRProgram。
*
- * @param roots 含 ModuleNode、FunctionNode 或 StatementNode 的顶层 AST 根节点列表
- * @return 包含所有转换后 IRFunction 的 IRProgram 对象
+ * @param roots 顶层 AST 根节点列表(ModuleNode / FunctionNode / StatementNode)
+ * @return 构建好的 IRProgram
* @throws IllegalStateException 遇到不支持的顶层节点类型时抛出
*
- *
- * 主流程为:
+ *
主流程:
*
- * - 首先登记全局常量(便于后续常量折叠优化)。
- * - 再注册所有 struct 的字段布局(为成员读写和 this.xx 做准备)。
- * - 随后依次遍历各顶层节点,根据类型进行分发处理:
- *
- * - ModuleNode: 先降级并注册 struct 方法/构造,再处理普通函数。
- * - FunctionNode: 直接构建为 IRFunction。
- * - StatementNode: 作为脚本模式顶层语句包装进 "_start" 函数。
- * - 其他类型: 抛出异常。
- *
+ * - 登记全局常量(便于后续常量折叠)。
+ * - 注册所有 struct 的字段布局(为成员读写和 this.xx 做准备)。
+ * - 遍历根节点:模块 → 先降级并注册 struct 的构造/方法,再处理模块函数;顶层函数直接构建;顶层语句打包为 "_start" 构建。
*
- *
*/
public IRProgram buildProgram(List roots) {
// 1. 先登记全局常量,便于后续常量折叠
@@ -95,29 +87,49 @@ public final class IRProgramBuilder {
// ===================== 预扫描:注册结构体字段布局 =====================
/**
- * 遍历所有模块与结构体,按字段声明顺序构建“字段名 -> 槽位索引”的映射,
- * 并注册到 {@link IRBuilderScope#registerStructLayout(String, Map)} 中。
- * 这样在构建任意函数/方法时,成员访问(如 this.name)就能查询到正确的字段索引。
+ * 为每个结构体注册字段布局(字段名 → 槽位索引),并在有继承时将父类布局复制并续接。
*
+ * 规则:
+ *
+ * - 若存在父类:先取到父类布局(如果能找到),将其按顺序复制到当前布局中;起始索引 = 父类字段数。
+ * - 再将当前结构体声明的字段按声明顺序追加;如果字段名与父类重复,跳过以避免覆盖。
+ * - 最后将布局以
StructName 为键注册到 {@link IRBuilderScope} 的全局布局表。
+ *
* @param roots AST 顶层节点列表,包含模块/结构体信息
*/
private void preloadStructLayouts(List roots) {
for (Node n : roots) {
- // 只处理模块节点
if (!(n instanceof ModuleNode mod)) continue;
if (mod.structs() == null) continue;
- // 遍历每个 struct,收集字段布局
for (StructNode s : mod.structs()) {
List fields = s.fields();
if (fields == null) continue;
+
Map 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 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, "")
);
}