refactor: 重构 AST节点中的位置信息表示方式

- 引入 NodeContext 类统一表示节点的上下文信息(行号、列号、文件名)
- 修改相关 AST 节点的构造函数,使用 NodeContext 替代单独的行号、列号和文件名参数
- 更新解析器代码,创建 NodeContext 实例以传递给 AST节点
- 此重构简化了 AST 节点的参数列表,提高了代码的可维护性和可读性
This commit is contained in:
Luke 2025-07-08 12:39:15 +08:00
parent ae0baf3e50
commit aefa9e2dff
44 changed files with 177 additions and 292 deletions

View File

@ -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, "")
);
}
}

View File

@ -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)) {

View File

@ -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; // 变量暂不处理后续可扩展符号表查询

View File

@ -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;

View File

@ -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 {
/**

View File

@ -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 {
/**

View File

@ -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"
* </p>
*
* @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}
* </p>
*
* @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);
}
/**

View File

@ -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<ExpressionNode> 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;
}
}

View File

@ -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<ExpressionNode> 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; }
}

View File

@ -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;
* </p>
*
* @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 {
}

View File

@ -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<ParameterNode> parameters,
String returnType,
List<StatementNode> body,
int line,
int column,
String file
NodeContext context
) implements Node {
}

View File

@ -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;
* 在语义分析中通常需要将此类节点绑定到其声明位置或符号表项
* </p>
*
* @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 {
/**

View File

@ -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 分支如果提供
* </p>
* <p>
* 示例语法结构
* </p>
* <pre>{@code
* if (x > 0) {
* print("Positive");
* } else {
* print("Negative");
* }
* }</pre>
*
* @param condition 控制分支执行的条件表达式
* @param thenBranch 条件为 true 时执行的语句块
* @param elseBranch 条件为 false 时执行的语句块可为空
* @param line 当前节点所在的行号
* @param column 当前节点所在的列号
* @param file 当前节点所在的文件
* @param context 节点上下文信息包含行号列号等
*/
public record IfNode(
ExpressionNode condition,
List<StatementNode> thenBranch,
List<StatementNode> elseBranch,
int line,
int column,
String file
NodeContext context
) implements StatementNode {
}

View File

@ -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;
* </p>
*
* @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 {
}

View File

@ -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<StatementNode> body,
int line,
int column,
String file
NodeContext context
) implements StatementNode {
}

View File

@ -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;
* 成员访问常见于结构体模块对象导入等上下文中是表达式链中常见的构件之一
* </p>
*
* @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 {
/**

View File

@ -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<ImportNode> imports,
List<FunctionNode> functions,
int line,
int column,
String file
NodeContext context
) implements Node {
/**

View File

@ -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;
* </p>
*
* @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 {
/**

View File

@ -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;
* 用于构成函数签名并参与类型检查与函数调用匹配
* </p>
*
* @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 {
/**

View File

@ -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<ExpressionNode> 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; }
}

View File

@ -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;
* </p>
*
* @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 {
/**

View File

@ -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 {
/**

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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));
}
/**

View File

@ -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()));
}
}

View File

@ -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));
}
/**

View File

@ -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));
}
}

View File

@ -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));
}
/**

View File

@ -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()));
}
}

View File

@ -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()));
}
}

View File

@ -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));
}
}

View File

@ -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<ParameterNode> parameters, String returnType, List<StatementNode> body
, int _, int _, String _
String name, List<ParameterNode> parameters, String returnType, List<StatementNode> 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<StatementNode> thenBranch, List<StatementNode> elseBranch, int _,
int _, String _
ExpressionNode condition, List<StatementNode> thenBranch, List<StatementNode> 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<StatementNode> body
, int _, int _, String _
StatementNode initializer, ExpressionNode condition, StatementNode update, List<StatementNode> 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); // 回退处理
}

View File

@ -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;
}

View File

@ -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 语句的结束

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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<ImportNode> imports, List<FunctionNode> functions, _, int _,
String _
String name, List<ImportNode> imports, List<FunctionNode> functions, NodeContext _
) -> {
Map<String, Object> 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<ExpressionNode> arguments, int _, int _, String _) -> {
case CallExpressionNode(ExpressionNode callee, List<ExpressionNode> arguments, NodeContext _) -> {
List<Object> 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

View File

@ -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<CallExpression
ExpressionNode callee = call.callee();
// 支持模块调用形式ModuleName.FunctionName(...)
if (callee instanceof MemberExpressionNode(var obj, String member, int _, int _, String _)
&& obj instanceof IdentifierNode(String mod, int _, int _, String _)) {
if (callee instanceof MemberExpressionNode(var obj, String member, NodeContext _)
&& obj instanceof IdentifierNode(String mod, NodeContext _)) {
// 验证模块是否存在并已导入
if (!ctx.getModules().containsKey(mod)
|| (!mi.getImports().contains(mod) && !mi.getName().equals(mod))) {
@ -65,7 +66,7 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer<CallExpression
functionName = member;
// 简单函数名形式func(...)
} else if (callee instanceof IdentifierNode(String name, int _, int _, String _)) {
} else if (callee instanceof IdentifierNode(String name, NodeContext _)) {
functionName = name;
// 不支持的 callee 形式

View File

@ -42,11 +42,12 @@ public record SemanticError(Node node, String message) {
String file = null;
if (node != null) {
line = node.line();
col = node.column();
file = node.file();
line = node.context().line();
col = node.context().column();
file = node.context().file();
}
StringBuilder sb = new StringBuilder();
if (file != null && !file.isBlank()) sb.append(file).append(": ");
sb.append((line >= 0 && col >= 0) ? "" + line + ", 列 " + col : "未知位置");