diff --git a/.run/Bug4.run.xml b/.run/Bug4.run.xml
new file mode 100644
index 0000000..d10e3f5
--- /dev/null
+++ b/.run/Bug4.run.xml
@@ -0,0 +1,11 @@
+
- * 本类作为指令生成器调度中心,不负责任何具体 IR 指令到 VM 指令的转换实现, - * 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成。 - *
- *- * 工作流程简述: - *
- * 键: IR 指令类型(Class对象), - * 值: 对应的指令生成器实例。 - *
+ * IR 指令类型到指令生成器的映射。 + * 每种 IRInstruction 都有对应的 InstructionGenerator 处理。 */ private final Map- * 本类用于编译器后端,将所有生成的 VM 指令(包括分支和调用指令)统一存储、管理。 - * 支持符号(如函数入口、标签地址)的延迟解析与回填(fix-up)机制, - * 可在目标尚未定义时提前生成分支或调用指令,定义后自动修正。 - *
- *- * 常用于处理跨函数、跨标签的 CALL/JUMP 等复杂控制流,确保最终生成的 VM 指令地址一致正确。 - *
+ * 主要职责: + *+ * 1. 记录符号到当前 pc 的映射; + * 2. 立即尝试修补之前所有针对该符号的延后调用和分支。 + * + * @param name 函数名或标签名(全限定名) */ public void beginFunction(String name) { - addr.put(name, pc); // 记录当前地址为入口 - patchCallFixes(name); // 修补所有待该符号的 CALL - patchBranchFixes(name); // 修补所有待该符号的分支 + addr.put(name, pc); + patchCallFixes(name); + patchBranchFixes(name); } - /** - * 结束函数(当前实现为空,方便 API 统一)。 - */ - public void endFunction() { /* no-op */ } + /** 函数结尾的处理(占位,无需特殊处理)。 */ + public void endFunction() {} /** - * 写入一条 VM 指令或标签。 - *
+ * 如果存在未修补的调用或分支,将抛出异常。
+ *
+ * @return 指令序列(不可变)
+ * @throws IllegalStateException 如果存在未修补符号
*/
public List
+ * 只支持全名精确修补,不做模糊查找或短名回退。
+ *
+ * @param name 目标函数全名
*/
private void patchCallFixes(String name) {
for (Iterator 主要职责:
+ * IRProgramBuilder 负责将 AST 根节点(如模块、函数、顶层语句)转换为可执行的 IRProgram 实例。
+ *
+ * 主要职责:
*
+ * 如果模块有全局声明,则这些声明会被插入到函数体前部。
+ *
+ * @param moduleNode 当前模块节点
+ * @param functionNode 模块中的函数节点
+ * @return 包含全局声明、已加前缀函数名的 IRFunction
*/
private IRFunction buildFunctionWithGlobals(ModuleNode moduleNode, FunctionNode functionNode) {
+ // 拼接模块名和函数名,生成全限定名
+ String qualifiedName = moduleNode.name() + "." + functionNode.name();
+ // 若无全局声明,仅重命名后直接构建
if (moduleNode.globals() == null || moduleNode.globals().isEmpty()) {
- return buildFunction(functionNode);
+ return buildFunction(renameFunction(functionNode, qualifiedName));
}
- // 重建函数体:先放 globals 的声明,再放原来的语句
+ // 若有全局声明,插入到函数体最前面
List
+ * 这对于脚本式文件支持至关重要(即文件最外层直接写语句)。
*
- * 封装规则:
- *
- *
*/
public final class IRProgramBuilder {
/**
- * 构建完整的 IRProgram 实例。
+ * 将解析生成的 AST 根节点列表转换为 IRProgram。
*
* @param roots 含 ModuleNode、FunctionNode 或 StatementNode 的顶层 AST 根节点列表
* @return 包含所有转换后 IRFunction 的 IRProgram 对象
@@ -36,17 +34,20 @@ public final class IRProgramBuilder {
IRProgram irProgram = new IRProgram();
for (Node node : roots) {
switch (node) {
- case ModuleNode moduleNode ->
- // 对每个模块,所有函数均自动注入 globals
- moduleNode.functions().forEach(f -> irProgram.add(buildFunctionWithGlobals(moduleNode, f)));
+ case ModuleNode moduleNode -> {
+ // 处理模块节点:遍历其中所有函数,统一用“模块名.函数名”作为全限定名
+ for (FunctionNode f : moduleNode.functions()) {
+ irProgram.add(buildFunctionWithGlobals(moduleNode, f));
+ }
+ }
case FunctionNode functionNode ->
- // 顶层函数节点: 直接构建并添加
+ // 处理顶层函数节点:直接构建为 IRFunction 并加入
irProgram.add(buildFunction(functionNode));
case StatementNode statementNode ->
- // 脚本式顶层语句: 封装为“_start”函数后构建并添加
+ // 处理脚本式顶层语句:封装成 "_start" 函数后构建并添加
irProgram.add(buildFunction(wrapTopLevel(statementNode)));
default ->
- // 严格校验节点类型,遇不支持者立即失败
+ // 遇到未知类型节点,抛出异常
throw new IllegalStateException("Unsupported top-level node: " + node);
}
}
@@ -54,21 +55,27 @@ public final class IRProgramBuilder {
}
/**
- * 构建带有模块全局声明“注入”的函数。
- * 为了在当前 IR 设计下能访问全局变量,将模块的 globals 作为前置声明
- * 追加到函数体最前面,使其在函数内被注册到 IR 作用域中。
+ * 构建带有模块全局声明“注入”的函数,并将函数名加上模块前缀,保证模块内函数名唯一。
+ *
- *
- *
- * @param stmt 待封装的顶层脚本语句节点
- * @return 生成的 FunctionNode,用于后续 IRFunction 构建
+ * @param stmt 要封装的顶层语句
+ * @return 包装成 FunctionNode 的 "_start" 函数
*/
private FunctionNode wrapTopLevel(StatementNode stmt) {
return new FunctionNode(
diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
index c31ec96..90cd8ae 100644
--- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
+++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java
@@ -1,7 +1,11 @@
package org.jcnc.snow.vm.commands.flow.control;
import org.jcnc.snow.vm.interfaces.Command;
-import org.jcnc.snow.vm.module.*;
+import org.jcnc.snow.vm.module.CallStack;
+import org.jcnc.snow.vm.module.LocalVariableStore;
+import org.jcnc.snow.vm.module.OperandStack;
+import org.jcnc.snow.vm.module.StackFrame;
+import org.jcnc.snow.vm.utils.LoggingUtils;
import static org.jcnc.snow.common.SnowConfig.print;
@@ -37,7 +41,7 @@ public class RetCommand implements Command {
/* ----- Root frame: do NOT pop, just end program ----- */
if (topFrame.getReturnAddress() == PROGRAM_END) {
- System.out.println("Return