diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java index 955baa7..766f53d 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java @@ -14,17 +14,17 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser; /** * {@code ExpressionStatementParser} 用于解析通用表达式语句(赋值或普通表达式)。 *

- * 支持以下两种语法结构: + * 支持以下两种语法结构: *

{@code
  * x = 1 + 2        // 赋值语句
  * doSomething()    // 一般表达式语句
+ * this.name = n    // 将 this.name 赋值语法糖为对 name 的赋值
  * }
- * - * 若语句起始为关键字或空行,将直接抛出异常,防止非法语法进入表达式解析流程。 + * + * - 以标识符开头且后接 '=' 时,解析为 {@link AssignmentNode}。 + * - 否则先解析为一般表达式;若后续遇到 '=',则回退为“ = ”赋值语句。 + * - 所有表达式语句必须以换行符(NEWLINE)结尾。 + *

*/ public class ExpressionStatementParser implements StatementParser { @@ -33,49 +33,81 @@ public class ExpressionStatementParser implements StatementParser { * * @param ctx 当前解析上下文,提供词法流与环境信息 * @return {@link AssignmentNode} 或 {@link ExpressionStatementNode} 语法节点 - * @throws UnexpectedToken 若遇到非法起始(关键字、空行等) + * @throws UnexpectedToken 若遇到非法起始(关键字 'end' 等) */ @Override public StatementNode parse(ParserContext ctx) { TokenStream ts = ctx.getTokens(); - if (ts.peek().getType() == TokenType.NEWLINE || ts.peek().getType() == TokenType.KEYWORD) { + // ----------- 起始 token 合法性检查(放宽以支持 this 开头)----------- + if (ts.peek().getType() == TokenType.NEWLINE) { + // 空行不应进入表达式解析,直接抛出异常 throw new UnexpectedToken( - "无法解析以关键字开头的表达式: " + ts.peek().getLexeme(), + "无法解析以空行开头的表达式", ts.peek().getLine(), ts.peek().getCol() ); } + if (ts.peek().getType() == TokenType.KEYWORD) { + String kw = ts.peek().getLexeme(); + // 仅允许 this 作为表达式起始;其它关键字(如 end/if/else 等)仍禁止 + if (!"this".equals(kw)) { + throw new UnexpectedToken( + "无法解析以关键字开头的表达式: " + kw, + ts.peek().getLine(), + ts.peek().getCol() + ); + } + } int line = ts.peek().getLine(); int column = ts.peek().getCol(); String file = ctx.getSourceName(); - // 简单形式: IDENTIFIER = expr + // ------------- 简单形式: IDENTIFIER = expr ------------- + // 快速路径:如 "a = ...",直接识别为赋值语句,无需完整表达式树回退 if (ts.peek().getType() == TokenType.IDENTIFIER && "=".equals(ts.peek(1).getLexeme())) { - String varName = ts.next().getLexeme(); - ts.expect("="); - ExpressionNode value = new PrattExpressionParser().parse(ctx); + String varName = ts.next().getLexeme(); // 消费 IDENTIFIER + ts.expect("="); // 消费 '=' + ExpressionNode value = new PrattExpressionParser().parse(ctx); // 解析右侧表达式 ts.expectType(TokenType.NEWLINE); + // 返回简单变量赋值节点 return new AssignmentNode(varName, value, new NodeContext(line, column, file)); } - // 尝试解析更通用的左值形式(支持下标): = + // ------------- 通用形式: [= ] ------------- + // 先解析潜在“左值表达式”或普通表达式 ExpressionNode lhs = new PrattExpressionParser().parse(ctx); + + // 若遇到等号,则尝试回退为赋值语句(兼容更复杂的左值表达式) if ("=".equals(ts.peek().getLexeme())) { - ts.next(); // consume '=' - ExpressionNode rhs = new PrattExpressionParser().parse(ctx); + ts.next(); // 消费 '=' + ExpressionNode rhs = new PrattExpressionParser().parse(ctx); // 解析右值表达式 ts.expectType(TokenType.NEWLINE); - // 根据左值类型构造具体赋值节点 + + // 根据左值 AST 类型,生成不同赋值节点 if (lhs instanceof org.jcnc.snow.compiler.parser.ast.IdentifierNode id) { + // 变量名赋值:a = rhs return new AssignmentNode(id.name(), rhs, new NodeContext(line, column, file)); + } else if (lhs instanceof org.jcnc.snow.compiler.parser.ast.IndexExpressionNode idx) { + // 下标赋值:a[i] = rhs return new org.jcnc.snow.compiler.parser.ast.IndexAssignmentNode(idx, rhs, new NodeContext(line, column, file)); + + } else if (lhs instanceof org.jcnc.snow.compiler.parser.ast.MemberExpressionNode mem + && mem.object() instanceof org.jcnc.snow.compiler.parser.ast.IdentifierNode oid + && "this".equals(oid.name())) { + // 支持:this.field = rhs + // 语法糖:降级为对当前作用域同名变量的赋值,相当于 "field = rhs" + return new AssignmentNode(mem.member(), rhs, new NodeContext(line, column, file)); + } else { + // 其它成员赋值(如 a.b = ...)不支持,报错 throw new UnexpectedToken("不支持的赋值左值类型: " + lhs.getClass().getSimpleName(), line, column); } } - // 普通表达式语句 + + // 不是赋值,则当作普通表达式语句处理 ts.expectType(TokenType.NEWLINE); return new ExpressionStatementNode(lhs, new NodeContext(line, column, file)); }