From a7bbd68507f2ba9f2419120bbe1ac263381dfb7e Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sun, 16 Aug 2026 11:19:16 +0800 Subject: [PATCH] =?UTF-8?q?fix(parser/lexer):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8B=AC=E5=8F=B7=E5=86=85=E8=A1=8C=E9=A6=96=20or/and=E3=80=81?= =?UTF-8?q?=E7=B1=BB=E5=9F=BA=E7=B1=BB=E8=B7=A8=E8=A1=8C=E3=80=81CRLF=20?= =?UTF-8?q?=E5=8F=8D=E6=96=9C=E6=9D=A0=E7=BB=AD=E8=A1=8C=EF=BC=88=E8=BF=BD?= =?UTF-8?q?=E5=8A=A069/70/71=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/ast/lexer.vp | 22 +++++++++++++++++----- includes/ast/parser.vp | 12 ++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/includes/ast/lexer.vp b/includes/ast/lexer.vp index 0cb88f2..2b82bb8 100644 --- a/includes/ast/lexer.vp +++ b/includes/ast/lexer.vp @@ -690,11 +690,23 @@ def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr: continue # Backslash continuation line - if ch == '\\' and lx.pos + 1 < lx.len and lx.src[lx.pos + 1] == '\n': - lx.pos += 2 - lx.lineno += 1 - lx.col = 0 - continue + # 支持 LF 与 CRLF(Windows 文件行尾):CRLF 下 `\` 后是 '\r'(非 '\n'), + # 只查 '\n' 会失效 → `\` 被当未知字符跳过、'\n' 产生 NEWLINE → 表达式 + # 中断(VpiReader.vp L324 `or \` 行尾续行根因,CRLF 文件)。 + if ch == '\\' and lx.pos + 1 < lx.len: + if lx.src[lx.pos + 1] == '\n': + lx.pos += 2 + lx.lineno += 1 + lx.col = 0 + continue + if lx.src[lx.pos + 1] == '\r': + # \ + \r\n:跳 \、\r、\n + lx.pos += 2 + if lx.pos < lx.len and lx.src[lx.pos] == '\n': + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue # Whitespace if _is_space(ch): diff --git a/includes/ast/parser.vp b/includes/ast/parser.vp index ae89787..114b96b 100644 --- a/includes/ast/parser.vp +++ b/includes/ast/parser.vp @@ -482,6 +482,11 @@ 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) @@ -501,6 +506,8 @@ 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) @@ -2277,6 +2284,10 @@ def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr: # bases / keywords if _accept_op(ps, TokOp.LPar): while not _match_op(ps, TokOp.RPar): + # 基类括号内跨行(class X(A,\n B):):逗号后换行在此跳过, + # 否则 cur=NL 非 Name/Comma → break → _expect_op(RPar) 报 + # "意外的 token"(Generator.vp L34 多继承跨行根因) + _skip_nl(ps) if _cur_type(ps) == TokenType.EndMarker: break # base 或 keyword=value if _cur_type(ps) == TokenType.Name: @@ -2291,6 +2302,7 @@ def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr: bases.append(e) if not _accept_op(ps, TokOp.Comma): break + _skip_nl(ps) # 末基类后换行收尾(class X(A,\n B):) _expect_op(ps, TokOp.RPar) _expect_op(ps, TokOp.Colon) dec_list: list[AST | t.CPtr] | t.CPtr = ps.pending_decorators