feat: 支持模块成员访问的语义分析

- 实现了跨模块常量和全局变量访问的语义分析- 能根据目标模块的全局符号表返回准确的类型信息- 完全支持跨模块类型推断
- 对非模块成员访问的情况增加了错误处理
This commit is contained in:
Luke 2025-08-26 14:32:58 +08:00
parent 439304c86a
commit f39aece9cf

View File

@ -8,35 +8,42 @@ import org.jcnc.snow.compiler.semantic.analyzers.base.ExpressionAnalyzer;
import org.jcnc.snow.compiler.semantic.core.Context; import org.jcnc.snow.compiler.semantic.core.Context;
import org.jcnc.snow.compiler.semantic.core.ModuleInfo; import org.jcnc.snow.compiler.semantic.core.ModuleInfo;
import org.jcnc.snow.compiler.semantic.error.SemanticError; 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.symbol.SymbolTable;
import org.jcnc.snow.compiler.semantic.type.BuiltinType; import org.jcnc.snow.compiler.semantic.type.BuiltinType;
import org.jcnc.snow.compiler.semantic.type.Type; import org.jcnc.snow.compiler.semantic.type.Type;
/** /**
* {@code MemberExpressionAnalyzer} 成员访问表达式的语义分析器 * {@code MemberExpressionAnalyzer} 用于分析模块成员访问表达式的类型和语义
* *
* <p> * <p>
* 当前实现仅支持 <code>ModuleName.constOrVar</code> 形式的跨模块常量 / * 当前实现支持 <code>ModuleName.constOrVar</code> 形式的跨模块常量/全局变量访问
* 全局变量访问不支持对象成员 a.b.c * 能根据目标模块的全局符号表返回准确的类型信息完全支持跨模块类型推断
* <br>
* 对于非模块成员的访问如对象.属性多级 a.b.c暂不支持遇到时将报告语义错误
* </p> * </p>
* *
* <p>
* <b>核心特性</b>
* <ul> * <ul>
* <li>示例ModuleA.a ModuleB.CONST_X</li> * <li>校验模块是否存在是否已导入或自身</li>
* <li>仅检查模块是否存在且已导入类型降级为 int后续由 IR 阶段常量折叠</li> * <li>跨模块访问目标模块的全局符号表查找指定成员符号及其类型</li>
* <li>暂不支持复杂的对象/类型成员访问</li> * <li>若成员不存在报告模块成员未定义语义错误</li>
* <li>暂不支持更复杂的对象成员访问遇到将报不支持的成员访问对象类型错误</li>
* </ul> * </ul>
* </p>
*/ */
public class MemberExpressionAnalyzer implements ExpressionAnalyzer<MemberExpressionNode> { public class MemberExpressionAnalyzer implements ExpressionAnalyzer<MemberExpressionNode> {
/** /**
* 对成员访问表达式执行语义分析 * 语义分析模块成员访问表达式
* *
* @param ctx 全局语义上下文包含模块表错误收集等 * @param ctx 全局语义分析上下文持有所有模块及错误记录
* @param mi 当前模块信息含本模块名已导入模块 * @param mi 当前模块信息用于判断导入关系
* @param fn 当前所在函数节点 * @param fn 当前函数节点
* @param locals 当前作用域符号表 * @param locals 当前局部符号表
* @param expr 当前要分析的成员表达式 ModuleA.a * @param expr 当前要分析的成员表达式 ModuleA.a
* @return 分析推断得到的类型目前恒定降级为 int如有错误也会记录 * @return 成员表达式的类型出错时类型降级为 int并记录语义错误
*/ */
@Override @Override
public Type analyze(Context ctx, public Type analyze(Context ctx,
@ -47,29 +54,41 @@ public class MemberExpressionAnalyzer implements ExpressionAnalyzer<MemberExpres
ctx.log("检查成员访问: " + expr); ctx.log("检查成员访问: " + expr);
/* ---------- 仅支持 ModuleName.member 形式 ---------- */ // -------- 仅支持 ModuleName.member 形式 --------
if (expr.object() instanceof IdentifierNode(String mod, NodeContext _)) { if (expr.object() instanceof IdentifierNode(String mod, NodeContext _)) {
// 1. 检查模块是否存在且已在当前模块 import 或为本模块 // 1. 校验模块存在且已导入或为本模块自身
if (!ctx.getModules().containsKey(mod) if (!ctx.getModules().containsKey(mod)
|| (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) { || (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) {
ctx.getErrors().add(new SemanticError(expr, ctx.getErrors().add(new SemanticError(expr,
"未知或未导入模块: " + mod)); "未知或未导入模块: " + mod));
ctx.log("错误: 未导入模块 " + mod); ctx.log("错误: 未导入模块 " + mod);
return BuiltinType.INT; // 语义降级默认 int
}
// 2. 目前不做类型精确推断后续可解析目标模块 globals 获取精确类型
// 这里只做语法级校验类型降级为 INT由后续阶段折叠
return BuiltinType.INT; return BuiltinType.INT;
} }
/* ---------- 其它对象成员(如 a.b.c暂不支持 ---------- */ // 2. 查找目标模块的全局符号表精确返回成员类型
ModuleInfo target = ctx.getModules().get(mod);
SymbolTable globals = target.getGlobals();
if (globals != null) {
Symbol sym = globals.resolve(expr.member());
if (sym != null) {
return sym.type(); // 找到成员返回其真实类型
}
}
// 3. 成员不存在记录语义错误并类型降级
ctx.getErrors().add(new SemanticError(expr,
"模块成员未定义: " + mod + "." + expr.member()));
ctx.log("错误: 模块成员未定义 " + mod + "." + expr.member());
return BuiltinType.INT;
}
// -------- 其它对象成员 a.b.c暂不支持 --------
ctx.getErrors().add(new SemanticError(expr, ctx.getErrors().add(new SemanticError(expr,
"不支持的成员访问对象类型: " "不支持的成员访问对象类型: "
+ expr.object().getClass().getSimpleName())); + expr.object().getClass().getSimpleName()));
ctx.log("错误: 不支持的成员访问对象类型 " ctx.log("错误: 不支持的成员访问对象类型 "
+ expr.object().getClass().getSimpleName()); + expr.object().getClass().getSimpleName());
return BuiltinType.INT; // 语义降级 return BuiltinType.INT;
} }
} }