diff --git a/includes/ast/parser.vp b/includes/ast/parser.vp index 44aa098..e6584ee 100644 --- a/includes/ast/parser.vp +++ b/includes/ast/parser.vp @@ -502,20 +502,23 @@ def _parse_or_test(ps: Parser | t.CPtr) -> AST | t.CPtr: """or_test: and_test ('or' and_test)*""" left: AST | t.CPtr = _parse_and_test(ps) if left is None: return None - # 括号内行首 or((A\n or B)):or 前的 NL 在此跳过,否则 or_test 返回后 - # 上层 _expect_op(RPar) 遇到 or 报"意外的 token 'or'" - # (CallGenMixin.vp L7918 跨模块调用检查根因;ClassGenMixin L1988 等 - # 括号内换行行首 or 同理,按解析顺序未暴露)。 - _skip_nl(ps) - if _cur_kw(ps) == Keyword.Or: - values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) - values.append(left) - while _cur_kw(ps) == Keyword.Or: - _advance(ps) - _skip_nl(ps) # 括号内跨行: a or\n b - right: AST | t.CPtr = _parse_and_test(ps) - if right is None: break - values.append(right) + values: list[AST | t.CPtr] | t.CPtr = None + while True: + # 括号内行首 or((A\n or B))与行尾 or(A or\n B)都支持: + # 每轮先 _skip_nl 再检查 or,否则 A or B\n or C 在 B 后停在 Nl 上 + # 循环退出,上层把续行 or 当非法 token(对齐 and_test / vast 实现)。 + _skip_nl(ps) + if _cur_kw(ps) != Keyword.Or: + break + if values is None: + values = list[AST | t.CPtr](ps.pool, 8) + values.append(left) + _advance(ps) + _skip_nl(ps) # 括号内跨行: a or\n b + right: AST | t.CPtr = _parse_and_test(ps) + if right is None: break + values.append(right) + if values is not None: node: AST | t.CPtr = BoolOp(ps.pool, OpKind.Or, values) _set_pos(node, left.lineno, left.col_offset, 0, 0) return node @@ -526,17 +529,24 @@ def _parse_and_test(ps: Parser | t.CPtr) -> AST | t.CPtr: """and_test: not_test ('and' not_test)*""" left: AST | t.CPtr = _parse_not_test(ps) if left is None: return None - # 括号内行首 and((A\n and B)):同 or_test 修复(or 前跳 NL) - _skip_nl(ps) - if _cur_kw(ps) == Keyword.And: - values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) - values.append(left) - while _cur_kw(ps) == Keyword.And: - _advance(ps) - _skip_nl(ps) # 括号内跨行: a and\n b - right: AST | t.CPtr = _parse_not_test(ps) - if right is None: break - values.append(right) + values: list[AST | t.CPtr] | t.CPtr = None + while True: + # 括号内行首 and((A\n and B))与行尾 and(A and\n B)都支持: + # 每轮先 _skip_nl 再检查 and,否则 A and B\n and C 在 B 后停在 + # Nl 上循环退出,上层把续行 and 当非法 token + # (ThreadingTest check 多行 and 链解析失败根因)。 + _skip_nl(ps) + if _cur_kw(ps) != Keyword.And: + break + if values is None: + values = list[AST | t.CPtr](ps.pool, 8) + values.append(left) + _advance(ps) + _skip_nl(ps) # 括号内跨行: a and\n b + right: AST | t.CPtr = _parse_not_test(ps) + if right is None: break + values.append(right) + if values is not None: node: AST | t.CPtr = BoolOp(ps.pool, OpKind.And, values) _set_pos(node, left.lineno, left.col_offset, 0, 0) return node @@ -565,6 +575,7 @@ def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr: left: AST | t.CPtr = _parse_bitor(ps) if left is None: return None + _skip_nl(ps) # 括号内行首比较运算符: (a\n < b) op_id: t.CInt = _match_comp_op(ps) if op_id == OpKind.NoneOp: return left @@ -580,6 +591,7 @@ def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr: _set_pos(first_cmp, left.lineno, left.col_offset, 0, 0) # Check chained comparison + _skip_nl(ps) # 括号内行首链式比较: (a < b\n < c) next_op: t.CInt = _match_comp_op(ps) if next_op == OpKind.NoneOp: return first_cmp @@ -600,6 +612,7 @@ def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr: _set_pos(cmp, cur_left.lineno, cur_left.col_offset, 0, 0) values.append(cmp) cur_left = cur_right + _skip_nl(ps) # 括号内行首链式比较: (a < b\n < c) next_op = _match_comp_op(ps) node: AST | t.CPtr = BoolOp(ps.pool, OpKind.And, values) _set_pos(node, left.lineno, left.col_offset, 0, 0) @@ -650,9 +663,12 @@ def _advance_comp_op(ps: Parser | t.CPtr): def _parse_bitor(ps: Parser | t.CPtr) -> AST | t.CPtr: left: AST | t.CPtr = _parse_bitxor(ps) if left is None: return None - while _match_op(ps, TokOp.VBar): + while True: + _skip_nl(ps) # 括号内行首 '|': (a\n | b) + if _match_op(ps, TokOp.VBar) == 0: + break _advance(ps) - _skip_nl(ps) + _skip_nl(ps) # 括号内跨行: a |\n b right: AST | t.CPtr = _parse_bitxor(ps) node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitOr, right) _set_pos(node, left.lineno, left.col_offset, 0, 0) @@ -663,9 +679,12 @@ def _parse_bitor(ps: Parser | t.CPtr) -> AST | t.CPtr: def _parse_bitxor(ps: Parser | t.CPtr) -> AST | t.CPtr: left: AST | t.CPtr = _parse_bitand(ps) if left is None: return None - while _match_op(ps, TokOp.Caret): + while True: + _skip_nl(ps) # 括号内行首 '^': (a\n ^ b) + if _match_op(ps, TokOp.Caret) == 0: + break _advance(ps) - _skip_nl(ps) + _skip_nl(ps) # 括号内跨行: a ^\n b right: AST | t.CPtr = _parse_bitand(ps) node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitXor, right) _set_pos(node, left.lineno, left.col_offset, 0, 0) @@ -676,9 +695,12 @@ def _parse_bitxor(ps: Parser | t.CPtr) -> AST | t.CPtr: def _parse_bitand(ps: Parser | t.CPtr) -> AST | t.CPtr: left: AST | t.CPtr = _parse_shift(ps) if left is None: return None - while _match_op(ps, TokOp.Amp): + while True: + _skip_nl(ps) # 括号内行首 '&': (a\n & b) + if _match_op(ps, TokOp.Amp) == 0: + break _advance(ps) - _skip_nl(ps) + _skip_nl(ps) # 括号内跨行: a &\n b right: AST | t.CPtr = _parse_shift(ps) node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitAnd, right) _set_pos(node, left.lineno, left.col_offset, 0, 0) @@ -689,10 +711,13 @@ def _parse_bitand(ps: Parser | t.CPtr) -> AST | t.CPtr: def _parse_shift(ps: Parser | t.CPtr) -> AST | t.CPtr: left: AST | t.CPtr = _parse_arith(ps) if left is None: return None - while _match_op(ps, TokOp.LtLt) or _match_op(ps, TokOp.GtGt): + while True: + _skip_nl(ps) # 括号内行首 '<<'/'>>': (a\n << b) + if _match_op(ps, TokOp.LtLt) == 0 and _match_op(ps, TokOp.GtGt) == 0: + break op_token: t.CInt = _cur_op(ps) _advance(ps) - _skip_nl(ps) + _skip_nl(ps) # 括号内跨行: a <<\n b right: AST | t.CPtr = _parse_arith(ps) ast_op: t.CInt = OpKind.LShift if op_token == TokOp.GtGt: @@ -706,10 +731,13 @@ def _parse_shift(ps: Parser | t.CPtr) -> AST | t.CPtr: def _parse_arith(ps: Parser | t.CPtr) -> AST | t.CPtr: left: AST | t.CPtr = _parse_term(ps) if left is None: return None - while _match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus): + while True: + _skip_nl(ps) # 括号内行首 '+'/'-': (a\n + b) + if _match_op(ps, TokOp.Plus) == 0 and _match_op(ps, TokOp.Minus) == 0: + break op_token: t.CInt = _cur_op(ps) _advance(ps) - _skip_nl(ps) + _skip_nl(ps) # 括号内跨行: a +\n b right: AST | t.CPtr = _parse_term(ps) ast_op: t.CInt = OpKind.Add if op_token == TokOp.Minus: @@ -724,6 +752,7 @@ def _parse_term(ps: Parser | t.CPtr) -> AST | t.CPtr: left: AST | t.CPtr = _parse_factor(ps) if left is None: return None while True: + _skip_nl(ps) # 括号内行首 '*'/'/'/'//'/'%'/'@': (a\n * b) op_token: t.CInt = 0 if _match_op(ps, TokOp.Star): op_token = TokOp.Star elif _match_op(ps, TokOp.Slash): op_token = TokOp.Slash @@ -732,7 +761,7 @@ def _parse_term(ps: Parser | t.CPtr) -> AST | t.CPtr: elif _match_op(ps, TokOp.At): op_token = TokOp.At if op_token == 0: break _advance(ps) - _skip_nl(ps) + _skip_nl(ps) # 括号内跨行: a *\n b right: AST | t.CPtr = _parse_factor(ps) ast_op: t.CInt = _binop_from_op(op_token) node: AST | t.CPtr = BinOp(ps.pool, left, ast_op, right)