From 439b2fbc1ec4210286dd4d7306ea6454b0e3f2c0 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 10 Jul 2025 02:47:46 +0000 Subject: [PATCH 1/5] update LICENSE. Signed-off-by: Luke --- LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/LICENSE b/LICENSE index 094dd59..8940ae8 100644 --- a/LICENSE +++ b/LICENSE @@ -187,6 +187,7 @@ identification within third-party archives. Copyright © 2025 Ke Xu (Luke), on behalf of the SnowLang Project + Repository: https://gitee.com/jcnc-org/snow Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From ae0baf3e50e496ee19fdc365fdf7221d03566776 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 10 Jul 2025 10:55:46 +0800 Subject: [PATCH 2/5] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=A3=B0=E6=98=8E=E6=96=87=E4=BB=B6=E5=B9=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 NOTICE 文件,包含项目版权、许可信息和贡献者致谢 - 在 README.md 中添加项目仓库地址 --- NOTICE | 15 +++++++++++++++ README.md | 1 + 2 files changed, 16 insertions(+) create mode 100644 NOTICE diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..b289ed9 --- /dev/null +++ b/NOTICE @@ -0,0 +1,15 @@ +========================================== +SnowLang Project – NOTICE +========================================== + +Copyright © 2025 Ke Xu (Luke), on behalf of the SnowLang Project +Repository: https://gitee.com/jcnc-org/snow + +Licensed under the Apache License, Version 2.0 (the "License") +You may obtain a copy of the License at: + http://www.apache.org/licenses/LICENSE-2.0 + +=============================================================================== +This product includes software developed by the SnowLang Project and +its contributors. +=============================================================================== diff --git a/README.md b/README.md index 74438c3..af43071 100644 --- a/README.md +++ b/README.md @@ -452,6 +452,7 @@ end module ## 版权声明 版权所有 © 2025 许轲(Luke),代表 SnowLang 项目。 +仓库地址: 本项目依据 [Apache 2.0 许可证](LICENSE) 进行许可和发布。 “SnowLang 项目”为由许轲(Luke)发起的独立开源项目。 From 45eed2aefce247669dcc0488fbfbdba2d42ef717 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 8 Jul 2025 12:39:15 +0800 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20AST?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E4=B8=AD=E7=9A=84=E4=BD=8D=E7=BD=AE=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=A1=A8=E7=A4=BA=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入 NodeContext 类统一表示节点的上下文信息(行号、列号、文件名) - 修改相关 AST 节点的构造函数,使用 NodeContext 替代单独的行号、列号和文件名参数 - 更新解析器代码,创建 NodeContext 实例以传递给 AST节点 - 此重构简化了 AST 节点的参数列表,提高了代码的可维护性和可读性 --- .../compiler/ir/builder/IRProgramBuilder.java | 5 +-- .../compiler/ir/builder/StatementBuilder.java | 9 ++-- .../compiler/ir/utils/ComparisonUtils.java | 3 +- .../compiler/ir/utils/ExpressionUtils.java | 3 +- .../compiler/parser/ast/AssignmentNode.java | 11 ++--- .../parser/ast/BinaryExpressionNode.java | 9 ++-- .../compiler/parser/ast/BoolLiteralNode.java | 18 ++++---- .../parser/ast/CallExpressionNode.java | 36 ++------------- .../compiler/parser/ast/DeclarationNode.java | 45 +++++-------------- .../parser/ast/ExpressionStatementNode.java | 11 ++--- .../compiler/parser/ast/FunctionNode.java | 11 ++--- .../compiler/parser/ast/IdentifierNode.java | 11 ++--- .../jcnc/snow/compiler/parser/ast/IfNode.java | 20 ++------- .../snow/compiler/parser/ast/ImportNode.java | 11 ++--- .../snow/compiler/parser/ast/LoopNode.java | 11 ++--- .../parser/ast/MemberExpressionNode.java | 15 +++---- .../snow/compiler/parser/ast/ModuleNode.java | 10 ++--- .../parser/ast/NumberLiteralNode.java | 9 ++-- .../compiler/parser/ast/ParameterNode.java | 15 +++---- .../snow/compiler/parser/ast/ReturnNode.java | 45 +++++-------------- .../parser/ast/StringLiteralNode.java | 11 ++--- .../parser/ast/UnaryExpressionNode.java | 9 ++-- .../snow/compiler/parser/ast/base/Node.java | 20 +-------- .../compiler/parser/ast/base/NodeContext.java | 11 +++++ .../expression/BinaryOperatorParselet.java | 8 ++-- .../expression/BoolLiteralParselet.java | 3 +- .../parser/expression/CallParselet.java | 4 +- .../parser/expression/IdentifierParselet.java | 3 +- .../parser/expression/MemberParselet.java | 3 +- .../expression/NumberLiteralParselet.java | 3 +- .../expression/StringLiteralParselet.java | 3 +- .../expression/UnaryOperatorParselet.java | 3 +- .../compiler/parser/function/ASTPrinter.java | 16 +++---- .../parser/function/FunctionParser.java | 5 ++- .../compiler/parser/module/ImportParser.java | 3 +- .../compiler/parser/module/ModuleParser.java | 3 +- .../statement/DeclarationStatementParser.java | 3 +- .../statement/ExpressionStatementParser.java | 5 ++- .../parser/statement/IfStatementParser.java | 3 +- .../parser/statement/LoopStatementParser.java | 5 ++- .../statement/ReturnStatementParser.java | 3 +- .../parser/utils/ASTJsonSerializer.java | 20 ++++----- .../expression/CallExpressionAnalyzer.java | 7 +-- .../semantic/error/SemanticError.java | 7 +-- 44 files changed, 177 insertions(+), 292 deletions(-) create mode 100644 src/main/java/org/jcnc/snow/compiler/parser/ast/base/NodeContext.java diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java index 5513fdc..225743e 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java @@ -5,6 +5,7 @@ import org.jcnc.snow.compiler.ir.core.IRProgram; import org.jcnc.snow.compiler.parser.ast.FunctionNode; import org.jcnc.snow.compiler.parser.ast.ModuleNode; import org.jcnc.snow.compiler.parser.ast.base.Node; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import java.util.List; @@ -81,9 +82,7 @@ public final class IRProgramBuilder { null, String.valueOf(List.of()), List.of(stmt), - -1, - -1, - "" + new NodeContext(-1, -1, "") ); } } diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java index 557634b..78e42fa 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java @@ -6,6 +6,7 @@ import org.jcnc.snow.compiler.ir.utils.IROpCodeUtils; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.parser.ast.*; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import java.util.Locale; @@ -66,12 +67,12 @@ public class StatementBuilder { buildIf(ifNode); return; } - if (stmt instanceof ExpressionStatementNode(ExpressionNode exp, int _, int _, String _)) { + if (stmt instanceof ExpressionStatementNode(ExpressionNode exp, NodeContext _)) { // 纯表达式语句,如 foo(); expr.build(exp); return; } - if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs, int _, int _, String _)) { + if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs, NodeContext _)) { // 赋值语句,如 a = b + 1; final String type = ctx.getScope().lookupType(var); @@ -209,9 +210,7 @@ public class StatementBuilder { ExpressionNode left, String operator, ExpressionNode right, - _, - _, - _ + NodeContext _ ) && ComparisonUtils.isComparisonOperator(operator)) { diff --git a/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java b/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java index 08b42b8..70ac8f5 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/utils/ComparisonUtils.java @@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.ir.core.IROpCode; import org.jcnc.snow.compiler.ir.core.IROpCodeMappings; import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import java.util.Map; @@ -41,7 +42,7 @@ public final class ComparisonUtils { /* ------------ 内部工具 ------------ */ private static boolean isLongLiteral(ExpressionNode node) { - if (node instanceof NumberLiteralNode(String value, int _, int _, String _)) { + if (node instanceof NumberLiteralNode(String value, NodeContext _)) { return value.endsWith("L") || value.endsWith("l"); } return false; // 变量暂不处理(后续可扩展符号表查询) diff --git a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java index 291b861..2eed575 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java @@ -7,6 +7,7 @@ import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.parser.ast.BinaryExpressionNode; import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import java.util.Map; @@ -127,7 +128,7 @@ public final class ExpressionUtils { /** 递归推断单个表达式节点的类型后缀(b/s/i/l/f/d)。 */ private static char typeChar(ExpressionNode node) { - if (node instanceof NumberLiteralNode(String value, int _, int _, String _)) { + if (node instanceof NumberLiteralNode(String value, NodeContext _)) { char last = Character.toLowerCase(value.charAt(value.length() - 1)); return switch (last) { case 'b','s','i','l','f','d' -> last; diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java index eace610..34b387c 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java @@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code AssignmentNode} 表示抽象语法树(AST)中的赋值语句节点。 @@ -16,16 +17,12 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode; * * @param variable 左值变量名(即赋值目标) * @param value 表达式右值(即赋值来源) - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点的上下文信息(包含行号、列号等) */ public record AssignmentNode( String variable, ExpressionNode value, - int line, - int column, - String file + NodeContext context ) implements StatementNode { /** @@ -40,4 +37,4 @@ public record AssignmentNode( public String toString() { return variable + " = " + value; } -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java index 40412de..ec56cc2 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code BinaryExpressionNode} 表示抽象语法树(AST)中的二元运算表达式节点。 @@ -12,17 +13,13 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; * @param left 左操作数(子表达式) * @param operator 运算符字符串(如 "+", "-", "*", "/" 等) * @param right 右操作数(子表达式) - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文(包含行号、列号等信息) */ public record BinaryExpressionNode( ExpressionNode left, String operator, ExpressionNode right, - int line, - int column, - String file + NodeContext context ) implements ExpressionNode { /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/BoolLiteralNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/BoolLiteralNode.java index bb46a30..909a43c 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/BoolLiteralNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/BoolLiteralNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * 表示布尔字面量(boolean literal)的抽象语法树(AST)节点。 @@ -9,16 +10,12 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; * 表达布尔类型的字面量常量(如 "true" 或 "false")。 *

* - * @param value 字面量的布尔值 - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param value 字面量的布尔值 + * @param context 节点上下文信息(行号、列号等) */ public record BoolLiteralNode( boolean value, - int line, - int column, - String file + NodeContext context ) implements ExpressionNode { /** @@ -28,10 +25,11 @@ public record BoolLiteralNode( * 如果传入的字符串为 "true"(忽略大小写),则解析结果为 {@code true};否则为 {@code false}。 *

* - * @param lexeme 布尔字面量的字符串表示 + * @param lexeme 布尔字面量的字符串表示 + * @param context 节点上下文信息(行号、列号等) */ - public BoolLiteralNode(String lexeme, int line, int column, String file) { - this(Boolean.parseBoolean(lexeme), line, column, file); + public BoolLiteralNode(String lexeme, NodeContext context) { + this(Boolean.parseBoolean(lexeme), context); } /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java index d7dbce9..8033989 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import java.util.List; @@ -12,16 +13,12 @@ import java.util.List; * * @param callee 被调用的表达式节点,通常为函数标识符或成员访问表达式,表示函数名或方法名等。 * @param arguments 参数表达式列表,表示函数调用中传递给函数的实际参数。参数的顺序与调用顺序一致。 - * @param line 当前表达式所在的行号,方便调试和错误定位。 - * @param column 当前表达式所在的列号,用于精确定位错误位置。 - * @param file 当前表达式所在的文件,用于错误定位。 + * @param context 节点上下文信息(包含行号、列号等)。 */ public record CallExpressionNode( ExpressionNode callee, // 被调用的表达式节点,表示函数或方法名 List arguments, // 函数调用的参数表达式列表 - int line, // 当前节点所在的行号 - int column, // 当前节点所在的列号 - String file // 当前节点所在的文件 + NodeContext context // 节点上下文信息(包含行号、列号等) ) implements ExpressionNode { /** @@ -43,31 +40,4 @@ public record CallExpressionNode( sb.append(")"); // 拼接右括号 return sb.toString(); // 返回拼接好的字符串 } - - /** - * 获取当前表达式所在的行号。 - * - * @return 当前表达式的行号。 - */ - public int line() { - return line; - } - - /** - * 获取当前表达式所在的列号。 - * - * @return 当前表达式的列号。 - */ - public int column() { - return column; - } - - /** - * 获取当前表达式所在的文件名。 - * - * @return 当前表达式所在的文件名。 - */ - public String file() { - return file; - } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java index 9e1edf5..dd5bea6 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java @@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import java.util.Optional; @@ -23,14 +24,8 @@ public class DeclarationNode implements StatementNode { /** 可选的初始化表达式 */ private final Optional initializer; - /** 当前节点所在的行号 **/ - private final int line; - - /** 当前节点所在的列号 **/ - private final int column; - - /** 当前节点所在的文件 **/ - private final String file; + /** 节点上下文信息(包含行号、列号等) */ + private final NodeContext context; /** * 构造一个 {@code DeclarationNode} 实例。 @@ -38,14 +33,13 @@ public class DeclarationNode implements StatementNode { * @param name 变量名称 * @param type 变量类型字符串(如 "int"、"string") * @param initializer 可选初始化表达式,若为 {@code null} 表示未初始化 + * @param context 节点上下文信息(包含行号、列号等) */ - public DeclarationNode(String name, String type, ExpressionNode initializer, int line, int column, String file) { + public DeclarationNode(String name, String type, ExpressionNode initializer, NodeContext context) { this.name = name; this.type = type; this.initializer = Optional.ofNullable(initializer); - this.line = line; - this.column = column; - this.file = file; + this.context = context; } /** @@ -76,27 +70,12 @@ public class DeclarationNode implements StatementNode { } /** - * 获取当前表达式所在的行号。 + * 获取节点上下文信息(包含行号、列号等)。 * - * @return 当前表达式的行号。 + * @return NodeContext 实例 */ - public int line() { - return line; + @Override + public NodeContext context() { + return context; } - - /** - * 获取当前表达式所在的列号。 - * - * @return 当前表达式的列号。 - */ - public int column() { - return column; - } - - /** - * 获取当前表达式所在的文件名。 - * - * @return 当前表达式所在的文件名。 - */ - public String file() { return file; } -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java index 1a2f7a5..9b1d821 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java @@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code ExpressionStatementNode} 表示抽象语法树(AST)中的表达式语句节点。 @@ -11,14 +12,10 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode; *

* * @param expression 表达式主体,通常为函数调用、赋值、方法链式调用等可求值表达式。 - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文信息(包含行号、列号等) */ public record ExpressionStatementNode( ExpressionNode expression, - int line, - int column, - String file + NodeContext context ) implements StatementNode { -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java index 29ab884..d1b29f2 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.Node; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import java.util.List; @@ -17,17 +18,13 @@ import java.util.List; * @param parameters 参数列表,每项为 {@link ParameterNode} 表示一个形参定义 * @param returnType 函数的返回类型(如 "int"、"void" 等) * @param body 函数体语句块,由一组 {@link StatementNode} 构成 - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文信息(包含行号、列号等) */ public record FunctionNode( String name, List parameters, String returnType, List body, - int line, - int column, - String file + NodeContext context ) implements Node { -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java index de0ed17..eb46091 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code IdentifierNode} 表示抽象语法树(AST)中的标识符表达式节点。 @@ -9,16 +10,12 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; * 在语义分析中,通常需要将此类节点绑定到其声明位置或符号表项。 *

* - * @param name 标识符的文本名称(如变量名 "x",函数名 "foo") - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param name 标识符的文本名称(如变量名 "x",函数名 "foo") + * @param context 节点上下文信息(包含行号、列号等) */ public record IdentifierNode( String name, - int line, - int column, - String file + NodeContext context ) implements ExpressionNode { /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java index a26c8e2..ecc0dd1 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java @@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import java.util.List; @@ -16,29 +17,16 @@ import java.util.List; * 若 condition 为假,则执行 else 分支(如果提供)。 *

*

- * 示例语法结构: - *

- *
{@code
- * if (x > 0) {
- *     print("Positive");
- * } else {
- *     print("Negative");
- * }
- * }
* * @param condition 控制分支执行的条件表达式 * @param thenBranch 条件为 true 时执行的语句块 * @param elseBranch 条件为 false 时执行的语句块(可为空) - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文信息(包含行号、列号等) */ public record IfNode( ExpressionNode condition, List thenBranch, List elseBranch, - int line, - int column, - String file + NodeContext context ) implements StatementNode { -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java index c6b65e9..a45c751 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.Node; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code ImportNode} 表示抽象语法树(AST)中的 import 语句节点。 @@ -14,14 +15,10 @@ import org.jcnc.snow.compiler.parser.ast.base.Node; *

* * @param moduleName 被导入的模块名称,通常为点分层次结构(如 "core.utils") - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文信息(包含行号、列号等) */ public record ImportNode( String moduleName, - int line, - int column, - String file + NodeContext context ) implements Node { -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java index a8ddbe1..2ba283e 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import java.util.List; @@ -17,17 +18,13 @@ import java.util.List; * @param condition 每次迭代前评估的条件表达式,控制循环是否继续 * @param update 每轮迭代完成后执行的更新语句 * @param body 循环体语句列表,表示循环主体执行逻辑 - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点的上下文信息(包含行号、列号、文件名等) */ public record LoopNode( StatementNode initializer, ExpressionNode condition, StatementNode update, List body, - int line, - int column, - String file + NodeContext context ) implements StatementNode { -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java index d0ac38e..8ab233b 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code MemberExpressionNode} 表示抽象语法树(AST)中的成员访问表达式节点。 @@ -9,18 +10,14 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; * 成员访问常见于结构体、模块、对象导入等上下文中,是表达式链中常见的构件之一。 *

* - * @param object 左侧对象表达式,表示成员所属的作用域或容器 - * @param member 要访问的成员名称(字段名或方法名) - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param object 左侧对象表达式,表示成员所属的作用域或容器 + * @param member 要访问的成员名称(字段名或方法名) + * @param context 节点上下文信息(包含行号、列号等) */ public record MemberExpressionNode( ExpressionNode object, String member, - int line, - int column, - String file + NodeContext context ) implements ExpressionNode { /** @@ -35,4 +32,4 @@ public record MemberExpressionNode( public String toString() { return object + "." + member; } -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java index 05d47de..84262dd 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.Node; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import java.util.List; import java.util.StringJoiner; @@ -8,22 +9,17 @@ import java.util.StringJoiner; /** * 表示模块定义的 AST 节点。 * 一个模块通常由模块名、导入语句列表和函数定义列表组成。 - * } * * @param name 模块名称。 * @param imports 模块导入列表,每个导入是一个 {@link ImportNode}。 * @param functions 模块中的函数列表,每个函数是一个 {@link FunctionNode}。 - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文信息(包含行号、列号等) */ public record ModuleNode( String name, List imports, List functions, - int line, - int column, - String file + NodeContext context ) implements Node { /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java index 9f253e2..6806112 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code NumberLiteralNode} 表示抽象语法树(AST)中的数字字面量表达式节点。 @@ -11,15 +12,11 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; *

* * @param value 数字字面量的原始字符串表示 - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文信息(包含行号、列号等) */ public record NumberLiteralNode( String value, - int line, - int column, - String file + NodeContext context ) implements ExpressionNode { /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java index 0fbdc18..593d46f 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.Node; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code ParameterNode} 表示抽象语法树(AST)中的函数参数定义节点。 @@ -9,18 +10,14 @@ import org.jcnc.snow.compiler.parser.ast.base.Node; * 用于构成函数签名并参与类型检查与函数调用匹配。 *

* - * @param name 参数名称标识符 - * @param type 参数类型字符串(如 "int"、"string") - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param name 参数名称标识符 + * @param type 参数类型字符串(如 "int"、"string") + * @param context 节点上下文信息(包含行号、列号等) */ public record ParameterNode( String name, String type, - int line, - int column, - String file + NodeContext context ) implements Node { /** @@ -35,4 +32,4 @@ public record ParameterNode( public String toString() { return name + ":" + type; } -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java index 0fc2254..b6d17e1 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java @@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import java.util.Optional; @@ -23,25 +24,18 @@ public class ReturnNode implements StatementNode { /** 可选的返回值表达式 */ private final Optional expression; - /** 当前节点所在的行号 **/ - private final int line; - - /** 当前节点所在的列号 **/ - private final int column; - - /** 当前节点所在的文件 **/ - private final String file; + /** 节点上下文信息(包含行号、列号等) */ + private final NodeContext context; /** * 构造一个 {@code ReturnNode} 实例。 * * @param expression 返回值表达式,如果无返回值则可为 {@code null} + * @param context 节点上下文信息(包含行号、列号等) */ - public ReturnNode(ExpressionNode expression, int line, int column, String file) { + public ReturnNode(ExpressionNode expression, NodeContext context) { this.expression = Optional.ofNullable(expression); - this.line = line; - this.column = column; - this.file = file; + this.context = context; } /** @@ -54,27 +48,12 @@ public class ReturnNode implements StatementNode { } /** - * 获取当前表达式所在的行号。 + * 获取节点上下文信息(包含行号、列号等)。 * - * @return 当前表达式的行号。 + * @return NodeContext 实例 */ - public int line() { - return line; + @Override + public NodeContext context() { + return context; } - - /** - * 获取当前表达式所在的列号。 - * - * @return 当前表达式的列号。 - */ - public int column() { - return column; - } - - /** - * 获取当前表达式所在的文件名。 - * - * @return 当前表达式所在的文件名。 - */ - public String file() { return file; } -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java index daa9f42..dd0e61f 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code StringLiteralNode} 表示抽象语法树(AST)中的字符串字面量表达式节点。 @@ -10,15 +11,11 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; *

* * @param value 字符串常量的内容,原始值中不包含双引号 - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文信息(包含行号、列号等) */ public record StringLiteralNode( String value, - int line, - int column, - String file + NodeContext context ) implements ExpressionNode { /** @@ -33,4 +30,4 @@ public record StringLiteralNode( public String toString() { return "\"" + value + "\""; } -} \ No newline at end of file +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java index 7e38ebc..cc22e6a 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.ast; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; /** * {@code UnaryExpressionNode} —— 前缀一元运算 AST 节点。 @@ -15,16 +16,12 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; * * @param operator 一元运算符(仅 "-" 或 "!") * @param operand 运算对象 / 右操作数 - * @param line 当前节点所在的行号 - * @param column 当前节点所在的列号 - * @param file 当前节点所在的文件 + * @param context 节点上下文信息(包含行号、列号等) */ public record UnaryExpressionNode( String operator, ExpressionNode operand, - int line, - int column, - String file + NodeContext context ) implements ExpressionNode { /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java index 5cba805..8b1e906 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/Node.java @@ -17,23 +17,7 @@ package org.jcnc.snow.compiler.parser.ast.base; */ public interface Node { /** - * 获取当前表达式所在的行号。 - * - * @return 当前表达式的行号。 + * 获取节点的上下文(行/列/文件等信息)。 */ - int line(); - - /** - * 获取当前表达式所在的列号。 - * - * @return 当前表达式的列号。 - */ - int column(); - - /** - * 获取当前表达式所在的文件名。 - * - * @return 当前表达式所在的文件名。 - */ - String file(); + NodeContext context(); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/base/NodeContext.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/NodeContext.java new file mode 100644 index 0000000..e73ce21 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/base/NodeContext.java @@ -0,0 +1,11 @@ +package org.jcnc.snow.compiler.parser.ast.base; + +/** + * NodeContext 记录 AST 节点的位置信息(文件、行、列)。 + */ +public record NodeContext(int line, int column, String file) { + @Override + public String toString() { + return file + ":" + line + ":" + column; + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java index adee8bd..973b81a 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.expression; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.parser.ast.BinaryExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.base.InfixParselet; @@ -46,12 +47,9 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i int prec = precedence.ordinal(); // 右侧表达式根据结合性确定优先级绑定 - ExpressionNode right = new PrattExpressionParser().parseExpression( - ctx, - leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1] - ); + ExpressionNode right = new PrattExpressionParser().parseExpression(ctx, leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1]); - return new BinaryExpressionNode(left, op.getLexeme(), right, line, column, file); + return new BinaryExpressionNode(left, op.getLexeme(), right, new NodeContext(line, column, file)); } /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/BoolLiteralParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/BoolLiteralParselet.java index cfd49db..677896d 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/BoolLiteralParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/BoolLiteralParselet.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.expression; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.parser.ast.BoolLiteralNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet; @@ -28,6 +29,6 @@ public class BoolLiteralParselet implements PrefixParselet { */ @Override public ExpressionNode parse(ParserContext ctx, Token token) { - return new BoolLiteralNode(token.getLexeme(), token.getLine(), token.getCol(), ctx.getSourceName()); + return new BoolLiteralNode(token.getLexeme(), new NodeContext(token.getLine(), token.getCol(), ctx.getSourceName())); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java index 9f5478a..6fd7f4a 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java @@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.parser.expression; import org.jcnc.snow.compiler.parser.ast.CallExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.base.InfixParselet; @@ -45,7 +46,8 @@ public class CallParselet implements InfixParselet { ctx.getTokens().expect(")"); // 消费并验证 ")" // 创建 CallExpressionNode 并传递位置信息 - return new CallExpressionNode(left, args, line, column, file); + return new CallExpressionNode(left, args, new NodeContext(line, column, file)); + } /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java index 7e46337..f0b9a34 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.expression; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.parser.ast.IdentifierNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet; @@ -29,6 +30,6 @@ public class IdentifierParselet implements PrefixParselet { int column = ctx.getTokens().peek(-1).getCol(); String file = ctx.getSourceName(); - return new IdentifierNode(token.getLexeme(), line, column, file); + return new IdentifierNode(token.getLexeme(), new NodeContext(line, column, file)); } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java index ed3cd58..76f1c7f 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.expression; import org.jcnc.snow.compiler.lexer.token.TokenType; import org.jcnc.snow.compiler.parser.ast.MemberExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.context.TokenStream; import org.jcnc.snow.compiler.parser.expression.base.InfixParselet; @@ -34,7 +35,7 @@ public class MemberParselet implements InfixParselet { String file = ctx.getSourceName(); String member = ts.expectType(TokenType.IDENTIFIER).getLexeme(); - return new MemberExpressionNode(left, member, line, column, file); + return new MemberExpressionNode(left, member, new NodeContext(line, column, file)); } /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java index 4b75174..69ac8d7 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.expression; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet; @@ -24,6 +25,6 @@ public class NumberLiteralParselet implements PrefixParselet { */ @Override public ExpressionNode parse(ParserContext ctx, Token token) { - return new NumberLiteralNode(token.getLexeme(), token.getLine(), token.getCol(), ctx.getSourceName()); + return new NumberLiteralNode(token.getLexeme(), new NodeContext(token.getLine(), token.getCol(), ctx.getSourceName())); } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java index b4eb3b3..542a097 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.expression; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.StringLiteralNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet; @@ -27,6 +28,6 @@ public class StringLiteralParselet implements PrefixParselet { public ExpressionNode parse(ParserContext ctx, Token token) { String raw = token.getRaw(); String content = raw.substring(1, raw.length() - 1); - return new StringLiteralNode(content, token.getLine(), token.getCol(), ctx.getSourceName()); + return new StringLiteralNode(content, new NodeContext(token.getLine(), token.getCol(), ctx.getSourceName())); } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java index 5aedf93..113ab94 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.expression; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.parser.ast.UnaryExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet; @@ -55,6 +56,6 @@ public class UnaryOperatorParselet implements PrefixParselet { /* ------------------------------------------------------------ * 2. 封装成 AST 节点并返回。 * ------------------------------------------------------------ */ - return new UnaryExpressionNode(token.getLexeme(), operand, line, column, file); + return new UnaryExpressionNode(token.getLexeme(), operand, new NodeContext(line, column, file)); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java b/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java index 75ffbca..c12edb3 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/function/ASTPrinter.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.function; import org.jcnc.snow.compiler.parser.ast.*; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.Node; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.parser.utils.ASTJsonSerializer; import org.jcnc.snow.compiler.parser.utils.JsonFormatter; @@ -66,8 +67,8 @@ public class ASTPrinter { } } case FunctionNode( - String name, List parameters, String returnType, List body - , int _, int _, String _ + String name, List parameters, String returnType, List body, + NodeContext _ ) -> { System.out.println(pad + "function " + name + "(params=" + parameters + ", return=" + returnType + ")"); @@ -82,11 +83,10 @@ public class ASTPrinter { .orElse(""); System.out.println(pad + "declare " + d.getName() + ":" + d.getType() + init); } - case AssignmentNode(String variable, ExpressionNode value, int _, int _, String _) -> + case AssignmentNode(String variable, ExpressionNode value, NodeContext _) -> System.out.println(pad + variable + " = " + value); case IfNode( - ExpressionNode condition, List thenBranch, List elseBranch, int _, - int _, String _ + ExpressionNode condition, List thenBranch, List elseBranch, NodeContext _ ) -> { System.out.println(pad + "if " + condition); for (StatementNode stmt : thenBranch) { @@ -100,8 +100,8 @@ public class ASTPrinter { } } case LoopNode( - StatementNode initializer, ExpressionNode condition, StatementNode update, List body - , int _, int _, String _ + StatementNode initializer, ExpressionNode condition, StatementNode update, List body, + NodeContext _ ) -> { System.out.println(pad + "loop {"); print(initializer, indent + 1); @@ -116,7 +116,7 @@ public class ASTPrinter { } case ReturnNode r -> System.out.println(pad + "return" + r.getExpression().map(e -> " " + e).orElse("")); - case ExpressionStatementNode(ExpressionNode expression, int _, int _, String _) -> + case ExpressionStatementNode(ExpressionNode expression, NodeContext _) -> System.out.println(pad + expression); case null, default -> System.out.println(pad + n); // 回退处理 } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java index a7a3449..3927767 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java @@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.parser.function; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.lexer.token.TokenType; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.base.TopLevelParser; import org.jcnc.snow.compiler.parser.ast.FunctionNode; import org.jcnc.snow.compiler.parser.ast.ParameterNode; @@ -74,7 +75,7 @@ public class FunctionParser implements TopLevelParser { parseFunctionFooter(ts); - return new FunctionNode(functionName, parameters, returnType[0], body, line, column, file); + return new FunctionNode(functionName, parameters, returnType[0], body, new NodeContext(line, column, file)); } /** @@ -194,7 +195,7 @@ public class FunctionParser implements TopLevelParser { String ptype = ts.expectType(TokenType.TYPE).getLexeme(); skipComments(ts); ts.expectType(TokenType.NEWLINE); - list.add(new ParameterNode(pname, ptype, line, column, file)); + list.add(new ParameterNode(pname, ptype, new NodeContext(line, column, file))); } return list; } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java index d5443ac..10ca4d5 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java @@ -1,6 +1,7 @@ package org.jcnc.snow.compiler.parser.module; import org.jcnc.snow.compiler.lexer.token.TokenType; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.ast.ImportNode; @@ -57,7 +58,7 @@ public class ImportParser { .getLexeme(); // 创建 ImportNode 节点并加入列表 - imports.add(new ImportNode(mod, line, column, file)); + imports.add(new ImportNode(mod, new NodeContext(line, column, file))); } while (ctx.getTokens().match(",")); // 如果匹配到逗号,继续解析下一个模块名 // 最后必须匹配换行符,标志 import 语句的结束 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java index 8a21e70..fc8ff02 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java @@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType; import org.jcnc.snow.compiler.parser.ast.FunctionNode; import org.jcnc.snow.compiler.parser.ast.ImportNode; import org.jcnc.snow.compiler.parser.ast.ModuleNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.base.TopLevelParser; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.context.TokenStream; @@ -93,6 +94,6 @@ public class ModuleParser implements TopLevelParser { ts.expect("end"); ts.expect("module"); - return new ModuleNode(name, imports, functions, line, column, file); + return new ModuleNode(name, imports, functions, new NodeContext(line, column, file)); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java index 2323ada..a7e6fa3 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.statement; import org.jcnc.snow.compiler.lexer.token.TokenType; import org.jcnc.snow.compiler.parser.ast.DeclarationNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser; @@ -74,6 +75,6 @@ public class DeclarationStatementParser implements StatementParser { ctx.getTokens().expectType(TokenType.NEWLINE); // 返回构建好的声明语法树节点 - return new DeclarationNode(name, type, init, line, column, file); + return new DeclarationNode(name, type, init, new NodeContext(line, column, file)); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java index f824b6b..36af619 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java @@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType; import org.jcnc.snow.compiler.parser.ast.AssignmentNode; import org.jcnc.snow.compiler.parser.ast.ExpressionStatementNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.context.TokenStream; @@ -56,12 +57,12 @@ public class ExpressionStatementParser implements StatementParser { ts.expect("="); ExpressionNode value = new PrattExpressionParser().parse(ctx); ts.expectType(TokenType.NEWLINE); - return new AssignmentNode(varName, value, line, column, file); + return new AssignmentNode(varName, value, new NodeContext(line, column, file)); } // 普通表达式语句 ExpressionNode expr = new PrattExpressionParser().parse(ctx); ts.expectType(TokenType.NEWLINE); - return new ExpressionStatementNode(expr, line, column, file); + return new ExpressionStatementNode(expr, new NodeContext(line, column, file)); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java index eda8bb1..24d6556 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.statement; import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.lexer.token.TokenType; import org.jcnc.snow.compiler.parser.ast.IfNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser; @@ -125,6 +126,6 @@ public class IfStatementParser implements StatementParser { ts.expectType(TokenType.NEWLINE); // 构建并返回 IfNode,包含条件、then 分支和 else 分支 - return new IfNode(condition, thenBranch, elseBranch, line, column, file); + return new IfNode(condition, thenBranch, elseBranch, new NodeContext(line, column, file)); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java index 4422636..c1a9c66 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java @@ -4,6 +4,7 @@ import org.jcnc.snow.compiler.lexer.token.TokenType; import org.jcnc.snow.compiler.parser.ast.AssignmentNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.LoopNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.ast.base.StatementNode; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.context.TokenStream; @@ -116,7 +117,7 @@ public class LoopStatementParser implements StatementParser { ts1.expect("="); ExpressionNode expr = new PrattExpressionParser().parse(ctx1); ts1.expectType(TokenType.NEWLINE); - update[0] = new AssignmentNode(varName, expr, line, column, file); + update[0] = new AssignmentNode(varName, expr, new NodeContext(line, column, file)); ParserUtils.skipNewlines(ts1); } )); @@ -150,6 +151,6 @@ public class LoopStatementParser implements StatementParser { ParserUtils.matchFooter(ts, "loop"); // 返回构造完成的 LoopNode - return new LoopNode(initializer[0], condition[0], update[0], body, loop_line, loop_column, file); + return new LoopNode(initializer[0], condition[0], update[0], body, new NodeContext(loop_line, loop_column, file)); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java index 080f1e6..3b4c6c1 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.statement; import org.jcnc.snow.compiler.lexer.token.TokenType; import org.jcnc.snow.compiler.parser.ast.ReturnNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser; @@ -54,6 +55,6 @@ public class ReturnStatementParser implements StatementParser { ctx.getTokens().expectType(TokenType.NEWLINE); // 构建并返回 ReturnNode(可能为空表达式) - return new ReturnNode(expr, line, column, file); + return new ReturnNode(expr, new NodeContext(line, column, file)); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java b/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java index 231d9af..278a42c 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/utils/ASTJsonSerializer.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.parser.utils; import org.jcnc.snow.compiler.parser.ast.*; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import org.jcnc.snow.compiler.parser.ast.base.Node; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; import java.util.*; @@ -82,8 +83,7 @@ public class ASTJsonSerializer { return switch (n) { // 模块节点 case ModuleNode( - String name, List imports, List functions, _, int _, - String _ + String name, List imports, List functions, NodeContext _ ) -> { Map map = newNodeMap("Module"); map.put("name", name); @@ -181,34 +181,34 @@ public class ASTJsonSerializer { return switch (expr) { // 二元表达式 case BinaryExpressionNode( - ExpressionNode left, String operator, ExpressionNode right, int _, int _, String _ + ExpressionNode left, String operator, ExpressionNode right, NodeContext _ ) -> exprMap("BinaryExpression", "left", exprToMap(left), "operator", operator, "right", exprToMap(right) ); // 一元表达式 - case UnaryExpressionNode(String operator, ExpressionNode operand, int _, int _, String _) -> + case UnaryExpressionNode(String operator, ExpressionNode operand, NodeContext _) -> exprMap("UnaryExpression", "operator", operator, "operand", exprToMap(operand) ); // 布尔字面量 - case BoolLiteralNode(boolean value, int _, int _, String _) -> exprMap("BoolLiteral", "value", value); + case BoolLiteralNode(boolean value, NodeContext _) -> exprMap("BoolLiteral", "value", value); // 标识符 - case IdentifierNode(String name, int _, int _, String _) -> exprMap("Identifier", "name", name); + case IdentifierNode(String name, NodeContext _) -> exprMap("Identifier", "name", name); // 数字字面量 - case NumberLiteralNode(String value, int _, int _, String _) -> exprMap("NumberLiteral", "value", value); + case NumberLiteralNode(String value, NodeContext _) -> exprMap("NumberLiteral", "value", value); // 字符串字面量 - case StringLiteralNode(String value, int _, int _, String _) -> exprMap("StringLiteral", "value", value); + case StringLiteralNode(String value, NodeContext _) -> exprMap("StringLiteral", "value", value); // 调用表达式 - case CallExpressionNode(ExpressionNode callee, List arguments, int _, int _, String _) -> { + case CallExpressionNode(ExpressionNode callee, List arguments, NodeContext _) -> { List args = new ArrayList<>(arguments.size()); for (ExpressionNode arg : arguments) args.add(exprToMap(arg)); yield exprMap("CallExpression", "callee", exprToMap(callee), "arguments", args); } // 成员访问表达式 - case MemberExpressionNode(ExpressionNode object, String member, int _, int _, String _) -> + case MemberExpressionNode(ExpressionNode object, String member, NodeContext _) -> exprMap("MemberExpression", "object", exprToMap(object), "member", member diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java index 83c331c..360ec99 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/CallExpressionAnalyzer.java @@ -2,6 +2,7 @@ package org.jcnc.snow.compiler.semantic.analyzers.expression; import org.jcnc.snow.compiler.parser.ast.*; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; 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; @@ -51,8 +52,8 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer= 0 && col >= 0) ? "行 " + line + ", 列 " + col : "未知位置"); From 2a25abcf035b5349a247b39dd787426c12c9733e Mon Sep 17 00:00:00 2001 From: zhangxun <1958638841@qq.com> Date: Sat, 28 Jun 2025 20:23:54 +0800 Subject: [PATCH 4/5] refactor: OpHelper.java --- .../java/org/jcnc/snow/compiler/backend/utils/OpHelper.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java b/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java index de873b8..8dc5529 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/utils/OpHelper.java @@ -135,7 +135,6 @@ public final class OpHelper { Map revmap = new HashMap<>(); // reverse map OPCODE_MAP.forEach((key, value) -> revmap.put(Integer.parseInt(value), key)); - OPCODE_NAME_MAP = Collections.unmodifiableMap(revmap); } @@ -197,7 +196,7 @@ public final class OpHelper { public static String opcodeName(int code) { String name = OPCODE_NAME_MAP.get(code); if (name == null) { - throw new IllegalStateException("Unknown opcode: " + name); + throw new IllegalStateException("Unknown opcode: " + code); } return name; } From c83a584795b9b81da7add2ce54532e61fbb1baa0 Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 9 Jul 2025 23:58:46 +0800 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=E5=9C=A8=E9=9D=9E=20void=20?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E4=B8=AD=E5=BC=BA=E5=88=B6=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=20return=20=E8=AF=AD=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 FunctionChecker 中添加一个检查,以确保具有非 void 返回类型的功能 类型必须至少包含一个返回节点。否则将引发语义错误。 --- .../compiler/semantic/core/FunctionChecker.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 e6d69c3..66385b6 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 @@ -2,11 +2,13 @@ package org.jcnc.snow.compiler.semantic.core; 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.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; /** * {@code FunctionChecker} 是语义分析阶段中用于检查函数体语句合法性的调度器。 @@ -79,6 +81,19 @@ public record FunctionChecker(Context ctx) { )); } } + + // 检查非 void 函数是否至少包含一条 return 语句 + var returnType = ctx.parseType(fn.returnType()); + if (returnType != BuiltinType.VOID) { + boolean hasReturn = fn.body().stream() + .anyMatch(stmtNode -> stmtNode instanceof ReturnNode); + if (!hasReturn) { + ctx.errors().add(new SemanticError( + fn, + "非 void 函数必须包含至少一条 return 语句" + )); + } + } } } }