feat: 语义分析支持结构体成员访问

- 新增对结构体实例成员和方法访问的支持
- 扩展跨模块成员访问,支持模块内的函数引用
- 优化了对成员访问表达式的处理逻辑,提高了类型推断的准确性和范围
- 修复了一些与成员访问相关的语义错误处理问题
This commit is contained in:
Luke 2025-08-29 17:50:58 +08:00
parent 1f7458be28
commit 258d1909e6

View File

@ -11,39 +11,49 @@ import org.jcnc.snow.compiler.semantic.error.SemanticError;
import org.jcnc.snow.compiler.semantic.symbol.Symbol;
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;
/**
* {@code MemberExpressionAnalyzer} 用于分析模块成员访问表达式的类型和语义
* {@code MemberExpressionAnalyzer}
*
* <p>
* 当前实现支持 <code>ModuleName.constOrVar</code> 形式的跨模块常量/全局变量访问
* 能根据目标模块的全局符号表返回准确的类型信息完全支持跨模块类型推断
* <br>
* 对于非模块成员的访问如对象.属性多级 a.b.c暂不支持遇到时将报告语义错误
* 负责成员访问表达式的语义分析与类型推断
* 典型形如 <code>a.b</code><code>this.x</code><code>Module.member</code>
* </p>
*
* <p>
* <b>核心特性</b>
* <ul>
* <li>校验模块是否存在是否已导入或自身</li>
* <li>跨模块访问目标模块的全局符号表查找指定成员符号及其类型</li>
* <li>若成员不存在报告模块成员未定义语义错误</li>
* <li>暂不支持更复杂的对象成员访问遇到将报不支持的成员访问对象类型错误</li>
* </ul>
* 支持三类成员访问方式
* </p>
* <ol>
* <li><b>当前实例字段语法糖</b> <code>this.x</code>等价于访问当前作用域下名为 <code>x</code> 的变量或字段</li>
* <li><b>跨模块成员访问</b> <code>ModuleName.member</code>常用于引用其他模块的全局变量常量函数等</li>
* <li><b>结构体实例成员/方法访问</b> <code>a.b</code> <code>a.method</code>a 为结构体变量b 为字段或方法</li>
* </ol>
*/
public class MemberExpressionAnalyzer implements ExpressionAnalyzer<MemberExpressionNode> {
/**
* 语义分析模块成员访问表达式
* 分析成员表达式并返回其类型如字段类型方法类型等
*
* @param ctx 全局语义分析上下文持有所有模块及错误记录
* @param mi 当前模块信息用于判断导入关系
* @param ctx 全局语义分析上下文
* @param mi 当前模块信息
* @param fn 当前函数节点
* @param locals 当前局部符号表
* @param expr 当前要分析的成员表达式 ModuleA.a
* @return 成员表达式的类型出错时类型降级为 int并记录语义错误
* @param locals 局部符号表当前作用域的变量形参等
* @param expr 当前成员访问表达式形如 obj.member
* @return 该表达式的推断类型如失败则返回 {@link BuiltinType#INT}
*
* <p>
* 主要处理流程分为四大分支
* <ol>
* <li>this.x 语法糖字段或变量访问</li>
* <li>ModuleName.member 跨模块成员访问</li>
* <li>结构体实例的成员/方法访问</li>
* <li>其它对象成员不支持</li>
* </ol>
* 出错时会注册语义错误返回 int 作为降级类型
* </p>
*/
@Override
public Type analyze(Context ctx,
@ -54,41 +64,117 @@ public class MemberExpressionAnalyzer implements ExpressionAnalyzer<MemberExpres
ctx.log("检查成员访问: " + expr);
// -------- 仅支持 ModuleName.member 形式 --------
if (expr.object() instanceof IdentifierNode(String mod, NodeContext _)) {
// =====================================================================
// 1) 处理 this.x 语法糖
// =====================================================================
// 匹配左侧为 IdentifierNode且为 "this"
if (expr.object() instanceof IdentifierNode oid) {
String objName = oid.name();
// 1. 校验模块存在且已导入或为本模块自身
if (!ctx.getModules().containsKey(mod)
|| (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) {
if ("this".equals(objName)) {
// 优先在当前局部符号表查找字段或变量如结构体字段/参数/局部变量等
if (locals != null) {
Symbol localSym = locals.resolve(expr.member());
if (localSym != null) {
return localSym.type();
}
}
// 再查全局符号表当前模块全局声明
SymbolTable globals = mi != null ? mi.getGlobals() : null;
if (globals != null) {
Symbol globalSym = globals.resolve(expr.member());
if (globalSym != null) {
return globalSym.type();
}
}
// 两处都查不到则报错
ctx.getErrors().add(new SemanticError(expr,
"未知或未导入模块: " + mod));
ctx.log("错误: 未导入模块 " + mod);
"未定义的字段或变量: " + expr.member()));
ctx.log("错误: 未定义的字段或变量 this." + expr.member());
// 降级为 int 类型
return BuiltinType.INT;
}
}
// 2. 查找目标模块的全局符号表精确返回成员类型
// =====================================================================
// 2) 处理 ModuleName.member 跨模块访问
// =====================================================================
// 左侧为 IdentifierNode尝试解析为模块名
if (expr.object() instanceof IdentifierNode(String mod, NodeContext _)) {
// 是否为已知模块
boolean moduleExists = ctx.getModules().containsKey(mod);
// 是否导入了该模块或就是本模块允许自引用
boolean importedOrSelf = mi != null && (mi.getName().equals(mod) || mi.getImports().contains(mod));
if (moduleExists && importedOrSelf) {
ModuleInfo target = ctx.getModules().get(mod);
SymbolTable globals = target.getGlobals();
// 1) 先查模块内函数支持模块.函数名引用
FunctionType ft = target.getFunctions().get(expr.member());
if (ft != null) return ft;
// 2) 再查模块全局符号表全局常量/变量
SymbolTable globals = target != null ? target.getGlobals() : null;
if (globals != null) {
Symbol sym = globals.resolve(expr.member());
if (sym != null) {
return sym.type(); // 找到成员返回其真实类型
return sym.type();
}
}
// 3. 成员不存在记录语义错误并类型降级
// 以上均未找到则报错
ctx.getErrors().add(new SemanticError(expr,
"模块成员未定义: " + mod + "." + expr.member()));
ctx.log("错误: 模块成员未定义 " + mod + "." + expr.member());
return BuiltinType.INT;
}
// -------- 其它对象成员 a.b.c暂不支持 --------
// 左侧不是模块名可能是变量名结构体实例进入结构体成员分支
if (locals != null) {
Symbol sym = locals.resolve(mod);
if (sym != null && sym.type() instanceof StructType st) {
// 结构体字段访问
Type t = st.getFields().get(expr.member());
if (t != null) return t;
// 结构体方法访问返回方法类型用于引用/分派
FunctionType ft = st.getMethods().get(expr.member());
if (ft != null) return ft;
// 字段和方法都没有报错
ctx.getErrors().add(new SemanticError(expr,
"不支持的成员访问对象类型: "
+ expr.object().getClass().getSimpleName()));
ctx.log("错误: 不支持的成员访问对象类型 "
+ expr.object().getClass().getSimpleName());
"结构体成员未定义: " + st + "." + expr.member()));
ctx.log("错误: 结构体成员未定义 " + st + "." + expr.member());
return BuiltinType.INT;
}
}
// 非模块非变量均未找到报错
ctx.getErrors().add(new SemanticError(expr, "未知或未导入模块: " + mod));
ctx.log("错误: 未导入模块或未声明变量 " + mod);
return BuiltinType.INT;
}
// =====================================================================
// 3) 支持通用结构体成员访问a.b 或任意表达式.b
// =====================================================================
// 动态推断左侧表达式类型如结构体类型等
Type leftType = ctx.getRegistry().getExpressionAnalyzer(expr.object())
.analyze(ctx, mi, fn, locals, expr.object());
if (leftType instanceof StructType st) {
// 字段访问
Type t = st.getFields().get(expr.member());
if (t != null) return t;
// 方法访问返回方法类型支持引用/分派
FunctionType ft = st.getMethods().get(expr.member());
if (ft != null) return ft;
// 均未找到报错
ctx.getErrors().add(new SemanticError(expr,
"结构体成员未定义: " + st + "." + expr.member()));
ctx.log("错误: 结构体成员未定义 " + st + "." + expr.member());
return BuiltinType.INT;
}
// =====================================================================
// 4) 其它对象成员 xx.yy xx 非结构体暂不支持
// =====================================================================
ctx.getErrors().add(new SemanticError(expr,
"不支持的成员访问对象类型: " + expr.object().getClass().getSimpleName()));
ctx.log("错误: 不支持的成员访问对象类型 " + expr.object().getClass().getSimpleName());
return BuiltinType.INT;
}
}