From 3e1ed0992bb9fe3294e98ba4ce20fc2f2b7bb27c Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 5 Oct 2026 15:04:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(ast):=20=E4=BF=AE=E6=AD=A3=E5=AE=9E?= =?UTF-8?q?=E5=8F=82=E4=BD=8D=E5=89=8D=E5=AF=BC=20*=20=E7=9A=84=E4=BC=98?= =?UTF-8?q?=E5=85=88=E7=BA=A7=EF=BC=8C*p=20+=20n=20=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E4=B8=BA=20(*p)=20+=20n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 规范 rule 5 允许把 c.Deref(x) 写作 *x,但语法分析器在实参位置对前导 * 取整条表达式作为操作数:*buf + *length 被解析成 *(buf + *length),*length + data_len 成 *(length + data_len),多解引用一层。表现为 zlib decompressobj 全部失效(decompress 返回 0 字节、eof 恒 0、unused_data 取不到),requests/download 同类语句亦受影响。 改为:实参位 *expr 只按 _parse_factor 取紧绑定操作数,经新增 Parser.starred_seed 挂起,由 _parse_factor 顶部接手,再交由上层续接二元运算。*p[0](即 *(p[0]))、*p**2(即 *(p**2))等结合性保持原 C/Python 语义。 验证:全量 77/77 顺序回归一次通过;ZlibTest 内部断言由 74 passed / 6 failed 变为 79 passed / 0 failed。 --- ast/parser.vp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/ast/parser.vp b/ast/parser.vp index d38902a..40b8db0 100644 --- a/ast/parser.vp +++ b/ast/parser.vp @@ -55,6 +55,8 @@ class Parser: pool: rawptr[memhub.MemManager] # memory pool error_count: int # error count pending_decorators: rawptr[list[rawptr[AST]]] # pending decorators list + # 实参位前导 `*` 的已解析左操作数挂起槽(见 _parse_call / _parse_power)。 + starred_seed: rawptr[AST] # `static` 修饰符(软关键字)挂起标记:语句起始消费 `static`(后随变量声明 # `Name :`)后置 1,由紧随的 `_parse_type_ann` 在类型联合最左插入 t.CStatic # 标记(`static x: int = 0` → `x: t.CStatic | int = 0`),插入后立即清零, @@ -95,6 +97,7 @@ def _parser_init(ps: rawptr[Parser], tokens: rawptr[Token], ps.pool = pool ps.error_count = 0 ps.pending_decorators = None + ps.starred_seed = None ps.pending_static = 0 ps.in_class_body = 0 ps.step_count = 0 @@ -1640,6 +1643,13 @@ def _parse_term(ps: rawptr[Parser]) -> rawptr[AST]: def _parse_factor(ps: rawptr[Parser]) -> rawptr[AST]: """factor: '+' factor | '-' factor | '~' factor | '*' factor | '&' factor | power""" + # 实参位前导 `*` 已由 _parse_call 解析出紧绑定的 Starred 左操作数,直接作为本层 + # 因子返回(必须先于下面的一元判定,否则其后的二元 `+`/`-` 会被误判为一元)。 + # 上层各层随即以该左操作数续接二元运算:`*p + n` ⇒ `(*p) + n`,而非 `*(p + n)`。 + if ps.starred_seed is not None: + seed: rawptr[AST] = ps.starred_seed + ps.starred_seed = None + return seed if (_match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus) or _match_op(ps, TokOp.Tilde) or _match_op(ps, TokOp.Star) or _match_op(ps, TokOp.Amp)): op_token: int = _cur_op(ps) @@ -1755,10 +1765,19 @@ def _parse_call(ps: rawptr[Parser], func: rawptr[AST]) -> rawptr[AST]: elif _match_op(ps, TokOp.Star): _advance(ps) _skip_nls_and_newlines(ps) + # 只按一元因子取下界(保持 `*p[0]` = `*(p[0])` 的 C 结合),再挂到 + # starred_seed 上,交由 _parse_expr 续接其后二元运算:`*p + n` ⇒ + # `(*p) + n`。若整体用 _parse_expr,前导 `*` 会吞掉整条 `p + n` + # 而错解为 `*(p + n)`(zlib append_bytes 的 out 参数不回写根因)。 + seed: rawptr[AST] = _parse_factor(ps) + if seed is None: + ps.error_count += 1 + break + star: rawptr[AST] = Starred(ps.pool, seed, ASTCtx.Load) + _set_pos(star, seed.lineno, seed.col_offset, 0, 0) + ps.starred_seed = star val = _parse_expr(ps) - star: rawptr[AST] = Starred(ps.pool, val, ASTCtx.Load) - _set_pos(star, val.lineno, val.col_offset, 0, 0) - args.append(star) + args.append(val) # keyword = expr elif _cur_type(ps) == TokenType.Name: if ps.cur.next is not None and ps.cur.next.type == TokenType.Op and ps.cur.next.op_subtype == TokOp.Equal: