feat(tpc): 注解支持 C 风格指针后缀 T*(int* → int | t.CPtr 多级展开)
This commit is contained in:
1 parent
0230385891
commit
63bc435723
4 files changed
+140
-33
No files matched your search
+55
-3
@@ -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" → 定义端裸名 + 不生成函数体)
|
||||
|
||||
+28
-24
@@ -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):
|
||||
|
||||
+52
-1
@@ -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
|
||||
+5
-5
@@ -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()
|
||||
|
||||
Reference in new issue
Block a user