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 a1168ec..5513fdc 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
@@ -76,6 +76,14 @@ public final class IRProgramBuilder {
* @return 生成的 FunctionNode,用于后续 IRFunction 构建
*/
private FunctionNode wrapTopLevel(StatementNode stmt) {
- return new FunctionNode("_start", null, String.valueOf(List.of()), List.of(stmt));
+ return new FunctionNode(
+ "_start",
+ null,
+ String.valueOf(List.of()),
+ List.of(stmt),
+ -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 2290278..f731c57 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
@@ -66,12 +66,12 @@ public class StatementBuilder {
buildIf(ifNode);
return;
}
- if (stmt instanceof ExpressionStatementNode(ExpressionNode exp)) {
+ if (stmt instanceof ExpressionStatementNode(ExpressionNode exp, _, _, _)) {
// 纯表达式语句,如 foo();
expr.build(exp);
return;
}
- if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs)) {
+ if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs, _, _, _)) {
// 赋值语句,如 a = b + 1;
final String type = ctx.getScope().lookupType(var);
@@ -208,7 +208,10 @@ public class StatementBuilder {
if (cond instanceof BinaryExpressionNode(
ExpressionNode left,
String operator,
- ExpressionNode right
+ ExpressionNode right,
+ _,
+ _,
+ _
)
&& ComparisonUtils.isComparisonOperator(operator)) {
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 69781b9..eace610 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
@@ -16,8 +16,17 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
*
* @param variable 左值变量名(即赋值目标)
* @param value 表达式右值(即赋值来源)
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record AssignmentNode(String variable, ExpressionNode value) implements StatementNode {
+public record AssignmentNode(
+ String variable,
+ ExpressionNode value,
+ int line,
+ int column,
+ String file
+) implements StatementNode {
/**
* 返回赋值语句的字符串形式,便于调试与日志输出。
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 6e49e63..40412de 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
@@ -12,9 +12,18 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
* @param left 左操作数(子表达式)
* @param operator 运算符字符串(如 "+", "-", "*", "/" 等)
* @param right 右操作数(子表达式)
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record BinaryExpressionNode(ExpressionNode left, String operator,
- ExpressionNode right) implements ExpressionNode {
+public record BinaryExpressionNode(
+ ExpressionNode left,
+ String operator,
+ ExpressionNode right,
+ int line,
+ int column,
+ String file
+) implements ExpressionNode {
/**
* 返回该二元运算表达式的字符串表示形式。
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 ac36871..22f47bc 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
@@ -14,6 +14,7 @@ import java.util.List;
* @param arguments 参数表达式列表,表示函数调用中传递给函数的实际参数。参数的顺序与调用顺序一致。
* @param line 当前表达式所在的行号,方便调试和错误定位。
* @param column 当前表达式所在的列号,用于精确定位错误位置。
+ * @param file 当前表达式所在的文件,用于错误定位。
*/
public record CallExpressionNode(
ExpressionNode callee, // 被调用的表达式节点,表示函数或方法名
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 1819d1f..9e1edf5 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
@@ -23,6 +23,15 @@ public class DeclarationNode implements StatementNode {
/** 可选的初始化表达式 */
private final Optional initializer;
+ /** 当前节点所在的行号 **/
+ private final int line;
+
+ /** 当前节点所在的列号 **/
+ private final int column;
+
+ /** 当前节点所在的文件 **/
+ private final String file;
+
/**
* 构造一个 {@code DeclarationNode} 实例。
*
@@ -30,10 +39,13 @@ public class DeclarationNode implements StatementNode {
* @param type 变量类型字符串(如 "int"、"string")
* @param initializer 可选初始化表达式,若为 {@code null} 表示未初始化
*/
- public DeclarationNode(String name, String type, ExpressionNode initializer) {
+ public DeclarationNode(String name, String type, ExpressionNode initializer, int line, int column, String file) {
this.name = name;
this.type = type;
this.initializer = Optional.ofNullable(initializer);
+ this.line = line;
+ this.column = column;
+ this.file = file;
}
/**
@@ -62,4 +74,29 @@ public class DeclarationNode implements StatementNode {
public Optional getInitializer() {
return initializer;
}
+
+ /**
+ * 获取当前表达式所在的行号。
+ *
+ * @return 当前表达式的行号。
+ */
+ public int line() {
+ return line;
+ }
+
+ /**
+ * 获取当前表达式所在的列号。
+ *
+ * @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 cf62fb1..1a2f7a5 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
@@ -11,6 +11,14 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
*
*
* @param expression 表达式主体,通常为函数调用、赋值、方法链式调用等可求值表达式。
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record ExpressionStatementNode(ExpressionNode expression) implements StatementNode {
+public record ExpressionStatementNode(
+ ExpressionNode expression,
+ int line,
+ int column,
+ String file
+) 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 7ab55dd..29ab884 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
@@ -17,7 +17,17 @@ import java.util.List;
* @param parameters 参数列表,每项为 {@link ParameterNode} 表示一个形参定义
* @param returnType 函数的返回类型(如 "int"、"void" 等)
* @param body 函数体语句块,由一组 {@link StatementNode} 构成
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record FunctionNode(String name, List parameters, String returnType,
- List body) implements Node {
+public record FunctionNode(
+ String name,
+ List parameters,
+ String returnType,
+ List body,
+ int line,
+ int column,
+ String file
+) 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 cfce3d4..de0ed17 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
@@ -10,8 +10,16 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
*
*
* @param name 标识符的文本名称(如变量名 "x",函数名 "foo")
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record IdentifierNode(String name) implements ExpressionNode {
+public record IdentifierNode(
+ String name,
+ int line,
+ int column,
+ String file
+) 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 9ac9371..a26c8e2 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
@@ -29,10 +29,16 @@ import java.util.List;
* @param condition 控制分支执行的条件表达式
* @param thenBranch 条件为 true 时执行的语句块
* @param elseBranch 条件为 false 时执行的语句块(可为空)
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
public record IfNode(
ExpressionNode condition,
List thenBranch,
- List elseBranch
+ List elseBranch,
+ int line,
+ int column,
+ String file
) 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 f551fd9..c6b65e9 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
@@ -14,6 +14,14 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
*
*
* @param moduleName 被导入的模块名称,通常为点分层次结构(如 "core.utils")
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record ImportNode(String moduleName) implements Node {
+public record ImportNode(
+ String moduleName,
+ int line,
+ int column,
+ String file
+) 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 7821ae4..a8ddbe1 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
@@ -17,7 +17,17 @@ import java.util.List;
* @param condition 每次迭代前评估的条件表达式,控制循环是否继续
* @param update 每轮迭代完成后执行的更新语句
* @param body 循环体语句列表,表示循环主体执行逻辑
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record LoopNode(StatementNode initializer, ExpressionNode condition, StatementNode update,
- List body) implements StatementNode {
+public record LoopNode(
+ StatementNode initializer,
+ ExpressionNode condition,
+ StatementNode update,
+ List body,
+ int line,
+ int column,
+ String file
+) 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 7b49db3..d0ac38e 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
@@ -11,8 +11,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
*
* @param object 左侧对象表达式,表示成员所属的作用域或容器
* @param member 要访问的成员名称(字段名或方法名)
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record MemberExpressionNode(ExpressionNode object, String member) implements ExpressionNode {
+public record MemberExpressionNode(
+ ExpressionNode object,
+ String member,
+ int line,
+ int column,
+ String file
+) implements ExpressionNode {
/**
* 返回成员访问表达式的字符串形式。
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 564402a..05d47de 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
@@ -13,8 +13,18 @@ import java.util.StringJoiner;
* @param name 模块名称。
* @param imports 模块导入列表,每个导入是一个 {@link ImportNode}。
* @param functions 模块中的函数列表,每个函数是一个 {@link FunctionNode}。
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record ModuleNode(String name, List imports, List functions) implements Node {
+public record ModuleNode(
+ String name,
+ List imports,
+ List functions,
+ int line,
+ int column,
+ String file
+) implements Node {
/**
* 返回模块节点的字符串表示形式,包含模块名、导入模块列表和函数列表。
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 91e93aa..0fbdc18 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
@@ -11,8 +11,17 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
*
* @param name 参数名称标识符
* @param type 参数类型字符串(如 "int"、"string")
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record ParameterNode(String name, String type) implements Node {
+public record ParameterNode(
+ String name,
+ String type,
+ int line,
+ int column,
+ String file
+) implements Node {
/**
* 返回参数的字符串形式,格式为 {@code name:type}。
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 28143dd..0fc2254 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
@@ -23,13 +23,25 @@ public class ReturnNode implements StatementNode {
/** 可选的返回值表达式 */
private final Optional expression;
+ /** 当前节点所在的行号 **/
+ private final int line;
+
+ /** 当前节点所在的列号 **/
+ private final int column;
+
+ /** 当前节点所在的文件 **/
+ private final String file;
+
/**
* 构造一个 {@code ReturnNode} 实例。
*
* @param expression 返回值表达式,如果无返回值则可为 {@code null}
*/
- public ReturnNode(ExpressionNode expression) {
+ public ReturnNode(ExpressionNode expression, int line, int column, String file) {
this.expression = Optional.ofNullable(expression);
+ this.line = line;
+ this.column = column;
+ this.file = file;
}
/**
@@ -40,4 +52,29 @@ public class ReturnNode implements StatementNode {
public Optional getExpression() {
return expression;
}
+
+ /**
+ * 获取当前表达式所在的行号。
+ *
+ * @return 当前表达式的行号。
+ */
+ public int line() {
+ return line;
+ }
+
+ /**
+ * 获取当前表达式所在的列号。
+ *
+ * @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/UnaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java
index d956fc8..7e38ebc 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
@@ -15,9 +15,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
*
* @param operator 一元运算符(仅 "-" 或 "!")
* @param operand 运算对象 / 右操作数
+ * @param line 当前节点所在的行号
+ * @param column 当前节点所在的列号
+ * @param file 当前节点所在的文件
*/
-public record UnaryExpressionNode(String operator,
- ExpressionNode operand) implements ExpressionNode {
+public record UnaryExpressionNode(
+ String operator,
+ ExpressionNode operand,
+ int line,
+ int column,
+ String file
+) implements ExpressionNode {
/**
* 生成调试友好的字符串表示,例如 {@code "-x"} 或 {@code "!flag"}。
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 da86f01..adee8bd 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
@@ -37,6 +37,11 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i
*/
@Override
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
Token op = ctx.getTokens().next();
int prec = precedence.ordinal();
@@ -46,7 +51,7 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i
leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1]
);
- return new BinaryExpressionNode(left, op.getLexeme(), right);
+ return new BinaryExpressionNode(left, op.getLexeme(), right, line, column, file);
}
/**
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 9499f6d..9f5478a 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
@@ -26,14 +26,15 @@ public class CallParselet implements InfixParselet {
*/
@Override
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
+ // 获取函数名 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek(-1).getLine();
+ int column = ctx.getTokens().peek(-1).getCol();
+ String file = ctx.getSourceName();
+
ctx.getTokens().next(); // 消费 "("
List args = new ArrayList<>();
- // 获取当前 token 的行号和列号
- int line = ctx.getTokens().peek().getLine();
- int column = ctx.getTokens().peek().getCol();
-
// 解析函数调用参数
if (!ctx.getTokens().peek().getLexeme().equals(")")) {
do {
@@ -43,8 +44,7 @@ public class CallParselet implements InfixParselet {
ctx.getTokens().expect(")"); // 消费并验证 ")"
- // 创建 CallExpressionNode 并传递位置信息,文件名称
- String file = ctx.getSourceName();
+ // 创建 CallExpressionNode 并传递位置信息
return new CallExpressionNode(left, args, 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 057c425..7e46337 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
@@ -24,6 +24,11 @@ public class IdentifierParselet implements PrefixParselet {
*/
@Override
public ExpressionNode parse(ParserContext ctx, Token token) {
- return new IdentifierNode(token.getLexeme());
+ // 获取标识符 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek(-1).getLine();
+ int column = ctx.getTokens().peek(-1).getCol();
+ String file = ctx.getSourceName();
+
+ return new IdentifierNode(token.getLexeme(), 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 b0f1e5f..ed3cd58 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
@@ -28,8 +28,13 @@ public class MemberParselet implements InfixParselet {
TokenStream ts = ctx.getTokens();
ts.expect("."); // 消费点号
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
String member = ts.expectType(TokenType.IDENTIFIER).getLexeme();
- return new MemberExpressionNode(left, member);
+ return new MemberExpressionNode(left, member, line, column, 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 abfa97a..5aedf93 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
@@ -41,6 +41,11 @@ public class UnaryOperatorParselet implements PrefixParselet {
*/
@Override
public ExpressionNode parse(ParserContext ctx, Token token) {
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
/* ------------------------------------------------------------
* 1. 以 UNARY 优先级递归解析操作数,避免错误结合顺序。
* ------------------------------------------------------------ */
@@ -50,6 +55,6 @@ public class UnaryOperatorParselet implements PrefixParselet {
/* ------------------------------------------------------------
* 2. 封装成 AST 节点并返回。
* ------------------------------------------------------------ */
- return new UnaryExpressionNode(token.getLexeme(), operand);
+ return new UnaryExpressionNode(token.getLexeme(), operand, line, column, file);
}
}
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 af2251e..a7a3449 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
@@ -57,6 +57,11 @@ public class FunctionParser implements TopLevelParser {
public FunctionNode parse(ParserContext ctx) {
TokenStream ts = ctx.getTokens();
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
parseFunctionHeader(ts);
String functionName = parseFunctionName(ts);
@@ -69,7 +74,7 @@ public class FunctionParser implements TopLevelParser {
parseFunctionFooter(ts);
- return new FunctionNode(functionName, parameters, returnType[0], body);
+ return new FunctionNode(functionName, parameters, returnType[0], body, line, column, file);
}
/**
@@ -92,7 +97,7 @@ public class FunctionParser implements TopLevelParser {
map.put("parameter", new SectionDefinition(
(TokenStream stream) -> stream.peek().getLexeme().equals("parameter"),
- (ParserContext context, TokenStream stream) -> params.addAll(parseParameters(stream))
+ (ParserContext context, TokenStream stream) -> params.addAll(parseParameters(context))
));
map.put("return_type", new SectionDefinition(
@@ -154,10 +159,12 @@ public class FunctionParser implements TopLevelParser {
*
*
*
- * @param ts 当前使用的 {@link TokenStream}。
+ * @param ctx 当前解析上下文,包含 {@link TokenStream} 和符号表等作用域信息。
* @return 所有参数节点的列表。
*/
- private List parseParameters(TokenStream ts) {
+ private List parseParameters(ParserContext ctx) {
+ TokenStream ts = ctx.getTokens();
+
ts.expect("parameter");
ts.expect(":");
skipComments(ts);
@@ -175,13 +182,19 @@ public class FunctionParser implements TopLevelParser {
if (lex.equals("return_type") || lex.equals("body") || lex.equals("end")) {
break;
}
+
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
ts.expect("declare");
String pname = ts.expectType(TokenType.IDENTIFIER).getLexeme();
ts.expect(":");
String ptype = ts.expectType(TokenType.TYPE).getLexeme();
skipComments(ts);
ts.expectType(TokenType.NEWLINE);
- list.add(new ParameterNode(pname, ptype));
+ list.add(new ParameterNode(pname, ptype, 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 38dd788..d5443ac 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
@@ -46,13 +46,18 @@ public class ImportParser {
// 解析一个或多个模块名(标识符),允许使用逗号分隔多个模块
do {
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
// 获取当前标识符类型的词法单元,并提取其原始词素
String mod = ctx.getTokens()
.expectType(TokenType.IDENTIFIER)
.getLexeme();
// 创建 ImportNode 节点并加入列表
- imports.add(new ImportNode(mod));
+ imports.add(new ImportNode(mod, 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 b696410..ac9e05d 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
@@ -40,6 +40,11 @@ public class ModuleParser implements TopLevelParser {
// 获取当前上下文中提供的词法流
TokenStream ts = ctx.getTokens();
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
// 期望模块声明以关键字 "module:" 开始
ts.expect("module");
ts.expect(":");
@@ -90,6 +95,6 @@ public class ModuleParser implements TopLevelParser {
ts.expect("module");
// 构建并返回完整的模块语法树节点
- return new ModuleNode(name, imports, functions);
+ return new ModuleNode(name, imports, functions, line, column, file);
}
}
\ No newline at end of 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 b99d09c..2323ada 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
@@ -43,6 +43,11 @@ public class DeclarationStatementParser implements StatementParser {
*/
@Override
public DeclarationNode parse(ParserContext ctx) {
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
// 声明语句必须以 "declare" 开头
ctx.getTokens().expect("declare");
@@ -69,6 +74,6 @@ public class DeclarationStatementParser implements StatementParser {
ctx.getTokens().expectType(TokenType.NEWLINE);
// 返回构建好的声明语法树节点
- return new DeclarationNode(name, type, init);
+ return new DeclarationNode(name, type, init, 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 dd9df94..526dbf0 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
@@ -50,6 +50,11 @@ public class ExpressionStatementParser implements StatementParser {
throw new IllegalStateException("Cannot parse expression starting with keyword: " + ts.peek().getLexeme());
}
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
// 处理赋值语句:格式为 identifier = expression
if (ts.peek().getType() == TokenType.IDENTIFIER
&& ts.peek(1).getLexeme().equals("=")) {
@@ -58,13 +63,13 @@ public class ExpressionStatementParser implements StatementParser {
ts.expect("="); // 消耗等号
ExpressionNode value = new PrattExpressionParser().parse(ctx); // 解析表达式
ts.expectType(TokenType.NEWLINE); // 语句必须以换行符结束
- return new AssignmentNode(varName, value); // 返回赋值节点
+ return new AssignmentNode(varName, value, line, column, file); // 返回赋值节点
}
// 处理普通表达式语句,如函数调用、字面量、运算表达式等
ExpressionNode expr = new PrattExpressionParser().parse(ctx);
ts.expectType(TokenType.NEWLINE); // 语句必须以换行符结束
- return new ExpressionStatementNode(expr); // 返回表达式语句节点
+ return new ExpressionStatementNode(expr, 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 f0e2498..eda8bb1 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
@@ -47,6 +47,11 @@ public class IfStatementParser implements StatementParser {
public IfNode parse(ParserContext ctx) {
var ts = ctx.getTokens(); // 获取 token 流引用
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
// 消耗起始关键字 "if"
ts.expect("if");
@@ -120,6 +125,6 @@ public class IfStatementParser implements StatementParser {
ts.expectType(TokenType.NEWLINE);
// 构建并返回 IfNode,包含条件、then 分支和 else 分支
- return new IfNode(condition, thenBranch, elseBranch);
+ return new IfNode(condition, thenBranch, elseBranch, 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 583b5c9..4422636 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
@@ -64,6 +64,12 @@ public class LoopStatementParser implements StatementParser {
public LoopNode parse(ParserContext ctx) {
TokenStream ts = ctx.getTokens();
+ // 获取当前 token 的行号、列号
+ int loop_line = ctx.getTokens().peek().getLine();
+ int loop_column = ctx.getTokens().peek().getCol();
+
+ String file = ctx.getSourceName();
+
// 匹配 loop: 起始语法
ParserUtils.matchHeader(ts, "loop");
@@ -101,12 +107,16 @@ public class LoopStatementParser implements StatementParser {
sections.put("update", new FlexibleSectionParser.SectionDefinition(
ts1 -> ts1.peek().getLexeme().equals("update"),
(ctx1, ts1) -> {
+ // 获取当前 token 的行号、列号
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+
ParserUtils.matchHeader(ts1, "update");
String varName = ts1.expectType(TokenType.IDENTIFIER).getLexeme();
ts1.expect("=");
ExpressionNode expr = new PrattExpressionParser().parse(ctx1);
ts1.expectType(TokenType.NEWLINE);
- update[0] = new AssignmentNode(varName, expr);
+ update[0] = new AssignmentNode(varName, expr, line, column, file);
ParserUtils.skipNewlines(ts1);
}
));
@@ -140,6 +150,6 @@ public class LoopStatementParser implements StatementParser {
ParserUtils.matchFooter(ts, "loop");
// 返回构造完成的 LoopNode
- return new LoopNode(initializer[0], condition[0], update[0], body);
+ return new LoopNode(initializer[0], condition[0], update[0], body, 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 8a6a6a2..080f1e6 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
@@ -35,6 +35,11 @@ public class ReturnStatementParser implements StatementParser {
*/
@Override
public ReturnNode parse(ParserContext ctx) {
+ // 获取当前 token 的行号、列号和文件名
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+ String file = ctx.getSourceName();
+
// 消耗 "return" 关键字
ctx.getTokens().expect("return");
@@ -49,6 +54,6 @@ public class ReturnStatementParser implements StatementParser {
ctx.getTokens().expectType(TokenType.NEWLINE);
// 构建并返回 ReturnNode(可能为空表达式)
- return new ReturnNode(expr);
+ return new ReturnNode(expr, line, column, file);
}
}
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 b82d78f..9a6f923 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
@@ -51,8 +51,8 @@ public class CallExpressionAnalyzer implements ExpressionAnalyzer