!1 bug: 修复 CallExpressionNode 缺失行号和列号跟踪

Merge pull request !1 from Luke/bugfix/fix-line-numbers
This commit is contained in:
Sky 2025-06-09 01:48:18 +00:00 committed by Gitee
commit ed898d1e74
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
2 changed files with 46 additions and 17 deletions

View File

@ -7,33 +7,56 @@ import java.util.List;
/** /**
* {@code CallExpressionNode} 表示抽象语法树AST中的函数调用表达式节点 * {@code CallExpressionNode} 表示抽象语法树AST中的函数调用表达式节点
* <p> * <p>
* 函数调用表达式用于表示函数或过程的调用操作 * 函数调用表达式用于表示函数或过程的调用操作包含被调用对象callee以及一组参数表达式arguments
* 包括被调用对象callee以及一组参数表达式arguments
* </p> * </p>
* *
* @param callee 被调用的表达式节点通常为函数标识符或成员访问表达式 * @param callee 被调用的表达式节点通常为函数标识符或成员访问表达式表示函数名或方法名等
* @param arguments 参数表达式列表依照调用顺序排列 * @param arguments 参数表达式列表表示函数调用中传递给函数的实际参数参数的顺序与调用顺序一致
* @param line 当前表达式所在的行号方便调试和错误定位
* @param column 当前表达式所在的列号用于精确定位错误位置
*/ */
public record CallExpressionNode(ExpressionNode callee, List<ExpressionNode> arguments) implements ExpressionNode { public record CallExpressionNode(
ExpressionNode callee, // 被调用的表达式节点表示函数或方法名
List<ExpressionNode> arguments, // 函数调用的参数表达式列表
int line, // 当前节点所在的行号
int column // 当前节点所在的列号
) implements ExpressionNode {
/** /**
* 返回函数调用表达式的字符串形式 * 返回函数调用表达式的字符串形式便于调试与语法树可视化
* <p> * <p>
* 该格式将输出为类似 {@code foo(a, b, c)} 的形式 * 该方法将表达式节点转化为类似 {@code foo(a, b, c)} 的格式便于查看和理解抽象语法树的结构
* 便于调试与语法树可视化
* </p> * </p>
* *
* @return 表示函数调用的字符串表示 * @return 表示函数调用的字符串表示格式为 {@code callee(arguments)}
*/ */
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(callee).append("("); sb.append(callee).append("("); // 拼接函数名和左括号
for (int i = 0; i < arguments.size(); i++) { for (int i = 0; i < arguments.size(); i++) {
sb.append(arguments.get(i)); sb.append(arguments.get(i)); // 拼接每个参数
if (i + 1 < arguments.size()) sb.append(", "); if (i + 1 < arguments.size()) sb.append(", "); // 如果不是最后一个参数添加逗号和空格
} }
sb.append(")"); sb.append(")"); // 拼接右括号
return sb.toString(); return sb.toString(); // 返回拼接好的字符串
}
/**
* 获取当前表达式所在的行号
*
* @return 当前表达式的行号
*/
public int line() {
return line;
}
/**
* 获取当前表达式所在的列号
*
* @return 当前表达式的列号
*/
public int column() {
return column;
} }
} }

View File

@ -12,8 +12,7 @@ import java.util.List;
* {@code CallParselet} 表示函数调用语法的中缀解析器 * {@code CallParselet} 表示函数调用语法的中缀解析器
* <p> * <p>
* 用于处理形如 {@code foo(arg1, arg2)} 的函数调用结构 * 用于处理形如 {@code foo(arg1, arg2)} 的函数调用结构
* Pratt 解析器架构中该解析器在函数名之后接收括号开始的调用参数 * Pratt 解析器架构中该解析器在函数名之后接收括号开始的调用参数构建 {@link CallExpressionNode} 抽象语法树节点
* 构建 {@link CallExpressionNode} 抽象语法树节点
* </p> * </p>
*/ */
public class CallParselet implements InfixParselet { public class CallParselet implements InfixParselet {
@ -31,6 +30,11 @@ public class CallParselet implements InfixParselet {
List<ExpressionNode> args = new ArrayList<>(); List<ExpressionNode> args = new ArrayList<>();
// 获取当前 token 的行号和列号
int line = ctx.getTokens().peek().getLine();
int column = ctx.getTokens().peek().getCol();
// 解析函数调用参数
if (!ctx.getTokens().peek().getLexeme().equals(")")) { if (!ctx.getTokens().peek().getLexeme().equals(")")) {
do { do {
args.add(new PrattExpressionParser().parse(ctx)); args.add(new PrattExpressionParser().parse(ctx));
@ -38,7 +42,9 @@ public class CallParselet implements InfixParselet {
} }
ctx.getTokens().expect(")"); // 消费并验证 ")" ctx.getTokens().expect(")"); // 消费并验证 ")"
return new CallExpressionNode(left, args);
// 创建 CallExpressionNode 并传递位置信息
return new CallExpressionNode(left, args, line, column);
} }
/** /**