feat: 新增对象创建表达式语义分析器

- 实现了 NewExpressionAnalyzer 类,负责分析和推断 "new T(args...)" 表达式的类型
- 校验目标类型是否为结构体,参数数量与类型是否匹配构造函数
- 支持数值类型的自动宽化
- 在类型解析失败时提供详细的错误信息
This commit is contained in:
Luke 2025-08-29 17:56:09 +08:00
parent a34f51dee1
commit 2abe056056

View File

@ -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}
* <p>
* 负责对象创建表达式<code>new T(args...)</code>的语义分析与类型推断
* <ul>
* <li>分析 new 关键字创建结构体对象的表达式</li>
* <li>校验目标类型是否为结构体参数数量与类型是否匹配构造函数</li>
* <li>出错时会收集详细的语义错误信息</li>
* </ul>
*
* <p>
* <b>表达式类型</b> 返回被 new 的结构体类型 <code>T</code>如失败则降级为 int
* </p>
*/
public class NewExpressionAnalyzer implements ExpressionAnalyzer<NewExpressionNode> {
/**
* 语义分析推断 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<Type> 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;
}
}