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 37c24b3..7b47a5a 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 @@ -26,76 +26,83 @@ import java.util.Map; *
  • 返回类型
  • *
  • 函数体
  • * - *

    - * 解析顺序不固定,且每个部分的解析逻辑由 {@code FlexibleSectionParser} 配合外部条件和解析器来控制。 - *

    - * 解析过程中,函数定义的各个部分被依次解析,并最终构建成 {@code FunctionNode},作为抽象语法树的一部分。 + * 各部分的顺序不固定,由 FlexibleSectionParser 按规则识别和处理。 *

    */ public class FunctionParser implements TopLevelParser { /** - * 解析函数定义,构建函数的抽象语法树。 + * 解析函数定义,构建函数的抽象语法树节点。 *

    - * 此方法解析函数的多个部分,包括函数名、参数、返回类型和函数体。各部分的解析顺序由 {@code FlexibleSectionParser} 控制。 + * 此方法首先解析函数的头部和名称,然后通过 FlexibleSectionParser + * 分别解析函数的参数、返回类型和函数体,最后封装为 FunctionNode 返回。 *

    * - * @param ctx 解析上下文,包含 Token 流等信息 - * @return 解析后的函数语法树节点 + * @param ctx 解析上下文(包含 Token 流、作用域信息等) + * @return 构建完成的 FunctionNode */ @Override public FunctionNode parse(ParserContext ctx) { TokenStream tokens = ctx.getTokens(); - // 匹配函数头部 + // 匹配并消费 "function:" 标记 parseFunctionHeader(tokens); - // 解析函数名 + // 获取函数名称 String functionName = parseFunctionName(tokens); - // 用于存储参数、返回类型和函数体 + // 用于接收参数、返回类型和函数体的容器 List parameters = new ArrayList<>(); - String[] returnType = {null}; // 模拟引用传参 + String[] returnType = {null}; // 使用数组模拟引用,以便 lambda 内修改值 List body = new ArrayList<>(); - // 定义可变区块的解析规则 + // 构建区块解析定义(参数、返回类型、函数体) Map sectionDefinitions = getStringSectionDefinitionMap(parameters, returnType, body); - // 使用 FlexibleSectionParser 解析函数的可变部分,顺序无关 + // 使用 FlexibleSectionParser 解析区块,顺序无关 FlexibleSectionParser.parse(ctx, tokens, sectionDefinitions); - // 匹配函数结尾标签 + // 匹配函数结束部分(end function) parseFunctionFooter(tokens); - // 返回构建好的函数节点 + // 构建语法树节点并返回 return new FunctionNode(functionName, parameters, returnType[0], body); } + /** + * 构造区块定义映射,包括参数、返回类型、函数体。 + * + * @param parameters 参数节点容器 + * @param returnType 返回类型容器(数组模拟引用) + * @param body 函数体语句节点容器 + * @return 各关键字对应的解析逻辑映射 + */ private Map getStringSectionDefinitionMap(List parameters, String[] returnType, List body) { Map sectionDefinitions = new HashMap<>(); - // 参数解析 + // 参数部分解析规则 sectionDefinitions.put("parameter", new SectionDefinition( ts -> ts.peek().getLexeme().equals("parameter"), (_, ts1) -> parameters.addAll(parseParameters(ts1)) )); - // 返回类型解析 + // 返回类型部分解析规则 sectionDefinitions.put("return_type", new SectionDefinition( ts -> ts.peek().getLexeme().equals("return_type"), (_, ts1) -> returnType[0] = parseReturnType(ts1) )); - // 函数体解析 + // 函数体部分解析规则 sectionDefinitions.put("body", new SectionDefinition( ts -> ts.peek().getLexeme().equals("body"), (ctx1, ts1) -> body.addAll(parseFunctionBody(ctx1, ts1)) )); + return sectionDefinitions; } /** - * 匹配并解析函数头部标记(例如:function:)。 + * 匹配并解析函数头部(function:)。 * * @param ts Token 流 */ @@ -105,10 +112,10 @@ public class FunctionParser implements TopLevelParser { } /** - * 解析函数名并跳过换行符。 + * 解析函数名称,并跳过换行。 * * @param ts Token 流 - * @return 函数名 + * @return 函数名称 */ private String parseFunctionName(TokenStream ts) { String name = ts.expectType(TokenType.IDENTIFIER).getLexeme(); @@ -117,7 +124,7 @@ public class FunctionParser implements TopLevelParser { } /** - * 匹配并解析函数结尾标记(例如:end function)。 + * 匹配并解析函数尾部(end function)。 * * @param ts Token 流 */ @@ -128,10 +135,12 @@ public class FunctionParser implements TopLevelParser { } /** - * 解析参数列表。 - *

    - * 该方法解析以 "declare" 开头的参数声明行,并返回一个包含参数的 {@code ParameterNode} 列表。 - *

    + * 解析函数参数部分,格式: + *
    +     * parameter:
    +     *   declare param1: int
    +     *   declare param2: string
    +     * 
    * * @param ts Token 流 * @return 参数节点列表 @@ -143,18 +152,21 @@ public class FunctionParser implements TopLevelParser { List params = new ArrayList<>(); + // 持续解析参数声明行,直到下一个区块或 "end" while (true) { if (ts.peek().getType() == TokenType.NEWLINE) { - ts.next(); + ts.next(); // 跳过空行 continue; } - if ("return_type".equals(ts.peek().getLexeme()) || "body".equals(ts.peek().getLexeme()) || "end".equals(ts.peek().getLexeme())) { + // 到达下一个区块或函数结尾时停止 + String keyword = ts.peek().getLexeme(); + if ("return_type".equals(keyword) || "body".equals(keyword) || "end".equals(keyword)) { break; } + // 匹配 "declare paramName: Type" 格式 ts.expect("declare"); - String paramName = ts.expectType(TokenType.IDENTIFIER).getLexeme(); ts.expect(":"); String paramType = ts.expectType(TokenType.TYPE).getLexeme(); @@ -167,10 +179,13 @@ public class FunctionParser implements TopLevelParser { } /** - * 解析返回类型。 + * 解析返回类型部分,格式如下: + *
    +     * return_type: int
    +     * 
    * * @param ts Token 流 - * @return 返回类型 + * @return 返回类型字符串 */ private String parseReturnType(TokenStream ts) { ts.expect("return_type"); @@ -181,14 +196,17 @@ public class FunctionParser implements TopLevelParser { } /** - * 解析函数体。 - *

    - * 该方法解析函数体中的每个语句,并返回一个 {@code StatementNode} 列表。 - *

    + * 解析函数体部分,格式示例: + *
    +     * body:
    +     *   print "hello"
    +     *   return x
    +     * end body
    +     * 
    * * @param ctx 解析上下文 * @param ts Token 流 - * @return 函数体的语句列表 + * @return 语句节点列表 */ private List parseFunctionBody(ParserContext ctx, TokenStream ts) { ts.expect("body"); @@ -197,6 +215,7 @@ public class FunctionParser implements TopLevelParser { List body = new ArrayList<>(); + // 持续解析直到遇到 end while (true) { if (ts.peek().getType() == TokenType.NEWLINE) { ts.next(); @@ -207,11 +226,13 @@ public class FunctionParser implements TopLevelParser { break; } + // 获取当前语句关键字,并通过工厂选择对应的语句解析器 String keyword = ts.peek().getLexeme(); StatementNode statement = StatementParserFactory.get(keyword).parse(ctx); body.add(statement); } + // 匹配 end body ts.expect("end"); ts.expect("body"); ts.expectType(TokenType.NEWLINE); diff --git a/src/main/java/org/jcnc/snow/compiler/parser/util/FlexibleSectionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/util/FlexibleSectionParser.java index a53511b..95390a0 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/util/FlexibleSectionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/util/FlexibleSectionParser.java @@ -14,9 +14,8 @@ import java.util.function.Predicate; * {@code FlexibleSectionParser} 提供了一个灵活的机制来解析可变的语法块。每个语法块的解析逻辑通过外部提供, * 该类仅负责按顺序解析不同的区块,直到遇到结束标记。它完全解耦了具体的语法关键字和解析逻辑。 *

    - * *

    - * 使用此类解析函数定义中的多个部分(如参数、返回类型、函数体等),而不需要在解析器中显式地硬编码每个部分。 + * 使用此类可以解析如函数定义中的多个部分(如参数、返回类型、函数体等),而无需在解析器中硬编码这些结构。 *

    */ public class FlexibleSectionParser { @@ -24,41 +23,45 @@ public class FlexibleSectionParser { /** * 解析一系列的可变区块,解析顺序和具体内容由外部定义。 *

    - * 该方法接受一个包含区块定义的映射,每个区块定义包含一个条件(`Predicate`)和一个解析器(`BiConsumer`)。 - * 条件用于判断是否应该解析该区块,解析器则负责实际的解析过程。 + * 该方法接受一个包含区块定义的映射,每个区块定义包含一个条件(Predicate) + * 和一个解析器(BiConsumer)。 + * 条件用于判断当前是否应解析该区块,解析器则执行解析逻辑。 *

    * - * @param ctx 解析上下文,包含词法流等信息 - * @param tokens 当前的 Token 流 - * @param sectionDefinitions 各种区块定义,键值为区块的名称,值为对应的解析器和条件 + * @param ctx 当前的解析上下文,包含语法分析所需的所有信息(如作用域、错误处理等) + * @param tokens 当前的词法 token 流,用于逐个查看或消耗 token + * @param sectionDefinitions 区块定义映射:每个关键字(如 "params", "returns", "body")对应一个区块定义 */ public static void parse(ParserContext ctx, TokenStream tokens, Map sectionDefinitions) { - // 跳过空行 + // 跳过最开始的空行,避免误判开始关键字 while (tokens.peek().getType() == TokenType.NEWLINE) { tokens.next(); } - // 遍历所有可变部分的解析 + // 主循环:逐个处理区块,直到遇到 "end" 为止 while (true) { + // 获取当前 token 的字面量(通常是关键字字符串) String keyword = tokens.peek().getLexeme(); - // 查找是否有与当前关键字匹配的区块 + // 尝试在映射中找到对应该关键字的区块定义 SectionDefinition definition = sectionDefinitions.get(keyword); + // 如果找到了定义且其条件满足当前 token 流 if (definition != null && definition.condition().test(tokens)) { - // 执行解析动作 + // 执行该区块的解析逻辑 definition.parser().accept(ctx, tokens); } else if ("end".equals(keyword)) { - // 如果遇到 "end",则退出解析 + // 如果遇到 "end",表示所有区块结束,退出循环 break; } else { + // 如果关键字无法识别,或不满足条件,则抛出异常 throw new RuntimeException("未识别的关键字或条件不满足: " + keyword); } - // 跳过空行,继续解析 + // 每次解析完成后,继续跳过空行,准备进入下一个区块的判断 while (tokens.peek().getType() == TokenType.NEWLINE) { tokens.next(); } @@ -66,31 +69,31 @@ public class FlexibleSectionParser { } /** - * 定义区块的结构:每个区块有一个条件和一个解析器。 + * 区块定义类:表示一个语法区块的匹配条件和解析逻辑。 *

    - * {@code SectionDefinition} 是描述如何解析某个语法块的结构。 - * 它包含一个条件(`Predicate`),用于判断当前 Token 是否符合该区块的开始标识, - * 以及一个解析器(`BiConsumer`),用于执行具体的解析操作。 + * 每个区块由两个部分组成: + * - 条件:用于判断当前 token 流是否应进入该区块的解析。 + * - 解析器:具体的解析逻辑,通常是消费若干 token 并更新解析上下文。 *

    * - * @param condition 条件,判断是否需要解析该区块 - * @param parser 区块的解析器 + * @param condition 匹配条件,返回 true 表示此区块应被解析 + * @param parser 实际解析逻辑 */ public record SectionDefinition(Predicate condition, BiConsumer parser) { /** - * 构造一个新的区块定义。 + * 构造函数。Java Record 自动生成,但我们保留注释以说明其目的。 * - * @param condition 判断该区块是否应该解析的条件 - * @param parser 区块的解析器 + * @param condition 判断当前是否应解析该区块的逻辑 + * @param parser 负责实际解析过程的处理器 */ public SectionDefinition { } /** - * 获取该区块的条件,用于判断是否解析此区块。 + * 获取条件判断函数。 * - * @return 区块的条件 + * @return 一个用于判断是否进入该区块的 Predicate */ @Override public Predicate condition() { @@ -98,9 +101,9 @@ public class FlexibleSectionParser { } /** - * 获取该区块的解析器。 + * 获取解析器函数。 * - * @return 区块的解析器 + * @return 一个解析该区块的 BiConsumer 函数 */ @Override public BiConsumer parser() {