From b058ee452685df0f66edb549d0e89fed2055e517 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 26 Aug 2025 16:25:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E5=8F=98=E9=87=8F=E5=A4=84=E7=90=86=E5=92=8C=E5=B8=B8?= =?UTF-8?q?=E9=87=8F=E6=8A=98=E5=8F=A0=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 过滤与函数参数重名的全局声明,避免命名冲突 - 优化常量折叠逻辑,支持跨模块常量优化- 修复字符串字面量和布尔字面量的处理 - 优化代码结构,提高可读性和可维护性 --- .../compiler/ir/builder/IRProgramBuilder.java | 104 +++++++++--------- 1 file changed, 55 insertions(+), 49 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 8d0a340..730b731 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 @@ -10,7 +10,9 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * IRProgramBuilder 负责将 AST 顶层节点转换为可执行的 {@link IRProgram}。 @@ -38,16 +40,16 @@ public final class IRProgramBuilder { for (Node node : roots) { switch (node) { case ModuleNode moduleNode -> { - // 处理模块节点:遍历其中所有函数,统一用“模块名.函数名”作为全限定名 + // 处理模块节点:遍历其中所有函数,统一用“模块名.函数名”作为全限定名,避免命名冲突 for (FunctionNode f : moduleNode.functions()) { irProgram.add(buildFunctionWithGlobals(moduleNode, f)); } } case FunctionNode functionNode -> - // 处理顶层函数节点:直接构建为 IRFunction 并加入 + // 处理顶层函数节点:直接构建为 IRFunction 并加入 irProgram.add(buildFunction(functionNode)); case StatementNode statementNode -> - // 处理脚本式顶层语句:封装成 "_start" 函数后构建并添加 + // 处理脚本式顶层语句:封装成 "_start" 函数后构建并添加 irProgram.add(buildFunction(wrapTopLevel(statementNode))); default -> // 遇到未知类型节点,抛出异常 @@ -62,10 +64,9 @@ public final class IRProgramBuilder { /** * 扫描所有模块节点,将其中声明的 const 全局变量(compile-time 常量) * 以 "模块名.常量名" 形式注册到全局常量表。 - *

- * 只处理直接字面量(数字、字符串、布尔),暂不支持复杂表达式。 + * 支持跨模块常量折叠,用于后续 IR 生成过程中的常量折叠优化。 * - * @param roots 所有顶层 AST 节点 + * @param roots AST 顶层节点列表 */ private void preloadGlobals(List roots) { for (Node n : roots) { @@ -73,6 +74,7 @@ public final class IRProgramBuilder { String moduleName = mod.name(); if (mod.globals() == null) continue; for (DeclarationNode decl : mod.globals()) { + // 只处理 compile-time 的 const 常量,并要求有初始值 if (!decl.isConst() || decl.getInitializer().isEmpty()) continue; ExpressionNode init = decl.getInitializer().get(); Object value = evalLiteral(init); @@ -86,53 +88,40 @@ public final class IRProgramBuilder { /** * 字面量提取与类型折叠工具。 - *

- * 用于从表达式节点中解析出直接可用于全局常量表注册的 Java 值, - * 支持以下字面量类型: - *

- * 不支持的表达式或解析失败将返回 null。 + * 用于将表达式节点还原为 Java 原生类型(int、long、double、String等),仅支持直接字面量。 * - * @param expr 字面量表达式节点,通常为 NumberLiteralNode/StringLiteralNode/BoolLiteralNode - * @return 提取出的 Java 值,可为 Integer/Byte/Short/Long/Double/String/Integer(布尔) 或 null + * @param expr 要计算的表达式节点 + * @return 提取到的原生常量值,不支持的情况返回 null */ private Object evalLiteral(ExpressionNode expr) { return switch (expr) { case NumberLiteralNode num -> { String raw = num.value(); - // 1. 去掉下划线分隔符,便于解析(如 1_000_000) String s = raw.replace("_", ""); - // 2. 提取类型后缀(b/s/l/f/d),若有则去除 char last = Character.toLowerCase(s.charAt(s.length() - 1)); String core = switch (last) { case 'b', 's', 'l', 'f', 'd' -> s.substring(0, s.length() - 1); default -> s; }; try { - // 3. 若为浮点字面量或科学计数法,直接转 double if (core.contains(".") || core.contains("e") || core.contains("E")) { - double dv = Double.parseDouble(core); - yield dv; + // 浮点数处理 + yield Double.parseDouble(core); } - // 4. 整数字面量,先转 long,再根据后缀决定精度 long lv = Long.parseLong(core); yield switch (last) { - case 'b' -> (byte) lv; // 末尾 b,转 byte - case 's' -> (short) lv; // 末尾 s,转 short - case 'l' -> lv; // 末尾 l,转 long - default -> (int) lv; // 无后缀,转 int + case 'b' -> (byte) lv; + case 's' -> (short) lv; + case 'l' -> lv; + default -> (int) lv; }; } catch (NumberFormatException ignore) { - // 解析失败,返回 null yield null; } } - case StringLiteralNode str -> str.value(); // 字符串字面量,返回内容 - case BoolLiteralNode b -> b.getValue() ? 1 : 0; // 布尔字面量,true=1,false=0 - default -> null; // 其它类型不支持 + case StringLiteralNode str -> str.value(); + case BoolLiteralNode b -> b.getValue() ? 1 : 0; + default -> null; }; } @@ -140,23 +129,41 @@ public final class IRProgramBuilder { /** * 构建带有模块全局声明“注入”的函数,并将函数名加上模块前缀,保证模块内函数名唯一。 - *

- * 如果模块有全局声明,则这些声明会被插入到函数体前部。 + * 如果模块有全局声明,则这些声明会被插入到函数体前部(**会过滤掉与参数同名的全局声明**)。 * - * @param moduleNode 当前模块节点 - * @param functionNode 模块中的函数节点 - * @return 包含全局声明、已加前缀函数名的 IRFunction + * @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(renameFunction(functionNode, qualifiedName)); } - // 若有全局声明,插入到函数体最前面 - List newBody = new ArrayList<>(moduleNode.globals().size() + functionNode.body().size()); - newBody.addAll(moduleNode.globals()); + + // ------- 过滤与参数重名的全局声明 ------- + Set paramNames = new HashSet<>(); + for (ParameterNode p : functionNode.parameters()) { + paramNames.add(p.name()); + } + List filteredGlobals = new ArrayList<>(); + for (DeclarationNode g : moduleNode.globals()) { + // 避免全局声明和参数重名,优先参数 + if (!paramNames.contains(g.getName())) { + filteredGlobals.add(g); + } + } + + if (filteredGlobals.isEmpty()) { + // 过滤后已无可插入的全局声明 + return buildFunction(renameFunction(functionNode, qualifiedName)); + } + + // 合并全局声明与函数体,前插全局声明 + List newBody = new ArrayList<>(filteredGlobals.size() + functionNode.body().size()); + newBody.addAll(filteredGlobals); newBody.addAll(functionNode.body()); FunctionNode wrapped = new FunctionNode( qualifiedName, @@ -169,11 +176,11 @@ public final class IRProgramBuilder { } /** - * 生成一个重命名的 FunctionNode(只修改函数名,其他属性保持不变)。 + * 生成一个重命名的 FunctionNode(只修改函数名,其他属性保持不变)。 * * @param fn 原始函数节点 - * @param newName 新的函数名(通常为全限定名) - * @return 重命名后的 FunctionNode + * @param newName 新的函数名(全限定名) + * @return 重命名后的函数节点 */ private FunctionNode renameFunction(FunctionNode fn, String newName) { return new FunctionNode( @@ -188,8 +195,8 @@ public final class IRProgramBuilder { /** * 构建 IRFunction。 * - * @param functionNode 要转换的函数节点 - * @return 转换结果 IRFunction + * @param functionNode 待构建的 FunctionNode + * @return 构建后的 IRFunction */ private IRFunction buildFunction(FunctionNode functionNode) { return new FunctionBuilder().build(functionNode); @@ -197,11 +204,10 @@ public final class IRProgramBuilder { /** * 将顶层语句节点封装成特殊的 "_start" 函数。 - *

- * 这对于脚本式文件支持至关重要(即文件最外层直接写语句)。 + * 主要用于脚本模式支持,使得顶层语句也可以被 IR 执行引擎统一处理。 * - * @param stmt 要封装的顶层语句 - * @return 包装成 FunctionNode 的 "_start" 函数 + * @param stmt 顶层语句节点 + * @return 封装后的 FunctionNode */ private FunctionNode wrapTopLevel(StatementNode stmt) { return new FunctionNode(