refactor: 优化全局变量处理和常量折叠逻辑
- 过滤与函数参数重名的全局声明,避免命名冲突 - 优化常量折叠逻辑,支持跨模块常量优化- 修复字符串字面量和布尔字面量的处理 - 优化代码结构,提高可读性和可维护性
This commit is contained in:
parent
71cbb3a737
commit
b058ee4526
@ -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 原生类型(int、long、double、String等),仅支持直接字面量。
|
||||||
* 用于从表达式节点中解析出直接可用于全局常量表注册的 Java 值,
|
|
||||||
* 支持以下字面量类型:
|
|
||||||
* <ul>
|
|
||||||
* <li>整数与浮点(可带下划线分隔符,支持类型后缀 b/s/l/f/d,自动转换为对应 Java 基本类型)</li>
|
|
||||||
* <li>字符串字面量,直接返回内容</li>
|
|
||||||
* <li>布尔字面量,true 返回 1,false 返回 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=1,false=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(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user