diff --git a/README.md b/README.md
index 52d4e39..f0d9cd6 100644
--- a/README.md
+++ b/README.md
@@ -3,27 +3,27 @@
Snow编程语言
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
+
@@ -68,9 +68,9 @@ Snow 语言受到 LLM 驱动代码生成趋势的启发,强调简单而清晰的
3. **运行项目**
- 使用IDEA配置好的运行配置SnowCompiler
+ 使用IDEA配置好的运行配置SnowCompiler
- 
+ 
4. **运行成功**
@@ -243,7 +243,7 @@ Process has ended
3: 0
```
-
+
## 编译Snow源代码
@@ -329,8 +329,6 @@ end module
[Git 管理规范](doc/Git-Management/Git-Management.md)
-
-
## 开发计划 / TODO
* 扩展标准库支持和更多内置模块,如字符串,文件操作等常用功能。
diff --git a/playground/main.snow b/playground/Main.snow
similarity index 100%
rename from playground/main.snow
rename to playground/Main.snow
diff --git a/playground/test.snow b/playground/Math.snow
similarity index 100%
rename from playground/test.snow
rename to playground/Math.snow
diff --git a/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java b/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java
index 6c2b335..fa0831a 100644
--- a/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java
+++ b/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java
@@ -59,7 +59,7 @@ public class SnowCompiler {
System.out.println(code);
LexerEngine lexer = new LexerEngine(code, p.toString());
- ParserContext ctx = new ParserContext(lexer.getAllTokens());
+ ParserContext ctx = new ParserContext(lexer.getAllTokens(), p.toString());
allAst.addAll(new ParserEngine(ctx).parse());
}
diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
index 819fa07..4d06999 100644
--- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java
@@ -48,7 +48,7 @@ public class LexerEngine {
* 构造时立即进行全量扫描。
*
* @param source 源代码文本
- * @param sourceName 文件名或来源描述(如"main.snow")
+ * @param sourceName 文件名或来源描述(如"Main.snow")
*/
public LexerEngine(String source, String sourceName) {
this.context = new LexerContext(source);
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 c9109a1..ac36871 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
@@ -7,33 +7,64 @@ import java.util.List;
/**
* {@code CallExpressionNode} 表示抽象语法树(AST)中的函数调用表达式节点。
*
- * 函数调用表达式用于表示函数或过程的调用操作,
- * 包括被调用对象(callee)以及一组参数表达式(arguments)。
+ * 函数调用表达式用于表示函数或过程的调用操作,包含被调用对象(callee)以及一组参数表达式(arguments)。
*
*
- * @param callee 被调用的表达式节点,通常为函数标识符或成员访问表达式。
- * @param arguments 参数表达式列表,依照调用顺序排列。
+ * @param callee 被调用的表达式节点,通常为函数标识符或成员访问表达式,表示函数名或方法名等。
+ * @param arguments 参数表达式列表,表示函数调用中传递给函数的实际参数。参数的顺序与调用顺序一致。
+ * @param line 当前表达式所在的行号,方便调试和错误定位。
+ * @param column 当前表达式所在的列号,用于精确定位错误位置。
*/
-public record CallExpressionNode(ExpressionNode callee, List arguments) implements ExpressionNode {
+public record CallExpressionNode(
+ ExpressionNode callee, // 被调用的表达式节点,表示函数或方法名
+ List arguments, // 函数调用的参数表达式列表
+ int line, // 当前节点所在的行号
+ int column, // 当前节点所在的列号
+ String file // 当前节点所在的文件
+) implements ExpressionNode {
/**
- * 返回函数调用表达式的字符串形式。
+ * 返回函数调用表达式的字符串形式,便于调试与语法树可视化。
*
- * 该格式将输出为类似 {@code foo(a, b, c)} 的形式,
- * 便于调试与语法树可视化。
+ * 该方法将表达式节点转化为类似 {@code foo(a, b, c)} 的格式,便于查看和理解抽象语法树的结构。
*
*
- * @return 表示函数调用的字符串表示
+ * @return 表示函数调用的字符串表示,格式为 {@code callee(arguments)}。
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(callee).append("(");
+ sb.append(callee).append("("); // 拼接函数名和左括号
for (int i = 0; i < arguments.size(); i++) {
- sb.append(arguments.get(i));
- if (i + 1 < arguments.size()) sb.append(", ");
+ sb.append(arguments.get(i)); // 拼接每个参数
+ if (i + 1 < arguments.size()) sb.append(", "); // 如果不是最后一个参数,添加逗号和空格
}
- sb.append(")");
- return sb.toString();
+ 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/context/ParserContext.java b/src/main/java/org/jcnc/snow/compiler/parser/context/ParserContext.java
index bbf2b2e..5ff228a 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/context/ParserContext.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/context/ParserContext.java
@@ -1,6 +1,8 @@
package org.jcnc.snow.compiler.parser.context;
import org.jcnc.snow.compiler.lexer.token.Token;
+
+import java.nio.file.Paths;
import java.util.List;
/**
@@ -16,15 +18,27 @@ public class ParserContext {
/** 当前语法分析所使用的 Token 流 */
private final TokenStream tokens;
+ /** 当前语法分析所使用的资源文件名 */
+ private final String sourceName;
+
+
/**
- * 使用词法分析得到的 Token 列表构造上下文。
+ * 构造一个新的 {@code ParserContext} 实例,用于在语法分析阶段传递上下文信息。
+ *
+ * 本构造方法接收词法分析得到的 {@link Token} 列表以及当前源文件名,
+ * 并将 Token 列表包装为 {@link TokenStream} 以便后续遍历与分析。
+ * 源文件名通常用于错误定位、调试和报错信息中指明具体文件。
+ *
*
- * @param tokens 词法分析器生成的 Token 集合
+ * @param tokens 词法分析器生成的 Token 集合,表示待解析的完整源代码流
+ * @param sourceName 当前正在解析的源文件名(或文件路径),用于错误报告和调试定位
*/
- public ParserContext(List tokens) {
+ public ParserContext(List tokens, String sourceName) {
this.tokens = new TokenStream(tokens);
+ this.sourceName = Paths.get(sourceName).toAbsolutePath().toString();
}
+
/**
* 获取封装的 Token 流,用于驱动语法分析过程。
*
@@ -33,4 +47,13 @@ public class ParserContext {
public TokenStream getTokens() {
return tokens;
}
+
+ /**
+ * 获取资源文件名,用于发现错误后展示文件名。
+ *
+ * @return 当前语法分析所使用的资源文件名
+ */
+ public String getSourceName() {
+ return sourceName;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/jcnc/snow/compiler/parser/core/ParserEngine.java b/src/main/java/org/jcnc/snow/compiler/parser/core/ParserEngine.java
index 03810b5..7d0854f 100644
--- a/src/main/java/org/jcnc/snow/compiler/parser/core/ParserEngine.java
+++ b/src/main/java/org/jcnc/snow/compiler/parser/core/ParserEngine.java
@@ -17,7 +17,7 @@ public record ParserEngine(ParserContext ctx) {
List errs = new ArrayList<>();
TokenStream ts = ctx.getTokens();
- while (ts.isAtEnd()) { // ← 取反
+ while (ts.isAtEnd()) {
// 跳过空行
if (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
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 4e8d3a3..9499f6d 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
@@ -12,8 +12,7 @@ import java.util.List;
* {@code CallParselet} 表示函数调用语法的中缀解析器。
*
* 用于处理形如 {@code foo(arg1, arg2)} 的函数调用结构。
- * 在 Pratt 解析器架构中,该解析器在函数名之后接收括号开始的调用参数,
- * 构建 {@link CallExpressionNode} 抽象语法树节点。
+ * 在 Pratt 解析器架构中,该解析器在函数名之后接收括号开始的调用参数,构建 {@link CallExpressionNode} 抽象语法树节点。
*
*/
public class CallParselet implements InfixParselet {
@@ -31,6 +30,11 @@ public class CallParselet implements InfixParselet {
List args = new ArrayList<>();
+ // 获取当前 token 的行号和列号
+ int line = ctx.getTokens().peek().getLine();
+ int column = ctx.getTokens().peek().getCol();
+
+ // 解析函数调用参数
if (!ctx.getTokens().peek().getLexeme().equals(")")) {
do {
args.add(new PrattExpressionParser().parse(ctx));
@@ -38,7 +42,10 @@ public class CallParselet implements InfixParselet {
}
ctx.getTokens().expect(")"); // 消费并验证 ")"
- return new CallExpressionNode(left, args);
+
+ // 创建 CallExpressionNode 并传递位置信息,文件名称
+ String file = ctx.getSourceName();
+ return new CallExpressionNode(left, args, line, column, file);
}
/**
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 02ada73..b696410 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
@@ -88,9 +88,8 @@ public class ModuleParser implements TopLevelParser {
// 确保模块体以 "end module" 结束
ts.expect("end");
ts.expect("module");
- ts.expectType(TokenType.NEWLINE);
// 构建并返回完整的模块语法树节点
return new ModuleNode(name, imports, functions);
}
-}
+}
\ No newline at end of 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 df36075..87dc160 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
@@ -182,7 +182,7 @@ public class ASTJsonSerializer {
case IdentifierNode(String name) -> exprMap("Identifier", "name", name);
case NumberLiteralNode(String value) -> exprMap("NumberLiteral", "value", value);
case StringLiteralNode(String value) -> exprMap("StringLiteral", "value", value);
- case CallExpressionNode(ExpressionNode callee, List arguments) -> {
+ case CallExpressionNode(ExpressionNode callee, List arguments, int line, int column, String file) -> {
List