From b56824d935239b0e5593daab488205eadfa11b0e Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 29 Aug 2025 17:38:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E4=BB=A5=20'this'=20?= =?UTF-8?q?=E5=BC=80=E5=A4=B4=E7=9A=84=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=B9=B6?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B5=8B=E5=80=BC=E8=AF=AD=E5=8F=A5=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 允许 'this'作为表达式起始,支持 'this.xxx' 形式的赋值 - 优化赋值语句解析逻辑,支持更复杂的左值表达式 - 新增对 'this' 成员赋值的特殊处理,降级为普通变量赋值 - 改进错误处理,对不支持的赋值左值类型抛出异常 --- .../semantic/core/FunctionChecker.java | 110 ++++++------------ 1 file changed, 38 insertions(+), 72 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java index c57bd07..0a585b9 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/FunctionChecker.java @@ -4,123 +4,89 @@ import org.jcnc.snow.compiler.parser.ast.DeclarationNode; import org.jcnc.snow.compiler.parser.ast.FunctionNode; import org.jcnc.snow.compiler.parser.ast.ModuleNode; import org.jcnc.snow.compiler.parser.ast.ReturnNode; +import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.semantic.analyzers.base.StatementAnalyzer; import org.jcnc.snow.compiler.semantic.error.SemanticError; import org.jcnc.snow.compiler.semantic.symbol.Symbol; import org.jcnc.snow.compiler.semantic.symbol.SymbolKind; import org.jcnc.snow.compiler.semantic.symbol.SymbolTable; import org.jcnc.snow.compiler.semantic.type.BuiltinType; +import org.jcnc.snow.compiler.semantic.type.Type; import java.util.ArrayList; import java.util.List; /** - * {@code FunctionChecker} 是 Snow 编译器语义分析阶段用于检查所有函数体合法性的总控调度器。 - *

- * 设计核心:采用“两遍扫描”方案,彻底解决跨模块全局变量/常量类型推断和引用依赖问题: - *

- * 功能职责: - * - * - * @param ctx 全局语义分析上下文,持有模块信息、符号表、错误收集等资源 + * 对所有模块的函数体进行两遍扫描的语义检查: + * 1) 先为每个模块建立全局符号表(globals),注册模块级变量/常量; + * 2) 再在全局表就绪后,依次分析各函数体。 */ public record FunctionChecker(Context ctx) { - /** - * 主入口:对所有模块的所有函数体进行语义检查(两遍扫描实现)。 - *

- * 第一遍:为每个模块提前构建全局符号表(包含本模块所有全局变量和常量), - * 并注册到 {@link ModuleInfo},确保跨模块引用时所有全局符号都已可用。 - *
- * 第二遍:遍历所有模块的所有函数,对每个函数体: - *

- * - * @param mods 所有模块的 AST 根节点集合 - */ public void check(Iterable mods) { List moduleList = new ArrayList<>(); - // ---------- 第1遍:收集所有全局符号表 ---------- + + // ---------- 第一遍:构建并注册各模块全局符号表 ---------- for (ModuleNode mod : mods) { + ctx.setCurrentModule(mod.name()); moduleList.add(mod); - // 获取当前模块的元信息 ModuleInfo mi = ctx.modules().get(mod.name()); - // 创建本模块全局作用域(无父作用域) SymbolTable globalScope = new SymbolTable(null); - // 注册所有全局变量/常量到符号表 for (DeclarationNode g : mod.globals()) { - var t = ctx.parseType(g.getType()); - SymbolKind k = g.isConst() ? SymbolKind.CONSTANT : SymbolKind.VARIABLE; + Type t = ctx.parseType(g.getType()); + if (t == null) { + ctx.errors().add(new SemanticError(g, "未知类型: " + g.getType())); + t = BuiltinType.INT; // 兜底,避免后续 NPE + } + SymbolKind kind = g.isConst() ? SymbolKind.CONSTANT : SymbolKind.VARIABLE; String dupType = g.isConst() ? "常量" : "变量"; - // 检查重复声明 - if (!globalScope.define(new Symbol(g.getName(), t, k))) { - ctx.errors().add(new SemanticError( - g, - dupType + "重复声明: " + g.getName() - )); + if (!globalScope.define(new Symbol(g.getName(), t, kind))) { + ctx.errors().add(new SemanticError(g, dupType + "重复声明: " + g.getName())); } } - // 注册到模块信息,供跨模块引用 mi.setGlobals(globalScope); } - // ---------- 第2遍:遍历所有函数,分析函数体 ---------- + // ---------- 第二遍:遍历各模块函数并分析函数体 ---------- for (ModuleNode mod : moduleList) { + ctx.setCurrentModule(mod.name()); ModuleInfo mi = ctx.modules().get(mod.name()); SymbolTable globalScope = mi.getGlobals(); for (FunctionNode fn : mod.functions()) { - // 构建函数局部作用域,父作用域为 globalScope + // 构建函数局部作用域:父作用域为全局 SymbolTable locals = new SymbolTable(globalScope); // 注册函数参数为局部变量 - fn.parameters().forEach(p -> - locals.define(new Symbol( - p.name(), - ctx.parseType(p.type()), - SymbolKind.VARIABLE - )) - ); + fn.parameters().forEach(p -> { + Type t = ctx.parseType(p.type()); + if (t == null) { + ctx.errors().add(new SemanticError(p, "未知类型: " + p.type())); + t = BuiltinType.INT; + } + locals.define(new Symbol(p.name(), t, SymbolKind.VARIABLE)); + }); - // 分析函数体内每条语句 - for (var stmt : fn.body()) { - var analyzer = ctx.getRegistry().getStatementAnalyzer(stmt); + // 分析函数体语句 —— 关键修复:传“实例”而不是 Class + for (StatementNode stmt : fn.body()) { + @SuppressWarnings("unchecked") + StatementAnalyzer analyzer = + (StatementAnalyzer) ctx.getRegistry().getStatementAnalyzer(stmt); if (analyzer != null) { analyzer.analyze(ctx, mi, fn, locals, stmt); } else { - ctx.errors().add(new SemanticError( - stmt, - "不支持的语句类型: " + stmt - )); + ctx.errors().add(new SemanticError(stmt, "不支持的语句类型: " + stmt)); } } - // 检查非 void 函数是否至少包含一条 return 语句 - var returnType = ctx.parseType(fn.returnType()); - if (returnType != BuiltinType.VOID) { - boolean hasReturn = fn.body().stream() - .anyMatch(stmtNode -> stmtNode instanceof ReturnNode); + // 非 void 的函数必须至少包含一条 return + Type ret = ctx.parseType(fn.returnType()); + if (ret != null && ret != BuiltinType.VOID) { + boolean hasReturn = fn.body().stream().anyMatch(s -> s instanceof ReturnNode); if (!hasReturn) { - ctx.errors().add(new SemanticError( - fn, - "非 void 函数必须包含至少一条 return 语句" - )); + ctx.errors().add(new SemanticError(fn, "非 void 函数必须包含至少一条 return 语句")); } } }