refactor(tpv): 新语法 R10 单语句块并一行(7722 处 if/for/while 单语句体)
This commit is contained in:
1 parent
f923dc4d8d
commit
4a685d478f
69 files changed
+7723
-15445
No files matched your search
@@ -26,20 +26,17 @@ def _eval_binop_valid(node: ast.AST*) -> int:
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant* = ast.Constant*(node)
|
||||
if cn.const_kind == ast.CONST_INT:
|
||||
return 1
|
||||
if cn.const_kind == ast.CONST_INT: return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop: ast.UnaryOp* = ast.UnaryOp*(node)
|
||||
if uop.operand is not None:
|
||||
return _eval_binop_valid(uop.operand)
|
||||
if uop.operand is not None: return _eval_binop_valid(uop.operand)
|
||||
return 0
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(node)
|
||||
if bop.left is not None and bop.right is not None:
|
||||
if _eval_binop_valid(bop.left) != 0:
|
||||
if _eval_binop_valid(bop.right) != 0:
|
||||
return 1
|
||||
if _eval_binop_valid(bop.right) != 0: return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
# Name 引用:检查是否是已注册的 CDefine 常量
|
||||
@@ -47,35 +44,28 @@ def _eval_binop_valid(node: ast.AST*) -> int:
|
||||
if nm.id is not None:
|
||||
# 从本地 CDefine 表查找
|
||||
val: int = _lookup_cdefine_for_pyi(nm.id)
|
||||
if _pyi_cdefine_found() != 0:
|
||||
return 1
|
||||
if _pyi_cdefine_found() != 0: return 1
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
def _eval_binop_int(node: ast.AST*) -> int64:
|
||||
"""递归计算 BinOp 节点的整数值(64 位,避免大整数 CDefine 截断)"""
|
||||
if node is None:
|
||||
return 0
|
||||
if node is None: return 0
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant* = ast.Constant*(node)
|
||||
if cn.const_kind == ast.CONST_INT:
|
||||
return cn.int_val
|
||||
if cn.const_kind == ast.CONST_INT: return cn.int_val
|
||||
return 0
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop: ast.UnaryOp* = ast.UnaryOp*(node)
|
||||
if uop.op == ast.OpKind.USub and uop.operand is not None:
|
||||
return -_eval_binop_int(uop.operand)
|
||||
if uop.op == ast.OpKind.UAdd and uop.operand is not None:
|
||||
return _eval_binop_int(uop.operand)
|
||||
if uop.op == ast.OpKind.Invert and uop.operand is not None:
|
||||
return ~_eval_binop_int(uop.operand)
|
||||
if uop.op == ast.OpKind.USub and uop.operand is not None: return -_eval_binop_int(uop.operand)
|
||||
if uop.op == ast.OpKind.UAdd and uop.operand is not None: return _eval_binop_int(uop.operand)
|
||||
if uop.op == ast.OpKind.Invert and uop.operand is not None: return ~_eval_binop_int(uop.operand)
|
||||
return 0
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(node)
|
||||
if bop.left is None or bop.right is None:
|
||||
return 0
|
||||
if bop.left is None or bop.right is None: return 0
|
||||
lv: int64 = _eval_binop_int(bop.left)
|
||||
rv: int64 = _eval_binop_int(bop.right)
|
||||
if bop.op == ast.OpKind.BitOr: return lv | rv
|
||||
@@ -92,8 +82,7 @@ def _eval_binop_int(node: ast.AST*) -> int64:
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None:
|
||||
return _lookup_cdefine_for_pyi(nm.id)
|
||||
if nm.id is not None: return _lookup_cdefine_for_pyi(nm.id)
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@@ -132,30 +121,23 @@ def _lookup_cdefine_for_pyi(name: str) -> int64:
|
||||
|
||||
def _eval_cdefine_value_cache(node: ast.AST*) -> int64:
|
||||
"""求值 CDefine 值(Constant/UnaryOp/BinOp/Call/Name),供 vpi 预处理注册缓存"""
|
||||
if node is None:
|
||||
return 0
|
||||
if node is None: return 0
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn_c: ast.Constant* = ast.Constant*(node)
|
||||
if cn_c.const_kind == ast.CONST_INT:
|
||||
return cn_c.int_val
|
||||
if cn_c.const_kind == ast.CONST_BOOL:
|
||||
return cn_c.int_val
|
||||
if cn_c.const_kind == ast.CONST_INT: return cn_c.int_val
|
||||
if cn_c.const_kind == ast.CONST_BOOL: return cn_c.int_val
|
||||
# STR/FLOAT/NONE 不参与整数 BinOp 引用(注册 0 无害)
|
||||
return 0
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
return _eval_binop_int(node)
|
||||
if k == ast.ASTKind.BinOp:
|
||||
return _eval_binop_int(node)
|
||||
if k == ast.ASTKind.UnaryOp: return _eval_binop_int(node)
|
||||
if k == ast.ASTKind.BinOp: return _eval_binop_int(node)
|
||||
if k == ast.ASTKind.Call:
|
||||
cl_c: ast.Call* = ast.Call*(node)
|
||||
if cl_c.args is not None and len(cl_c.args) > 0:
|
||||
return _eval_cdefine_value_cache(cl_c.args.get(0))
|
||||
if cl_c.args is not None and len(cl_c.args) > 0: return _eval_cdefine_value_cache(cl_c.args.get(0))
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm_c: ast.Name* = ast.Name*(node)
|
||||
if nm_c.id is not None:
|
||||
return _lookup_cdefine_for_pyi(nm_c.id)
|
||||
if nm_c.id is not None: return _lookup_cdefine_for_pyi(nm_c.id)
|
||||
return 0
|
||||
return 0
|
||||
|
||||
@@ -174,16 +156,12 @@ def _pyi_cdefine_found() -> int:
|
||||
def _PyiEmit(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
text: str) -> sizet:
|
||||
"""追加 text 到 buf 的 pos 位置,返回新的 pos"""
|
||||
if buf is None or text is None or pos >= buf_size:
|
||||
return pos
|
||||
if buf is None or text is None or pos >= buf_size: return pos
|
||||
tlen: sizet = string.strlen(text)
|
||||
if tlen == 0:
|
||||
return pos
|
||||
if tlen == 0: return pos
|
||||
remain: sizet = buf_size - pos
|
||||
if tlen >= remain:
|
||||
tlen = remain - 1
|
||||
if tlen > 0:
|
||||
string.memcpy(buf + pos, text, tlen)
|
||||
if tlen >= remain: tlen = remain - 1
|
||||
if tlen > 0: string.memcpy(buf + pos, text, tlen)
|
||||
return pos + tlen
|
||||
|
||||
|
||||
@@ -248,16 +226,14 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
if depth > 64:
|
||||
VLogger.error("vpi 类型注解递归过深(AST 环或嵌套超过 64 层)", "StubGen")
|
||||
sys.exit(1)
|
||||
if annot is None:
|
||||
return _PyiEmit(buf, buf_size, pos, "int")
|
||||
if annot is None: return _PyiEmit(buf, buf_size, pos, "int")
|
||||
|
||||
k: int = annot.kind()
|
||||
|
||||
# Name: 简单类型名 (如 int, str, MyClass)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(annot)
|
||||
if nm.id is not None:
|
||||
return _PyiEmit(buf, buf_size, pos, nm.id)
|
||||
if nm.id is not None: return _PyiEmit(buf, buf_size, pos, nm.id)
|
||||
return _PyiEmit(buf, buf_size, pos, "int")
|
||||
|
||||
# Attribute: 属性引用 (如 int, memhub.MemBuddy)
|
||||
@@ -265,8 +241,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
at: ast.Attribute* = ast.Attribute*(annot)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, at.value, depth + 1)
|
||||
pos = _PyiEmit(buf, buf_size, pos, ".")
|
||||
if at.attr is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, at.attr)
|
||||
if at.attr is not None: pos = _PyiEmit(buf, buf_size, pos, at.attr)
|
||||
return pos
|
||||
|
||||
# Subscript: 下标类型 (如 list[int], t.CArray[elem, count])
|
||||
@@ -293,12 +268,9 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
# USub → "-";其余一元运算符两侧都不支持 → fail-fast(不静默写错符号)。
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop_t: ast.UnaryOp* = ast.UnaryOp*(annot)
|
||||
if uop_t.op == ast.OpKind.Not:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "not ")
|
||||
elif uop_t.op == ast.OpKind.Invert:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "~")
|
||||
elif uop_t.op == ast.OpKind.USub:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "-")
|
||||
if uop_t.op == ast.OpKind.Not: pos = _PyiEmit(buf, buf_size, pos, "not ")
|
||||
elif uop_t.op == ast.OpKind.Invert: pos = _PyiEmit(buf, buf_size, pos, "~")
|
||||
elif uop_t.op == ast.OpKind.USub: pos = _PyiEmit(buf, buf_size, pos, "-")
|
||||
else:
|
||||
GenApi.fatal_error(annot, "vpi 类型注解节点类型未知", "TypeError")
|
||||
return pos # 不可达(fatal_error 已退出)
|
||||
@@ -326,8 +298,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
else: pos = _PyiEmit(buf, buf_size, pos, " ? ")
|
||||
# TPC 按 ops 的下标取 comparators[i];此处加长度守卫,
|
||||
# 畸形 AST(ops/comparators 不等长)不越界。
|
||||
if cmps_ct is not None and oi_ct < len(cmps_ct):
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, cmps_ct.get(oi_ct), depth + 1)
|
||||
if cmps_ct is not None and oi_ct < len(cmps_ct): pos = _PyiTypeStr(buf, buf_size, pos, cmps_ct.get(oi_ct), depth + 1)
|
||||
oi_ct += 1
|
||||
return pos
|
||||
|
||||
@@ -341,10 +312,8 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
vi_bt: sizet = 0
|
||||
while vi_bt < vn_bt:
|
||||
if vi_bt > 0:
|
||||
if bool_t.op == ast.OpKind.Or:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " or ")
|
||||
else:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " and ")
|
||||
if bool_t.op == ast.OpKind.Or: pos = _PyiEmit(buf, buf_size, pos, " or ")
|
||||
else: pos = _PyiEmit(buf, buf_size, pos, " and ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, vals_bt.get(vi_bt), depth + 1)
|
||||
vi_bt += 1
|
||||
return pos
|
||||
@@ -354,12 +323,10 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
cn: ast.Constant* = ast.Constant*(annot)
|
||||
if cn.const_kind == ast.CONST_STR:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "'")
|
||||
if cn.str_val is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, cn.str_val)
|
||||
if cn.str_val is not None: pos = _PyiEmit(buf, buf_size, pos, cn.str_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "'")
|
||||
return pos
|
||||
if cn.const_kind == ast.CONST_NONE:
|
||||
return _PyiEmit(buf, buf_size, pos, "None")
|
||||
if cn.const_kind == ast.CONST_NONE: return _PyiEmit(buf, buf_size, pos, "None")
|
||||
# 数字常量(t.CArray[uint32, 64] 的 count 等):输出数值本身,
|
||||
# 而不是回退 int——否则 vpi 生成 "t.CArray[..., int]" 在加载
|
||||
# stub 时触发 TypeError(count 必须是整数常量、None、CDefine 常量名
|
||||
@@ -385,8 +352,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
ln: sizet = len(lst_elts)
|
||||
li: sizet = 0
|
||||
while li < ln:
|
||||
if li > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if li > 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
le: ast.AST* = lst_elts.get(li)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, le, depth + 1)
|
||||
li += 1
|
||||
@@ -401,8 +367,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
tn: sizet = len(tup_elts)
|
||||
ti: sizet = 0
|
||||
while ti < tn:
|
||||
if ti > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if ti > 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
el: ast.AST* = tup_elts.get(ti)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, el, depth + 1)
|
||||
ti += 1
|
||||
@@ -418,8 +383,7 @@ def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
can: sizet = len(cl_args)
|
||||
cai: sizet = 0
|
||||
while cai < can:
|
||||
if cai > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if cai > 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
ca: ast.AST* = cl_args.get(cai)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, ca, depth + 1)
|
||||
cai += 1
|
||||
@@ -448,8 +412,7 @@ def _PyiDefaultStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
if depth > 64:
|
||||
VLogger.error("vpi 默认值表达式递归过深(AST 环或嵌套超过 64 层)", "StubGen")
|
||||
sys.exit(1)
|
||||
if node is None:
|
||||
return pos
|
||||
if node is None: return pos
|
||||
|
||||
k: int = node.kind()
|
||||
# Constant: 数字/字符串/bool/None 直接输出字面量
|
||||
@@ -464,37 +427,28 @@ def _PyiDefaultStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
return pos
|
||||
if cn.const_kind == ast.CONST_STR:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\"")
|
||||
if cn.str_val is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, cn.str_val)
|
||||
if cn.str_val is not None: pos = _PyiEmit(buf, buf_size, pos, cn.str_val)
|
||||
return _PyiEmit(buf, buf_size, pos, "\"")
|
||||
if cn.const_kind == ast.CONST_BOOL:
|
||||
if cn.int_val != 0:
|
||||
return _PyiEmit(buf, buf_size, pos, "True")
|
||||
if cn.int_val != 0: return _PyiEmit(buf, buf_size, pos, "True")
|
||||
return _PyiEmit(buf, buf_size, pos, "False")
|
||||
if cn.const_kind == ast.CONST_NONE:
|
||||
return _PyiEmit(buf, buf_size, pos, "None")
|
||||
if cn.const_kind == ast.CONST_NONE: return _PyiEmit(buf, buf_size, pos, "None")
|
||||
return pos
|
||||
|
||||
# Name: CDefine 常量名(如 share: ULONG = SHARE_READ)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None:
|
||||
return _PyiEmit(buf, buf_size, pos, nm.id)
|
||||
if nm.id is not None: return _PyiEmit(buf, buf_size, pos, nm.id)
|
||||
return pos
|
||||
|
||||
# UnaryOp: 一元运算(如 -1, ~0)
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop: ast.UnaryOp* = ast.UnaryOp*(node)
|
||||
if uop.op == ast.OpKind.USub:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "-")
|
||||
elif uop.op == ast.OpKind.UAdd:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "+")
|
||||
elif uop.op == ast.OpKind.Invert:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "~")
|
||||
else:
|
||||
return pos
|
||||
if uop.operand is not None:
|
||||
return _PyiDefaultStr(buf, buf_size, pos, uop.operand, depth + 1)
|
||||
if uop.op == ast.OpKind.USub: pos = _PyiEmit(buf, buf_size, pos, "-")
|
||||
elif uop.op == ast.OpKind.UAdd: pos = _PyiEmit(buf, buf_size, pos, "+")
|
||||
elif uop.op == ast.OpKind.Invert: pos = _PyiEmit(buf, buf_size, pos, "~")
|
||||
else: return pos
|
||||
if uop.operand is not None: return _PyiDefaultStr(buf, buf_size, pos, uop.operand, depth + 1)
|
||||
return pos
|
||||
|
||||
# 其它(BinOp 等复杂表达式):不输出,保持无默认值(fail-fast 由调用侧兜底)
|
||||
@@ -511,25 +465,20 @@ def _PyiDefaultStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
def _PyiRejectCReturnDecorator(node: ast.AST*,
|
||||
decorators: list[ast.AST*]*) -> int:
|
||||
"""装饰器列表里出现 @c.CReturn 即 fatal_error(返回 0 = 无该装饰器)"""
|
||||
if decorators is None:
|
||||
return 0
|
||||
if decorators is None: return 0
|
||||
dn: sizet = len(decorators)
|
||||
di: sizet = 0
|
||||
while di < dn:
|
||||
dnode: ast.AST* = decorators.get(di)
|
||||
di += 1
|
||||
if dnode is None:
|
||||
continue
|
||||
if dnode is None: continue
|
||||
# 兼容 @c.CReturn(...)(Call(func=Attribute))与裸 @c.CReturn(Attribute)两形态
|
||||
dattr: ast.Attribute* = None
|
||||
if dnode.kind() == ast.ASTKind.Call:
|
||||
dcall: ast.Call* = ast.Call*(dnode)
|
||||
if dcall.func is not None and dcall.func.kind() == ast.ASTKind.Attribute:
|
||||
dattr = ast.Attribute*(dcall.func)
|
||||
elif dnode.kind() == ast.ASTKind.Attribute:
|
||||
dattr = ast.Attribute*(dnode)
|
||||
if dattr is None or dattr.attr is None:
|
||||
continue
|
||||
if dcall.func is not None and dcall.func.kind() == ast.ASTKind.Attribute: dattr = ast.Attribute*(dcall.func)
|
||||
elif dnode.kind() == ast.ASTKind.Attribute: dattr = ast.Attribute*(dnode)
|
||||
if dattr is None or dattr.attr is None: continue
|
||||
if string.strcmp(dattr.attr, "CReturn") == 0:
|
||||
GenApi.fatal_error(node, "vpi 中仍带 `@c.CReturn`(已移除):请用返回注解 `-> tuple[ty1, ty2, ...]` 重新生成该 .vpi(可加 --clean)", "TypeError")
|
||||
return 1
|
||||
@@ -561,8 +510,7 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
|
||||
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "def ")
|
||||
if fn.name is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, fn.name)
|
||||
if fn.name is not None: pos = _PyiEmit(buf, buf_size, pos, fn.name)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||||
|
||||
# 参数列表
|
||||
@@ -580,16 +528,13 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
# arg_defaults 必须内联声明:联合接收者的 .get 会被误分派,预声明 + 重赋值会解析成 list[int].get 返回 i32 截断指针而崩溃。
|
||||
arg_defaults: list[ast.AST*]* = args.defaults
|
||||
dn: sizet = 0
|
||||
if arg_defaults is not None:
|
||||
dn = len(arg_defaults)
|
||||
if arg_defaults is not None: dn = len(arg_defaults)
|
||||
ai: sizet = 0
|
||||
while ai < an:
|
||||
if first == 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if first == 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
first = 0
|
||||
ag: ast.Arg* = ast.Arg*(args_args.get(ai))
|
||||
if ag.arg is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ag.arg)
|
||||
if ag.arg is not None: pos = _PyiEmit(buf, buf_size, pos, ag.arg)
|
||||
if ag.annotation is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, ag.annotation)
|
||||
@@ -603,23 +548,19 @@ def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
|
||||
# *args
|
||||
if args.vararg is not None:
|
||||
if first == 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if first == 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
first = 0
|
||||
pos = _PyiEmit(buf, buf_size, pos, "*")
|
||||
va: ast.Arg* = ast.Arg*(args.vararg)
|
||||
if va.arg is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, va.arg)
|
||||
if va.arg is not None: pos = _PyiEmit(buf, buf_size, pos, va.arg)
|
||||
|
||||
# **kwargs
|
||||
if args.kwarg is not None:
|
||||
if first == 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if first == 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
first = 0
|
||||
pos = _PyiEmit(buf, buf_size, pos, "**")
|
||||
kw: ast.Arg* = ast.Arg*(args.kwarg)
|
||||
if kw.arg is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, kw.arg)
|
||||
if kw.arg is not None: pos = _PyiEmit(buf, buf_size, pos, kw.arg)
|
||||
|
||||
pos = _PyiEmit(buf, buf_size, pos, ")")
|
||||
|
||||
@@ -662,8 +603,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
|
||||
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "class ")
|
||||
if cls.name is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, cls.name)
|
||||
if cls.name is not None: pos = _PyiEmit(buf, buf_size, pos, cls.name)
|
||||
|
||||
# PEP 695 类型参数 (class Foo[T]:)
|
||||
if cls.type_params is not None:
|
||||
@@ -682,11 +622,9 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||||
tpi: sizet = 0
|
||||
while tpi < tpn:
|
||||
if tpi > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if tpi > 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
tpname: str = cls_type_params.get(tpi)
|
||||
if tpname is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, tpname)
|
||||
if tpname is not None: pos = _PyiEmit(buf, buf_size, pos, tpname)
|
||||
tpi += 1
|
||||
pos = _PyiEmit(buf, buf_size, pos, "]")
|
||||
|
||||
@@ -698,8 +636,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||||
bi: sizet = 0
|
||||
while bi < bn:
|
||||
if bi > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if bi > 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
base: ast.AST* = cls_bases.get(bi)
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, base)
|
||||
bi += 1
|
||||
@@ -741,8 +678,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
ici += 1
|
||||
continue
|
||||
pos = _PyiIndent(buf, buf_size, pos, indent_level + 1)
|
||||
if iat.attr is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, iat.attr)
|
||||
if iat.attr is not None: pos = _PyiEmit(buf, buf_size, pos, iat.attr)
|
||||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, iaa.annotation)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
@@ -757,8 +693,7 @@ def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||||
if aa.target is not None and aa.target.kind() == ast.ASTKind.Name:
|
||||
tn: ast.Name* = ast.Name*(aa.target)
|
||||
pos = _PyiIndent(buf, buf_size, pos, indent_level + 1)
|
||||
if tn.id is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, tn.id)
|
||||
if tn.id is not None: pos = _PyiEmit(buf, buf_size, pos, tn.id)
|
||||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation)
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
@@ -789,8 +724,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
rel_path: str, buf: bytes,
|
||||
buf_size: sizet) -> sizet:
|
||||
"""从 AST 生成 .vpi 存根文件内容到 buf"""
|
||||
if tree is None or buf is None or buf_size == 0:
|
||||
return 0
|
||||
if tree is None or buf is None or buf_size == 0: return 0
|
||||
|
||||
# 错误归因:把"当前文件"指向正在生成 stub 的这份(rel_path 非 None 时)。
|
||||
# 本函数内触发的 fatal_error(如 L227/L303/L430 的注解节点类型未知)应指向
|
||||
@@ -801,8 +735,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
# 中途新增的分支;入口设一次覆盖全部(含后续所有 fatal_error / push_trace)。
|
||||
# rel_path 为 None 时不改写 CurrentFile(保持上一次设置值):调用侧确实拿不到
|
||||
# 路径时,宁可沿用"上一次设置的文件"也不要把归因抹成 None。
|
||||
if rel_path is not None:
|
||||
GenApi.set_current_file_type(rel_path)
|
||||
if rel_path is not None: GenApi.set_current_file_type(rel_path)
|
||||
|
||||
pos: sizet = 0
|
||||
|
||||
@@ -822,8 +755,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
tgt_pc0: ast.Name* = ast.Name*(aa_pc0.target)
|
||||
if tgt_pc0.id is not None and aa_pc0.annotation.kind() == ast.ASTKind.Attribute:
|
||||
ann_pc0: ast.Attribute* = ast.Attribute*(aa_pc0.annotation)
|
||||
if ann_pc0.attr is not None and string.strcmp(ann_pc0.attr, "CDefine") == 0:
|
||||
_g_pyi_cdef_count += 1
|
||||
if ann_pc0.attr is not None and string.strcmp(ann_pc0.attr, "CDefine") == 0: _g_pyi_cdef_count += 1
|
||||
if _g_pyi_cdef_count > 0:
|
||||
_g_pyi_cdef_names = (str*)(mb.alloc(sizet(_g_pyi_cdef_count) * 8))
|
||||
_g_pyi_cdef_vals = (int64*)(mb.alloc(sizet(_g_pyi_cdef_count) * 8))
|
||||
@@ -849,8 +781,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\"\"\"Auto-generated Python stub file\"\"\"\n\n")
|
||||
|
||||
if tree.children is None:
|
||||
if pos < buf_size:
|
||||
buf[pos] = 0
|
||||
if pos < buf_size: buf[pos] = 0
|
||||
return pos
|
||||
|
||||
tree_children: list[ast.AST*]* = tree.children
|
||||
@@ -869,20 +800,14 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
for ai in range(an):
|
||||
al: ast.Alias* = ast.Alias*(imp_names.get(ai))
|
||||
if al is not None and al.name is not None:
|
||||
if string.strcmp(al.name, "t") == 0:
|
||||
has_import_t = 1
|
||||
elif string.strcmp(al.name, "c") == 0:
|
||||
has_import_c = 1
|
||||
if string.strcmp(al.name, "t") == 0: has_import_t = 1
|
||||
elif string.strcmp(al.name, "c") == 0: has_import_c = 1
|
||||
|
||||
# 补充缺失的 import t/c
|
||||
if has_import_t == 0 and has_import_c == 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "import t, c\n\n")
|
||||
elif has_import_t == 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "import t\n\n")
|
||||
elif has_import_c == 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "import c\n\n")
|
||||
else:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
if has_import_t == 0 and has_import_c == 0: pos = _PyiEmit(buf, buf_size, pos, "import t, c\n\n")
|
||||
elif has_import_t == 0: pos = _PyiEmit(buf, buf_size, pos, "import t\n\n")
|
||||
elif has_import_c == 0: pos = _PyiEmit(buf, buf_size, pos, "import c\n\n")
|
||||
else: pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
|
||||
# 第二遍扫描:生成声明
|
||||
for i in range(n):
|
||||
@@ -905,8 +830,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
an2: sizet = len(imp2_names)
|
||||
ai2: sizet = 0
|
||||
while ai2 < an2:
|
||||
if ai2 > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if ai2 > 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
al2: ast.Alias* = ast.Alias*(imp2_names.get(ai2))
|
||||
# fail-fast:别名节点或其名字为空 ⇒ 绝不静默写出 "import , "。
|
||||
# vpi 里 import 行的名字是**包重导出注册的唯一输入**
|
||||
@@ -942,8 +866,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
while lvl > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ".")
|
||||
lvl -= 1
|
||||
if ifr.module is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ifr.module)
|
||||
if ifr.module is not None: pos = _PyiEmit(buf, buf_size, pos, ifr.module)
|
||||
pos = _PyiEmit(buf, buf_size, pos, " import ")
|
||||
# fail-fast:同 Import 分支——`from X import *` 走的是 Alias("*"),
|
||||
# 列表为空或名字为空都说明 AST 坏;静默写出 `from X import ` 会让
|
||||
@@ -958,8 +881,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
an3: sizet = len(ifr_names)
|
||||
ai3: sizet = 0
|
||||
while ai3 < an3:
|
||||
if ai3 > 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
if ai3 > 0: pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||
al3: ast.Alias* = ast.Alias*(ifr_names.get(ai3))
|
||||
# fail-fast:同 Import 分支(两种成因分开报,一次定位)。
|
||||
if al3 is None:
|
||||
@@ -987,8 +909,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
# 特化体按调用点单态化生成({模板SHA1}.f[args]),其签名由编译器
|
||||
# 内存中的模板表 + 实参跨模块复现(见 ClassGenGeneric.
|
||||
# _ensure_generic_func_declare),不落 vpi。
|
||||
if fn.type_params is not None:
|
||||
continue
|
||||
if fn.type_params is not None: continue
|
||||
pos = _PyiFunction(buf, buf_size, pos, fn, 0, "")
|
||||
|
||||
# 类定义
|
||||
@@ -1014,8 +935,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
if ctd_at.attr is not None and string.strcmp(ctd_at.attr, "CTypedef") == 0:
|
||||
if ctd_at.value is not None and ctd_at.value.kind() == ast.ASTKind.Name:
|
||||
ctd_mod: ast.Name* = ast.Name*(ctd_at.value)
|
||||
if ctd_mod.id is not None and string.strcmp(ctd_mod.id, "t") == 0:
|
||||
is_ctypedef_ann = 1
|
||||
if ctd_mod.id is not None and string.strcmp(ctd_mod.id, "t") == 0: is_ctypedef_ann = 1
|
||||
if is_ctypedef_ann != 0 and aa.value is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = ")
|
||||
pos = _PyiTypeStr(buf, buf_size, pos, aa.value)
|
||||
@@ -1032,10 +952,8 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
viperlib.snprintf(fbuf_c, 64, " = %.17g", cv.float_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, fbuf_c)
|
||||
elif cv.const_kind == ast.CONST_BOOL:
|
||||
if cv.int_val != 0:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = True")
|
||||
else:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = False")
|
||||
if cv.int_val != 0: pos = _PyiEmit(buf, buf_size, pos, " = True")
|
||||
else: pos = _PyiEmit(buf, buf_size, pos, " = False")
|
||||
elif cv.const_kind == ast.CONST_STR:
|
||||
# 字符串 CDefine(pyzlib.ZLIB_VERSION = "1.3.2" 等)必须输出值,让 stub 自包含(读回端按目标名判定会回退源文件)
|
||||
sbuf_c: bytes = mb.alloc(string.strlen(cv.str_val) + 6)
|
||||
@@ -1043,8 +961,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
viperlib.snprintf(sbuf_c, string.strlen(cv.str_val) + 6,
|
||||
" = \"%s\"", cv.str_val)
|
||||
pos = _PyiEmit(buf, buf_size, pos, sbuf_c)
|
||||
elif cv.const_kind == ast.CONST_NONE:
|
||||
pos = _PyiEmit(buf, buf_size, pos, " = None")
|
||||
elif cv.const_kind == ast.CONST_NONE: pos = _PyiEmit(buf, buf_size, pos, " = None")
|
||||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.UnaryOp:
|
||||
# 处理负值常量(如 INVALID_HANDLE_VALUE = -1)
|
||||
# UnaryOp(USub, Constant(1)) → -1
|
||||
@@ -1138,34 +1055,22 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||||
inferred: int = 0
|
||||
if avk == ast.ASTKind.Constant:
|
||||
acv: ast.Constant* = ast.Constant*(aval)
|
||||
if acv.const_kind == ast.CONST_INT:
|
||||
inferred = 1
|
||||
elif acv.const_kind == ast.CONST_FLOAT:
|
||||
inferred = 2
|
||||
elif acv.const_kind == ast.CONST_STR:
|
||||
inferred = 3
|
||||
elif acv.const_kind == ast.CONST_BOOL:
|
||||
inferred = 4
|
||||
elif acv.const_kind == ast.CONST_NONE:
|
||||
inferred = 5
|
||||
if acv.const_kind == ast.CONST_INT: inferred = 1
|
||||
elif acv.const_kind == ast.CONST_FLOAT: inferred = 2
|
||||
elif acv.const_kind == ast.CONST_STR: inferred = 3
|
||||
elif acv.const_kind == ast.CONST_BOOL: inferred = 4
|
||||
elif acv.const_kind == ast.CONST_NONE: inferred = 5
|
||||
if inferred > 0 and agn.id is not None:
|
||||
pos = _PyiEmit(buf, buf_size, pos, agn.id)
|
||||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||||
if inferred == 1:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "int")
|
||||
elif inferred == 2:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "double")
|
||||
elif inferred == 3:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "str")
|
||||
elif inferred == 4:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "bool")
|
||||
elif inferred == 5:
|
||||
pos = _PyiEmit(buf, buf_size, pos, "None")
|
||||
if inferred == 1: pos = _PyiEmit(buf, buf_size, pos, "int")
|
||||
elif inferred == 2: pos = _PyiEmit(buf, buf_size, pos, "double")
|
||||
elif inferred == 3: pos = _PyiEmit(buf, buf_size, pos, "str")
|
||||
elif inferred == 4: pos = _PyiEmit(buf, buf_size, pos, "bool")
|
||||
elif inferred == 5: pos = _PyiEmit(buf, buf_size, pos, "None")
|
||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||
|
||||
# NUL 终止
|
||||
if pos < buf_size:
|
||||
buf[pos] = 0
|
||||
else:
|
||||
buf[buf_size - 1] = 0
|
||||
if pos < buf_size: buf[pos] = 0
|
||||
else: buf[buf_size - 1] = 0
|
||||
return pos
|
||||
+499
-998
File diff suppressed because it is too large.
Load diff
@@ -35,16 +35,13 @@ import lib.Stub.StubMerger as StubMerger
|
||||
# ============================================================
|
||||
def _IsAppModule(mod_name: str) -> int:
|
||||
"""mod_name 是否为 App 源文件(store 命中且 incdir 为空)"""
|
||||
if mod_name is None:
|
||||
return 0
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||||
return 0
|
||||
if mod_name is None: return 0
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None: return 0
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
midx: sizet = sizet(i) * 64
|
||||
if string.strcmp(StubMerger._sha1_store_mod + midx, mod_name) == 0:
|
||||
iidx: sizet = sizet(i) * StubMerger.MAX_INC_DIR_LEN
|
||||
if StubMerger._sha1_store_incdir[iidx] == '\0':
|
||||
return 1
|
||||
if StubMerger._sha1_store_incdir[iidx] == '\0': return 1
|
||||
return 0
|
||||
return 0
|
||||
# ============================================================
|
||||
@@ -58,32 +55,25 @@ def _IsAppModule(mod_name: str) -> int:
|
||||
# ============================================================
|
||||
def _AppendDepsToWorklist(worklist: bytes, wl_len: sizet,
|
||||
deps_str: str, processed: str) -> int:
|
||||
if worklist is None or deps_str is None:
|
||||
return -1
|
||||
if worklist is None or deps_str is None: return -1
|
||||
cur_len: sizet = wl_len
|
||||
dl: sizet = string.strlen(deps_str)
|
||||
dpos: sizet = 0
|
||||
while dpos < dl:
|
||||
dstart: sizet = dpos
|
||||
while dpos < dl and deps_str[dpos] != ' ':
|
||||
dpos += 1
|
||||
while dpos < dl and deps_str[dpos] != ' ': dpos += 1
|
||||
dlen: sizet = dpos - dstart
|
||||
if dpos < dl:
|
||||
dpos += 1
|
||||
if dlen == 0:
|
||||
continue
|
||||
if dpos < dl: dpos += 1
|
||||
if dlen == 0: continue
|
||||
dmod: bytes = stdlib.malloc(dlen + 1)
|
||||
if dmod is None:
|
||||
continue
|
||||
if dmod is None: continue
|
||||
string.strncpy(dmod, deps_str + dstart, dlen)
|
||||
dmod[dlen] = '\0'
|
||||
in_wl: int = 0
|
||||
if cur_len > 0:
|
||||
if GenApi.is_module_imported(worklist, dmod) != 0:
|
||||
in_wl = 1
|
||||
if GenApi.is_module_imported(worklist, dmod) != 0: in_wl = 1
|
||||
if in_wl == 0 and processed is not None:
|
||||
if GenApi.is_module_imported(processed, dmod) != 0:
|
||||
in_wl = 1
|
||||
if GenApi.is_module_imported(processed, dmod) != 0: in_wl = 1
|
||||
if in_wl == 0:
|
||||
if cur_len + dlen + 2 < StubMerger.REACH_WORKLIST_BUF:
|
||||
if cur_len > 0 and worklist[cur_len - 1] != ' ':
|
||||
@@ -119,8 +109,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
app_deps: str = None,
|
||||
includes_dirs: str = None) -> int:
|
||||
"""构建可达 SHA1 集合(依赖图按需扫描,App 优先)"""
|
||||
if source_dir is None or temp_dir is None or reachable_set is None:
|
||||
return -1
|
||||
if source_dir is None or temp_dir is None or reachable_set is None: return -1
|
||||
if includes_dirs is None:
|
||||
VLogger.error("includes_dirs 缺失,无法按需解析依赖图", "Reachable")
|
||||
return -1
|
||||
@@ -129,8 +118,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
|
||||
# 工作列表(空格分隔的模块名)
|
||||
worklist: bytes = stdlib.malloc(StubMerger.REACH_WORKLIST_BUF)
|
||||
if worklist is None:
|
||||
return -1
|
||||
if worklist is None: return -1
|
||||
worklist[0] = '\0'
|
||||
wl_len: sizet = 0
|
||||
|
||||
@@ -142,8 +130,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
es_r: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
for e_i_r in range(scan_res_r.Count):
|
||||
e_r: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](uint64(scan_res_r.Entries) + uint64(e_i_r) * es_r)
|
||||
if e_r is None or e_r.Path is None:
|
||||
continue
|
||||
if e_r is None or e_r.Path is None: continue
|
||||
# 文件级 mark:parse 完立即回收 AST(App 全量 parse 驻留会 OOM)
|
||||
app_mark: sizet = mb.mark()
|
||||
sbuf: bytes = Utils.read_file_to_buf(e_r.Path, SRC_BUF_SIZE_R)
|
||||
@@ -186,21 +173,16 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
im_pos_a: sizet = 0
|
||||
while im_pos_a < im_len_a:
|
||||
im_start_a: sizet = im_pos_a
|
||||
while im_pos_a < im_len_a and tr._imported_modules[im_pos_a] != ' ':
|
||||
im_pos_a += 1
|
||||
while im_pos_a < im_len_a and tr._imported_modules[im_pos_a] != ' ': im_pos_a += 1
|
||||
im_mod_len: sizet = im_pos_a - im_start_a
|
||||
if im_pos_a < im_len_a:
|
||||
im_pos_a += 1
|
||||
if im_mod_len == 0:
|
||||
continue
|
||||
if im_pos_a < im_len_a: im_pos_a += 1
|
||||
if im_mod_len == 0: continue
|
||||
im_buf_a: bytes = stdlib.malloc(im_mod_len + 1)
|
||||
if im_buf_a is None:
|
||||
continue
|
||||
if im_buf_a is None: continue
|
||||
string.strncpy(im_buf_a, tr._imported_modules + im_start_a, im_mod_len)
|
||||
im_buf_a[im_mod_len] = '\0'
|
||||
in_wl_a: int = 0
|
||||
if wl_len > 0 and GenApi.is_module_imported(worklist, im_buf_a) != 0:
|
||||
in_wl_a = 1
|
||||
if wl_len > 0 and GenApi.is_module_imported(worklist, im_buf_a) != 0: in_wl_a = 1
|
||||
if in_wl_a == 0:
|
||||
if wl_len + im_mod_len + 2 < StubMerger.REACH_WORKLIST_BUF:
|
||||
if wl_len > 0:
|
||||
@@ -213,10 +195,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
worklist[wl_len] = '\0'
|
||||
stdlib.free(im_buf_a)
|
||||
# 释放 Translator 资源
|
||||
if tr._global_names is not None:
|
||||
stdlib.free(tr._global_names)
|
||||
if tr._nonlocal_names is not None:
|
||||
stdlib.free(tr._nonlocal_names)
|
||||
if tr._global_names is not None: stdlib.free(tr._global_names)
|
||||
if tr._nonlocal_names is not None: stdlib.free(tr._nonlocal_names)
|
||||
stdlib.free(sbuf)
|
||||
mb.reset_to(app_mark)
|
||||
else:
|
||||
@@ -263,12 +243,9 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
tb_inc_slot[0] = 0
|
||||
tb_found = IncludesScanner.ResolveModuleToPath(
|
||||
includes_dirs, "traceback", tb_abs, tb_rel, tb_inc)
|
||||
if tb_abs is not None:
|
||||
stdlib.free(tb_abs)
|
||||
if tb_rel is not None:
|
||||
stdlib.free(tb_rel)
|
||||
if tb_inc is not None:
|
||||
stdlib.free(tb_inc)
|
||||
if tb_abs is not None: stdlib.free(tb_abs)
|
||||
if tb_rel is not None: stdlib.free(tb_rel)
|
||||
if tb_inc is not None: stdlib.free(tb_inc)
|
||||
if tb_found != 0:
|
||||
stdlib.free(worklist)
|
||||
VLogger.error(f"--traceback: 在 includes 目录中找不到 traceback.vp,无法编译并链接 Install()(请确认 project.vpj 的 includes 包含仓库 includes 目录;已扫描: {includes_dirs})", "Traceback")
|
||||
@@ -299,19 +276,15 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
pos: sizet = wl_pos_slot[0]
|
||||
# 提取一个模块名(到空格或末尾)
|
||||
name_start: sizet = pos
|
||||
while pos < wl_len and worklist[pos] != ' ':
|
||||
pos += 1
|
||||
while pos < wl_len and worklist[pos] != ' ': pos += 1
|
||||
name_len: sizet = pos - name_start
|
||||
if pos < wl_len:
|
||||
pos += 1
|
||||
if pos < wl_len: pos += 1
|
||||
wl_pos_slot[0] = pos
|
||||
if name_len == 0:
|
||||
continue
|
||||
if name_len == 0: continue
|
||||
|
||||
# 复制模块名
|
||||
mod_buf: bytes = stdlib.malloc(name_len + 1)
|
||||
if mod_buf is None:
|
||||
continue
|
||||
if mod_buf is None: continue
|
||||
string.strncpy(mod_buf, worklist + name_start, name_len)
|
||||
mod_buf[name_len] = '\0'
|
||||
|
||||
@@ -354,12 +327,9 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
out_rel: t.CPtr = stdlib.malloc(8)
|
||||
out_inc: t.CPtr = stdlib.malloc(8)
|
||||
if out_abs is None or out_rel is None or out_inc is None:
|
||||
if out_abs is not None:
|
||||
stdlib.free(out_abs)
|
||||
if out_rel is not None:
|
||||
stdlib.free(out_rel)
|
||||
if out_inc is not None:
|
||||
stdlib.free(out_inc)
|
||||
if out_abs is not None: stdlib.free(out_abs)
|
||||
if out_rel is not None: stdlib.free(out_rel)
|
||||
if out_inc is not None: stdlib.free(out_inc)
|
||||
stdlib.free(mod_buf)
|
||||
continue
|
||||
# 输出槽防御性初始化(成功路径必全写;未找到/未命中时仅 free 槽本身)
|
||||
@@ -501,10 +471,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
stdlib.free(out_rel)
|
||||
stdlib.free(out_inc)
|
||||
stdlib.free(sbuf_r)
|
||||
if tr_r2._global_names is not None:
|
||||
stdlib.free(tr_r2._global_names)
|
||||
if tr_r2._nonlocal_names is not None:
|
||||
stdlib.free(tr_r2._nonlocal_names)
|
||||
if tr_r2._global_names is not None: stdlib.free(tr_r2._global_names)
|
||||
if tr_r2._nonlocal_names is not None: stdlib.free(tr_r2._nonlocal_names)
|
||||
stdlib.free(mod_buf)
|
||||
stdlib.free(worklist)
|
||||
stdlib.free(processed)
|
||||
@@ -525,8 +493,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
df_w: rawptr[fileio.File] = fileio.File(deps_path_w, fileio.MODE.W)
|
||||
if not df_w.closed:
|
||||
dl_w: sizet = string.strlen(deps_r2)
|
||||
if dl_w > 0:
|
||||
df_w.write(deps_r2, dl_w)
|
||||
if dl_w > 0: df_w.write(deps_r2, dl_w)
|
||||
df_w.close()
|
||||
stdlib.free(deps_path_w)
|
||||
# 追加依赖到 worklist(去重防溢出)
|
||||
@@ -546,14 +513,11 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
mb.reset_to(scan_mark_r)
|
||||
return -1
|
||||
wl_len = sizet(ret_w)
|
||||
else:
|
||||
VLogger.debug(f"无依赖: {rel_path}", "Reachable")
|
||||
else: VLogger.debug(f"无依赖: {rel_path}", "Reachable")
|
||||
|
||||
# 释放 Translator 的 C malloc 资源 + 回收本文件 AST
|
||||
if tr_r2._global_names is not None:
|
||||
stdlib.free(tr_r2._global_names)
|
||||
if tr_r2._nonlocal_names is not None:
|
||||
stdlib.free(tr_r2._nonlocal_names)
|
||||
if tr_r2._global_names is not None: stdlib.free(tr_r2._global_names)
|
||||
if tr_r2._nonlocal_names is not None: stdlib.free(tr_r2._nonlocal_names)
|
||||
stdlib.free(sbuf_r)
|
||||
mb.reset_to(scan_mark_r)
|
||||
|
||||
@@ -581,25 +545,21 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy*, source_dir: str,
|
||||
def LoadFullIR(temp_dir: str, sha1: str,
|
||||
out_buf: bytes, out_size: sizet) -> sizet:
|
||||
"""读取 {sha1}.full.ll 到 out_buf;返回长度(0=失败)"""
|
||||
if temp_dir is None or sha1 is None or out_buf is None or out_size == 0:
|
||||
return 0
|
||||
if temp_dir is None or sha1 is None or out_buf is None or out_size == 0: return 0
|
||||
td_len: sizet = string.strlen(temp_dir)
|
||||
p: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "full.ll")
|
||||
if p is None:
|
||||
return 0
|
||||
if p is None: return 0
|
||||
f: rawptr[fileio.File] = fileio.File(p, fileio.MODE.R)
|
||||
stdlib.free(p)
|
||||
out_buf[0] = '\0'
|
||||
if f.closed:
|
||||
return 0
|
||||
if f.closed: return 0
|
||||
if f.size() >= out_size:
|
||||
f.close()
|
||||
VLogger.error("full.ll 超过 IR 缓冲上限", "StubMerger")
|
||||
return 0
|
||||
rd: int64 = f.read_all(out_buf, out_size)
|
||||
f.close()
|
||||
if rd <= 0:
|
||||
return 0
|
||||
if rd <= 0: return 0
|
||||
out_buf[rd] = '\0'
|
||||
return sizet(rd)
|
||||
|
||||
@@ -620,10 +580,8 @@ def LoadDepVpiIntoModule(pool: memhub.MemBuddy*,
|
||||
temp_dir: str,
|
||||
trans: rawptr[HandlesTranslator.Translator]) -> int:
|
||||
"""加载依赖模块的 .vpi 文件,将函数声明注入到当前模块"""
|
||||
if pool is None or mod is None or temp_dir is None or trans is None:
|
||||
return 0
|
||||
if imported_modules is None:
|
||||
return 0
|
||||
if pool is None or mod is None or temp_dir is None or trans is None: return 0
|
||||
if imported_modules is None: return 0
|
||||
|
||||
# 每个模块的 stub 注入前重置 typedef 递归注册的防环标记:
|
||||
# CTypedef 表每文件隔离(translate 前 clear),visited 若跨模块残留会
|
||||
@@ -642,22 +600,17 @@ def LoadDepVpiIntoModule(pool: memhub.MemBuddy*,
|
||||
ci: sizet = 0
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
while ci < total_len and imported_modules[ci] == ' ':
|
||||
ci += 1
|
||||
if ci >= total_len:
|
||||
break
|
||||
while ci < total_len and imported_modules[ci] == ' ': ci += 1
|
||||
if ci >= total_len: break
|
||||
# 提取模块名(到下一个空格或字符串末尾)
|
||||
word_start: sizet = ci
|
||||
while ci < total_len and imported_modules[ci] != ' ':
|
||||
ci += 1
|
||||
while ci < total_len and imported_modules[ci] != ' ': ci += 1
|
||||
word_len: sizet = ci - word_start
|
||||
if word_len == 0:
|
||||
continue
|
||||
if word_len == 0: continue
|
||||
|
||||
# 复制模块名到临时缓冲区并 null 终止
|
||||
mod_nm_buf: str = stdlib.malloc(word_len + 1)
|
||||
if mod_nm_buf is None:
|
||||
continue
|
||||
if mod_nm_buf is None: continue
|
||||
string.strncpy(mod_nm_buf, imported_modules + word_start, word_len)
|
||||
mod_nm_buf[word_len] = '\0'
|
||||
|
||||
@@ -667,8 +620,7 @@ def LoadDepVpiIntoModule(pool: memhub.MemBuddy*,
|
||||
# 改名别名(import X as Y,如 HT→lib.core.Handles.HandlesTranslator):
|
||||
# 精确/包名回退均失败时从 from_imports 查别名映射再查 SHA1,
|
||||
# 否则该类模块的 vpi/stub 不注入 → 跨模块符号解析失败
|
||||
if sha1_val is None and from_imports is not None:
|
||||
sha1_val = StubMergerStore.LookupSha1ByAlias(from_imports, mod_nm_buf)
|
||||
if sha1_val is None and from_imports is not None: sha1_val = StubMergerStore.LookupSha1ByAlias(from_imports, mod_nm_buf)
|
||||
|
||||
# 如果精确查找失败,尝试包名回退(如 "ast" → "ast.__init__")
|
||||
# LookupSha1ByModName 内部已处理包名回退,此处无需重复
|
||||
@@ -684,8 +636,7 @@ def LoadDepVpiIntoModule(pool: memhub.MemBuddy*,
|
||||
# 调用 VpiReader 解析 .vpi 并注入 declare
|
||||
# (错误上下文帧由调用方 HandlesTranslator 维护)
|
||||
ret: int = VpiReader.ParseVpiIntoModule(pool, mod, vpi_path, trans)
|
||||
if ret == 1:
|
||||
success_count += 1
|
||||
if ret == 1: success_count += 1
|
||||
stdlib.free(vpi_path)
|
||||
# sha1_val 指向内部存储,无需 free
|
||||
|
||||
|
||||
@@ -44,8 +44,7 @@ def _sliced_path(temp_dir: str, td_len: sizet, sha1: str, ext: str) -> str:
|
||||
|
||||
level>0 时自动调用 ensure_dir 创建子目录。
|
||||
"""
|
||||
if temp_dir is None or sha1 is None or ext is None:
|
||||
return None
|
||||
if temp_dir is None or sha1 is None or ext is None: return None
|
||||
sha1_len: sizet = string.strlen(sha1)
|
||||
ext_len: sizet = string.strlen(ext)
|
||||
|
||||
@@ -71,13 +70,11 @@ def _sliced_path(temp_dir: str, td_len: sizet, sha1: str, ext: str) -> str:
|
||||
if sub_len > 0:
|
||||
path_len = td_len + sub_len + sha1_len + ext_len + 4
|
||||
path = stdlib.malloc(path_len)
|
||||
if path is not None:
|
||||
viperlib.snprintf(path, path_len, "%s/%s/%s.%s", temp_dir, subdir_buf, sha1, ext)
|
||||
if path is not None: viperlib.snprintf(path, path_len, "%s/%s/%s.%s", temp_dir, subdir_buf, sha1, ext)
|
||||
else:
|
||||
path_len = td_len + sha1_len + ext_len + 3
|
||||
path = stdlib.malloc(path_len)
|
||||
if path is not None:
|
||||
viperlib.snprintf(path, path_len, "%s/%s.%s", temp_dir, sha1, ext)
|
||||
if path is not None: viperlib.snprintf(path, path_len, "%s/%s.%s", temp_dir, sha1, ext)
|
||||
|
||||
return path
|
||||
|
||||
@@ -96,14 +93,11 @@ def _load_includes_sha1_set(pool: memhub.MemBuddy*,
|
||||
数据来源是 PopulateSha1MapStore 填充的全局存储器。
|
||||
sha1_set 大小为 MAX_INCLUDES_SHA1 * 17(每个 SHA1 16字符+null)
|
||||
返回找到的 includes SHA1 数量,-1 表示错误"""
|
||||
if sha1_set is None:
|
||||
return -1
|
||||
if StubMerger._sha1_store_arr is None:
|
||||
return -1
|
||||
if sha1_set is None: return -1
|
||||
if StubMerger._sha1_store_arr is None: return -1
|
||||
count: int = 0
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
if count >= StubMerger.MAX_INCLUDES_SHA1:
|
||||
break
|
||||
if count >= StubMerger.MAX_INCLUDES_SHA1: break
|
||||
idx: sizet = sizet(i) * 17
|
||||
string.strcpy(sha1_set + sizet(count) * 17, StubMerger._sha1_store_arr + idx)
|
||||
count += 1
|
||||
@@ -113,11 +107,9 @@ def _load_includes_sha1_set(pool: memhub.MemBuddy*,
|
||||
# ============================================================
|
||||
def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int:
|
||||
"""检查 sha1 是否在集合中"""
|
||||
if sha1 is None or sha1_set is None:
|
||||
return 0
|
||||
if sha1 is None or sha1_set is None: return 0
|
||||
for i in range(set_count):
|
||||
if string.strcmp(sha1_set + i * 17, sha1) == 0:
|
||||
return 1
|
||||
if string.strcmp(sha1_set + i * 17, sha1) == 0: return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt(仅人类可读的调试输出,程序内部不读取,
|
||||
@@ -134,20 +126,17 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy*, temp_dir: str,
|
||||
|
||||
若 filter_set 不为 None 且 filter_count > 0,只写入 filter_set 中的条目。
|
||||
"""
|
||||
if temp_dir is None or scan_result is None:
|
||||
return 1
|
||||
if temp_dir is None or scan_result is None: return 1
|
||||
|
||||
# 构造路径 temp_dir/_sha1_map.txt
|
||||
dir_len: sizet = string.strlen(temp_dir)
|
||||
map_path: bytes = stdlib.malloc(dir_len + 32)
|
||||
if map_path is None:
|
||||
return 1
|
||||
if map_path is None: return 1
|
||||
viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir)
|
||||
|
||||
# 打开文件写入(CREATE_ALWAYS)
|
||||
f: rawptr[fileio.File] = fileio.File(map_path, fileio.MODE.W)
|
||||
if f.closed:
|
||||
return 1
|
||||
if f.closed: return 1
|
||||
|
||||
# 写入每个 include 条目: {sha1}:includes/{rel_path}\n
|
||||
entry_size_w: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
@@ -160,12 +149,10 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy*, temp_dir: str,
|
||||
for i in range(scan_result.Count):
|
||||
ea_w: uint64 = uint64(scan_result.Entries) + i * entry_size_w
|
||||
ent_w: rawptr[IncludesScanner.FileEntry] = (rawptr[IncludesScanner.FileEntry])(ea_w)
|
||||
if ent_w is None or ent_w.Sha1 is None or ent_w.RelPath is None:
|
||||
continue
|
||||
if ent_w is None or ent_w.Sha1 is None or ent_w.RelPath is None: continue
|
||||
# 若提供过滤集合,只写入集合中的条目
|
||||
if filter_set is not None and filter_count > 0:
|
||||
if _is_in_sha1_set(ent_w.Sha1, filter_set, filter_count) == 0:
|
||||
continue
|
||||
if _is_in_sha1_set(ent_w.Sha1, filter_set, filter_count) == 0: continue
|
||||
viperlib.snprintf(line_buf, 512, "%s:includes/%s\n", ent_w.Sha1, ent_w.RelPath)
|
||||
line_len_w: sizet = string.strlen(line_buf)
|
||||
f.write(line_buf, line_len_w)
|
||||
|
||||
@@ -76,8 +76,7 @@ def WriteModuleMeta(mod: mlirlite.LLVMModule*, temp_dir: str,
|
||||
VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
break
|
||||
mark: str = "DECL"
|
||||
if mlirlite.function_is_declared(cur) == 0:
|
||||
mark = "DEF"
|
||||
if mlirlite.function_is_declared(cur) == 0: mark = "DEF"
|
||||
viperlib.snprintf(line, nlen + 16, "FUNC %s %s\n", nm, mark)
|
||||
mf.write(line, string.strlen(line))
|
||||
stdlib.free(line)
|
||||
@@ -98,10 +97,8 @@ def WriteModuleMeta(mod: mlirlite.LLVMModule*, temp_dir: str,
|
||||
VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
break
|
||||
fc: int = mlirlite.get_struct_fcount(nt.Ty)
|
||||
if fc < 0:
|
||||
viperlib.snprintf(lb, tl + 48, "STRUCT %s OPAQUE\n", tn)
|
||||
else:
|
||||
viperlib.snprintf(lb, tl + 48, "STRUCT %s FIELDS %d PACKED %d\n", tn, fc, nt.IsPacked)
|
||||
if fc < 0: viperlib.snprintf(lb, tl + 48, "STRUCT %s OPAQUE\n", tn)
|
||||
else: viperlib.snprintf(lb, tl + 48, "STRUCT %s FIELDS %d PACKED %d\n", tn, fc, nt.IsPacked)
|
||||
mf.write(lb, string.strlen(lb))
|
||||
stdlib.free(lb)
|
||||
nt = nt.Next
|
||||
@@ -123,11 +120,9 @@ def WriteModuleMeta(mod: mlirlite.LLVMModule*, temp_dir: str,
|
||||
string.strncpy(base, gn, base_len)
|
||||
base[base_len] = '\0'
|
||||
ar: int = mlirlite.get_struct_fcount(gv.Ty)
|
||||
if ar < 0:
|
||||
ar = 0
|
||||
if ar < 0: ar = 0
|
||||
lb2: bytes = stdlib.malloc(base_len + 40)
|
||||
if lb2 is None:
|
||||
VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
if lb2 is None: VLogger.error("meta 写出:行缓冲分配失败", "Meta")
|
||||
else:
|
||||
viperlib.snprintf(lb2, base_len + 40, "VTABLE %s SLOTS %d\n", base, ar)
|
||||
mf.write(lb2, string.strlen(lb2))
|
||||
@@ -146,41 +141,32 @@ def WriteModuleMeta(mod: mlirlite.LLVMModule*, temp_dir: str,
|
||||
# ============================================================
|
||||
def _MetaHasDef(temp_dir: str, td_len: sizet, sha1: str) -> int:
|
||||
"""读 {sha1}.meta:含 "FUNC ... DEF" 行返回 1,无则 0,文件不可读 -1"""
|
||||
if temp_dir is None or sha1 is None:
|
||||
return -1
|
||||
if temp_dir is None or sha1 is None: return -1
|
||||
mpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "meta")
|
||||
if mpath is None:
|
||||
return -1
|
||||
if mpath is None: return -1
|
||||
mf: fileio.File = fileio.File(mpath, fileio.MODE.R)
|
||||
stdlib.free(mpath)
|
||||
if mf.closed:
|
||||
return -1
|
||||
if mf.closed: return -1
|
||||
mbuf: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
|
||||
mbr: int64 = 0
|
||||
if mbuf is not None:
|
||||
mbr = mf.read_all(mbuf, StubMerger.STUB_READ_BUF_SIZE)
|
||||
if mbuf is not None: mbr = mf.read_all(mbuf, StubMerger.STUB_READ_BUF_SIZE)
|
||||
mf.close()
|
||||
if mbuf is None:
|
||||
return -1
|
||||
if mbuf is None: return -1
|
||||
if mbr <= 0:
|
||||
# 空 meta:无 DEF,纯声明
|
||||
stdlib.free(mbuf)
|
||||
return 0
|
||||
if mbr < StubMerger.STUB_READ_BUF_SIZE:
|
||||
mbuf[mbr] = '\0'
|
||||
if mbr < StubMerger.STUB_READ_BUF_SIZE: mbuf[mbr] = '\0'
|
||||
# 逐行扫描:行尾 " DEF" 即为实现文件
|
||||
mpos: sizet = 0
|
||||
while mpos < mbr:
|
||||
mls: sizet = mpos
|
||||
while mpos < mbr:
|
||||
if mbuf[mpos] == '\n':
|
||||
break
|
||||
if mbuf[mpos] == '\n': break
|
||||
mpos += 1
|
||||
mll: sizet = mpos - mls
|
||||
if mpos < mbr:
|
||||
mpos += 1
|
||||
if mll > 0 and mbuf[mls + mll - 1] == '\r':
|
||||
mll -= 1
|
||||
if mpos < mbr: mpos += 1
|
||||
if mll > 0 and mbuf[mls + mll - 1] == '\r': mll -= 1
|
||||
if mll >= 10 and string.strncmp(mbuf + mls, "FUNC ", 5) == 0:
|
||||
if mbuf[mls + mll - 4] == ' ' and string.strncmp(mbuf + mls + mll - 3, "DEF", 3) == 0:
|
||||
stdlib.free(mbuf)
|
||||
@@ -199,10 +185,8 @@ def _MetaHasDef(temp_dir: str, td_len: sizet, sha1: str) -> int:
|
||||
def IsDeclOnlyModule(temp_dir: str, td_len: sizet, sha1: str) -> int:
|
||||
"""判断模块是否为纯声明文件(meta 无 FUNC ... DEF 行)"""
|
||||
h: int = _MetaHasDef(temp_dir, td_len, sha1)
|
||||
if h < 0:
|
||||
return -1
|
||||
if h == 1:
|
||||
return 0
|
||||
if h < 0: return -1
|
||||
if h == 1: return 0
|
||||
return 1
|
||||
# ============================================================
|
||||
# _is_submodule_of_imported - 检查模块名是否是已导入包的子模块
|
||||
@@ -212,15 +196,12 @@ def IsDeclOnlyModule(temp_dir: str, td_len: sizet, sha1: str) -> int:
|
||||
# ============================================================
|
||||
def _is_submodule_of_imported(deps_buf: str, mod_name: str) -> int:
|
||||
"""检查 mod_name 是否是 deps_buf 中已导入包的子模块"""
|
||||
if deps_buf is None or mod_name is None:
|
||||
return 0
|
||||
if deps_buf is None or mod_name is None: return 0
|
||||
# 查找第一个 '.',提取顶层包名
|
||||
dot_pos: str = string.strchr(mod_name, 46) # '.' = 46
|
||||
if dot_pos is None:
|
||||
return 0
|
||||
if dot_pos is None: return 0
|
||||
pkg_len: sizet = sizet(uint64(dot_pos) - uint64(mod_name))
|
||||
if pkg_len == 0 or pkg_len >= 256:
|
||||
return 0
|
||||
if pkg_len == 0 or pkg_len >= 256: return 0
|
||||
# 构造顶层包名(截断到 '.' 之前)
|
||||
# 直接在 mod_name 上临时截断检查,避免分配
|
||||
saved_ch: char = mod_name[pkg_len]
|
||||
@@ -243,14 +224,11 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: sizet,
|
||||
temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。
|
||||
数据来源是 PopulateSha1MapStore 填充的全局存储器。
|
||||
"""
|
||||
if sha1_list is None or mod_list is None:
|
||||
return 0
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||||
return 0
|
||||
if sha1_list is None or mod_list is None: return 0
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None: return 0
|
||||
count: int = 0
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
if count >= StubMerger.MAX_INCLUDES:
|
||||
break
|
||||
if count >= StubMerger.MAX_INCLUDES: break
|
||||
idx: sizet = sizet(i) * 17
|
||||
idx2: sizet = sizet(i) * 64
|
||||
string.strcpy(sha1_list + sizet(count) * 17, StubMerger._sha1_store_arr + idx)
|
||||
@@ -270,10 +248,8 @@ def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
|
||||
精确匹配失败时,尝试 "{mod_name}.__init__" 回退,
|
||||
支持 import ast(包)→ ast.__init__ 的 SHA1 查找。
|
||||
"""
|
||||
if sha1_arr is None or mod_arr is None or mod_name is None:
|
||||
return None
|
||||
if count <= 0:
|
||||
return None
|
||||
if sha1_arr is None or mod_arr is None or mod_name is None: return None
|
||||
if count <= 0: return None
|
||||
# 第一遍:精确匹配
|
||||
for i in range(count):
|
||||
idx: sizet = sizet(i) * 64
|
||||
@@ -303,12 +279,10 @@ def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
|
||||
# ============================================================
|
||||
def _AddSha1ToSet(set_buf: str, count: int, sha1: str) -> int:
|
||||
"""将 SHA1 加入集合,返回新 count"""
|
||||
if set_buf is None or sha1 is None:
|
||||
return count
|
||||
if set_buf is None or sha1 is None: return count
|
||||
for i in range(count):
|
||||
idx: sizet = sizet(i) * 17
|
||||
if string.strcmp(set_buf + idx, sha1) == 0:
|
||||
return count
|
||||
if string.strcmp(set_buf + idx, sha1) == 0: return count
|
||||
if count < StubMerger.MAX_INCLUDES_SHA1:
|
||||
idx: sizet = sizet(count) * 17
|
||||
string.strcpy(set_buf + idx, sha1)
|
||||
|
||||
@@ -57,13 +57,11 @@ class ImportCtx:
|
||||
# ============================================================
|
||||
def AppendImportedModule(pool: memhub.MemBuddy*, cur: str, name: str) -> str:
|
||||
"""追加模块名到空格分隔列表(pool 分配),返回新列表"""
|
||||
if name is None:
|
||||
return cur
|
||||
if name is None: return cur
|
||||
if cur is None:
|
||||
nlen: sizet = string.strlen(name)
|
||||
buf: str = pool.alloc(nlen + 1)
|
||||
if buf is not None:
|
||||
string.strcpy(buf, name)
|
||||
if buf is not None: string.strcpy(buf, name)
|
||||
return buf
|
||||
old_len: sizet = string.strlen(cur)
|
||||
name_len: sizet = string.strlen(name)
|
||||
@@ -85,8 +83,7 @@ def AppendImportedModule(pool: memhub.MemBuddy*, cur: str, name: str) -> str:
|
||||
def AppendFromImport(pool: memhub.MemBuddy*, cur: str,
|
||||
local: str, mod: str, orig: str) -> str:
|
||||
"""追加 from-import 映射(pool 分配),返回新列表"""
|
||||
if local is None or mod is None:
|
||||
return cur
|
||||
if local is None or mod is None: return cur
|
||||
llen: sizet = string.strlen(local)
|
||||
mlen: sizet = string.strlen(mod)
|
||||
use_orig: int = 0
|
||||
@@ -96,19 +93,16 @@ def AppendFromImport(pool: memhub.MemBuddy*, cur: str,
|
||||
olen = string.strlen(orig)
|
||||
# local ':' mod [':' orig] '\0'
|
||||
need: sizet = llen + 1 + mlen + 1
|
||||
if use_orig != 0:
|
||||
need += 1 + olen
|
||||
if use_orig != 0: need += 1 + olen
|
||||
entry: str = pool.alloc(need)
|
||||
if entry is None:
|
||||
return cur
|
||||
if entry is None: return cur
|
||||
string.strcpy(entry, local)
|
||||
entry[llen] = ':'
|
||||
string.strcpy(entry + llen + 1, mod)
|
||||
if use_orig != 0:
|
||||
entry[llen + 1 + mlen] = ':'
|
||||
string.strcpy(entry + llen + 1 + mlen + 1, orig)
|
||||
if cur is None:
|
||||
return entry
|
||||
if cur is None: return entry
|
||||
old_len: sizet = string.strlen(cur)
|
||||
entry_len: sizet = string.strlen(entry)
|
||||
buf: str = pool.alloc(old_len + 1 + entry_len + 1)
|
||||
@@ -126,8 +120,7 @@ def AllocImportCtx(pool: memhub.MemBuddy*,
|
||||
imported_modules: str, from_imports: str) -> ImportCtx*:
|
||||
"""构造导入上下文容器(pool 分配);两串可为 None"""
|
||||
ctx: ImportCtx* = pool.alloc(ImportCtx.__sizeof__())
|
||||
if ctx is None:
|
||||
return None
|
||||
if ctx is None: return None
|
||||
ctx.ImportedModules = imported_modules
|
||||
ctx.FromImports = from_imports
|
||||
return ctx
|
||||
@@ -144,8 +137,7 @@ def AllocImportCtx(pool: memhub.MemBuddy*,
|
||||
def NotePlainImport(pool: memhub.MemBuddy*, ctx: ImportCtx*,
|
||||
name: str, asname: str) -> int:
|
||||
"""记账单条 import(就地更新 ctx),返回 0"""
|
||||
if ctx is None or name is None:
|
||||
return 1
|
||||
if ctx is None or name is None: return 1
|
||||
ctx.ImportedModules = AppendImportedModule(pool, ctx.ImportedModules, name)
|
||||
if asname is not None:
|
||||
ctx.ImportedModules = AppendImportedModule(pool, ctx.ImportedModules, asname)
|
||||
@@ -178,23 +170,17 @@ def PopulateSha1MapStore(scan_result: rawptr[IncludesScanner.ScanResult]) -> int
|
||||
模块名通过 _PathToModuleName(includes/rel_path) 计算。
|
||||
内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||||
"""
|
||||
if scan_result is None:
|
||||
return -1
|
||||
if scan_result is None: return -1
|
||||
# 释放旧存储器
|
||||
if StubMerger._sha1_store_arr is not None:
|
||||
stdlib.free(StubMerger._sha1_store_arr)
|
||||
if StubMerger._sha1_store_mod is not None:
|
||||
stdlib.free(StubMerger._sha1_store_mod)
|
||||
if StubMerger._sha1_store_rel is not None:
|
||||
stdlib.free(StubMerger._sha1_store_rel)
|
||||
if StubMerger._sha1_store_incdir is not None:
|
||||
stdlib.free(StubMerger._sha1_store_incdir)
|
||||
if StubMerger._sha1_store_arr is not None: stdlib.free(StubMerger._sha1_store_arr)
|
||||
if StubMerger._sha1_store_mod is not None: stdlib.free(StubMerger._sha1_store_mod)
|
||||
if StubMerger._sha1_store_rel is not None: stdlib.free(StubMerger._sha1_store_rel)
|
||||
if StubMerger._sha1_store_incdir is not None: stdlib.free(StubMerger._sha1_store_incdir)
|
||||
StubMerger._sha1_store_arr = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||||
StubMerger._sha1_store_mod = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||||
StubMerger._sha1_store_rel = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||||
StubMerger._sha1_store_incdir = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None:
|
||||
return -1
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None: return -1
|
||||
string.memset(StubMerger._sha1_store_arr, 0, StubMerger.MAX_INCLUDES * 17)
|
||||
string.memset(StubMerger._sha1_store_mod, 0, StubMerger.MAX_INCLUDES * 64)
|
||||
string.memset(StubMerger._sha1_store_rel, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||||
@@ -203,8 +189,7 @@ def PopulateSha1MapStore(scan_result: rawptr[IncludesScanner.ScanResult]) -> int
|
||||
p_bad: int = 0
|
||||
entry_size_p: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
for i in range(scan_result.Count):
|
||||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES:
|
||||
VLogger.error("includes SHA1 存储超上限,终止", "StubMerger")
|
||||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES: VLogger.error("includes SHA1 存储超上限,终止", "StubMerger")
|
||||
ea: uint64 = uint64(scan_result.Entries) + i * entry_size_p
|
||||
ent: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](ea)
|
||||
if ent is None or ent.Sha1 is None or ent.RelPath is None:
|
||||
@@ -224,16 +209,14 @@ def PopulateSha1MapStore(scan_result: rawptr[IncludesScanner.ScanResult]) -> int
|
||||
string.strcpy(StubMerger._sha1_store_arr + idx, ent.Sha1)
|
||||
idx2: sizet = sizet(StubMerger._sha1_store_count) * 64
|
||||
mn_len: sizet = string.strlen(mod_name)
|
||||
if mn_len < 64:
|
||||
string.strcpy(StubMerger._sha1_store_mod + idx2, mod_name)
|
||||
if mn_len < 64: string.strcpy(StubMerger._sha1_store_mod + idx2, mod_name)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_mod + idx2, mod_name, 63)
|
||||
StubMerger._sha1_store_mod[idx2 + 63] = '\0'
|
||||
stdlib.free(mod_name)
|
||||
# 保存 rel_path(供 Phase2 3.5 编译缺失 includes 使用)
|
||||
idx3: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_REL_PATH_LEN
|
||||
if rp_len < StubMerger.MAX_REL_PATH_LEN:
|
||||
string.strcpy(StubMerger._sha1_store_rel + idx3, ent.RelPath)
|
||||
if rp_len < StubMerger.MAX_REL_PATH_LEN: string.strcpy(StubMerger._sha1_store_rel + idx3, ent.RelPath)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_rel + idx3, ent.RelPath, StubMerger.MAX_REL_PATH_LEN - 1)
|
||||
StubMerger._sha1_store_rel[idx3 + StubMerger.MAX_REL_PATH_LEN - 1] = '\0'
|
||||
@@ -241,14 +224,12 @@ def PopulateSha1MapStore(scan_result: rawptr[IncludesScanner.ScanResult]) -> int
|
||||
idx_inc: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||||
if ent.IncDir is not None:
|
||||
icd_len: sizet = string.strlen(ent.IncDir)
|
||||
if icd_len < StubMerger.MAX_INC_DIR_LEN:
|
||||
string.strcpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir)
|
||||
if icd_len < StubMerger.MAX_INC_DIR_LEN: string.strcpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir, StubMerger.MAX_INC_DIR_LEN - 1)
|
||||
StubMerger._sha1_store_incdir[idx_inc + StubMerger.MAX_INC_DIR_LEN - 1] = '\0'
|
||||
StubMerger._sha1_store_count += 1
|
||||
if p_bad > 0:
|
||||
VLogger.error(f"includes SHA1 存储有 {p_bad} 个条目失败", "StubMerger")
|
||||
if p_bad > 0: VLogger.error(f"includes SHA1 存储有 {p_bad} 个条目失败", "StubMerger")
|
||||
return StubMerger._sha1_store_count
|
||||
# ============================================================
|
||||
# AppendToSha1MapStore - 追加 App 模块条目到全局 SHA1 映射存储器(Phase1 先用 PopulateSha1MapStore 填 includes,
|
||||
@@ -260,32 +241,27 @@ def PopulateSha1MapStore(scan_result: rawptr[IncludesScanner.ScanResult]) -> int
|
||||
# ============================================================
|
||||
def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
"""追加条目到全局 SHA1 映射存储器(Phase2 用)"""
|
||||
if sha1 is None or rel_path is None:
|
||||
return 1
|
||||
if sha1 is None or rel_path is None: return 1
|
||||
# 存储器未初始化:自动初始化(Phase2 可能先于 Phase1 调用)
|
||||
if StubMerger._sha1_store_arr is None:
|
||||
StubMerger._sha1_store_arr = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||||
StubMerger._sha1_store_mod = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||||
StubMerger._sha1_store_rel = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||||
StubMerger._sha1_store_incdir = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None:
|
||||
return 1
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None: return 1
|
||||
string.memset(StubMerger._sha1_store_arr, 0, StubMerger.MAX_INCLUDES * 17)
|
||||
string.memset(StubMerger._sha1_store_mod, 0, StubMerger.MAX_INCLUDES * 64)
|
||||
string.memset(StubMerger._sha1_store_rel, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||||
string.memset(StubMerger._sha1_store_incdir, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||||
StubMerger._sha1_store_count = 0
|
||||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES:
|
||||
return 1
|
||||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES: return 1
|
||||
# 模块名:rel_path "lib/core/StubMerger.vp" → "lib.core.StubMerger"
|
||||
full_path_buf: bytes = stdlib.malloc(string.strlen(rel_path) + 10)
|
||||
if full_path_buf is None:
|
||||
return 1
|
||||
if full_path_buf is None: return 1
|
||||
viperlib.snprintf(full_path_buf, string.strlen(rel_path) + 10, "includes/%s", rel_path)
|
||||
mod_name: str = Utils.PathToModuleName(full_path_buf, 1)
|
||||
stdlib.free(full_path_buf)
|
||||
if mod_name is None:
|
||||
return 1
|
||||
if mod_name is None: return 1
|
||||
# 去重:SHA1 与模块名都相同才跳过——同一 SHA1 可能先以全路径模块名注册(App 源文件在 includes 目录下),
|
||||
# App 追加的短模块名必须保留,否则 import 该模块的精确查找失败、后缀匹配会劫持到其它同名模块。
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
@@ -301,8 +277,7 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
# 写入模块名
|
||||
idx_m: sizet = sizet(StubMerger._sha1_store_count) * 64
|
||||
mn_len: sizet = string.strlen(mod_name)
|
||||
if mn_len < 64:
|
||||
string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name)
|
||||
if mn_len < 64: string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_mod + idx_m, mod_name, 63)
|
||||
StubMerger._sha1_store_mod[idx_m + 63] = '\0'
|
||||
@@ -310,8 +285,7 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
# 写入相对路径
|
||||
idx_r: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_REL_PATH_LEN
|
||||
rp_len: sizet = string.strlen(rel_path)
|
||||
if rp_len < StubMerger.MAX_REL_PATH_LEN:
|
||||
string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path)
|
||||
if rp_len < StubMerger.MAX_REL_PATH_LEN: string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_rel + idx_r, rel_path, StubMerger.MAX_REL_PATH_LEN - 1)
|
||||
StubMerger._sha1_store_rel[idx_r + StubMerger.MAX_REL_PATH_LEN - 1] = '\0'
|
||||
@@ -330,46 +304,40 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
# ============================================================
|
||||
def AddIncludeToSha1MapStore(sha1: str, rel_path: str, inc_dir: str, mod_name: str) -> int:
|
||||
"""单条登记 includes 条目到全局 SHA1 映射存储器(依赖图按需扫描用)"""
|
||||
if sha1 is None or rel_path is None or mod_name is None:
|
||||
return 1
|
||||
if sha1 is None or rel_path is None or mod_name is None: return 1
|
||||
# 存储器未初始化:自动初始化
|
||||
if StubMerger._sha1_store_arr is None:
|
||||
StubMerger._sha1_store_arr = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||||
StubMerger._sha1_store_mod = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||||
StubMerger._sha1_store_rel = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||||
StubMerger._sha1_store_incdir = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None:
|
||||
return 1
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None: return 1
|
||||
string.memset(StubMerger._sha1_store_arr, 0, StubMerger.MAX_INCLUDES * 17)
|
||||
string.memset(StubMerger._sha1_store_mod, 0, StubMerger.MAX_INCLUDES * 64)
|
||||
string.memset(StubMerger._sha1_store_rel, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_REL_PATH_LEN)
|
||||
string.memset(StubMerger._sha1_store_incdir, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||||
StubMerger._sha1_store_count = 0
|
||||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES:
|
||||
return 1
|
||||
if StubMerger._sha1_store_count >= StubMerger.MAX_INCLUDES: return 1
|
||||
# 去重:SHA1 与模块名都相同才跳过(对齐 AppendToSha1MapStore)
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
sidx_d: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0:
|
||||
midx_d: sizet = sizet(i) * 64
|
||||
if string.strcmp(StubMerger._sha1_store_mod + midx_d, mod_name) == 0:
|
||||
return 0
|
||||
if string.strcmp(StubMerger._sha1_store_mod + midx_d, mod_name) == 0: return 0
|
||||
# 写 SHA1
|
||||
idx_a: sizet = sizet(StubMerger._sha1_store_count) * 17
|
||||
string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1)
|
||||
# 写模块名
|
||||
idx_m: sizet = sizet(StubMerger._sha1_store_count) * 64
|
||||
mn_len: sizet = string.strlen(mod_name)
|
||||
if mn_len < 64:
|
||||
string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name)
|
||||
if mn_len < 64: string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_mod + idx_m, mod_name, 63)
|
||||
StubMerger._sha1_store_mod[idx_m + 63] = '\0'
|
||||
# 写相对路径
|
||||
idx_r: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_REL_PATH_LEN
|
||||
rp_len: sizet = string.strlen(rel_path)
|
||||
if rp_len < StubMerger.MAX_REL_PATH_LEN:
|
||||
string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path)
|
||||
if rp_len < StubMerger.MAX_REL_PATH_LEN: string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_rel + idx_r, rel_path, StubMerger.MAX_REL_PATH_LEN - 1)
|
||||
StubMerger._sha1_store_rel[idx_r + StubMerger.MAX_REL_PATH_LEN - 1] = '\0'
|
||||
@@ -377,13 +345,11 @@ def AddIncludeToSha1MapStore(sha1: str, rel_path: str, inc_dir: str, mod_name: s
|
||||
idx_inc: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||||
if inc_dir is not None:
|
||||
icd_len: sizet = string.strlen(inc_dir)
|
||||
if icd_len < StubMerger.MAX_INC_DIR_LEN:
|
||||
string.strcpy(StubMerger._sha1_store_incdir + idx_inc, inc_dir)
|
||||
if icd_len < StubMerger.MAX_INC_DIR_LEN: string.strcpy(StubMerger._sha1_store_incdir + idx_inc, inc_dir)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_incdir + idx_inc, inc_dir, StubMerger.MAX_INC_DIR_LEN - 1)
|
||||
StubMerger._sha1_store_incdir[idx_inc + StubMerger.MAX_INC_DIR_LEN - 1] = '\0'
|
||||
else:
|
||||
StubMerger._sha1_store_incdir[idx_inc] = '\0'
|
||||
else: StubMerger._sha1_store_incdir[idx_inc] = '\0'
|
||||
StubMerger._sha1_store_count += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
@@ -446,26 +412,21 @@ def RegisterGenericOwner(cls_name: str, mod_sha1: str) -> int:
|
||||
同名异 sha1(跨模块同名泛型类)保留首个,与泛型模板表按类名去重的口径一致。
|
||||
"""
|
||||
global _generic_owner_names, _generic_owner_sha1s, _generic_owner_count
|
||||
if cls_name is None or mod_sha1 is None:
|
||||
return 0
|
||||
if cls_name[0] == '\0' or mod_sha1[0] == '\0':
|
||||
return 0
|
||||
if cls_name is None or mod_sha1 is None: return 0
|
||||
if cls_name[0] == '\0' or mod_sha1[0] == '\0': return 0
|
||||
if _generic_owner_names is None:
|
||||
_generic_owner_names = stdlib.malloc(GENERIC_OWNER_MAX * 64)
|
||||
_generic_owner_sha1s = stdlib.malloc(GENERIC_OWNER_MAX * 17)
|
||||
if _generic_owner_names is None or _generic_owner_sha1s is None:
|
||||
return 0
|
||||
if _generic_owner_names is None or _generic_owner_sha1s is None: return 0
|
||||
string.memset(_generic_owner_names, 0, GENERIC_OWNER_MAX * 64)
|
||||
string.memset(_generic_owner_sha1s, 0, GENERIC_OWNER_MAX * 17)
|
||||
_generic_owner_count = 0
|
||||
i_go: int
|
||||
for i_go in range(_generic_owner_count):
|
||||
if string.strcmp(_generic_owner_names + sizet(i_go) * 64, cls_name) == 0:
|
||||
if string.strcmp(_generic_owner_sha1s + sizet(i_go) * 17, mod_sha1) == 0:
|
||||
return 1
|
||||
if string.strcmp(_generic_owner_sha1s + sizet(i_go) * 17, mod_sha1) == 0: return 1
|
||||
return 0
|
||||
if _generic_owner_count >= GENERIC_OWNER_MAX:
|
||||
return 0
|
||||
if _generic_owner_count >= GENERIC_OWNER_MAX: return 0
|
||||
string.strncpy(_generic_owner_names + sizet(_generic_owner_count) * 64, cls_name, 63)
|
||||
string.strncpy(_generic_owner_sha1s + sizet(_generic_owner_count) * 17, mod_sha1, 16)
|
||||
_generic_owner_count += 1
|
||||
@@ -474,12 +435,10 @@ def RegisterGenericOwner(cls_name: str, mod_sha1: str) -> int:
|
||||
|
||||
def LookupGenericOwnerSha1(cls_name: str) -> str:
|
||||
"""按泛型类名取定义模块 SHA1(返回内部指针,无需释放;未登记 None)"""
|
||||
if cls_name is None or _generic_owner_names is None:
|
||||
return None
|
||||
if cls_name is None or _generic_owner_names is None: return None
|
||||
i_lg: int
|
||||
for i_lg in range(_generic_owner_count):
|
||||
if string.strcmp(_generic_owner_names + sizet(i_lg) * 64, cls_name) == 0:
|
||||
return _generic_owner_sha1s + sizet(i_lg) * 17
|
||||
if string.strcmp(_generic_owner_names + sizet(i_lg) * 64, cls_name) == 0: return _generic_owner_sha1s + sizet(i_lg) * 17
|
||||
return None
|
||||
# ============================================================
|
||||
# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1(用于 from .X import Y:impf.module 是 ".X",而映射表键是 "pkg.X")
|
||||
@@ -489,22 +448,17 @@ def LookupGenericOwnerSha1(cls_name: str) -> str:
|
||||
# ============================================================
|
||||
def LookupSha1ByModNameSuffix(mod_suffix: str) -> str:
|
||||
"""后缀匹配查找模块 SHA1"""
|
||||
if mod_suffix is None:
|
||||
return None
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||||
return None
|
||||
if StubMerger._sha1_store_count <= 0:
|
||||
return None
|
||||
if mod_suffix is None: return None
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None: return None
|
||||
if StubMerger._sha1_store_count <= 0: return None
|
||||
suffix_len_sf: sizet = string.strlen(mod_suffix)
|
||||
if suffix_len_sf == 0:
|
||||
return None
|
||||
if suffix_len_sf == 0: return None
|
||||
i_sf: int
|
||||
for i_sf in range(StubMerger._sha1_store_count):
|
||||
idx_sf: sizet = sizet(i_sf) * 64
|
||||
mod_name_sf: str = StubMerger._sha1_store_mod + idx_sf
|
||||
mod_len_sf: sizet = string.strlen(mod_name_sf)
|
||||
if mod_len_sf == 0:
|
||||
continue
|
||||
if mod_len_sf == 0: continue
|
||||
# 精确匹配
|
||||
if mod_len_sf == suffix_len_sf:
|
||||
if string.strcmp(mod_name_sf, mod_suffix) == 0:
|
||||
@@ -534,23 +488,18 @@ def LookupSha1ByModNameSuffix(mod_suffix: str) -> str:
|
||||
# ============================================================
|
||||
def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||||
"""从 from_imports 别名映射解析模块 SHA1(改名别名 import X as Y 场景)"""
|
||||
if from_imports is None or alias is None:
|
||||
return None
|
||||
if from_imports is None or alias is None: return None
|
||||
alias_len: sizet = string.strlen(alias)
|
||||
if alias_len == 0:
|
||||
return None
|
||||
if alias_len == 0: return None
|
||||
total_len: sizet = string.strlen(from_imports)
|
||||
ci: sizet = 0
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
while ci < total_len and from_imports[ci] == ' ':
|
||||
ci += 1
|
||||
if ci >= total_len:
|
||||
break
|
||||
while ci < total_len and from_imports[ci] == ' ': ci += 1
|
||||
if ci >= total_len: break
|
||||
# 条目起点 ci,找 ':'(local_name 结束)
|
||||
colon: sizet = ci
|
||||
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ':
|
||||
colon += 1
|
||||
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ': colon += 1
|
||||
local_len: sizet = colon - ci
|
||||
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
|
||||
# 比较 local_name == alias
|
||||
@@ -565,8 +514,7 @@ def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||||
# 提取 module(colon+1 到下一个 ':' 或空格)
|
||||
m_start: sizet = colon + 1
|
||||
m_end: sizet = m_start
|
||||
while m_end < total_len and from_imports[m_end] != ':' and from_imports[m_end] != ' ':
|
||||
m_end += 1
|
||||
while m_end < total_len and from_imports[m_end] != ':' and from_imports[m_end] != ' ': m_end += 1
|
||||
if m_end > m_start:
|
||||
mbuf: str = stdlib.malloc(m_end - m_start + 1)
|
||||
if mbuf is not None:
|
||||
@@ -577,8 +525,7 @@ def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||||
return res
|
||||
return None
|
||||
# 跳到下一条目
|
||||
while ci < total_len and from_imports[ci] != ' ':
|
||||
ci += 1
|
||||
while ci < total_len and from_imports[ci] != ' ': ci += 1
|
||||
return None
|
||||
# ============================================================
|
||||
# LookupModNameByAlias - 从 from_imports 别名映射解析模块真名
|
||||
@@ -589,23 +536,18 @@ def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||||
# ============================================================
|
||||
def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||||
"""从 from_imports 别名映射解析模块真名(import X as Y → Y:X)"""
|
||||
if from_imports is None or alias is None:
|
||||
return None
|
||||
if from_imports is None or alias is None: return None
|
||||
alias_len: sizet = string.strlen(alias)
|
||||
if alias_len == 0:
|
||||
return None
|
||||
if alias_len == 0: return None
|
||||
total_len: sizet = string.strlen(from_imports)
|
||||
ci: sizet = 0
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
while ci < total_len and from_imports[ci] == ' ':
|
||||
ci += 1
|
||||
if ci >= total_len:
|
||||
break
|
||||
while ci < total_len and from_imports[ci] == ' ': ci += 1
|
||||
if ci >= total_len: break
|
||||
# 条目起点 ci,找 ':'(local_name 结束)
|
||||
colon: sizet = ci
|
||||
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ':
|
||||
colon += 1
|
||||
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ': colon += 1
|
||||
local_len: sizet = colon - ci
|
||||
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
|
||||
# 比较 local_name == alias
|
||||
@@ -620,8 +562,7 @@ def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||||
# 提取 module(colon+1 到下一个 ':' 或空格)
|
||||
m_start: sizet = colon + 1
|
||||
m_end: sizet = m_start
|
||||
while m_end < total_len and from_imports[m_end] != ':' and from_imports[m_end] != ' ':
|
||||
m_end += 1
|
||||
while m_end < total_len and from_imports[m_end] != ':' and from_imports[m_end] != ' ': m_end += 1
|
||||
if m_end > m_start:
|
||||
mbuf: str = stdlib.malloc(m_end - m_start + 1)
|
||||
if mbuf is not None:
|
||||
@@ -630,8 +571,7 @@ def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||||
return mbuf
|
||||
return None
|
||||
# 跳到下一条目
|
||||
while ci < total_len and from_imports[ci] != ' ':
|
||||
ci += 1
|
||||
while ci < total_len and from_imports[ci] != ' ': ci += 1
|
||||
return None
|
||||
# ============================================================
|
||||
# PopulateIncludesDeps - 将 includes 文件的依赖存入内存
|
||||
@@ -642,24 +582,20 @@ def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||||
# ============================================================
|
||||
def PopulateIncludesDeps(sha1: str, deps_str: str) -> int:
|
||||
"""将 includes 文件的依赖存入内存"""
|
||||
if sha1 is None:
|
||||
return 1
|
||||
if sha1 is None: return 1
|
||||
# 延迟初始化
|
||||
if StubMerger._includes_deps_sha1 is None:
|
||||
StubMerger._includes_deps_sha1 = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||||
StubMerger._includes_deps_str = stdlib.malloc(StubMerger.MAX_INCLUDES * StubMerger.MAX_DEPS_STR_LEN)
|
||||
if StubMerger._includes_deps_sha1 is None or StubMerger._includes_deps_str is None:
|
||||
return 1
|
||||
if StubMerger._includes_deps_sha1 is None or StubMerger._includes_deps_str is None: return 1
|
||||
string.memset(StubMerger._includes_deps_sha1, 0, StubMerger.MAX_INCLUDES * 17)
|
||||
string.memset(StubMerger._includes_deps_str, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_DEPS_STR_LEN)
|
||||
StubMerger._includes_deps_count = 0
|
||||
if StubMerger._includes_deps_count >= StubMerger.MAX_INCLUDES:
|
||||
return 1
|
||||
if StubMerger._includes_deps_count >= StubMerger.MAX_INCLUDES: return 1
|
||||
# 去重:若 SHA1 已存在则跳过
|
||||
for i in range(StubMerger._includes_deps_count):
|
||||
sidx: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
|
||||
return 0
|
||||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0: return 0
|
||||
# 写入 SHA1
|
||||
idx: sizet = sizet(StubMerger._includes_deps_count) * 17
|
||||
string.strcpy(StubMerger._includes_deps_sha1 + idx, sha1)
|
||||
@@ -667,12 +603,9 @@ def PopulateIncludesDeps(sha1: str, deps_str: str) -> int:
|
||||
idx2: sizet = sizet(StubMerger._includes_deps_count) * StubMerger.MAX_DEPS_STR_LEN
|
||||
if deps_str is not None:
|
||||
dl: sizet = string.strlen(deps_str)
|
||||
if dl < StubMerger.MAX_DEPS_STR_LEN:
|
||||
string.strcpy(StubMerger._includes_deps_str + idx2, deps_str)
|
||||
else:
|
||||
string.strncpy(StubMerger._includes_deps_str + idx2, deps_str, StubMerger.MAX_DEPS_STR_LEN - 1)
|
||||
else:
|
||||
StubMerger._includes_deps_str[idx2] = '\0'
|
||||
if dl < StubMerger.MAX_DEPS_STR_LEN: string.strcpy(StubMerger._includes_deps_str + idx2, deps_str)
|
||||
else: string.strncpy(StubMerger._includes_deps_str + idx2, deps_str, StubMerger.MAX_DEPS_STR_LEN - 1)
|
||||
else: StubMerger._includes_deps_str[idx2] = '\0'
|
||||
StubMerger._includes_deps_count = StubMerger._includes_deps_count + 1
|
||||
return 0
|
||||
# ============================================================
|
||||
@@ -686,10 +619,8 @@ def PopulateIncludesDeps(sha1: str, deps_str: str) -> int:
|
||||
# ============================================================
|
||||
def LookupIncludesDeps(sha1: str) -> str:
|
||||
"""从内存查找 includes 文件的依赖"""
|
||||
if sha1 is None or StubMerger._includes_deps_sha1 is None:
|
||||
return None
|
||||
if StubMerger._includes_deps_count <= 0:
|
||||
return None
|
||||
if sha1 is None or StubMerger._includes_deps_sha1 is None: return None
|
||||
if StubMerger._includes_deps_count <= 0: return None
|
||||
for i in range(StubMerger._includes_deps_count):
|
||||
sidx: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
|
||||
@@ -721,19 +652,14 @@ def GetSha1StoreArr(out_sha1_arr: rawptr[t.CPtr], out_mod_arr: rawptr[t.CPtr], o
|
||||
out_sha1_arr/out_mod_arr/out_rel_arr 是调用者提供的 t.CPtr 槽的地址(t.CPtr*),
|
||||
函数把存储器数组指针写入这些槽。返回条目数,-1 失败
|
||||
"""
|
||||
if out_sha1_arr is None or out_mod_arr is None or out_rel_arr is None:
|
||||
return -1
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None:
|
||||
return -1
|
||||
if out_sha1_arr is None or out_mod_arr is None or out_rel_arr is None: return -1
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None: return -1
|
||||
sp: rawptr[t.CPtr] = out_sha1_arr
|
||||
if sp is not None:
|
||||
sp[0] = StubMerger._sha1_store_arr
|
||||
if sp is not None: sp[0] = StubMerger._sha1_store_arr
|
||||
mp: rawptr[t.CPtr] = out_mod_arr
|
||||
if mp is not None:
|
||||
mp[0] = StubMerger._sha1_store_mod
|
||||
if mp is not None: mp[0] = StubMerger._sha1_store_mod
|
||||
rp: rawptr[t.CPtr] = out_rel_arr
|
||||
if rp is not None:
|
||||
rp[0] = StubMerger._sha1_store_rel
|
||||
if rp is not None: rp[0] = StubMerger._sha1_store_rel
|
||||
return StubMerger._sha1_store_count
|
||||
|
||||
# ============================================================
|
||||
@@ -745,10 +671,8 @@ def GetSha1StoreArr(out_sha1_arr: rawptr[t.CPtr], out_mod_arr: rawptr[t.CPtr], o
|
||||
# ============================================================
|
||||
def LookupSha1RelPath(sha1: str) -> str:
|
||||
"""通过 SHA1 查找相对路径,返回只读指针,None=未找到"""
|
||||
if sha1 is None:
|
||||
return None
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_rel is None:
|
||||
return None
|
||||
if sha1 is None: return None
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_rel is None: return None
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
sidx: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._sha1_store_arr + sidx, sha1) == 0:
|
||||
@@ -776,10 +700,8 @@ def LookupSha1RelPath(sha1: str) -> str:
|
||||
# ============================================================
|
||||
def LookupModNameBySha1(sha1: str) -> str:
|
||||
"""通过 SHA1 查找模块名,返回只读指针,None=未找到"""
|
||||
if sha1 is None or sha1[0] == '\0':
|
||||
return None
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||||
return None
|
||||
if sha1 is None or sha1[0] == '\0': return None
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None: return None
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
sidx_mb: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._sha1_store_arr + sidx_mb, sha1) == 0:
|
||||
|
||||
@@ -46,18 +46,14 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
reachable_count: int,
|
||||
sorted_idx: sizet*) -> int:
|
||||
"""对可达 includes 逆拓扑排序(被依赖者先),store 索引写入 sorted_idx"""
|
||||
if store_count <= 0 or store_sha1_arr is None or store_mod_arr is None or sorted_idx is None:
|
||||
return 0
|
||||
if store_count <= 0 or store_sha1_arr is None or store_mod_arr is None or sorted_idx is None: return 0
|
||||
indegree: sizet* = (sizet*)(stdlib.malloc(8 * (store_count + 1)))
|
||||
queue: sizet* = (sizet*)(stdlib.malloc(8 * (store_count + 1)))
|
||||
rel_idx: sizet* = (sizet*)(stdlib.malloc(8 * (store_count + 1)))
|
||||
if indegree is None or queue is None or rel_idx is None:
|
||||
if indegree is not None:
|
||||
stdlib.free(indegree)
|
||||
if queue is not None:
|
||||
stdlib.free(queue)
|
||||
if rel_idx is not None:
|
||||
stdlib.free(rel_idx)
|
||||
if indegree is not None: stdlib.free(indegree)
|
||||
if queue is not None: stdlib.free(queue)
|
||||
if rel_idx is not None: stdlib.free(rel_idx)
|
||||
return 0
|
||||
# 清零 indegree/queue/rel_idx(malloc 返回未初始化内存,Kahn 依赖入度初值 0)
|
||||
zi: int = 0
|
||||
@@ -82,22 +78,17 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
for i_r in range(rel_count):
|
||||
si: int = rel_idx[i_r]
|
||||
deps_si: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + sizet(si) * 17)
|
||||
if deps_si is None:
|
||||
continue
|
||||
if deps_si is None: continue
|
||||
dl_si: sizet = string.strlen(deps_si)
|
||||
dpos: sizet = 0
|
||||
while dpos < dl_si:
|
||||
dstart: sizet = dpos
|
||||
while dpos < dl_si and deps_si[dpos] != ' ':
|
||||
dpos += 1
|
||||
while dpos < dl_si and deps_si[dpos] != ' ': dpos += 1
|
||||
dlen: sizet = dpos - dstart
|
||||
if dpos < dl_si:
|
||||
dpos += 1
|
||||
if dlen == 0:
|
||||
continue
|
||||
if dpos < dl_si: dpos += 1
|
||||
if dlen == 0: continue
|
||||
dname_buf: bytes = stdlib.malloc(dlen + 1)
|
||||
if dname_buf is None:
|
||||
continue
|
||||
if dname_buf is None: continue
|
||||
string.strncpy(dname_buf, deps_si + dstart, dlen)
|
||||
dname_buf[dlen] = '\0'
|
||||
dsha1: str = StubMergerIR._FindSha1ByModName(store_sha1_arr, store_mod_arr, store_count, dname_buf)
|
||||
@@ -127,25 +118,19 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
mod_m_len: sizet = string.strlen(mod_m)
|
||||
for i_r in range(rel_count):
|
||||
si3: int = rel_idx[i_r]
|
||||
if indegree[si3] == 0:
|
||||
continue
|
||||
if indegree[si3] == 0: continue
|
||||
deps_si3: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + sizet(si3) * 17)
|
||||
if deps_si3 is None:
|
||||
continue
|
||||
if deps_si3 is None: continue
|
||||
dl_si3: sizet = string.strlen(deps_si3)
|
||||
dpos3: sizet = 0
|
||||
found_dep: int = 0
|
||||
while dpos3 < dl_si3 and found_dep == 0:
|
||||
dstart3: sizet = dpos3
|
||||
while dpos3 < dl_si3 and deps_si3[dpos3] != ' ':
|
||||
dpos3 += 1
|
||||
while dpos3 < dl_si3 and deps_si3[dpos3] != ' ': dpos3 += 1
|
||||
dlen3: sizet = dpos3 - dstart3
|
||||
if dpos3 < dl_si3:
|
||||
dpos3 += 1
|
||||
if dlen3 == 0:
|
||||
continue
|
||||
if dlen3 == mod_m_len and string.strncmp(deps_si3 + dstart3, mod_m, mod_m_len) == 0:
|
||||
found_dep = 1
|
||||
if dpos3 < dl_si3: dpos3 += 1
|
||||
if dlen3 == 0: continue
|
||||
if dlen3 == mod_m_len and string.strncmp(deps_si3 + dstart3, mod_m, mod_m_len) == 0: found_dep = 1
|
||||
if found_dep == 1:
|
||||
# 中间 int 变量递减:绕过联合类型指针算术编译 bug
|
||||
indg3: int = indegree[si3]
|
||||
|
||||
Reference in new issue
Block a user