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 dba62b3..8d155e9 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,15 +2,16 @@ 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.ReturnNode;
-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;
+import org.jcnc.snow.compiler.parser.ast.ReturnNode;
+import org.jcnc.snow.compiler.parser.ast.base.NodeContext;
import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
+import org.jcnc.snow.compiler.parser.base.TopLevelParser;
import org.jcnc.snow.compiler.parser.context.ParseException;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.context.TokenStream;
+import org.jcnc.snow.compiler.parser.context.UnexpectedToken;
import org.jcnc.snow.compiler.parser.factory.StatementParserFactory;
import org.jcnc.snow.compiler.parser.utils.FlexibleSectionParser;
import org.jcnc.snow.compiler.parser.utils.FlexibleSectionParser.SectionDefinition;
@@ -22,15 +23,13 @@ import java.util.*;
* 实现 {@link TopLevelParser} 接口,用于将源代码中的函数块解析为抽象语法树(AST)中的 {@link FunctionNode}。
*
*
- * 本类使用 {@link FlexibleSectionParser} 机制,按照语义区块结构对函数进行模块化解析,支持以下部分:
- *
- *
+ * 使用 {@link FlexibleSectionParser} 机制,按照语义区块结构对函数进行模块化解析,支持以下部分:
*
- * - 函数头(关键字 {@code function:} 与函数名)
- * - 参数列表(params 区块)
- * - 返回类型(returns 区块)
- * - 函数体(body 区块)
- * - 函数结束(关键字 {@code end function})
+ * - 函数头(关键字 {@code function:} 与函数名)
+ * - 参数列表(params 区块)
+ * - 返回类型(returns 区块)
+ * - 函数体(body 区块)
+ * - 函数结束(关键字 {@code end function})
*
*
*
@@ -47,76 +46,80 @@ public class FunctionParser implements TopLevelParser {
* 顶层语法解析入口。
*
*
- * 该方法负责完整解析函数定义,包括其所有组成部分,并构建对应的 {@link FunctionNode}。
+ * 解析并生成函数的 AST。
+ * 该方法从源代码中获取 {@link TokenStream},并按照函数定义的不同区块解析,最终生成 {@link FunctionNode}。
*
*
- * @param ctx 当前解析上下文,包含 {@link TokenStream} 和符号表等作用域信息。
- * @return 构建完成的 {@link FunctionNode} 抽象语法树节点。
+ * @param ctx 当前解析上下文,包含 {@link TokenStream} 和符号表等信息
+ * @return 构建完成的 {@link FunctionNode} 对象
*/
@Override
public FunctionNode parse(ParserContext ctx) {
- // 获取当前解析上下文中的 token 流
TokenStream ts = ctx.getTokens();
- // 记录当前 token 的行号、列号和源文件名,用于错误报告或生成节点上下文
- int line = ctx.getTokens().peek().getLine();
- int column = ctx.getTokens().peek().getCol();
+ int line = ts.peek().getLine();
+ int column = ts.peek().getCol();
String file = ctx.getSourceName();
- // 解析函数头(例如可能是 `function` 关键字等)
+ // 解析函数头 (function:)
parseFunctionHeader(ts);
- // 解析函数名
+ // 函数名
String functionName = parseFunctionName(ts);
- // 用于存放解析出来的参数列表
List parameters = new ArrayList<>();
- // 用于存放返回类型,这里用数组是为了在闭包中修改其值
- String[] returnType = new String[1];
- // 用于存放函数体语句列表
+ String[] returnType = new String[1]; // 使用数组模拟可变引用
List body = new ArrayList<>();
- // 获取函数可以包含的可选节(如参数、返回类型、主体等)的定义映射
+ // 定义函数可选区块规则 (params, returns, body)
Map sections = getSectionDefinitions(parameters, returnType, body);
- // 调用通用的多节解析器,实际根据 sections 中注册的规则解析各部分内容
+ // 解析这些区块
FlexibleSectionParser.parse(ctx, ts, sections);
- // 如果函数体为空且返回类型为 void,自动补充一个空的 return 语句
- if (body.isEmpty() && returnType[0].equals("void")) {
+ // 如果函数体为空且返回 void,补充一个空 return
+ if (body.isEmpty() && "void".equals(returnType[0])) {
body.add(new ReturnNode(null, new NodeContext(line, column, file)));
}
- // 检查参数名称是否重复
- Set set = new HashSet<>();
- parameters.forEach((node) -> {
- final String name = node.name();
- if (set.contains(name)) {
- // 如果参数名重复,抛出带具体行列信息的解析异常
- throw new ParseException(String.format("参数 `%s` 重定义", name),
- node.context().line(), node.context().column());
+ // 检查参数名是否重复
+ Set seen = new HashSet<>();
+ for (ParameterNode node : parameters) {
+ if (!seen.add(node.name())) {
+ throw new ParseException(
+ String.format("参数 `%s` 重定义", node.name()),
+ node.context().line(),
+ node.context().column());
}
- set.add(name);
- });
+ }
- // 解析函数的尾部(例如右大括号或者 end 标志)
+ // 解析函数结尾
parseFunctionFooter(ts);
- // 返回完整的函数节点,包含函数名、参数、返回类型、函数体以及源位置信息
- return new FunctionNode(functionName, parameters, returnType[0], body, new NodeContext(line, column, file));
+ return new FunctionNode(functionName, parameters, returnType[0], body,
+ new NodeContext(line, column, file));
}
+ /* ====================================================================== */
+ /* -------------------------- Section Definitions ----------------------- */
+ /* ====================================================================== */
+
/**
- * 构造函数定义中各区块的解析规则(params、returns、body)。
+ * 定义函数的各个语义区块及其解析规则,包括参数列表、返回类型及函数体。
*
*
- * 每个 {@link SectionDefinition} 包含两个部分: 区块起始判断器(基于关键字)与具体的解析逻辑。
+ * 此方法将定义如下的三个区块:
+ *
+ * - "params" 区块,解析参数列表。
+ * - "returns" 区块,解析返回类型。
+ * - "body" 区块,解析函数体。
+ *
*
*
- * @param params 参数节点收集容器,解析结果将存入此列表。
- * @param returnType 返回类型容器,以单元素数组方式模拟引用传递。
- * @param body 函数体语句节点列表容器。
- * @return 区块关键字到解析定义的映射表。
+ * @param params 存储函数参数列表的集合
+ * @param returnType 存储函数返回类型的字符串数组
+ * @param body 存储函数体的语句列表
+ * @return 各个区块的解析定义
*/
private Map getSectionDefinitions(
List params,
@@ -142,8 +145,12 @@ public class FunctionParser implements TopLevelParser {
return map;
}
+ /* ====================================================================== */
+ /* ---------------------------- 函数头/尾 ------------------------------- */
+ /* ====================================================================== */
+
/**
- * 解析函数头部标识符 {@code function:},并跳过其后多余注释与空行。
+ * 解析函数头部分,期望的格式为 `function:`。
*
* @param ts 当前使用的 {@link TokenStream}。
*/
@@ -158,7 +165,7 @@ public class FunctionParser implements TopLevelParser {
* 解析函数名称(标识符)并跳过换行。
*
* @param ts 当前使用的 {@link TokenStream}。
- * @return 函数名字符串。
+ * @return 函数名称字符串。
*/
private String parseFunctionName(TokenStream ts) {
String name = ts.expectType(TokenType.IDENTIFIER).getLexeme();
@@ -167,7 +174,7 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 解析函数结束标记 {@code end function}。
+ * 解析函数结束标记 `end function`。
*
* @param ts 当前使用的 {@link TokenStream}。
*/
@@ -177,18 +184,14 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 解析函数参数列表。
- *
- *
- * 支持声明后附加注释,格式示例:
+ * 解析函数参数列表,支持附加注释,格式为:
*
* params:
* declare x: int // 说明文字
* declare y: float
*
- *
*
- * @param ctx 当前解析上下文,包含 {@link TokenStream} 和符号表等作用域信息。
+ * @param ctx 当前解析上下文,包含 {@link TokenStream} 和符号表等信息。
* @return 所有参数节点的列表。
*/
private List parseParameters(ParserContext ctx) {
@@ -208,19 +211,28 @@ public class FunctionParser implements TopLevelParser {
continue;
}
String lex = ts.peek().getLexeme();
- if (lex.equals("returns") || lex.equals("body") || lex.equals("end")) {
- break;
- }
+ if (lex.equals("returns") || lex.equals("body") || lex.equals("end")) break;
- // 获取当前 token 的行号、列号和文件名
- int line = ctx.getTokens().peek().getLine();
- int column = ctx.getTokens().peek().getCol();
+ int line = ts.peek().getLine();
+ int column = ts.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();
+
+ // 既接受 TYPE 也接受 IDENTIFIER
+ String ptype;
+ if (ts.peek().getType() == TokenType.TYPE || ts.peek().getType() == TokenType.IDENTIFIER) {
+ ptype = ts.next().getLexeme();
+ } else {
+ var t = ts.peek();
+ throw new UnexpectedToken(
+ "期望 TYPE 或 IDENTIFIER,但实际得到 " +
+ t.getType() + " ('" + t.getLexeme() + "')",
+ t.getLine(), t.getCol());
+ }
+
skipComments(ts);
ts.expectType(TokenType.NEWLINE);
list.add(new ParameterNode(pname, ptype, new NodeContext(line, column, file)));
@@ -229,20 +241,27 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 解析返回类型声明。
- *
- *
- * 格式为 {@code returns: TYPE},支持前置或行尾注释。
- *
+ * 解析返回类型声明,格式为 `returns: TYPE`,支持注释。
*
* @param ts 当前使用的 {@link TokenStream}。
- * @return 返回类型名称字符串。
+ * @return 返回类型字符串。
*/
private String parseReturnType(TokenStream ts) {
ts.expect("returns");
ts.expect(":");
skipComments(ts);
- Token typeToken = ts.expectType(TokenType.TYPE);
+
+ Token typeToken;
+ if (ts.peek().getType() == TokenType.TYPE || ts.peek().getType() == TokenType.IDENTIFIER) {
+ typeToken = ts.next();
+ } else {
+ var t = ts.peek();
+ throw new UnexpectedToken(
+ "期望 TYPE 或 IDENTIFIER,但实际得到 " +
+ t.getType() + " ('" + t.getLexeme() + "')",
+ t.getLine(), t.getCol());
+ }
+
String rtype = typeToken.getLexeme();
skipComments(ts);
ts.expectType(TokenType.NEWLINE);
@@ -251,14 +270,10 @@ public class FunctionParser implements TopLevelParser {
}
/**
- * 解析函数体区块,直到遇到 {@code end body}。
- *
- *
- * 每一行由对应的语句解析器处理,可嵌套控制结构、返回语句、表达式等。
- *
+ * 解析函数体区块,直到遇到 `end body`。
*
* @param ctx 当前解析上下文。
- * @param ts 当前使用的 {@link TokenStream}。
+ * @param ts 当前使用的 {@link TokenStream}。
* @return 所有函数体语句节点的列表。
*/
private List parseFunctionBody(ParserContext ctx, TokenStream ts) {
@@ -275,9 +290,8 @@ public class FunctionParser implements TopLevelParser {
ts.next();
continue;
}
- if ("end".equals(ts.peek().getLexeme())) {
- break;
- }
+ if ("end".equals(ts.peek().getLexeme())) break;
+
stmts.add(StatementParserFactory.get(ts.peek().getLexeme()).parse(ctx));
}
ts.expect("end");
@@ -293,9 +307,7 @@ public class FunctionParser implements TopLevelParser {
* @param ts 当前使用的 {@link TokenStream}。
*/
private void skipComments(TokenStream ts) {
- while (ts.peek().getType() == TokenType.COMMENT) {
- ts.next();
- }
+ while (ts.peek().getType() == TokenType.COMMENT) ts.next();
}
/**
@@ -304,8 +316,6 @@ public class FunctionParser implements TopLevelParser {
* @param ts 当前使用的 {@link TokenStream}。
*/
private void skipNewlines(TokenStream ts) {
- while (ts.peek().getType() == TokenType.NEWLINE) {
- ts.next();
- }
+ while (ts.peek().getType() == TokenType.NEWLINE) ts.next();
}
-}
\ No newline at end of file
+}