From 63bc435723a526c573d9f05de52f95d48d7308de Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 28 Aug 2026 08:01:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(tpc):=20=E6=B3=A8=E8=A7=A3=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20C=20=E9=A3=8E=E6=A0=BC=E6=8C=87=E9=92=88=E5=90=8E?= =?UTF-8?q?=E7=BC=80=20T*=EF=BC=88int*=20=E2=86=92=20int=20|=20t.CPtr=20?= =?UTF-8?q?=E5=A4=9A=E7=BA=A7=E5=B1=95=E5=BC=80=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/ast/parser.vp | 58 ++++++++++++++++++++++++++++++++++++-- lib/core/LLVMTypeMapper.py | 52 ++++++++++++++++++---------------- lib/vast/ExprParser.py | 53 +++++++++++++++++++++++++++++++++- lib/vast/Parser.py | 10 +++---- 4 files changed, 140 insertions(+), 33 deletions(-) diff --git a/includes/ast/parser.vp b/includes/ast/parser.vp index a375bd1..7a55d99 100644 --- a/includes/ast/parser.vp +++ b/includes/ast/parser.vp @@ -1557,6 +1557,58 @@ def _parse_varargslist(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CP return Arguments(ps.pool, args, vararg, kwarg, defaults, kw_defaults) +def _parse_type_ann(ps: Parser | t.CPtr) -> AST | t.CPtr: + """解析类型注解,支持 C 风格指针后缀(* / **)。 + + int* → int | t.CPtr (i32*) + int** → (int | t.CPtr) | t.CPtr (i32**) + int****** → 6 层嵌套 (i32******) + + _parse_test 会把后缀 '*' 消费为乘法(Mult)、'**' 消费为幂(Pow), + 右操作数解析失败时产生 BinOp(op, right=None) 垃圾节点并 error_count+1 + ('int***' 形态为 BinOp(Pow, UnaryOp(Deref, None)),StarStar+Star)。 + 本函数回收该形态并恢复 error_count,再按层数嵌套构造 BinOp(BitOr, t.CPtr)。 + """ + before_ec: t.CInt = ps.error_count + base: AST | t.CPtr = _parse_test(ps) + if base is None: + return None + ptr_level: t.CInt = 0 + # 回收垃圾节点(_parse_test 对后缀 * / ** 的消费产物) + if base.kind() == ASTKind.BinOp: + gb: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(base) + if gb.op == OpKind.Mult and gb.right is None: + ptr_level += 1 + base = gb.left + elif gb.op == OpKind.Pow: + if gb.right is None: + ptr_level += 2 + base = gb.left + elif gb.right.kind() == ASTKind.UnaryOp: + gu: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(gb.right) + if gu.op == OpKind.Deref and gu.operand is None: + ptr_level += 3 + base = gb.left + if ptr_level > 0: + ps.error_count = before_ec # 回收成功,恢复错误计数避免整文件解析失败 + # 循环消费残留后缀('**' 是词法单 token 计 2 层,'*' 计 1 层) + while _match_op(ps, TokOp.StarStar): + _advance(ps) + ptr_level += 2 + while _match_op(ps, TokOp.Star): + _advance(ps) + ptr_level += 1 + # 嵌套构造 base | t.CPtr(n 层) + li_an: t.CInt = 0 + while li_an < ptr_level: + cptr_an: AST | t.CPtr = Attribute(ps.pool, + Name(ps.pool, "t", ASTCtx.Load), + "CPtr", ASTCtx.Load) + base = BinOp(ps.pool, base, OpKind.BitOr, cptr_an) + li_an += 1 + return base + + def _parse_arg_def(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CPtr: """arg: TokenType.Name [':' annotation]""" if _cur_type(ps) != TokenType.Name: @@ -1569,7 +1621,7 @@ def _parse_arg_def(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CPtr: annotation: AST | t.CPtr = None if is_lambda == 0: if _accept_op(ps, TokOp.Colon): - annotation = _parse_test(ps) + annotation = _parse_type_ann(ps) result: AST | t.CPtr = Arg(ps.pool, name_str, annotation) _set_pos(result, lineno, col, 0, 0) return result @@ -1808,7 +1860,7 @@ def _parse_expr_stmt(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr: # annassign: target ':' annotation [= value] if _match_op(ps, TokOp.Colon): _advance(ps) - annotation: AST | t.CPtr = _parse_test(ps) + annotation: AST | t.CPtr = _parse_type_ann(ps) value3: AST | t.CPtr = None if _accept_op(ps, TokOp.Equal): value3 = _parse_testlist(ps) @@ -2312,7 +2364,7 @@ def _parse_funcdef(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr: _expect_op(ps, TokOp.RPar) returns: AST | t.CPtr = None if _accept_op(ps, TokOp.RArrow): - returns = _parse_test(ps) + returns = _parse_type_ann(ps) if is_extern_fd: # extern 声明:返回注解改写为 <原类型> | t.State,复用既有 # State/外部 C 函数识别路径(vpi 注解含 "State" → 定义端裸名 + 不生成函数体) diff --git a/lib/core/LLVMTypeMapper.py b/lib/core/LLVMTypeMapper.py index 30edccf..119aa26 100644 --- a/lib/core/LLVMTypeMapper.py +++ b/lib/core/LLVMTypeMapper.py @@ -18,7 +18,7 @@ if TYPE_CHECKING: from lib.core.SymbolTable import SymbolTable from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap -from lib.core.SymbolUtils import IsTModule, IsListAnnotation +from lib.core.SymbolUtils import IsTModule, IsListAnnotation, IsCPtrNode from lib.includes import t as _t from lib.includes.t import CTypeRegistry @@ -60,17 +60,8 @@ class LLVMTypeMapper: if returns_node is None: return 'i32' if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr): - left_str: str = self.get_llvm_type_str(returns_node.left) - right_str: str = self.get_llvm_type_str(returns_node.right) - if right_str and right_str.endswith('*'): - return right_str - if left_str and left_str.endswith('*'): - return left_str - if left_str and left_str not in ('i32', 'void', 'i64'): - return left_str - if right_str and right_str not in ('i32', 'void', 'i64'): - return right_str - return left_str + # 统一走 CPtr 感知的联合解析(int | t.CPtr → i32*、str | t.CPtr → i8**) + return self._resolve_bitor(returns_node) result: str = self.get_llvm_type_str(returns_node) return result if result else 'i32' @@ -79,17 +70,8 @@ class LLVMTypeMapper: if annotation_node is None: return 'i8*' if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): - left_str: str = self.get_llvm_type_str(annotation_node.left) - right_str: str = self.get_llvm_type_str(annotation_node.right) - if right_str and right_str.endswith('*'): - return right_str - if left_str and left_str.endswith('*'): - return left_str - if right_str and right_str not in ('i32', 'void', 'i64'): - return right_str - if left_str and left_str not in ('i32', 'void', 'i64'): - return left_str - return right_str if right_str else left_str + # 统一走 CPtr 感知的联合解析 + return self._resolve_bitor(annotation_node) result: str = self.get_llvm_type_str(annotation_node) return result if result else 'i8*' @@ -279,9 +261,21 @@ class LLVMTypeMapper: return 'i32' def _resolve_bitor(self, node: ast.BinOp) -> str: - """解析 ast.BinOp(BitOr) 节点""" + """解析 ast.BinOp(BitOr) 节点(CPtr 感知的指针层级叠加)。 + + T | t.CPtr 一侧为 t.CPtr 标记时,另一侧追加一层 '*': + int | t.CPtr → i32* (原逻辑误降级为 i8*) + str | t.CPtr → i8** (原逻辑误降级为 i8*) + (int | t.CPtr) | t.CPtr → i32**(嵌套递归叠加) + """ left: str = self.get_llvm_type_str(node.left) right: str = self.get_llvm_type_str(node.right) + left_is_cptr: bool = IsCPtrNode(node.left) + right_is_cptr: bool = IsCPtrNode(node.right) + if right_is_cptr: + return self._add_pointer_level(left) + if left_is_cptr: + return self._add_pointer_level(right) if right and right.endswith('*'): return right if left and left.endswith('*'): @@ -292,6 +286,16 @@ class LLVMTypeMapper: return right return left if left else right + def _add_pointer_level(self, ty: str) -> str: + """给类型字符串追加一层指针 '*'(void/void* → i8*)。""" + if not ty: + return 'i8*' + if ty == 'void' or ty == 'void*': + return 'i8*' + if ty.endswith('*'): + return ty + '*' + return ty + '*' + def _resolve_call(self, node: ast.Call) -> str: """解析 ast.Call 节点""" if isinstance(node.func, ast.Attribute): diff --git a/lib/vast/ExprParser.py b/lib/vast/ExprParser.py index 179598b..00c8544 100644 --- a/lib/vast/ExprParser.py +++ b/lib/vast/ExprParser.py @@ -51,6 +51,9 @@ class TokenStream: # 游标移动后 Idx 变化自然失配,无需显式失效。 self._PeekCacheIdx: int = -1 self._PeekCacheTok: Token | None = None + # 类型注解解析模式:为 True 时 '*' / '**' 按 C 风格指针后缀处理 + # (int* → int | t.CPtr、int** → 嵌套两层),不按乘法/幂运算消费。 + self._InTypeAnnotation: bool = False # ------------------------------------------------------------------ # 游标操作 @@ -394,6 +397,8 @@ class ExprParserMixin(TokenStream): tok: Token = self._Peek() op_type: type | None = None if tok.Type == OP: + if self._InTypeAnnotation and tok.Value == '*': + break # 注解模式:'*' 是 C 风格指针后缀标记,不按乘法处理 op_type = {'*': N.Mult, '/': N.Div, '//': N.FloorDiv, '%': N.Mod, '@': N.MatMult}.get(tok.Value) if op_type is None: @@ -424,6 +429,8 @@ class ExprParserMixin(TokenStream): start: Token = self._Peek() base: N.expr = self._ParseAwaitPrimary() if self._AtOp('**'): + if self._InTypeAnnotation: + return base # 注解模式:'**' 是 C 风格指针后缀标记(2 层),不按幂处理 self._Next() exponent: N.expr = self._ParseFactor() # ** 右结合 node: N.BinOp = N.BinOp(left=base, op=N.Pow(), right=exponent) @@ -1471,7 +1478,51 @@ class ExprParserMixin(TokenStream): annotation: N.expr | None = None if allow_annotation and self._AtOp(':'): self._Next() - annotation = self.ParseExpr() + annotation = self._ParseTypeAnnotation() a: N.arg = N.arg(arg=start.Value, annotation=annotation, type_comment=None) self._FixLoc(a, start) return a + + def _ParseTypeAnnotation(self) -> N.expr: + """解析类型注解,支持 C 风格指针后缀(* / **)。 + + 注解模式开启后,'_ParseTerm'/'_ParsePower' 不再把 '*' / '**' 当 + 乘法/幂运算消费,而由本方法统一循环消费并展开为嵌套联合类型: + + int* → int | t.CPtr (i32*) + int** → (int | t.CPtr) | t.CPtr (i32**) + int****** → 6 层嵌套 (i32******) + + 展开为 BinOp(BitOr) 链后,TPC/TPV 现有类型解析(TypeAnnotationResolver + 的 PtrCount 相加、TPV TypeGenResolve 的递归 BinOp 分支)零改动即可 + 生成多级指针 LLVM 类型。 + """ + saved_flag: bool = self._InTypeAnnotation + self._InTypeAnnotation = True + try: + expr: N.expr = self.ParseExpr() + finally: + self._InTypeAnnotation = saved_flag + if expr is None: + return None + # 循环消费 '*' / '**' 后缀('**' 是词法单 token,计 2 层) + while True: + tok: Token = self._Peek() + if tok.Type == OP and tok.Value == '*': + self._Next() + expr = self._MakePtrType(expr, tok) + elif tok.Type == OP and tok.Value == '**': + self._Next() + expr = self._MakePtrType(expr, tok) + expr = self._MakePtrType(expr, tok) + else: + break + return expr + + def _MakePtrType(self, base: N.expr, tok: Token) -> N.expr: + """构造一层指针包装:base | t.CPtr。""" + cptr: N.expr = N.Attribute(value=N.Name(id='t', ctx=N.Load()), + attr='CPtr', ctx=N.Load()) + node: N.BinOp = N.BinOp(left=base, op=N.BitOr(), right=cptr) + self._FixLoc(node, tok) + return node diff --git a/lib/vast/Parser.py b/lib/vast/Parser.py index ea88009..d72ded2 100644 --- a/lib/vast/Parser.py +++ b/lib/vast/Parser.py @@ -259,7 +259,7 @@ class Parser(ExprParserMixin): if self._At(NAME) and self._Peek(1).Type == OP and self._Peek(1).Value == ':': name_tok: Token = self._Next() self._Next() # ':' - annotation: N.expr = self.ParseExpr() + annotation: N.expr = self._ParseTypeAnnotation() value: N.expr | None = None if self._AtOp('='): self._Next() @@ -280,7 +280,7 @@ class Parser(ExprParserMixin): return None if self._AtOp(':') and isinstance(expr, (N.Name, N.Attribute, N.Subscript)): self._Next() - annotation = self.ParseExpr() + annotation = self._ParseTypeAnnotation() value = None if self._AtOp('='): self._Next() @@ -531,7 +531,7 @@ class Parser(ExprParserMixin): returns: N.expr | None = None if self._AtOp('->'): self._Next() - returns = self.ParseExpr() + returns = self._ParseTypeAnnotation() self._ExpectOp(':') body: list[N.stmt] = self._ParseSuite() cls: type = N.AsyncFunctionDef if is_async else N.FunctionDef @@ -567,7 +567,7 @@ class Parser(ExprParserMixin): returns: N.expr | None = None if self._AtOp('->'): self._Next() - returns = self.ParseExpr() + returns = self._ParseTypeAnnotation() body: list[N.stmt] = [] if self._AtOp(':'): self._Next() @@ -612,7 +612,7 @@ class Parser(ExprParserMixin): returns: N.expr | None = None if self._AtOp('->'): self._Next() - returns = self.ParseExpr() + returns = self._ParseTypeAnnotation() body: list[N.stmt] = [] if self._AtOp(':'): self._Next()