From 1835b85c5c5718525b2319544fabccd309df5c5f Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 29 Aug 2025 17:58:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=AF=B9=E8=B1=A1?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E8=A1=A8=E8=BE=BE=E5=BC=8F=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 NewExpressionNode 类,表示对象创建表达式 - 该节点用于处理 "new" 关键字实例化类型的语法 - 包含目标类型名、构造函数参数列表和源码位置信息 - 实现了 ExpressionNode 接口,提供获取源码上下文的方法 --- .../parser/expression/NewObjectParselet.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/main/java/org/jcnc/snow/compiler/parser/expression/NewObjectParselet.java diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/NewObjectParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/NewObjectParselet.java new file mode 100644 index 0000000..fbda9e4 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/NewObjectParselet.java @@ -0,0 +1,84 @@ +package org.jcnc.snow.compiler.parser.expression; + +import org.jcnc.snow.compiler.lexer.token.Token; +import org.jcnc.snow.compiler.lexer.token.TokenType; +import org.jcnc.snow.compiler.parser.ast.NewExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.NodeContext; +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.expression.base.PrefixParselet; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@code NewObjectParselet} + *

+ * 解析对象创建表达式 new TypeName(arg1, arg2, ...) 的前缀解析器实现。 + *

+ *

+ */ +public class NewObjectParselet implements PrefixParselet { + + /** + * 解析 new 对象创建表达式,并生成 AST 新建节点。 + * + * @param ctx 语法分析上下文,包含 TokenStream 及源文件名等信息 + * @param token 当前读取到的 new 关键字 Token + * @return 表达式节点(NewExpressionNode) + * + *

+ * 解析流程: + *

    + *
  1. 读取类型名(支持内建类型或结构体名);
  2. + *
  3. 读取参数列表,参数为表达式,用逗号分隔;
  4. + *
  5. 封装为 NewExpressionNode,记录源码位置信息。
  6. + *
+ * 出错时会抛出 UnexpectedToken 异常。 + *

+ */ + @Override + public ExpressionNode parse(ParserContext ctx, Token token) { + TokenStream ts = ctx.getTokens(); + + // ========================== + // 1) 解析类型名 + // ========================== + // 类型名只能为内建类型(TYPE)或用户结构体名(IDENTIFIER) + if (ts.peek().getType() != TokenType.TYPE && ts.peek().getType() != TokenType.IDENTIFIER) { + var t = ts.peek(); + throw new UnexpectedToken( + "期望的标记类型为 TYPE 或 IDENTIFIER,但实际得到的是 " + + t.getType() + " ('" + t.getLexeme() + "')", + t.getLine(), t.getCol() + ); + } + String typeName = ts.next().getLexeme(); + + // ========================== + // 2) 解析构造参数列表 + // ========================== + ts.expect("("); // 必须有左括号 + + List args = new ArrayList<>(); + if (!ts.match(")")) { // 非空参数列表 + // 连续处理逗号分隔的多个参数 + do { + args.add(new PrattExpressionParser().parse(ctx)); + } while (ts.match(",")); + ts.expect(")"); // 结尾必须为右括号 + } + + // ========================== + // 3) 封装为 AST 节点并返回 + // ========================== + NodeContext nc = new NodeContext(token.getLine(), token.getCol(), ctx.getSourceName()); + return new NewExpressionNode(typeName, args, nc); + } +}