refactor: 优化全局变量处理和常量折叠逻辑

- 过滤与函数参数重名的全局声明,避免命名冲突
- 优化常量折叠逻辑,支持跨模块常量优化- 修复字符串字面量和布尔字面量的处理
- 优化代码结构,提高可读性和可维护性
This commit is contained in:
Luke 2025-08-26 16:25:19 +08:00
parent 71cbb3a737
commit b058ee4526

View File

@ -10,7 +10,9 @@ import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* IRProgramBuilder 负责将 AST 顶层节点转换为可执行的 {@link IRProgram} * IRProgramBuilder 负责将 AST 顶层节点转换为可执行的 {@link IRProgram}
@ -38,16 +40,16 @@ public final class IRProgramBuilder {
for (Node node : roots) { for (Node node : roots) {
switch (node) { switch (node) {
case ModuleNode moduleNode -> { case ModuleNode moduleNode -> {
// 处理模块节点:遍历其中所有函数统一用模块名.函数名作为全限定名 // 处理模块节点遍历其中所有函数统一用模块名.函数名作为全限定名避免命名冲突
for (FunctionNode f : moduleNode.functions()) { for (FunctionNode f : moduleNode.functions()) {
irProgram.add(buildFunctionWithGlobals(moduleNode, f)); irProgram.add(buildFunctionWithGlobals(moduleNode, f));
} }
} }
case FunctionNode functionNode -> case FunctionNode functionNode ->
// 处理顶层函数节点:直接构建为 IRFunction 并加入 // 处理顶层函数节点直接构建为 IRFunction 并加入
irProgram.add(buildFunction(functionNode)); irProgram.add(buildFunction(functionNode));
case StatementNode statementNode -> case StatementNode statementNode ->
// 处理脚本式顶层语句:封装成 "_start" 函数后构建并添加 // 处理脚本式顶层语句封装成 "_start" 函数后构建并添加
irProgram.add(buildFunction(wrapTopLevel(statementNode))); irProgram.add(buildFunction(wrapTopLevel(statementNode)));
default -> default ->
// 遇到未知类型节点抛出异常 // 遇到未知类型节点抛出异常
@ -62,10 +64,9 @@ public final class IRProgramBuilder {
/** /**
* 扫描所有模块节点将其中声明的 const 全局变量compile-time 常量 * 扫描所有模块节点将其中声明的 const 全局变量compile-time 常量
* "模块名.常量名" 形式注册到全局常量表 * "模块名.常量名" 形式注册到全局常量表
* <p> * 支持跨模块常量折叠用于后续 IR 生成过程中的常量折叠优化
* 只处理直接字面量数字字符串布尔暂不支持复杂表达式
* *
* @param roots 所有顶层 AST 节点 * @param roots AST 顶层节点列表
*/ */
private void preloadGlobals(List<Node> roots) { private void preloadGlobals(List<Node> roots) {
for (Node n : roots) { for (Node n : roots) {
@ -73,6 +74,7 @@ public final class IRProgramBuilder {
String moduleName = mod.name(); String moduleName = mod.name();
if (mod.globals() == null) continue; if (mod.globals() == null) continue;
for (DeclarationNode decl : mod.globals()) { for (DeclarationNode decl : mod.globals()) {
// 只处理 compile-time const 常量并要求有初始值
if (!decl.isConst() || decl.getInitializer().isEmpty()) continue; if (!decl.isConst() || decl.getInitializer().isEmpty()) continue;
ExpressionNode init = decl.getInitializer().get(); ExpressionNode init = decl.getInitializer().get();
Object value = evalLiteral(init); Object value = evalLiteral(init);
@ -86,53 +88,40 @@ public final class IRProgramBuilder {
/** /**
* 字面量提取与类型折叠工具 * 字面量提取与类型折叠工具
* <p> * 用于将表达式节点还原为 Java 原生类型intlongdoubleString等仅支持直接字面量
* 用于从表达式节点中解析出直接可用于全局常量表注册的 Java
* 支持以下字面量类型
* <ul>
* <li>整数与浮点可带下划线分隔符支持类型后缀 b/s/l/f/d自动转换为对应 Java 基本类型</li>
* <li>字符串字面量直接返回内容</li>
* <li>布尔字面量true 返回 1false 返回 0用于数值语境</li>
* </ul>
* 不支持的表达式或解析失败将返回 null
* *
* @param expr 字面量表达式节点通常为 NumberLiteralNode/StringLiteralNode/BoolLiteralNode * @param expr 要计算的表达式节点
* @return 提取出的 Java 可为 Integer/Byte/Short/Long/Double/String/Integer(布尔) null * @return 提取到的原生常量值不支持的情况返回 null
*/ */
private Object evalLiteral(ExpressionNode expr) { private Object evalLiteral(ExpressionNode expr) {
return switch (expr) { return switch (expr) {
case NumberLiteralNode num -> { case NumberLiteralNode num -> {
String raw = num.value(); String raw = num.value();
// 1. 去掉下划线分隔符便于解析 1_000_000
String s = raw.replace("_", ""); String s = raw.replace("_", "");
// 2. 提取类型后缀b/s/l/f/d若有则去除
char last = Character.toLowerCase(s.charAt(s.length() - 1)); char last = Character.toLowerCase(s.charAt(s.length() - 1));
String core = switch (last) { String core = switch (last) {
case 'b', 's', 'l', 'f', 'd' -> s.substring(0, s.length() - 1); case 'b', 's', 'l', 'f', 'd' -> s.substring(0, s.length() - 1);
default -> s; default -> s;
}; };
try { try {
// 3. 若为浮点字面量或科学计数法直接转 double
if (core.contains(".") || core.contains("e") || core.contains("E")) { 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); long lv = Long.parseLong(core);
yield switch (last) { yield switch (last) {
case 'b' -> (byte) lv; // 末尾 b byte case 'b' -> (byte) lv;
case 's' -> (short) lv; // 末尾 s short case 's' -> (short) lv;
case 'l' -> lv; // 末尾 l long case 'l' -> lv;
default -> (int) lv; // 无后缀 int default -> (int) lv;
}; };
} catch (NumberFormatException ignore) { } catch (NumberFormatException ignore) {
// 解析失败返回 null
yield null; yield null;
} }
} }
case StringLiteralNode str -> str.value(); // 字符串字面量返回内容 case StringLiteralNode str -> str.value();
case BoolLiteralNode b -> b.getValue() ? 1 : 0; // 布尔字面量true=1false=0 case BoolLiteralNode b -> b.getValue() ? 1 : 0;
default -> null; // 其它类型不支持 default -> null;
}; };
} }
@ -140,23 +129,41 @@ public final class IRProgramBuilder {
/** /**
* 构建带有模块全局声明注入的函数并将函数名加上模块前缀保证模块内函数名唯一 * 构建带有模块全局声明注入的函数并将函数名加上模块前缀保证模块内函数名唯一
* <p> * 如果模块有全局声明则这些声明会被插入到函数体前部**会过滤掉与参数同名的全局声明**
* 如果模块有全局声明则这些声明会被插入到函数体前部
* *
* @param moduleNode 当前模块节点 * @param moduleNode 所属模块节点
* @param functionNode 模块中的函数节点 * @param functionNode 待构建的函数节点
* @return 包含全局声明已加前缀函数名 IRFunction * @return 包含全局声明 IRFunction
*/ */
private IRFunction buildFunctionWithGlobals(ModuleNode moduleNode, FunctionNode functionNode) { private IRFunction buildFunctionWithGlobals(ModuleNode moduleNode, FunctionNode functionNode) {
// 拼接模块名和函数名生成全限定名 // 拼接模块名和函数名生成全限定名
String qualifiedName = moduleNode.name() + "." + functionNode.name(); String qualifiedName = moduleNode.name() + "." + functionNode.name();
// 若无全局声明仅重命名后直接构建
if (moduleNode.globals() == null || moduleNode.globals().isEmpty()) { if (moduleNode.globals() == null || moduleNode.globals().isEmpty()) {
// 无全局声明直接重命名构建
return buildFunction(renameFunction(functionNode, qualifiedName)); return buildFunction(renameFunction(functionNode, qualifiedName));
} }
// 若有全局声明插入到函数体最前面
List<StatementNode> newBody = new ArrayList<>(moduleNode.globals().size() + functionNode.body().size()); // ------- 过滤与参数重名的全局声明 -------
newBody.addAll(moduleNode.globals()); Set<String> paramNames = new HashSet<>();
for (ParameterNode p : functionNode.parameters()) {
paramNames.add(p.name());
}
List<StatementNode> 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<StatementNode> newBody = new ArrayList<>(filteredGlobals.size() + functionNode.body().size());
newBody.addAll(filteredGlobals);
newBody.addAll(functionNode.body()); newBody.addAll(functionNode.body());
FunctionNode wrapped = new FunctionNode( FunctionNode wrapped = new FunctionNode(
qualifiedName, qualifiedName,
@ -169,11 +176,11 @@ public final class IRProgramBuilder {
} }
/** /**
* 生成一个重命名的 FunctionNode(只修改函数名其他属性保持不变) * 生成一个重命名的 FunctionNode只修改函数名其他属性保持不变
* *
* @param fn 原始函数节点 * @param fn 原始函数节点
* @param newName 新的函数名(通常为全限定名) * @param newName 新的函数名全限定名
* @return 重命名后的 FunctionNode * @return 重命名后的函数节点
*/ */
private FunctionNode renameFunction(FunctionNode fn, String newName) { private FunctionNode renameFunction(FunctionNode fn, String newName) {
return new FunctionNode( return new FunctionNode(
@ -188,8 +195,8 @@ public final class IRProgramBuilder {
/** /**
* 构建 IRFunction * 构建 IRFunction
* *
* @param functionNode 要转换的函数节点 * @param functionNode 待构建的 FunctionNode
* @return 转换结果 IRFunction * @return 构建后的 IRFunction
*/ */
private IRFunction buildFunction(FunctionNode functionNode) { private IRFunction buildFunction(FunctionNode functionNode) {
return new FunctionBuilder().build(functionNode); return new FunctionBuilder().build(functionNode);
@ -197,11 +204,10 @@ public final class IRProgramBuilder {
/** /**
* 将顶层语句节点封装成特殊的 "_start" 函数 * 将顶层语句节点封装成特殊的 "_start" 函数
* <p> * 主要用于脚本模式支持使得顶层语句也可以被 IR 执行引擎统一处理
* 这对于脚本式文件支持至关重要(即文件最外层直接写语句)
* *
* @param stmt 要封装的顶层语句 * @param stmt 顶层语句节点
* @return 包装成 FunctionNode "_start" 函数 * @return 封装后的 FunctionNode
*/ */
private FunctionNode wrapTopLevel(StatementNode stmt) { private FunctionNode wrapTopLevel(StatementNode stmt) {
return new FunctionNode( return new FunctionNode(