diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/NewExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/NewExpressionAnalyzer.java new file mode 100644 index 0000000..821b830 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/NewExpressionAnalyzer.java @@ -0,0 +1,121 @@ +package org.jcnc.snow.compiler.semantic.analyzers.expression; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.NewExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.semantic.analyzers.base.ExpressionAnalyzer; +import org.jcnc.snow.compiler.semantic.core.Context; +import org.jcnc.snow.compiler.semantic.core.ModuleInfo; +import org.jcnc.snow.compiler.semantic.error.SemanticError; +import org.jcnc.snow.compiler.semantic.symbol.SymbolTable; +import org.jcnc.snow.compiler.semantic.type.BuiltinType; +import org.jcnc.snow.compiler.semantic.type.FunctionType; +import org.jcnc.snow.compiler.semantic.type.StructType; +import org.jcnc.snow.compiler.semantic.type.Type; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@code NewExpressionAnalyzer} + *

+ * 负责“对象创建表达式”new T(args...)的语义分析与类型推断。 + *

+ * + *

+ * 表达式类型: 返回被 new 的结构体类型 T,如失败则降级为 int。 + *

+ */ +public class NewExpressionAnalyzer implements ExpressionAnalyzer { + + /** + * 语义分析:推断 new 表达式的类型、参数检查、构造函数合法性校验。 + * + * @param ctx 全局语义分析上下文 + * @param mi 当前模块信息 + * @param fn 当前所在函数节点 + * @param locals 局部符号表(当前作用域变量/形参) + * @param expr new 表达式节点 + * @return 分析推断得到的类型;如出错则降级为 int 类型 + */ + @Override + public Type analyze(Context ctx, + ModuleInfo mi, + FunctionNode fn, + SymbolTable locals, + NewExpressionNode expr) { + + final String typeName = expr.typeName(); + + // 1) 解析目标类型(通过语义上下文统一入口,支持别名、跨模块等情况) + Type parsed = ctx.parseType(typeName); + if (parsed == null) { + // 类型不存在,报错并降级 + ctx.errors().add(new SemanticError(expr, "未知类型: " + typeName)); + return BuiltinType.INT; // 兜底,避免连锁报错 + } + if (!(parsed instanceof StructType st)) { + // 非结构体类型不能用 new + ctx.errors().add(new SemanticError(expr, "只有结构体类型才能使用 new: " + parsed)); + return BuiltinType.INT; + } + + // 2) 分析所有实参的类型 + List argTypes = new ArrayList<>(); + for (ExpressionNode a : expr.arguments()) { + Type at = ctx.getRegistry() + .getExpressionAnalyzer(a) + .analyze(ctx, mi, fn, locals, a); + if (at == null) { + // 兜底处理,防止后续 NPE + at = BuiltinType.INT; + } + argTypes.add(at); + } + + // 3) 检查并获取结构体构造函数(init)签名 + FunctionType ctor = st.getConstructor(); + if (ctor == null) { + // 未定义构造函数,仅允许零参数,否则报错 + if (!argTypes.isEmpty()) { + ctx.errors().add(new SemanticError(expr, + "结构体 " + st.name() + " 未定义构造函数 init,不能接收参数")); + } + // 允许 new T() 零参数构造 + return st; + } + + // 3.1) 构造函数参数数量检查 + if (ctor.paramTypes().size() != argTypes.size()) { + ctx.errors().add(new SemanticError(expr, + String.format("构造函数参数数量不匹配: 期望 %d 个, 实际 %d 个", + ctor.paramTypes().size(), argTypes.size()))); + return st; + } + + // 3.2) 构造函数参数类型兼容性检查(包括数值类型宽化) + for (int i = 0; i < argTypes.size(); i++) { + Type expected = ctor.paramTypes().get(i); // 构造函数声明的参数类型 + Type actual = argTypes.get(i); // 实际传入的实参类型 + + boolean compatible = expected.isCompatible(actual); // 直接类型兼容 + boolean widenOK = expected.isNumeric() + && actual.isNumeric() + && expected.equals(Type.widen(actual, expected)); // 支持数值类型自动宽化 + + if (!compatible && !widenOK) { + // 实参类型不兼容也无法宽化,报错 + ctx.errors().add(new SemanticError(expr, + String.format("构造函数参数类型不匹配 (位置 %d): 期望 %s, 实际 %s", + i, expected, actual))); + } + } + + // 4) new 表达式的类型就是结构体类型 + return st; + } +}