Compare commits
286
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15b416b527 | ||
|
|
2c33effee1 | ||
|
|
4958fd2c14 | ||
|
|
87e2356eea | ||
|
|
c0d3231e02 | ||
|
|
d1c0f6754c | ||
|
|
01e95b51cf | ||
|
|
1ad7abf33d | ||
|
|
7e82ed6940 | ||
|
|
1d1efc6288 | ||
|
|
f865986675 | ||
|
|
981af07d5c | ||
|
|
57f8c655c8 | ||
|
|
acd6c9a615 | ||
|
|
3b8a2b225f | ||
|
|
96c110242e | ||
|
|
9994d2e983 | ||
|
|
b91dfef777 | ||
|
|
c3f554f1f5 | ||
|
|
3ccc37ca3f | ||
|
|
02b9429363 | ||
|
|
be14fa5f94 | ||
|
|
2f6db41b11 | ||
|
|
59865b2a3a | ||
|
|
e0bcf4bcef | ||
|
|
21d5cd1cd1 | ||
|
|
a714ec9d37 | ||
|
|
8e3811c490 | ||
|
|
93e983f74e | ||
|
|
0a81e67e89 | ||
|
|
f748cae562 | ||
|
|
dc4e06d88b | ||
|
|
d979cc8c1f | ||
|
|
25c1c9875b | ||
|
|
2bfcb6ef6e | ||
|
|
455c7608b1 | ||
|
|
875a9beb08 | ||
|
|
660427f759 | ||
|
|
3329c9beae | ||
|
|
f2f3e5b7bf | ||
|
|
79f044bc47 | ||
|
|
7b0c05b70b | ||
|
|
0f6e102e02 | ||
|
|
b289e93650 | ||
|
|
2b2b70e636 | ||
|
|
83baf5a4b6 | ||
|
|
f3c708613f | ||
|
|
849001ae9e | ||
|
|
a92b38e826 | ||
|
|
1cce6c4a47 | ||
|
|
2a798dd643 | ||
|
|
ef4421db20 | ||
|
|
d63787f8fc | ||
|
|
0e5ebd07ba | ||
|
|
6a287b955e | ||
|
|
c1a22411ca | ||
|
|
e1bb42fade | ||
|
|
31f341cf6f | ||
|
|
df1244d6f4 | ||
|
|
bbd0cdbf62 | ||
|
|
1b2324edab | ||
|
|
2b8cc2a69b | ||
|
|
868d48ae22 | ||
|
|
dddaba3254 | ||
|
|
65d7f7cc31 | ||
|
|
8e7d7feb57 | ||
|
|
c2d7480f3d | ||
|
|
07f2f2e9fc | ||
|
|
1f93550b6d | ||
|
|
a9e4aafae1 | ||
|
|
fddadf9d56 | ||
|
|
aa52cf157d | ||
|
|
13080f646f | ||
|
|
75ea6fb9b2 | ||
|
|
af5fba81c5 | ||
|
|
825fe6d326 | ||
|
|
d579d70113 | ||
|
|
70448f4590 | ||
|
|
29acf97dbc | ||
|
|
eb1065f387 | ||
|
|
23428b63a5 | ||
|
|
4807012bd8 | ||
|
|
9c427aa548 | ||
|
|
3bed3a70a6 | ||
|
|
be1acdb602 | ||
|
|
e2c4c7645e | ||
|
|
f03aea15c7 | ||
|
|
ee50ce61fe | ||
|
|
59a9fc5b1f | ||
|
|
dfae2f090c | ||
|
|
d06c4d2c0e | ||
|
|
f2d7b748ea | ||
|
|
5e100e2195 | ||
|
|
a79e723e8d | ||
|
|
bb864dff6f | ||
|
|
31898ab4a5 | ||
|
|
66e697e8df | ||
|
|
d82f24e17a | ||
|
|
e65f04f16b | ||
|
|
0279965074 | ||
|
|
beccb36b66 | ||
|
|
4255ab9d32 | ||
|
|
72a3c483e4 | ||
|
|
ca5473304f | ||
|
|
12bd7b7a16 | ||
|
|
dd56580855 | ||
|
|
424dbd7379 | ||
|
|
87f5b1026c | ||
|
|
9455db0eec | ||
|
|
a76cf55a2d | ||
|
|
c387926977 | ||
|
|
7c53a8744d | ||
|
|
cf815b17de | ||
|
|
7d28c9649e | ||
|
|
f084da7c01 | ||
|
|
78fc7313fb | ||
|
|
f0309e4904 | ||
|
|
bcf66edebe | ||
|
|
373a20c3e5 | ||
|
|
676c19c362 | ||
|
|
a7af34bd7e | ||
|
|
951b89be36 | ||
|
|
a5ceb3d4eb | ||
|
|
9910e05760 | ||
|
|
9e2ccbfab7 | ||
|
|
eb01a45024 | ||
|
|
cb0836de8a | ||
|
|
9a191daa8d | ||
|
|
7cba4cbc95 | ||
|
|
b28f20cce7 | ||
|
|
429de97083 | ||
|
|
a83d183abb | ||
|
|
31b8dccffd | ||
|
|
de86a1ed70 | ||
|
|
296f6a739e | ||
|
|
617d4ea911 | ||
|
|
5a59432733 | ||
|
|
6394ea30e2 | ||
|
|
b27633c86e | ||
|
|
813f0157e3 | ||
|
|
592400a1ea | ||
|
|
8312e653e8 | ||
|
|
31df298341 | ||
|
|
60100fa6af | ||
|
|
c1859a111c | ||
|
|
05d5bfbf37 | ||
|
|
82f16127c0 | ||
|
|
785741026f | ||
|
|
51daf28297 | ||
|
|
7fabf886fc | ||
|
|
a46391bf42 | ||
|
|
b918321f77 | ||
|
|
ce612c8e57 | ||
|
|
4ed7f3909a | ||
|
|
e7f47735ed | ||
|
|
cb430bf00a | ||
|
|
e8db102b9e | ||
|
|
16472a61d9 | ||
|
|
a9819e4123 | ||
|
|
76df3f0225 | ||
|
|
0dd7511a9b | ||
|
|
af2c66e7d7 | ||
|
|
eef84657a1 | ||
|
|
e0e024ee93 | ||
|
|
ea2abba574 | ||
|
|
17f109e204 | ||
|
|
626f79cbd1 | ||
|
|
3c45895878 | ||
|
|
590a6a2bbe | ||
|
|
b206e7d9c1 | ||
|
|
ced50bd78b | ||
|
|
967095df5b | ||
|
|
7e68e76ec4 | ||
|
|
471bedbcf4 | ||
|
|
82eea2719f | ||
|
|
7471cc64f9 | ||
|
|
679758c05b | ||
|
|
cc17a8f8db | ||
|
|
7fbf69ae63 | ||
|
|
1039969f69 | ||
|
|
ae63f4f6ab | ||
|
|
19fca19ca7 | ||
|
|
41c5908c5e | ||
|
|
db8220801c | ||
|
|
cc3359faea | ||
|
|
22c71388d4 | ||
|
|
a4bc5dc0ce | ||
|
|
e55ec5fde0 | ||
|
|
9e461d21cb | ||
|
|
95133d8483 | ||
|
|
8aad248c25 | ||
|
|
029a423f55 | ||
|
|
7028399366 | ||
|
|
7fedf8daad | ||
|
|
0a108e6289 | ||
|
|
a173ba0296 | ||
|
|
0e973d5f23 | ||
|
|
ff7caa57e8 | ||
|
|
f0deff931d | ||
|
|
b7100e9dc1 | ||
|
|
b1090abe70 | ||
|
|
b8470c1cae | ||
|
|
c71642dca0 | ||
|
|
cfb92e5da5 | ||
|
|
4ce55e3ea3 | ||
|
|
d3690f9143 | ||
|
|
e66d9e3adb | ||
|
|
751fbccb29 | ||
|
|
f5ee178407 | ||
|
|
e20a6f3d11 | ||
|
|
bd46b47b22 | ||
|
|
a5260f4441 | ||
|
|
76f03b5987 | ||
|
|
adfd202218 | ||
|
|
1d76280d0e | ||
|
|
bb9bb76653 | ||
|
|
7611d10072 | ||
|
|
3e4f3b88b0 | ||
|
|
82558bd86b | ||
|
|
709c3570fb | ||
|
|
ab814f55e6 | ||
|
|
a260b9316d | ||
|
|
1146719de1 | ||
|
|
4496738a24 | ||
|
|
bcedb15b23 | ||
|
|
41ed7176e9 | ||
|
|
ed373a3ef2 | ||
|
|
6b368b46a7 | ||
|
|
c35246f426 | ||
|
|
50d53d3ce6 | ||
|
|
8dda9f7c2d | ||
|
|
75db09e18a | ||
|
|
131f3a9a4d | ||
|
|
178ea401b7 | ||
|
|
c7c37e1007 | ||
|
|
60deee1d17 | ||
|
|
29667672e4 | ||
|
|
9b46e1da78 | ||
|
|
d14415a4e6 | ||
|
|
a0d6dced00 | ||
|
|
4db68ff5c4 | ||
|
|
23e7f5b1fb | ||
|
|
fa4c69f95d | ||
|
|
c2b9a26c62 | ||
|
|
1fe7878074 | ||
|
|
2b2c242d14 | ||
|
|
efc8f7948f | ||
|
|
b7eeb504ee | ||
|
|
a99db2a29b | ||
|
|
58d61badcb | ||
|
|
8d0241e0c3 | ||
|
|
9af7b2ead4 | ||
|
|
d3bdfd5205 | ||
|
|
25363120f8 | ||
|
|
99ddff2d87 | ||
|
|
0a84ca8db3 | ||
|
|
7b81e3c7cf | ||
|
|
6540e27844 | ||
|
|
20ba8e0297 | ||
|
|
0b0cf5ba66 | ||
|
|
f75a4d795a | ||
|
|
9e72393a11 | ||
|
|
ec4fb0bcf8 | ||
|
|
98efd9b1d2 | ||
|
|
8a69719acf | ||
|
|
fa90586a83 | ||
|
|
2610f361fd | ||
|
|
4415f1f38b | ||
|
|
4748915472 | ||
|
|
5551db3432 | ||
|
|
85e7011b6c | ||
|
|
8445af93d2 | ||
|
|
27ba74c720 | ||
|
|
a8eb7fe5fe | ||
|
|
24ae2dc966 | ||
|
|
d99b6268de | ||
|
|
b3a4be21d3 | ||
|
|
19171ee165 | ||
|
|
6daec5fa58 | ||
|
|
d971bae7cd | ||
|
|
54462320d2 | ||
|
|
c542442987 | ||
|
|
ce62546e90 | ||
|
|
907f7892f9 | ||
|
|
c54e87bd6d | ||
|
|
a603736f64 |
No files matched your search
@@ -10,6 +10,7 @@ __pycache__/
|
||||
# 构建产物(防御性)
|
||||
**/output/
|
||||
**/temp/
|
||||
**/output_dbg/
|
||||
**/*.deps.json
|
||||
**/*.doc.json
|
||||
**/*.pyi
|
||||
|
||||
+1451
-294
File diff suppressed because it is too large.
Load diff
+653
-522
File diff suppressed because it is too large.
Load diff
+158
-165
@@ -11,8 +11,7 @@ import w32.win32base
|
||||
import ast
|
||||
import llvmlite
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Gen.Translator as HandlesTranslator
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Gen.Generator as GenGenerator
|
||||
@@ -33,10 +32,9 @@ import lib.core.Gen.GenApi as GenApi
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Phase1Scan - Phase1 拆分(阶段 E):Phase1Scan
|
||||
# Phase1Scan - 扫描类继承关系、泛型类标记与容器使用
|
||||
#
|
||||
# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy;
|
||||
# 调用方经本模块前缀访问。全局符号经 Phase1._xxx 跨模块访问。
|
||||
# 函数实现直接位于本模块,调用方经本模块前缀访问;全局符号经 Phase1._xxx 跨模块访问。
|
||||
# ============================================================
|
||||
|
||||
# 拓扑排序使用扁平字节数组存储类信息和文件依赖,
|
||||
@@ -48,26 +46,15 @@ import lib.core.Gen.GenApi as GenApi
|
||||
# ============================================================
|
||||
# _ScanClassInheritance - 预扫描 includes 文件,收集类继承关系
|
||||
#
|
||||
# 遍历所有可达 includes 文件,解析 AST 收集 ClassDef 的类名和父类名。
|
||||
# 结果存入扁平字节数组,返回收集到的类数量。
|
||||
# 遍历所有可达 includes 文件解析 AST,收集 ClassDef 的类名与父类名存入扁平字节数组,返回收集到的类数量。
|
||||
#
|
||||
# Args:
|
||||
# mb: 内存池
|
||||
# result: IncludesScanner 扫描结果
|
||||
# reachable_set: 可达 SHA1 集合
|
||||
# reachable_count: 可达 SHA1 数量
|
||||
# use_reachable: 是否使用可达集合过滤
|
||||
# sha1_set: SHA1 集合(use_reachable=0 时使用)
|
||||
# set_count: SHA1 集合数量
|
||||
# class_names_buf: 类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节,连续内存)
|
||||
# parent_names_buf: 父类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节,无父类填 '\0')
|
||||
# def_sha1s_buf: 定义 SHA1 扁平数组(每个 Phase1.SHA1_LEN 字节)
|
||||
#
|
||||
# Returns:
|
||||
# 收集到的类数量,-1 失败
|
||||
# Args: mb 内存池;result IncludesScanner 扫描结果;reachable_set 可达 SHA1 集合;reachable_count 可达 SHA1 数量;use_reachable 是否使用可达集合过滤;
|
||||
# sha1_set SHA1 集合(use_reachable=0 时使用);set_count SHA1 集合数量;class_names_buf 类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节);
|
||||
# parent_names_buf 父类名扁平数组(每个 Phase1.CLASS_NAME_LEN 字节,无父类填 '\0');def_sha1s_buf 定义 SHA1 扁平数组(每个 Phase1.SHA1_LEN 字节)
|
||||
# Returns: 收集到的类数量,-1 失败
|
||||
# ============================================================
|
||||
def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
result: IncludesScanner.ScanResult | t.CPtr,
|
||||
def _ScanClassInheritance(mb: memhub.MemBuddy*,
|
||||
result: rawptr[IncludesScanner.ScanResult],
|
||||
reachable_set: str, reachable_count: int,
|
||||
use_reachable: int,
|
||||
sha1_set: str, set_count: int,
|
||||
@@ -77,20 +64,22 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
generic_file_indices: t.CPtr,
|
||||
generic_file_count_box: t.CPtr) -> int:
|
||||
"""预扫描 includes 文件,收集类继承关系"""
|
||||
if result is None or class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None:
|
||||
if result is None:
|
||||
return -1
|
||||
# class_names_buf/parent_names_buf/def_sha1s_buf 由调用方 mb.alloc 分配(Phase1Main 预扫描前),本函数把其地址直接作为 strcpy 目的缓冲;
|
||||
# 分配失败返回 NULL 时目的指针为近零地址 → strcpy 写零页(ASan access-violation),故按 fail-fast 显式报错终止(VLogger.error 内部 sys.exit(1)),不静默返回 -1。
|
||||
if class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None:
|
||||
VLogger.error("类继承预扫描扁平缓冲分配失败(class_names_buf/parent_names_buf/def_sha1s_buf 为 NULL)", "Phase1")
|
||||
|
||||
entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
entry_size: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
class_count: int = 0
|
||||
|
||||
for i in range(result.Count):
|
||||
# 文件级 mark:收集完类继承信息后立即回收本文件 AST(可达 includes
|
||||
# 全量 parse 的 AST 若驻留到 mark1 → 1GB 主池耗尽 OOM 根因;
|
||||
# class_names_buf/parent_names_buf/def_sha1s_buf 在调用前分配,
|
||||
# 位于本 mark 之前,reset 不影响;generic_file_indices 同理)
|
||||
scan_mark: t.CSizeT = mb.mark()
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
|
||||
entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
# 文件级 mark:收集完类继承信息后立即回收本文件 AST(可达 includes 全量 parse 的 AST 若驻留到 mark1 会耗尽 1GB 主池 OOM);
|
||||
# class_names_buf/parent_names_buf/def_sha1s_buf 与 generic_file_indices 在调用前分配、位于本 mark 之前,reset 不影响。
|
||||
scan_mark: sizet = mb.mark()
|
||||
entry_addr: uint64 = uint64(result.Entries) + i * entry_size
|
||||
entry: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](entry_addr)
|
||||
if entry is None or entry.Sha1 is None:
|
||||
continue
|
||||
|
||||
@@ -108,10 +97,16 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 读取文件
|
||||
file_path: str = entry.Path
|
||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||
f: rawptr[fileio.File] = fileio.File(file_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
continue
|
||||
|
||||
# read_all 的容量参数含终止符(最多读 cap-1 字节), 文件更长会被静默截断
|
||||
if f.size() >= Phase1.SRC_BUF_SIZE:
|
||||
VLogger.error(f"源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path}", "Phase1")
|
||||
f.close()
|
||||
continue
|
||||
|
||||
src_buf: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE)
|
||||
if src_buf is None:
|
||||
f.close()
|
||||
@@ -124,49 +119,47 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
continue
|
||||
if bytes_read < Phase1.SRC_BUF_SIZE:
|
||||
src_buf[bytes_read] = 0
|
||||
else:
|
||||
src_buf[Phase1.SRC_BUF_SIZE - 1] = 0
|
||||
|
||||
# 解析 AST
|
||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||
lx: ast.Lexer* = ast.new_lexer(mb)
|
||||
if lx is None:
|
||||
stdlib.free(src_buf)
|
||||
continue
|
||||
ast._lexer_init(lx, src_buf, mb)
|
||||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||||
tokens: ast.Token* = ast.tokenize(lx)
|
||||
tree: ast.AST* = ast.parse_tokens(mb, tokens)
|
||||
if tree is None:
|
||||
stdlib.free(src_buf)
|
||||
continue
|
||||
|
||||
# 遍历 AST 顶层节点,收集 ClassDef
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is not None:
|
||||
cn: t.CSizeT = len(ch)
|
||||
cn: sizet = len(ch)
|
||||
for ci in range(cn):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
child: ast.AST* = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
kd: int = child.kind()
|
||||
if kd != ast.ASTKind.ClassDef:
|
||||
continue
|
||||
|
||||
cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
|
||||
cd: ast.ClassDef* = ast.ClassDef*(child)
|
||||
if cd is None or cd.name is None:
|
||||
continue
|
||||
|
||||
# 检测泛型类(有 type_params),记录文件索引以供 Phase 1a 预注册
|
||||
if file_has_generic == 0:
|
||||
tp_scan: list[str] | t.CPtr = cd.type_params
|
||||
tp_scan: list[str]* = cd.type_params
|
||||
if tp_scan is not None:
|
||||
file_has_generic = 1
|
||||
if generic_file_count_box is not None:
|
||||
gfc_ptr_scan: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(generic_file_count_box, t.CPtr))
|
||||
gfc_ptr_scan: t.CPtr = (int | t.CPtr)(generic_file_count_box)
|
||||
if gfc_ptr_scan is not None:
|
||||
gfc_scan: int = gfc_ptr_scan[0]
|
||||
if gfc_scan < Phase1.MAX_FILE_DEPS and generic_file_indices is not None:
|
||||
gi_addr_scan: t.CUInt64T = t.CUInt64T(generic_file_indices) + gfc_scan * 4
|
||||
gi_ptr_scan: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(gi_addr_scan, t.CPtr))
|
||||
gi_addr_scan: uint64 = uint64(generic_file_indices) + gfc_scan * 4
|
||||
gi_ptr_scan: t.CPtr = (int | t.CPtr)(gi_addr_scan)
|
||||
if gi_ptr_scan is not None:
|
||||
gi_ptr_scan[0] = i
|
||||
gfc_ptr_scan[0] = gfc_scan + 1
|
||||
@@ -176,7 +169,7 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 填充扁平数组:类名(偏移 = class_count * Phase1.CLASS_NAME_LEN)
|
||||
name_dst: str = class_names_buf + class_count * Phase1.CLASS_NAME_LEN
|
||||
nm_len: t.CSizeT = string.strlen(cd.name)
|
||||
nm_len: sizet = string.strlen(cd.name)
|
||||
if nm_len >= Phase1.CLASS_NAME_LEN:
|
||||
string.strncpy(name_dst, cd.name, Phase1.CLASS_NAME_LEN - 1)
|
||||
name_dst[Phase1.CLASS_NAME_LEN - 1] = '\0'
|
||||
@@ -189,7 +182,7 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
parent_nm: str = GenApi._get_parent_class(cd, None)
|
||||
# parent_nm 是 AST 节点内部指针,不需要释放
|
||||
if parent_nm is not None:
|
||||
pnm_len: t.CSizeT = string.strlen(parent_nm)
|
||||
pnm_len: sizet = string.strlen(parent_nm)
|
||||
if pnm_len >= Phase1.CLASS_NAME_LEN:
|
||||
string.strncpy(parent_dst, parent_nm, Phase1.CLASS_NAME_LEN - 1)
|
||||
parent_dst[Phase1.CLASS_NAME_LEN - 1] = '\0'
|
||||
@@ -210,33 +203,27 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
# ============================================================
|
||||
# _BufHasGenericClassMarker - 文本扫描检测文件是否含泛型类标记
|
||||
#
|
||||
# 泛型类(PEP 695)语法: class Name[T]:(类名后紧跟 '[')。
|
||||
# 逐字节扫描找词边界 'class' 关键字,其后标识符后非空白是 '[' → 命中。
|
||||
# 用于 _PreRegisterAllGenericTemplates 预注册前筛选,避免 parse 全部
|
||||
# 98 个 includes 导致 AST 驻留 mark1 前把 pool 推到 OOM
|
||||
# (NewAstTest [52/68] pool 耗尽根因:1a-pre 已 parse 全部驻留,
|
||||
# 预注册再全量 parse 等于翻倍)。
|
||||
# 误报(字符串/注释里的 "class X[")无害(多 parse 一个文件);
|
||||
# 漏报有害(泛型模板未预注册 → 悬空复发),模式保守匹配行内单行形式
|
||||
# (TPV 源码泛型类均为单行 `class X[T]:`,grep 确认)。
|
||||
# 泛型类(PEP 695)语法: class Name[T]:(类名后紧跟 '[')。逐字节扫描找词边界 'class' 关键字,其后标识符后非空白是 '[' → 命中。
|
||||
# 用于 _PreRegisterAllGenericTemplates 预注册前筛选,避免 parse 全部 98 个 includes 致 AST 驻留 mark1 前把 pool 推到 OOM。
|
||||
# 误报(字符串/注释里的 "class X[")无害(多 parse 一个文件);漏报有害(泛型模板未预注册 → 悬空复发),故保守只匹配单行形式。
|
||||
# ============================================================
|
||||
def _BufHasGenericClassMarker(buf: bytes, blen: t.CSizeT) -> int:
|
||||
def _BufHasGenericClassMarker(buf: bytes, blen: sizet) -> int:
|
||||
"""文本扫描:buf 中是否有 'class 标识符[' 泛型类标记,返回 1/0"""
|
||||
if buf is None or blen <= 6:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
pos: sizet = 0
|
||||
while pos + 5 < blen:
|
||||
if buf[pos] == 'c' and buf[pos + 1] == 'l' and buf[pos + 2] == 'a' \
|
||||
and buf[pos + 3] == 's' and buf[pos + 4] == 's':
|
||||
# class 前是词边界(行首或非标识符字符)
|
||||
prev_ok: int = 1
|
||||
if pos > 0:
|
||||
pc: t.CChar = buf[pos - 1]
|
||||
pc: char = buf[pos - 1]
|
||||
if(pc >= 'a' and pc <= 'z') or(pc >= 'A' and pc <= 'Z') \
|
||||
or(pc >= '0' and pc <= '9') or pc == '_':
|
||||
prev_ok = 0
|
||||
if prev_ok != 0:
|
||||
p: t.CSizeT = pos + 5
|
||||
p: sizet = pos + 5
|
||||
# 跳过空白
|
||||
while p < blen and(buf[p] == ' ' or buf[p] == '\t'):
|
||||
p += 1
|
||||
@@ -260,40 +247,37 @@ def _BufHasGenericClassMarker(buf: bytes, blen: t.CSizeT) -> int:
|
||||
# ============================================================
|
||||
# _PreRegisterAllGenericTemplates - 预注册 includes 泛型类模板(mark1 前)
|
||||
#
|
||||
# 背景:泛型模板表(GenericClassNames/GenericClassNodes/GenericClassSha1s/
|
||||
# GenericClassFiles + 模板节点)是懒分配的跨文件持久表,首次注册必须落在
|
||||
# mark1 之前才能跨 Phase1 1b(reset_to(mark1))与 Phase2(reset_to(mark2),
|
||||
# mark2 > mark1)存活。现有 1a-pre-generic 只注册"可达"泛型文件;FuncTest
|
||||
# 这类可达集合无泛型的项目,模板要等 Phase2 Phase A-pre-inc(mark2 之后)
|
||||
# 翻译全部 includes 时才注册 → reset 回收表与节点 → _find_generic_template
|
||||
# 遍历悬空内存 strcmp 崩溃。
|
||||
# 本函数先文本扫描(_BufHasGenericClassMarker,不 parse、不驻留)筛选出
|
||||
# 含泛型类的文件(全量 parse 会把 98 个 includes 的 AST 驻留 mark1 前 →
|
||||
# NewAstTest [52/68] pool 耗尽 OOM),仅对命中的文件用**永久池(perm_pool)**
|
||||
# 解析 → 模板节点与表直接进 perm_pool,跨 mark 永久存活、不占主 pool。
|
||||
# 重复注册由 _register_generic_template 内部查重跳过。
|
||||
# 泛型模板表(GenericClassNames/GenericClassNodes/GenericClassSha1s/GenericClassFiles + 模板节点)是懒分配的跨文件持久表,
|
||||
# 首次注册必须落在 mark1 之前才能跨 Phase1 1b(reset_to(mark1))与 Phase2(reset_to(mark2))存活;否则表与节点被 reset 回收,
|
||||
# _find_generic_template 遍历悬空内存 strcmp 崩溃。本函数先文本扫描(_BufHasGenericClassMarker,不 parse)筛选出含泛型类的文件,
|
||||
# 仅对命中文件用**永久池(perm_pool)**解析(模板节点与表直接进 perm_pool,跨 mark 永久存活、不占主 pool);重复注册由 _register_generic_template 内部查重跳过。
|
||||
# ============================================================
|
||||
def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy | t.CPtr,
|
||||
result: IncludesScanner.ScanResult | t.CPtr) -> int:
|
||||
def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy*,
|
||||
result: rawptr[IncludesScanner.ScanResult]) -> int:
|
||||
"""预注册全部 includes 文件的泛型类模板,返回处理到的泛型类数量"""
|
||||
if result is None or mb is None:
|
||||
return 0
|
||||
perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
if perm is None:
|
||||
return 0
|
||||
p1e_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
p1e_size: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
handled_count: int = 0
|
||||
for i in range(result.Count):
|
||||
entry_addr_pg: t.CUInt64T = t.CUInt64T(result.Entries) + i * p1e_size
|
||||
entry_pg: IncludesScanner.FileEntry | t.CPtr = (
|
||||
IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_pg, t.CPtr))
|
||||
entry_addr_pg: uint64 = uint64(result.Entries) + i * p1e_size
|
||||
entry_pg: rawptr[IncludesScanner.FileEntry] = (
|
||||
rawptr[IncludesScanner.FileEntry])(entry_addr_pg)
|
||||
if entry_pg is None or entry_pg.Sha1 is None:
|
||||
continue
|
||||
# 读取文件
|
||||
file_path_pg: str = entry_pg.Path
|
||||
f_pg: fileio.File | t.CPtr = fileio.File(file_path_pg, fileio.MODE.R)
|
||||
f_pg: rawptr[fileio.File] = fileio.File(file_path_pg, fileio.MODE.R)
|
||||
if f_pg.closed:
|
||||
continue
|
||||
# read_all 的容量参数含终止符(最多读 cap-1 字节), 文件更长会被静默截断
|
||||
if f_pg.size() >= Phase1.SRC_BUF_SIZE:
|
||||
VLogger.error(f"源文件超过 {Phase1.SRC_BUF_SIZE} 字节上限, 拒绝读取: {file_path_pg}", "Phase1")
|
||||
f_pg.close()
|
||||
continue
|
||||
src_buf_pg: bytes = stdlib.malloc(Phase1.SRC_BUF_SIZE)
|
||||
if src_buf_pg is None:
|
||||
f_pg.close()
|
||||
@@ -305,35 +289,33 @@ def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy | t.CPtr,
|
||||
continue
|
||||
if bytes_read_pg < Phase1.SRC_BUF_SIZE:
|
||||
src_buf_pg[bytes_read_pg] = 0
|
||||
else:
|
||||
src_buf_pg[Phase1.SRC_BUF_SIZE - 1] = 0
|
||||
# 文本扫描筛选:非泛型文件跳过(不 parse、不驻留,防 OOM)
|
||||
if _BufHasGenericClassMarker(src_buf_pg, bytes_read_pg) == 0:
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
# 泛型文件:永久池解析 → 注册模板(节点/表进 perm_pool,跨 reset 存活)
|
||||
lx_pg: ast.Lexer | t.CPtr = ast.new_lexer(perm)
|
||||
lx_pg: ast.Lexer* = ast.new_lexer(perm)
|
||||
if lx_pg is None:
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
ast._lexer_init(lx_pg, src_buf_pg, perm)
|
||||
tokens_pg: ast.Token | t.CPtr = ast.tokenize(lx_pg)
|
||||
tree_pg: ast.AST | t.CPtr = ast.parse_tokens(perm, tokens_pg)
|
||||
tokens_pg: ast.Token* = ast.tokenize(lx_pg)
|
||||
tree_pg: ast.AST* = ast.parse_tokens(perm, tokens_pg)
|
||||
if tree_pg is None:
|
||||
stdlib.free(src_buf_pg)
|
||||
continue
|
||||
# 遍历顶层 ClassDef,注册泛型模板(type_params 非 None)
|
||||
ch_pg: list[ast.AST | t.CPtr] | t.CPtr = tree_pg.children
|
||||
ch_pg: list[ast.AST*]* = tree_pg.children
|
||||
if ch_pg is not None:
|
||||
cn_pg: t.CSizeT = len(ch_pg)
|
||||
cn_pg: sizet = len(ch_pg)
|
||||
for ci_pg in range(cn_pg):
|
||||
child_pg: ast.AST | t.CPtr = ch_pg.get(ci_pg)
|
||||
child_pg: ast.AST* = ch_pg.get(ci_pg)
|
||||
if child_pg is None or child_pg.kind() != ast.ASTKind.ClassDef:
|
||||
continue
|
||||
cd_pg: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child_pg)
|
||||
cd_pg: ast.ClassDef* = ast.ClassDef*(child_pg)
|
||||
if cd_pg is None or cd_pg.name is None:
|
||||
continue
|
||||
tp_pg: list[str] | t.CPtr = cd_pg.type_params
|
||||
tp_pg: list[str]* = cd_pg.type_params
|
||||
if tp_pg is None:
|
||||
continue
|
||||
GenApi.set_current_file_type(file_path_pg)
|
||||
@@ -341,22 +323,15 @@ def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy | t.CPtr,
|
||||
handled_count += 1
|
||||
stdlib.free(src_buf_pg)
|
||||
if handled_count > 0:
|
||||
fb_gpre2: str = VLogger.fmt_buf()
|
||||
if fb_gpre2 is not None:
|
||||
viperlib.snprintf(fb_gpre2, 1024, "mark1 前永久池预注册 %d 个 includes 泛型类模板", handled_count)
|
||||
VLogger.info(fb_gpre2, "Phase1")
|
||||
VLogger.info(f"mark1 前永久池预注册 {handled_count} 个 includes 泛型类模板", "Phase1")
|
||||
else:
|
||||
VLogger.info(f"mark1 前永久池预注册 0 个泛型模板(扫描 {result.Count} 个文件,可能 marker 未命中或全量扫描失败)", "Phase1")
|
||||
return handled_count
|
||||
# ============================================================
|
||||
# _FindClassDefSha1 - 在扁平数组中查找类名对应的定义文件 SHA1
|
||||
#
|
||||
# Args:
|
||||
# class_names_buf: 类名扁平数组
|
||||
# def_sha1s_buf: 定义 SHA1 扁平数组
|
||||
# class_count: 类数量
|
||||
# class_name: 要查找的类名
|
||||
#
|
||||
# Returns:
|
||||
# SHA1 字符串指针(指向 def_sha1s_buf 内部偏移),None 未找到
|
||||
# Args: class_names_buf 类名扁平数组;def_sha1s_buf 定义 SHA1 扁平数组;class_count 类数量;class_name 要查找的类名
|
||||
# Returns: SHA1 字符串指针(指向 def_sha1s_buf 内部偏移),None 未找到
|
||||
# ============================================================
|
||||
def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes,
|
||||
class_count: int, class_name: str) -> str:
|
||||
@@ -371,14 +346,36 @@ def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes,
|
||||
# ============================================================
|
||||
# _ScanTreeForContainers - 递归扫描 AST 检测 list/dict 容器使用
|
||||
#
|
||||
# TPV 的 AST 中,语句块挂在 children,而表达式/注解树全部以结构体
|
||||
# 字段挂载(value/slice/func/args/annotation/targets/returns/bases/
|
||||
# left/right 等)。只递归 children 会漏掉 list[...] | t.CPtr(BinOp
|
||||
# 包裹)、list[...](...)(Call.func)、字段注解等一切非语句块位置。
|
||||
# 因此每个节点先递归其表达式承载字段,再递归 children 语句块。
|
||||
# TPV 的 AST 中语句块挂在 children,而表达式/注解树全部以结构体字段挂载(value/slice/func/args/annotation/targets/returns/bases/left/right 等);
|
||||
# 只递归 children 会漏掉 list[...] | t.CPtr、list[...](...)、字段注解等非语句块位置,故每个节点先递归表达式承载字段、再递归 children。
|
||||
# 命中即置 need_list/need_dict;误报无害(最多多编译两个空壳模块)。
|
||||
# ============================================================
|
||||
def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
|
||||
def _AnnIsContainer(ann: ast.AST*) -> int:
|
||||
"""注解是否为 list/dict 容器(Name 裸名或 Subscript list[...]/dict[...])
|
||||
|
||||
数组初始化(t.CArray[...] / 裸数组注解)返回 0,避免 _ScanTreeForContainers
|
||||
把数组字面量误判为 list 容器使用(FIX 2026-08-30,联动 Translator.vp 同修)。
|
||||
"""
|
||||
while ann is not None:
|
||||
ak_c: int = ann.kind()
|
||||
if ak_c == ast.ASTKind.Name:
|
||||
nm_c: ast.Name* = ast.Name*(ann)
|
||||
if nm_c.id is not None:
|
||||
if string.strcmp(nm_c.id, "list") == 0:
|
||||
return 1
|
||||
if string.strcmp(nm_c.id, "dict") == 0:
|
||||
return 1
|
||||
return 0
|
||||
elif ak_c == ast.ASTKind.Subscript:
|
||||
sub_c: ast.Subscript* = ast.Subscript*(ann)
|
||||
ann = sub_c.value
|
||||
else:
|
||||
return 0
|
||||
return 0
|
||||
|
||||
|
||||
def _ScanTreeForContainers(node: ast.AST*,
|
||||
need_list_box: t.CPtr,
|
||||
need_dict_box: t.CPtr,
|
||||
depth: int = 0):
|
||||
@@ -386,127 +383,123 @@ def _ScanTreeForContainers(node: ast.AST | t.CPtr,
|
||||
# 递归深度守卫:AST 损坏成自引用环(字段/children 回指祖先)时无限
|
||||
# 递归直至栈耗尽(每个 includes 文件 parse 后必执行)。fail-fast 终止。
|
||||
if depth > 128:
|
||||
fb_stc: str = VLogger.fmt_buf()
|
||||
if fb_stc is not None:
|
||||
viperlib.snprintf(fb_stc, 256, "容器扫描递归过深(AST 环或嵌套超过 128 层)")
|
||||
VLogger.error(fb_stc, "Phase1")
|
||||
sys.exit(1)
|
||||
VLogger.error("容器扫描递归过深(AST 环或嵌套超过 128 层)", "Phase1")
|
||||
if node is None:
|
||||
return
|
||||
k_s: int = node.kind()
|
||||
if k_s == ast.ASTKind.Name:
|
||||
nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
nm_s: ast.Name* = ast.Name*(node)
|
||||
if nm_s.id is not None:
|
||||
if string.strcmp(nm_s.id, "list") == 0:
|
||||
need_list_box[0] = 1
|
||||
elif string.strcmp(nm_s.id, "dict") == 0:
|
||||
need_dict_box[0] = 1
|
||||
elif k_s == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
sub_s: ast.Subscript* = ast.Subscript*(node)
|
||||
_ScanTreeForContainers(sub_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
_ScanTreeForContainers(sub_s.slice, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.BinOp:
|
||||
bop_s: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
bop_s: ast.BinOp* = ast.BinOp*(node)
|
||||
_ScanTreeForContainers(bop_s.left, need_list_box, need_dict_box, depth + 1)
|
||||
_ScanTreeForContainers(bop_s.right, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Call:
|
||||
cl_s2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
cl_s2: ast.Call* = ast.Call*(node)
|
||||
_ScanTreeForContainers(cl_s2.func, need_list_box, need_dict_box, depth + 1)
|
||||
cl_args_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.args
|
||||
cl_args_s: list[ast.AST*]* = cl_s2.args
|
||||
if cl_args_s is not None:
|
||||
na_s: t.CSizeT = len(cl_args_s)
|
||||
i_a2: t.CSizeT
|
||||
na_s: sizet = len(cl_args_s)
|
||||
i_a2: sizet
|
||||
for i_a2 in range(na_s):
|
||||
_ScanTreeForContainers(cl_args_s.get(i_a2), need_list_box, need_dict_box, depth + 1)
|
||||
cl_kws_s: list[ast.AST | t.CPtr] | t.CPtr = cl_s2.keywords
|
||||
cl_kws_s: list[ast.AST*]* = cl_s2.keywords
|
||||
if cl_kws_s is not None:
|
||||
nk_s: t.CSizeT = len(cl_kws_s)
|
||||
i_k2: t.CSizeT
|
||||
nk_s: sizet = len(cl_kws_s)
|
||||
i_k2: sizet
|
||||
for i_k2 in range(nk_s):
|
||||
kw_s: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(cl_kws_s.get(i_k2))
|
||||
kw_s: rawptr[ast.Keyword] = rawptr[ast.Keyword](cl_kws_s.get(i_k2))
|
||||
if kw_s is not None:
|
||||
_ScanTreeForContainers(kw_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Assign:
|
||||
asn_s: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||||
asn_s: ast.Assign* = ast.Assign*(node)
|
||||
_ScanTreeForContainers(asn_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
tgts_s: list[ast.AST | t.CPtr] | t.CPtr = asn_s.targets
|
||||
tgts_s: list[ast.AST*]* = asn_s.targets
|
||||
if tgts_s is not None:
|
||||
nt_s: t.CSizeT = len(tgts_s)
|
||||
i_t2: t.CSizeT
|
||||
nt_s: sizet = len(tgts_s)
|
||||
i_t2: sizet
|
||||
for i_t2 in range(nt_s):
|
||||
_ScanTreeForContainers(tgts_s.get(i_t2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.AnnAssign:
|
||||
aa_s2: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
aa_s2: ast.AnnAssign* = ast.AnnAssign*(node)
|
||||
_ScanTreeForContainers(aa_s2.annotation, need_list_box, need_dict_box, depth + 1)
|
||||
_ScanTreeForContainers(aa_s2.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.FunctionDef:
|
||||
fn_s: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
|
||||
fn_s: ast.FunctionDef* = ast.FunctionDef*(node)
|
||||
_ScanTreeForContainers(fn_s.returns, need_list_box, need_dict_box, depth + 1)
|
||||
fn_args_s: ast.Arguments | t.CPtr = fn_s.args
|
||||
fn_args_s: ast.Arguments* = ast.Arguments*(fn_s.args)
|
||||
if fn_args_s is not None:
|
||||
fa_s: list[ast.AST | t.CPtr] | t.CPtr = fn_args_s.args
|
||||
fa_s: list[ast.AST*]* = fn_args_s.args
|
||||
if fa_s is not None:
|
||||
nf_s: t.CSizeT = len(fa_s)
|
||||
i_f2: t.CSizeT
|
||||
nf_s: sizet = len(fa_s)
|
||||
i_f2: sizet
|
||||
for i_f2 in range(nf_s):
|
||||
arg_s: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(fa_s.get(i_f2))
|
||||
arg_s: ast.Arg* = ast.Arg*(fa_s.get(i_f2))
|
||||
if arg_s is not None:
|
||||
_ScanTreeForContainers(arg_s.annotation, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.ClassDef:
|
||||
cd_s: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node)
|
||||
bases_s: list[ast.AST | t.CPtr] | t.CPtr = cd_s.bases
|
||||
cd_s: ast.ClassDef* = ast.ClassDef*(node)
|
||||
bases_s: list[ast.AST*]* = cd_s.bases
|
||||
if bases_s is not None:
|
||||
nb_s: t.CSizeT = len(bases_s)
|
||||
i_b2: t.CSizeT
|
||||
nb_s: sizet = len(bases_s)
|
||||
i_b2: sizet
|
||||
for i_b2 in range(nb_s):
|
||||
_ScanTreeForContainers(bases_s.get(i_b2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Attribute:
|
||||
at_s: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
at_s: ast.Attribute* = ast.Attribute*(node)
|
||||
_ScanTreeForContainers(at_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Tuple:
|
||||
tu_s: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
|
||||
elts_s: list[ast.AST | t.CPtr] | t.CPtr = tu_s.elts
|
||||
tu_s: ast.Tuple* = ast.Tuple*(node)
|
||||
elts_s: list[ast.AST*]* = tu_s.elts
|
||||
if elts_s is not None:
|
||||
ne_s: t.CSizeT = len(elts_s)
|
||||
i_e2: t.CSizeT
|
||||
ne_s: sizet = len(elts_s)
|
||||
i_e2: sizet
|
||||
for i_e2 in range(ne_s):
|
||||
_ScanTreeForContainers(elts_s.get(i_e2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.UnaryOp:
|
||||
uop_s: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||||
uop_s: ast.UnaryOp* = ast.UnaryOp*(node)
|
||||
_ScanTreeForContainers(uop_s.operand, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Expr:
|
||||
ex_s: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
|
||||
ex_s: rawptr[ast.Expr] = rawptr[ast.Expr](node)
|
||||
_ScanTreeForContainers(ex_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Return:
|
||||
rt_s: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node)
|
||||
rt_s: rawptr[ast.Return] = rawptr[ast.Return](node)
|
||||
_ScanTreeForContainers(rt_s.value, need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.Compare:
|
||||
cp_s: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
|
||||
cp_s: rawptr[ast.Compare] = rawptr[ast.Compare](node)
|
||||
_ScanTreeForContainers(cp_s.left, need_list_box, need_dict_box, depth + 1)
|
||||
cps_s: list[ast.AST | t.CPtr] | t.CPtr = cp_s.comparators
|
||||
cps_s: list[ast.AST*]* = cp_s.comparators
|
||||
if cps_s is not None:
|
||||
nc_s: t.CSizeT = len(cps_s)
|
||||
i_c2: t.CSizeT
|
||||
nc_s: sizet = len(cps_s)
|
||||
i_c2: sizet
|
||||
for i_c2 in range(nc_s):
|
||||
_ScanTreeForContainers(cps_s.get(i_c2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.BoolOp:
|
||||
bo_s: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
|
||||
bvs_s: list[ast.AST | t.CPtr] | t.CPtr = bo_s.values
|
||||
bo_s: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
|
||||
bvs_s: list[ast.AST*]* = bo_s.values
|
||||
if bvs_s is not None:
|
||||
nv_s: t.CSizeT = len(bvs_s)
|
||||
i_v2: t.CSizeT
|
||||
nv_s: sizet = len(bvs_s)
|
||||
i_v2: sizet
|
||||
for i_v2 in range(nv_s):
|
||||
_ScanTreeForContainers(bvs_s.get(i_v2), need_list_box, need_dict_box, depth + 1)
|
||||
elif k_s == ast.ASTKind.List:
|
||||
# [] 字面量
|
||||
need_list_box[0] = 1
|
||||
elif k_s == ast.ASTKind.Dict:
|
||||
# {} 字面量
|
||||
need_dict_box[0] = 1
|
||||
# `[...]`/`{}` 字面量不触发 _list/_dict 导入:字面量广泛用于编译期常量列表(c.Asm 的 op/inp/out CLOBBER 参数)与数组数据初始化,并非容器使用;
|
||||
# 容器的真实使用由类型位置检测覆盖(Name/Subscript 注解、Call.func 构造名)。
|
||||
# elif k_s == ast.ASTKind.List:
|
||||
# need_list_box[0] = 1
|
||||
# elif k_s == ast.ASTKind.Dict:
|
||||
# need_dict_box[0] = 1
|
||||
# 递归语句块子节点
|
||||
if node.children is not None:
|
||||
ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children
|
||||
n_s: t.CSizeT = len(ch_s)
|
||||
ci_s: t.CSizeT
|
||||
ch_s: list[ast.AST*]* = node.children
|
||||
n_s: sizet = len(ch_s)
|
||||
ci_s: sizet
|
||||
for ci_s in range(n_s):
|
||||
_ScanTreeForContainers(ch_s.get(ci_s), need_list_box, need_dict_box, depth + 1)
|
||||
@@ -10,8 +10,7 @@ import w32.win32base
|
||||
import ast
|
||||
import llvmlite
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Gen.Translator as HandlesTranslator
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Gen.Generator as GenGenerator
|
||||
@@ -29,57 +28,37 @@ import lib.Phase.Phase1.Phase1Topo as Phase1Topo
|
||||
import lib.Phase.Phase1 as Phase1
|
||||
|
||||
# ============================================================
|
||||
# Phase1Topo - Phase1 拆分(阶段 E):Phase1Topo
|
||||
# Phase1Topo - 按类继承与 import 依赖对源文件做拓扑排序
|
||||
#
|
||||
# 直接移动模式:函数迁至此模块,原 Phase1.vp 仅保留常量/_mbuddy;
|
||||
# 调用方经本模块前缀访问。全局符号经 Phase1._xxx 跨模块访问。
|
||||
# 函数实现直接位于本模块,调用方经本模块前缀访问;全局符号经 Phase1._xxx 跨模块访问。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _TopoSortFiles - 根据类继承关系对文件进行拓扑排序
|
||||
# _TopoSortFiles - 根据类继承关系对文件进行拓扑排序(Kahn)
|
||||
#
|
||||
# 算法(Kahn):
|
||||
# 1. 从扁平类信息数组构建"文件 SHA1 → 依赖文件 SHA1 集合"映射
|
||||
# 2. 计算每个文件的入度(依赖数量)
|
||||
# 3. 入度为 0 的文件先处理,处理后减少依赖它的文件入度
|
||||
# 4. 重复直到所有文件处理完成
|
||||
# 步骤:1) 从扁平类信息数组构建「文件 SHA1 → 依赖文件 SHA1 集合」映射;2) 计算每个文件入度(DepCount,初始化 InDegree = DepCount);
|
||||
# 3) 入度为 0 的先处理,处理后减少依赖它的文件入度;4) 重复直到全部处理完成。
|
||||
# 依赖方向是「父类所在文件 → 子类所在文件」,即父类文件必须先处理。
|
||||
#
|
||||
# 注意:依赖方向是"父类所在文件 → 子类所在文件",
|
||||
# 即父类文件必须先处理。Kahn 用 DepCount 作为剩余依赖计数,
|
||||
# 依赖为 0 的先处理,初始化 InDegree = DepCount。
|
||||
#
|
||||
# Args:
|
||||
# mb: 内存池
|
||||
# result: IncludesScanner 扫描结果
|
||||
# reachable_set: 可达 SHA1 集合
|
||||
# reachable_count: 可达 SHA1 数量
|
||||
# use_reachable: 是否使用可达集合过滤
|
||||
# sha1_set: SHA1 集合
|
||||
# set_count: SHA1 集合数量
|
||||
# class_names_buf: 类名扁平数组
|
||||
# parent_names_buf: 父类名扁平数组
|
||||
# def_sha1s_buf: 定义 SHA1 扁平数组
|
||||
# class_count: 类数量
|
||||
# out_order: 输出拓扑顺序的文件索引数组(调用者分配,int 数组)
|
||||
# out_count: 输出文件数量
|
||||
#
|
||||
# Returns:
|
||||
# 0 成功,-1 失败
|
||||
# Args: mb 内存池;result IncludesScanner 扫描结果;reachable_set 可达 SHA1 集合;reachable_count 可达 SHA1 数量;use_reachable 是否用可达集合过滤;
|
||||
# sha1_set SHA1 集合;set_count SHA1 集合数量;class_names_buf 类名扁平数组;parent_names_buf 父类名扁平数组;def_sha1s_buf 定义 SHA1 扁平数组;
|
||||
# class_count 类数量;out_order 输出拓扑顺序的文件索引数组(调用者分配,int 数组);out_count 输出文件数量
|
||||
# Returns: 0 成功,-1 失败
|
||||
# ============================================================
|
||||
def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
result: IncludesScanner.ScanResult | t.CPtr,
|
||||
def _TopoSortFiles(mb: memhub.MemBuddy*,
|
||||
result: rawptr[IncludesScanner.ScanResult],
|
||||
reachable_set: str, reachable_count: int,
|
||||
use_reachable: int,
|
||||
sha1_set: str, set_count: int,
|
||||
class_names_buf: bytes, parent_names_buf: bytes,
|
||||
def_sha1s_buf: bytes, class_count: int,
|
||||
out_order: t.CPtr, out_count: t.CPtr,
|
||||
temp_dir: str, td_len_ts: t.CSizeT) -> int:
|
||||
temp_dir: str, td_len_ts: sizet) -> int:
|
||||
"""根据类继承关系对文件进行拓扑排序"""
|
||||
if result is None or out_order is None or out_count is None:
|
||||
return -1
|
||||
|
||||
entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
entry_size: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
|
||||
# 1. 分配扁平数组:文件 SHA1、依赖 SHA1 列表、依赖数量、入度、处理状态
|
||||
# 用扁平数组代替 FileDepEntry 结构体,避免 str 指针字段 NULL 崩溃
|
||||
@@ -111,8 +90,8 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
file_count: int = 0
|
||||
# sha1→file_index 映射(简单线性查找,文件数不多)
|
||||
for i in range(result.Count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
|
||||
entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
entry_addr: uint64 = uint64(result.Entries) + i * entry_size
|
||||
entry: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](entry_addr)
|
||||
if entry is None or entry.Sha1 is None:
|
||||
continue
|
||||
|
||||
@@ -161,8 +140,8 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
continue
|
||||
|
||||
# 读取当前依赖数量
|
||||
cnt_addr: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi * 4
|
||||
cnt_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr, t.CPtr))
|
||||
cnt_addr: uint64 = uint64(file_dep_counts) + fi * 4
|
||||
cnt_ptr: t.CPtr = (int | t.CPtr)(cnt_addr)
|
||||
if cnt_ptr is None:
|
||||
break
|
||||
cur_cnt: int = cnt_ptr[0]
|
||||
@@ -185,15 +164,9 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 2.5 补充 import 依赖边:被 import 的模块先完整翻译。
|
||||
#
|
||||
# 仅按类继承建边不够:跨模块全局变量 stub(lexer.vp from-import
|
||||
# tokens.vp 的 _op_head)、跨模块 vtable TypeStr(astaux 继承 base 的
|
||||
# AST)、泛型模板(base.vp 用 list[...])都要求依赖模块先翻译,而它们
|
||||
# 之间可能无类继承关系。deps(_includes_deps_*)由 Phase 1a-pre 填充
|
||||
# (含容器按需注入的 _list/_dict)。
|
||||
#
|
||||
# 用 _BuildIncludesSha1Map 复制局部 sha1→模块名 数组(与
|
||||
# _BuildReachableSha1Set 的 BFS 一致),避免直接使用全局 store 返回值
|
||||
# 跨函数传参(bytes|t.CPtr 联合转 str 参数)的地址异常。
|
||||
# 仅按类继承建边不够:跨模块全局变量 stub、跨模块 vtable TypeStr、泛型模板都要求依赖模块先翻译,而它们之间可能无类继承关系。
|
||||
# deps(_includes_deps_*)由 Phase 1a-pre 填充(含容器按需注入的 _list/_dict);用 _BuildIncludesSha1Map 复制局部 sha1→模块名 数组
|
||||
# (与 _BuildReachableSha1Set 的 BFS 一致),避免直接跨函数传全局 store 返回值导致地址异常。
|
||||
sha1_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||||
mod_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||||
map_count_ts: int = 0
|
||||
@@ -207,13 +180,13 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
deps_imp: str = StubMergerStore.LookupIncludesDeps(fsha1_imp)
|
||||
if deps_imp is None:
|
||||
continue
|
||||
dl_imp: t.CSizeT = string.strlen(deps_imp)
|
||||
dpos_imp: t.CSizeT = 0
|
||||
dl_imp: sizet = string.strlen(deps_imp)
|
||||
dpos_imp: sizet = 0
|
||||
while dpos_imp < dl_imp:
|
||||
dstart_imp: t.CSizeT = dpos_imp
|
||||
dstart_imp: sizet = dpos_imp
|
||||
while dpos_imp < dl_imp and deps_imp[dpos_imp] != ' ':
|
||||
dpos_imp += 1
|
||||
dlen_imp: t.CSizeT = dpos_imp - dstart_imp
|
||||
dlen_imp: sizet = dpos_imp - dstart_imp
|
||||
if dpos_imp < dl_imp:
|
||||
dpos_imp += 1
|
||||
if dlen_imp == 0:
|
||||
@@ -235,8 +208,8 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
if fj_imp == fi_imp:
|
||||
break
|
||||
# 去重 + 加边:fi_imp 依赖 fj_imp(InDegree[fi_imp]++)
|
||||
cnt_addr_imp: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi_imp * 4
|
||||
cnt_ptr_imp: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr_imp, t.CPtr))
|
||||
cnt_addr_imp: uint64 = uint64(file_dep_counts) + fi_imp * 4
|
||||
cnt_ptr_imp: t.CPtr = (int | t.CPtr)(cnt_addr_imp)
|
||||
if cnt_ptr_imp is None:
|
||||
break
|
||||
cur_cnt_imp: int = cnt_ptr_imp[0]
|
||||
@@ -261,10 +234,10 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 3. Kahn 算法:InDegree = DepCount(依赖多少个父文件)
|
||||
# 依赖为 0 的先处理,处理后减少依赖它的文件入度
|
||||
for fi in range(file_count):
|
||||
cnt_addr3: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi * 4
|
||||
cnt_ptr3: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr3, t.CPtr))
|
||||
ind_addr3: t.CUInt64T = t.CUInt64T(file_indegrees) + fi * 4
|
||||
ind_ptr3: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr3, t.CPtr))
|
||||
cnt_addr3: uint64 = uint64(file_dep_counts) + fi * 4
|
||||
cnt_ptr3: t.CPtr = (int | t.CPtr)(cnt_addr3)
|
||||
ind_addr3: uint64 = uint64(file_indegrees) + fi * 4
|
||||
ind_ptr3: t.CPtr = (int | t.CPtr)(ind_addr3)
|
||||
if cnt_ptr3 is not None and ind_ptr3 is not None:
|
||||
ind_ptr3[0] = cnt_ptr3[0]
|
||||
|
||||
@@ -275,13 +248,13 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
changed = 0
|
||||
for fi in range(file_count):
|
||||
# 检查处理状态
|
||||
proc_addr4: t.CUInt64T = t.CUInt64T(file_processed) + fi * 4
|
||||
proc_ptr4: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr4, t.CPtr))
|
||||
proc_addr4: uint64 = uint64(file_processed) + fi * 4
|
||||
proc_ptr4: t.CPtr = (int | t.CPtr)(proc_addr4)
|
||||
if proc_ptr4 is None or proc_ptr4[0] != 0:
|
||||
continue
|
||||
# 检查入度
|
||||
ind_addr4: t.CUInt64T = t.CUInt64T(file_indegrees) + fi * 4
|
||||
ind_ptr4: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr4, t.CPtr))
|
||||
ind_addr4: uint64 = uint64(file_indegrees) + fi * 4
|
||||
ind_ptr4: t.CPtr = (int | t.CPtr)(ind_addr4)
|
||||
if ind_ptr4 is None or ind_ptr4[0] > 0:
|
||||
continue
|
||||
|
||||
@@ -289,13 +262,13 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 找到对应的 result.Entries 索引
|
||||
target_sha1: str = file_sha1s_buf + fi * Phase1.SHA1_LEN
|
||||
for ri in range(result.Count):
|
||||
ea_r: t.CUInt64T = t.CUInt64T(result.Entries) + ri * entry_size
|
||||
ent_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_r, t.CPtr))
|
||||
ea_r: uint64 = uint64(result.Entries) + ri * entry_size
|
||||
ent_r: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](ea_r)
|
||||
if ent_r is not None and ent_r.Sha1 is not None:
|
||||
if string.strcmp(ent_r.Sha1, target_sha1) == 0:
|
||||
# 写入输出索引数组
|
||||
out_idx_addr: t.CUInt64T = t.CUInt64T(out_order) + out_idx * 4
|
||||
out_int_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_idx_addr, t.CPtr))
|
||||
out_idx_addr: uint64 = uint64(out_order) + out_idx * 4
|
||||
out_int_ptr: t.CPtr = (int | t.CPtr)(out_idx_addr)
|
||||
if out_int_ptr is not None:
|
||||
out_int_ptr[0] = ri
|
||||
out_idx += 1
|
||||
@@ -307,40 +280,37 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 减少依赖该文件的其他文件的入度
|
||||
for fj in range(file_count):
|
||||
proc_addr5: t.CUInt64T = t.CUInt64T(file_processed) + fj * 4
|
||||
proc_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr5, t.CPtr))
|
||||
proc_addr5: uint64 = uint64(file_processed) + fj * 4
|
||||
proc_ptr5: t.CPtr = (int | t.CPtr)(proc_addr5)
|
||||
if proc_ptr5 is None or proc_ptr5[0] != 0:
|
||||
continue
|
||||
# 读取 fj 的依赖数量
|
||||
cnt_addr5: t.CUInt64T = t.CUInt64T(file_dep_counts) + fj * 4
|
||||
cnt_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr5, t.CPtr))
|
||||
cnt_addr5: uint64 = uint64(file_dep_counts) + fj * 4
|
||||
cnt_ptr5: t.CPtr = (int | t.CPtr)(cnt_addr5)
|
||||
if cnt_ptr5 is None:
|
||||
continue
|
||||
fj_dep_cnt: int = cnt_ptr5[0]
|
||||
for di in range(fj_dep_cnt):
|
||||
dep_slot5: str = file_deps_buf + fj * Phase1.MAX_DEP_EDGES * Phase1.SHA1_LEN + di * Phase1.SHA1_LEN
|
||||
if string.strcmp(dep_slot5, target_sha1) == 0:
|
||||
ind_addr5: t.CUInt64T = t.CUInt64T(file_indegrees) + fj * 4
|
||||
ind_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr5, t.CPtr))
|
||||
ind_addr5: uint64 = uint64(file_indegrees) + fj * 4
|
||||
ind_ptr5: t.CPtr = (int | t.CPtr)(ind_addr5)
|
||||
if ind_ptr5 is not None:
|
||||
ind_ptr5[0] = ind_ptr5[0] - 1
|
||||
break
|
||||
|
||||
# 处理循环依赖:环内优先输出"被依赖者"(被其余剩余文件依赖数量多者先)。
|
||||
# 处理循环依赖:环内优先输出被依赖者(被其余剩余文件依赖数量多者先)。
|
||||
#
|
||||
# 背景:容器按需注入(string 用 list 泛型 → 依赖 _list)与真实 import
|
||||
# (_list import string)形成伪环,Kahn 无法完全归零。若按扫描顺序追加,
|
||||
# 依赖者(astaux)会先于被依赖者(base)翻译 → 跨模块 vtable TypeStr
|
||||
# 未注册 → 误杀。被依赖者先翻译,其 stub/TypeStr/模板先就绪,依赖者
|
||||
# 翻译时可引用(函数/全局声明由 1a-pre 的 vpi 兜底)。
|
||||
# 容器按需注入(string 用 list 泛型 → 依赖 _list)与真实 import 会形成伪环,Kahn 无法完全归零;若按扫描顺序追加,
|
||||
# 依赖者会先于被依赖者翻译 → 跨模块 vtable TypeStr 未注册 → 误杀。
|
||||
if out_idx < file_count:
|
||||
rem_idx: t.CPtr = stdlib.malloc(4 * file_count)
|
||||
rem_depcnt: t.CPtr = stdlib.malloc(4 * file_count)
|
||||
rem_count: int = 0
|
||||
if rem_idx is not None and rem_depcnt is not None:
|
||||
for fi in range(file_count):
|
||||
proc_addr7: t.CUInt64T = t.CUInt64T(file_processed) + fi * 4
|
||||
proc_ptr7: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr7, t.CPtr))
|
||||
proc_addr7: uint64 = uint64(file_processed) + fi * 4
|
||||
proc_ptr7: t.CPtr = (int | t.CPtr)(proc_addr7)
|
||||
if proc_ptr7 is not None and proc_ptr7[0] == 0:
|
||||
rem_idx[rem_count] = fi
|
||||
rem_depcnt[rem_count] = 0
|
||||
@@ -353,8 +323,8 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
fi_b: int = rem_idx[i_b]
|
||||
if fi_b == fi_a:
|
||||
continue
|
||||
cnt_addr_b: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi_b * 4
|
||||
cnt_ptr_b: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr_b, t.CPtr))
|
||||
cnt_addr_b: uint64 = uint64(file_dep_counts) + fi_b * 4
|
||||
cnt_ptr_b: t.CPtr = (int | t.CPtr)(cnt_addr_b)
|
||||
if cnt_ptr_b is None:
|
||||
continue
|
||||
cnt_b: int = cnt_ptr_b[0]
|
||||
@@ -376,18 +346,18 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 按序输出剩余文件
|
||||
for i_a in range(rem_count):
|
||||
fi_a2: int = rem_idx[i_a]
|
||||
proc_addr8: t.CUInt64T = t.CUInt64T(file_processed) + fi_a2 * 4
|
||||
proc_ptr8: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr8, t.CPtr))
|
||||
proc_addr8: uint64 = uint64(file_processed) + fi_a2 * 4
|
||||
proc_ptr8: t.CPtr = (int | t.CPtr)(proc_addr8)
|
||||
if proc_ptr8 is None or proc_ptr8[0] != 0:
|
||||
continue
|
||||
target_sha1_2: str = file_sha1s_buf + fi_a2 * Phase1.SHA1_LEN
|
||||
for ri in range(result.Count):
|
||||
ea_r2: t.CUInt64T = t.CUInt64T(result.Entries) + ri * entry_size
|
||||
ent_r2: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_r2, t.CPtr))
|
||||
ea_r2: uint64 = uint64(result.Entries) + ri * entry_size
|
||||
ent_r2: rawptr[IncludesScanner.FileEntry] = rawptr[IncludesScanner.FileEntry](ea_r2)
|
||||
if ent_r2 is not None and ent_r2.Sha1 is not None:
|
||||
if string.strcmp(ent_r2.Sha1, target_sha1_2) == 0:
|
||||
out_idx_addr2: t.CUInt64T = t.CUInt64T(out_order) + out_idx * 4
|
||||
out_int_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_idx_addr2, t.CPtr))
|
||||
out_idx_addr2: uint64 = uint64(out_order) + out_idx * 4
|
||||
out_int_ptr2: t.CPtr = (int | t.CPtr)(out_idx_addr2)
|
||||
if out_int_ptr2 is not None:
|
||||
out_int_ptr2[0] = ri
|
||||
out_idx += 1
|
||||
@@ -397,7 +367,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
stdlib.free(rem_depcnt)
|
||||
|
||||
# 写入输出数量
|
||||
out_count_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_count, t.CPtr))
|
||||
out_count_ptr: t.CPtr = (int | t.CPtr)(out_count)
|
||||
if out_count_ptr is not None:
|
||||
out_count_ptr[0] = out_idx
|
||||
|
||||
|
||||
@@ -1,37 +1,15 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import ast
|
||||
import llvmlite
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Gen.Generator as GenGenerator
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.Phase.BuildPipeline as BuildPipeline
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Stub.StubGen.Converter as StubConverter
|
||||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||||
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
|
||||
import lib.Stub.StubMerger.StubMergerIR as StubMergerIR
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
_mbuddy: memhub.MemBuddy*
|
||||
|
||||
# 源代码缓冲区大小(1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
|
||||
# vpi 缓冲区大小(256KB)
|
||||
PYI_BUF_SIZE: t.CSizeT = 262144
|
||||
PYI_BUF_SIZE: sizet = 262144
|
||||
|
||||
# 拓扑排序相关常量
|
||||
MAX_CLASSES: t.CDefine = 512
|
||||
|
||||
+586
-588
File diff suppressed because it is too large.
Load diff
+728
-635
File diff suppressed because it is too large.
Load diff
+256
-267
@@ -1,267 +1,256 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
import hashlib
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import w32.fileio as fileio
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Utils - 工程工具函数
|
||||
#
|
||||
# 提供 SHA1 计算和目录清理等通用工具函数。
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# nibble_to_hex_char - 半字节转十六进制字符
|
||||
# ============================================================
|
||||
def nibble_to_hex_char(n: int, uppercase: int) -> t.CChar:
|
||||
"""0-15 → '0'-'9'/'a'-'f'(uppercase=1 时用 'A'-'F')"""
|
||||
if n < 10: return '0' + n
|
||||
if uppercase != 0: return 'A' + (n - 10)
|
||||
return 'a' + (n - 10)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# bytes_to_hex - 字节序列转十六进制字符串
|
||||
# ============================================================
|
||||
def bytes_to_hex(pool: memhub.MemBuddy | t.CPtr,
|
||||
digest: bytes,
|
||||
nbytes: t.CSizeT,
|
||||
uppercase: int,
|
||||
use_malloc: int) -> str:
|
||||
"""将 digest 前 nbytes 字节转为 2*nbytes 个十六进制字符(含 null 终止)
|
||||
|
||||
use_malloc=1 时用 stdlib.malloc(调用方负责 free),否则 pool.alloc。
|
||||
合并自 Utils.compute_sha1 / IncludesScanner.compute_file_sha1 的重复 hex 转换。
|
||||
"""
|
||||
if digest is None or nbytes <= 0:
|
||||
return None
|
||||
hex_len: t.CSizeT = nbytes * 2 + 1
|
||||
hex_buf: str = None
|
||||
if use_malloc != 0:
|
||||
hex_buf = stdlib.malloc(hex_len)
|
||||
else:
|
||||
hex_buf = pool.alloc(hex_len)
|
||||
if hex_buf is None:
|
||||
return None
|
||||
for i in range(nbytes):
|
||||
hi: int = (digest[i] >> 4) & 0xF
|
||||
lo: int = digest[i] & 0xF
|
||||
hex_buf[i * 2] = nibble_to_hex_char(hi, uppercase)
|
||||
hex_buf[i * 2 + 1] = nibble_to_hex_char(lo, uppercase)
|
||||
hex_buf[nbytes * 2] = '\0'
|
||||
return hex_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# compute_sha1 - 计算字符串的 SHA1,返回前 16 个十六进制字符
|
||||
#
|
||||
# 使用 includes/hashlib 库的 sha1 类计算摘要,转为十六进制字符串。
|
||||
# 参考 Projectrans.py 的 compute_sha1(hashlib.sha1().hexdigest()[:16])。
|
||||
# ============================================================
|
||||
def compute_sha1(pool: memhub.MemBuddy | t.CPtr, content: str) -> str:
|
||||
"""计算字符串的 SHA1,返回前 16 个十六进制字符(用于文件命名)"""
|
||||
if content is None or pool is None:
|
||||
return None
|
||||
|
||||
# 构造 sha1 对象(__init__ 会初始化 state/count/buf)
|
||||
# ctx 在栈上分配(alloca),函数内使用完即丢弃,无需堆分配
|
||||
ctx: hashlib.sha1 | t.CPtr = hashlib.sha1()
|
||||
if ctx is None: return None
|
||||
|
||||
# 计算摘要
|
||||
ctx.update(content)
|
||||
digest: bytes = pool.alloc(hashlib.SHA1_DIGEST_LEN)
|
||||
if digest is None: return None
|
||||
ctx.final(digest)
|
||||
|
||||
# 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符)
|
||||
return bytes_to_hex(pool, digest, 8, 0, 0)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# is_vp_at - 检查路径段是否以 .vp 后缀结尾
|
||||
# ============================================================
|
||||
def is_vp_at(p: str, start: t.CSizeT, plen: t.CSizeT) -> int:
|
||||
"""检查 p[start, start+plen) 是否以 .vp 后缀结尾(1=是,0=否)。
|
||||
|
||||
不再识别 .py(移除 vp -> py 后缀识别回退:Viper 源文件仅 .vp)。
|
||||
"""
|
||||
if p is None or plen <= 3:
|
||||
return 0
|
||||
base: t.CSizeT = start + plen - 3
|
||||
if p[base] == '.' and p[base + 1] == 'v' and p[base + 2] == 'p':
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# JoinPath - 拼接两个路径段为 a/b
|
||||
# ============================================================
|
||||
def JoinPath(a: str, b: str) -> str:
|
||||
"""拼接路径段为 "a/b"(stdlib.malloc 分配,调用方负责 free),失败返回 None"""
|
||||
if a is None or b is None:
|
||||
return None
|
||||
a_len: t.CSizeT = string.strlen(a)
|
||||
b_len: t.CSizeT = string.strlen(b)
|
||||
total_len: t.CSizeT = a_len + b_len + 2
|
||||
buf: str = stdlib.malloc(total_len)
|
||||
if buf is None: return None
|
||||
viperlib.snprintf(buf, total_len, "%s/%s", a, b)
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# read_file_to_buf - 读取整个文件到缓冲区(null 终止)
|
||||
# ============================================================
|
||||
def read_file_to_buf(path: str, buf_size: t.CSizeT) -> bytes:
|
||||
"""读取文件到 stdlib.malloc 缓冲区并保证 null 终止
|
||||
|
||||
返回缓冲区(调用方负责 free);打开失败/空文件/分配失败返回 None。
|
||||
合并自 Phase2/StubMerger/IncludesScanner 的重复"打开+读取+终止"序列。
|
||||
"""
|
||||
if path is None or buf_size <= 0: return None
|
||||
sf: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.R)
|
||||
if sf.closed: return None
|
||||
buf: bytes = stdlib.malloc(buf_size)
|
||||
if buf is None:
|
||||
sf.close()
|
||||
return None
|
||||
br: t.CInt64T = sf.read_all(buf, buf_size)
|
||||
sf.close()
|
||||
if br <= 0:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
if br < buf_size:
|
||||
buf[br] = 0
|
||||
else:
|
||||
buf[buf_size - 1] = 0
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PathToModuleName - 文件路径转模块名
|
||||
# ============================================================
|
||||
def PathToModuleName(path: str, strip_includes_prefix: int) -> str:
|
||||
"""将文件路径转换为模块名(stdlib.malloc 分配,调用方负责 free)
|
||||
|
||||
strip_includes_prefix=1 时跳过 includes/ 前缀(如 includes/ast/__init__.vp → ast)。
|
||||
特殊处理 __init__.vp:pkg/__init__.vp → pkg(而非 pkg.__init__)。
|
||||
合并自 StubMerger._PathToModuleName / IncludesScanner 内联模块名计算。
|
||||
"""
|
||||
if path is None:
|
||||
return None
|
||||
plen: t.CSizeT = string.strlen(path)
|
||||
# 跳过 includes/ 或 includes\ 前缀(Windows 反斜杠兼容)
|
||||
prefix_len: t.CSizeT = 9
|
||||
path_start: t.CSizeT = 0
|
||||
if strip_includes_prefix != 0 and plen > prefix_len and string.strncmp(path, "includes", 8) == 0:
|
||||
psep_ch: t.CChar = path[8]
|
||||
if psep_ch == '/' or psep_ch == '\\':
|
||||
path_start = prefix_len
|
||||
plen = plen - prefix_len
|
||||
# 去掉 .vp 后缀(Viper 源文件仅 .vp,不再识别 .py)
|
||||
if is_vp_at(path, path_start, plen) != 0:
|
||||
plen -= 3
|
||||
if plen == 0:
|
||||
return None
|
||||
# 检查是否以 /__init__ 或 \__init__ 结尾(包的 __init__.vp)
|
||||
# 同时支持 / 和 \ 两种分隔符(TPC 写入的路径可能混合使用)
|
||||
if plen > 9:
|
||||
tail_off: t.CSizeT = path_start + plen - 9
|
||||
sep_char: t.CChar = path[tail_off]
|
||||
if (sep_char == '/' or sep_char == '\\') \
|
||||
and path[tail_off + 1] == '_' and path[tail_off + 2] == '_' \
|
||||
and path[tail_off + 3] == 'i' and path[tail_off + 4] == 'n' and path[tail_off + 5] == 'i' \
|
||||
and path[tail_off + 6] == 't' and path[tail_off + 7] == '_' and path[tail_off + 8] == '_':
|
||||
# 去掉 分隔符+__init__ 后缀,plen 就是包名部分长度
|
||||
plen = tail_off - path_start
|
||||
if plen == 0:
|
||||
return None
|
||||
# 复制并替换 / 为 .
|
||||
result: str = stdlib.malloc(plen + 1)
|
||||
if result is None:
|
||||
return None
|
||||
for ri in range(plen):
|
||||
ch: t.CChar = path[path_start + ri]
|
||||
if ch == '/' or ch == '\\':
|
||||
result[ri] = '.'
|
||||
else:
|
||||
result[ri] = ch
|
||||
result[plen] = '\0'
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CleanDir - 递归删除目录中所有文件和子目录(保留 dir_path 本身)
|
||||
#
|
||||
# 用于 --clean 选项:清理 temp_dir 和 output_dir 中的旧文件。
|
||||
# SHA1 分片目录结构(如 temp/1c/、temp/7a/)需要递归清理,
|
||||
# 否则旧的截断文件(如 256KB text.ll)会被 Phase1 跳过逻辑复用。
|
||||
# ============================================================
|
||||
def CleanDir(dir_path: str) -> int:
|
||||
"""递归删除目录中所有文件和子目录,保留 dir_path 本身,返回删除的文件数,-1 表示错误"""
|
||||
if dir_path is None:
|
||||
return -1
|
||||
dir_len: t.CSizeT = string.strlen(dir_path)
|
||||
pattern: bytes = stdlib.malloc(dir_len + 8)
|
||||
if pattern is None:
|
||||
return -1
|
||||
viperlib.snprintf(pattern, dir_len + 8, "%s/*", dir_path)
|
||||
|
||||
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
if find_data is None:
|
||||
stdlib.free(pattern)
|
||||
return -1
|
||||
string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
|
||||
handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data)
|
||||
if handle == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
stdlib.free(pattern)
|
||||
stdlib.free(find_data)
|
||||
return 0
|
||||
|
||||
deleted: int = 0
|
||||
while True:
|
||||
fname: str = find_data.cFileName
|
||||
if fname is not None:
|
||||
# 跳过 . 和 ..
|
||||
if fname[0] == '.':
|
||||
if fname[1] == '\0':
|
||||
fname = None
|
||||
elif fname[1] == '.' and fname[2] == '\0':
|
||||
fname = None
|
||||
if fname is not None:
|
||||
full_path: bytes = JoinPath(dir_path, fname)
|
||||
if full_path is not None:
|
||||
# 检查是否为目录(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
is_dir: t.CUInt32T = find_data.dwFileAttributes & w32.win32file.FILE_ATTRIBUTE_DIRECTORY
|
||||
if is_dir != 0:
|
||||
# 递归清理子目录中的文件
|
||||
sub_deleted: int = CleanDir(full_path)
|
||||
if sub_deleted > 0:
|
||||
deleted += sub_deleted
|
||||
# 删除空子目录(RemoveDirectoryA 要求目录为空)
|
||||
w32.win32file.RemoveDirectoryA(full_path)
|
||||
else:
|
||||
# 删除文件
|
||||
if w32.win32file.DeleteFileA(full_path) != 0:
|
||||
deleted += 1
|
||||
stdlib.free(full_path)
|
||||
|
||||
if w32.win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
|
||||
w32.win32file.FindClose(handle)
|
||||
stdlib.free(pattern)
|
||||
stdlib.free(find_data)
|
||||
return deleted
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
import hashlib
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import w32.fileio as fileio
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Utils - 工程工具函数(SHA1 计算、目录清理等)
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy*
|
||||
|
||||
|
||||
# ============================================================
|
||||
# nibble_to_hex_char - 半字节转十六进制字符
|
||||
# ============================================================
|
||||
def nibble_to_hex_char(n: int, uppercase: int) -> char:
|
||||
"""0-15 → '0'-'9'/'a'-'f'(uppercase=1 时用 'A'-'F')"""
|
||||
if n < 10: return '0' + n
|
||||
if uppercase != 0: return 'A' + (n - 10)
|
||||
return 'a' + (n - 10)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# bytes_to_hex - 字节序列转十六进制字符串
|
||||
# ============================================================
|
||||
def bytes_to_hex(pool: memhub.MemBuddy*,
|
||||
digest: bytes,
|
||||
nbytes: sizet,
|
||||
uppercase: int,
|
||||
use_malloc: int) -> str:
|
||||
"""将 digest 前 nbytes 字节转为 2*nbytes 个十六进制字符(含 null 终止)
|
||||
|
||||
use_malloc=1 时用 stdlib.malloc(调用方负责 free),否则 pool.alloc。
|
||||
合并自 Utils.compute_sha1 / IncludesScanner.compute_file_sha1 的重复 hex 转换。
|
||||
"""
|
||||
if digest is None or nbytes <= 0:
|
||||
return None
|
||||
hex_len: sizet = nbytes * 2 + 1
|
||||
hex_buf: str = None
|
||||
if use_malloc != 0:
|
||||
hex_buf = stdlib.malloc(hex_len)
|
||||
else:
|
||||
hex_buf = pool.alloc(hex_len)
|
||||
if hex_buf is None:
|
||||
return None
|
||||
for i in range(nbytes):
|
||||
hi: int = (digest[i] >> 4) & 0xF
|
||||
lo: int = digest[i] & 0xF
|
||||
hex_buf[i * 2] = nibble_to_hex_char(hi, uppercase)
|
||||
hex_buf[i * 2 + 1] = nibble_to_hex_char(lo, uppercase)
|
||||
hex_buf[nbytes * 2] = '\0'
|
||||
return hex_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# compute_sha1 - 计算字符串的 SHA1,返回前 16 个十六进制字符(与 Projectrans.py 一致)
|
||||
# ============================================================
|
||||
def compute_sha1(pool: memhub.MemBuddy*, content: str) -> str:
|
||||
"""计算字符串的 SHA1,返回前 16 个十六进制字符(用于文件命名)"""
|
||||
if content is None or pool is None:
|
||||
return None
|
||||
|
||||
# 构造 sha1 对象(__init__ 会初始化 state/count/buf)
|
||||
# ctx 在栈上分配(alloca),函数内使用完即丢弃,无需堆分配
|
||||
ctx: rawptr[hashlib.sha1] = hashlib.sha1()
|
||||
if ctx is None: return None
|
||||
|
||||
# 计算摘要
|
||||
ctx.update(content)
|
||||
digest: bytes = pool.alloc(hashlib.SHA1_DIGEST_LEN)
|
||||
if digest is None: return None
|
||||
ctx.final(digest)
|
||||
|
||||
# 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符)
|
||||
return bytes_to_hex(pool, digest, 8, 0, 0)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# is_vp_at - 检查路径段是否以 .vp 后缀结尾
|
||||
# ============================================================
|
||||
def is_vp_at(p: str, start: sizet, plen: sizet) -> int:
|
||||
"""检查 p[start, start+plen) 是否以 .vp 后缀结尾(1=是,0=否)。
|
||||
|
||||
不再识别 .py(移除 vp -> py 后缀识别回退:Viper 源文件仅 .vp)。
|
||||
"""
|
||||
if p is None or plen <= 3:
|
||||
return 0
|
||||
base: sizet = start + plen - 3
|
||||
if p[base] == '.' and p[base + 1] == 'v' and p[base + 2] == 'p':
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# JoinPath - 拼接两个路径段为 a/b
|
||||
# ============================================================
|
||||
def JoinPath(a: str, b: str) -> str:
|
||||
"""拼接路径段为 "a/b"(stdlib.malloc 分配,调用方负责 free),失败返回 None"""
|
||||
if a is None or b is None:
|
||||
return None
|
||||
a_len: sizet = string.strlen(a)
|
||||
b_len: sizet = string.strlen(b)
|
||||
total_len: sizet = a_len + b_len + 2
|
||||
buf: str = stdlib.malloc(total_len)
|
||||
if buf is None: return None
|
||||
viperlib.snprintf(buf, total_len, "%s/%s", a, b)
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# read_file_to_buf - 读取整个文件到缓冲区(null 终止)
|
||||
# ============================================================
|
||||
def read_file_to_buf(path: str, buf_size: sizet) -> bytes:
|
||||
"""读取文件到 stdlib.malloc 缓冲区并保证 null 终止
|
||||
|
||||
返回缓冲区(调用方负责 free);打开失败/空文件/分配失败返回 None。
|
||||
合并自 Phase2/StubMerger/IncludesScanner 的重复"打开+读取+终止"序列。
|
||||
"""
|
||||
if path is None or buf_size <= 0: return None
|
||||
sf: rawptr[fileio.File] = fileio.File(path, fileio.MODE.R)
|
||||
if sf.closed: return None
|
||||
buf: bytes = stdlib.malloc(buf_size)
|
||||
if buf is None:
|
||||
sf.close()
|
||||
return None
|
||||
br: int64 = sf.read_all(buf, buf_size)
|
||||
sf.close()
|
||||
if br <= 0:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
if br < buf_size:
|
||||
buf[br] = 0
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PathToModuleName - 文件路径转模块名
|
||||
# ============================================================
|
||||
def PathToModuleName(path: str, strip_includes_prefix: int) -> str:
|
||||
"""将文件路径转换为模块名(stdlib.malloc 分配,调用方负责 free)
|
||||
|
||||
strip_includes_prefix=1 时跳过 includes/ 前缀(如 includes/ast/__init__.vp → ast)。
|
||||
特殊处理 __init__.vp:pkg/__init__.vp → pkg(而非 pkg.__init__)。
|
||||
合并自 StubMerger._PathToModuleName / IncludesScanner 内联模块名计算。
|
||||
"""
|
||||
if path is None:
|
||||
return None
|
||||
plen: sizet = string.strlen(path)
|
||||
# 跳过 includes/ 或 includes\ 前缀(Windows 反斜杠兼容)
|
||||
prefix_len: sizet = 9
|
||||
path_start: sizet = 0
|
||||
if strip_includes_prefix != 0 and plen > prefix_len and string.strncmp(path, "includes", 8) == 0:
|
||||
psep_ch: char = path[8]
|
||||
if psep_ch == '/' or psep_ch == '\\':
|
||||
path_start = prefix_len
|
||||
plen = plen - prefix_len
|
||||
# 去掉 .vp 后缀(Viper 源文件仅 .vp,不再识别 .py)
|
||||
if is_vp_at(path, path_start, plen) != 0:
|
||||
plen -= 3
|
||||
if plen == 0:
|
||||
return None
|
||||
# 检查是否以 /__init__ 或 \__init__ 结尾(包的 __init__.vp)
|
||||
# 同时支持 / 和 \ 两种分隔符(TPC 写入的路径可能混合使用)
|
||||
if plen > 9:
|
||||
tail_off: sizet = path_start + plen - 9
|
||||
sep_char: char = path[tail_off]
|
||||
if (sep_char == '/' or sep_char == '\\') \
|
||||
and path[tail_off + 1] == '_' and path[tail_off + 2] == '_' \
|
||||
and path[tail_off + 3] == 'i' and path[tail_off + 4] == 'n' and path[tail_off + 5] == 'i' \
|
||||
and path[tail_off + 6] == 't' and path[tail_off + 7] == '_' and path[tail_off + 8] == '_':
|
||||
# 去掉 分隔符+__init__ 后缀,plen 就是包名部分长度
|
||||
plen = tail_off - path_start
|
||||
if plen == 0:
|
||||
return None
|
||||
# 复制并替换 / 为 .
|
||||
result: str = stdlib.malloc(plen + 1)
|
||||
if result is None:
|
||||
return None
|
||||
for ri in range(plen):
|
||||
ch: char = path[path_start + ri]
|
||||
if ch == '/' or ch == '\\':
|
||||
result[ri] = '.'
|
||||
else:
|
||||
result[ri] = ch
|
||||
result[plen] = '\0'
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CleanDir - 递归删除目录中所有文件和子目录(保留 dir_path 本身;用于 --clean)
|
||||
# ============================================================
|
||||
def CleanDir(dir_path: str) -> int:
|
||||
"""递归删除目录中所有文件和子目录,保留 dir_path 本身,返回删除的文件数,-1 表示错误"""
|
||||
if dir_path is None:
|
||||
return -1
|
||||
dir_len: sizet = string.strlen(dir_path)
|
||||
pattern: bytes = stdlib.malloc(dir_len + 8)
|
||||
if pattern is None:
|
||||
return -1
|
||||
viperlib.snprintf(pattern, dir_len + 8, "%s/*", dir_path)
|
||||
|
||||
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
if find_data is None:
|
||||
stdlib.free(pattern)
|
||||
return -1
|
||||
string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
|
||||
handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data)
|
||||
if handle == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
stdlib.free(pattern)
|
||||
stdlib.free(find_data)
|
||||
return 0
|
||||
|
||||
deleted: int = 0
|
||||
while True:
|
||||
fname: str = find_data.cFileName
|
||||
if fname is not None:
|
||||
# 跳过 . 和 ..
|
||||
if fname[0] == '.':
|
||||
if fname[1] == '\0':
|
||||
fname = None
|
||||
elif fname[1] == '.' and fname[2] == '\0':
|
||||
fname = None
|
||||
if fname is not None:
|
||||
full_path: bytes = JoinPath(dir_path, fname)
|
||||
if full_path is not None:
|
||||
# 检查是否为目录(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
is_dir: uint32 = find_data.dwFileAttributes & w32.win32file.FILE_ATTRIBUTE_DIRECTORY
|
||||
if is_dir != 0:
|
||||
# 递归清理子目录中的文件
|
||||
sub_deleted: int = CleanDir(full_path)
|
||||
if sub_deleted > 0:
|
||||
deleted += sub_deleted
|
||||
# 删除空子目录(RemoveDirectoryA 要求目录为空)
|
||||
w32.win32file.RemoveDirectoryA(full_path)
|
||||
else:
|
||||
# 删除文件
|
||||
if w32.win32file.DeleteFileA(full_path) != 0:
|
||||
deleted += 1
|
||||
stdlib.free(full_path)
|
||||
|
||||
if w32.win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
|
||||
w32.win32file.FindClose(handle)
|
||||
stdlib.free(pattern)
|
||||
stdlib.free(find_data)
|
||||
return deleted
|
||||
+444
-282
File diff suppressed because it is too large.
Load diff
+3128
-556
File diff suppressed because it is too large.
Load diff
@@ -1,3 +1 @@
|
||||
# ============================================================
|
||||
# StubGen 包入口
|
||||
# ============================================================
|
||||
# StubGen
|
||||
File diff suppressed because it is too large.
Load diff
@@ -12,7 +12,7 @@ import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Gen.Translator as HandlesTranslator
|
||||
import lib.Phase.BuildPipeline as BuildPipeline
|
||||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
@@ -26,52 +26,39 @@ import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
|
||||
# ============================================================
|
||||
# StubMergerCollect - StubMerger 拆分(阶段 E):StubMergerCollect
|
||||
# StubMergerCollect - 切片路径构建与 stub 文件 SHA1 收集
|
||||
#
|
||||
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
|
||||
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
|
||||
# StubMerger._xxx 访问(main.vp 先例)。
|
||||
# 函数实现直接位于本模块,调用方经本模块前缀访问;全局变量跨模块经 StubMerger._xxx 访问。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _sliced_path - 构建切片路径(stdlib.malloc 分配,调用者负责 free)
|
||||
# _sliced_path - 构建切片路径(stdlib.malloc 分配,调用者负责 free;level>0 时自动调 BuildPipeline.ensure_dir 建子目录)
|
||||
#
|
||||
# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录:
|
||||
# level=0 → {temp_dir}/{sha1}.{ext}
|
||||
# level=1 → {temp_dir}/b7/{sha1}.{ext}
|
||||
# level=2 → {temp_dir}/b7/90/{sha1}.{ext}
|
||||
# 按 Config.Sha1SliceLevel 分散到 SHA1 前缀子目录:level=0 → {temp_dir}/{sha1}.{ext};level=1 → {temp_dir}/b7/{sha1}.{ext};level=2 → {temp_dir}/b7/90/{sha1}.{ext}
|
||||
#
|
||||
# 自动调用 BuildPipeline.ensure_dir 创建子目录(level>0 时)。
|
||||
#
|
||||
# Args:
|
||||
# temp_dir: 基础目录
|
||||
# td_len: temp_dir 长度(避免重复 strlen)
|
||||
# sha1: SHA1 字符串
|
||||
# ext: 文件扩展名(如 "stub.ll")
|
||||
#
|
||||
# Returns:
|
||||
# 完整路径(stdlib.malloc 分配,需 stdlib.free),None 失败
|
||||
# Args: temp_dir 基础目录;td_len temp_dir 长度(避免重复 strlen);sha1 SHA1 字符串;ext 文件扩展名(如 "stub.ll")
|
||||
# Returns: 完整路径(stdlib.malloc 分配,需 stdlib.free),None 失败
|
||||
# ============================================================
|
||||
def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str:
|
||||
def _sliced_path(temp_dir: str, td_len: sizet, sha1: str, ext: str) -> str:
|
||||
"""构建切片路径(stdlib.malloc 分配,调用者负责 free)
|
||||
|
||||
level>0 时自动调用 ensure_dir 创建子目录。
|
||||
"""
|
||||
if temp_dir is None or sha1 is None or ext is None:
|
||||
return None
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
ext_len: t.CSizeT = string.strlen(ext)
|
||||
sha1_len: sizet = string.strlen(sha1)
|
||||
ext_len: sizet = string.strlen(ext)
|
||||
|
||||
# 子目录前缀:复用 Config.slice_subdir(SHA1 切片唯一权威实现,mbuddy 分配无需 free)
|
||||
subdir_buf: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel)
|
||||
sub_len: t.CSizeT = 0
|
||||
sub_len: sizet = 0
|
||||
if subdir_buf is not None:
|
||||
sub_len = string.strlen(subdir_buf)
|
||||
|
||||
# 确保子目录存在: {temp_dir}/{subdir}
|
||||
# 不创建目录会导致 fileio.File(MODE.W) 静默失败(file.closed==True),
|
||||
# 进而 BuildCombinedIR 读不到文件返回 0("BuildCombinedIR 失败")。
|
||||
dir_path_len: t.CSizeT = td_len + sub_len + 2
|
||||
dir_path_len: sizet = td_len + sub_len + 2
|
||||
dir_path: bytes = stdlib.malloc(dir_path_len)
|
||||
if dir_path is not None:
|
||||
viperlib.snprintf(dir_path, dir_path_len, "%s/%s", temp_dir, subdir_buf)
|
||||
@@ -80,7 +67,7 @@ def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str:
|
||||
|
||||
# 构建完整路径
|
||||
path: str = None
|
||||
path_len: t.CSizeT = 0
|
||||
path_len: sizet = 0
|
||||
if sub_len > 0:
|
||||
path_len = td_len + sub_len + sha1_len + ext_len + 4
|
||||
path = stdlib.malloc(path_len)
|
||||
@@ -94,24 +81,14 @@ def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str:
|
||||
|
||||
return path
|
||||
# ============================================================
|
||||
# _collect_stub_sha1s - 递归扫描子目录,收集 .stub.ll 文件的 SHA1
|
||||
# _collect_stub_sha1s - 递归扫描子目录,收集 .stub.ll 文件的 SHA1(从文件名提取)
|
||||
#
|
||||
# 根据 level 递归扫描子目录:
|
||||
# level=0 → 扫描 {base_dir}/*.stub.ll,从文件名提取 SHA1
|
||||
# level>0 → 扫描 {base_dir}/* 的子目录,对每个子目录递归调用
|
||||
# level=0 → 扫描 {base_dir}/*.stub.ll;level>0 → 扫描 {base_dir}/* 的子目录并对每个子目录递归调用。
|
||||
#
|
||||
# Args:
|
||||
# base_dir: 当前扫描目录
|
||||
# bd_len: base_dir 长度
|
||||
# level: 剩余递归层数
|
||||
# out_arr: 输出数组(每个 SHA1 17 字节 = 16字符 + null)
|
||||
# out_count: 当前已收集数量
|
||||
# max_count: 最大数量
|
||||
#
|
||||
# Returns:
|
||||
# 收集后的总数量
|
||||
# Args: base_dir 当前扫描目录;bd_len base_dir 长度;level 剩余递归层数;out_arr 输出数组(每个 SHA1 17 字节 = 16字符 + null);out_count 当前已收集数量;max_count 最大数量
|
||||
# Returns: 收集后的总数量
|
||||
# ============================================================
|
||||
def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int,
|
||||
def _collect_stub_sha1s(base_dir: str, bd_len: sizet, level: int,
|
||||
out_arr: str, out_count: int, max_count: int) -> int:
|
||||
"""递归扫描子目录,收集 .stub.ll 文件的 SHA1"""
|
||||
if base_dir is None or out_arr is None:
|
||||
@@ -119,7 +96,7 @@ def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int,
|
||||
if out_count >= max_count:
|
||||
return out_count
|
||||
|
||||
find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
find_data: rawptr[win32file.WIN32_FIND_DATAA] = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
if find_data is None:
|
||||
return out_count
|
||||
string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
@@ -159,7 +136,7 @@ def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int,
|
||||
if handle != win32base.INVALID_HANDLE_VALUE:
|
||||
while True:
|
||||
# 检查是否是目录(FILE_ATTRIBUTE_DIRECTORY = 0x10 = 16)
|
||||
attrs: t.CUInt32T = find_data.dwFileAttributes
|
||||
attrs: uint32 = find_data.dwFileAttributes
|
||||
if (attrs & 16) != 0:
|
||||
fname = find_data.cFileName
|
||||
if fname is not None:
|
||||
@@ -174,7 +151,7 @@ def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int,
|
||||
# 构建子目录路径并递归扫描
|
||||
sub_dir: str = Utils.JoinPath(base_dir, fname)
|
||||
if sub_dir is not None:
|
||||
sub_dir_len: t.CSizeT = string.strlen(sub_dir)
|
||||
sub_dir_len: sizet = string.strlen(sub_dir)
|
||||
out_count = _collect_stub_sha1s(sub_dir, sub_dir_len, level - 1, out_arr, out_count, max_count)
|
||||
stdlib.free(sub_dir)
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
@@ -189,7 +166,7 @@ def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int,
|
||||
# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。
|
||||
# 用于过滤 stub 文件,避免加载 TransPyV 自身源文件(lib/*)的 stub 导致链接失败。
|
||||
# ============================================================
|
||||
def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr,
|
||||
def _load_includes_sha1_set(pool: memhub.MemBuddy*,
|
||||
temp_dir: str,
|
||||
sha1_set: str) -> int:
|
||||
"""从全局内存存储器将 includes 的 SHA1 写入 sha1_set
|
||||
@@ -206,8 +183,8 @@ def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr,
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
if count >= StubMerger.MAX_INCLUDES_SHA1:
|
||||
break
|
||||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||
string.strcpy(sha1_set + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx)
|
||||
idx: sizet = sizet(i) * 17
|
||||
string.strcpy(sha1_set + sizet(count) * 17, StubMerger._sha1_store_arr + idx)
|
||||
count += 1
|
||||
return count
|
||||
# ============================================================
|
||||
@@ -222,21 +199,14 @@ def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int:
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt(人类可读输出)
|
||||
# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt(仅人类可读的调试输出,程序内部不读取,
|
||||
# 机器分析用 PopulateSha1MapStore 填充的全局内存存储器)
|
||||
#
|
||||
# _sha1_map.txt 仅作为人类可读的调试输出,程序内部不读取此文件。
|
||||
# 机器分析使用 PopulateSha1MapStore 填充的全局内存存储器。
|
||||
#
|
||||
# Args:
|
||||
# mb: 内存池
|
||||
# temp_dir: 临时目录(_sha1_map.txt 写入位置)
|
||||
# scan_result: IncludesScanner 扫描结果
|
||||
#
|
||||
# Returns:
|
||||
# 0 成功,非 0 失败
|
||||
# Args: mb 内存池;temp_dir 临时目录(_sha1_map.txt 写入位置);scan_result IncludesScanner 扫描结果
|
||||
# Returns: 0 成功,非 0 失败
|
||||
# ============================================================
|
||||
def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
|
||||
scan_result: IncludesScanner.ScanResult | t.CPtr,
|
||||
def WriteIncludesSha1Map(mb: memhub.MemBuddy*, temp_dir: str,
|
||||
scan_result: rawptr[IncludesScanner.ScanResult],
|
||||
filter_set: str,
|
||||
filter_count: int) -> int:
|
||||
"""将 includes 扫描结果写入 _sha1_map.txt(人类可读输出,程序内部使用内存存储器)
|
||||
@@ -247,19 +217,19 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
|
||||
return 1
|
||||
|
||||
# 构造路径 temp_dir/_sha1_map.txt
|
||||
dir_len: t.CSizeT = string.strlen(temp_dir)
|
||||
dir_len: sizet = string.strlen(temp_dir)
|
||||
map_path: bytes = stdlib.malloc(dir_len + 32)
|
||||
if map_path is None:
|
||||
return 1
|
||||
viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir)
|
||||
|
||||
# 打开文件写入(CREATE_ALWAYS)
|
||||
f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.W)
|
||||
f: rawptr[fileio.File] = fileio.File(map_path, fileio.MODE.W)
|
||||
if f.closed:
|
||||
return 1
|
||||
|
||||
# 写入每个 include 条目: {sha1}:includes/{rel_path}\n
|
||||
entry_size_w: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
entry_size_w: sizet = IncludesScanner.FileEntry.__sizeof__()
|
||||
line_buf: bytes = stdlib.malloc(512)
|
||||
if line_buf is None:
|
||||
f.close()
|
||||
@@ -267,8 +237,8 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
|
||||
|
||||
written_count: int = 0
|
||||
for i in range(scan_result.Count):
|
||||
ea_w: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_w
|
||||
ent_w: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_w, t.CPtr))
|
||||
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
|
||||
# 若提供过滤集合,只写入集合中的条目
|
||||
@@ -276,7 +246,7 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
|
||||
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: t.CSizeT = string.strlen(line_buf)
|
||||
line_len_w: sizet = string.strlen(line_buf)
|
||||
f.write(line_buf, line_len_w)
|
||||
written_count += 1
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Gen.Translator as HandlesTranslator
|
||||
import lib.Phase.BuildPipeline as BuildPipeline
|
||||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
@@ -27,21 +27,16 @@ import lib.Stub.StubMerger as StubMerger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StubMergerIR - StubMerger 拆分(阶段 E):StubMergerIR
|
||||
# StubMergerIR - IR 文本去重/注释与模块名-SHA1 映射工具
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# IsDeclOnlyModule - 判断模块是否为纯声明文件
|
||||
# IsDeclOnlyModule - 判断模块是否为纯声明文件(读 {temp_dir}/{sha1}.text.ll 扫描是否含 "define " 行)
|
||||
#
|
||||
# 读取 {temp_dir}/{sha1}.text.ll,扫描是否含 "define " 行:
|
||||
# 返回 1 = 纯声明(无函数体,如 stdio.vp 全 pass),无需 .obj
|
||||
# 返回 0 = 实现文件(含 define 函数体)
|
||||
# 返回 -1 = text.ll 不存在/无法判断
|
||||
#
|
||||
# 与 Phase B+(Phase2.vp 编译缺失 includes 时)的内联判断逻辑一致,
|
||||
# 供 Phase C 链接时区分"声明文件无需 .obj"与"实现文件缺失"。
|
||||
# 返回 1 = 纯声明(无函数体,如全 pass 的模块,无需 .obj);0 = 实现文件(含 define 函数体);-1 = text.ll 不存在/无法判断。
|
||||
# 与 Phase B+ 编译缺失 includes 时的内联判断逻辑一致,供 Phase C 链接时区分「声明文件无需 .obj」与「实现文件缺失」。
|
||||
# ============================================================
|
||||
def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int:
|
||||
def IsDeclOnlyModule(temp_dir: str, td_len: sizet, sha1: str) -> int:
|
||||
"""判断模块是否为纯声明文件(text.ll 无 define 行)"""
|
||||
if temp_dir is None or sha1 is None:
|
||||
return -1
|
||||
@@ -53,7 +48,7 @@ def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int:
|
||||
if tf_d.closed:
|
||||
return -1
|
||||
tbuf_d: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
|
||||
tbr_d: t.CInt64T = 0
|
||||
tbr_d: int64 = 0
|
||||
if tbuf_d is not None:
|
||||
tbr_d = tf_d.read_all(tbuf_d, StubMerger.STUB_READ_BUF_SIZE)
|
||||
tf_d.close()
|
||||
@@ -65,17 +60,15 @@ def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int:
|
||||
return 1
|
||||
if tbr_d < StubMerger.STUB_READ_BUF_SIZE:
|
||||
tbuf_d[tbr_d] = '\0'
|
||||
else:
|
||||
tbuf_d[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0'
|
||||
# 逐行扫描:找 "define " 行即为实现文件
|
||||
tpos_d: t.CSizeT = 0
|
||||
tpos_d: sizet = 0
|
||||
while tpos_d < tbr_d:
|
||||
tls_d: t.CSizeT = tpos_d
|
||||
tls_d: sizet = tpos_d
|
||||
while tpos_d < tbr_d:
|
||||
if tbuf_d[tpos_d] == '\n':
|
||||
break
|
||||
tpos_d += 1
|
||||
tll_d: t.CSizeT = tpos_d - tls_d
|
||||
tll_d: sizet = tpos_d - tls_d
|
||||
if tpos_d < tbr_d:
|
||||
tpos_d += 1
|
||||
if tll_d >= 7 and string.strncmp(tbuf_d + tls_d, "define ", 7) == 0:
|
||||
@@ -86,29 +79,24 @@ def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int:
|
||||
# ============================================================
|
||||
# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define
|
||||
#
|
||||
# 逐字节strncmp搜索 func_sig(如 @"sha1.func"(/ @printf( ),每次
|
||||
# 找到匹配后检查行首是否以 "declare " 或 "define " 开头,跳过 call 语句。
|
||||
# 避免 strstr 子串匹配误匹配 call ... @"func"(...) 中的 @"func"( 子串。
|
||||
# 逐字节 strncmp 搜索 func_sig(如 @"sha1.func"(/ @printf(),命中后检查行首是否为 "declare "/"define ",跳过 call 语句
|
||||
# (避免 strstr 子串匹配误命中 call ... @"func"(...)。
|
||||
#
|
||||
# Args:
|
||||
# out_buf: 已有的 IR 文本缓冲区
|
||||
# func_sig: 函数签名片段,如 @"sha1.func"(/ @printf(
|
||||
#
|
||||
# Returns:
|
||||
# 1=已存在 declare/define, 0=不存在
|
||||
# Args: out_buf 已有 IR 文本缓冲区;func_sig 函数签名片段,如 @"sha1.func"(/ @printf(
|
||||
# Returns: 1=已存在 declare/define, 0=不存在
|
||||
# ============================================================
|
||||
def _IsFuncDeclaredOrDefined(out_buf: bytes, func_sig: str) -> int:
|
||||
"""检查 out_buf 中是否已有函数的 declare 或 define 行"""
|
||||
if out_buf is None or func_sig is None:
|
||||
return 0
|
||||
sig_len: t.CSizeT = string.strlen(func_sig)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
sig_len: sizet = string.strlen(func_sig)
|
||||
out_len: sizet = string.strlen(out_buf)
|
||||
if sig_len == 0 or out_len == 0 or sig_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
pos: sizet = 0
|
||||
for pos in range(0, out_len - sig_len + 1):
|
||||
if string.strncmp(out_buf + pos, func_sig, sig_len) == 0:
|
||||
ls: t.CSizeT = pos
|
||||
ls: sizet = pos
|
||||
while ls > 0 and out_buf[ls - 1] != '\n':
|
||||
ls -= 1
|
||||
if string.strncmp(out_buf + ls, "declare ", 8) == 0:
|
||||
@@ -127,14 +115,14 @@ def _CommentOutDeclareInBuf(out_buf: bytes, func_sig: str) -> int:
|
||||
"""在 out_buf 中搜索 declare 行(包含 func_sig),将其注释掉"""
|
||||
if out_buf is None or func_sig is None:
|
||||
return 0
|
||||
sig_len: t.CSizeT = string.strlen(func_sig)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
sig_len: sizet = string.strlen(func_sig)
|
||||
out_len: sizet = string.strlen(out_buf)
|
||||
if sig_len == 0 or out_len == 0 or sig_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
pos: sizet = 0
|
||||
while pos + sig_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, func_sig, sig_len) == 0:
|
||||
ls: t.CSizeT = pos
|
||||
ls: sizet = pos
|
||||
while ls > 0 and out_buf[ls - 1] != '\n':
|
||||
ls -= 1
|
||||
if string.strncmp(out_buf + ls, "declare ", 8) == 0:
|
||||
@@ -160,11 +148,11 @@ def _CommentOutGlobalInBuf(out_buf: bytes, global_name: str) -> int:
|
||||
"""
|
||||
if out_buf is None or global_name is None:
|
||||
return 0
|
||||
name_len: t.CSizeT = string.strlen(global_name)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
name_len: sizet = string.strlen(global_name)
|
||||
out_len: sizet = string.strlen(out_buf)
|
||||
if name_len == 0 or out_len == 0 or name_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
pos: sizet = 0
|
||||
commented: int = 0
|
||||
while pos + name_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, global_name, name_len) == 0:
|
||||
@@ -183,11 +171,11 @@ def _HasGlobalInBuf(out_buf: bytes, global_name: str) -> int:
|
||||
"""
|
||||
if out_buf is None or global_name is None:
|
||||
return 0
|
||||
name_len: t.CSizeT = string.strlen(global_name)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
name_len: sizet = string.strlen(global_name)
|
||||
out_len: sizet = string.strlen(out_buf)
|
||||
if name_len == 0 or out_len == 0 or name_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
pos: sizet = 0
|
||||
while pos + name_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, global_name, name_len) == 0:
|
||||
# 确认是行首(前一个是换行或 pos==0)
|
||||
@@ -211,17 +199,17 @@ def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int:
|
||||
"""
|
||||
if out_buf is None or type_name_prefix is None:
|
||||
return 0
|
||||
prefix_len: t.CSizeT = string.strlen(type_name_prefix)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
prefix_len: sizet = string.strlen(type_name_prefix)
|
||||
out_len: sizet = string.strlen(out_buf)
|
||||
if prefix_len == 0 or out_len == 0 or prefix_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
pos: sizet = 0
|
||||
while pos + prefix_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0:
|
||||
# 确认是行首(前一个是换行或 pos==0)
|
||||
if pos == 0 or out_buf[pos - 1] == '\n':
|
||||
# 检查后面是否是 " = type opaque"
|
||||
p: t.CSizeT = pos + prefix_len
|
||||
p: sizet = pos + prefix_len
|
||||
# 跳过空格
|
||||
while p < out_len and out_buf[p] == ' ':
|
||||
p += 1
|
||||
@@ -239,15 +227,8 @@ def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int:
|
||||
# ============================================================
|
||||
# _is_submodule_of_imported - 检查模块名是否是已导入包的子模块
|
||||
#
|
||||
# deps.txt 只记录直接导入的模块名(如 "ast"),但包的 __init__.vp
|
||||
# 内部 from .lexer import Lexer 会让 IR 引用 ast.lexer 子模块类型。
|
||||
# 当模块名包含 '.' 时,检查其顶层包名是否在 deps_buf 中。
|
||||
#
|
||||
# 例如:
|
||||
# deps_buf = "ast stdio string"
|
||||
# mod_name = "ast.lexer" → 顶层包 "ast" 在 deps_buf 中 → 返回 1
|
||||
# mod_name = "ast.token" → 顶层包 "ast" 在 deps_buf 中 → 返回 1
|
||||
# mod_name = "foo.bar" → 顶层包 "foo" 不在 deps_buf 中 → 返回 0
|
||||
# deps_buf 只记录直接导入的模块名(如 "ast"),但包的 __init__.vp 内部 from .lexer import Lexer 会让 IR 引用 ast.lexer
|
||||
# 子模块类型;模块名含 '.' 时检查其顶层包名是否在 deps_buf 中(deps_buf = "ast stdio string" 时 "ast.lexer" → 1,"foo.bar" → 0)。
|
||||
# ============================================================
|
||||
def _is_submodule_of_imported(deps_buf: str, mod_name: str) -> int:
|
||||
"""检查 mod_name 是否是 deps_buf 中已导入包的子模块"""
|
||||
@@ -257,12 +238,12 @@ def _is_submodule_of_imported(deps_buf: str, mod_name: str) -> int:
|
||||
dot_pos: str = string.strchr(mod_name, 46) # '.' = 46
|
||||
if dot_pos is None:
|
||||
return 0
|
||||
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_pos) - t.CUInt64T(mod_name))
|
||||
pkg_len: sizet = sizet(uint64(dot_pos) - uint64(mod_name))
|
||||
if pkg_len == 0 or pkg_len >= 256:
|
||||
return 0
|
||||
# 构造顶层包名(截断到 '.' 之前)
|
||||
# 直接在 mod_name 上临时截断检查,避免分配
|
||||
saved_ch: t.CChar = mod_name[pkg_len]
|
||||
saved_ch: char = mod_name[pkg_len]
|
||||
mod_name[pkg_len] = '\0'
|
||||
result: int = GenApi.is_module_imported(deps_buf, mod_name)
|
||||
mod_name[pkg_len] = saved_ch
|
||||
@@ -278,11 +259,11 @@ def _HasFullTypeDefinition(out_buf: bytes, type_name_prefix: str) -> int:
|
||||
"""检查 out_buf 中是否已有 type_name_prefix 的完整定义"""
|
||||
if out_buf is None or type_name_prefix is None:
|
||||
return 0
|
||||
prefix_len: t.CSizeT = string.strlen(type_name_prefix)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
prefix_len: sizet = string.strlen(type_name_prefix)
|
||||
out_len: sizet = string.strlen(out_buf)
|
||||
if prefix_len == 0 or out_len == 0 or prefix_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
pos: sizet = 0
|
||||
while pos + prefix_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0:
|
||||
# 确认是行首(前一个是换行或 pos==0),且未被注释(行首不是 ';')
|
||||
@@ -293,7 +274,7 @@ def _HasFullTypeDefinition(out_buf: bytes, type_name_prefix: str) -> int:
|
||||
is_line_start = 1
|
||||
if is_line_start == 1:
|
||||
# 检查后面是否是 " = type {" 或 " = type <"
|
||||
p: t.CSizeT = pos + prefix_len
|
||||
p: sizet = pos + prefix_len
|
||||
while p < out_len and out_buf[p] == ' ':
|
||||
p += 1
|
||||
if p < out_len and out_buf[p] == '=':
|
||||
@@ -315,7 +296,7 @@ def _HasFullTypeDefinition(out_buf: bytes, type_name_prefix: str) -> int:
|
||||
# 返回两个数组(sha1_list 和 mod_list),长度存储在 count 中。
|
||||
# 所有内存由 stdlib.malloc 分配,调用者负责释放。
|
||||
# ============================================================
|
||||
def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
|
||||
def _BuildIncludesSha1Map(temp_dir: str, td_len: sizet,
|
||||
sha1_list: str,
|
||||
mod_list: str) -> int:
|
||||
"""从全局内存存储器复制 sha1→module_name 映射到调用者数组
|
||||
@@ -331,26 +312,17 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
if count >= StubMerger.MAX_INCLUDES:
|
||||
break
|
||||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||||
string.strcpy(sha1_list + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx)
|
||||
string.strcpy(mod_list + t.CSizeT(count) * 64, StubMerger._sha1_store_mod + idx2)
|
||||
idx: sizet = sizet(i) * 17
|
||||
idx2: sizet = sizet(i) * 64
|
||||
string.strcpy(sha1_list + sizet(count) * 17, StubMerger._sha1_store_arr + idx)
|
||||
string.strcpy(mod_list + sizet(count) * 64, StubMerger._sha1_store_mod + idx2)
|
||||
count += 1
|
||||
return count
|
||||
# ============================================================
|
||||
# _FindSha1ByModName - 从模块名查找 SHA1(精确匹配)
|
||||
# _FindSha1ByModName - 从模块名查找 SHA1(精确匹配;供依赖图分析「模块名 → SHA1」)
|
||||
#
|
||||
# 在 sha1_arr/mod_arr 映射中查找模块名对应的 SHA1。
|
||||
# 用于依赖图分析:模块名 → SHA1。
|
||||
#
|
||||
# Args:
|
||||
# sha1_arr: SHA1 数组(每个 17 字节)
|
||||
# mod_arr: 模块名数组(每个 64 字节)
|
||||
# count: 映射条目数
|
||||
# mod_name: 要查找的模块名
|
||||
#
|
||||
# Returns:
|
||||
# SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None
|
||||
# Args: sha1_arr SHA1 数组(每个 17 字节);mod_arr 模块名数组(每个 64 字节);count 映射条目数;mod_name 要查找的模块名
|
||||
# Returns: SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None
|
||||
# ============================================================
|
||||
def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
|
||||
count: int, mod_name: str) -> str:
|
||||
@@ -365,46 +337,41 @@ def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
|
||||
return None
|
||||
# 第一遍:精确匹配
|
||||
for i in range(count):
|
||||
idx: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(mod_arr + idx, mod_name) == 0:
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
idx: sizet = sizet(i) * 64
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
|
||||
# (热点:本函数全表逐条 strcmp 查名)。
|
||||
if mod_arr[idx] == mod_name[0] and string.strcmp(mod_arr + idx, mod_name) == 0:
|
||||
sidx: sizet = sizet(i) * 17
|
||||
return sha1_arr + sidx
|
||||
# 第二遍:包名回退("ast" → "ast.__init__")
|
||||
nm_len: t.CSizeT = string.strlen(mod_name)
|
||||
nm_len: sizet = string.strlen(mod_name)
|
||||
init_buf: bytes = stdlib.malloc(nm_len + 12)
|
||||
if init_buf is not None:
|
||||
viperlib.snprintf(init_buf, nm_len + 12, "%s.__init__", mod_name)
|
||||
for i in range(count):
|
||||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(mod_arr + idx2, init_buf) == 0:
|
||||
sidx2: t.CSizeT = t.CSizeT(i) * 17
|
||||
idx2: sizet = sizet(i) * 64
|
||||
if mod_arr[idx2] == init_buf[0] and string.strcmp(mod_arr + idx2, init_buf) == 0:
|
||||
sidx2: sizet = sizet(i) * 17
|
||||
stdlib.free(init_buf)
|
||||
return sha1_arr + sidx2
|
||||
stdlib.free(init_buf)
|
||||
return None
|
||||
# ============================================================
|
||||
# _AddSha1ToSet - 将 SHA1 加入集合(去重)
|
||||
# _AddSha1ToSet - 将 SHA1 加入集合(去重;已在集合中则 count 不变)
|
||||
#
|
||||
# 检查 SHA1 是否已在集合中,若不在则加入。返回新的 count。
|
||||
#
|
||||
# Args:
|
||||
# set_buf: SHA1 集合缓冲区(每个 17 字节)
|
||||
# count: 当前集合中的 SHA1 数量
|
||||
# sha1: 要加入的 SHA1
|
||||
#
|
||||
# Returns:
|
||||
# 新的 count(如果已存在则不变)
|
||||
# Args: set_buf SHA1 集合缓冲区(每个 17 字节);count 当前集合中的 SHA1 数量;sha1 要加入的 SHA1
|
||||
# Returns: 新的 count
|
||||
# ============================================================
|
||||
def _AddSha1ToSet(set_buf: str, count: int, sha1: str) -> int:
|
||||
"""将 SHA1 加入集合,返回新 count"""
|
||||
if set_buf is None or sha1 is None:
|
||||
return count
|
||||
for i in range(count):
|
||||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||
idx: sizet = sizet(i) * 17
|
||||
if string.strcmp(set_buf + idx, sha1) == 0:
|
||||
return count
|
||||
if count < StubMerger.MAX_INCLUDES_SHA1:
|
||||
idx: t.CSizeT = t.CSizeT(count) * 17
|
||||
idx: sizet = sizet(count) * 17
|
||||
string.strcpy(set_buf + idx, sha1)
|
||||
return count + 1
|
||||
return count
|
||||
@@ -12,7 +12,7 @@ import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Gen.Translator as HandlesTranslator
|
||||
import lib.Phase.BuildPipeline as BuildPipeline
|
||||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
@@ -26,23 +26,152 @@ import lib.Stub.StubMerger as StubMerger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StubMergerStore - StubMerger 拆分(阶段 E):StubMergerStore
|
||||
# StubMergerStore - 全局 SHA1 映射存储器(sha1→模块名/相对路径)读写
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# PopulateSha1MapStore - 从扫描结果填充全局 SHA1 映射存储器
|
||||
# 导入上下文记账(单一真源)
|
||||
#
|
||||
# 遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。
|
||||
# 模块名通过 _PathToModuleName(includes/rel_path) 计算。
|
||||
# 内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||||
# 「AST 导入语句 → imported_modules / from_imports」的记账口径必须唯一。
|
||||
# 翻译期(ImportsGenMixin.translate_import)与 vpi 注入期(VpiReader 顶层
|
||||
# 遍历)此前各写一份:注入期漏掉 `import X as Y → from_imports "Y:X"`(别名
|
||||
# 反查模块真名的唯一入口,见 LookupModNameByAlias)以及 `import a.b.c →
|
||||
# imported_modules "a"`(顶层包名放行 is_module_imported)。前者使注解里的
|
||||
# `TSpec.TypeSpec*` 在 _forward_declare_ptr_from_node 4a'/4b 全落空 → 退化
|
||||
# 为 Ptr(i8)(现场:GenTypes.VarEntry.Spec.PtrLevel 属性访问失败);后者使
|
||||
# 包限定解析在 stub 上下文里被误判"未导入"。
|
||||
#
|
||||
# Args:
|
||||
# scan_result: IncludesScanner 扫描结果
|
||||
#
|
||||
# Returns:
|
||||
# 填充的条目数,-1 表示失败
|
||||
# 现统一到本模块,两侧只保留各自的特有副作用(SHA1 校验 / reexport 注册 /
|
||||
# add_visible_struct),字符串记账一律走下面这组函数。ImportCtx 只承载两个
|
||||
# 上下文串(Viper 无多返回值,用 pool 分配的小 struct 传出)。
|
||||
# ============================================================
|
||||
def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> int:
|
||||
|
||||
class ImportCtx:
|
||||
"""导入上下文容器:两个空格分隔串(ImportedModules / FromImports)"""
|
||||
ImportedModules: str
|
||||
FromImports: str
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AppendImportedModule - 追加模块名到空格分隔列表(纯记账,无索引副作用)
|
||||
# ============================================================
|
||||
def AppendImportedModule(pool: memhub.MemBuddy*, cur: str, name: str) -> str:
|
||||
"""追加模块名到空格分隔列表(pool 分配),返回新列表"""
|
||||
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)
|
||||
return buf
|
||||
old_len: sizet = string.strlen(cur)
|
||||
name_len: sizet = string.strlen(name)
|
||||
buf2: str = pool.alloc(old_len + 1 + name_len + 1)
|
||||
if buf2 is not None:
|
||||
string.strcpy(buf2, cur)
|
||||
buf2[old_len] = ' '
|
||||
string.strcpy(buf2 + old_len + 1, name)
|
||||
return buf2
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AppendFromImport - 追加 from-import 映射("local:mod[:orig]" 空格分隔)
|
||||
#
|
||||
# [D7·截断纪律] 旧实现固定 256 缓冲 + snprintf:三者合计超长即被静默截断,
|
||||
# 该条目在查找侧仍被当作合法条目解析出错误的 local/mod/orig ⇒ 跨模块类名/
|
||||
# 别名还原取到错名字(污染 Spec.SourceName)。此处按精确长度分配,无上限。
|
||||
# ============================================================
|
||||
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
|
||||
llen: sizet = string.strlen(local)
|
||||
mlen: sizet = string.strlen(mod)
|
||||
use_orig: int = 0
|
||||
olen: sizet = 0
|
||||
if orig is not None and string.strcmp(orig, local) != 0:
|
||||
use_orig = 1
|
||||
olen = string.strlen(orig)
|
||||
# local ':' mod [':' orig] '\0'
|
||||
need: sizet = llen + 1 + mlen + 1
|
||||
if use_orig != 0:
|
||||
need += 1 + olen
|
||||
entry: str = pool.alloc(need)
|
||||
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
|
||||
old_len: sizet = string.strlen(cur)
|
||||
entry_len: sizet = string.strlen(entry)
|
||||
buf: str = pool.alloc(old_len + 1 + entry_len + 1)
|
||||
if buf is not None:
|
||||
string.strcpy(buf, cur)
|
||||
buf[old_len] = ' '
|
||||
string.strcpy(buf + old_len + 1, entry)
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AllocImportCtx - 用两个既有上下文串构造记账容器
|
||||
# ============================================================
|
||||
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
|
||||
ctx.ImportedModules = imported_modules
|
||||
ctx.FromImports = from_imports
|
||||
return ctx
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NotePlainImport - 记账 `import X` / `import X as Y`(就地更新 ctx)
|
||||
#
|
||||
# 有别名:追加别名 `Y`,并写 from-import 映射 "Y:X"——这就是 `LookupModNameByAlias`
|
||||
# 与 `_forward_declare_ptr_from_node` 4a' 反查模块真名的唯一来源,绝不可省。
|
||||
# 无别名:`import a.b.c` 时把顶层包名 `a` 也追加(使 a.b.c 作为属性访问 base
|
||||
# 时 is_module_imported("a") 放行)。
|
||||
# ============================================================
|
||||
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
|
||||
ctx.ImportedModules = AppendImportedModule(pool, ctx.ImportedModules, name)
|
||||
if asname is not None:
|
||||
ctx.ImportedModules = AppendImportedModule(pool, ctx.ImportedModules, asname)
|
||||
ctx.FromImports = AppendFromImport(pool, ctx.FromImports, asname, name, None)
|
||||
else:
|
||||
dot_ptr: str = string.strstr(name, ".")
|
||||
if dot_ptr is not None:
|
||||
pkg_len: sizet = sizet(uint64(dot_ptr) - uint64(name))
|
||||
if pkg_len > 0 and pkg_len < 256:
|
||||
pkg_buf: str = pool.alloc(pkg_len + 1)
|
||||
if pkg_buf is not None:
|
||||
string.strncpy(pkg_buf, name, pkg_len)
|
||||
pkg_buf[pkg_len] = '\0'
|
||||
ctx.ImportedModules = AppendImportedModule(
|
||||
pool, ctx.ImportedModules, pkg_buf)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PopulateSha1MapStore - 遍历 ScanResult.Entries 构建 sha1→module_name 映射,填充全局存储器
|
||||
#
|
||||
# 模块名通过 _PathToModuleName(includes/rel_path) 计算;内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||||
# Args: scan_result IncludesScanner 扫描结果
|
||||
# Returns: 填充的条目数,-1 表示失败
|
||||
# ============================================================
|
||||
def PopulateSha1MapStore(scan_result: rawptr[IncludesScanner.ScanResult]) -> int:
|
||||
"""从扫描结果填充全局 SHA1 映射存储器
|
||||
|
||||
遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。
|
||||
@@ -72,17 +201,17 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
|
||||
string.memset(StubMerger._sha1_store_incdir, 0, StubMerger.MAX_INCLUDES * StubMerger.MAX_INC_DIR_LEN)
|
||||
StubMerger._sha1_store_count = 0
|
||||
p_bad: int = 0
|
||||
entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
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")
|
||||
ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p
|
||||
ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||
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:
|
||||
p_bad += 1
|
||||
continue
|
||||
# 构建完整路径 includes/{RelPath}(_PathToModuleName 需要)
|
||||
rp_len: t.CSizeT = string.strlen(ent.RelPath)
|
||||
rp_len: sizet = string.strlen(ent.RelPath)
|
||||
full_path_buf: bytes = stdlib.malloc(rp_len + 10)
|
||||
if full_path_buf is None:
|
||||
p_bad += 1
|
||||
@@ -91,10 +220,10 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
|
||||
mod_name: str = Utils.PathToModuleName(full_path_buf, 1)
|
||||
stdlib.free(full_path_buf)
|
||||
if mod_name is not None:
|
||||
idx: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17
|
||||
idx: sizet = sizet(StubMerger._sha1_store_count) * 17
|
||||
string.strcpy(StubMerger._sha1_store_arr + idx, ent.Sha1)
|
||||
idx2: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64
|
||||
mn_len: t.CSizeT = string.strlen(mod_name)
|
||||
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)
|
||||
else:
|
||||
@@ -102,16 +231,16 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
|
||||
StubMerger._sha1_store_mod[idx2 + 63] = '\0'
|
||||
stdlib.free(mod_name)
|
||||
# 保存 rel_path(供 Phase2 3.5 编译缺失 includes 使用)
|
||||
idx3: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * StubMerger.MAX_REL_PATH_LEN
|
||||
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)
|
||||
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'
|
||||
# 保存所属 includes 根目录(Phase2 预注册/按需编译拼路径用)
|
||||
idx_inc: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||||
idx_inc: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||||
if ent.IncDir is not None:
|
||||
icd_len: t.CSizeT = string.strlen(ent.IncDir)
|
||||
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)
|
||||
else:
|
||||
@@ -119,30 +248,15 @@ def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> in
|
||||
StubMerger._sha1_store_incdir[idx_inc + StubMerger.MAX_INC_DIR_LEN - 1] = '\0'
|
||||
StubMerger._sha1_store_count += 1
|
||||
if p_bad > 0:
|
||||
fb_pbad: str = VLogger.fmt_buf()
|
||||
if fb_pbad is not None:
|
||||
viperlib.snprintf(fb_pbad, 1024, "includes SHA1 存储有 %d 个条目失败", p_bad)
|
||||
VLogger.error(fb_pbad, "StubMerger")
|
||||
VLogger.error(f"includes SHA1 存储有 {p_bad} 个条目失败", "StubMerger")
|
||||
return StubMerger._sha1_store_count
|
||||
# ============================================================
|
||||
# AppendToSha1MapStore - 追加条目到全局 SHA1 映射存储器
|
||||
# AppendToSha1MapStore - 追加 App 模块条目到全局 SHA1 映射存储器(Phase1 先用 PopulateSha1MapStore 填 includes,
|
||||
# Phase2 扫描 App 源文件后调用本函数追加,否则编译 App 自身时跨模块 CDefine 查找命中不到 App 模块)
|
||||
#
|
||||
# Phase1 调用 PopulateSha1MapStore 填充 includes 文件,
|
||||
# Phase2 扫描 App 源文件后调用此函数追加 App 模块条目,
|
||||
# 确保编译 App 自身时跨模块 CDefine 查找能命中 App 模块
|
||||
# (如 StubMerger.StubMerger.MAX_INCLUDES 在编译 Phase2 时通过
|
||||
# _build_source_path_from_sha1 查找 StubMerger 的源路径)。
|
||||
#
|
||||
# 若存储器未初始化(PopulateSha1MapStore 未调用),自动初始化。
|
||||
# 若 SHA1 已存在(去重),跳过。
|
||||
#
|
||||
# Args:
|
||||
# sha1: SHA1 字符串(16 字符 + null)
|
||||
# rel_path: 相对路径(如 "lib/core/StubMerger.vp",
|
||||
# 不含 includes/ 前缀,与 _sha1_map.txt 格式一致)
|
||||
#
|
||||
# Returns:
|
||||
# 0 成功(含去重跳过),1 失败
|
||||
# 存储器未初始化时自动初始化;SHA1 已存在(去重)则跳过。
|
||||
# Args: sha1 SHA1 字符串(16 字符 + null);rel_path 相对路径(如 "lib/core/StubMerger.vp",不含 includes/ 前缀,与 _sha1_map.txt 格式一致)
|
||||
# Returns: 0 成功(含去重跳过),1 失败
|
||||
# ============================================================
|
||||
def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
"""追加条目到全局 SHA1 映射存储器(Phase2 用)"""
|
||||
@@ -172,24 +286,21 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
stdlib.free(full_path_buf)
|
||||
if mod_name is None:
|
||||
return 1
|
||||
# 去重:SHA1 与模块名都相同才跳过。同一 SHA1 可能被 includes 扫描先以
|
||||
# 全路径模块名注册(如 App 源文件在 includes 目录下 → "Apps.Scene3D.gfx"),
|
||||
# App 追加的短模块名("gfx")必须保留——否则 import gfx 的精确查找
|
||||
# LookupSha1ByModName("gfx") 失败 → 后缀匹配劫持到 VKernel 同名 gfx
|
||||
# (VKernel/Kernel/drivers/video/vesafb/gfx.vp,类 Scene3D 归属错乱根因)。
|
||||
# 去重:SHA1 与模块名都相同才跳过——同一 SHA1 可能先以全路径模块名注册(App 源文件在 includes 目录下),
|
||||
# App 追加的短模块名必须保留,否则 import 该模块的精确查找失败、后缀匹配会劫持到其它同名模块。
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
sidx_d: t.CSizeT = t.CSizeT(i) * 17
|
||||
sidx_d: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0:
|
||||
midx_d: t.CSizeT = t.CSizeT(i) * 64
|
||||
midx_d: sizet = sizet(i) * 64
|
||||
if string.strcmp(StubMerger._sha1_store_mod + midx_d, mod_name) == 0:
|
||||
stdlib.free(mod_name)
|
||||
return 0
|
||||
# 写入 SHA1
|
||||
idx_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17
|
||||
idx_a: sizet = sizet(StubMerger._sha1_store_count) * 17
|
||||
string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1)
|
||||
# 写入模块名
|
||||
idx_m: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64
|
||||
mn_len: t.CSizeT = string.strlen(mod_name)
|
||||
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)
|
||||
else:
|
||||
@@ -197,19 +308,85 @@ def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
StubMerger._sha1_store_mod[idx_m + 63] = '\0'
|
||||
stdlib.free(mod_name)
|
||||
# 写入相对路径
|
||||
idx_r: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * StubMerger.MAX_REL_PATH_LEN
|
||||
rp_len: t.CSizeT = string.strlen(rel_path)
|
||||
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)
|
||||
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'
|
||||
# App 源文件不属于任何 includes 目录:IncDir 留空(Phase2 回退 includes_dir 参数)
|
||||
idx_inc_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||||
idx_inc_a: sizet = sizet(StubMerger._sha1_store_count) * StubMerger.MAX_INC_DIR_LEN
|
||||
StubMerger._sha1_store_incdir[idx_inc_a] = '\0'
|
||||
StubMerger._sha1_store_count += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# AddIncludeToSha1MapStore - 单条登记 includes 条目到全局 SHA1 映射存储器
|
||||
#
|
||||
# 依赖图按需扫描(_BuildReachableSha1Set)解析到可达 includes 文件后逐条登记,未引用的 includes 不进 store;
|
||||
# App 源文件仍用 AppendToSha1MapStore(inc_dir 留空)。
|
||||
# Args: sha1 SHA1 字符串(16 字符 + null);rel_path 相对 includes 根目录的路径(如 "ast/parser.vp");inc_dir 所属 includes 根目录;mod_name 模块名(如 "ast.parser")
|
||||
# Returns: 0 成功(含去重跳过),1 失败
|
||||
# ============================================================
|
||||
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 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
|
||||
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
|
||||
# 去重: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
|
||||
# 写 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)
|
||||
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)
|
||||
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'
|
||||
# 写所属 includes 根目录(非空 = includes 条目;App 条目留空)
|
||||
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)
|
||||
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'
|
||||
StubMerger._sha1_store_count += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# GetSha1StoreCount - 获取全局存储器条目数
|
||||
# ============================================================
|
||||
def GetSha1StoreCount() -> int:
|
||||
@@ -227,15 +404,88 @@ def GetSha1StoreCount() -> int:
|
||||
def LookupSha1ByModName(mod_name: str) -> str:
|
||||
"""从模块名查找 SHA1(精确匹配 + 包名回退),委托通用实现 _FindSha1ByModName"""
|
||||
return StubMergerIR._FindSha1ByModName(StubMerger._sha1_store_arr, StubMerger._sha1_store_mod, StubMerger._sha1_store_count, mod_name)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1
|
||||
# 泛型类归属表(泛型类名 → 定义模块 SHA1)——仅 REPL 会话登记/查询
|
||||
#
|
||||
# 为什么需要:REPL 的 includes 会话初始化只注入 `.vpi` 的类(泛型类被跳过),
|
||||
# 不跑批处理的 _PreRegister*GenericTemplates ⇒ 会话内泛型模板表为空 ⇒ 注解里的
|
||||
# `list[rawptr[AST]]` 等泛型下标解析(`TypeGenResolve._resolve_generic_subscript_ty`)
|
||||
# 恒 miss。会话侧的最后兜底要按**定义侧特化命名** "%{模板模块 sha1}.{mangled}"
|
||||
# 造 opaque 具名类型(实证:`%"b56d2f995104690d.list[rawptr[AST]]"`),因此需要
|
||||
# "泛型类定义在哪个模块"这一事实——由注入期扫 `.vpi` 的 ClassDef 登记(见
|
||||
# VpiReader._repl_stub_collect_module)。
|
||||
#
|
||||
# 归属模块 sha1 无法从类名反推(模块名取自文件路径,class list ← _list.vp;用户
|
||||
# 泛型类更是名字与模块名无关),故必须显式登记,不做"按名字猜"。
|
||||
# 批处理不登记(表恒空 ⇒ 查询恒 None ⇒ 批处理路径一字不改)。
|
||||
# 容量:includes 现有 6 个泛型类定义(list/dict 系 + Vector/GSList/ndarray),取 32 槽。
|
||||
# ============================================================
|
||||
GENERIC_OWNER_MAX: t.CDefine = 32
|
||||
_generic_owner_names: bytes = None
|
||||
_generic_owner_sha1s: bytes = None
|
||||
_generic_owner_count: int = 0
|
||||
|
||||
|
||||
def ResetGenericOwners() -> None:
|
||||
"""清空泛型类归属表(REPL 会话初始化开始时调用一次)"""
|
||||
global _generic_owner_names, _generic_owner_sha1s, _generic_owner_count
|
||||
if _generic_owner_names is not None:
|
||||
stdlib.free(_generic_owner_names)
|
||||
_generic_owner_names = None
|
||||
if _generic_owner_sha1s is not None:
|
||||
stdlib.free(_generic_owner_sha1s)
|
||||
_generic_owner_sha1s = None
|
||||
_generic_owner_count = 0
|
||||
|
||||
|
||||
def RegisterGenericOwner(cls_name: str, mod_sha1: str) -> int:
|
||||
"""登记"泛型类名 → 定义模块 SHA1";1=已登记(含重复)/ 0=失败(参数/满/同名异 sha1)
|
||||
|
||||
同名异 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 _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
|
||||
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
|
||||
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
|
||||
return 1
|
||||
|
||||
|
||||
def LookupGenericOwnerSha1(cls_name: str) -> str:
|
||||
"""按泛型类名取定义模块 SHA1(返回内部指针,无需释放;未登记 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
|
||||
return None
|
||||
# ============================================================
|
||||
# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1(用于 from .X import Y:impf.module 是 ".X",而映射表键是 "pkg.X")
|
||||
#
|
||||
# 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点),
|
||||
# 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。
|
||||
# 包含三种匹配方式:精确、后缀、反向后缀。
|
||||
#
|
||||
# Returns:
|
||||
# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到
|
||||
# Returns: SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到
|
||||
# ============================================================
|
||||
def LookupSha1ByModNameSuffix(mod_suffix: str) -> str:
|
||||
"""后缀匹配查找模块 SHA1"""
|
||||
@@ -245,55 +495,52 @@ def LookupSha1ByModNameSuffix(mod_suffix: str) -> str:
|
||||
return None
|
||||
if StubMerger._sha1_store_count <= 0:
|
||||
return None
|
||||
suffix_len_sf: t.CSizeT = string.strlen(mod_suffix)
|
||||
suffix_len_sf: sizet = string.strlen(mod_suffix)
|
||||
if suffix_len_sf == 0:
|
||||
return None
|
||||
i_sf: int
|
||||
for i_sf in range(StubMerger._sha1_store_count):
|
||||
idx_sf: t.CSizeT = t.CSizeT(i_sf) * 64
|
||||
idx_sf: sizet = sizet(i_sf) * 64
|
||||
mod_name_sf: str = StubMerger._sha1_store_mod + idx_sf
|
||||
mod_len_sf: t.CSizeT = string.strlen(mod_name_sf)
|
||||
mod_len_sf: sizet = string.strlen(mod_name_sf)
|
||||
if mod_len_sf == 0:
|
||||
continue
|
||||
# 精确匹配
|
||||
if mod_len_sf == suffix_len_sf:
|
||||
if string.strcmp(mod_name_sf, mod_suffix) == 0:
|
||||
sidx_sf: t.CSizeT = t.CSizeT(i_sf) * 17
|
||||
sidx_sf: sizet = sizet(i_sf) * 17
|
||||
return StubMerger._sha1_store_arr + sidx_sf
|
||||
# 后缀匹配:mod_name 以 "." + mod_suffix 结尾
|
||||
if mod_len_sf > suffix_len_sf:
|
||||
if mod_name_sf[mod_len_sf - suffix_len_sf - 1] == '.':
|
||||
cmp_start_sf: str = mod_name_sf + mod_len_sf - suffix_len_sf
|
||||
if string.strcmp(cmp_start_sf, mod_suffix) == 0:
|
||||
sidx2_sf: t.CSizeT = t.CSizeT(i_sf) * 17
|
||||
sidx2_sf: sizet = sizet(i_sf) * 17
|
||||
return StubMerger._sha1_store_arr + sidx2_sf
|
||||
# 反向后缀匹配:mod_suffix 以 "." + mod_name 结尾
|
||||
if suffix_len_sf > mod_len_sf:
|
||||
if mod_suffix[suffix_len_sf - mod_len_sf - 1] == '.':
|
||||
cmp_start_rev_sf: str = mod_suffix + suffix_len_sf - mod_len_sf
|
||||
if string.strcmp(cmp_start_rev_sf, mod_name_sf) == 0:
|
||||
sidx_rev_sf: t.CSizeT = t.CSizeT(i_sf) * 17
|
||||
sidx_rev_sf: sizet = sizet(i_sf) * 17
|
||||
return StubMerger._sha1_store_arr + sidx_rev_sf
|
||||
return None
|
||||
# ============================================================
|
||||
# LookupSha1ByAlias - 从 from_imports 别名映射解析模块 SHA1
|
||||
#
|
||||
# from_imports 条目格式: "local:module" 或 "local:module:orig"(空格分隔),
|
||||
# 由 ImportsGenMixin.add_from_import 写入(import X as Y → "Y:X")。
|
||||
# 命中 local==alias 时,对 module 执行 LookupSha1ByModName 返回 SHA1。
|
||||
#
|
||||
# Returns:
|
||||
# SHA1 字符串指针(指向全局存储器内部),None 未找到
|
||||
# from_imports 条目格式 "local:module" 或 "local:module:orig"(空格分隔,由 ImportsGenMixin.add_from_import 写入);
|
||||
# 命中 local==alias 时对 module 执行 LookupSha1ByModName。
|
||||
# Returns: SHA1 字符串指针(指向全局存储器内部),None 未找到
|
||||
# ============================================================
|
||||
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
|
||||
alias_len: t.CSizeT = string.strlen(alias)
|
||||
alias_len: sizet = string.strlen(alias)
|
||||
if alias_len == 0:
|
||||
return None
|
||||
total_len: t.CSizeT = string.strlen(from_imports)
|
||||
ci: t.CSizeT = 0
|
||||
total_len: sizet = string.strlen(from_imports)
|
||||
ci: sizet = 0
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
while ci < total_len and from_imports[ci] == ' ':
|
||||
@@ -301,14 +548,14 @@ def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||||
if ci >= total_len:
|
||||
break
|
||||
# 条目起点 ci,找 ':'(local_name 结束)
|
||||
colon: t.CSizeT = ci
|
||||
colon: sizet = ci
|
||||
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ':
|
||||
colon += 1
|
||||
local_len: t.CSizeT = colon - ci
|
||||
local_len: sizet = colon - ci
|
||||
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
|
||||
# 比较 local_name == alias
|
||||
match: int = 1
|
||||
li: t.CSizeT = 0
|
||||
li: sizet = 0
|
||||
while li < alias_len:
|
||||
if from_imports[ci + li] != alias[li]:
|
||||
match = 0
|
||||
@@ -316,8 +563,8 @@ def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||||
li += 1
|
||||
if match == 1:
|
||||
# 提取 module(colon+1 到下一个 ':' 或空格)
|
||||
m_start: t.CSizeT = colon + 1
|
||||
m_end: t.CSizeT = m_start
|
||||
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
|
||||
if m_end > m_start:
|
||||
@@ -336,22 +583,19 @@ def LookupSha1ByAlias(from_imports: str, alias: str) -> str:
|
||||
# ============================================================
|
||||
# LookupModNameByAlias - 从 from_imports 别名映射解析模块真名
|
||||
#
|
||||
# import X as Y 时 ImportsGenMixin.add_from_import 写入 "Y:X"(Y=别名,
|
||||
# X=模块真名)。本函数返回别名 Y 对应的模块真名 X(供限定名解析
|
||||
# "Y.Class" → 按 X 模块归属匹配,如 "types.fileinfo" → "fat32_types")。
|
||||
#
|
||||
# Returns:
|
||||
# 模块名字符串(stdlib 分配,调用方负责 free),None 未找到
|
||||
# import X as Y 时 ImportsGenMixin.add_from_import 写入 "Y:X"(Y=别名,X=模块真名);
|
||||
# 本函数返回别名 Y 对应的模块真名 X(供限定名解析 "Y.Class" → 按 X 模块归属匹配)。
|
||||
# Returns: 模块名字符串(stdlib 分配,调用方负责 free),None 未找到
|
||||
# ============================================================
|
||||
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
|
||||
alias_len: t.CSizeT = string.strlen(alias)
|
||||
alias_len: sizet = string.strlen(alias)
|
||||
if alias_len == 0:
|
||||
return None
|
||||
total_len: t.CSizeT = string.strlen(from_imports)
|
||||
ci: t.CSizeT = 0
|
||||
total_len: sizet = string.strlen(from_imports)
|
||||
ci: sizet = 0
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
while ci < total_len and from_imports[ci] == ' ':
|
||||
@@ -359,14 +603,14 @@ def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||||
if ci >= total_len:
|
||||
break
|
||||
# 条目起点 ci,找 ':'(local_name 结束)
|
||||
colon: t.CSizeT = ci
|
||||
colon: sizet = ci
|
||||
while colon < total_len and from_imports[colon] != ':' and from_imports[colon] != ' ':
|
||||
colon += 1
|
||||
local_len: t.CSizeT = colon - ci
|
||||
local_len: sizet = colon - ci
|
||||
if colon < total_len and from_imports[colon] == ':' and local_len == alias_len:
|
||||
# 比较 local_name == alias
|
||||
match: int = 1
|
||||
li: t.CSizeT = 0
|
||||
li: sizet = 0
|
||||
while li < alias_len:
|
||||
if from_imports[ci + li] != alias[li]:
|
||||
match = 0
|
||||
@@ -374,8 +618,8 @@ def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||||
li += 1
|
||||
if match == 1:
|
||||
# 提取 module(colon+1 到下一个 ':' 或空格)
|
||||
m_start: t.CSizeT = colon + 1
|
||||
m_end: t.CSizeT = m_start
|
||||
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
|
||||
if m_end > m_start:
|
||||
@@ -392,15 +636,9 @@ def LookupModNameByAlias(from_imports: str, alias: str) -> str:
|
||||
# ============================================================
|
||||
# PopulateIncludesDeps - 将 includes 文件的依赖存入内存
|
||||
#
|
||||
# Phase B+ 前用 declare_only 翻译 includes 文件,提取 _imported_modules
|
||||
# 后调用此函数存入内存。_BuildReachableSha1Set 从内存读取,不读 deps.txt。
|
||||
#
|
||||
# Args:
|
||||
# sha1: includes 文件的 SHA1(16字符)
|
||||
# deps_str: 依赖模块名字符串(空格分隔,如 "t c stdint string")
|
||||
#
|
||||
# Returns:
|
||||
# 0 成功,非 0 失败
|
||||
# Phase B+ 前用 declare_only 翻译 includes 文件、提取 _imported_modules 后调用本函数存入内存;_BuildReachableSha1Set 从内存读取,不读 deps.txt。
|
||||
# Args: sha1 includes 文件的 SHA1(16字符);deps_str 依赖模块名字符串(空格分隔,如 "t c stdint string")
|
||||
# Returns: 0 成功,非 0 失败
|
||||
# ============================================================
|
||||
def PopulateIncludesDeps(sha1: str, deps_str: str) -> int:
|
||||
"""将 includes 文件的依赖存入内存"""
|
||||
@@ -419,16 +657,16 @@ def PopulateIncludesDeps(sha1: str, deps_str: str) -> int:
|
||||
return 1
|
||||
# 去重:若 SHA1 已存在则跳过
|
||||
for i in range(StubMerger._includes_deps_count):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
sidx: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
|
||||
return 0
|
||||
# 写入 SHA1
|
||||
idx: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * 17
|
||||
idx: sizet = sizet(StubMerger._includes_deps_count) * 17
|
||||
string.strcpy(StubMerger._includes_deps_sha1 + idx, sha1)
|
||||
# 写入依赖字符串
|
||||
idx2: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * StubMerger.MAX_DEPS_STR_LEN
|
||||
idx2: sizet = sizet(StubMerger._includes_deps_count) * StubMerger.MAX_DEPS_STR_LEN
|
||||
if deps_str is not None:
|
||||
dl: t.CSizeT = string.strlen(deps_str)
|
||||
dl: sizet = string.strlen(deps_str)
|
||||
if dl < StubMerger.MAX_DEPS_STR_LEN:
|
||||
string.strcpy(StubMerger._includes_deps_str + idx2, deps_str)
|
||||
else:
|
||||
@@ -453,9 +691,9 @@ def LookupIncludesDeps(sha1: str) -> str:
|
||||
if StubMerger._includes_deps_count <= 0:
|
||||
return None
|
||||
for i in range(StubMerger._includes_deps_count):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
sidx: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
|
||||
idx2: t.CSizeT = t.CSizeT(i) * StubMerger.MAX_DEPS_STR_LEN
|
||||
idx2: sizet = sizet(i) * StubMerger.MAX_DEPS_STR_LEN
|
||||
return StubMerger._includes_deps_str + idx2
|
||||
return None
|
||||
def GetSha1StoreArrPtr() -> bytes:
|
||||
@@ -477,24 +715,23 @@ def GetSha1StoreIncdirArrPtr() -> bytes:
|
||||
# 调用者直接遍历数组:sha1_arr[i*17]、mod_arr[i*64]、rel_arr[i*StubMerger.MAX_REL_PATH_LEN]
|
||||
# 内存归全局存储器所有,调用者不要 free
|
||||
# ============================================================
|
||||
def GetSha1StoreArr(out_sha1_arr: t.CPtr, out_mod_arr: t.CPtr, out_rel_arr: t.CPtr) -> int:
|
||||
def GetSha1StoreArr(out_sha1_arr: rawptr[t.CPtr], out_mod_arr: rawptr[t.CPtr], out_rel_arr: rawptr[t.CPtr]) -> int:
|
||||
"""获取全局存储器数组指针
|
||||
|
||||
out_sha1_arr/out_mod_arr/out_rel_arr 是调用者提供的 t.CPtr 指针,
|
||||
函数将存储器数组指针写入这些位置。
|
||||
返回条目数,-1 失败
|
||||
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
|
||||
sp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_sha1_arr, t.CPtr)) # 存疑
|
||||
sp: rawptr[t.CPtr] = out_sha1_arr
|
||||
if sp is not None:
|
||||
sp[0] = StubMerger._sha1_store_arr
|
||||
mp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_mod_arr, t.CPtr))
|
||||
mp: rawptr[t.CPtr] = out_mod_arr
|
||||
if mp is not None:
|
||||
mp[0] = StubMerger._sha1_store_mod
|
||||
rp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_rel_arr, t.CPtr))
|
||||
rp: rawptr[t.CPtr] = out_rel_arr
|
||||
if rp is not None:
|
||||
rp[0] = StubMerger._sha1_store_rel
|
||||
return StubMerger._sha1_store_count
|
||||
@@ -502,14 +739,9 @@ def GetSha1StoreArr(out_sha1_arr: t.CPtr, out_mod_arr: t.CPtr, out_rel_arr: t.CP
|
||||
# ============================================================
|
||||
# LookupSha1RelPath - 通过 SHA1 查找相对路径
|
||||
#
|
||||
# 遍历全局存储器,返回 sha1 对应的相对路径指针(只读,不要 free)。
|
||||
# 用于错误提示:将 sha1 转换为人类可读的文件路径。
|
||||
#
|
||||
# Args:
|
||||
# sha1: SHA1 字符串(16 字符)
|
||||
#
|
||||
# Returns:
|
||||
# 相对路径字符串指针(只读),None=未找到
|
||||
# 遍历全局存储器,返回 sha1 对应的相对路径指针(只读,不要 free),用于把 sha1 转成人类可读的文件路径。
|
||||
# Args: sha1 SHA1 字符串(16 字符)
|
||||
# Returns: 相对路径字符串指针(只读),None=未找到
|
||||
# ============================================================
|
||||
def LookupSha1RelPath(sha1: str) -> str:
|
||||
"""通过 SHA1 查找相对路径,返回只读指针,None=未找到"""
|
||||
@@ -518,8 +750,39 @@ def LookupSha1RelPath(sha1: str) -> str:
|
||||
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: t.CSizeT = t.CSizeT(i) * 17
|
||||
sidx: sizet = sizet(i) * 17
|
||||
if string.strcmp(StubMerger._sha1_store_arr + sidx, sha1) == 0:
|
||||
ridx: t.CSizeT = t.CSizeT(i) * StubMerger.MAX_REL_PATH_LEN
|
||||
ridx: sizet = sizet(i) * StubMerger.MAX_REL_PATH_LEN
|
||||
return StubMerger._sha1_store_rel + ridx
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# LookupModNameBySha1 - 通过 SHA1 反查模块名
|
||||
#
|
||||
# 用途:判定"本 stub 是否某包的 __init__"(模块名以 ".__init__" 结尾)——该事实
|
||||
# **不依赖 sha1→rel_path 字段**:rel_path 反查在部分运行形态下拿不到条目 ⇒
|
||||
# VpiReader 原来的 `strstr(rel_path, "__init__.vp")` 判定恒 false ⇒ 包重导出类的
|
||||
# 别名 entry 静默不登记 ⇒ `ast.ClassDef` 这类**限定名在泛型实参里保留包前缀**,
|
||||
# 与构造函数侧(真定义模块前缀)分裂成两个类型(现场 ClassGenGeneric.vp:92 的
|
||||
# CastError;幽灵名 `list[1abcd5277fa442de.ClassDef*]` 全产物 opaque)。
|
||||
# 模块名与 rel_path 是同一次登记写入的(PopulateSha1MapStore /
|
||||
# AppendToSha1MapStore),但模块名可用即足以作出判定与取包前缀。
|
||||
#
|
||||
# 同一 SHA1 可能有多条(App 源文件按全路径模块名与短模块名各登记一次):返回
|
||||
# **第一条命中**;各条的包前缀一致,调用方只取"去 .__init__ 后的前缀"。
|
||||
# Args: sha1 SHA1 字符串(16 字符)
|
||||
# Returns: 模块名字符串指针(只读,不要 free),None=未找到
|
||||
# ============================================================
|
||||
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
|
||||
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:
|
||||
midx_mb: sizet = sizet(i) * 64
|
||||
return StubMerger._sha1_store_mod + midx_mb
|
||||
return None
|
||||
@@ -12,7 +12,7 @@ import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Gen.Translator as HandlesTranslator
|
||||
import lib.Phase.BuildPipeline as BuildPipeline
|
||||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
@@ -26,44 +26,31 @@ import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
|
||||
# ============================================================
|
||||
# StubMergerTopo - StubMerger 拆分(阶段 E):StubMergerTopo
|
||||
# StubMergerTopo - 对可达 includes 做逆拓扑排序(被依赖者先编译)
|
||||
#
|
||||
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
|
||||
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
|
||||
# StubMerger._xxx 访问(main.vp 先例)。
|
||||
# 函数实现直接位于本模块,调用方经本模块前缀访问;全局变量跨模块经 StubMerger._xxx 访问。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# BuildTopoSortedIndices - 对可达 includes 逆拓扑排序(被依赖者先)
|
||||
#
|
||||
# 背景:跨模块 vtable 生成要求被依赖模块先完整翻译(如 astaux.vp 继承
|
||||
# base.vp 的 AST,vtable 槽位需 AST.accept 的 TypeStr 已注册到全局表)。
|
||||
# Phase B+ 原先按 store 扫描顺序编译,依赖顺序不保证 → fail-fast 暴露。
|
||||
# 跨模块 vtable 生成要求被依赖模块先完整翻译(子类 vtable 槽位需父类方法的类型已注册到全局表)。
|
||||
# 算法:Kahn 逆拓扑。边 m→d 表示 m 依赖 d(d 在 m 的 deps 中);入度为 0(不依赖任何可达模块)者先输出,
|
||||
# 输出后对依赖它的模块减入度,入度归 0 者入队。reachable_count <= 0 时对全部 store 排序(与既有全量编译行为一致)。
|
||||
#
|
||||
# 算法:Kahn 逆拓扑。边 m→d 表示 m 依赖 d(d 在 m 的 deps 中)。
|
||||
# indegree[m] = m 在可达集合内的直接依赖数;
|
||||
# 入度为 0(不依赖任何可达模块)者先输出,输出后对依赖它的模块
|
||||
# 减入度,入度归 0 者入队。结果即"被依赖者先编译"。
|
||||
# reachable_count <= 0 时对全部 store 排序(与既有全量编译行为一致)。
|
||||
#
|
||||
# Args:
|
||||
# store_count / store_sha1_arr / store_mod_arr: store 元数据
|
||||
# reachable_set / reachable_count: 可达集合(_BuildReachableSha1Set 输出)
|
||||
# sorted_idx: 输出数组(store_count+1 个 8 字节槽),前 N 个为拓扑序 store 索引
|
||||
#
|
||||
# Returns:
|
||||
# 拓扑序条数;有环时剩余条目按 store 顺序补齐(避免漏编译)
|
||||
# Args: store_count / store_sha1_arr / store_mod_arr store 元数据;reachable_set / reachable_count 可达集合(_BuildReachableSha1Set 输出);sorted_idx 输出数组(store_count+1 个 8 字节槽),前 N 个为拓扑序 store 索引
|
||||
# Returns: 拓扑序条数;有环时剩余条目按 store 顺序补齐(避免漏编译)
|
||||
# ============================================================
|
||||
def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
store_mod_arr: bytes, reachable_set: bytes,
|
||||
reachable_count: int,
|
||||
sorted_idx: t.CSizeT | t.CPtr) -> 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
|
||||
indegree: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||||
queue: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||||
rel_idx: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||||
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)
|
||||
@@ -87,28 +74,23 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
rel_count += 1
|
||||
else:
|
||||
for i_t in range(store_count):
|
||||
if StubMergerCollect._is_in_sha1_set(store_sha1_arr + t.CSizeT(i_t) * 17, reachable_set, reachable_count) != 0:
|
||||
if StubMergerCollect._is_in_sha1_set(store_sha1_arr + sizet(i_t) * 17, reachable_set, reachable_count) != 0:
|
||||
rel_idx[rel_count] = i_t
|
||||
rel_count += 1
|
||||
# 诊断:可达 store 索引数(rel_count=0 → topo_count=0 → PhaseB+ 循环不执行)
|
||||
fb_rel: str = VLogger.fmt_buf()
|
||||
if fb_rel is not None:
|
||||
viperlib.snprintf(fb_rel, 1024, "诊断 topo rel_count=%d", rel_count)
|
||||
VLogger.debug(fb_rel, "StubMergerTopo")
|
||||
|
||||
# 计算入度:m 在可达集合内的直接依赖数
|
||||
i_r: int
|
||||
for i_r in range(rel_count):
|
||||
si: int = rel_idx[i_r]
|
||||
deps_si: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si) * 17)
|
||||
deps_si: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + sizet(si) * 17)
|
||||
if deps_si is None:
|
||||
continue
|
||||
dl_si: t.CSizeT = string.strlen(deps_si)
|
||||
dpos: t.CSizeT = 0
|
||||
dl_si: sizet = string.strlen(deps_si)
|
||||
dpos: sizet = 0
|
||||
while dpos < dl_si:
|
||||
dstart: t.CSizeT = dpos
|
||||
dstart: sizet = dpos
|
||||
while dpos < dl_si and deps_si[dpos] != ' ':
|
||||
dpos += 1
|
||||
dlen: t.CSizeT = dpos - dstart
|
||||
dlen: sizet = dpos - dstart
|
||||
if dpos < dl_si:
|
||||
dpos += 1
|
||||
if dlen == 0:
|
||||
@@ -133,32 +115,31 @@ def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
queue[q_tail] = si2
|
||||
q_tail += 1
|
||||
out_count: int = 0
|
||||
# Kahn 主循环必须用 while(不能用 for range):循环体内会动态入队
|
||||
# (queue[q_tail]=si3; q_tail+=1),for range 上界只求值一次,
|
||||
# 动态入队的模块永远不会被处理且兜底(indegree>0)也捞不回 → 拓扑漏项
|
||||
# Kahn 主循环必须用 while 而非 for range:循环体内会动态入队(for range 上界只求值一次,
|
||||
# 动态入队的模块永远不会被处理,且 indegree>0 兜底也捞不回 → 拓扑漏项)
|
||||
q_head: int = 0
|
||||
while q_head < q_tail:
|
||||
m: int = queue[q_head]
|
||||
sorted_idx[out_count] = m
|
||||
out_count += 1
|
||||
# 对依赖 m 的可达模块减入度
|
||||
mod_m: str = store_mod_arr + t.CSizeT(m) * 64
|
||||
mod_m_len: t.CSizeT = string.strlen(mod_m)
|
||||
mod_m: str = store_mod_arr + sizet(m) * 64
|
||||
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
|
||||
deps_si3: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si3) * 17)
|
||||
deps_si3: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + sizet(si3) * 17)
|
||||
if deps_si3 is None:
|
||||
continue
|
||||
dl_si3: t.CSizeT = string.strlen(deps_si3)
|
||||
dpos3: t.CSizeT = 0
|
||||
dl_si3: sizet = string.strlen(deps_si3)
|
||||
dpos3: sizet = 0
|
||||
found_dep: int = 0
|
||||
while dpos3 < dl_si3 and found_dep == 0:
|
||||
dstart3: t.CSizeT = dpos3
|
||||
dstart3: sizet = dpos3
|
||||
while dpos3 < dl_si3 and deps_si3[dpos3] != ' ':
|
||||
dpos3 += 1
|
||||
dlen3: t.CSizeT = dpos3 - dstart3
|
||||
dlen3: sizet = dpos3 - dstart3
|
||||
if dpos3 < dl_si3:
|
||||
dpos3 += 1
|
||||
if dlen3 == 0:
|
||||
|
||||
@@ -12,7 +12,7 @@ import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Gen.Translator as HandlesTranslator
|
||||
import lib.Phase.BuildPipeline as BuildPipeline
|
||||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
@@ -20,26 +20,21 @@ import lib.Projectrans.Config as Config
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StubMerger - stub 声明合并模块
|
||||
# StubMerger - stub 声明合并模块(Phase2 核心)
|
||||
#
|
||||
# 从 temp 目录加载所有 .stub.ll 文件,将声明内容合并到主 IR。
|
||||
# 这是 Phase2 的核心功能:翻译主文件时,将所有依赖的 stub
|
||||
# 声明合并到主 IR 前面,使链接器能解析跨模块符号引用。
|
||||
#
|
||||
# 合并策略:
|
||||
# 1. 扫描 temp 目录,收集所有 {sha1}.stub.ll 文件
|
||||
# 2. 读取每个 stub 文件内容
|
||||
# 3. 过滤去重(避免重复声明)
|
||||
# 4. 将声明插入到主 IR 的 target triple 之后
|
||||
# 从 temp 目录加载所有 .stub.ll,把依赖模块的声明合并到主 IR 的 target triple 之后,使链接器能解析跨模块符号引用。
|
||||
# 合并策略:扫描 temp 目录收集 {sha1}.stub.ll → 读取内容 → 过滤去重(避免重复声明)→ 插入主 IR。
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
_mbuddy: memhub.MemBuddy*
|
||||
|
||||
# 最大 includes SHA1 数(用于过滤)
|
||||
MAX_INCLUDES_SHA1: t.CDefine = 1024
|
||||
# stub 读取缓冲区大小
|
||||
STUB_READ_BUF_SIZE: t.CDefine = 1048576
|
||||
# 1MB 不够:ast/parser.vp 的 text.ll >1MB,BuildCombinedIR 读取本地 text.ll
|
||||
# 单次截断 → 合并 IR 尾部丢字(opt: "end of file in global variable name")。
|
||||
STUB_READ_BUF_SIZE: t.CDefine = 8388608
|
||||
# 最大 includes 条目数
|
||||
MAX_INCLUDES: t.CDefine = 1024
|
||||
# 可达性分析 worklist/processed 缓冲区大小(8192 不够:递归扫描 source_dir
|
||||
@@ -61,10 +56,8 @@ _includes_deps_sha1: bytes # SHA1 数组(每个 17 字节,MAX_INCLUDES 个
|
||||
_includes_deps_str: bytes # 依赖字符串数组(每个 512 字节,MAX_INCLUDES 个)
|
||||
_includes_deps_count: int # 条目数
|
||||
|
||||
# BuildCombinedIR 全目录扫描缓存:Phase B 对每个源文件调用一次 BuildCombinedIR,
|
||||
# 每次 _collect_stub_sha1s 递归扫描 temp_dir 全部切片子目录(O(N×S) 目录枚举,
|
||||
# 90 文件 × 全目录是 Phase B 慢的根因之一)。按 temp_dir 缓存扫描结果,
|
||||
# 首次扫描后复用,temp_dir 变化时自动重建。
|
||||
# BuildCombinedIR 全目录扫描缓存:Phase B 每个源文件调用一次 BuildCombinedIR,而 _collect_stub_sha1s 会递归枚举
|
||||
# temp_dir 全部切片子目录(O(N×S) 目录枚举很慢);按 temp_dir 缓存扫描结果,首次扫描后复用,temp_dir 变化时自动重建。
|
||||
_stub_scan_cache_dir: str # 缓存对应的 temp_dir(None=未初始化)
|
||||
_stub_scan_cache_arr: str # 扫描结果数组(每 17 字节一个 SHA1,MAX_INCLUDES_SHA1 个)
|
||||
_stub_scan_cache_count: int # 收集数量
|
||||
|
||||
+13
-13
@@ -1,13 +1,13 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lib 包入口 - 声明全局 _mbuddy 内存池指针
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 内存池指针(由 App/main.vp 初始化后注入)
|
||||
# 注意: 使用 MemBuddy 类型而非 MemManager,避免虚函数分派不工作时调用父类 alloc 返回 None
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lib 包入口 - 声明全局 _mbuddy 内存池指针
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 内存池指针(由 App/main.vp 初始化后注入)
|
||||
# 注意: 使用 MemBuddy 类型而非 MemManager,避免虚函数分派不工作时调用父类 alloc 返回 None
|
||||
_mbuddy: memhub.MemBuddy*
|
||||
@@ -1,68 +1,34 @@
|
||||
import t, c
|
||||
import memhub
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CompilerFactory - 编译器结构体工厂(对齐 TPC Translator 装配模式)
|
||||
#
|
||||
# TPC 的 Translator 在 __init__ 集中创建编译器各子对象(Handler/
|
||||
# SymbolTable/Exportable 等),是编译器的"装配器/工厂";TPV 的 main
|
||||
# 目前手动创建 mb/gen 并逐模块注入(_mbuddy/set_global_gen),装配
|
||||
# 逻辑散落。本工厂集中持有编译器级共享内存对象:
|
||||
#
|
||||
# - Pool :主内存池(MemBuddy,瞬时数据,受 mark/reset_to 回收)
|
||||
# - PermPool :永久内存池(MemBuddy,跨 mark 持久数据专用,从不 reset)
|
||||
#
|
||||
# 各模块经模块级委托 CompilerFactory.get_perm_pool() 获取永久池,
|
||||
# 避免把编译器专属单例塞进通用内存库 memhub(memhub 保持通用)。
|
||||
# includes 层(llvmlite/__types.vp 的 DeepCopyType)不依赖本工厂:
|
||||
# 深拷贝的分配源由调用方以 pool 参数传入(传 PermPool 即持久)。
|
||||
# 类名与模块名同名(均为 CompilerFactory):合法场景,TPC 已支持
|
||||
# 模块别名优先解析——`X.func()` 中 X 是 import 别名(IsModuleAlias)
|
||||
# 时按模块函数处理,`X.X(args)` 的类构造按 FuncAttr==类名 走 struct
|
||||
# 路径,二者互不冲突(勿再改类名规避,见用户明确要求)。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CompilerFactory:
|
||||
"""编译器结构体工厂(持有主池/永久池等共享对象)"""
|
||||
|
||||
Pool: memhub.MemBuddy | t.CPtr # 主内存池(瞬时数据,mark/reset 回收)
|
||||
PermPool: memhub.MemBuddy | t.CPtr # 永久内存池(持久数据,从不 reset)
|
||||
|
||||
def __init__(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
perm_pool: memhub.MemBuddy | t.CPtr):
|
||||
if self is None:
|
||||
return
|
||||
self.Pool = pool
|
||||
self.PermPool = perm_pool
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局工厂单例
|
||||
# ============================================================
|
||||
_g_factory: CompilerFactory | t.CPtr = None
|
||||
|
||||
|
||||
def set_factory(factory: CompilerFactory | t.CPtr) -> None:
|
||||
"""注册全局工厂单例(main 创建后注册)"""
|
||||
global _g_factory
|
||||
_g_factory = factory
|
||||
|
||||
|
||||
def get_factory() -> CompilerFactory | t.CPtr:
|
||||
"""获取全局工厂单例(未注册返回 None)"""
|
||||
return _g_factory
|
||||
|
||||
|
||||
def get_pool() -> memhub.MemBuddy | t.CPtr:
|
||||
"""获取主内存池(瞬时数据分配源)"""
|
||||
if _g_factory is not None:
|
||||
return _g_factory.Pool
|
||||
return None
|
||||
|
||||
|
||||
def get_perm_pool() -> memhub.MemBuddy | t.CPtr:
|
||||
"""获取永久内存池(跨 mark 持久数据分配源)"""
|
||||
if _g_factory is not None:
|
||||
return _g_factory.PermPool
|
||||
return None
|
||||
import t, c
|
||||
import memhub
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CompilerFactory - 编译器结构体工厂(对齐 TPC Translator 装配模式)
|
||||
# ============================================================
|
||||
novirtual class CompilerFactory:
|
||||
"""编译器结构体工厂(持有主池/永久池等共享对象)"""
|
||||
Pool: memhub.MemBuddy* # 主内存池(瞬时数据,mark/reset 回收)
|
||||
PermPool: memhub.MemBuddy* # 永久内存池(持久数据,从不 reset)
|
||||
|
||||
# ---- REnum 变体注册表(编译期单例持有,与 perm_pool 的 struct entry 同寿命)----
|
||||
RenumClassNames: sizet*
|
||||
RenumClassVariantCounts: sizet*
|
||||
RenumVariantNames: sizet*
|
||||
RenumVariantTags: sizet*
|
||||
RenumClassCount: int
|
||||
|
||||
# ---- REnum 变体字段别名表(同上,必须同寿命;_bind_variant_fields 查字段真实类型)----
|
||||
RenumAliasClass: sizet*
|
||||
RenumAliasField: sizet*
|
||||
RenumAliasIndex: sizet*
|
||||
RenumAliasTy: sizet*
|
||||
RenumAliasVariant: sizet*
|
||||
RenumAliasCount: int
|
||||
|
||||
def __init__(self, pool: memhub.MemBuddy*, perm_pool: memhub.MemBuddy*):
|
||||
if self is None: return
|
||||
self.Pool = pool
|
||||
self.PermPool = perm_pool
|
||||
|
||||
# 全局工厂单例
|
||||
factory: CompilerFactory* = None
|
||||
+2155
-789
File diff suppressed because it is too large.
Load diff
+2659
-2848
File diff suppressed because it is too large.
Load diff
@@ -4,44 +4,33 @@ import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import llvmlite
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
|
||||
|
||||
# ============================================================
|
||||
# BaseGenMixin - 生成器基座(状态容器)
|
||||
#
|
||||
# 对象化重构 P1(方案见 wiki/14-oo-refactor.md):
|
||||
# 将 Translator/Handles 的共享状态集中于此。后续 Mixin
|
||||
# (TypeGen/StructGen/ExprGen/CallGen/FuncGen/ClassGen/StmtGen/
|
||||
# ImportsGen)单继承本类,逐步把 Handles* 模块的函数迁移为
|
||||
# Generator 的方法,消除 (pool, builder, mod, node, ...) 六参连传。
|
||||
#
|
||||
# 注意:@t.NoVTable(静态绑定,骨架无多态需求;若未来需要
|
||||
# 运行时多态再改 @t.CVTable,字段布局由编译器统一管理)。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class BaseGenMixin:
|
||||
novirtual class BaseGenMixin:
|
||||
"""生成器状态容器(基座)"""
|
||||
|
||||
# 内存/IR 状态
|
||||
Gen: Generator.Generator | t.CPtr
|
||||
Pool: memhub.MemBuddy | t.CPtr # 内存池
|
||||
Module: llvmlite.LLVMModule | t.CPtr # 当前 LLVM 模块
|
||||
Builder: llvmlite.IRBuilder | t.CPtr # 当前 IRBuilder
|
||||
Gen: Generator.Generator*
|
||||
Pool: memhub.MemBuddy* # 内存池
|
||||
Module: llvmlite.LLVMModule* # 当前 LLVM 模块
|
||||
Builder: llvmlite.IRBuilder* # 当前 IRBuilder
|
||||
# 符号表/函数表
|
||||
SymTab: GenTypes.SymbolTable | t.CPtr
|
||||
Funcs: GenTypes.FuncEntry | t.CPtr
|
||||
SymTab: rawptr[GenTypes.SymbolTable]
|
||||
Funcs: GenTypes.FuncEntry*
|
||||
FuncCount: int
|
||||
# 导入/模块信息
|
||||
ImportedModules: str
|
||||
FromImports: str
|
||||
ModuleSha1: str
|
||||
# 当前翻译上下文
|
||||
CurFunc: llvmlite.Function | t.CPtr
|
||||
CurBuilder: llvmlite.IRBuilder | t.CPtr
|
||||
CurFunc: llvmlite.Function*
|
||||
CurBuilder: llvmlite.IRBuilder*
|
||||
CurClassName: str
|
||||
|
||||
def InitBaseGen(self, pool: memhub.MemBuddy | t.CPtr) -> int:
|
||||
def InitBaseGen(self, pool: memhub.MemBuddy*) -> int:
|
||||
"""初始化生成器状态(默认值;子类构造时调用)"""
|
||||
if self is None:
|
||||
return 1
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+1818
-1684
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,296 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
|
||||
from . import CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenFd - CallGenMixin 拆分(阶段 B):FakeDuck / requires 字段注入 / provider 栈
|
||||
# ============================================================
|
||||
novirtual class CallGenFd(CallGenBase.CallGenBase):
|
||||
"""FakeDuck / requires 字段注入 / provider 栈"""
|
||||
def _translate_fakeduck_call(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
cls_name: str,
|
||||
method_name: str,
|
||||
cl: ast.Call*,
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""FakeDuck: str 变量方法调用解析到扩展类 _Type/_str,返回 call 结果或 None"""
|
||||
if pool is None or builder is None or cl is None or trans is None: return None
|
||||
if method_name is None: return None
|
||||
# 仅对 str 类型触发(AnnotClassName == "str",对象是 char*);
|
||||
# cls_name 为 None(表达式接收者解析失败)时也尝试
|
||||
if cls_name is not None and string.strcmp(cls_name, "str") != 0: return None
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: return None
|
||||
fd_at: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if fd_at is None or fd_at.value is None or fd_at.attr is None: return None
|
||||
if string.strcmp(fd_at.attr, method_name) != 0: return None
|
||||
# 候选扩展类:先 _Type(a.type_id())后 _str(a.upper() 等)
|
||||
fd_func: llvmlite.Function* = None
|
||||
fd_cls: str = None
|
||||
fd_key: str = pool.alloc(160)
|
||||
if fd_key is not None:
|
||||
for fd_ci in range(2):
|
||||
fd_cn: str = "_Type"
|
||||
if fd_ci == 1:
|
||||
fd_cn = "_str"
|
||||
viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name)
|
||||
fd_func = self.find_func_in_module(mod, fd_key)
|
||||
if fd_func is not None:
|
||||
fd_cls = fd_cn
|
||||
break
|
||||
if fd_func is None or fd_cls is None: return None
|
||||
# 扩展类结构体必须已注册(GEP/临时影子需要类型)
|
||||
fd_sty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(fd_cls)
|
||||
if fd_sty is None: return None
|
||||
# 扩展类字段数:有字段(_str)时 self 用影子结构体指针;
|
||||
# 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876)
|
||||
fd_entry_fd: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(fd_sty)
|
||||
fd_has_fields: int = 0
|
||||
if fd_entry_fd is not None and fd_entry_fd.FieldCount > 0:
|
||||
fd_has_fields = 1
|
||||
# self 参数:优先使用已有影子 {var}__meta__(fd2 创建,仅当扩展类有字段时)
|
||||
fd_self: llvmlite.Value* = None
|
||||
if fd_at.value.kind() == ast.ASTKind.Name:
|
||||
fd_onm: ast.Name* = ast.Name*(fd_at.value)
|
||||
if fd_onm.id is not None:
|
||||
# pool 持久缓冲(f-string 栈缓冲在函数返回后失效)
|
||||
fd_mn: str = pool.alloc(256)
|
||||
if fd_mn is not None:
|
||||
viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id)
|
||||
fd_meta: llvmlite.Value* = self.Gen.VarGen.lookup_current(trans.SymTab, fd_mn)
|
||||
if fd_meta is not None and fd_has_fields != 0:
|
||||
fd_self = fd_meta
|
||||
if fd_self is None:
|
||||
if fd_has_fields != 0:
|
||||
# 有字段扩展类且无影子(字符串字面量等):入口创建临时影子并初始化
|
||||
# 先确保 _str 完整定义(跨模块结构体默认 opaque,alloca 报 unsized)
|
||||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, fd_sty)
|
||||
fd_self = self.Gen.VarGen._alloca_at_entry(builder, fd_sty)
|
||||
if fd_self is None: return None
|
||||
fd_obj_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fd_at.value, None, 0, trans)
|
||||
if fd_obj_val is not None:
|
||||
fd_dfe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(fd_sty, "__data__")
|
||||
if fd_dfe is not None and fd_dfe.Ty is not None:
|
||||
fd_dp: llvmlite.Value* = llvmlite.build_gep_struct(builder, fd_sty, fd_dfe.Ty, fd_self, fd_dfe.Index)
|
||||
if fd_dp is not None:
|
||||
llvmlite.build_store(builder, fd_obj_val, fd_dp)
|
||||
fd_bfe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(fd_sty, "__mbuddy__")
|
||||
if fd_bfe is not None and fd_bfe.Ty is not None:
|
||||
fd_bp: llvmlite.Value* = llvmlite.build_gep_struct(builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index)
|
||||
fd_null: llvmlite.Value* = llvmlite.ConstNull(pool, fd_bfe.Ty, "null")
|
||||
if fd_bp is not None and fd_null is not None:
|
||||
llvmlite.build_store(builder, fd_null, fd_bp)
|
||||
# FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)
|
||||
self._inject_requires_fields(trans, pool, builder, mod, fd_self, fd_cls)
|
||||
else:
|
||||
# 无字段扩展类(_Type):对象值 bitcast 到扩展类指针
|
||||
fd_obj_v: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fd_at.value, None, 0, trans)
|
||||
if fd_obj_v is None: return None
|
||||
fd_self = llvmlite.build_bitcast(builder, fd_obj_v, llvmlite.Ptr(pool, fd_sty))
|
||||
if fd_self is None: return None
|
||||
# 构建参数链表: self → 其余参数
|
||||
llvmlite.value_set_next(fd_self, None)
|
||||
fd_head: llvmlite.Value* = fd_self
|
||||
fd_tail: llvmlite.Value* = fd_self
|
||||
fd_args: list[ast.AST*]* = cl.args
|
||||
fd_can: int = 0
|
||||
if fd_args is not None:
|
||||
fd_can = len(fd_args)
|
||||
for fd_ai in range(fd_can):
|
||||
fd_arg: ast.AST* = fd_args.get(fd_ai)
|
||||
if fd_arg is not None:
|
||||
fd_av: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fd_arg, None, 0, trans)
|
||||
# char 常量参数 → 单字符字符串(char 隐式转 str,
|
||||
# 如 s1.split(','):',' 是 i32 值 44,传给 str 参数须先字符串化,
|
||||
# 否则运行时 strlen/strncmp 解引用 44 崩溃)
|
||||
if fd_arg.kind() == ast.ASTKind.Constant:
|
||||
fd_ac: ast.Constant* = ast.Constant*(fd_arg)
|
||||
if fd_ac.const_kind == ast.CONST_CHAR:
|
||||
ch_buf: str = pool.alloc(2)
|
||||
if ch_buf is not None:
|
||||
ch_buf[0] = char(fd_ac.int_val)
|
||||
ch_buf[1] = '\0'
|
||||
fd_av = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, ch_buf, trans)
|
||||
if fd_av is not None:
|
||||
llvmlite.value_set_next(fd_av, None)
|
||||
llvmlite.value_set_next(fd_tail, fd_av)
|
||||
fd_tail = fd_av
|
||||
# 返回类型与调用名(来自 find_func_in_module 命中的函数定义)
|
||||
fd_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(fd_func)
|
||||
if fd_ret_ty is None:
|
||||
fd_ret_ty = llvmlite.Int32(pool)
|
||||
fd_fname: str = llvmlite.function_get_name(fd_func)
|
||||
if fd_fname is None: return None
|
||||
# 返回类型精确化:跨模块 declare 的 list[T] 特化返回类型可能被简化为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标路径而非 list 内联 __getitem__(printf %s 崩溃)。从定义模块 text.ll 读取精确返回类型;仅当函数名确为 "{16hex}.{func}"(判定走唯一真源 GenApi.sha1_prefix_len)才提取模块 sha1
|
||||
if GenApi.sha1_prefix_len(fd_fname) != 0:
|
||||
fd_sha1: str = pool.alloc(17)
|
||||
if fd_sha1 is not None:
|
||||
string.strncpy(fd_sha1, fd_fname, 16)
|
||||
fd_sha1[16] = '\0'
|
||||
fd_exact: llvmlite.LLVMType* = self._LookupMethodRetTyFromTextLL(pool, fd_sha1, fd_cls, method_name)
|
||||
if fd_exact is not None:
|
||||
fd_ret_ty = fd_exact
|
||||
fd_total: int = 1 + fd_can
|
||||
return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0)
|
||||
# ============================================================
|
||||
# _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段
|
||||
#
|
||||
# 对齐 TPC HandlesExprCall.py L4021-4079:
|
||||
# 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用
|
||||
# _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时
|
||||
# bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖
|
||||
# 用户已手动设置的值)。_find_provider 未注册(未 import
|
||||
# _withcontent)时跳过注入,不影响非 with 场景。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _inject_requires_fields(self, trans: HT.Translator*,
|
||||
pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
meta_ptr: llvmlite.Value*,
|
||||
class_name: str) -> int:
|
||||
"""在 with 上下文注入 requires 字段,返回注入字段数"""
|
||||
if trans is None or pool is None or builder is None or mod is None:
|
||||
return 0
|
||||
if meta_ptr is None or class_name is None:
|
||||
return 0
|
||||
# _withcontent._find_provider(跨模块):仅当本模块可见(_withcontent
|
||||
# 被 import,vpi stub declare 已注入)时才注入。对齐 TPC L4048-4050
|
||||
# (Gen.functions.get('_find_provider') 不存在则跳过)——否则非 with
|
||||
# 项目(如 HashTableTest 未 import _withcontent)也会为每个 _str(...)
|
||||
# 构造发射 {sha1}._find_provider 调用 → ld.lld undefined symbol。
|
||||
fd_fn_probe: llvmlite.Function* = self.find_func_in_module(mod, "_find_provider")
|
||||
if fd_fn_probe is None: return 0
|
||||
fd_fname: str = llvmlite.function_get_name(fd_fn_probe)
|
||||
if fd_fname is None: return 0
|
||||
cnt: int = self.Gen.ClassGenBase.class_meta_count(GenTypes.CLASS_META_REQUIRES, class_name)
|
||||
if cnt <= 0: return 0
|
||||
sty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(class_name)
|
||||
if sty is None: return 0
|
||||
i8_ty_j: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
if i8_ty_j is None: return 0
|
||||
i8_ptr_ty_j: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_j)
|
||||
if i8_ptr_ty_j is None: return 0
|
||||
cur_func: llvmlite.Function* = trans._cur_func
|
||||
if cur_func is None: return 0
|
||||
injected: int = 0
|
||||
for ji in range(cnt):
|
||||
fname: str = self.Gen.ClassGenBase.class_meta_field_at(GenTypes.CLASS_META_REQUIRES, class_name, ji)
|
||||
if fname is None: continue
|
||||
fe: GenTypes.FieldEntry* = self.Gen.StructGen.lookup_field(sty, fname)
|
||||
if fe is None or fe.Ty is None: continue
|
||||
# 参数:字段名字符串(i8*)
|
||||
fd_fstr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fname, trans)
|
||||
if fd_fstr is None: continue
|
||||
llvmlite.value_set_next(fd_fstr, None)
|
||||
self._ensure_method_declare(pool, mod, fd_fname, i8_ptr_ty_j, fd_fstr, 1)
|
||||
fd_ptr: llvmlite.Value* = llvmlite.build_call(builder, fd_fname, fd_fstr, 1, i8_ptr_ty_j, 0)
|
||||
if fd_ptr is None: continue
|
||||
# 条件注入:ptr != NULL 才写入(保留用户手动设置的值)
|
||||
fd_null: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty_j, "null")
|
||||
if fd_null is None: continue
|
||||
fd_cmp: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, fd_ptr, fd_null)
|
||||
if fd_cmp is None: continue
|
||||
# 块名唯一化(create_block 不自动编号,同名 label 在文本 IR 中
|
||||
# 冲突 → llc "Terminator found in the middle of a basic block")
|
||||
vtc2: int = trans._label_counter
|
||||
trans._label_counter = vtc2 + 1
|
||||
fd_bb_buf2: str = pool.alloc(64)
|
||||
if fd_bb_buf2 is None: continue
|
||||
viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2)
|
||||
fd_skip_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, cur_func, fd_bb_buf2)
|
||||
viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2)
|
||||
fd_inject_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, cur_func, fd_bb_buf2)
|
||||
if fd_skip_bb is None or fd_inject_bb is None: continue
|
||||
llvmlite.build_cond_br(builder, fd_cmp, fd_inject_bb, fd_skip_bb)
|
||||
# inject 块:bitcast + GEP + store,跳回 skip
|
||||
llvmlite.position_at_end(builder, fd_inject_bb)
|
||||
fd_cast: llvmlite.Value* = llvmlite.build_bitcast(builder, fd_ptr, fe.Ty)
|
||||
if fd_cast is not None:
|
||||
fd_fp: llvmlite.Value* = llvmlite.build_gep_struct(builder, sty, fe.Ty, meta_ptr, fe.Index)
|
||||
if fd_fp is not None: llvmlite.build_store(builder, fd_cast, fd_fp)
|
||||
llvmlite.build_br(builder, fd_skip_bb)
|
||||
# skip 块:恢复 CurBlock,继续后续代码生成
|
||||
llvmlite.position_at_end(builder, fd_skip_bb)
|
||||
injected += 1
|
||||
return injected
|
||||
# ============================================================
|
||||
# _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文
|
||||
# provider push/pop(__provides__ 元数据,fd1 注册)
|
||||
#
|
||||
# 对齐 TPC HandlesWith.py L138-174:
|
||||
# with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8);
|
||||
# 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责
|
||||
# 维护 TLS provider 栈,供 _inject_requires_fields 查找。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _emit_provider_push(self, trans: HT.Translator*,
|
||||
pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
cls_name: str,
|
||||
ctx_val: llvmlite.Value*) -> int:
|
||||
"""生成 _push_provider(field, ctx_i8) 调用(每提供字段一次),返回字段数"""
|
||||
if trans is None or pool is None or builder is None or mod is None: return 0
|
||||
if cls_name is None or ctx_val is None: return 0
|
||||
fd_pc: int = self.Gen.ClassGenBase.class_meta_count(GenTypes.CLASS_META_PROVIDES, cls_name)
|
||||
if fd_pc <= 0: return 0
|
||||
# _withcontent._push_provider(跨模块,同 _find_provider 的可见性守卫:
|
||||
# 本模块未 import _withcontent 时跳过,避免 undefined symbol)
|
||||
fd_pfn_probe: llvmlite.Function* = self.find_func_in_module(mod, "_push_provider")
|
||||
if fd_pfn_probe is None: return 0
|
||||
fd_pfn: str = llvmlite.function_get_name(fd_pfn_probe)
|
||||
if fd_pfn is None: return 0
|
||||
i8_ty_p: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
if i8_ty_p is None: return 0
|
||||
i8_ptr_ty_p: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_p)
|
||||
if i8_ptr_ty_p is None: return 0
|
||||
ret_i32_p: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
if ret_i32_p is None: return 0
|
||||
# ctx 值 bitcast 到 i8*(provider 栈存 void*)
|
||||
fd_ctx_i8: llvmlite.Value* = llvmlite.build_bitcast(builder, ctx_val, i8_ptr_ty_p)
|
||||
if fd_ctx_i8 is None: return 0
|
||||
for pi in range(fd_pc):
|
||||
fname: str = self.Gen.ClassGenBase.class_meta_field_at(GenTypes.CLASS_META_PROVIDES, cls_name, pi)
|
||||
if fname is None: continue
|
||||
fd_fstr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fname, trans)
|
||||
if fd_fstr is None: continue
|
||||
llvmlite.value_set_next(fd_fstr, fd_ctx_i8)
|
||||
llvmlite.value_set_next(fd_ctx_i8, None)
|
||||
self._ensure_method_declare(pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2)
|
||||
llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0)
|
||||
return fd_pc
|
||||
def _emit_provider_pop(self, trans: HT.Translator*,
|
||||
pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
cls_name: str) -> int:
|
||||
"""生成 _pop_provider() 调用(每提供字段一次),返回字段数"""
|
||||
if trans is None or pool is None or builder is None or mod is None: return 0
|
||||
if cls_name is None: return 0
|
||||
fd_pc: int = self.Gen.ClassGenBase.class_meta_count(GenTypes.CLASS_META_PROVIDES, cls_name)
|
||||
if fd_pc <= 0: return 0
|
||||
# _withcontent._pop_provider(跨模块,同 _find_provider 的可见性守卫:
|
||||
# 本模块未 import _withcontent 时跳过,避免 undefined symbol)
|
||||
fd_pon_probe: llvmlite.Function* = self.find_func_in_module(mod, "_pop_provider")
|
||||
if fd_pon_probe is None: return 0
|
||||
fd_pon: str = llvmlite.function_get_name(fd_pon_probe)
|
||||
if fd_pon is None: return 0
|
||||
ret_i32_q: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
if ret_i32_q is None: return 0
|
||||
self._ensure_method_declare(pool, mod, fd_pon, ret_i32_q, None, 0)
|
||||
for _pi in range(fd_pc):
|
||||
llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0)
|
||||
return fd_pc
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,783 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
|
||||
from . import CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenLib - CallGenMixin 拆分(阶段 C):C 库声明 / 返回类型推断 /
|
||||
# ============================================================
|
||||
novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
"""C 库声明 / 返回类型推断 / kwargs 调用辅助(继承 Base)"""
|
||||
|
||||
def _ensure_c_lib_declare(self, pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
name: str) -> llvmlite.Function*:
|
||||
"""为已知的 C 库函数创建 declare 声明"""
|
||||
if pool is None or mod is None or name is None: return None
|
||||
|
||||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
ret_ty: llvmlite.LLVMType* = None
|
||||
params: int = 0 # 参数数量
|
||||
|
||||
if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0:
|
||||
ret_ty = i64_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "memset") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "memcpy") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "memmove") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "memcmp") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "strcmp") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 2
|
||||
elif string.strcmp(name, "strncmp") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "strcpy") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 2
|
||||
elif string.strcmp(name, "strncpy") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "strcat") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 2
|
||||
elif string.strcmp(name, "puts") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "atoi") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "atol") == 0:
|
||||
ret_ty = i64_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "abs") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "labs") == 0:
|
||||
ret_ty = i64_ty
|
||||
params = 1
|
||||
else:
|
||||
return None
|
||||
|
||||
# 创建 declare
|
||||
fn: llvmlite.Function* = llvmlite.create_declare(pool, mod, name, ret_ty)
|
||||
if fn is None:
|
||||
return None
|
||||
# 添加参数
|
||||
if params == 1:
|
||||
if string.strcmp(name, "abs") == 0:
|
||||
llvmlite.add_param(pool, fn, i32_ty, "n")
|
||||
elif string.strcmp(name, "labs") == 0:
|
||||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||||
else:
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "s")
|
||||
elif params == 2:
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "src")
|
||||
elif params == 3:
|
||||
if string.strcmp(name, "memset") == 0:
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||||
llvmlite.add_param(pool, fn, i32_ty, "c")
|
||||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||||
else:
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "src")
|
||||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||||
return fn
|
||||
|
||||
def _promote_clib_call_args(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
call_name: str,
|
||||
head: llvmlite.Value*,
|
||||
count: int) -> llvmlite.Value*:
|
||||
"""裸名 C 库函数实参按标准签名提升(B3)。
|
||||
|
||||
跨模块裸名调用(string.memset → @memset)时 _ensure_method_declare 用
|
||||
实参类型建 declare:第三参字面量 32=i32 把定义 sizet(i64) 固化窄
|
||||
→ declare/call @memset(i8*,i32,i32) vs 定义 @memset(i8*,i32,i64),
|
||||
ABI 宽度不一致(VKernel process.vp B3)。调用点先把第三参窄整数
|
||||
实参提升到 i64,declare 与 call 均按 i64 生成 → 与定义一致。
|
||||
未命中白名单原样返回 head。
|
||||
"""
|
||||
if pool is None or builder is None or call_name is None or head is None:
|
||||
return head
|
||||
# 仅裸名(无 '.' 分隔 → 无 sha1 前缀);带前缀走 vpi 定义侧解析
|
||||
if string.strchr(call_name, 46) is not None:
|
||||
return head
|
||||
# 白名单:size_t(i64) 长度参数所在下标(与 _ensure_c_lib_declare 一致;vsnprintf 第二参即 sizet 长度)
|
||||
size_idx: int = -1
|
||||
if string.strcmp(call_name, "memset") == 0: size_idx = 2
|
||||
elif string.strcmp(call_name, "memcpy") == 0: size_idx = 2
|
||||
elif string.strcmp(call_name, "memmove") == 0: size_idx = 2
|
||||
elif string.strcmp(call_name, "memcmp") == 0: size_idx = 2
|
||||
elif string.strcmp(call_name, "strncmp") == 0: size_idx = 2
|
||||
elif string.strcmp(call_name, "strncpy") == 0: size_idx = 2
|
||||
elif string.strcmp(call_name, "strncat") == 0: size_idx = 2
|
||||
elif string.strcmp(call_name, "vsnprintf") == 0: size_idx = 1
|
||||
if size_idx < 0 or count <= size_idx:
|
||||
return head
|
||||
# 定位长度参数(index size_idx)
|
||||
cur: llvmlite.Value* = head
|
||||
idx: int = 0
|
||||
while cur is not None and idx < size_idx:
|
||||
cur = cur.Next
|
||||
idx += 1
|
||||
if cur is None or cur.Ty is None:
|
||||
return head
|
||||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||||
promoted: llvmlite.Value* = None
|
||||
match cur.Ty:
|
||||
case llvmlite.LLVMType.Int(bits):
|
||||
if bits >= 64:
|
||||
return head
|
||||
if cur.IsConst != 0:
|
||||
# 常量:直接 i64 常量(位模式保留,无符号长度语义)
|
||||
promoted = llvmlite.const_int(pool, 64, cur.IntVal)
|
||||
else:
|
||||
# SSA 值:zext 到 i64(size_t 无符号长度)
|
||||
promoted = llvmlite.build_zext(builder, cur, i64_ty)
|
||||
case _:
|
||||
return head
|
||||
if promoted is None:
|
||||
return head
|
||||
# 重建实参链表:index size_idx 替换为提升后的值
|
||||
new_head: llvmlite.Value* = None
|
||||
new_tail: llvmlite.Value* = None
|
||||
cur2: llvmlite.Value* = head
|
||||
i2: int = 0
|
||||
while cur2 is not None:
|
||||
node_v: llvmlite.Value* = cur2
|
||||
if i2 == size_idx:
|
||||
node_v = promoted
|
||||
if new_head is None:
|
||||
new_head = node_v
|
||||
else:
|
||||
new_tail.Next = node_v
|
||||
new_tail = node_v
|
||||
cur2 = cur2.Next
|
||||
i2 += 1
|
||||
return new_head
|
||||
|
||||
# _coerce_args_to_def_params:按 vpi 定义侧形参注解把跨模块调用实参 coerce 到目标类型并重建实参链,使 call/declare/define 宽度一致;支持 {sha1}.{func} 与 {sha1}.{cls}.{method} 两形态(段下标与实参下标一一对应),裸名 C 库走 _promote_clib_call_args/_ensure_c_lib_declare,未命中原样保留
|
||||
def _coerce_args_to_def_params(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
call_name: str,
|
||||
head: llvmlite.Value*,
|
||||
count: int,
|
||||
cargs: list[ast.AST*]* = None,
|
||||
self_off: int = 0,
|
||||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||||
"""把跨模块调用实参 coerce 到 vpi 定义侧形参类型,返回重建的实参链
|
||||
|
||||
cargs/self_off/trans:实参 AST 列表与其在实参链中的偏移(模块级函数 0、
|
||||
方法 1——链首元素是 self,而 vpi 段 0 即 self 占位段)。仅用于非常量
|
||||
(SSA)整型扩宽时的**源符号性**判定(与 ExprGenBase._zext_or_sext_val
|
||||
同源);缺省时该判定退化为有符号(sext),与 coerce_to_type 默认一致。
|
||||
"""
|
||||
if pool is None or builder is None or call_name is None or head is None:
|
||||
return head
|
||||
if self._is_sha1_mangled_call(call_name) == 0:
|
||||
return head
|
||||
# 拆 {sha1}.{rest}:rest 含 '.' 则为 {cls}.{method},否则为 {func}
|
||||
rest: str = call_name + 17
|
||||
cls_nm: str = None
|
||||
meth_nm: str = rest
|
||||
# 取末个 '.':method 不含 '.',首个 '.' 会把含模块限定名的类型实参截断
|
||||
dot_r: str = string.strrchr(rest, 46)
|
||||
if dot_r is not None:
|
||||
cls_len: sizet = uint64(dot_r) - uint64(rest)
|
||||
if cls_len <= 0:
|
||||
return head
|
||||
cls_buf: bytes = stdlib.malloc(cls_len + 1)
|
||||
if cls_buf is None:
|
||||
return head
|
||||
string.strncpy(cls_buf, rest, cls_len)
|
||||
cls_buf[cls_len] = '\0'
|
||||
cls_nm = cls_buf
|
||||
meth_nm = dot_r + 1
|
||||
if meth_nm is None or meth_nm[0] == '\0':
|
||||
if cls_nm is not None:
|
||||
stdlib.free(cls_nm)
|
||||
return head
|
||||
sha1_buf: bytes = stdlib.malloc(17)
|
||||
if sha1_buf is None:
|
||||
if cls_nm is not None:
|
||||
stdlib.free(cls_nm)
|
||||
return head
|
||||
string.strncpy(sha1_buf, call_name, 16)
|
||||
sha1_buf[16] = '\0'
|
||||
# 直接 ensure 加载 + 直查缓存(不用 _vpi_method_param_annot:其 cls_name is None 时恒返回 None,模块级函数永不生效)
|
||||
if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0:
|
||||
VpiReader._ensure_vpi_param_annot_loaded(sha1_buf, self.Gen.CallGenBase.TempDir)
|
||||
prm_annots: str = VpiReader._lookup_vpi_param_annots(sha1_buf, cls_nm, meth_nm)
|
||||
# 泛型特化类({sha}.list[str].__new__):定义侧注解写在模板类上,精确键必遗漏 ⇒ tpl_src=1 时退查模板注解并替换类型形参(VpiReader._resolve_vpi_param_annot_seg_template)
|
||||
tpl_src: int = 0
|
||||
if prm_annots is None:
|
||||
if cls_nm is not None and string.strchr(cls_nm, 91) is not None:
|
||||
tpl_src = 1
|
||||
else:
|
||||
stdlib.free(sha1_buf)
|
||||
if cls_nm is not None:
|
||||
stdlib.free(cls_nm)
|
||||
return head
|
||||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
new_head: llvmlite.Value* = None
|
||||
new_tail: llvmlite.Value* = None
|
||||
cur: llvmlite.Value* = head
|
||||
idx: int = 0
|
||||
while cur is not None and idx < count:
|
||||
node_v: llvmlite.Value* = cur
|
||||
tgt_ty: llvmlite.LLVMType* = None
|
||||
if tpl_src != 0:
|
||||
tgt_ty = VpiReader._resolve_vpi_param_annot_seg_template(pool, sha1_buf, cls_nm, meth_nm, idx, i32_ty, i8_ptr_ty)
|
||||
else:
|
||||
tgt_ty = VpiReader._resolve_vpi_param_annot_seg(pool, sha1_buf, cls_nm, meth_nm, idx, i32_ty, i8_ptr_ty)
|
||||
if tgt_ty is not None and cur.Ty is not None:
|
||||
# 实参 AST(源符号性判定用):链下标 idx 减 self 偏移即 AST 下标
|
||||
arg_idx: int = idx - self_off
|
||||
arg_node: ast.AST* = None
|
||||
if cargs is not None and arg_idx >= 0 and arg_idx < len(cargs):
|
||||
arg_node = cargs.get(arg_idx)
|
||||
node_v = self._coerce_arg_value_to_ty(pool, builder, cur, tgt_ty, arg_node, trans, tpl_src)
|
||||
if new_head is None:
|
||||
new_head = node_v
|
||||
else:
|
||||
new_tail.Next = node_v
|
||||
new_tail = node_v
|
||||
cur = cur.Next
|
||||
idx += 1
|
||||
stdlib.free(sha1_buf)
|
||||
if cls_nm is not None:
|
||||
stdlib.free(cls_nm)
|
||||
return new_head
|
||||
|
||||
# _coerce_arg_value_to_ty:单个实参 Value 转换到目标形参类型——整型同宽原样、窄化 trunc/按宽度重建常量、扩宽按源符号性 zext/sext;同层指针类型不一致则 bitcast 到目标类型;其余原样返回(不可转换亦不改型)
|
||||
def _coerce_arg_value_to_ty(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
val: llvmlite.Value*,
|
||||
tgt_ty: llvmlite.LLVMType*,
|
||||
node: ast.AST* = None,
|
||||
trans: HT.Translator* = None,
|
||||
tpl_src: int = 0) -> llvmlite.Value*:
|
||||
"""把单个实参 Value 转换到目标形参类型,无法安全转换时原样返回
|
||||
|
||||
node/trans:实参 AST 与其翻译器(仅 SSA 整型扩宽的源符号性判定用,
|
||||
委托 ExprGenBase._zext_or_sext_val;缺省退化为有符号 sext)。
|
||||
tpl_src:目标类型来自**泛型模板类**注解(特化名精确键遗漏 → 退查模板 +
|
||||
类型形参替换,见 VpiReader._resolve_vpi_param_annot_seg_template)⇒
|
||||
指针口径亦可对齐定义侧(同为具体结构体指针但基类型不同时 bitcast)。
|
||||
"""
|
||||
if pool is None or builder is None or val is None or tgt_ty is None or val.Ty is None:
|
||||
return val
|
||||
match val.Ty:
|
||||
case llvmlite.LLVMType.Int(bits_a):
|
||||
match tgt_ty:
|
||||
case llvmlite.LLVMType.Int(bits_b):
|
||||
if bits_b == bits_a:
|
||||
return val
|
||||
if bits_b < bits_a:
|
||||
if val.IsConst != 0:
|
||||
nv_c: llvmlite.Value* = llvmlite.const_int(pool, bits_b, val.IntVal)
|
||||
if nv_c is not None: return nv_c
|
||||
else:
|
||||
nv_t: llvmlite.Value* = llvmlite.build_trunc(builder, val, tgt_ty)
|
||||
if nv_t is not None: return nv_t
|
||||
# 扩宽(实参窄于形参):编译期常量按十进制值重建,各自保持原类型数值,无需 AST 判符号性
|
||||
if val.IsConst != 0:
|
||||
nv_w: llvmlite.Value* = llvmlite.const_int(pool, bits_b, val.IntVal)
|
||||
if nv_w is not None:
|
||||
return nv_w
|
||||
return val
|
||||
# 非常量(SSA)扩宽:扩宽方向由源符号性决定(i1/i8、无符号源 → zext,否则 sext),使 declare/call/define 三者同宽
|
||||
if bits_b > bits_a:
|
||||
if self.Gen.ExprGenBase._zext_or_sext_val(pool, val, node, trans) != 0:
|
||||
nv_zw: llvmlite.Value* = llvmlite.build_zext(builder, val, tgt_ty)
|
||||
if nv_zw is not None: return nv_zw
|
||||
else:
|
||||
nv_sw: llvmlite.Value* = llvmlite.build_sext(builder, val, tgt_ty)
|
||||
if nv_sw is not None: return nv_sw
|
||||
return val
|
||||
case _:
|
||||
pass
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
match tgt_ty:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
# 同层指针:实参类型与定义侧形参类型不一致就 bitcast 对齐(一致则不比,
|
||||
# 避免生成非法 `bitcast T* to T*`)。跨模块调用的 call/declare 都以
|
||||
# 定义侧为准(declare 见 CallGenBase._ensure_method_declare),故这里
|
||||
# 必须对齐:首个调用点由它建立 declare、不走 coerce_to_type,原样传具体
|
||||
# 指针就会与 declare 的类型不一致(llc 报 argument type mismatch)。
|
||||
# 原判据只覆盖"一侧为 i8*"与"模板注解来源",漏了两侧同为具体结构体指针
|
||||
# 但基类型不同的情形(实参 MemBuddy* vs 定义侧形参 MemManager*)。
|
||||
if self.Gen.AssignGen._stg_ty_equal(pool, val.Ty, tgt_ty) == 0:
|
||||
nv_p: llvmlite.Value* = llvmlite.build_bitcast(builder, val, tgt_ty)
|
||||
if nv_p is not None: return nv_p
|
||||
case _:
|
||||
pass
|
||||
case _:
|
||||
# 聚合值 → 指针:rvalue 结构体/数组落栈取址(FuncGenDef 形参一律 lowering 为 Ptr,跨模块时上游 coerce_to_type 不参与)
|
||||
match tgt_ty:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
vk_a: int = val.Ty.kind()
|
||||
if vk_a == llvmlite.LLVMType.Struct or vk_a == llvmlite.LLVMType.Array:
|
||||
tmp_a: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, val.Ty)
|
||||
if tmp_a is not None:
|
||||
llvmlite.build_store(builder, val, tmp_a)
|
||||
return tmp_a
|
||||
case _:
|
||||
pass
|
||||
return val
|
||||
|
||||
def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy*,
|
||||
func_name: str,
|
||||
node: ast.AST*,
|
||||
fatal_if_unknown: int) -> llvmlite.LLVMType*:
|
||||
"""根据函数名推断外部 includes 函数的返回类型
|
||||
|
||||
支持三种函数名形式:
|
||||
1. 裸名: "parse", "strlen"
|
||||
2. 别名: "json_parse"(from X import parse as json_parse)
|
||||
3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name)
|
||||
|
||||
fatal_if_unknown: 白名单全部未命中时的行为。
|
||||
=1(纯裸名外部函数,无法收敛)→ fatal_error fail-fast(默认 i32
|
||||
会截断指针/i64,静默生成导致运行时数据损坏,不兜底原则)。
|
||||
=0(Phase A 中间遍,_deps_pending 下遍重译可收敛)→ 返回默认
|
||||
i32 占位,不输出 WARN(下遍依赖就绪后走 text.ll/vpi 精确解析)。
|
||||
"""
|
||||
if pool is None or func_name is None:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
# 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse")
|
||||
# SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔
|
||||
bare_name: str = func_name
|
||||
dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.')
|
||||
if dot_pos is not None:
|
||||
# '.' 后的部分是裸函数名
|
||||
bare_name = dot_pos + 1
|
||||
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 返回 i8* 的函数(指针返回值,截断会导致错误)
|
||||
if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0:
|
||||
return i8_ptr_ty
|
||||
# JSON 解析函数返回 JsonValue*(指针)
|
||||
# from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖
|
||||
if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0:
|
||||
return i8_ptr_ty
|
||||
# MemBuddy 方法(当类型信息丢失时可能走外部函数路径)
|
||||
# 存疑
|
||||
# malloc:裸名 CExport 跨模块调用(uhci/desktop 等 mm.malloc → @malloc)
|
||||
# 在模块归属解析失败(mod_ret_sha1=None)或 vpi/text.ll 未命中时回退到
|
||||
# 此白名单。缺失导致返回类型被推断为 i32 → call i32 @malloc 截断 64 位
|
||||
# 指针 → mm.malloc 实际返回非空但调用方判 None(uhci frame list /
|
||||
# desktop bg_row_buf 根因)。calloc/realloc/alloc 均已登记,malloc 遗漏。
|
||||
if string.strcmp(bare_name, "malloc") == 0 or string.strcmp(func_name, "malloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "alloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "calloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "realloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "alloc_buf") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃)
|
||||
if string.strcmp(func_name, "get_logger") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "fmt_buf") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏)
|
||||
if string.strcmp(func_name, "get_includes_binary_dir") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断)
|
||||
if string.strcmp(bare_name, "_parse_type_string") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 返回 i64 的函数
|
||||
if string.strcmp(func_name, "strlen") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(func_name, "atoll") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
# llvmlite 函数名长度访问器返回 sizet(i64):默认 i32 与 declare 的 i64 签名不一致,须登记
|
||||
if string.strcmp(bare_name, "function_get_name_len") == 0 or \
|
||||
string.strcmp(func_name, "function_get_name_len") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
|
||||
# 返回 double 的函数
|
||||
if string.strcmp(func_name, "atof") == 0:
|
||||
return llvmlite.Double(pool)
|
||||
|
||||
# 返回 i8 的函数
|
||||
if string.strcmp(func_name, "samestr") == 0:
|
||||
return llvmlite.Int8(pool)
|
||||
|
||||
# Win32 API 返回指针(VOIDPTR/HANDLE)的函数
|
||||
# stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "VirtualAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "HeapAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "HeapReAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "HeapCreate") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetProcessHeap") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GlobalAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GlobalFree") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GlobalLock") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "LocalAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "LocalFree") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetProcAddress") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetModuleHandleA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetModuleHandleW") == 0:
|
||||
return i8_ptr_ty
|
||||
# GetCommandLineA/W 返回 LPSTR(i8*):缺则 64 位指针被截成 i32,解引用读到无效地址
|
||||
if string.strcmp(func_name, "GetCommandLineA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetCommandLineW") == 0:
|
||||
return i8_ptr_ty
|
||||
# gethostbyname 返回 hostent*(i8*)
|
||||
if string.strcmp(func_name, "gethostbyname") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "LoadLibraryA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "LoadLibraryW") == 0:
|
||||
return i8_ptr_ty
|
||||
# Win32 Handle 返回函数(HANDLE = void* = i8*)
|
||||
if string.strcmp(func_name, "GetStdHandle") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "CreateFileA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "CreateFileW") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "FindFirstFileA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "FindFirstFileW") == 0:
|
||||
return i8_ptr_ty
|
||||
|
||||
# Win32 API 返回 i64 (SIZE_T) 的函数
|
||||
if string.strcmp(func_name, "VirtualQuery") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(func_name, "HeapSize") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(func_name, "HeapCompact") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(func_name, "GlobalSize") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
|
||||
# llvmlite build_* 返回类型推断:多数返回 Value*,少数终止指令返回 void(stubs 未注入时防指针截断)
|
||||
if string.strncmp(func_name, "build_", 6) == 0:
|
||||
# 返回 void 的 build_* 函数(终止指令和无返回值指令)
|
||||
if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \
|
||||
string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \
|
||||
string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \
|
||||
string.strcmp(func_name, "build_switch") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
# 其他 build_* 函数返回 Value*(指针)
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# llvmlite 类型工厂 / 常量构造 / 访问器函数返回指针(LLVMType*/Value*):Int*/Ptr/Func/Array/Struct/Void 等、const_*/Const*、function_get_*/param_get_*
|
||||
if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \
|
||||
string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \
|
||||
string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \
|
||||
string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \
|
||||
string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \
|
||||
string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \
|
||||
string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \
|
||||
string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \
|
||||
string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \
|
||||
string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \
|
||||
string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \
|
||||
string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \
|
||||
string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 默认 i32 占位:fatal_if_unknown=1 → fail-fast 报错;=0(Phase A 中间遍)保持占位,不输出 WARN
|
||||
if fatal_if_unknown != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"外部函数返回类型未登记且无法收敛推断(默认 i32 会截断指针/i64,需提供 stub 声明或加入白名单): {func_name}", "TypeError")
|
||||
return llvmlite.Int32(pool)
|
||||
def _get_external_func_param_ty(self, pool: memhub.MemBuddy*,
|
||||
func_name: str,
|
||||
param_idx: int) -> llvmlite.LLVMType*:
|
||||
"""获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型
|
||||
|
||||
对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中
|
||||
ULONG/SIZE_T 被统一翻译为 i64 的情况。
|
||||
"""
|
||||
if pool is None or func_name is None:
|
||||
return None
|
||||
|
||||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||||
|
||||
# Win32 API 函数列表:所有非指针参数在 declare 中都是 i64
|
||||
# (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64)
|
||||
win32_apis: list[str]* = [
|
||||
"VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery",
|
||||
"VirtualLock", "VirtualUnlock",
|
||||
"HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc",
|
||||
"HeapFree", "HeapSize", "HeapValidate", "HeapCompact",
|
||||
"GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize",
|
||||
"LocalAlloc", "LocalFree",
|
||||
"GetLastError", "SetLastError",
|
||||
"Sleep", "SleepEx",
|
||||
"GetTickCount", "GetProcessHeap"
|
||||
]
|
||||
|
||||
# list 迭代不支持,用 range + get 替代
|
||||
api_count: sizet = len(win32_apis)
|
||||
for ai in range(api_count):
|
||||
api_name: str = win32_apis.get(ai)
|
||||
if string.strcmp(api_name, func_name) == 0:
|
||||
return i64_ty
|
||||
|
||||
# 内存分配函数:size 参数声明为 i64(size_t),裸名回退时不提升则 call 与 define 宽度不匹配;calloc/realloc 的 size 在 idx 1
|
||||
if string.strcmp(func_name, "malloc") == 0 \
|
||||
or string.strcmp(func_name, "alloc") == 0 \
|
||||
or string.strcmp(func_name, "alloc_buf") == 0:
|
||||
if param_idx == 0:
|
||||
return i64_ty
|
||||
if string.strcmp(func_name, "calloc") == 0:
|
||||
if param_idx == 0 or param_idx == 1:
|
||||
return i64_ty
|
||||
if string.strcmp(func_name, "realloc") == 0:
|
||||
if param_idx == 1:
|
||||
return i64_ty
|
||||
|
||||
return None
|
||||
def _is_sha1_mangled_call(self, call_name: str) -> int:
|
||||
"""判断 call_name 是否为跨模块 Viper 函数("{16位小写hex}.func" 形式)
|
||||
|
||||
C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0,
|
||||
不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。
|
||||
判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛:不再接受大写 hex)。
|
||||
"""
|
||||
if call_name is None:
|
||||
return 0
|
||||
if GenApi.sha1_prefix_len(call_name) != 0:
|
||||
return 1
|
||||
return 0
|
||||
def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
dst_val: llvmlite.Value*,
|
||||
src_val: llvmlite.Value*,
|
||||
num_val: llvmlite.Value*) -> llvmlite.Value*:
|
||||
"""将 memcpy 调用映射到 @llvm.memcpy 内联函数
|
||||
|
||||
直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的
|
||||
Next 字段可能被其他操作污染,导致链表断裂)。
|
||||
"""
|
||||
if pool is None or builder is None or mod is None:
|
||||
return None
|
||||
if dst_val is None or src_val is None or num_val is None:
|
||||
return None
|
||||
|
||||
# 在函数顶部声明 void_ty,避免后续遮蔽
|
||||
void_ty: llvmlite.LLVMType* = llvmlite.Void(pool)
|
||||
|
||||
# 声明 @llvm.memcpy(如未声明)
|
||||
memcpy_func: llvmlite.Function* = self.find_func_in_module(mod, "llvm.memcpy")
|
||||
if memcpy_func is None:
|
||||
memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty)
|
||||
if memcpy_func is not None:
|
||||
i8_ptr_ty_d: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
i64_ty_d: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||||
i1_ty_d: llvmlite.LLVMType* = llvmlite.Int1(pool)
|
||||
llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst")
|
||||
llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src")
|
||||
llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len")
|
||||
llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile")
|
||||
|
||||
# 类型转换: dst, src → i8*; num → i64
|
||||
# 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||||
|
||||
# dst → i8*
|
||||
dst_coerced: llvmlite.Value* = dst_val
|
||||
dst_ty: llvmlite.LLVMType* = llvmlite.value_get_ty(dst_val)
|
||||
if self.Gen.ExprGenBase.is_ptr_type(dst_ty) != 0:
|
||||
dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty)
|
||||
else:
|
||||
dst_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(dst_ty)
|
||||
if dst_bits != 0:
|
||||
if dst_bits < 64:
|
||||
dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty)
|
||||
dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty)
|
||||
|
||||
# src → i8*
|
||||
src_coerced: llvmlite.Value* = src_val
|
||||
src_ty: llvmlite.LLVMType* = llvmlite.value_get_ty(src_val)
|
||||
if self.Gen.ExprGenBase.is_ptr_type(src_ty) != 0:
|
||||
src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty)
|
||||
else:
|
||||
src_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(src_ty)
|
||||
if src_bits != 0:
|
||||
if src_bits < 64:
|
||||
src_coerced = llvmlite.build_zext(builder, src_val, i64_ty)
|
||||
src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty)
|
||||
|
||||
# num → i64
|
||||
num_coerced: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, num_val, i64_ty)
|
||||
|
||||
if dst_coerced is None or src_coerced is None or num_coerced is None:
|
||||
return None
|
||||
|
||||
# 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数
|
||||
false_val: llvmlite.Value* = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false")
|
||||
|
||||
# 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移
|
||||
# (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty)
|
||||
llvmlite.value_set_next(dst_coerced, src_coerced)
|
||||
llvmlite.value_set_next(src_coerced, num_coerced)
|
||||
if false_val is not None:
|
||||
llvmlite.value_set_next(num_coerced, false_val)
|
||||
llvmlite.value_set_next(false_val, None)
|
||||
else:
|
||||
llvmlite.value_set_next(num_coerced, None)
|
||||
|
||||
# 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确)
|
||||
# _ll_name_needs_quote 已对 llvm. 前缀豁免引号
|
||||
result: llvmlite.Value* = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0)
|
||||
|
||||
# 返回 dst(匹配 C memcpy 语义: 返回 dest 指针)
|
||||
return dst_coerced
|
||||
# _translate_call_with_kwargs:带关键字参数的函数调用,按 found_func.Params 顺序构建实参链表(位置参数优先,否则按参数名匹配关键字)
|
||||
|
||||
# ============================================================
|
||||
def _translate_call_with_kwargs(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
func_name: str,
|
||||
found_func: llvmlite.Function*,
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
keywords: list[ast.AST*]*,
|
||||
kw_count: sizet,
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""带关键字参数的函数调用,按参数顺序构建调用链表
|
||||
|
||||
使用 llvmlite 访问器函数绕过 stub 类型限制:
|
||||
found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub
|
||||
类型中字段不足,直接访问会被 TransPyC 静默跳过。
|
||||
"""
|
||||
head: llvmlite.Value* = None
|
||||
tail: llvmlite.Value* = None
|
||||
actual_count: sizet = 0
|
||||
# memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染)
|
||||
mc_dst1: llvmlite.Value* = None
|
||||
mc_src1: llvmlite.Value* = None
|
||||
mc_num1: llvmlite.Value* = None
|
||||
|
||||
# 遍历函数参数链表(使用访问器获取 Head)
|
||||
param_idx: sizet = 0
|
||||
cur_param: llvmlite.Param* = llvmlite.function_get_param_head(found_func)
|
||||
|
||||
while cur_param is not None:
|
||||
arg_val: llvmlite.Value* = None
|
||||
param_ty: llvmlite.LLVMType* = llvmlite.param_get_ty(cur_param)
|
||||
if param_idx < can:
|
||||
# 优先使用位置参数
|
||||
arg: ast.AST* = cargs.get(param_idx)
|
||||
if arg is not None:
|
||||
# 传形参类型(char 字面量 → str 形参需物化字符串,见 translate_constant)
|
||||
arg_val = self.Gen.ExprGen.translate_value(builder, pool, mod, arg, None, 0, trans, param_ty)
|
||||
else:
|
||||
# 查找匹配的关键字参数
|
||||
param_name: str = llvmlite.param_get_name(cur_param)
|
||||
if param_name is not None:
|
||||
for ki in range(kw_count):
|
||||
kw: rawptr[ast.Keyword] = rawptr[ast.Keyword](keywords.get(ki))
|
||||
if kw is None or kw.arg is None or kw.value is None: continue
|
||||
if self.Gen.CallGenCall._kwarg_name_matches(kw.arg, param_name) == 1:
|
||||
arg_val = self.Gen.ExprGen.translate_value(builder, pool, mod, kw.value, None, 0, trans, param_ty)
|
||||
break
|
||||
|
||||
if arg_val is not None:
|
||||
# 类型转换(按参数类型,使用访问器)
|
||||
if param_ty is not None:
|
||||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, param_ty)
|
||||
arg_val.Next = None
|
||||
if head is None:
|
||||
head = arg_val
|
||||
else:
|
||||
tail.Next = arg_val
|
||||
tail = arg_val
|
||||
# memcpy 专用: 保存前三个参数的独立引用
|
||||
if actual_count == 0:
|
||||
mc_dst1 = arg_val
|
||||
elif actual_count == 1:
|
||||
mc_src1 = arg_val
|
||||
elif actual_count == 2:
|
||||
mc_num1 = arg_val
|
||||
actual_count += 1
|
||||
|
||||
param_idx += 1
|
||||
cur_param = llvmlite.param_get_next(cur_param)
|
||||
|
||||
# declare 与 define 统一用 found_func.Name:普通函数带 SHA1 前缀,t.CExtern/t.State/t.CExport 用裸名(用裸名会造成 call 与 define 符号名不一致)
|
||||
call_name: str = func_name
|
||||
found_name: str = llvmlite.function_get_name(found_func)
|
||||
if found_name is not None:
|
||||
call_name = found_name
|
||||
|
||||
# 返回类型(使用访问器)
|
||||
call_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(found_func)
|
||||
if call_ret_ty is None:
|
||||
# found_func 已有 declare 却读不到返回类型(访问器异常,罕见防御):
|
||||
# 白名单未命中也不 fail-fast,保持默认 i32(有声明即有类型来源)。
|
||||
call_ret_ty = self._infer_external_func_ret_ty(pool, func_name, None, 0)
|
||||
|
||||
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
|
||||
if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3:
|
||||
return self._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1)
|
||||
return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,4 +1,5 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
@@ -6,39 +7,18 @@ import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.Translator as HT
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
from . import CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenProp - CallGenMixin 拆分(阶段 B):属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenProp(CallGenBase.CallGenBase):
|
||||
novirtual class CallGenProp(CallGenBase.CallGenBase):
|
||||
"""属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)"""
|
||||
|
||||
# ============================================================
|
||||
# _ensure_method_declare - 为跨模块方法调用创建 declare 声明
|
||||
#
|
||||
# 当 found_func 为 None(stub 未注入或跨模块调用)时,
|
||||
# 在当前模块中创建函数声明,避免 llc 报 undefined value。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
|
||||
#
|
||||
@@ -57,26 +37,24 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
#
|
||||
# call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数)
|
||||
# ============================================================
|
||||
def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
def _translate_property_call(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
class_name: str,
|
||||
method_name: str,
|
||||
call_head: llvmlite.Value | t.CPtr,
|
||||
call_head: llvmlite.Value*,
|
||||
call_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""翻译属性/静态方法调用,返回 call 结果 Value"""
|
||||
if pool is None or builder is None or class_name is None or method_name is None:
|
||||
return None
|
||||
if pool is None or builder is None or class_name is None or method_name is None: return None
|
||||
|
||||
# 构造查找名: ClassName.method_name
|
||||
lookup_name: str = pool.alloc(128)
|
||||
if lookup_name is None:
|
||||
return None
|
||||
if lookup_name is None: return None
|
||||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
|
||||
|
||||
# 查找函数(精确/后缀匹配)
|
||||
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
|
||||
found_func: llvmlite.Function* = self.find_func_in_module(mod, lookup_name)
|
||||
|
||||
# 确定调用名
|
||||
call_name: str = lookup_name
|
||||
@@ -88,50 +66,38 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
# 未找到:用类所属模块的 SHA1 构造调用名
|
||||
cls_sha1_pc: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
if cls_sha1_pc is not None:
|
||||
mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2
|
||||
mlen_pc: sizet = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2
|
||||
mangled_pc: str = pool.alloc(mlen_pc)
|
||||
if mangled_pc is not None:
|
||||
viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name)
|
||||
call_name = mangled_pc
|
||||
|
||||
# 确定返回类型
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
call_ret_ty: llvmlite.LLVMType* = i32_ty
|
||||
if found_func is not None:
|
||||
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
|
||||
frt: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(found_func)
|
||||
if frt is not None:
|
||||
call_ret_ty = frt
|
||||
else:
|
||||
sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name)
|
||||
sp_ty1: llvmlite.LLVMType* = self._special_method_ret_ty(pool, class_name, method_name)
|
||||
if sp_ty1 is not None:
|
||||
call_ret_ty = sp_ty1
|
||||
else:
|
||||
cls_sha1_rt: str = self.Gen.StructGen.get_struct_sha1(class_name)
|
||||
looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||||
pool, cls_sha1_rt, class_name, method_name)
|
||||
looked_up_ty: llvmlite.LLVMType* = self._LookupMethodRetTyFromTextLL(pool, cls_sha1_rt, class_name, method_name)
|
||||
if looked_up_ty is not None:
|
||||
call_ret_ty = looked_up_ty
|
||||
else:
|
||||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||||
pool, cls_sha1_rt, class_name, method_name)
|
||||
vpi_ret_ty: llvmlite.LLVMType* = self._lookup_method_ret_ty_via_vpi(pool, cls_sha1_rt, class_name, method_name)
|
||||
if vpi_ret_ty is not None:
|
||||
call_ret_ty = vpi_ret_ty
|
||||
else:
|
||||
# Phase A 依赖未就绪(cls_sha1_rt None / 定义模块 text.ll 未生成):
|
||||
# 标记 pending 下遍重译(对齐 _translate_method_call L4783-4790),
|
||||
# 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。
|
||||
# 保持默认 i32(build_call(Void) 返回 None 会破坏表达式翻译)。
|
||||
if cls_sha1_rt is None \
|
||||
or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0:
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
# [DEPDBG] 临时诊断:属性方法依赖未就绪即 pending 的根因(用后移除)
|
||||
dbg_ms8: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||||
stdio.printf("[DEPDBG] pending(prop_ret): mod=%s cls=%s method=%s sha1=%s\n",
|
||||
dbg_ms8, class_name, method_name,
|
||||
cls_sha1_rt if cls_sha1_rt is not None else "none")
|
||||
# 依赖未就绪:保持默认 i32(build_call(Void) 返回 None
|
||||
# 会破坏表达式翻译;pending 文件本遍不写盘,下遍重译)
|
||||
call_ret_ty = llvmlite.Int32(pool)
|
||||
else:
|
||||
call_ret_ty = self._fail_method_ret_ty(method_name)
|
||||
@@ -140,18 +106,17 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
# 一致)。例如 from_long(10) 的 i32 字面量 → i64 形参(v: t.CLong),
|
||||
# 不转换则 call(i32) 与 declare(i64) 不匹配,llc 报参数类型错误。
|
||||
# 目标函数优先用已找到的 found_func,否则按 mangled 调用名查模块 declare。
|
||||
tgt_func_pc: llvmlite.Function | t.CPtr = found_func
|
||||
tgt_func_pc: llvmlite.Function* = found_func
|
||||
if tgt_func_pc is None:
|
||||
tgt_func_pc = self.find_func_in_module(mod, call_name)
|
||||
if tgt_func_pc is not None:
|
||||
prev_pc: llvmlite.Value | t.CPtr = None
|
||||
cur_arg_pc: llvmlite.Value | t.CPtr = call_head
|
||||
cur_param_pc: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(tgt_func_pc)
|
||||
prev_pc: llvmlite.Value* = None
|
||||
cur_arg_pc: llvmlite.Value* = call_head
|
||||
cur_param_pc: llvmlite.Param* = llvmlite.function_get_param_head(tgt_func_pc)
|
||||
while cur_arg_pc is not None and cur_param_pc is not None:
|
||||
param_ty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_pc)
|
||||
param_ty_pc: llvmlite.LLVMType* = llvmlite.param_get_ty(cur_param_pc)
|
||||
if param_ty_pc is not None and cur_arg_pc.Ty is not None:
|
||||
coerced_pc: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, cur_arg_pc, param_ty_pc)
|
||||
coerced_pc: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, cur_arg_pc, param_ty_pc)
|
||||
if coerced_pc is not None and coerced_pc != cur_arg_pc:
|
||||
# 保持链表完整性:新 Value 继承原节点的 Next,前驱指向新节点
|
||||
llvmlite.value_set_next(coerced_pc, cur_arg_pc.Next)
|
||||
@@ -176,22 +141,38 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
obj_node: ast.AST | t.CPtr) -> str:
|
||||
def _resolve_obj_class_name(self, pool: memhub.MemBuddy*,
|
||||
trans: HT.Translator*,
|
||||
obj_node: ast.AST*) -> str:
|
||||
"""解析对象表达式的类名(短名),失败返回 None"""
|
||||
if pool is None or trans is None or obj_node is None:
|
||||
return None
|
||||
if obj_node.kind() == ast.ASTKind.Name:
|
||||
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node)
|
||||
obj_nm: ast.Name* = ast.Name*(obj_node)
|
||||
if obj_nm.id is not None:
|
||||
var_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, obj_nm.id)
|
||||
if var_entry is not None and var_entry.AnnotClassName is not None:
|
||||
annot_val: str = var_entry.AnnotClassName
|
||||
dot_ptr: str = string.strrchr(annot_val, '.')
|
||||
if dot_ptr is not None:
|
||||
return dot_ptr + 1
|
||||
var_entry: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, obj_nm.id)
|
||||
annot_val: str = self.Gen.VarGen.var_annot_class_name(var_entry)
|
||||
if annot_val is not None:
|
||||
# [D32] 取「模块限定名」末段时只按**括号外**的 '.' 切分。
|
||||
# 此前用 string.strrchr 在整个串上找最后一个 '.':泛型特化名
|
||||
# "list[e94ef9e139461915.AST|t.CPtr]" 的 '.' 落在 '[' 内 ⇒
|
||||
# 返回 "AST|t.CPtr]" 这种垃圾短名 ⇒ 后续按它查表必落空,
|
||||
# 进而可能被兜底成任意特化(.get() 误分派)。
|
||||
n_av: sizet = string.strlen(annot_val)
|
||||
last_dot_av: sizet = n_av
|
||||
depth_av: int = 0
|
||||
ai_av: sizet = 0
|
||||
while ai_av < n_av:
|
||||
ch_av: int = annot_val[ai_av]
|
||||
if ch_av == '[':
|
||||
depth_av += 1
|
||||
elif ch_av == ']':
|
||||
depth_av -= 1
|
||||
elif ch_av == '.' and depth_av == 0:
|
||||
last_dot_av = ai_av
|
||||
ai_av += 1
|
||||
if last_dot_av < n_av:
|
||||
return annot_val + last_dot_av + 1
|
||||
return annot_val
|
||||
return None
|
||||
# ============================================================
|
||||
@@ -202,13 +183,13 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
at_node: ast.Attribute | t.CPtr,
|
||||
obj_ptr: llvmlite.Value | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
fallback_class_name: str = None) -> llvmlite.Value | t.CPtr:
|
||||
def _try_property_getter_attr(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
at_node: ast.Attribute*,
|
||||
obj_ptr: llvmlite.Value*,
|
||||
trans: HT.Translator*,
|
||||
fallback_class_name: str = None) -> llvmlite.Value*:
|
||||
"""尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None
|
||||
|
||||
fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。
|
||||
@@ -225,8 +206,7 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
return None
|
||||
# 单参数调用: obj → getter
|
||||
llvmlite.value_set_next(obj_ptr, None)
|
||||
return self._translate_property_call(
|
||||
pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans)
|
||||
return self._translate_property_call(pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans)
|
||||
# ============================================================
|
||||
# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用
|
||||
#
|
||||
@@ -235,36 +215,29 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
target_attr: ast.Attribute | t.CPtr,
|
||||
rhs_val: llvmlite.Value | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
def _try_property_setter(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
target_attr: ast.Attribute*,
|
||||
rhs_val: llvmlite.Value*,
|
||||
trans: HT.Translator*) -> int:
|
||||
"""尝试 property setter 赋值,返回 1=已处理(生成调用)"""
|
||||
if pool is None or builder is None or mod is None or trans is None:
|
||||
return 0
|
||||
if target_attr is None or target_attr.attr is None or rhs_val is None:
|
||||
return 0
|
||||
if pool is None or builder is None or mod is None or trans is None: return 0
|
||||
if target_attr is None or target_attr.attr is None or rhs_val is None: return 0
|
||||
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
|
||||
if class_name is None:
|
||||
return 0
|
||||
if class_name is None: return 0
|
||||
meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, target_attr.attr)
|
||||
if meta & GenTypes.META_PROP_SETTER == 0:
|
||||
return 0
|
||||
if meta & GenTypes.META_PROP_SETTER == 0: return 0
|
||||
# 翻译对象值(self 参数)
|
||||
obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, target_attr.value, None, 0, trans)
|
||||
if obj_val is None:
|
||||
return 0
|
||||
obj_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, target_attr.value, None, 0, trans)
|
||||
if obj_val is None: return 0
|
||||
# 构建参数链表: obj → rhs
|
||||
llvmlite.value_set_next(obj_val, None)
|
||||
llvmlite.value_set_next(rhs_val, None)
|
||||
llvmlite.value_set_next(obj_val, rhs_val)
|
||||
# setter 函数名带 $set 后缀
|
||||
setter_name_buf: str = pool.alloc(128)
|
||||
if setter_name_buf is None:
|
||||
return 0
|
||||
if setter_name_buf is None: return 0
|
||||
viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr)
|
||||
self._translate_property_call(pool, builder, mod, class_name,
|
||||
setter_name_buf, obj_val, 2, trans)
|
||||
@@ -277,32 +250,25 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
target_attr: ast.Attribute | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
def _try_property_deleter(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
target_attr: ast.Attribute*,
|
||||
trans: HT.Translator*) -> int:
|
||||
"""尝试 property deleter 删除,返回 1=已处理(生成调用)"""
|
||||
if pool is None or builder is None or mod is None or trans is None:
|
||||
return 0
|
||||
if target_attr is None or target_attr.attr is None:
|
||||
return 0
|
||||
if pool is None or builder is None or mod is None or trans is None: return 0
|
||||
if target_attr is None or target_attr.attr is None: return 0
|
||||
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
|
||||
if class_name is None:
|
||||
return 0
|
||||
if class_name is None: return 0
|
||||
meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, target_attr.attr)
|
||||
if meta & GenTypes.META_PROP_DELETER == 0:
|
||||
return 0
|
||||
if meta & GenTypes.META_PROP_DELETER == 0: return 0
|
||||
# 翻译对象值(self 参数)
|
||||
obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, target_attr.value, None, 0, trans)
|
||||
if obj_val is None:
|
||||
return 0
|
||||
obj_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, target_attr.value, None, 0, trans)
|
||||
if obj_val is None: return 0
|
||||
llvmlite.value_set_next(obj_val, None)
|
||||
# deleter 函数名带 $del 后缀
|
||||
del_name_buf: str = pool.alloc(128)
|
||||
if del_name_buf is None:
|
||||
return 0
|
||||
if del_name_buf is None: return 0
|
||||
viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr)
|
||||
self._translate_property_call(pool, builder, mod, class_name,
|
||||
del_name_buf, obj_val, 1, trans)
|
||||
@@ -315,58 +281,48 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
def _translate_static_class_call(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
class_name: str,
|
||||
method_name: str,
|
||||
cl: ast.Call | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
cl: ast.Call*,
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None"""
|
||||
if pool is None or builder is None or mod is None or trans is None:
|
||||
return None
|
||||
if class_name is None or method_name is None or cl is None:
|
||||
return None
|
||||
if pool is None or builder is None or mod is None or trans is None: return None
|
||||
if class_name is None or method_name is None or cl is None: return None
|
||||
meta: int = self.Gen.ClassGenBase.lookup_method_meta(class_name, method_name)
|
||||
is_static: int = 0
|
||||
is_class: int = 0
|
||||
if meta & GenTypes.META_STATIC != 0:
|
||||
is_static = 1
|
||||
if meta & GenTypes.META_CLASS != 0:
|
||||
is_class = 1
|
||||
if is_static == 0 and is_class == 0:
|
||||
return None
|
||||
if meta & GenTypes.META_STATIC != 0: is_static = 1
|
||||
if meta & GenTypes.META_CLASS != 0: is_class = 1
|
||||
if is_static == 0 and is_class == 0: return None
|
||||
|
||||
# 构建参数链表
|
||||
head: llvmlite.Value | t.CPtr = None
|
||||
head: llvmlite.Value* = None
|
||||
total_count: int = 0
|
||||
|
||||
# @classmethod: 插入栈上分配的类实例指针作为 cls 参数
|
||||
if is_class != 0:
|
||||
struct_ty_cc: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(class_name)
|
||||
if struct_ty_cc is None:
|
||||
return None
|
||||
cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc)
|
||||
if cls_ptr is None:
|
||||
return None
|
||||
struct_ty_cc: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type(class_name)
|
||||
if struct_ty_cc is None: return None
|
||||
cls_ptr: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, struct_ty_cc)
|
||||
if cls_ptr is None: return None
|
||||
llvmlite.value_set_next(cls_ptr, None)
|
||||
head = cls_ptr
|
||||
total_count = 1
|
||||
|
||||
# 翻译调用参数
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
can: t.CSizeT = 0
|
||||
cargs: list[ast.AST*]* = cl.args
|
||||
can: sizet = 0
|
||||
if cargs is not None:
|
||||
can = len(cargs)
|
||||
tail: llvmlite.Value | t.CPtr = head
|
||||
tail: llvmlite.Value* = head
|
||||
for ai in range(can):
|
||||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg_node is None:
|
||||
continue
|
||||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg_node, None, 0, trans)
|
||||
if arg_val is None:
|
||||
continue
|
||||
arg_node: ast.AST* = cargs.get(ai)
|
||||
if arg_node is None: continue
|
||||
arg_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, arg_node, None, 0, trans)
|
||||
if arg_val is None: continue
|
||||
llvmlite.value_set_next(arg_val, None)
|
||||
if head is None:
|
||||
head = arg_val
|
||||
@@ -381,8 +337,7 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
# 若此处 return None,调用方回退通用路径把方法名当裸函数解析,生成
|
||||
# call i32 @new() → 链接 undefined reference(CPythonTest 根因)。
|
||||
# @classmethod 恒有 cls_ptr(head 非 None),不受影响。
|
||||
return self._translate_property_call(pool, builder, mod, class_name,
|
||||
method_name, head, total_count, trans)
|
||||
return self._translate_property_call(pool, builder, mod, class_name, method_name, head, total_count, trans)
|
||||
# ============================================================
|
||||
# _is_list_builtin_method - 判断是否是 list 泛型内置容器方法
|
||||
#
|
||||
@@ -400,11 +355,9 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
def _is_list_builtin_method(self, class_name: str,
|
||||
method_name: str) -> int:
|
||||
"""判断 (class_name, method_name) 是否是 list 泛型内置方法"""
|
||||
if class_name is None or method_name is None:
|
||||
return 0
|
||||
if class_name is None or method_name is None: return 0
|
||||
# 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名)
|
||||
if string.strncmp(class_name, "list", 4) != 0:
|
||||
return 0
|
||||
if string.strncmp(class_name, "list", 4) != 0: return 0
|
||||
# 方法名必须是 list 内置方法集合
|
||||
if string.strcmp(method_name, "append") == 0: return 1
|
||||
if string.strcmp(method_name, "get") == 0: return 1
|
||||
@@ -415,4 +368,78 @@ class CallGenProp(CallGenBase.CallGenBase):
|
||||
if string.strcmp(method_name, "__len__") == 0: return 1
|
||||
if string.strcmp(method_name, "__getitem__") == 0: return 1
|
||||
if string.strcmp(method_name, "__setitem__") == 0: return 1
|
||||
return 0
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _strip_module_sha1_prefix - 去跨模块特化名的 sha1 前缀
|
||||
#
|
||||
# 接收者实际结构体名常带 "{16位小写hex}." 前缀(如
|
||||
# "e94ef9e139461915.list[ast.ASTptr]");判定基名 | 特化名前必须先剥离。
|
||||
# 前缀长度判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛)。
|
||||
# ============================================================
|
||||
def _strip_module_sha1_prefix(self, name: str) -> str:
|
||||
"""去除 "{16hex}." 前缀(无前缀则原样返回;返回原串内部子串)"""
|
||||
if name is None:
|
||||
return None
|
||||
pfx: int = GenApi.sha1_prefix_len(name)
|
||||
return name + pfx if pfx != 0 else name
|
||||
|
||||
# _resolve_generic_receiver_name:解析接收者实际泛型特化名(IR 真值)——接收者实际 LLVM 结构体类型名比可能退化的注解/注册名可靠,故泛型判定以此为准:去 sha1 前缀取 '[' 前基名,基名是已注册泛型模板时含类型实参 ⇒ 返回实际特化名,无类型实参 ⇒ fail-fast(D25);基名非泛型模板或实际类型不可得 ⇒ 返回 None(调用方各自回退)。与 CallGenCall._translate_method_call 的 D25 分派修复共用本函数(唯一口径)
|
||||
def _resolve_generic_receiver_name(self, pool: memhub.MemBuddy*,
|
||||
struct_ty: llvmlite.LLVMType*,
|
||||
method_name: str,
|
||||
cl: ast.Call*) -> str:
|
||||
"""返回实际泛型特化名(去 sha1)或 None;裸泛型基类 fail-fast"""
|
||||
if struct_ty is None:
|
||||
return None
|
||||
ty_nm: str = llvmlite.get_struct_name(struct_ty)
|
||||
if ty_nm is None or ty_nm[0] == '\0':
|
||||
return None
|
||||
short_nm: str = self._strip_module_sha1_prefix(ty_nm)
|
||||
lb: str = string.strchr(short_nm, '[')
|
||||
bare_len: sizet = 0
|
||||
if lb is not None:
|
||||
bare_len = sizet(uint64(lb) - uint64(short_nm))
|
||||
else:
|
||||
bare_len = string.strlen(short_nm)
|
||||
if bare_len == 0:
|
||||
return None
|
||||
base_nm: str = pool.alloc(bare_len + 1)
|
||||
if base_nm is None:
|
||||
return None
|
||||
string.strncpy(base_nm, short_nm, bare_len)
|
||||
base_nm[bare_len] = '\0'
|
||||
# 基名非已注册泛型模板(普通类接收者)⇒ 非泛型,交由调用方原口径处理
|
||||
if self.Gen.ClassGenGeneric._find_generic_template(base_nm) is None:
|
||||
return None
|
||||
if lb is not None:
|
||||
return short_nm
|
||||
# 裸泛型基类(无类型实参):接收者元素类型未知 → fail-fast(D25 口径)
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
cl,
|
||||
f"方法 '{method_name}' 的接收者实际结构体类型是裸泛型基类 "
|
||||
f"'{short_nm}*'(丢失类型实参),元素类型未知;"
|
||||
f"禁止静默按默认元素类型处理(元素按 i32 处理会截断指针),"
|
||||
f"请让该变量的注解/类型带上实参(如 list[ast.AST*])",
|
||||
"TypeError")
|
||||
return None
|
||||
|
||||
# _is_list_builtin_receiver:基于接收者实际类型判定 list 内建方法,判据与 _resolve_generic_receiver_name 同源——优先采用接收者实际 LLVM 结构体类型名(去 sha1 判基名),不可得时回退注解名/注册名判定。返回 1=list 内置方法 / 0=非
|
||||
def _is_list_builtin_receiver(self, pool: memhub.MemBuddy*,
|
||||
recv_val: llvmlite.Value*,
|
||||
fallback_name: str,
|
||||
method_name: str,
|
||||
cl: ast.Call*) -> int:
|
||||
"""基于接收者实际类型判定 list 内建方法(实际类型不可得回退注解名)"""
|
||||
sty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(recv_val)
|
||||
if sty is not None:
|
||||
ty_nm: str = llvmlite.get_struct_name(sty)
|
||||
if ty_nm is not None and ty_nm[0] != '\0':
|
||||
# 泛型模板接收者:裸基类 fail-fast;含实参用实际特化名
|
||||
act_nm: str = self._resolve_generic_receiver_name(pool, sty, method_name, cl)
|
||||
if act_nm is not None:
|
||||
return self._is_list_builtin_method(act_nm, method_name)
|
||||
# 非泛型模板接收者:用去 sha1 后的实际短名判定(不复用退化注解名)
|
||||
return self._is_list_builtin_method(self._strip_module_sha1_prefix(ty_nm), method_name)
|
||||
# 实际类型不可得 → 回退注解名/注册名判定(信息缺失下的既有行为)
|
||||
return self._is_list_builtin_method(fallback_name, method_name)
|
||||
@@ -4,31 +4,15 @@ import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.Translator as HT
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
from . import CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenVa - CallGenMixin 拆分(阶段 B):va_arg 变长参数(start/arg/end / 变长调用提升)
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenVa(CallGenBase.CallGenBase):
|
||||
novirtual class CallGenVa(CallGenBase.CallGenBase):
|
||||
"""va_arg 变长参数(start/arg/end / 变长调用提升)"""
|
||||
|
||||
# ============================================================
|
||||
@@ -38,38 +22,37 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
# _translate_method 在含 raise 的函数签名末尾注入(main 除外)。
|
||||
# ============================================================
|
||||
|
||||
def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
arg_node: ast.AST | t.CPtr,
|
||||
def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
arg_node: ast.AST*,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""获取 va_list 变量的 alloca 指针(不 load)
|
||||
|
||||
va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针),
|
||||
而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca;
|
||||
否则用 translate_value 翻译(调用者负责确保传入的是指针)。
|
||||
"""
|
||||
if arg_node is None:
|
||||
return None
|
||||
if arg_node is None: return None
|
||||
# Name 节点:直接查符号表获取 alloca 指针(不 load)
|
||||
if arg_node.kind() == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node)
|
||||
nm: ast.Name* = ast.Name*(arg_node)
|
||||
if nm.id is not None:
|
||||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
if alloca is not None:
|
||||
return alloca
|
||||
# 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况)
|
||||
return self.Gen.ExprGen.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans)
|
||||
def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
type_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||||
def _resolve_va_arg_type(self, pool: memhub.MemBuddy*,
|
||||
type_node: ast.AST*,
|
||||
trans: HT.Translator*) -> llvmlite.LLVMType*:
|
||||
"""解析 va_arg/arg 的类型参数为 LLVMType
|
||||
|
||||
支持的类型表达式:
|
||||
t.CInt / t.CInt32T → i32
|
||||
t.CInt64T → i64
|
||||
int / int32 → i32
|
||||
int64 → i64
|
||||
t.CDouble → double
|
||||
t.CPtr / str → i8*
|
||||
str / bytes → i8*
|
||||
@@ -78,22 +61,21 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
if type_node is None:
|
||||
return llvmlite.Int32(pool)
|
||||
# 使用 HandlesType.resolve_annotation_type 解析类型表达式
|
||||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, type_node, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
resolved: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, type_node, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
if resolved is not None:
|
||||
return resolved
|
||||
# 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位)
|
||||
self.Gen.TypeGenErr.fatal_error(type_node, "va_arg 类型解析失败", "TypeError")
|
||||
return llvmlite.Int32(pool)
|
||||
def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cl: ast.Call | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
def _translate_va_arg_sugar(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
cl: ast.Call*,
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""va_arg(ap, type) / va_arg(ap) → %N = va_arg <ap_ty> <ap>, <type>
|
||||
|
||||
生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。
|
||||
@@ -104,36 +86,43 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
# 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm)
|
||||
# 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址;
|
||||
# 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。
|
||||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
ap_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, ap_node, None, 0, trans)
|
||||
ap_node: ast.AST* = cargs.get(0)
|
||||
ap_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, ap_node, None, 0, trans)
|
||||
if ap_val is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
ap_ptr: llvmlite.Value | t.CPtr = ap_val
|
||||
ap_ptr: llvmlite.Value* = ap_val
|
||||
|
||||
# 第二个参数:目标类型(可选,默认 i32)
|
||||
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
arg_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
if can >= 2:
|
||||
type_node: ast.AST | t.CPtr = cargs.get(1)
|
||||
type_node: ast.AST* = cargs.get(1)
|
||||
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
|
||||
|
||||
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73)
|
||||
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
|
||||
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73),
|
||||
# 再 trunc 回目标宽度——否则返回 8 字节含高位垃圾,%d/%i 语义错误
|
||||
# (viperlib vsnprintf %d 非 long 分支 `int64(va_arg(ap, int))`
|
||||
# 编译成直接 va_arg i64,高 32 位未定义 → 负数当大正数 A6 根因)。
|
||||
read_ty: llvmlite.LLVMType* = arg_ty
|
||||
abits_va: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_ty)
|
||||
if abits_va != 0 and abits_va < 64:
|
||||
read_ty = llvmlite.Int64(pool)
|
||||
va_raw: llvmlite.Value* = llvmlite.build_va_arg(builder, ap_ptr, read_ty)
|
||||
if va_raw is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
# 8 字节槽 → 目标宽度(低 bits 位);调用方 int64(...) 会再 sext/zext
|
||||
return llvmlite.build_trunc(builder, va_raw, arg_ty)
|
||||
|
||||
# 生成 va_arg 指令
|
||||
return llvmlite.build_va_arg(builder, ap_ptr, read_ty)
|
||||
def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cl: ast.Call | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
def _translate_arg_sugar(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
cl: ast.Call*,
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""arg(type) → %N = va_arg <va_list_ty> <trans._va_list_ptr>, <type>
|
||||
|
||||
使用当前函数的隐式 va_list(trans._va_list_ptr),
|
||||
@@ -143,27 +132,32 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 第一个参数:目标类型(可选,默认 i32)
|
||||
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
arg_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
if can >= 1 and cargs is not None:
|
||||
type_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
type_node: ast.AST* = cargs.get(0)
|
||||
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
|
||||
|
||||
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致)
|
||||
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
|
||||
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致),
|
||||
# 再 trunc 回目标宽度(%d/%i 高位垃圾 A6 修复,见 _translate_va_arg_sugar)
|
||||
read_ty: llvmlite.LLVMType* = arg_ty
|
||||
abits_arg: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_ty)
|
||||
if abits_arg != 0 and abits_arg < 64:
|
||||
read_ty = llvmlite.Int64(pool)
|
||||
arg_raw: llvmlite.Value* = llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty)
|
||||
if arg_raw is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
return llvmlite.build_trunc(builder, arg_raw, arg_ty)
|
||||
|
||||
# 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址)
|
||||
return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty)
|
||||
def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
def _translate_va_start_sugar(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap)
|
||||
|
||||
初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。
|
||||
@@ -172,30 +166,29 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 第一个参数:va_list 指针(获取 alloca,不 load)
|
||||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
|
||||
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
|
||||
ap_node: ast.AST* = cargs.get(0)
|
||||
ap_ptr: llvmlite.Value* = self._va_arg_get_alloca_ptr(pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
|
||||
if ap_ptr is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# bitcast 到 i8*(@llvm.va_start 接受 i8*)
|
||||
i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs)
|
||||
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs)
|
||||
i8_ty_vs: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_vs: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_vs)
|
||||
ap_i8: llvmlite.Value* = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs)
|
||||
if ap_i8 is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
void_ty_vs: llvmlite.LLVMType* = llvmlite.Void(pool)
|
||||
llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0)
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
def _translate_va_end_sugar(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
cargs: list[ast.AST*]*,
|
||||
can: sizet,
|
||||
funcs_ptr: t.CPtr,
|
||||
func_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""va_end(ap) → call void @llvm.va_end(i8* %ap)
|
||||
|
||||
清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。
|
||||
@@ -204,28 +197,27 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 第一个参数:va_list 指针(获取 alloca,不 load)
|
||||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
|
||||
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
|
||||
ap_node: ast.AST* = cargs.get(0)
|
||||
ap_ptr: llvmlite.Value* = self._va_arg_get_alloca_ptr(pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
|
||||
if ap_ptr is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
# bitcast 到 i8*(@llvm.va_end 接受 i8*)
|
||||
i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve)
|
||||
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve)
|
||||
i8_ty_ve: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_ve: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_ve)
|
||||
ap_i8: llvmlite.Value* = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve)
|
||||
if ap_i8 is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
|
||||
void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
void_ty_ve: llvmlite.LLVMType* = llvmlite.Void(pool)
|
||||
llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0)
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int:
|
||||
def _get_func_fixed_param_count(self, func: llvmlite.Function*) -> int:
|
||||
"""获取函数的固定参数数量(遍历 Params 链表)"""
|
||||
if func is None:
|
||||
return 0
|
||||
count: int = 0
|
||||
param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
|
||||
param: llvmlite.Param* = llvmlite.function_get_param_head(func)
|
||||
while param is not None:
|
||||
count += 1
|
||||
param = llvmlite.param_get_next(param)
|
||||
@@ -248,8 +240,8 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
return 2
|
||||
return -1
|
||||
|
||||
def _get_known_vararg_cfunc_param_ty(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, idx: int) -> llvmlite.LLVMType | t.CPtr:
|
||||
def _get_known_vararg_cfunc_param_ty(self, pool: memhub.MemBuddy*,
|
||||
name: str, idx: int) -> llvmlite.LLVMType*:
|
||||
"""已知变参 C 库函数第 idx 个固定参数类型(变参位置/未知返回 None)
|
||||
|
||||
固定参数类型是 C ABI 硬约束(snprintf 的 size 为 i64),stub 未注入
|
||||
@@ -257,8 +249,8 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
"""
|
||||
if pool is None or name is None or idx < 0:
|
||||
return None
|
||||
i8_ptr_kv: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
i64_kv: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
i8_ptr_kv: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
i64_kv: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||||
if string.strcmp(name, "snprintf") == 0:
|
||||
if idx == 0:
|
||||
return i8_ptr_kv
|
||||
@@ -274,15 +266,15 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
return i8_ptr_kv
|
||||
return None
|
||||
return None
|
||||
def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
call_name: str,
|
||||
head: llvmlite.Value | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None,
|
||||
head: llvmlite.Value*,
|
||||
can: sizet,
|
||||
arg_nodes: list[ast.AST*]* = None,
|
||||
self_offset: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
trans: HT.Translator* = None) -> int:
|
||||
"""检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升
|
||||
|
||||
返回: is_variadic (1=变长调用, 0=普通调用)
|
||||
@@ -295,18 +287,12 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
if mod is None or call_name is None or head is None:
|
||||
return 0
|
||||
# 查找函数对象
|
||||
func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
|
||||
func: llvmlite.Function* = self.find_func_in_module(mod, call_name)
|
||||
fixed_count: int = -1
|
||||
if func is not None and func.IsVarArg == 1:
|
||||
fixed_count = self._get_func_fixed_param_count(func)
|
||||
else:
|
||||
# 两种情况回退已知变参 C 库函数签名表(snprintf 等):
|
||||
# 1. func 为 None——跨模块 stub 未注入(CallGenMixin 注释:stubs
|
||||
# 在翻译后才注入,翻译时跨模块函数 found_func 恒 None);
|
||||
# 2. func 存在但 IsVarArg=0——该 declare 由 _ensure_method_declare
|
||||
# 按实参类型临时创建(无 ... 标记),不能代表真实签名。
|
||||
# 否则 i32 变参不提升,Win64 8 字节槽只写 4 字节 →
|
||||
# va_arg(i64) 高 4 字节读残留栈垃圾(clean 日志 0x7ff700000052 根因)。
|
||||
# 两种情况回退已知变参 C 库函数签名表(snprintf 等):func 为 None(跨模块 stub 未注入,翻译时 found_func 恒 None);func 存在但 IsVarArg=0(该 declare 由 _ensure_method_declare 按实参类型临时创建,无 ... 标记,不代表真实签名)。否则 i32 变参不提升,Win64 8 字节槽只写 4 字节 → va_arg(i64) 高 4 字节读残留栈垃圾
|
||||
fixed_count = self._get_known_vararg_cfunc_fixed_count(call_name)
|
||||
if fixed_count < 0:
|
||||
return 0
|
||||
@@ -316,8 +302,8 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
return 1
|
||||
|
||||
# 遍历到第 fixed_count 个节点(固定参数的最后一个)
|
||||
cur: llvmlite.Value | t.CPtr = head
|
||||
prev: llvmlite.Value | t.CPtr = None
|
||||
cur: llvmlite.Value* = head
|
||||
prev: llvmlite.Value* = None
|
||||
idx: int = 0
|
||||
while cur is not None and idx < fixed_count:
|
||||
prev = cur
|
||||
@@ -326,23 +312,23 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
|
||||
# cur 指向第 fixed_count+1 个节点(第一个变长参数)
|
||||
# 对变长参数进行 C ABI 提升
|
||||
i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||||
i32_ty_promote: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
double_ty_promote: llvmlite.LLVMType* = llvmlite.Double(pool)
|
||||
v_idx: int = fixed_count
|
||||
while cur is not None:
|
||||
next_node: llvmlite.Value | t.CPtr = cur.Next
|
||||
promoted: llvmlite.Value | t.CPtr = cur
|
||||
next_node: llvmlite.Value* = cur.Next
|
||||
promoted: llvmlite.Value* = cur
|
||||
# C ABI integer promotion: i8/i16 → i32
|
||||
arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cur.Ty)
|
||||
if arg_bits != 0 and arg_bits < 32:
|
||||
# 无符号整型(t.CUInt8T/CUInt16T 等)→ zext;有符号/未知 → sext。
|
||||
# 无符号整型(uint8/CUInt16T 等)→ zext;有符号/未知 → sext。
|
||||
# 修复: printf("%02x", buf[i]) 中 buf[i] 是 CUInt8T,sext 得
|
||||
# 0xFFFFFFF3 打印 fffffff3(哈希摘要输出垃圾),应 zext 得 0xF3。
|
||||
is_u_va: int = 0
|
||||
if arg_nodes is not None and trans is not None:
|
||||
ast_idx_va: int = v_idx - self_offset
|
||||
if ast_idx_va >= 0 and ast_idx_va < len(arg_nodes):
|
||||
an_va: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va)
|
||||
an_va: ast.AST* = arg_nodes.get(ast_idx_va)
|
||||
if an_va is not None:
|
||||
if self.Gen.ExprGenOps._node_type_unsigned(pool, an_va, trans) != 0:
|
||||
is_u_va = 1
|
||||
@@ -375,15 +361,15 @@ class CallGenVa(CallGenBase.CallGenBase):
|
||||
# 调用方必须写满 8 字节槽,否则高 4 字节残留旧栈数据,%d 读到
|
||||
# 0x7ff700000052 类垃圾(clean 日志根因;对齐 CallGenMixin
|
||||
# L798-811 的 found_func.IsVarArg 提升)。
|
||||
i64_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
i64_ty_promote: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||||
pb_va: int = self.Gen.ExprGenBase.get_llvm_type_bits(promoted.Ty)
|
||||
if pb_va != 0 and pb_va < 64:
|
||||
promoted_va2: llvmlite.Value | t.CPtr = None
|
||||
promoted_va2: llvmlite.Value* = None
|
||||
is_u_va2: int = 0
|
||||
if arg_nodes is not None and trans is not None:
|
||||
ast_idx_va2: int = v_idx - self_offset
|
||||
if ast_idx_va2 >= 0 and ast_idx_va2 < len(arg_nodes):
|
||||
an_va2: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va2)
|
||||
an_va2: ast.AST* = arg_nodes.get(ast_idx_va2)
|
||||
if an_va2 is not None:
|
||||
if self.Gen.ExprGenOps._node_type_unsigned(pool, an_va2, trans) != 0:
|
||||
is_u_va2 = 1
|
||||
@@ -0,0 +1,177 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
|
||||
from . import CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenVt - CallGenMixin 拆分(阶段 B):vtable 槽位写入
|
||||
# ============================================================
|
||||
novirtual class CallGenVt(CallGenBase.CallGenBase):
|
||||
"""vtable 槽位写入"""
|
||||
|
||||
# _write_vtable_slot / _write_vtable_attr:把模块级函数指针写入对象 vtable 的方法槽位(devfs 驱动注册模式,对齐 TPC HandlesAssign.py L905-949 写时复制)——vtable 方法不是数据字段,get_attribute_ptr 查不到;对象 vtable 仍指向类默认 vtable 时先复制一份(internal 全局 + llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store i8*。多次写入互不覆盖
|
||||
|
||||
# ============================================================
|
||||
def _write_vtable_slot(self, pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
obj_ptr: llvmlite.Value*,
|
||||
class_name: str,
|
||||
method_index: int,
|
||||
func_val: llvmlite.Value*,
|
||||
trans: HT.Translator*) -> int:
|
||||
"""生成 vtable 槽位写入(写时复制),成功返回 1"""
|
||||
if pool is None or builder is None or mod is None or trans is None: return 0
|
||||
if obj_ptr is None or class_name is None or func_val is None: return 0
|
||||
if method_index < 0 or trans._cur_func is None: return 0
|
||||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
if i8_ty is None: return 0
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||||
if i8_ptr_ty is None: return 0
|
||||
i8_ptr_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty)
|
||||
if i8_ptr_ptr_ty is None: return 0
|
||||
method_count: int = self.Gen.StructGen.get_vtable_method_count(class_name)
|
||||
if method_count <= 0: return 0
|
||||
# 构造 vtable 类型 { i8*, i8*, ... }
|
||||
# vtable 类型的字段链表是 llvmlite.ParamNode(new_param_node / paramnode_set_next /
|
||||
# Struct 形参均为 rawptr[ParamNode])——原先误注解为 Function*。
|
||||
vt_first: llvmlite.ParamNode* = None
|
||||
vt_prev: llvmlite.ParamNode* = None
|
||||
for vi in range(method_count):
|
||||
pn: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i8_ptr_ty)
|
||||
if pn is None: continue
|
||||
if vt_first is None:
|
||||
vt_first = pn
|
||||
if vt_prev is not None:
|
||||
llvmlite.paramnode_set_next(vt_prev, pn)
|
||||
vt_prev = pn
|
||||
vtable_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, vt_first, method_count, None)
|
||||
if vtable_ty is None:
|
||||
return 0
|
||||
# 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段)
|
||||
vtable_slot: llvmlite.Value* = llvmlite.build_bitcast(builder, obj_ptr, i8_ptr_ptr_ty)
|
||||
if vtable_slot is None: return 0
|
||||
vtable_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
|
||||
if vtable_ptr is None: return 0
|
||||
# 类默认 vtable 地址(比较用)
|
||||
class_vt: llvmlite.Value* = self.Gen.CallGenLeafKit._make_vtable_ref_i8(pool, builder, mod, class_name, trans)
|
||||
if class_vt is None: return 0
|
||||
cmp_vt: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt)
|
||||
if cmp_vt is None: return 0
|
||||
# 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如
|
||||
# devfs open/close/read/write 连续赋值)同名 label 冲突)
|
||||
vtc3: int = trans._label_counter
|
||||
trans._label_counter = vtc3 + 1
|
||||
vt_bb_buf3: str = pool.alloc(64)
|
||||
if vt_bb_buf3 is None: return 0
|
||||
viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3)
|
||||
vt_copy_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, trans._cur_func, vt_bb_buf3)
|
||||
viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3)
|
||||
vt_skip_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, trans._cur_func, vt_bb_buf3)
|
||||
if vt_copy_bb is None or vt_skip_bb is None: return 0
|
||||
llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb)
|
||||
# copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本
|
||||
llvmlite.position_at_end(builder, vt_copy_bb)
|
||||
vtc: int = trans._label_counter
|
||||
trans._label_counter = vtc + 1
|
||||
vcopy_buf: str = pool.alloc(256)
|
||||
if vcopy_buf is not None:
|
||||
viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc)
|
||||
vcopy_gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, vcopy_buf, vtable_ty)
|
||||
if vcopy_gv is not None:
|
||||
llvmlite.module_add_global(mod, vcopy_gv)
|
||||
vcopy_gv.Linkage = None
|
||||
vcopy_gv.Initializer = "zeroinitializer"
|
||||
# 引用名必须带 @ 前缀:SSAValue 名原样输出,裸名
|
||||
# devfs_file.vtable.copy.71 无 @ → llc "expected value token"
|
||||
# (devfs vtable.copy 根因;全局定义 @name 是 new_global_variable
|
||||
# 输出时加的,引用侧不自动加)
|
||||
vcopy_ref_nm: str = pool.alloc(272)
|
||||
if vcopy_ref_nm is None:
|
||||
vcopy_ref_nm = vcopy_buf
|
||||
else:
|
||||
viperlib.snprintf(vcopy_ref_nm, 272, "@%s", vcopy_buf)
|
||||
vcopy_ref: llvmlite.Value* = llvmlite.SSAValue(pool, llvmlite.Ptr(pool, vtable_ty), vcopy_ref_nm)
|
||||
if vcopy_ref is not None:
|
||||
vcopy_i8: llvmlite.Value* = llvmlite.build_bitcast(builder, vcopy_ref, i8_ptr_ty)
|
||||
if vcopy_i8 is not None:
|
||||
# ConstInt 的 name 必须是数字文本(如 "56"),不能是
|
||||
# 标识符 "vtsz"——参数经 Name 原样输出,裸名 vtsz 无 %
|
||||
# → llc "expected value token"(devfs memcpy 根因)
|
||||
vtsz_buf: str = pool.alloc(32)
|
||||
if vtsz_buf is not None:
|
||||
viperlib.snprintf(vtsz_buf, 32, "%lld", method_count * 8)
|
||||
vt_size: llvmlite.Value* = llvmlite.ConstInt(pool, llvmlite.Int64(pool), method_count * 8, vtsz_buf)
|
||||
if vt_size is not None:
|
||||
self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(pool, builder, mod, vcopy_i8, class_vt, vt_size)
|
||||
llvmlite.build_store(builder, vcopy_i8, vtable_slot)
|
||||
llvmlite.build_br(builder, vt_skip_bb)
|
||||
# skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*)
|
||||
llvmlite.position_at_end(builder, vt_skip_bb)
|
||||
vt_ptr2: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
|
||||
if vt_ptr2 is None: return 0
|
||||
vt_typed: llvmlite.Value* = llvmlite.build_bitcast(builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty))
|
||||
if vt_typed is None: return 0
|
||||
vt_slotp: llvmlite.Value* = llvmlite.build_gep_struct(builder, vtable_ty, i8_ptr_ty, vt_typed, method_index)
|
||||
if vt_slotp is None: return 0
|
||||
fptr_i8: llvmlite.Value* = llvmlite.build_bitcast(builder, func_val, i8_ptr_ty)
|
||||
if fptr_i8 is not None:
|
||||
llvmlite.build_store(builder, fptr_i8, vt_slotp)
|
||||
return 1
|
||||
def _write_vtable_attr(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
node: ast.AST*,
|
||||
rhs_val: llvmlite.Value*,
|
||||
trans: HT.Translator*) -> int:
|
||||
"""属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)"""
|
||||
if node is None or builder is None or pool is None or mod is None: return 0
|
||||
if rhs_val is None or trans is None: return 0
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at is None or at.value is None or at.attr is None: return 0
|
||||
# 解析类名(AnnotClassName;去模块前缀)
|
||||
class_nm_v: str = None
|
||||
if at.value.kind() == ast.ASTKind.Name:
|
||||
nm_v: ast.Name* = ast.Name*(at.value)
|
||||
if nm_v.id is not None:
|
||||
ve_v: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_v.id)
|
||||
if ve_v is not None:
|
||||
class_nm_v = self.Gen.VarGen.var_annot_class_name(ve_v)
|
||||
elif at.value.kind() == ast.ASTKind.Attribute:
|
||||
# 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenAttr,经 self.Gen 调用
|
||||
class_nm_v = self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, at.value)
|
||||
if class_nm_v is None: return 0
|
||||
fd_dot_v: str = string.strrchr(class_nm_v, '.')
|
||||
if fd_dot_v is not None:
|
||||
class_nm_v = fd_dot_v + 1
|
||||
if self.Gen.StructGen.get_struct_type(class_nm_v) is None: return 0
|
||||
vm_idx_v: int = self.Gen.StructGen.get_vtable_method_index(class_nm_v, at.attr)
|
||||
if vm_idx_v < 0: return 0
|
||||
# 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca)
|
||||
obj_ptr_v: llvmlite.Value* = None
|
||||
if at.value.kind() == ast.ASTKind.Name:
|
||||
obj_ptr_v = self.Gen.VarGen.lookup_var(trans.SymTab, (ast.Name*(at.value)).id)
|
||||
else:
|
||||
obj_ptr_v = self.Gen.ExprGen.translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||||
if obj_ptr_v is None or obj_ptr_v.Ty is None: return 0
|
||||
# X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针
|
||||
match obj_ptr_v.Ty:
|
||||
case llvmlite.LLVMType.Ptr(inner_v):
|
||||
match inner_v:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v)
|
||||
case _:
|
||||
pass
|
||||
case _:
|
||||
pass
|
||||
if obj_ptr_v is None:
|
||||
return 0
|
||||
return self._write_vtable_slot(pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans)
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,404 +0,0 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenFd - CallGenMixin 拆分(阶段 B):FakeDuck / requires 字段注入 / provider 栈
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenFd(CallGenBase.CallGenBase):
|
||||
"""FakeDuck / requires 字段注入 / provider 栈"""
|
||||
|
||||
# ============================================================
|
||||
# _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str
|
||||
#
|
||||
# 对齐 TPC HandlesExprCall.py L2841-2880:
|
||||
# ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找
|
||||
# {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2
|
||||
# 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时
|
||||
# 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免
|
||||
# bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _translate_fakeduck_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cls_name: str,
|
||||
method_name: str,
|
||||
cl: ast.Call | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""FakeDuck: str 变量方法调用解析到扩展类 _Type/_str,返回 call 结果或 None"""
|
||||
if pool is None or builder is None or cl is None or trans is None:
|
||||
return None
|
||||
if method_name is None:
|
||||
return None
|
||||
# 仅对 str 类型触发(AnnotClassName == "str",对象是 char*);
|
||||
# cls_name 为 None(表达式接收者解析失败)时也尝试
|
||||
if cls_name is not None and string.strcmp(cls_name, "str") != 0:
|
||||
return None
|
||||
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute:
|
||||
return None
|
||||
fd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if fd_at is None or fd_at.value is None or fd_at.attr is None:
|
||||
return None
|
||||
if string.strcmp(fd_at.attr, method_name) != 0:
|
||||
return None
|
||||
# 候选扩展类:先 _Type(a.type_id())后 _str(a.upper() 等)
|
||||
fd_func: llvmlite.Function | t.CPtr = None
|
||||
fd_cls: str = None
|
||||
fd_key: str = pool.alloc(160)
|
||||
if fd_key is not None:
|
||||
for fd_ci in range(2):
|
||||
fd_cn: str = "_Type"
|
||||
if fd_ci == 1:
|
||||
fd_cn = "_str"
|
||||
viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name)
|
||||
fd_func = self.find_func_in_module(mod, fd_key)
|
||||
if fd_func is not None:
|
||||
fd_cls = fd_cn
|
||||
break
|
||||
if fd_func is None or fd_cls is None:
|
||||
return None
|
||||
# 扩展类结构体必须已注册(GEP/临时影子需要类型)
|
||||
fd_sty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(fd_cls)
|
||||
if fd_sty is None:
|
||||
return None
|
||||
# 扩展类字段数:有字段(_str)时 self 用影子结构体指针;
|
||||
# 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876)
|
||||
fd_entry_fd: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(fd_sty)
|
||||
fd_has_fields: int = 0
|
||||
if fd_entry_fd is not None and fd_entry_fd.FieldCount > 0:
|
||||
fd_has_fields = 1
|
||||
# self 参数:优先使用已有影子 {var}__meta__(fd2 创建,仅当扩展类有字段时)
|
||||
fd_self: llvmlite.Value | t.CPtr = None
|
||||
if fd_at.value.kind() == ast.ASTKind.Name:
|
||||
fd_onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_at.value)
|
||||
if fd_onm.id is not None:
|
||||
# pool 持久缓冲(f-string 栈缓冲在函数返回后失效)
|
||||
fd_mn: str = pool.alloc(256)
|
||||
if fd_mn is not None:
|
||||
viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id)
|
||||
fd_meta: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current(
|
||||
trans.SymTab, fd_mn)
|
||||
if fd_meta is not None and fd_has_fields != 0:
|
||||
fd_self = fd_meta
|
||||
if fd_self is None:
|
||||
if fd_has_fields != 0:
|
||||
# 有字段扩展类且无影子(字符串字面量等):入口创建临时影子并初始化
|
||||
# 先确保 _str 完整定义(跨模块结构体默认 opaque,alloca 报 unsized)
|
||||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, fd_sty)
|
||||
fd_self = self.Gen.VarGen._alloca_at_entry(builder, fd_sty)
|
||||
if fd_self is None:
|
||||
return None
|
||||
fd_obj_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, fd_at.value, None, 0, trans)
|
||||
if fd_obj_val is not None:
|
||||
fd_dfe: GenTypes.FieldEntry | t.CPtr = \
|
||||
self.Gen.StructGen.lookup_field(fd_sty, "__data__")
|
||||
if fd_dfe is not None and fd_dfe.Ty is not None:
|
||||
fd_dp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, fd_sty, fd_dfe.Ty, fd_self, fd_dfe.Index)
|
||||
if fd_dp is not None:
|
||||
llvmlite.build_store(builder, fd_obj_val, fd_dp)
|
||||
fd_bfe: GenTypes.FieldEntry | t.CPtr = \
|
||||
self.Gen.StructGen.lookup_field(fd_sty, "__mbuddy__")
|
||||
if fd_bfe is not None and fd_bfe.Ty is not None:
|
||||
fd_bp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index)
|
||||
fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
|
||||
pool, fd_bfe.Ty, "null")
|
||||
if fd_bp is not None and fd_null is not None:
|
||||
llvmlite.build_store(builder, fd_null, fd_bp)
|
||||
# FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)
|
||||
self._inject_requires_fields(
|
||||
trans, pool, builder, mod, fd_self, fd_cls)
|
||||
else:
|
||||
# 无字段扩展类(_Type):对象值 bitcast 到扩展类指针
|
||||
fd_obj_v: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, fd_at.value, None, 0, trans)
|
||||
if fd_obj_v is None:
|
||||
return None
|
||||
fd_self = llvmlite.build_bitcast(
|
||||
builder, fd_obj_v, llvmlite.Ptr(pool, fd_sty))
|
||||
if fd_self is None:
|
||||
return None
|
||||
# 构建参数链表: self → 其余参数
|
||||
llvmlite.value_set_next(fd_self, None)
|
||||
fd_head: llvmlite.Value | t.CPtr = fd_self
|
||||
fd_tail: llvmlite.Value | t.CPtr = fd_self
|
||||
fd_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
fd_can: int = 0
|
||||
if fd_args is not None:
|
||||
fd_can = len(fd_args)
|
||||
for fd_ai in range(fd_can):
|
||||
fd_arg: ast.AST | t.CPtr = fd_args.get(fd_ai)
|
||||
if fd_arg is not None:
|
||||
fd_av: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, fd_arg, None, 0, trans)
|
||||
# char 常量参数 → 单字符字符串(char 隐式转 str,
|
||||
# 如 s1.split(','):',' 是 i32 值 44,传给 str 参数须先字符串化,
|
||||
# 否则运行时 strlen/strncmp 解引用 44 崩溃)
|
||||
if fd_arg.kind() == ast.ASTKind.Constant:
|
||||
fd_ac: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(fd_arg)
|
||||
if fd_ac.const_kind == ast.CONST_CHAR:
|
||||
ch_buf: str = pool.alloc(2)
|
||||
if ch_buf is not None:
|
||||
ch_buf[0] = t.CChar(fd_ac.int_val)
|
||||
ch_buf[1] = '\0'
|
||||
fd_av = self.Gen.ExprGenConst.create_global_string(
|
||||
builder, pool, mod, ch_buf, trans)
|
||||
if fd_av is not None:
|
||||
llvmlite.value_set_next(fd_av, None)
|
||||
llvmlite.value_set_next(fd_tail, fd_av)
|
||||
fd_tail = fd_av
|
||||
# 返回类型与调用名(来自 find_func_in_module 命中的函数定义)
|
||||
fd_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fd_func)
|
||||
if fd_ret_ty is None:
|
||||
fd_ret_ty = llvmlite.Int32(pool)
|
||||
fd_fname: str = llvmlite.function_get_name(fd_func)
|
||||
if fd_fname is None:
|
||||
return None
|
||||
# 返回类型精确化:跨模块 declare 的 list[T] 特化返回类型可能被简化
|
||||
# 为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标
|
||||
# 路径而非 list 内联 __getitem__(printf %s 解引用字符值崩溃)。
|
||||
# 从定义模块 text.ll 读取精确返回类型(对齐普通方法调用 _translate_method_call)。
|
||||
fd_sha1: str = pool.alloc(17)
|
||||
if fd_sha1 is not None:
|
||||
string.strncpy(fd_sha1, fd_fname, 16)
|
||||
fd_sha1[16] = '\0'
|
||||
fd_exact: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||||
pool, fd_sha1, fd_cls, method_name)
|
||||
if fd_exact is not None:
|
||||
fd_ret_ty = fd_exact
|
||||
fd_total: int = 1 + fd_can
|
||||
return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0)
|
||||
# ============================================================
|
||||
# _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段
|
||||
#
|
||||
# 对齐 TPC HandlesExprCall.py L4021-4079:
|
||||
# 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用
|
||||
# _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时
|
||||
# bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖
|
||||
# 用户已手动设置的值)。_find_provider 未注册(未 import
|
||||
# _withcontent)时跳过注入,不影响非 with 场景。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _inject_requires_fields(self, trans: HT.Translator | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
meta_ptr: llvmlite.Value | t.CPtr,
|
||||
class_name: str) -> int:
|
||||
"""在 with 上下文注入 requires 字段,返回注入字段数"""
|
||||
if trans is None or pool is None or builder is None or mod is None:
|
||||
return 0
|
||||
if meta_ptr is None or class_name is None:
|
||||
return 0
|
||||
# _withcontent._find_provider(跨模块):仅当本模块可见(_withcontent
|
||||
# 被 import,vpi stub declare 已注入)时才注入。对齐 TPC L4048-4050
|
||||
# (Gen.functions.get('_find_provider') 不存在则跳过)——否则非 with
|
||||
# 项目(如 HashTableTest 未 import _withcontent)也会为每个 _str(...)
|
||||
# 构造发射 {sha1}._find_provider 调用 → ld.lld undefined symbol。
|
||||
fd_fn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module(
|
||||
mod, "_find_provider")
|
||||
if fd_fn_probe is None:
|
||||
return 0
|
||||
fd_fname: str = llvmlite.function_get_name(fd_fn_probe)
|
||||
if fd_fname is None:
|
||||
return 0
|
||||
cnt: int = self.Gen.ClassGenBase.class_meta_count(
|
||||
GenTypes.CLASS_META_REQUIRES, class_name)
|
||||
if cnt <= 0:
|
||||
return 0
|
||||
sty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(class_name)
|
||||
if sty is None:
|
||||
return 0
|
||||
i8_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
if i8_ty_j is None:
|
||||
return 0
|
||||
i8_ptr_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_j)
|
||||
if i8_ptr_ty_j is None:
|
||||
return 0
|
||||
cur_func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
if cur_func is None:
|
||||
return 0
|
||||
injected: int = 0
|
||||
for ji in range(cnt):
|
||||
fname: str = self.Gen.ClassGenBase.class_meta_field_at(
|
||||
GenTypes.CLASS_META_REQUIRES, class_name, ji)
|
||||
if fname is None:
|
||||
continue
|
||||
fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||||
sty, fname)
|
||||
if fe is None or fe.Ty is None:
|
||||
continue
|
||||
# 参数:字段名字符串(i8*)
|
||||
fd_fstr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string(
|
||||
builder, pool, mod, fname, trans)
|
||||
if fd_fstr is None:
|
||||
continue
|
||||
llvmlite.value_set_next(fd_fstr, None)
|
||||
self._ensure_method_declare(
|
||||
pool, mod, fd_fname, i8_ptr_ty_j, fd_fstr, 1)
|
||||
fd_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||||
builder, fd_fname, fd_fstr, 1, i8_ptr_ty_j, 0)
|
||||
if fd_ptr is None:
|
||||
continue
|
||||
# 条件注入:ptr != NULL 才写入(保留用户手动设置的值)
|
||||
fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
|
||||
pool, i8_ptr_ty_j, "null")
|
||||
if fd_null is None:
|
||||
continue
|
||||
fd_cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_NE, fd_ptr, fd_null)
|
||||
if fd_cmp is None:
|
||||
continue
|
||||
# 块名唯一化(create_block 不自动编号,同名 label 在文本 IR 中
|
||||
# 冲突 → llc "Terminator found in the middle of a basic block")
|
||||
vtc2: int = trans._label_counter
|
||||
trans._label_counter = vtc2 + 1
|
||||
fd_bb_buf2: str = pool.alloc(64)
|
||||
if fd_bb_buf2 is None:
|
||||
continue
|
||||
viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2)
|
||||
fd_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, cur_func, fd_bb_buf2)
|
||||
viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2)
|
||||
fd_inject_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, cur_func, fd_bb_buf2)
|
||||
if fd_skip_bb is None or fd_inject_bb is None:
|
||||
continue
|
||||
llvmlite.build_cond_br(builder, fd_cmp, fd_inject_bb, fd_skip_bb)
|
||||
# inject 块:bitcast + GEP + store,跳回 skip
|
||||
llvmlite.position_at_end(builder, fd_inject_bb)
|
||||
fd_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, fd_ptr, fe.Ty)
|
||||
if fd_cast is not None:
|
||||
fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, sty, fe.Ty, meta_ptr, fe.Index)
|
||||
if fd_fp is not None:
|
||||
llvmlite.build_store(builder, fd_cast, fd_fp)
|
||||
llvmlite.build_br(builder, fd_skip_bb)
|
||||
# skip 块:恢复 CurBlock,继续后续代码生成
|
||||
llvmlite.position_at_end(builder, fd_skip_bb)
|
||||
injected += 1
|
||||
return injected
|
||||
# ============================================================
|
||||
# _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文
|
||||
# provider push/pop(__provides__ 元数据,fd1 注册)
|
||||
#
|
||||
# 对齐 TPC HandlesWith.py L138-174:
|
||||
# with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8);
|
||||
# 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责
|
||||
# 维护 TLS provider 栈,供 _inject_requires_fields 查找。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _emit_provider_push(self, trans: HT.Translator | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cls_name: str,
|
||||
ctx_val: llvmlite.Value | t.CPtr) -> int:
|
||||
"""生成 _push_provider(field, ctx_i8) 调用(每提供字段一次),返回字段数"""
|
||||
if trans is None or pool is None or builder is None or mod is None:
|
||||
return 0
|
||||
if cls_name is None or ctx_val is None:
|
||||
return 0
|
||||
fd_pc: int = self.Gen.ClassGenBase.class_meta_count(
|
||||
GenTypes.CLASS_META_PROVIDES, cls_name)
|
||||
if fd_pc <= 0:
|
||||
return 0
|
||||
# _withcontent._push_provider(跨模块,同 _find_provider 的可见性守卫:
|
||||
# 本模块未 import _withcontent 时跳过,避免 undefined symbol)
|
||||
fd_pfn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module(
|
||||
mod, "_push_provider")
|
||||
if fd_pfn_probe is None:
|
||||
return 0
|
||||
fd_pfn: str = llvmlite.function_get_name(fd_pfn_probe)
|
||||
if fd_pfn is None:
|
||||
return 0
|
||||
i8_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
if i8_ty_p is None:
|
||||
return 0
|
||||
i8_ptr_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_p)
|
||||
if i8_ptr_ty_p is None:
|
||||
return 0
|
||||
ret_i32_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if ret_i32_p is None:
|
||||
return 0
|
||||
# ctx 值 bitcast 到 i8*(provider 栈存 void*)
|
||||
fd_ctx_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, ctx_val, i8_ptr_ty_p)
|
||||
if fd_ctx_i8 is None:
|
||||
return 0
|
||||
for pi in range(fd_pc):
|
||||
fname: str = self.Gen.ClassGenBase.class_meta_field_at(
|
||||
GenTypes.CLASS_META_PROVIDES, cls_name, pi)
|
||||
if fname is None:
|
||||
continue
|
||||
fd_fstr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string(
|
||||
builder, pool, mod, fname, trans)
|
||||
if fd_fstr is None:
|
||||
continue
|
||||
llvmlite.value_set_next(fd_fstr, fd_ctx_i8)
|
||||
llvmlite.value_set_next(fd_ctx_i8, None)
|
||||
self._ensure_method_declare(
|
||||
pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2)
|
||||
llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0)
|
||||
return fd_pc
|
||||
def _emit_provider_pop(self, trans: HT.Translator | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
cls_name: str) -> int:
|
||||
"""生成 _pop_provider() 调用(每提供字段一次),返回字段数"""
|
||||
if trans is None or pool is None or builder is None or mod is None:
|
||||
return 0
|
||||
if cls_name is None:
|
||||
return 0
|
||||
fd_pc: int = self.Gen.ClassGenBase.class_meta_count(
|
||||
GenTypes.CLASS_META_PROVIDES, cls_name)
|
||||
if fd_pc <= 0:
|
||||
return 0
|
||||
# _withcontent._pop_provider(跨模块,同 _find_provider 的可见性守卫:
|
||||
# 本模块未 import _withcontent 时跳过,避免 undefined symbol)
|
||||
fd_pon_probe: llvmlite.Function | t.CPtr = self.find_func_in_module(
|
||||
mod, "_pop_provider")
|
||||
if fd_pon_probe is None:
|
||||
return 0
|
||||
fd_pon: str = llvmlite.function_get_name(fd_pon_probe)
|
||||
if fd_pon is None:
|
||||
return 0
|
||||
ret_i32_q: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if ret_i32_q is None:
|
||||
return 0
|
||||
self._ensure_method_declare(pool, mod, fd_pon, ret_i32_q, None, 0)
|
||||
for _pi in range(fd_pc):
|
||||
llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0)
|
||||
return fd_pc
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,584 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenLib - CallGenMixin 拆分(阶段 C):C 库声明 / 返回类型推断 /
|
||||
# 变长参数 / memcpy / kwargs 调用辅助方法
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenLib(CallGenBase.CallGenBase):
|
||||
"""C 库声明 / 返回类型推断 / kwargs 调用辅助(继承 Base)"""
|
||||
|
||||
def _ensure_c_lib_declare(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
name: str) -> llvmlite.Function | t.CPtr:
|
||||
"""为已知的 C 库函数创建 declare 声明"""
|
||||
if pool is None or mod is None or name is None:
|
||||
return None
|
||||
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
params: int = 0 # 参数数量
|
||||
|
||||
if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0:
|
||||
ret_ty = i64_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "memset") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "memcpy") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "memmove") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "memcmp") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "strcmp") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 2
|
||||
elif string.strcmp(name, "strncmp") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "strcpy") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 2
|
||||
elif string.strcmp(name, "strncpy") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 3
|
||||
elif string.strcmp(name, "strcat") == 0:
|
||||
ret_ty = i8_ptr_ty
|
||||
params = 2
|
||||
elif string.strcmp(name, "puts") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "atoi") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "atol") == 0:
|
||||
ret_ty = i64_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "abs") == 0:
|
||||
ret_ty = i32_ty
|
||||
params = 1
|
||||
elif string.strcmp(name, "labs") == 0:
|
||||
ret_ty = i64_ty
|
||||
params = 1
|
||||
else:
|
||||
return None
|
||||
|
||||
# 创建 declare
|
||||
fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty)
|
||||
if fn is None:
|
||||
return None
|
||||
# 添加参数
|
||||
if params == 1:
|
||||
if string.strcmp(name, "abs") == 0:
|
||||
llvmlite.add_param(pool, fn, i32_ty, "n")
|
||||
elif string.strcmp(name, "labs") == 0:
|
||||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||||
else:
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "s")
|
||||
elif params == 2:
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "src")
|
||||
elif params == 3:
|
||||
if string.strcmp(name, "memset") == 0:
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||||
llvmlite.add_param(pool, fn, i32_ty, "c")
|
||||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||||
else:
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||||
llvmlite.add_param(pool, fn, i8_ptr_ty, "src")
|
||||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||||
return fn
|
||||
def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
func_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""根据函数名推断外部 includes 函数的返回类型
|
||||
|
||||
支持三种函数名形式:
|
||||
1. 裸名: "parse", "strlen"
|
||||
2. 别名: "json_parse"(from X import parse as json_parse)
|
||||
3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name)
|
||||
"""
|
||||
if pool is None or func_name is None:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
# 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse")
|
||||
# SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔
|
||||
bare_name: str = func_name
|
||||
dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.')
|
||||
if dot_pos is not None:
|
||||
# '.' 后的部分是裸函数名
|
||||
bare_name = dot_pos + 1
|
||||
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 返回 i8* 的函数(指针返回值,截断会导致错误)
|
||||
if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0:
|
||||
return i8_ptr_ty
|
||||
# JSON 解析函数返回 JsonValue*(指针)
|
||||
# from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖
|
||||
if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0:
|
||||
return i8_ptr_ty
|
||||
# MemBuddy 方法(当类型信息丢失时可能走外部函数路径)
|
||||
# 存疑
|
||||
# malloc:裸名 CExport 跨模块调用(uhci/desktop 等 mm.malloc → @malloc)
|
||||
# 在模块归属解析失败(mod_ret_sha1=None)或 vpi/text.ll 未命中时回退到
|
||||
# 此白名单。缺失导致返回类型被推断为 i32 → call i32 @malloc 截断 64 位
|
||||
# 指针 → mm.malloc 实际返回非空但调用方判 None(uhci frame list /
|
||||
# desktop bg_row_buf 根因)。calloc/realloc/alloc 均已登记,malloc 遗漏。
|
||||
if string.strcmp(bare_name, "malloc") == 0 or string.strcmp(func_name, "malloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "alloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "calloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "realloc") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "alloc_buf") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃)
|
||||
if string.strcmp(func_name, "get_logger") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "fmt_buf") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏)
|
||||
if string.strcmp(func_name, "get_includes_binary_dir") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
# HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断)
|
||||
if string.strcmp(bare_name, "_parse_type_string") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 返回 i64 的函数
|
||||
if string.strcmp(func_name, "strlen") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(func_name, "atoll") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
|
||||
# 返回 double 的函数
|
||||
if string.strcmp(func_name, "atof") == 0:
|
||||
return llvmlite.Double(pool)
|
||||
|
||||
# 返回 i8 的函数
|
||||
if string.strcmp(func_name, "samestr") == 0:
|
||||
return llvmlite.Int8(pool)
|
||||
|
||||
# Win32 API 返回指针(VOIDPTR/HANDLE)的函数
|
||||
# stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
if string.strcmp(func_name, "VirtualAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "HeapAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "HeapReAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "HeapCreate") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetProcessHeap") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GlobalAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GlobalFree") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GlobalLock") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "LocalAlloc") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "LocalFree") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetProcAddress") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetModuleHandleA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetModuleHandleW") == 0:
|
||||
return i8_ptr_ty
|
||||
# GetCommandLineA/W 返回 LPSTR(i8*):缺则 64 位指针被截成 i32 →
|
||||
# inttoptr 后 strlen 读到无效地址(SysLibTest argv 段 ASAN 崩溃,
|
||||
# 非 ASAN 环境随机表现:IDE 0xC0000005 / 部分环境侥幸可读)。
|
||||
if string.strcmp(func_name, "GetCommandLineA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "GetCommandLineW") == 0:
|
||||
return i8_ptr_ty
|
||||
# gethostbyname 返回 hostent*(i8*)
|
||||
if string.strcmp(func_name, "gethostbyname") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "LoadLibraryA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "LoadLibraryW") == 0:
|
||||
return i8_ptr_ty
|
||||
# Win32 Handle 返回函数(HANDLE = void* = i8*)
|
||||
if string.strcmp(func_name, "GetStdHandle") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "CreateFileA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "CreateFileW") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "FindFirstFileA") == 0:
|
||||
return i8_ptr_ty
|
||||
if string.strcmp(func_name, "FindFirstFileW") == 0:
|
||||
return i8_ptr_ty
|
||||
|
||||
# Win32 API 返回 i64 (SIZE_T) 的函数
|
||||
if string.strcmp(func_name, "VirtualQuery") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(func_name, "HeapSize") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(func_name, "HeapCompact") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
if string.strcmp(func_name, "GlobalSize") == 0:
|
||||
return llvmlite.Int64(pool)
|
||||
|
||||
# llvmlite build_* 函数返回类型推断
|
||||
# stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32
|
||||
# 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void
|
||||
if string.strncmp(func_name, "build_", 6) == 0:
|
||||
# 返回 void 的 build_* 函数(终止指令和无返回值指令)
|
||||
if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \
|
||||
string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \
|
||||
string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \
|
||||
string.strcmp(func_name, "build_switch") == 0:
|
||||
return llvmlite.Void(pool)
|
||||
# 其他 build_* 函数返回 Value*(指针)
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# llvmlite 类型工厂函数返回 LLVMType*(指针)
|
||||
# Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label
|
||||
# new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针)
|
||||
# const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针)
|
||||
# function_get_name/param_get_ty 等访问器返回指针
|
||||
if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \
|
||||
string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \
|
||||
string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \
|
||||
string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \
|
||||
string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \
|
||||
string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \
|
||||
string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \
|
||||
string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \
|
||||
string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \
|
||||
string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \
|
||||
string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \
|
||||
string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \
|
||||
string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0:
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
|
||||
# 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324)
|
||||
# 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出
|
||||
# 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配
|
||||
# x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致
|
||||
# WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断
|
||||
# --nowarn-register 可抑制此 WARN(自举编译中大量出现,刷屏影响日志收敛)
|
||||
if VLogger.nowarn_register() == 0:
|
||||
VLogger.warning(
|
||||
f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}",
|
||||
"HandlesExprCall")
|
||||
return llvmlite.Int32(pool)
|
||||
def _get_external_func_param_ty(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
func_name: str,
|
||||
param_idx: int) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型
|
||||
|
||||
对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中
|
||||
ULONG/SIZE_T 被统一翻译为 i64 的情况。
|
||||
"""
|
||||
if pool is None or func_name is None:
|
||||
return None
|
||||
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
|
||||
# Win32 API 函数列表:所有非指针参数在 declare 中都是 i64
|
||||
# (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64)
|
||||
win32_apis: list[str] | t.CPtr = [
|
||||
"VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery",
|
||||
"VirtualLock", "VirtualUnlock",
|
||||
"HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc",
|
||||
"HeapFree", "HeapSize", "HeapValidate", "HeapCompact",
|
||||
"GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize",
|
||||
"LocalAlloc", "LocalFree",
|
||||
"GetLastError", "SetLastError",
|
||||
"Sleep", "SleepEx",
|
||||
"GetTickCount", "GetProcessHeap"
|
||||
]
|
||||
|
||||
# list 迭代不支持,用 range + get 替代
|
||||
api_count: t.CSizeT = len(win32_apis)
|
||||
for ai in range(api_count):
|
||||
api_name: str = win32_apis.get(ai)
|
||||
if string.strcmp(api_name, func_name) == 0:
|
||||
return i64_ty
|
||||
|
||||
# 内存分配函数:size 参数在声明中为 i64(size_t),裸名回退时
|
||||
# 不提升则 call(i32 size) 与 define(i64 size) 不匹配(desktop start
|
||||
# 第 4 次 mm.malloc(w*4) 返回值被破坏收到 0x0 根因;HelloWorld
|
||||
# vpsdk 的 malloc 同理)。calloc/realloc 的 size 参数在 idx 1。
|
||||
if string.strcmp(func_name, "malloc") == 0 \
|
||||
or string.strcmp(func_name, "alloc") == 0 \
|
||||
or string.strcmp(func_name, "alloc_buf") == 0:
|
||||
if param_idx == 0:
|
||||
return i64_ty
|
||||
if string.strcmp(func_name, "calloc") == 0:
|
||||
if param_idx == 0 or param_idx == 1:
|
||||
return i64_ty
|
||||
if string.strcmp(func_name, "realloc") == 0:
|
||||
if param_idx == 1:
|
||||
return i64_ty
|
||||
|
||||
return None
|
||||
def _is_sha1_mangled_call(self, call_name: str) -> int:
|
||||
"""判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式)
|
||||
|
||||
C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0,
|
||||
不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。
|
||||
"""
|
||||
if call_name is None:
|
||||
return 0
|
||||
first_dot: str = string.strchr(call_name, '.')
|
||||
if first_dot is None:
|
||||
return 0
|
||||
pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name))
|
||||
if pre_len != 16:
|
||||
return 0
|
||||
for hx in range(16):
|
||||
ch: int = call_name[hx]
|
||||
if ch < 48 or ch > 57:
|
||||
if ch < 97 or ch > 102:
|
||||
if ch < 65 or ch > 70:
|
||||
return 0
|
||||
return 1
|
||||
def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
dst_val: llvmlite.Value | t.CPtr,
|
||||
src_val: llvmlite.Value | t.CPtr,
|
||||
num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""将 memcpy 调用映射到 @llvm.memcpy 内联函数
|
||||
|
||||
直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的
|
||||
Next 字段可能被其他操作污染,导致链表断裂)。
|
||||
"""
|
||||
if pool is None or builder is None or mod is None:
|
||||
return None
|
||||
if dst_val is None or src_val is None or num_val is None:
|
||||
return None
|
||||
|
||||
# 在函数顶部声明 void_ty,避免后续遮蔽
|
||||
void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
|
||||
# 声明 @llvm.memcpy(如未声明)
|
||||
memcpy_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "llvm.memcpy")
|
||||
if memcpy_func is None:
|
||||
memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty)
|
||||
if memcpy_func is not None:
|
||||
i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||||
llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst")
|
||||
llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src")
|
||||
llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len")
|
||||
llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile")
|
||||
|
||||
# 类型转换: dst, src → i8*; num → i64
|
||||
# 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
|
||||
# dst → i8*
|
||||
dst_coerced: llvmlite.Value | t.CPtr = dst_val
|
||||
dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val)
|
||||
if self.Gen.ExprGenBase.is_ptr_type(dst_ty) != 0:
|
||||
dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty)
|
||||
else:
|
||||
dst_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(dst_ty)
|
||||
if dst_bits != 0:
|
||||
if dst_bits < 64:
|
||||
dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty)
|
||||
dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty)
|
||||
|
||||
# src → i8*
|
||||
src_coerced: llvmlite.Value | t.CPtr = src_val
|
||||
src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val)
|
||||
if self.Gen.ExprGenBase.is_ptr_type(src_ty) != 0:
|
||||
src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty)
|
||||
else:
|
||||
src_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(src_ty)
|
||||
if src_bits != 0:
|
||||
if src_bits < 64:
|
||||
src_coerced = llvmlite.build_zext(builder, src_val, i64_ty)
|
||||
src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty)
|
||||
|
||||
# num → i64
|
||||
num_coerced: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(builder, num_val, i64_ty)
|
||||
|
||||
if dst_coerced is None or src_coerced is None or num_coerced is None:
|
||||
return None
|
||||
|
||||
# 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数
|
||||
false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false")
|
||||
|
||||
# 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移
|
||||
# (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty)
|
||||
llvmlite.value_set_next(dst_coerced, src_coerced)
|
||||
llvmlite.value_set_next(src_coerced, num_coerced)
|
||||
if false_val is not None:
|
||||
llvmlite.value_set_next(num_coerced, false_val)
|
||||
llvmlite.value_set_next(false_val, None)
|
||||
else:
|
||||
llvmlite.value_set_next(num_coerced, None)
|
||||
|
||||
# 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确)
|
||||
# _ll_name_needs_quote 已对 llvm. 前缀豁免引号
|
||||
result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0)
|
||||
|
||||
# 返回 dst(匹配 C memcpy 语义: 返回 dest 指针)
|
||||
return dst_coerced
|
||||
# ============================================================
|
||||
# _translate_call_with_kwargs — 带关键字参数的函数调用
|
||||
#
|
||||
# 支持两种语法:
|
||||
# add(b=4, a=3) — 全关键字乱序
|
||||
# greet("Hello", name="World") — 位置 + 关键字混合
|
||||
#
|
||||
# 策略: 遍历 found_func.Params 链表,对每个参数:
|
||||
# 1. 若位置参数仍有剩余(param_idx < can),取位置参数
|
||||
# 2. 否则按参数名匹配关键字参数
|
||||
# 3. 按参数顺序构建调用参数链表
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _translate_call_with_kwargs(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
func_name: str,
|
||||
found_func: llvmlite.Function | t.CPtr,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
can: t.CSizeT,
|
||||
keywords: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
kw_count: t.CSizeT,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""带关键字参数的函数调用,按参数顺序构建调用链表
|
||||
|
||||
使用 llvmlite 访问器函数绕过 stub 类型限制:
|
||||
found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub
|
||||
类型中字段不足,直接访问会被 TransPyC 静默跳过。
|
||||
"""
|
||||
head: llvmlite.Value | t.CPtr = None
|
||||
tail: llvmlite.Value | t.CPtr = None
|
||||
actual_count: t.CSizeT = 0
|
||||
# memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染)
|
||||
mc_dst1: llvmlite.Value | t.CPtr = None
|
||||
mc_src1: llvmlite.Value | t.CPtr = None
|
||||
mc_num1: llvmlite.Value | t.CPtr = None
|
||||
|
||||
# 遍历函数参数链表(使用访问器获取 Head)
|
||||
param_idx: t.CSizeT = 0
|
||||
cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
|
||||
while cur_param is not None:
|
||||
arg_val: llvmlite.Value | t.CPtr = None
|
||||
param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param)
|
||||
if param_idx < can:
|
||||
# 优先使用位置参数
|
||||
arg: ast.AST | t.CPtr = cargs.get(param_idx)
|
||||
if arg is not None:
|
||||
# 传形参类型(char 字面量 → str 形参需物化字符串,见 translate_constant)
|
||||
arg_val = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, arg, None, 0, trans, param_ty)
|
||||
else:
|
||||
# 查找匹配的关键字参数
|
||||
param_name: str = llvmlite.param_get_name(cur_param)
|
||||
if param_name is not None:
|
||||
for ki in range(kw_count):
|
||||
kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki))
|
||||
if kw is None or kw.arg is None or kw.value is None:
|
||||
continue
|
||||
if self.Gen.CallGenCall._kwarg_name_matches(kw.arg, param_name) == 1:
|
||||
arg_val = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, kw.value, None, 0, trans, param_ty)
|
||||
break
|
||||
|
||||
if arg_val is not None:
|
||||
# 类型转换(按参数类型,使用访问器)
|
||||
if param_ty is not None:
|
||||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, param_ty)
|
||||
arg_val.Next = None
|
||||
if head is None:
|
||||
head = arg_val
|
||||
else:
|
||||
tail.Next = arg_val
|
||||
tail = arg_val
|
||||
# memcpy 专用: 保存前三个参数的独立引用
|
||||
if actual_count == 0:
|
||||
mc_dst1 = arg_val
|
||||
elif actual_count == 1:
|
||||
mc_src1 = arg_val
|
||||
elif actual_count == 2:
|
||||
mc_num1 = arg_val
|
||||
actual_count += 1
|
||||
|
||||
param_idx += 1
|
||||
cur_param = llvmlite.param_get_next(cur_param)
|
||||
|
||||
# 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器)
|
||||
# declare 和 define 统一用 found_func.Name:
|
||||
# - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name)
|
||||
# - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名
|
||||
# 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀,
|
||||
# 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference
|
||||
call_name: str = func_name
|
||||
found_name: str = llvmlite.function_get_name(found_func)
|
||||
if found_name is not None:
|
||||
call_name = found_name
|
||||
|
||||
# 返回类型(使用访问器)
|
||||
call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
|
||||
if call_ret_ty is None:
|
||||
call_ret_ty = self._infer_external_func_ret_ty(pool, func_name)
|
||||
|
||||
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
|
||||
if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3:
|
||||
return self._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1)
|
||||
return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0)
|
||||
@@ -1,246 +0,0 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import lib.core.Gen.ExprGenAttr as ExprGenAttr
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CallGenVt - CallGenMixin 拆分(阶段 B):vtable 槽位写入
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class CallGenVt(CallGenBase.CallGenBase):
|
||||
"""vtable 槽位写入"""
|
||||
|
||||
# ============================================================
|
||||
# _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入
|
||||
#
|
||||
# serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数
|
||||
# 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry),
|
||||
# get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。
|
||||
# 对齐 TPC HandlesAssign.py L905-949 的写时复制:
|
||||
# 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 +
|
||||
# llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store
|
||||
# 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认,
|
||||
# 跳过复制直接写槽位)。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
def _write_vtable_slot(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
obj_ptr: llvmlite.Value | t.CPtr,
|
||||
class_name: str,
|
||||
method_index: int,
|
||||
func_val: llvmlite.Value | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
"""生成 vtable 槽位写入(写时复制),成功返回 1"""
|
||||
if pool is None or builder is None or mod is None or trans is None:
|
||||
return 0
|
||||
if obj_ptr is None or class_name is None or func_val is None:
|
||||
return 0
|
||||
if method_index < 0 or trans._cur_func is None:
|
||||
return 0
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
if i8_ty is None:
|
||||
return 0
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
if i8_ptr_ty is None:
|
||||
return 0
|
||||
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
|
||||
if i8_ptr_ptr_ty is None:
|
||||
return 0
|
||||
method_count: int = self.Gen.StructGen.get_vtable_method_count(class_name)
|
||||
if method_count <= 0:
|
||||
return 0
|
||||
# 构造 vtable 类型 { i8*, i8*, ... }
|
||||
vt_first: llvmlite.ParamNode | t.CPtr = None
|
||||
vt_prev: llvmlite.ParamNode | t.CPtr = None
|
||||
for vi in range(method_count):
|
||||
pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
|
||||
if pn is None:
|
||||
continue
|
||||
if vt_first is None:
|
||||
vt_first = pn
|
||||
if vt_prev is not None:
|
||||
llvmlite.paramnode_set_next(vt_prev, pn)
|
||||
vt_prev = pn
|
||||
vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None)
|
||||
if vtable_ty is None:
|
||||
return 0
|
||||
# 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段)
|
||||
vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, obj_ptr, i8_ptr_ptr_ty)
|
||||
if vtable_slot is None:
|
||||
return 0
|
||||
vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i8_ptr_ty, vtable_slot)
|
||||
if vtable_ptr is None:
|
||||
return 0
|
||||
# 类默认 vtable 地址(比较用)
|
||||
class_vt: llvmlite.Value | t.CPtr = self.Gen.CallGenLeafKit._make_vtable_ref_i8(
|
||||
pool, builder, mod, class_name, trans)
|
||||
if class_vt is None:
|
||||
return 0
|
||||
cmp_vt: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt)
|
||||
if cmp_vt is None:
|
||||
return 0
|
||||
# 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如
|
||||
# devfs open/close/read/write 连续赋值)同名 label 冲突)
|
||||
vtc3: int = trans._label_counter
|
||||
trans._label_counter = vtc3 + 1
|
||||
vt_bb_buf3: str = pool.alloc(64)
|
||||
if vt_bb_buf3 is None:
|
||||
return 0
|
||||
viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3)
|
||||
vt_copy_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, trans._cur_func, vt_bb_buf3)
|
||||
viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3)
|
||||
vt_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, trans._cur_func, vt_bb_buf3)
|
||||
if vt_copy_bb is None or vt_skip_bb is None:
|
||||
return 0
|
||||
llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb)
|
||||
# copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本
|
||||
llvmlite.position_at_end(builder, vt_copy_bb)
|
||||
vtc: int = trans._label_counter
|
||||
trans._label_counter = vtc + 1
|
||||
vcopy_buf: str = pool.alloc(256)
|
||||
if vcopy_buf is not None:
|
||||
viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc)
|
||||
vcopy_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
|
||||
pool, vcopy_buf, vtable_ty)
|
||||
if vcopy_gv is not None:
|
||||
llvmlite.module_add_global(mod, vcopy_gv)
|
||||
vcopy_gv.Linkage = None
|
||||
vcopy_gv.Initializer = "zeroinitializer"
|
||||
# 引用名必须带 @ 前缀:SSAValue 名原样输出,裸名
|
||||
# devfs_file.vtable.copy.71 无 @ → llc "expected value token"
|
||||
# (devfs vtable.copy 根因;全局定义 @name 是 new_global_variable
|
||||
# 输出时加的,引用侧不自动加)
|
||||
vcopy_ref_nm: str = pool.alloc(272)
|
||||
if vcopy_ref_nm is None:
|
||||
vcopy_ref_nm = vcopy_buf
|
||||
else:
|
||||
viperlib.snprintf(vcopy_ref_nm, 272, "@%s", vcopy_buf)
|
||||
vcopy_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, llvmlite.Ptr(pool, vtable_ty), vcopy_ref_nm)
|
||||
if vcopy_ref is not None:
|
||||
vcopy_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, vcopy_ref, i8_ptr_ty)
|
||||
if vcopy_i8 is not None:
|
||||
# ConstInt 的 name 必须是数字文本(如 "56"),不能是
|
||||
# 标识符 "vtsz"——参数经 Name 原样输出,裸名 vtsz 无 %
|
||||
# → llc "expected value token"(devfs memcpy 根因)
|
||||
vtsz_buf: str = pool.alloc(32)
|
||||
if vtsz_buf is not None:
|
||||
viperlib.snprintf(vtsz_buf, 32, "%lld", method_count * 8)
|
||||
vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||||
pool, llvmlite.Int64(pool), method_count * 8, vtsz_buf)
|
||||
if vt_size is not None:
|
||||
self.Gen.CallGenLib._emit_llvm_memcpy_intrinsic(
|
||||
pool, builder, mod, vcopy_i8, class_vt, vt_size)
|
||||
llvmlite.build_store(builder, vcopy_i8, vtable_slot)
|
||||
llvmlite.build_br(builder, vt_skip_bb)
|
||||
# skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*)
|
||||
llvmlite.position_at_end(builder, vt_skip_bb)
|
||||
vt_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i8_ptr_ty, vtable_slot)
|
||||
if vt_ptr2 is None:
|
||||
return 0
|
||||
vt_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty))
|
||||
if vt_typed is None:
|
||||
return 0
|
||||
vt_slotp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||||
builder, vtable_ty, i8_ptr_ty, vt_typed, method_index)
|
||||
if vt_slotp is None:
|
||||
return 0
|
||||
fptr_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
builder, func_val, i8_ptr_ty)
|
||||
if fptr_i8 is not None:
|
||||
llvmlite.build_store(builder, fptr_i8, vt_slotp)
|
||||
return 1
|
||||
def _write_vtable_attr(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
rhs_val: llvmlite.Value | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
"""属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)"""
|
||||
if node is None or builder is None or pool is None or mod is None:
|
||||
return 0
|
||||
if rhs_val is None or trans is None:
|
||||
return 0
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
if at is None or at.value is None or at.attr is None:
|
||||
return 0
|
||||
# 解析类名(AnnotClassName;去模块前缀)
|
||||
class_nm_v: str = None
|
||||
if at.value.kind() == ast.ASTKind.Name:
|
||||
nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if nm_v.id is not None:
|
||||
ve_v: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, nm_v.id)
|
||||
if ve_v is not None:
|
||||
class_nm_v = ve_v.AnnotClassName
|
||||
elif at.value.kind() == ast.ASTKind.Attribute:
|
||||
# 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenAttr,经 self.Gen 调用
|
||||
class_nm_v = self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, at.value)
|
||||
if class_nm_v is None:
|
||||
return 0
|
||||
fd_dot_v: str = string.strrchr(class_nm_v, '.')
|
||||
if fd_dot_v is not None:
|
||||
class_nm_v = fd_dot_v + 1
|
||||
if self.Gen.StructGen.get_struct_type(class_nm_v) is None:
|
||||
return 0
|
||||
vm_idx_v: int = self.Gen.StructGen.get_vtable_method_index(class_nm_v, at.attr)
|
||||
if vm_idx_v < 0:
|
||||
return 0
|
||||
# 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca)
|
||||
obj_ptr_v: llvmlite.Value | t.CPtr = None
|
||||
if at.value.kind() == ast.ASTKind.Name:
|
||||
obj_ptr_v = self.Gen.VarGen.lookup_var(
|
||||
trans.SymTab, ((ast.Name | t.CPtr)(at.value)).id)
|
||||
else:
|
||||
obj_ptr_v = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, at.value, None, 0, trans)
|
||||
if obj_ptr_v is None or obj_ptr_v.Ty is None:
|
||||
return 0
|
||||
# X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针
|
||||
match obj_ptr_v.Ty:
|
||||
case llvmlite.LLVMType.Ptr(inner_v):
|
||||
match inner_v:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v)
|
||||
case _:
|
||||
pass
|
||||
case _:
|
||||
pass
|
||||
if obj_ptr_v is None:
|
||||
return 0
|
||||
return self._write_vtable_slot(
|
||||
pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,753 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
from . import ClassGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ClassGenDef - ClassGenMixin 拆分(阶段 D):translate_class_def 主入口
|
||||
# ============================================================
|
||||
novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
"""translate_class_def 主入口"""
|
||||
|
||||
# ============================================================
|
||||
# translate_class_def — 翻译 class 定义(簇 D)
|
||||
# ============================================================
|
||||
def translate_class_def(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译 class 定义,返回 0"""
|
||||
if node is None or trans is None: return 0
|
||||
|
||||
cd: ast.ClassDef* = ast.ClassDef*(node)
|
||||
if cd is None or cd.name is None: return 0
|
||||
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
class_name: str = cd.name
|
||||
|
||||
if trans.ModuleSha1 is None:
|
||||
# fail-fast:翻译类时模块 SHA1 缺失(命名空间隔离依赖它)——
|
||||
VLogger.error("翻译类时 ModuleSha1 缺失", "CLASS")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, "翻译类时 ModuleSha1 缺失", "TypeError")
|
||||
|
||||
# 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前,
|
||||
# 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类)
|
||||
self.Gen.StructGen.add_visible_struct(pool, class_name)
|
||||
# 登记"本模块声明了这个类"(键 "{SHA1}.{类名}",与 struct 注册状态无关):
|
||||
# 泛型类型实参命名规范化(TypeGenResolve._norm_type_arg_name 规则 5.5)据此
|
||||
# 判定裸类名归属 —— 类体里的**自引用**(如 includes/ast/base.vp
|
||||
# `AST.children: list[rawptr[AST]]`)解析时本类尚未 register_struct,
|
||||
# 只查注册表会留在裸名 ⇒ 与后续带 SHA1 的形式分裂成两个特化名。
|
||||
self.Gen.StructGen.mark_module_class(pool, trans.ModuleSha1, class_name)
|
||||
|
||||
# 枚举类:交给 HandlesEnum 处理
|
||||
# 分派歧义检测(fail-fast):REnum 优先于 CEnum/CUnion。若某类同时被判为枚举,
|
||||
# 说明被 `_is_enum_class` 抢先截胡 → 走 _translate_enum_def ⇒ 变体表永不注册
|
||||
# ⇒ _is_renum_class_name 恒 0、变体构造拿不到 tag。两者语义互斥,禁止静默按枚举处理。
|
||||
if self.Gen.ClassGenBase._is_enum_class(cd, trans) == 1:
|
||||
if self.Gen.ClassGenBase._is_renum_class(cd, trans) == 1:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
cd,
|
||||
f"类 '{class_name}' 同时被判定为 CEnum 与 REnum(分派歧义),"
|
||||
f"REnum 变体表将无法注册",
|
||||
"TypeError")
|
||||
return self.Gen.ClassGenEnum._translate_enum_def(trans, cd)
|
||||
|
||||
# 联合体类:交给联合体处理
|
||||
if self.Gen.ClassGenBase._is_union_class(cd, trans) == 1:
|
||||
return self.Gen.ClassGenEnum._translate_union_def(trans, cd)
|
||||
|
||||
# REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局)
|
||||
if self.Gen.ClassGenBase._is_renum_class(cd, trans) == 1:
|
||||
return self.Gen.ClassGenEnum._translate_renum_def(trans, cd)
|
||||
|
||||
# 泛型类:存储为模板,不发射 IR(等实例化时特化)
|
||||
# 用局部变量接收 cd.type_params,触发类型推断
|
||||
tp_val: list[str]* = cd.type_params
|
||||
if self.Gen.ClassGenGeneric._is_generic_class(tp_val) == 1:
|
||||
self.Gen.ClassGenGeneric._register_generic_template(pool, cd, trans.ModuleSha1)
|
||||
return 0
|
||||
|
||||
# 异常类(try-except):注册编码+继承树,不生成 struct
|
||||
# (对齐 TPC HandlesClassDef.py L509-511:_is_exception_class →
|
||||
# _RegisterExceptionClass → return,异常类不编译为结构体)
|
||||
if self.Gen.ClassGenBase._is_exception_class_def(cd) == 1:
|
||||
return self.Gen.ClassGenBase._register_exception_class_def(trans, cd)
|
||||
|
||||
# 嵌套类 / 嵌套 struct:类体里再写 class / struct 此前被**静默丢弃**
|
||||
# (字段循环只认 AnnAssign、_translate_oop_methods 只认 FunctionDef),
|
||||
# 现按既有扁平命名先例发射为独立结构体 `{外类}_{内类}`(与 TPC 的
|
||||
# union/renum 嵌套命名 `{ClassName}_{Nested}` 同源)。
|
||||
# 放在此处(enum/union/renum/泛型/异常分派之后、existing 检查之前):
|
||||
# 位于**所有提前 return 之前**,故 declare_only=1/0 两条路径都会递归;
|
||||
# 而 REnum/union 的嵌套类已由各自分支按"变体"处理并提前 return,不会重复发射。
|
||||
self._translate_nested_classdefs(trans, cd)
|
||||
|
||||
# 检查是否已注册(用 SHA1 区分跨模块同名类)
|
||||
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(class_name, trans.ModuleSha1)
|
||||
# 空类注册不完整检测:existing FieldCount==0 但源类体声明了字段(vpi 注入/注册缺陷)。
|
||||
# 标记 _deps_pending 延迟会让空 entry 持久存在、多遍死锁不收敛 ⇒ 改为中和旧 entry
|
||||
# (置空 Name + Ty=None,使 find_struct_by_module 不再命中),走下方完整注册路径重建。
|
||||
needs_rereg: int = 0
|
||||
# 前向声明占位命中:本类此前被"指向未注册类的指针"注解按名字前向声明过
|
||||
# (StructGenMixin.ensure_forward_class 建了 {sha}.Class 不透明占位)。
|
||||
# 此处**不早退**,走下方"原位填充"分支——把字段体写进同一个 Ty 对象,
|
||||
# 保住指针身份,使所有已发出的 Ptr(占位.Ty) 引用(如 CallGenBase.Gen)
|
||||
# 在填充后自动指向完整定义(对齐 TPC 的 opaque 占位 + set_body 填充)。
|
||||
fill_fwd: int = 0
|
||||
if existing is not None:
|
||||
if existing.IsForwardDecl != 0:
|
||||
fill_fwd = 1
|
||||
elif existing.FieldCount == 0 and trans._declare_only == 0:
|
||||
if self.Gen.ClassGenBase._class_body_has_field(cd) != 0:
|
||||
if existing.Name is not None:
|
||||
existing.Name[0] = '\0'
|
||||
existing.Ty = None
|
||||
existing.FieldCount = 0
|
||||
needs_rereg = 1
|
||||
if existing is not None and needs_rereg == 0 and fill_fwd == 0:
|
||||
# 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法
|
||||
if existing.Ty is not None:
|
||||
# Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty,
|
||||
# 其 Name(如 "sha1.ClassName")指向 Phase 1a 的 pool 内存。虽然 mark1
|
||||
# 之前分配不被 reset 回收,但 struct_ty 会被后续文件翻译引用(vtable/
|
||||
# self 参数类型打印),部分实现下 pool 块被复用导致 Name 悬空崩溃。
|
||||
# 保险起见:深拷贝 Name 到 stdlib,确保跨文件永久存活。
|
||||
if trans._declare_only == 0:
|
||||
# 深拷贝整个 existing.Ty 到 stdlib:1a pool Ty 跨 1b reset 悬空,
|
||||
# _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表
|
||||
# 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType
|
||||
# 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。
|
||||
ty_deep: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, existing.Ty)
|
||||
if ty_deep is not None:
|
||||
existing.Ty = ty_deep
|
||||
old_name: str = llvmlite.get_struct_name(existing.Ty)
|
||||
if old_name is not None:
|
||||
on_len: sizet = string.strlen(old_name)
|
||||
on_copy: str = CompilerFactory.factory.PermPool.alloc(on_len + 1)
|
||||
if on_copy is not None:
|
||||
string.strcpy(on_copy, old_name)
|
||||
# in-place 覆盖所指 REnum 值(保留 existing.Ty 的指针同一性:
|
||||
# Phase A 已把它登记进 named-type 表,换指针旧条目仍指向悬空
|
||||
# Name)。REnum 变体构造返回 **boxed 指针**,`*槽 = <boxed 变体>`
|
||||
# 属「构造物化」(boxed 指针 → 值槽的整对象拷贝,语义即
|
||||
# load+store),按严格规则③的构造物化例外放行——与
|
||||
# c.DerefAs(ptr, <boxed 变体>) 等价,用 * 写法更直白。
|
||||
*existing.Ty = llvmlite.LLVMType.Struct(llvmlite.get_struct_fields(existing.Ty), llvmlite.get_struct_fcount(existing.Ty), on_copy)
|
||||
# Phase B: 将已存在的命名结构体注册到当前模块(输出类型定义行)
|
||||
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
|
||||
# B5:existing 路径(Phase B 已注册类)同样需设置 packed/aligned——
|
||||
# Phase A 注册时虽已设置,但 Phase B 重新 add_named_type 后节点
|
||||
# IsPacked=0,打印输出 `{...}`(idt_entry packed 未生效根因)。
|
||||
if self.Gen.ClassGenBase._class_has_tattr(cd.decorator_list, "packed") != 0:
|
||||
llvmlite.module_set_named_type_packed(trans.Module, pool, existing.Ty, 1)
|
||||
# StructTable 每 Phase 可能重建(existing 是 Phase B 新 entry),
|
||||
# 必须补设 IsPacked——否则跨模块 stub 注入(ensure_struct_def
|
||||
# _in_module)按 entry.IsPacked 判定 packed 时读 0 → stub 非 packed。
|
||||
existing.IsPacked = 1
|
||||
align_ex: int = self.Gen.ClassGenBase._class_aligned_value(cd.decorator_list)
|
||||
if align_ex > 0 and existing.Align == 0:
|
||||
existing.Align = align_ex
|
||||
# Phase A-pre(declare_only=1)多遍扫描时,类已注册但不应翻译方法体
|
||||
# Phase B(declare_only=0)时全量翻译方法体
|
||||
if trans._declare_only == 1:
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, existing.Ty, class_name, 1)
|
||||
else:
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, existing.Ty, class_name)
|
||||
# SHA1 已在 register_struct 时设置,无需再补
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 触发 base 中 Subscript 的泛型特化(如 GSListNode[Value])
|
||||
# 必须在 _detect_vtable_status 和父类字段继承之前调用,
|
||||
# 否则 find_struct_by_module("GSListNode[Value]") 返回 None
|
||||
# ============================================================
|
||||
self.Gen.ClassGenBase._trigger_base_specialization(trans, cd)
|
||||
|
||||
# ============================================================
|
||||
# VTable 检测:判断是否启用虚表
|
||||
# ============================================================
|
||||
has_vtable: int = self.Gen.ClassGenBase._detect_vtable_status(cd, trans)
|
||||
parent_name: str = self.Gen.ClassGenBase._get_parent_class(cd, trans)
|
||||
# 多继承:收集所有真实父类名(跳过 marker base),供字段展平/vtable/MRO 使用
|
||||
parents_buf: sizet* = pool.alloc(8 * GenTypes.PARENT_MAX)
|
||||
parents_count: int = 0
|
||||
if parents_buf is not None:
|
||||
parents_count = self.Gen.ClassGenBase._collect_parents(pool, cd, parents_buf, GenTypes.PARENT_MAX, trans)
|
||||
is_novtable_deco: int = 0
|
||||
if cd.decorator_list is not None:
|
||||
if self.Gen.ClassGenBase._has_decorator(cd.decorator_list, "NoVTable") == 1:
|
||||
is_novtable_deco = 1
|
||||
|
||||
# ============================================================
|
||||
# PhaseA 预注册延迟检查:父类未注册时延迟注册当前类
|
||||
#
|
||||
# 根因:AssignHandle(HandlesBase.Mixin) 有自己的字段 _CurrentClass,
|
||||
# 当 Mixin 未注册时(字母序:HandlesAssign.py 在 HandlesBase.py 之前),
|
||||
# field_count=1(不是0),field_count==0 静默返回不触发,
|
||||
# AssignHandle 被注册为只有 _CurrentClass 字段(缺 Trans)。
|
||||
# 后续遍 existing is not None,不补字段 → attribute ptr is None: self.Trans
|
||||
#
|
||||
# 修复:declare_only==1 且父类未注册时,延迟注册到下一遍。
|
||||
# 多遍 PhaseA-pre 会在后续遍中重试(父类已注册后完整注册)。
|
||||
# Phase B(declare_only==0)不延迟,避免死锁。
|
||||
# ============================================================
|
||||
if trans._declare_only == 1 and parent_name is not None:
|
||||
parent_check: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(parent_name, trans.ModuleSha1)
|
||||
if parent_check is None:
|
||||
parent_check = self.Gen.StructGen.find_struct(parent_name)
|
||||
if parent_check is None:
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 1. 遍历 class body,收集字段信息
|
||||
# ============================================================
|
||||
# 用 CSizeT 数组存储指针值(64 位系统上 8 字节)
|
||||
field_names_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_types_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_defaults_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_annot_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
# 字段 volatile 标记缓冲(1=字段注解联合含 t.CVolatile);与 field_annot_buf
|
||||
# 并行,取值 0/1(sizet 数组复用,避免另设类型)。
|
||||
field_volatile_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
# 字段「所指物 volatile」标记缓冲(1=字段注解为 rawptr[t.CVolatile | T],
|
||||
# 等价 C 的 volatile T*);与 field_volatile_buf 并行,取值 0/1。
|
||||
field_pointee_volatile_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
# 字段 const 对象标记缓冲(1=字段注解含 t.CConst 且字段类型非指针);
|
||||
# 与 field_volatile_buf 并行,取值 0/1。
|
||||
field_const_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
if field_names_buf is None or field_types_buf is None or field_defaults_buf is None:
|
||||
return 0
|
||||
if field_annot_buf is None or field_volatile_buf is None:
|
||||
return 0
|
||||
if field_pointee_volatile_buf is None or field_const_buf is None:
|
||||
return 0
|
||||
string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_defaults_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_annot_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_volatile_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_pointee_volatile_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_const_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
|
||||
field_count: int = 0
|
||||
|
||||
# ============================================================
|
||||
# 1.5 继承父类字段(字段展平)
|
||||
# ============================================================
|
||||
#
|
||||
# 父类字段排在子类字段之前,结构体布局:
|
||||
# [vtable_ptr?, parent_field1, ..., child_field1, ...]
|
||||
# 跳过父类的 __vtable__ 字段(子类会有自己的 vtable 指针)
|
||||
# ============================================================
|
||||
# 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明优先)
|
||||
if parents_count > 0 and parents_buf is not None:
|
||||
for pi in range(parents_count):
|
||||
pname_addr: sizet = parents_buf[pi]
|
||||
if pname_addr == 0: continue
|
||||
pname: str = rawptr(pname_addr)
|
||||
if pname is None: continue
|
||||
# 用 SHA1 感知查找父类,规避跨模块同名找错
|
||||
parent_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_module(pname, trans.ModuleSha1)
|
||||
if parent_entry is None:
|
||||
# 父类可能定义在另一个模块(不同 SHA1,如 HandlesBase.Mixin),
|
||||
# find_struct_by_module 不回退全局查找,此处手动回退到 find_struct,
|
||||
# 否则子类无法继承父类字段 → field_count==0 → __sizeof__ 失败
|
||||
parent_entry = self.Gen.StructGen.find_struct(pname)
|
||||
if parent_entry is None:
|
||||
# 父类尚未注册(Phase A 按文件序,子类模块可能先于父类模块):此时
|
||||
# **不能**继续注册——StructTable 在 StdlibAlloc=1 时用 perm_pool 分配,
|
||||
# 残缺条目跨 pass 存活,后续 pass 的 existing 早退永远无法修复 → 子类
|
||||
# __init__ 写父类字段每遍永久失败。整类 defer(不注册);模块级变量/函数
|
||||
# 参数解析失败静默降级 i32,不致命。
|
||||
return 0
|
||||
pfc: int = parent_entry.FieldCount
|
||||
for pfi in range(pfc):
|
||||
pfe: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(parent_entry, pfi)
|
||||
if pfe is None: continue
|
||||
pfn: str = self.Gen.StructGen.get_field_name_ptr(pfe)
|
||||
if pfn is None: continue
|
||||
# 跳过父类的 vtable 指针字段
|
||||
if string.strcmp(pfn, "__vtable__") == 0: continue
|
||||
# 多继承去重:字段名已存在跳过(先声明父类优先)
|
||||
if self.Gen.ClassGenBase._field_name_exists(field_names_buf, field_count, pfn) != 0: continue
|
||||
if field_count < GenTypes.FIELD_MAX:
|
||||
pft: llvmlite.LLVMType* = self.Gen.StructGen.get_field_type_ptr(pfe)
|
||||
pfd: ast.AST* = self.Gen.StructGen.get_field_default_ptr(pfe)
|
||||
pfa: str = self.Gen.StructGen.get_field_annot_class_name(pfe)
|
||||
field_names_buf[field_count] = sizet(pfn)
|
||||
field_types_buf[field_count] = sizet(pft)
|
||||
if pfd is not None:
|
||||
field_defaults_buf[field_count] = sizet(pfd)
|
||||
else:
|
||||
field_defaults_buf[field_count] = 0
|
||||
if pfa is not None:
|
||||
stored_val: sizet = sizet(pfa)
|
||||
field_annot_buf[field_count] = stored_val
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
# 继承父类字段的 volatile 标记(字段展平后语义不变)
|
||||
field_volatile_buf[field_count] = sizet(pfe.IsVolatile)
|
||||
# 继承父类字段的「所指物 volatile」标记(展平后语义不变)
|
||||
field_pointee_volatile_buf[field_count] = sizet(pfe.PointeeVolatile)
|
||||
# 继承父类字段的 const 对象标记(展平后语义不变)
|
||||
field_const_buf[field_count] = sizet(pfe.IsConst)
|
||||
field_count += 1
|
||||
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
return 0
|
||||
|
||||
cn: sizet = len(children)
|
||||
for ci in range(cn):
|
||||
stmt: ast.AST* = children.get(ci)
|
||||
if stmt is None: continue
|
||||
sk: int = stmt.kind()
|
||||
|
||||
if sk != ast.ASTKind.AnnAssign: continue
|
||||
|
||||
# AnnAssign(target=Name(id), annotation=type, value=...)
|
||||
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
|
||||
if aa is None or aa.target is None: continue
|
||||
|
||||
# 获取字段名
|
||||
if aa.target.kind() != ast.ASTKind.Name: continue
|
||||
tgt: ast.Name* = ast.Name*(aa.target)
|
||||
if tgt.id is None: continue
|
||||
|
||||
# 类体 CDefine 常量(任意位置,2026-08-10):注册到全局 CDefine 表。
|
||||
# 方法内裸名(如 ISINSTANCE_CLASS_MAX)经 translate_name_value 查
|
||||
# CDefine 表解析为常量值;类体开头的常量(MRO_MAX 等)由早期预注册
|
||||
# 路径注册,但方法之后的 AnnAssign 不经过那些路径 → 此处统一兜底注册。
|
||||
if self.Gen.AssignGen.is_cdefine_annotation(aa.annotation) != 0:
|
||||
if aa.value is not None:
|
||||
self.Gen.AssignGen._register_cdefine_from_value(pool, tgt.id, aa.value, aa.annotation)
|
||||
# CDefine 字段类型固定 i32,直接收集后跳过通用注解解析:
|
||||
# resolve_annotation_type 不识别 "CDefine"(map_t_type/CTypedef
|
||||
# 表均无此名),类体尾部常量(ISINSTANCE_CLASS_MAX 是首个触发
|
||||
# 该路径的实例)Phase B 会 NameError: 't.CDefine' is not defined。
|
||||
# 与类头常量(MRO_MAX 等)的 i32 字段语义保持一致。
|
||||
if field_count < GenTypes.FIELD_MAX:
|
||||
cdef_ty_l: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
if cdef_ty_l is not None:
|
||||
field_names_buf[field_count] = sizet(tgt.id)
|
||||
field_types_buf[field_count] = sizet(cdef_ty_l)
|
||||
if aa.value is not None:
|
||||
field_defaults_buf[field_count] = sizet(aa.value)
|
||||
else:
|
||||
field_defaults_buf[field_count] = 0
|
||||
field_count += 1
|
||||
continue
|
||||
|
||||
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
|
||||
# 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码
|
||||
# (FakeDuck:_str.__requires__=['__mbuddy__'])。此处解析 list[str]
|
||||
# 字面量注册到持久元数据表,供 requires 注入 / with provider 查询。
|
||||
if string.strcmp(tgt.id, "__provides__") == 0:
|
||||
self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_PROVIDES, class_name, aa.value)
|
||||
continue
|
||||
if string.strcmp(tgt.id, "__requires__") == 0:
|
||||
self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_REQUIRES, class_name, aa.value)
|
||||
continue
|
||||
if string.strcmp(tgt.id, "__require_must__") == 0:
|
||||
self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_REQUIRE_MUST, class_name, aa.value)
|
||||
continue
|
||||
|
||||
# 解析字段类型
|
||||
field_ty: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
# void 不是合法字段类型(用户 2026-10-01:void 只能用于 `void*` 与
|
||||
# `typedef 不透明结构体 = void`);`void*` 已在上游归并为 i8*,不会命中。
|
||||
# 放任会按 LLVM void 建字段槽 ⇒ 结构体布局非法(拖到 llc 才暴露),
|
||||
# 故此处编译期 fail-fast。
|
||||
if field_ty is not None and self.Gen.StmtGenDecl._is_void_type(field_ty) != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(aa, f"字段 '{tgt.id}' 不能是 void 类型(void 只能用于 void* 与 typedef 别名)", "TypeError")
|
||||
# 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem]
|
||||
# (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义):
|
||||
# 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**),
|
||||
# for x in self.field 会误走指针迭代(元素非整数 → null 终止符
|
||||
# 检查失败报错)。推断为静态数组后走数组迭代(按长度 N)。
|
||||
if field_ty is not None:
|
||||
field_ty = self.Gen.AssignGen._infer_static_array_ty_from_literal(pool, aa.annotation, aa.value, field_ty)
|
||||
if field_ty is None:
|
||||
# BUG 5 方案1修改点1:消除 i32 静默回退
|
||||
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,延迟到下一遍
|
||||
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止该类翻译
|
||||
# 不再用 i32 回退(会导致结构体布局错误 + GEP 索引错乱)
|
||||
# 例外:泛型 Subscript(如 list[AST|t.CPtr])未特化时回退为 Ptr(i8),
|
||||
# 因为泛型特化可能延迟到构造调用时。AnnotClassName 会携带 mangled name
|
||||
# 供 translate_attribute 做后续 bitcast。
|
||||
is_generic_sub: int = 0
|
||||
if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Subscript:
|
||||
# t.CArray[elem, N](含裸 CArray[elem, N])是定长值数组,非泛型堆对象——
|
||||
# 元素类型未就绪时若回退 Ptr(i8) 会注册成退化字段布局,Phase B 复用该 entry
|
||||
# 后 GEP 元素成 i8、字段访问/赋值全部失效。仅真正的泛型类(list[T]/Vector[T]
|
||||
# 等堆对象)未特化才回退 Ptr(i8)(AnnotClassName 携带 mangled name 供后续恢复)。
|
||||
sub_g: ast.Subscript* = ast.Subscript*(aa.annotation)
|
||||
is_carray_sub_g: int = 0
|
||||
if sub_g is not None and sub_g.value is not None:
|
||||
if sub_g.value.kind() == ast.ASTKind.Attribute:
|
||||
svg_at: ast.Attribute* = ast.Attribute*(sub_g.value)
|
||||
if svg_at.attr is not None and string.strcmp(svg_at.attr, "CArray") == 0:
|
||||
is_carray_sub_g = 1
|
||||
elif sub_g.value.kind() == ast.ASTKind.Name:
|
||||
svg_nm: ast.Name* = ast.Name*(sub_g.value)
|
||||
if svg_nm.id is not None and (string.strcmp(svg_nm.id, "CArray") == 0 or string.strcmp(svg_nm.id, "rawarray") == 0 or string.strcmp(svg_nm.id, "array") == 0):
|
||||
is_carray_sub_g = 1
|
||||
if is_carray_sub_g == 0:
|
||||
is_generic_sub = 1
|
||||
if is_generic_sub != 0:
|
||||
# 泛型未特化:回退为 Ptr(i8),依赖 AnnotClassName 做后续类型恢复
|
||||
field_ty = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
else:
|
||||
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
|
||||
# 静默 return 0 让多遍收敛机制生效(下一遍依赖类已注册即可成功)
|
||||
if trans._declare_only == 1:
|
||||
return 0
|
||||
# Phase A(declare_only=0,Phase2.vp L573 多遍):依赖模块按
|
||||
# 文件序可能晚于本模块翻译(如 TypeGenMixin.vp G < HandlesType.vp
|
||||
# H,TraceFrames 注解的 HandlesType.TraceFrame 未注册)→ 不在本遍
|
||||
# 以残缺字段注册结构体。
|
||||
return 0
|
||||
# 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时
|
||||
# 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底)
|
||||
|
||||
# 存储到数组(指针转 CSizeT)
|
||||
if field_count < GenTypes.FIELD_MAX:
|
||||
diag_name_val: sizet = sizet(tgt.id)
|
||||
field_names_buf[field_count] = diag_name_val
|
||||
field_types_buf[field_count] = sizet(field_ty)
|
||||
# 存储默认值 AST 指针(None=无默认值)
|
||||
if aa.value is not None:
|
||||
field_defaults_buf[field_count] = sizet(aa.value)
|
||||
else:
|
||||
field_defaults_buf[field_count] = 0
|
||||
# 提取原始类型注解的类名(联合类型简化为 Ptr(i8) 时回退查找结构体)
|
||||
# BUG 1 方案3:传 pool 使泛型 Subscript 返回 mangled name(如 "list[ast.AST|t.CPtr]")
|
||||
if aa.annotation is not None:
|
||||
annot_cn: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(aa.annotation, trans._imported_modules, pool, trans._from_imports)
|
||||
if annot_cn is not None:
|
||||
diag_cn_val: sizet = sizet(annot_cn)
|
||||
field_annot_buf[field_count] = diag_cn_val
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
# t.CVolatile 存储类标记 → 该字段经对象访问的 load/store 带
|
||||
# volatile(如 Spinlock.locked: t.CVolatile | t.CInt)。
|
||||
if self.Gen.TypeGenErr.has_decorator_marker(aa.annotation, "CVolatile", 0) != 0:
|
||||
field_volatile_buf[field_count] = 1
|
||||
else:
|
||||
field_volatile_buf[field_count] = 0
|
||||
# rawptr[t.CVolatile | T](volatile 指针指向物,等价 C 的
|
||||
# volatile T*)→ 经该字段解引用(self.ptr[i]/self.ptr.field)
|
||||
# 的 load/store 带 volatile。
|
||||
if self.Gen.TypeGenErr.has_pointee_volatile_marker(aa.annotation) != 0:
|
||||
field_pointee_volatile_buf[field_count] = 1
|
||||
else:
|
||||
field_pointee_volatile_buf[field_count] = 0
|
||||
# const 对象字段(注解含 t.CConst 且字段类型非指针)→ 经对象给该
|
||||
# 字段赋值 fail-fast。判据与 TPC 的 Gen.field_const_flags 一致。
|
||||
if self.Gen.TypeGenErr.is_const_object_marker(aa.annotation, field_ty) != 0:
|
||||
field_const_buf[field_count] = 1
|
||||
else:
|
||||
field_const_buf[field_count] = 0
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
field_volatile_buf[field_count] = 0
|
||||
field_pointee_volatile_buf[field_count] = 0
|
||||
field_const_buf[field_count] = 0
|
||||
field_count += 1
|
||||
|
||||
if field_count == 0:
|
||||
# PhaseA 预注册时,父类可能尚未注册(字母序单遍扫描),
|
||||
# 导致子类无法继承父类字段 → field_count==0。
|
||||
# 静默返回,Phase2.py 的多遍 PhaseA-pre 会在后续遍中重试。
|
||||
if trans._declare_only == 1 and parent_name is not None:
|
||||
return 0
|
||||
# 无字段类(接口/标记类):不能整体跳过——类可能只有方法
|
||||
# (如多继承中的 ShapeM/Vec2Extra),需注册类并翻译方法。
|
||||
# 空 struct 在 LLVM 中合法({});@t.CVTable 类由下方补 vtable 指针字段。
|
||||
|
||||
# ============================================================
|
||||
# 2. 创建 LLVM StructType
|
||||
# ============================================================
|
||||
# 构建 ParamNode 链表
|
||||
first_node: rawptr[llvmlite.ParamNode] = None
|
||||
prev_node: rawptr[llvmlite.ParamNode] = None
|
||||
total_field_count: int = field_count
|
||||
|
||||
# 如果有虚表,首字段添加 i8* vtable 指针
|
||||
if has_vtable == 1:
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
vtable_node: rawptr[llvmlite.ParamNode] = pool.alloc(llvmlite.ParamNode.__sizeof__())
|
||||
if vtable_node is None:
|
||||
VLogger.error(f"failed to alloc vtable node for {class_name}", "CLASS")
|
||||
return 0
|
||||
string.memset(vtable_node, 0, llvmlite.ParamNode.__sizeof__())
|
||||
vtable_node.Ty = i8_ptr_ty
|
||||
first_node = vtable_node
|
||||
prev_node = vtable_node
|
||||
total_field_count = field_count + 1
|
||||
|
||||
for fi in range(field_count):
|
||||
fty_addr: sizet = field_types_buf[fi]
|
||||
if fty_addr == 0:
|
||||
continue
|
||||
fty: llvmlite.LLVMType* = (llvmlite.LLVMType*)(fty_addr)
|
||||
|
||||
# 创建 ParamNode
|
||||
pnode: rawptr[llvmlite.ParamNode] = pool.alloc(llvmlite.ParamNode.__sizeof__())
|
||||
if pnode is None:
|
||||
continue
|
||||
string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__())
|
||||
pnode.Ty = fty
|
||||
|
||||
if first_node is None:
|
||||
first_node = pnode
|
||||
if prev_node is not None:
|
||||
prev_node.Next = pnode
|
||||
prev_node = pnode
|
||||
|
||||
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
|
||||
# 注意: Phase 1b(declare_only=0)时 struct_ty 会注册到全局表并被后续
|
||||
# 文件翻译引用(vtable/self 参数类型打印),其 Name 必须跨 1b 每文件
|
||||
# reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。
|
||||
type_name: str = class_name
|
||||
if trans.ModuleSha1 is not None:
|
||||
name_buf: str = pool.alloc(64)
|
||||
if name_buf is not None:
|
||||
viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
|
||||
type_name = name_buf
|
||||
if trans._declare_only == 0 and type_name is not None:
|
||||
tn_len: sizet = string.strlen(type_name)
|
||||
tn_copy: str = CompilerFactory.factory.PermPool.alloc(tn_len + 1)
|
||||
if tn_copy is not None:
|
||||
string.strcpy(tn_copy, type_name)
|
||||
type_name = tn_copy
|
||||
|
||||
# 创建 StructType(命名结构体)
|
||||
struct_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, first_node, total_field_count, type_name)
|
||||
if struct_ty is None:
|
||||
VLogger.error(f"failed to create StructType for {class_name}", "CLASS")
|
||||
return 0
|
||||
|
||||
# Phase 1b(declare_only=0)新注册的 struct_ty 会被注册到全局表并被后续文件
|
||||
# 翻译引用(vtable/self 参数类型打印/find_struct_by_type 指针匹配)。LLVMType
|
||||
# 对象和 Fields 链是 pool 分配的,本文件 reset_to(mark1) 后悬空。深拷贝整棵树
|
||||
# 到 stdlib,并替换 struct_ty 指针,保证 entry.Ty 与调用方持有的 struct_ty
|
||||
# 指向同一个 stdlib 拷贝(指针匹配不失效)且跨文件永久存活。
|
||||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc(declare_only=1)
|
||||
# 预注册 includes 时若仍用 pool struct_ty,reset_to(mark2) 后 entry.Ty 悬空 →
|
||||
# 后续文件字段类型引用(resolve → Ptr(entry.Ty))→ opaque 扫描遍历悬空 fields
|
||||
# 崩溃(LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。
|
||||
if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||||
st_copy: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, struct_ty)
|
||||
if st_copy is not None:
|
||||
struct_ty = st_copy
|
||||
type_name = llvmlite.get_struct_name(struct_ty)
|
||||
|
||||
# 前向声明占位命中:**原位填充**——保持 existing.Ty 指针身份不变,仅把刚构建
|
||||
# 的字段体写进同一个类型对象(名称沿用占位的 "{sha}.Class")。此后所有已发出的
|
||||
# Ptr(占位.Ty) 引用(如 CallGenBase.Gen)自动指向完整定义。这一步必须早于
|
||||
# module_add_named_type:避免同一名字先以占位名注册、又以新对象重复注册。
|
||||
if fill_fwd != 0 and existing is not None and existing.Ty is not None:
|
||||
_fwd_name: str = llvmlite.get_struct_name(existing.Ty)
|
||||
_fwd_fields: rawptr[llvmlite.ParamNode] = llvmlite.get_struct_fields(struct_ty)
|
||||
_fwd_fc: int = llvmlite.get_struct_fcount(struct_ty)
|
||||
*existing.Ty = llvmlite.LLVMType.Struct(_fwd_fields, _fwd_fc, _fwd_name)
|
||||
struct_ty = existing.Ty
|
||||
type_name = _fwd_name
|
||||
existing.IsForwardDecl = 0
|
||||
existing.FieldCount = 0
|
||||
|
||||
# 注册命名结构体到模块(输出 %"name" = type { ... } 定义行)
|
||||
llvmlite.module_add_named_type(trans.Module, pool, struct_ty)
|
||||
|
||||
# B5:@c.Attribute(t.attr.packed) 打包结构体 → 类型定义输出 <{...}>
|
||||
# (LLVM packed struct,无字段填充,GEP 按 packed 布局计算偏移)。
|
||||
# idt/gdt/elf/fat32 等二进制格式结构体依赖它读写硬件/磁盘布局。
|
||||
is_packed_cd: int = self.Gen.ClassGenBase._class_has_tattr(cd.decorator_list, "packed")
|
||||
if is_packed_cd != 0:
|
||||
llvmlite.module_set_named_type_packed(trans.Module, pool, struct_ty, 1)
|
||||
|
||||
# 扫描字段类型,为跨模块结构体引用添加 opaque 声明
|
||||
# 例如 list[int].__pool__ 引用 memhub.MemManager,需要在当前模块添加 %"sha1.MemManager" = type opaque
|
||||
for fi in range(field_count):
|
||||
fty_addr_op: sizet = field_types_buf[fi]
|
||||
if fty_addr_op == 0:
|
||||
continue
|
||||
fty_op: llvmlite.LLVMType* = (llvmlite.LLVMType*)(fty_addr_op)
|
||||
llvmlite.module_ensure_opaque_for_type(trans.Module, pool, fty_op)
|
||||
|
||||
# ============================================================
|
||||
# 3. 注册到 HandlesStruct
|
||||
# ============================================================
|
||||
entry: GenTypes.StructEntry* = None
|
||||
if fill_fwd != 0 and existing is not None:
|
||||
# 前向声明占位:字段体已原位写入 existing.Ty,登记条目沿用 existing
|
||||
# (不新建条目/Ty,否则已发出的 Ptr(占位.Ty) 引用会指向旧空对象)。
|
||||
entry = existing
|
||||
else:
|
||||
entry = self.Gen.StructGen.register_struct(pool, class_name, struct_ty, trans.ModuleSha1)
|
||||
if entry is None:
|
||||
VLogger.error(f"failed to register {class_name}", "CLASS")
|
||||
return 0
|
||||
|
||||
# B5:记录 packed 标记到 StructEntry(供 __sizeof__/字段布局等派生查询)
|
||||
if is_packed_cd != 0:
|
||||
entry.IsPacked = 1
|
||||
# B5:记录 aligned 对齐值(@c.Attribute(t.attr.aligned(N)),如 fpu_context 16 对齐),
|
||||
# 供全局变量/局部 alloca 生成时施加对齐。
|
||||
align_cd: int = self.Gen.ClassGenBase._class_aligned_value(cd.decorator_list)
|
||||
if align_cd > 0:
|
||||
entry.Align = align_cd
|
||||
|
||||
# 标记 VTable 状态(直接用 entry,规避跨模块同名 find_struct 找错)
|
||||
if has_vtable == 1:
|
||||
entry.HasVTable = 1
|
||||
if is_novtable_deco == 1:
|
||||
entry.IsNoVTable = 1
|
||||
if parent_name is not None:
|
||||
# 1b 阶段父类名是 pool 字符串,reset 后悬空;_translate_oop_methods/
|
||||
# _detect_vtable_status 会在后续文件 find_struct(ParentName) strcmp 解引用
|
||||
# → 用 stdlib 拷贝保证跨文件存活。
|
||||
if self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||||
pn_len: sizet = string.strlen(parent_name)
|
||||
pn_buf: str = CompilerFactory.factory.PermPool.alloc(pn_len + 1)
|
||||
if pn_buf is not None:
|
||||
string.strcpy(pn_buf, parent_name)
|
||||
entry.ParentName = pn_buf
|
||||
else:
|
||||
entry.ParentName = parent_name
|
||||
# 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活)
|
||||
if parents_count > 0 and parents_buf is not None:
|
||||
self.Gen.StructGen.set_parent_names(pool, class_name, parents_buf, parents_count)
|
||||
|
||||
# 添加字段信息
|
||||
# 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始
|
||||
if has_vtable == 1:
|
||||
i8_ptr_ty2: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
self.Gen.StructGen.add_field(pool, entry, "__vtable__", i8_ptr_ty2, None, None)
|
||||
|
||||
for fi in range(field_count):
|
||||
fname_addr: sizet = field_names_buf[fi]
|
||||
if fname_addr == 0:
|
||||
continue
|
||||
fname: str = rawptr(fname_addr)
|
||||
fty_addr2: sizet = field_types_buf[fi]
|
||||
if fty_addr2 == 0:
|
||||
continue
|
||||
fty2: llvmlite.LLVMType* = (llvmlite.LLVMType*)(fty_addr2)
|
||||
# 恢复默认值 AST 指针
|
||||
fdef_addr: sizet = field_defaults_buf[fi]
|
||||
fdef: ast.AST* = None
|
||||
if fdef_addr != 0:
|
||||
fdef = (ast.AST*)(fdef_addr)
|
||||
# 恢复注解类名指针
|
||||
fannot_addr: sizet = field_annot_buf[fi]
|
||||
fannot: str = None
|
||||
if fannot_addr != 0:
|
||||
fannot = str(fannot_addr)
|
||||
if fname is not None and fty2 is not None:
|
||||
fidx_add: int = self.Gen.StructGen.add_field(pool, entry, fname, fty2, fdef, fannot)
|
||||
# t.CVolatile 字段标记(field_volatile_buf[fi] 与 add_field 顺序一一对应)
|
||||
if fidx_add >= 0 and field_volatile_buf[fi] != 0:
|
||||
fe_vol: GenTypes.FieldEntry* = \
|
||||
self.Gen.StructGen._get_field_entry(entry, fidx_add)
|
||||
if fe_vol is not None:
|
||||
fe_vol.IsVolatile = 1
|
||||
# rawptr[t.CVolatile | T] 字段标记(field_pointee_volatile_buf[fi] 与
|
||||
# add_field 顺序一一对应):经该字段解引用时 load/store 带 volatile。
|
||||
if fidx_add >= 0 and field_pointee_volatile_buf[fi] != 0:
|
||||
fe_pv: GenTypes.FieldEntry* = \
|
||||
self.Gen.StructGen._get_field_entry(entry, fidx_add)
|
||||
if fe_pv is not None:
|
||||
fe_pv.PointeeVolatile = 1
|
||||
# const 对象字段标记(field_const_buf[fi] 与 add_field 顺序一一对应)
|
||||
if fidx_add >= 0 and field_const_buf[fi] != 0:
|
||||
fe_c: GenTypes.FieldEntry* = \
|
||||
self.Gen.StructGen._get_field_entry(entry, fidx_add)
|
||||
if fe_c is not None:
|
||||
fe_c.IsConst = 1
|
||||
|
||||
# Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体
|
||||
if trans._declare_only == 1:
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name, 1)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 4. OOP 方法处理:扫描 FunctionDef,标记 OOP,翻译方法,生成 __before_init__
|
||||
# ============================================================
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name)
|
||||
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _translate_nested_classdefs - 递归翻译类体内的嵌套 class / struct
|
||||
#
|
||||
# 命名与引用口径(用户 2026-10-01 定,与 TPC union/renum 嵌套命名同源):
|
||||
# · 内层结构体 IR 名 = `{sha1}.{外类}_{内类}`(sha1 = 与外层相同的定义模块);
|
||||
# · 引用两种写法都可:限定名 `外类.内类`(Attribute 兜底,见 TypeGenResolve)
|
||||
# 与扁平名 `外类_内类`(裸名直查结构体表即可命中);
|
||||
# · 多层嵌套自然递归为 `A_B_C`(递归时子节点名已被改写为 A_B)。
|
||||
# 实现选择"临时改写子节点 name 再递归"而非另写发射器:本模块所有名字派生点
|
||||
# (IR 名 {sha}.{名}、register_struct/add_field、AnnotClassName、方法符号名
|
||||
# `{类}.{方法}` 的 mangling、mark_module_class 键)都读 cd.name ⇒ 改名即全链路
|
||||
# 一致,且复用继承展平/packed/OOP/vtable 等全部既有逻辑,零新增判据。
|
||||
# 两个必须的护栏:
|
||||
# ① 扁平名字符串分配在 PermPool —— 它要跨 Phase(1a/1b)存活,trans.Pool 会随
|
||||
# mark/reset 回收成悬空串(后续 strcmp 读悬空内存)。
|
||||
# ② 递归返回后**还原"正在定义类"窗口**(CurDefModuleSha1/CurDefClassName 会被
|
||||
# 内层 mark_module_class 覆盖)——不还原会让外层随后的字段注解解析误判
|
||||
# "当前定义类"(规则 5.5 的自引用窗口据此判定,误判会冻结裸名票名)。
|
||||
# ============================================================
|
||||
def _translate_nested_classdefs(self, trans: HT.Translator*,
|
||||
cd: ast.ClassDef*) -> None:
|
||||
"""把本类体内的嵌套 ClassDef 逐个按 `{外类}_{内类}` 递归翻译"""
|
||||
if trans is None or cd is None or cd.name is None:
|
||||
return
|
||||
children: list[ast.AST*]* = cd.children
|
||||
if children is None:
|
||||
return
|
||||
cn: sizet = len(children)
|
||||
ci: sizet = 0
|
||||
while ci < cn:
|
||||
child_ast: ast.AST* = children.get(ci)
|
||||
ci += 1
|
||||
if child_ast is None:
|
||||
continue
|
||||
if child_ast.kind() != ast.ASTKind.ClassDef:
|
||||
continue
|
||||
child: ast.ClassDef* = ast.ClassDef*(child_ast)
|
||||
if child is None or child.name is None:
|
||||
continue
|
||||
# 扁平名 `{外类}_{内类}`(优先 PermPool:名字要跨 Phase 存活;
|
||||
# PermPool 缺失时退回本遍池,行为与旧路径一致)
|
||||
flat_pool: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
if flat_pool is None:
|
||||
flat_pool = trans.Pool
|
||||
if flat_pool is None:
|
||||
continue
|
||||
outer_len: sizet = string.strlen(cd.name)
|
||||
inner_len: sizet = string.strlen(child.name)
|
||||
flat_len: sizet = outer_len + 1 + inner_len
|
||||
flat_buf: str = flat_pool.alloc(flat_len + 1)
|
||||
if flat_buf is None:
|
||||
continue
|
||||
viperlib.snprintf(flat_buf, flat_len + 1, "%s_%s", cd.name, child.name)
|
||||
# 改写子节点名 → 递归(内部一律以扁平名注册/发射)
|
||||
old_name: str = child.name
|
||||
child.name = flat_buf
|
||||
saved_def_sha1: str = self.Gen.StructGen.CurDefModuleSha1
|
||||
saved_def_cls: str = self.Gen.StructGen.CurDefClassName
|
||||
self.translate_class_def(trans, child_ast)
|
||||
self.Gen.StructGen.CurDefModuleSha1 = saved_def_sha1
|
||||
self.Gen.StructGen.CurDefClassName = saved_def_cls
|
||||
child.name = old_name
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,40 +2,29 @@ import lib.core.Gen.GenTypes as GenTypes
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
import lib.core.Gen.ClassGenBase as ClassGenBase
|
||||
from . import ClassGenBase
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
|
||||
|
||||
# 泛型特化递归深度上限(泛型循环套用防护)
|
||||
# 正常嵌套特化深度 ≤ 3(如 list[list[str]]);64 远超合理值,命中即循环。
|
||||
# (原 HandlesClassDef/ClassGenMixin 顶层常量,阶段 D 拆分时遗漏,补回)
|
||||
GENERIC_SPEC_MAX_DEPTH: t.CDefine = 64
|
||||
define GENERIC_SPEC_MAX_DEPTH = 64
|
||||
# 泛型模板表容量上限(与 GenericClassNames 等 pool 表可容纳的模板数对齐;
|
||||
# 原 ClassGenMixin 顶层常量,阶段 D 拆分时遗漏,补回)
|
||||
GENERIC_TEMPLATE_MAX: t.CDefine = 512
|
||||
# 泛型特化缓存表容量(原 HandlesClassDef.SPEC_CACHE_MAX,阶段 D 拆分遗漏)
|
||||
SPEC_CACHE_MAX: t.CDefine = 512
|
||||
define GENERIC_TEMPLATE_MAX = 512
|
||||
# 泛型特化缓存表容量
|
||||
define SPEC_CACHE_MAX = 512
|
||||
|
||||
# ============================================================
|
||||
# ClassGenGeneric - ClassGenMixin 拆分(阶段 D):泛型模板注册/特化/克隆
|
||||
#
|
||||
# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ClassGenGeneric - 泛型模板注册/特化/克隆
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
novirtual class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
"""泛型模板注册/特化/克隆"""
|
||||
|
||||
# ============================================================
|
||||
@@ -48,47 +37,82 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
# - _spec_* 全局缓存迁移为 self.SpecKeys/SpecNames/SpecCount
|
||||
# ============================================================
|
||||
|
||||
def _is_generic_class(self, tp: list[str] | t.CPtr) -> int:
|
||||
def _is_generic_class(self, tp: list[str]*) -> int:
|
||||
"""检查 ClassDef 是否有类型参数(泛型类),返回 1=是 / 0=否
|
||||
|
||||
接收 type_params 而非 cd,避免 cd.type_params 属性访问
|
||||
因跨模块类型推断失败返回 None。
|
||||
"""
|
||||
if tp is None:
|
||||
return 0
|
||||
if tp is None: return 0
|
||||
return 1
|
||||
def _register_generic_template(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
cd: ast.ClassDef | t.CPtr,
|
||||
def _dup_perm_str(self, s: str) -> str:
|
||||
"""深拷贝字符串到永久池(无永久池/分配失败时原样返回入参)"""
|
||||
if s is None: return None
|
||||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
if perm is None: return s
|
||||
n: sizet = string.strlen(s)
|
||||
b: str = perm.alloc(n + 1)
|
||||
if b is None: return s
|
||||
string.strcpy(b, s)
|
||||
return b
|
||||
def _register_generic_template(self, pool: memhub.MemBuddy*,
|
||||
cd: ast.ClassDef*,
|
||||
module_sha1: str) -> None:
|
||||
"""注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)"""
|
||||
"""注册泛型类模板(类名 + ClassDef 节点 + 来源模块 SHA1)
|
||||
|
||||
[池归属修复] 这四张表 + GenericClassTpParams 的语义都是**永久表**:
|
||||
批量编译下要在 Phase1 的 reset_to(mark1) 与 Phase2 的 reset_to(mark2) 之后
|
||||
继续可读(读点见 _find_generic_template/_find_generic_template_sha1/
|
||||
_find_generic_template_file/_find_generic_template_tp_params,均有"遍历
|
||||
悬空内存 strcmp 即崩溃"的记录),REPL 下还要跨片段存活。但注册点有三个:
|
||||
- Phase1Scan.vp:322 → perm(永久池);
|
||||
- Phase2/__init__.vp:321 → perm(永久池);
|
||||
- ClassGenDef.vp:78 → trans.Pool(**会被 reset_to 回收的池**)。
|
||||
于是"表在哪个池"取决于哪条路径先注册到表:批量编译里两遍预注册
|
||||
(_PreRegisterAllGenericTemplates / _PreRegisterAppGenericTemplates)在前,
|
||||
表被建在永久池 ⇒ 第三条路径只是追加;而两遍预注册都没建成表时(例如
|
||||
includes 的泛型 marker 文本预筛未命中),第三条路径把表建在 trans.Pool 上,
|
||||
随 mark 回收 ⇒ 后续 _find_generic_template 遍历悬空表(UAF)。REPL 从不跑
|
||||
Phase1/Phase2,第三条路径是**唯一**注册点 ⇒ 表必然落在会被每片段 reset 的
|
||||
池上,M4 一旦在片段里定义泛型类就是必现 UAF。
|
||||
故此处统一:表体一律用永久池(无永久池时退回入参池,即旧行为),并把
|
||||
调用方池里的三个串(类名/SHA1/来源文件)深拷贝进永久池——它们同样会随
|
||||
调用方池回收而悬空(挂名 strcmp 即读悬空内存)。
|
||||
批量编译不变量:变更只影响"表与串分配在哪个池",写入的**内容**逐字不变
|
||||
(同样的类名/节点/ SHA1/文件路径,同样的插入顺序与查重),发射的 IR 与
|
||||
符号名不受池选择影响 ⇒ 逐字不变。
|
||||
"""
|
||||
if cd is None or cd.name is None: return
|
||||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
table_pool: memhub.MemBuddy* = perm
|
||||
if table_pool is None:
|
||||
table_pool = pool
|
||||
if self.GenericClassNames is None:
|
||||
self.GenericClassNames = list[str](pool, 8)
|
||||
self.GenericClassNodes = list[ast.ClassDef | t.CPtr](pool, 8)
|
||||
self.GenericClassSha1s = list[str](pool, 8)
|
||||
self.GenericClassFiles = list[str](pool, 8)
|
||||
self.GenericClassNames = list[str](table_pool, 8)
|
||||
self.GenericClassNodes = list[ast.ClassDef*](table_pool, 8)
|
||||
self.GenericClassSha1s = list[str](table_pool, 8)
|
||||
self.GenericClassFiles = list[str](table_pool, 8)
|
||||
if self.GenericClassTpParams is None:
|
||||
self.GenericClassTpParams = CompilerFactory.get_perm_pool().alloc(GENERIC_TEMPLATE_MAX * 8)
|
||||
if self.GenericClassTpParams is None:
|
||||
return
|
||||
if perm is None: return
|
||||
self.GenericClassTpParams = perm.alloc(GENERIC_TEMPLATE_MAX * 8)
|
||||
if self.GenericClassTpParams is None: return
|
||||
string.memset(self.GenericClassTpParams, 0, GENERIC_TEMPLATE_MAX * 8)
|
||||
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
|
||||
names_local: list[str] | t.CPtr = self.GenericClassNames
|
||||
cn: t.CSizeT = len(names_local)
|
||||
i: t.CSizeT
|
||||
names_local: list[str]* = self.GenericClassNames
|
||||
cn: sizet = len(names_local)
|
||||
for i in range(cn):
|
||||
nm: str = names_local.get(i)
|
||||
if nm is not None and string.strcmp(nm, cd.name) == 0:
|
||||
return
|
||||
if nm is not None and string.strcmp(nm, cd.name) == 0: return
|
||||
# type_params stdlib 深拷贝:模板节点的 type_params 是 pool 分配的
|
||||
tp_names_buf: str = self._copy_type_params_stdlib(cd.type_params)
|
||||
self.GenericClassNames.append(cd.name)
|
||||
self.GenericClassNames.append(self._dup_perm_str(cd.name))
|
||||
self.GenericClassNodes.append(cd)
|
||||
self.GenericClassSha1s.append(module_sha1)
|
||||
self.GenericClassSha1s.append(self._dup_perm_str(module_sha1))
|
||||
# 同时保存模板来源文件路径(错误定位用,见字段注释)
|
||||
self.GenericClassFiles.append(self.Gen.TypeGenResolve.get_current_file())
|
||||
self.GenericClassFiles.append(self._dup_perm_str(self.Gen.TypeGenResolve.get_current_file()))
|
||||
if tp_names_buf is not None and cn < GENERIC_TEMPLATE_MAX:
|
||||
self.GenericClassTpParams[cn] = t.CSizeT(tp_names_buf)
|
||||
def _copy_type_params_stdlib(self, tp: list[str] | t.CPtr) -> str:
|
||||
self.GenericClassTpParams[cn] = sizet(tp_names_buf)
|
||||
def _copy_type_params_stdlib(self, tp: list[str]*) -> str:
|
||||
"""将模板 type_params 深拷贝为空格分隔、NUL 结尾的 stdlib 缓冲区
|
||||
|
||||
TPC Python 参考实现:type_params = [tp.name for tp in Node.type_params]
|
||||
@@ -98,17 +122,17 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
"""
|
||||
if tp is None:
|
||||
return None
|
||||
tp_n: t.CSizeT = len(tp)
|
||||
tp_n: sizet = len(tp)
|
||||
if tp_n == 0:
|
||||
return None
|
||||
# 计算总长:各名字长度 + (n-1) 个空格 + NUL
|
||||
total: t.CSizeT = 1
|
||||
ti: t.CSizeT
|
||||
total: sizet = 1
|
||||
ti: sizet
|
||||
for ti in range(tp_n):
|
||||
tp_name: str = tp.get(ti)
|
||||
if tp_name is not None:
|
||||
total += string.strlen(tp_name) + 1
|
||||
buf: str = CompilerFactory.get_perm_pool().alloc(total)
|
||||
buf: str = CompilerFactory.factory.PermPool.alloc(total)
|
||||
if buf is None:
|
||||
return None
|
||||
buf[0] = '\0'
|
||||
@@ -120,8 +144,8 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
string.strcat(buf, " ")
|
||||
string.strcat(buf, tp_name)
|
||||
return buf
|
||||
def _find_generic_template_tp_params(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
class_name: str) -> list[str] | t.CPtr:
|
||||
def _find_generic_template_tp_params(self, pool: memhub.MemBuddy*,
|
||||
class_name: str) -> list[str]*:
|
||||
"""查找泛型类模板的类型参数名列表,未找到返回 None
|
||||
|
||||
从注册时深拷贝的 stdlib 缓冲区重建当前 pool 的 list[str]
|
||||
@@ -130,32 +154,32 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if self.GenericClassNames is None or class_name is None \
|
||||
or self.GenericClassTpParams is None:
|
||||
return None
|
||||
names_local: list[str] | t.CPtr = self.GenericClassNames
|
||||
cn: t.CSizeT = len(names_local)
|
||||
i: t.CSizeT
|
||||
names_local: list[str]* = self.GenericClassNames
|
||||
cn: sizet = len(names_local)
|
||||
i: sizet
|
||||
for i in range(cn):
|
||||
nm: str = names_local.get(i)
|
||||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||||
if i >= GENERIC_TEMPLATE_MAX:
|
||||
return None
|
||||
buf_addr: t.CSizeT = self.GenericClassTpParams[i]
|
||||
buf_addr: sizet = self.GenericClassTpParams[i]
|
||||
if buf_addr == 0:
|
||||
return None
|
||||
buf_tp: str = (str | t.CPtr)(t.CVoid(buf_addr, t.CPtr))
|
||||
buf_tp: str = rawptr(buf_addr)
|
||||
# 空格分隔 → list[str]
|
||||
# 注意:list[str](pool, 8) 第二个参数是 elem_size(指针 8 字节),
|
||||
# 不是容量!传 4 会导致 get(i) 偏移算错、append 相互覆盖
|
||||
# (Pair[T1,T2] 的 seg1 写 data+4 覆盖 seg0 高 4 字节 → strcmp
|
||||
# 收到 0x15B78D5015B78CB0 混合垃圾崩溃,GenericTest 回归根因)
|
||||
tp_list: list[str] | t.CPtr = list[str](pool, 8)
|
||||
tp_list: list[str]* = list[str](pool, 8)
|
||||
if tp_list is None:
|
||||
return None
|
||||
seg_start: t.CSizeT = 0
|
||||
pos: t.CSizeT = 0
|
||||
blen: t.CSizeT = string.strlen(buf_tp)
|
||||
seg_start: sizet = 0
|
||||
pos: sizet = 0
|
||||
blen: sizet = string.strlen(buf_tp)
|
||||
while pos <= blen:
|
||||
if buf_tp[pos] == ' ' or buf_tp[pos] == '\0':
|
||||
seg_len: t.CSizeT = pos - seg_start
|
||||
seg_len: sizet = pos - seg_start
|
||||
if seg_len > 0:
|
||||
seg: str = pool.alloc(seg_len + 1)
|
||||
if seg is not None:
|
||||
@@ -166,19 +190,19 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
pos += 1
|
||||
return tp_list
|
||||
return None
|
||||
def _find_generic_template(self, class_name: str) -> ast.ClassDef | t.CPtr:
|
||||
def _find_generic_template(self, class_name: str) -> ast.ClassDef*:
|
||||
"""查找泛型类模板,返回 ClassDef 节点或 None"""
|
||||
if self.GenericClassNames is None or class_name is None:
|
||||
return None
|
||||
# 用局部变量接收 list,触发类型推断(避免字段 __len__ 失败)
|
||||
names_local: list[str] | t.CPtr = self.GenericClassNames
|
||||
nodes_local: list[ast.ClassDef | t.CPtr] | t.CPtr = self.GenericClassNodes
|
||||
cn: t.CSizeT = len(names_local)
|
||||
i: t.CSizeT
|
||||
names_local: list[str]* = self.GenericClassNames
|
||||
nodes_local: list[ast.ClassDef*] | t.CPtr = self.GenericClassNodes
|
||||
cn: sizet = len(names_local)
|
||||
i: sizet
|
||||
for i in range(cn):
|
||||
nm: str = names_local.get(i)
|
||||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||||
node: ast.ClassDef | t.CPtr = nodes_local.get(i)
|
||||
node: ast.ClassDef* = nodes_local.get(i)
|
||||
return node
|
||||
return None
|
||||
def _find_generic_template_sha1(self, class_name: str) -> str:
|
||||
@@ -186,10 +210,10 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if self.GenericClassNames is None or class_name is None:
|
||||
return None
|
||||
# 用局部变量接收 list,触发类型推断
|
||||
names_local: list[str] | t.CPtr = self.GenericClassNames
|
||||
sha1s_local: list[str] | t.CPtr = self.GenericClassSha1s
|
||||
cn: t.CSizeT = len(names_local)
|
||||
i: t.CSizeT
|
||||
names_local: list[str]* = self.GenericClassNames
|
||||
sha1s_local: list[str]* = self.GenericClassSha1s
|
||||
cn: sizet = len(names_local)
|
||||
i: sizet
|
||||
for i in range(cn):
|
||||
nm: str = names_local.get(i)
|
||||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||||
@@ -204,35 +228,61 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
"""
|
||||
if self.GenericClassNames is None or class_name is None:
|
||||
return None
|
||||
names_local: list[str] | t.CPtr = self.GenericClassNames
|
||||
files_local: list[str] | t.CPtr = self.GenericClassFiles
|
||||
cn: t.CSizeT = len(names_local)
|
||||
i: t.CSizeT
|
||||
names_local: list[str]* = self.GenericClassNames
|
||||
files_local: list[str]* = self.GenericClassFiles
|
||||
cn: sizet = len(names_local)
|
||||
i: sizet
|
||||
for i in range(cn):
|
||||
nm: str = names_local.get(i)
|
||||
if nm is not None and string.strcmp(nm, class_name) == 0:
|
||||
f_val: str = files_local.get(i)
|
||||
return f_val
|
||||
return None
|
||||
def _mangle_generic_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
def _mangle_generic_class_name(self, pool: memhub.MemBuddy*,
|
||||
class_name: str,
|
||||
type_args: list[str] | t.CPtr) -> str:
|
||||
type_args: list[str]*,
|
||||
from_imports: str = None) -> str:
|
||||
"""生成特化类名: list + [int] -> list[int]
|
||||
|
||||
**唯一生成器 + 唯一规范化点**:所有特化名(结构体注册名、方法符号里的
|
||||
后缀段、查找键)都由这里产出,故类型实参的 SHA1 规范化只在这里做一次 ——
|
||||
每个实参经 `TypeGenResolve._norm_type_arg_name` 归一到
|
||||
`{定义模块SHA1}.{Class}`(该函数对已规范化的串**幂等**:规则 2/3/6 原样
|
||||
返回,嵌套 `rawptr[X]` 也递归同形)⇒ 无论调用方(注解侧 / 构造侧 /
|
||||
基类侧 / 字面量推断侧)传进来的实参是裸名还是已带前缀,注册名与查找名
|
||||
**必然同形**。此前裸露名与已带前缀的两侧会分裂成两个特化结构体,已出现
|
||||
三种现场:形参侧/实参侧(stmts.vp:60)、字段侧/构造侧(base.vp:357)、
|
||||
基类侧/注解侧(ClassGenBase._get_base_name 的裸 Name.id)。
|
||||
|
||||
分配新缓冲区拼接,避免原地 strcat 导致缓冲区溢出
|
||||
"""
|
||||
if class_name is None or type_args is None or pool is None:
|
||||
return class_name
|
||||
n: t.CSizeT = len(type_args)
|
||||
n: sizet = len(type_args)
|
||||
if n == 0:
|
||||
return class_name
|
||||
# 逐实参规范化(幂等):先归一成新列表,长度计算与拼接都用归一后的串
|
||||
norm_args: list[str]* = list[str](pool, 8)
|
||||
if norm_args is None:
|
||||
return class_name
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
ta_raw: str = type_args.get(i)
|
||||
if ta_raw is None:
|
||||
continue
|
||||
ta_norm: str = self.Gen.TypeGenResolve._norm_type_arg_name(pool, ta_raw, from_imports)
|
||||
if ta_norm is None:
|
||||
ta_norm = ta_raw
|
||||
norm_args.append(ta_norm)
|
||||
n = len(norm_args)
|
||||
if n == 0:
|
||||
return class_name
|
||||
# 计算总长度: class_name + "[" + arg0 + "," + arg1 + ... + "]" + NUL
|
||||
total_len: t.CSizeT = string.strlen(class_name) + 2 # "[" 和 "]"
|
||||
i: t.CSizeT
|
||||
total_len: sizet = string.strlen(class_name) + 2 # "[" 和 "]"
|
||||
for i in range(n):
|
||||
if i > 0:
|
||||
total_len += 1 # ","
|
||||
ta: str = type_args.get(i)
|
||||
ta: str = norm_args.get(i)
|
||||
if ta is not None:
|
||||
total_len += string.strlen(ta)
|
||||
total_len += 1 # NUL
|
||||
@@ -246,15 +296,15 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
for i in range(n):
|
||||
if i > 0:
|
||||
string.strcat(mangled, ",")
|
||||
ta: str = type_args.get(i)
|
||||
ta: str = norm_args.get(i)
|
||||
if ta is not None:
|
||||
string.strcat(mangled, ta)
|
||||
string.strcat(mangled, "]")
|
||||
return mangled
|
||||
def _clone_annotation(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
tp_names: list[str] | t.CPtr,
|
||||
type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr:
|
||||
def _clone_annotation(self, pool: memhub.MemBuddy*,
|
||||
node: ast.AST*,
|
||||
tp_names: list[str]*,
|
||||
type_args: list[str]*) -> ast.AST*:
|
||||
"""拷贝类型注解表达式,替换类型参数 T 为具体类型名
|
||||
|
||||
tp_names: 类型参数名列表 ['T']
|
||||
@@ -266,97 +316,97 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
|
||||
# Name: 可能是类型参数 T
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None:
|
||||
n: t.CSizeT = len(tp_names) if tp_names is not None else 0
|
||||
i: t.CSizeT
|
||||
n: sizet = len(tp_names) if tp_names is not None else 0
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
tpn: str = tp_names.get(i)
|
||||
if tpn is not None and string.strcmp(nm.id, tpn) == 0:
|
||||
ta: str = type_args.get(i)
|
||||
# 类型实参可能是复合类型(如 "AST|t.CPtr"),用 _parse_type_string 解析
|
||||
parsed_node: ast.AST | t.CPtr = self.Gen.TypeGenResolve._parse_type_string(pool, ta, nm.ctx)
|
||||
parsed_node: ast.AST* = self.Gen.TypeGenResolve._parse_type_string(pool, ta, nm.ctx)
|
||||
return parsed_node
|
||||
return ast.Name(pool, nm.id, nm.ctx)
|
||||
return None
|
||||
|
||||
# Attribute: t.CPtr 等
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
new_value: ast.AST | t.CPtr = self._clone_annotation(pool, at.value, tp_names, type_args)
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
new_value: ast.AST* = self._clone_annotation(pool, at.value, tp_names, type_args)
|
||||
return ast.Attribute(pool, new_value, at.attr, at.ctx)
|
||||
|
||||
# BinOp: T | t.CPtr 等
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
new_left: ast.AST | t.CPtr = self._clone_annotation(pool, bop.left, tp_names, type_args)
|
||||
new_right: ast.AST | t.CPtr = self._clone_annotation(pool, bop.right, tp_names, type_args)
|
||||
bop: ast.BinOp* = ast.BinOp*(node)
|
||||
new_left: ast.AST* = self._clone_annotation(pool, bop.left, tp_names, type_args)
|
||||
new_right: ast.AST* = self._clone_annotation(pool, bop.right, tp_names, type_args)
|
||||
return ast.BinOp(pool, new_left, bop.op, new_right)
|
||||
|
||||
# Subscript: list[int] 等
|
||||
if k == ast.ASTKind.Subscript:
|
||||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
new_value2: ast.AST | t.CPtr = self._clone_annotation(pool, sub.value, tp_names, type_args)
|
||||
new_slice: ast.AST | t.CPtr = self._clone_annotation(pool, sub.slice, tp_names, type_args)
|
||||
sub: ast.Subscript* = ast.Subscript*(node)
|
||||
new_value2: ast.AST* = self._clone_annotation(pool, sub.value, tp_names, type_args)
|
||||
new_slice: ast.AST* = self._clone_annotation(pool, sub.slice, tp_names, type_args)
|
||||
return ast.Subscript(pool, new_value2, new_slice, sub.ctx)
|
||||
|
||||
# Tuple: (T, int) 等
|
||||
if k == ast.ASTKind.Tuple:
|
||||
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
|
||||
new_elts: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8)
|
||||
tup: ast.Tuple* = ast.Tuple*(node)
|
||||
new_elts: list[ast.AST*]* = list[ast.AST*](pool, 8)
|
||||
if tup.elts is not None:
|
||||
tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts
|
||||
en: t.CSizeT = len(tup_elts)
|
||||
ei: t.CSizeT
|
||||
tup_elts: list[ast.AST*]* = tup.elts
|
||||
en: sizet = len(tup_elts)
|
||||
ei: sizet
|
||||
for ei in range(en):
|
||||
el: ast.AST | t.CPtr = tup_elts.get(ei)
|
||||
new_el: ast.AST | t.CPtr = self._clone_annotation(pool, el, tp_names, type_args)
|
||||
el: ast.AST* = tup_elts.get(ei)
|
||||
new_el: ast.AST* = self._clone_annotation(pool, el, tp_names, type_args)
|
||||
if new_el is not None:
|
||||
new_elts.append(new_el)
|
||||
return ast.Tuple(pool, new_elts, tup.ctx)
|
||||
|
||||
# Constant: 默认值等
|
||||
if k == ast.ASTKind.Constant:
|
||||
cnst: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
cnst: ast.Constant* = ast.Constant*(node)
|
||||
return ast.Constant(pool, cnst.const_kind, cnst.int_val, cnst.float_val,
|
||||
cnst.str_val, cnst.lineno, cnst.col_offset)
|
||||
|
||||
# 其他: 直接引用(不拷贝)
|
||||
return node
|
||||
def _clone_arguments(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
args: ast.AST | t.CPtr,
|
||||
tp_names: list[str] | t.CPtr,
|
||||
type_args: list[str] | t.CPtr) -> ast.AST | t.CPtr:
|
||||
def _clone_arguments(self, pool: memhub.MemBuddy*,
|
||||
args: ast.AST*,
|
||||
tp_names: list[str]*,
|
||||
type_args: list[str]*) -> ast.AST*:
|
||||
"""拷贝 Arguments 节点,替换 arg annotation 中的 T"""
|
||||
if args is None:
|
||||
return None
|
||||
if args.kind() != ast.ASTKind.Arguments:
|
||||
return args
|
||||
old_args: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args)
|
||||
old_args: ast.Arguments* = ast.Arguments*(args)
|
||||
# 拷贝 args 列表,替换每个 Arg 的 annotation
|
||||
new_arg_list: list[ast.AST | t.CPtr] | t.CPtr = list[ast.AST | t.CPtr](pool, 8)
|
||||
new_arg_list: list[ast.AST*]* = list[ast.AST*](pool, 8)
|
||||
if old_args.args is not None:
|
||||
old_arg_list: list[ast.AST | t.CPtr] | t.CPtr = old_args.args
|
||||
an: t.CSizeT = len(old_arg_list)
|
||||
ai: t.CSizeT
|
||||
old_arg_list: list[ast.AST*]* = old_args.args
|
||||
an: sizet = len(old_arg_list)
|
||||
ai: sizet
|
||||
for ai in range(an):
|
||||
arg_node: ast.AST | t.CPtr = old_arg_list.get(ai)
|
||||
arg_node: ast.AST* = old_arg_list.get(ai)
|
||||
if arg_node is None:
|
||||
continue
|
||||
if arg_node.kind() == ast.ASTKind.Arg:
|
||||
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(arg_node)
|
||||
new_anno: ast.AST | t.CPtr = self._clone_annotation(pool, ag.annotation, tp_names, type_args)
|
||||
new_arg: ast.Arg | t.CPtr = ast.Arg(pool, ag.arg, new_anno)
|
||||
ag: ast.Arg* = ast.Arg*(arg_node)
|
||||
new_anno: ast.AST* = self._clone_annotation(pool, ag.annotation, tp_names, type_args)
|
||||
new_arg: ast.Arg* = ast.Arg(pool, ag.arg, new_anno)
|
||||
new_arg_list.append(new_arg)
|
||||
else:
|
||||
new_arg_list.append(arg_node)
|
||||
return ast.Arguments(pool, new_arg_list, old_args.vararg, old_args.kwarg,
|
||||
old_args.defaults, old_args.kw_defaults)
|
||||
def _clone_classdef_for_spec(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
cd: ast.ClassDef | t.CPtr,
|
||||
def _clone_classdef_for_spec(self, pool: memhub.MemBuddy*,
|
||||
cd: ast.ClassDef*,
|
||||
spec_name: str,
|
||||
tp_names: list[str] | t.CPtr,
|
||||
type_args: list[str] | t.CPtr) -> ast.ClassDef | t.CPtr:
|
||||
tp_names: list[str]*,
|
||||
type_args: list[str]*) -> ast.ClassDef*:
|
||||
"""拷贝 ClassDef 节点用于泛型特化
|
||||
|
||||
- 替换类名为 spec_name
|
||||
@@ -365,40 +415,40 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
- 方法体直接引用原始节点(通过 type_map 上下文处理 T)
|
||||
"""
|
||||
# 创建新 ClassDef(type_params=None 表示非泛型)
|
||||
new_cd: ast.ClassDef | t.CPtr = ast.ClassDef(pool, spec_name, cd.bases, cd.keywords,
|
||||
new_cd: ast.ClassDef* = ast.ClassDef(pool, spec_name, cd.bases, cd.keywords,
|
||||
cd.decorator_list, None)
|
||||
# 拷贝 children
|
||||
if cd.children is not None:
|
||||
cd_children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
cn: t.CSizeT = len(cd_children)
|
||||
ci: t.CSizeT
|
||||
cd_children: list[ast.AST*]* = cd.children
|
||||
cn: sizet = len(cd_children)
|
||||
ci: sizet
|
||||
for ci in range(cn):
|
||||
child: ast.AST | t.CPtr = cd_children.get(ci)
|
||||
child: ast.AST* = cd_children.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
ck: int = child.kind()
|
||||
|
||||
if ck == ast.ASTKind.AnnAssign:
|
||||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child)
|
||||
new_target: ast.AST | t.CPtr = aa.target
|
||||
new_anno2: ast.AST | t.CPtr = self._clone_annotation(pool, aa.annotation, tp_names, type_args)
|
||||
new_value3: ast.AST | t.CPtr = aa.value
|
||||
new_aa: ast.AnnAssign | t.CPtr = ast.AnnAssign(pool, new_target, new_anno2, new_value3, aa.simple)
|
||||
aa: ast.AnnAssign* = ast.AnnAssign*(child)
|
||||
new_target: ast.AST* = aa.target
|
||||
new_anno2: ast.AST* = self._clone_annotation(pool, aa.annotation, tp_names, type_args)
|
||||
new_value3: ast.AST* = aa.value
|
||||
new_aa: ast.AnnAssign* = ast.AnnAssign(pool, new_target, new_anno2, new_value3, aa.simple)
|
||||
new_cd.append(new_aa)
|
||||
|
||||
elif ck == ast.ASTKind.FunctionDef:
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||||
new_args2: ast.AST | t.CPtr = self._clone_arguments(pool, fd.args, tp_names, type_args)
|
||||
new_returns2: ast.AST | t.CPtr = self._clone_annotation(pool, fd.returns, tp_names, type_args)
|
||||
new_fd: ast.FunctionDef | t.CPtr = ast.FunctionDef(pool, fd.name, new_args2,
|
||||
fd: ast.FunctionDef* = ast.FunctionDef*(child)
|
||||
new_args2: ast.AST* = self._clone_arguments(pool, fd.args, tp_names, type_args)
|
||||
new_returns2: ast.AST* = self._clone_annotation(pool, fd.returns, tp_names, type_args)
|
||||
new_fd: ast.FunctionDef* = ast.FunctionDef(pool, fd.name, new_args2,
|
||||
fd.decorator_list, new_returns2, 0)
|
||||
# 方法体直接引用原始节点
|
||||
if fd.children is not None:
|
||||
fd_children: list[ast.AST | t.CPtr] | t.CPtr = fd.children
|
||||
bcn: t.CSizeT = len(fd_children)
|
||||
bci: t.CSizeT
|
||||
fd_children: list[ast.AST*]* = fd.children
|
||||
bcn: sizet = len(fd_children)
|
||||
bci: sizet
|
||||
for bci in range(bcn):
|
||||
body_stmt: ast.AST | t.CPtr = fd_children.get(bci)
|
||||
body_stmt: ast.AST* = fd_children.get(bci)
|
||||
if body_stmt is not None:
|
||||
new_fd.append(body_stmt)
|
||||
new_cd.append(new_fd)
|
||||
@@ -413,21 +463,21 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
return None
|
||||
i: int
|
||||
for i in range(self.SpecCount):
|
||||
key_addr: t.CSizeT = self.SpecKeys[i]
|
||||
key_addr: sizet = self.SpecKeys[i]
|
||||
if key_addr != 0:
|
||||
k: str = (str | t.CPtr)(t.CVoid(key_addr, t.CPtr))
|
||||
k: str = rawptr(key_addr)
|
||||
if k is not None and string.strcmp(k, spec_key) == 0:
|
||||
name_addr: t.CSizeT = self.SpecNames[i]
|
||||
name_addr: sizet = self.SpecNames[i]
|
||||
if name_addr != 0:
|
||||
return (str | t.CPtr)(t.CVoid(name_addr, t.CPtr))
|
||||
return rawptr(name_addr)
|
||||
return None
|
||||
def _cache_spec(self, pool: memhub.MemBuddy | t.CPtr, spec_key: str, spec_name: str):
|
||||
def _cache_spec(self, pool: memhub.MemBuddy*, spec_key: str, spec_name: str):
|
||||
"""缓存特化结果(stdlib 深拷贝存储,跨文件安全)"""
|
||||
if spec_key is None or spec_name is None:
|
||||
return
|
||||
if self.SpecKeys is None:
|
||||
self.SpecKeys = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8)
|
||||
self.SpecNames = CompilerFactory.get_perm_pool().alloc(SPEC_CACHE_MAX * 8)
|
||||
self.SpecKeys = CompilerFactory.factory.PermPool.alloc(SPEC_CACHE_MAX * 8)
|
||||
self.SpecNames = CompilerFactory.factory.PermPool.alloc(SPEC_CACHE_MAX * 8)
|
||||
if self.SpecKeys is None or self.SpecNames is None:
|
||||
return
|
||||
string.memset(self.SpecKeys, 0, SPEC_CACHE_MAX * 8)
|
||||
@@ -436,18 +486,18 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if self.SpecCount >= SPEC_CACHE_MAX:
|
||||
return
|
||||
# 深拷贝字符串到 stdlib 区
|
||||
key_len: t.CSizeT = string.strlen(spec_key)
|
||||
name_len: t.CSizeT = string.strlen(spec_name)
|
||||
key_copy: str = CompilerFactory.get_perm_pool().alloc(key_len + 1)
|
||||
name_copy: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||||
key_len: sizet = string.strlen(spec_key)
|
||||
name_len: sizet = string.strlen(spec_name)
|
||||
key_copy: str = CompilerFactory.factory.PermPool.alloc(key_len + 1)
|
||||
name_copy: str = CompilerFactory.factory.PermPool.alloc(name_len + 1)
|
||||
if key_copy is None or name_copy is None:
|
||||
return
|
||||
string.strcpy(key_copy, spec_key)
|
||||
string.strcpy(name_copy, spec_name)
|
||||
self.SpecKeys[self.SpecCount] = t.CSizeT(key_copy)
|
||||
self.SpecNames[self.SpecCount] = t.CSizeT(name_copy)
|
||||
self.SpecKeys[self.SpecCount] = sizet(key_copy)
|
||||
self.SpecNames[self.SpecCount] = sizet(name_copy)
|
||||
self.SpecCount += 1
|
||||
def _merge_template_imports(self, trans: HT.Translator | t.CPtr,
|
||||
def _merge_template_imports(self, trans: HT.Translator*,
|
||||
template_sha1: str) -> None:
|
||||
"""将模板模块的 imports 并入 trans._imported_modules(空格分隔)"""
|
||||
if trans is None or template_sha1 is None:
|
||||
@@ -459,8 +509,8 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if cur is None or cur[0] == '\0':
|
||||
trans._imported_modules = tdeps
|
||||
return
|
||||
cur_len: t.CSizeT = string.strlen(cur)
|
||||
td_len: t.CSizeT = string.strlen(tdeps)
|
||||
cur_len: sizet = string.strlen(cur)
|
||||
td_len: sizet = string.strlen(tdeps)
|
||||
merged: str = trans.Pool.alloc(cur_len + td_len + 2)
|
||||
if merged is None:
|
||||
return
|
||||
@@ -468,7 +518,7 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
merged[cur_len] = ' '
|
||||
string.strcpy(merged + cur_len + 1, tdeps)
|
||||
trans._imported_modules = merged
|
||||
def _record_spec_trigger(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
def _record_spec_trigger(self, pool: memhub.MemBuddy*,
|
||||
spec_name: str, trigger_sha1: str) -> int:
|
||||
"""记录泛型特化类的触发文件 sha1(StructEntry.SpecTriggerSha1)
|
||||
|
||||
@@ -479,21 +529,21 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
"""
|
||||
if spec_name is None or trigger_sha1 is None:
|
||||
return 0
|
||||
entry_rt: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name)
|
||||
entry_rt: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||||
if entry_rt is None:
|
||||
return 0
|
||||
if string.strcmp(entry_rt.Name, spec_name) != 0:
|
||||
return 0
|
||||
ts_len_r: t.CSizeT = string.strlen(trigger_sha1)
|
||||
ts_buf_r: str = CompilerFactory.get_perm_pool().alloc(ts_len_r + 1)
|
||||
ts_len_r: sizet = string.strlen(trigger_sha1)
|
||||
ts_buf_r: str = CompilerFactory.factory.PermPool.alloc(ts_len_r + 1)
|
||||
if ts_buf_r is None:
|
||||
return 0
|
||||
string.strcpy(ts_buf_r, trigger_sha1)
|
||||
entry_rt.SpecTriggerSha1 = ts_buf_r
|
||||
return 1
|
||||
def _specialize_generic_class(self, trans: HT.Translator | t.CPtr,
|
||||
def _specialize_generic_class(self, trans: HT.Translator*,
|
||||
class_name: str,
|
||||
type_args: list[str] | t.CPtr) -> str:
|
||||
type_args: list[str]*) -> str:
|
||||
"""特化泛型类,返回特化类名
|
||||
|
||||
1. 查找泛型模板
|
||||
@@ -512,7 +562,7 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
# 特化触发文件 sha1:进入函数时 trans.ModuleSha1 是触发方文件,
|
||||
# 翻译特化类时会被切换为模板 sha1(见下方),作废重译时按此重置
|
||||
# 特化类 MethodsEmitted(见 _record_spec_trigger / reset_module_methods_emitted)
|
||||
spec_trigger_sha1: str = trans.ModuleSha1
|
||||
spec_trigger_sha1: str = trans.ModuleSha1
|
||||
if self.GenericSpecDepth > GENERIC_SPEC_MAX_DEPTH:
|
||||
err_spec: str = trans.Pool.alloc(256)
|
||||
if err_spec is not None:
|
||||
@@ -524,8 +574,8 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
# 防御:泛型上下文内收集的 type_args 若残留未替换的类型参数名(如 "T"),
|
||||
# 统一替换为具体类型名,避免 ndarray[T] 二次递归特化崩溃。
|
||||
# 调用方传入的 type_args 均为临时新建列表,就地替换无共享副作用。
|
||||
ta_cnt_g: t.CSizeT = len(type_args)
|
||||
ta_i_g: t.CSizeT
|
||||
ta_cnt_g: sizet = len(type_args)
|
||||
ta_i_g: sizet
|
||||
for ta_i_g in range(ta_cnt_g):
|
||||
ta_raw_g: str = type_args.get(ta_i_g)
|
||||
if ta_raw_g is not None:
|
||||
@@ -533,27 +583,29 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if ta_rsv_g is not None and string.strcmp(ta_raw_g, ta_rsv_g) != 0:
|
||||
type_args.set(ta_i_g, ta_rsv_g)
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
|
||||
# 1. 查找泛型模板
|
||||
template_cd: ast.ClassDef | t.CPtr = self._find_generic_template(class_name)
|
||||
template_cd: ast.ClassDef* = self._find_generic_template(class_name)
|
||||
if template_cd is None:
|
||||
self.GenericSpecDepth -= 1
|
||||
return None
|
||||
|
||||
# 2. 生成特化名
|
||||
spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args)
|
||||
# 2. 生成特化名(唯一生成器内部逐实参规范化:裸名/带前缀在此收敛为同一名)
|
||||
_from_imports: str = None
|
||||
if trans is not None:
|
||||
_from_imports = trans._from_imports
|
||||
spec_name: str = self._mangle_generic_class_name(pool, class_name, type_args, _from_imports)
|
||||
if spec_name is None:
|
||||
self.GenericSpecDepth -= 1
|
||||
return None
|
||||
|
||||
# 治本修复:Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前)
|
||||
# Phase 1a(declare_only==1)特化时只注册结构体不译方法体(MethodsEmitted==0),
|
||||
# Phase B(declare_only==0)重复进入时若方法体未译,补译方法体生成 define,
|
||||
# 避免 GSList[Line].append 等符号只有 declare 无 define → 链接失败。
|
||||
# Phase B 补译泛型特化类方法体(统一入口,在 cache/existing 检查之前):Phase 1a
|
||||
# 特化时只注册结构体不译方法体(MethodsEmitted==0),Phase B 重复进入时补译以生成
|
||||
# define,避免符号只有 declare 无 define → 链接失败。
|
||||
# 首次 Phase B 特化(Phase 1a 未特化)find_struct 返回 None,不补译,走下方正常全量翻译。
|
||||
if trans._declare_only == 0:
|
||||
pre_existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name)
|
||||
pre_existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||||
if pre_existing is not None and pre_existing.MethodsEmitted == 0:
|
||||
# 防重入:先标记 MethodsEmitted=1,避免补译过程中方法体/返回类型注解
|
||||
# 再次触发 _specialize_generic_class(如 __iter__ 返回 list[T]|t.CPtr)
|
||||
@@ -563,12 +615,10 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
# 方法体永不发射 → 特化方法只有 call 无 define → 链接 undefined symbol。
|
||||
pre_existing.MethodsEmitted = 1
|
||||
# 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效)
|
||||
tp_names_pre: list[str] | t.CPtr = self._find_generic_template_tp_params(
|
||||
pool, class_name)
|
||||
tp_names_pre: list[str]* = self._find_generic_template_tp_params(pool, class_name)
|
||||
if tp_names_pre is None:
|
||||
tp_names_pre = template_cd.type_params
|
||||
spec_cd_pre: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec(
|
||||
pool, template_cd, spec_name, tp_names_pre, type_args)
|
||||
spec_cd_pre: ast.ClassDef* = self._clone_classdef_for_spec(pool, template_cd, spec_name, tp_names_pre, type_args)
|
||||
if spec_cd_pre is not None:
|
||||
trans.GenericTypeParamNames = tp_names_pre
|
||||
trans.GenericTypeArgs = type_args
|
||||
@@ -599,9 +649,9 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
|
||||
# 3. 检查缓存(spec_key 包含所有类型实参,避免多参数泛型缓存冲突)
|
||||
# 分配新缓冲区避免原地 strcat 溢出
|
||||
sk_n: t.CSizeT = len(type_args)
|
||||
sk_total: t.CSizeT = string.strlen(class_name) + 2 # "<" 和 ">"
|
||||
sk_i: t.CSizeT
|
||||
sk_n: sizet = len(type_args)
|
||||
sk_total: sizet = string.strlen(class_name) + 2 # "<" 和 ">"
|
||||
sk_i: sizet
|
||||
for sk_i in range(sk_n):
|
||||
if sk_i > 0:
|
||||
sk_total += 1 # ","
|
||||
@@ -630,7 +680,7 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
return cached
|
||||
|
||||
# 4. 检查是否已注册(Phase B 重复特化)
|
||||
existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name)
|
||||
existing: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||||
if existing is not None:
|
||||
self._cache_spec(pool, spec_key, spec_name)
|
||||
self._record_spec_trigger(pool, spec_name, spec_trigger_sha1)
|
||||
@@ -642,12 +692,10 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
|
||||
# 5. 拷贝 ClassDef 节点
|
||||
# 从 stdlib 深拷贝表取 type_params(模板节点 pool list 跨 Phase 可能失效)
|
||||
tp_names: list[str] | t.CPtr = self._find_generic_template_tp_params(
|
||||
pool, class_name)
|
||||
tp_names: list[str]* = self._find_generic_template_tp_params(pool, class_name)
|
||||
if tp_names is None:
|
||||
tp_names = template_cd.type_params
|
||||
spec_cd: ast.ClassDef | t.CPtr = self._clone_classdef_for_spec(
|
||||
pool, template_cd, spec_name, tp_names, type_args)
|
||||
spec_cd: ast.ClassDef* = self._clone_classdef_for_spec(pool, template_cd, spec_name, tp_names, type_args)
|
||||
if spec_cd is None:
|
||||
self.GenericSpecDepth -= 1
|
||||
return None
|
||||
@@ -665,6 +713,18 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
# 避免模板方法体内的跨模块调用被误报"模块未导入"。
|
||||
saved_module_sha1: str = trans.ModuleSha1
|
||||
saved_imported: str = trans._imported_modules
|
||||
# 【窗口同进同出】类定义窗口(CurDefModuleSha1/CurDefClassName)必须与
|
||||
# ModuleSha1 一起保存/恢复:下方 translate_class_def(:729)内部会按
|
||||
# **模板模块 sha1 + 特化类名** 调 mark_module_class(ClassGenDef.vp:50),
|
||||
# 覆盖这两个窗口变量。原实现只恢复 trans.ModuleSha1 ⇒ 调用方文件在此之后
|
||||
# 解析任何裸类名时,规则 5.5 的归属判据(证据 ② is_module_class /
|
||||
# ③ CurDefClassName 逐字相同)全都在对着"模板模块 / 特化类"判 ⇒ 判不到
|
||||
# ⇒ 该实参以**裸名**形式被首次注册并永久复用,与同一特化在别处解析出的
|
||||
# 带 SHA1 形式分裂成两个名字,最终以"被指类型是非基本类型……不可隐式转换"
|
||||
# 报出(现场:includes/ast/base.vp:359 `_append_child(self.children, ...)`
|
||||
# 源 list[rawptr[AST]] vs 目标 list[rawptr<定义模块SHA1>.AST])。
|
||||
saved_def_mod: str = self.Gen.StructGen.CurDefModuleSha1
|
||||
saved_def_cls: str = self.Gen.StructGen.CurDefClassName
|
||||
template_sha1: str = self._find_generic_template_sha1(class_name)
|
||||
if template_sha1 is not None:
|
||||
trans.ModuleSha1 = template_sha1
|
||||
@@ -681,9 +741,11 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
if tpl_file_full is not None:
|
||||
self.Gen.TypeGenBase.pop_trace()
|
||||
self.Gen.TypeGenResolve.set_current_file(saved_cur_full)
|
||||
# 恢复原始 ModuleSha1 与 imports
|
||||
# 恢复原始 ModuleSha1 / imports / **类定义窗口**(窗口不平移,见上方说明)
|
||||
trans.ModuleSha1 = saved_module_sha1
|
||||
trans._imported_modules = saved_imported
|
||||
self.Gen.StructGen.CurDefModuleSha1 = saved_def_mod
|
||||
self.Gen.StructGen.CurDefClassName = saved_def_cls
|
||||
|
||||
# 8. 清除 type_map 上下文
|
||||
trans.GenericTypeParamNames = None
|
||||
@@ -693,12 +755,10 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
# 特化结果字段名完整性检查(fail-fast:字段名缺失 = 字段表损坏,
|
||||
# 静默继续会让后续 GEP 按错索引访问)
|
||||
if string.strcmp(class_name, "GSListNode") == 0:
|
||||
result_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name)
|
||||
result_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||||
if result_entry is not None:
|
||||
ri: int
|
||||
for ri in range(result_entry.FieldCount):
|
||||
rfe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||||
result_entry, ri)
|
||||
rfe: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(result_entry, ri)
|
||||
if rfe is not None:
|
||||
rfn: str = self.Gen.StructGen.get_field_name_ptr(rfe)
|
||||
if rfn is None:
|
||||
@@ -0,0 +1,9 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
from . import ClassGenBase
|
||||
|
||||
# ============================================================
|
||||
# ClassGenMixin - 类定义/继承/泛型/vtable/enum/union/renum
|
||||
# ============================================================
|
||||
novirtual class ClassGenMixin(ClassGenBase.ClassGenBase):
|
||||
"""类定义处理 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)"""
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,579 +0,0 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
import lib.core.Gen.ClassGenBase as ClassGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ClassGenDef - ClassGenMixin 拆分(阶段 D):translate_class_def 主入口
|
||||
#
|
||||
# 继承 ClassGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesClassDef 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
"""translate_class_def 主入口"""
|
||||
|
||||
# ============================================================
|
||||
# translate_class_def — 翻译 class 定义(簇 D)
|
||||
# ============================================================
|
||||
def translate_class_def(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 class 定义,返回 0"""
|
||||
if node is None or trans is None:
|
||||
return 0
|
||||
|
||||
cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(node)
|
||||
if cd is None or cd.name is None:
|
||||
return 0
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
class_name: str = cd.name
|
||||
|
||||
if trans.ModuleSha1 is None:
|
||||
# fail-fast:翻译类时模块 SHA1 缺失(命名空间隔离依赖它)——
|
||||
VLogger.error("翻译类时 ModuleSha1 缺失", "CLASS")
|
||||
self.Gen.TypeGenErr.fatal_error(cd, "翻译类时 ModuleSha1 缺失", "TypeError")
|
||||
|
||||
# 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前,
|
||||
# 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类)
|
||||
self.Gen.StructGen.add_visible_struct(pool, class_name)
|
||||
|
||||
# 枚举类:交给 HandlesEnum 处理
|
||||
if self.Gen.ClassGenBase._is_enum_class(cd, trans) == 1:
|
||||
return self.Gen.ClassGenEnum._translate_enum_def(trans, cd)
|
||||
|
||||
# 联合体类:交给联合体处理
|
||||
if self.Gen.ClassGenBase._is_union_class(cd, trans) == 1:
|
||||
return self.Gen.ClassGenEnum._translate_union_def(trans, cd)
|
||||
|
||||
# REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局)
|
||||
if self.Gen.ClassGenBase._is_renum_class(cd, trans) == 1:
|
||||
return self.Gen.ClassGenEnum._translate_renum_def(trans, cd)
|
||||
|
||||
# 泛型类:存储为模板,不发射 IR(等实例化时特化)
|
||||
# 用局部变量接收 cd.type_params,触发类型推断
|
||||
tp_val: list[str] | t.CPtr = cd.type_params
|
||||
if self.Gen.ClassGenGeneric._is_generic_class(tp_val) == 1:
|
||||
self.Gen.ClassGenGeneric._register_generic_template(pool, cd, trans.ModuleSha1)
|
||||
return 0
|
||||
|
||||
# 异常类(try-except):注册编码+继承树,不生成 struct
|
||||
# (对齐 TPC HandlesClassDef.py L509-511:_is_exception_class →
|
||||
# _RegisterExceptionClass → return,异常类不编译为结构体)
|
||||
if self.Gen.ClassGenBase._is_exception_class_def(cd) == 1:
|
||||
return self.Gen.ClassGenBase._register_exception_class_def(trans, cd)
|
||||
|
||||
# 检查是否已注册(用 SHA1 区分跨模块同名类)
|
||||
existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module(
|
||||
class_name, trans.ModuleSha1)
|
||||
if existing is not None:
|
||||
# BUG 5 方案1修改点2:existing 时字段完整性检查
|
||||
# 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整)
|
||||
# 注意:无字段类(接口/标记类,类体无 AnnAssign)合法(空 struct + 方法),
|
||||
# 仅当"类体声明了字段但 FieldCount==0"才算注册不完整(Phase A-pre 漏注册)。
|
||||
if existing.FieldCount == 0 and trans._declare_only == 0:
|
||||
if self.Gen.ClassGenBase._class_body_has_field(cd) != 0:
|
||||
# Phase B 时字段数为 0 说明注册不完整(Phase A-pre 可能漏注册)
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node,
|
||||
f"结构体已注册但字段数为0,类: {class_name},可能注册不完整",
|
||||
"InternalCompilerError")
|
||||
# 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法
|
||||
if existing.Ty is not None:
|
||||
# Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty,
|
||||
# 其 Name(如 "sha1.ClassName")指向 Phase 1a 的 pool 内存。虽然 mark1
|
||||
# 之前分配不被 reset 回收,但 struct_ty 会被后续文件翻译引用(vtable/
|
||||
# self 参数类型打印),部分实现下 pool 块被复用导致 Name 悬空崩溃。
|
||||
# 保险起见:深拷贝 Name 到 stdlib,确保跨文件永久存活。
|
||||
if trans._declare_only == 0:
|
||||
# 深拷贝整个 existing.Ty 到 stdlib:1a pool Ty 跨 1b reset 悬空,
|
||||
# _ensure_field_types_in_module 遍历悬空字段 ParamNode 链表
|
||||
# 读悬空挂起(G3 LinkedNode.prepend 挂起根因)。DeepCopyType
|
||||
# 递归深拷贝字段链表/子类型/Name 到 stdlib(深度上限+链守卫)。
|
||||
ty_deep: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), existing.Ty)
|
||||
if ty_deep is not None:
|
||||
existing.Ty = ty_deep
|
||||
old_name: str = llvmlite.get_struct_name(existing.Ty)
|
||||
if old_name is not None:
|
||||
on_len: t.CSizeT = string.strlen(old_name)
|
||||
on_copy: str = CompilerFactory.get_perm_pool().alloc(on_len + 1)
|
||||
if on_copy is not None:
|
||||
string.strcpy(on_copy, old_name)
|
||||
c.DerefAs(existing.Ty, llvmlite.LLVMType.Struct(
|
||||
llvmlite.get_struct_fields(existing.Ty),
|
||||
llvmlite.get_struct_fcount(existing.Ty),
|
||||
on_copy))
|
||||
# Phase B: 将已存在的命名结构体注册到当前模块(输出类型定义行)
|
||||
llvmlite.module_add_named_type(trans.Module, pool, existing.Ty)
|
||||
# Phase A-pre(declare_only=1)多遍扫描时,类已注册但不应翻译方法体
|
||||
# Phase B(declare_only=0)时全量翻译方法体
|
||||
if trans._declare_only == 1:
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, existing.Ty, class_name, 1)
|
||||
else:
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, existing.Ty, class_name)
|
||||
# SHA1 已在 register_struct 时设置,无需再补
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 触发 base 中 Subscript 的泛型特化(如 GSListNode[Value])
|
||||
# 必须在 _detect_vtable_status 和父类字段继承之前调用,
|
||||
# 否则 find_struct_by_module("GSListNode[Value]") 返回 None
|
||||
# ============================================================
|
||||
self.Gen.ClassGenBase._trigger_base_specialization(trans, cd)
|
||||
|
||||
# ============================================================
|
||||
# VTable 检测:判断是否启用虚表
|
||||
# ============================================================
|
||||
has_vtable: int = self.Gen.ClassGenBase._detect_vtable_status(cd, trans)
|
||||
parent_name: str = self.Gen.ClassGenBase._get_parent_class(cd, trans)
|
||||
# 多继承:收集所有真实父类名(跳过 marker base),供字段展平/vtable/MRO 使用
|
||||
parents_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.PARENT_MAX)
|
||||
parents_count: int = 0
|
||||
if parents_buf is not None:
|
||||
parents_count = self.Gen.ClassGenBase._collect_parents(pool, cd, parents_buf, GenTypes.PARENT_MAX, trans)
|
||||
is_novtable_deco: int = 0
|
||||
if cd.decorator_list is not None:
|
||||
if self.Gen.ClassGenBase._has_decorator(cd.decorator_list, "NoVTable") == 1:
|
||||
is_novtable_deco = 1
|
||||
|
||||
# ============================================================
|
||||
# PhaseA 预注册延迟检查:父类未注册时延迟注册当前类
|
||||
#
|
||||
# 根因:AssignHandle(HandlesBase.Mixin) 有自己的字段 _CurrentClass,
|
||||
# 当 Mixin 未注册时(字母序:HandlesAssign.py 在 HandlesBase.py 之前),
|
||||
# field_count=1(不是0),field_count==0 静默返回不触发,
|
||||
# AssignHandle 被注册为只有 _CurrentClass 字段(缺 Trans)。
|
||||
# 后续遍 existing is not None,不补字段 → attribute ptr is None: self.Trans
|
||||
#
|
||||
# 修复:declare_only==1 且父类未注册时,延迟注册到下一遍。
|
||||
# 多遍 PhaseA-pre 会在后续遍中重试(父类已注册后完整注册)。
|
||||
# Phase B(declare_only==0)不延迟,避免死锁。
|
||||
# ============================================================
|
||||
if trans._declare_only == 1 and parent_name is not None:
|
||||
parent_check: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module(
|
||||
parent_name, trans.ModuleSha1)
|
||||
if parent_check is None:
|
||||
parent_check = self.Gen.StructGen.find_struct(parent_name)
|
||||
if parent_check is None:
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 1. 遍历 class body,收集字段信息
|
||||
# ============================================================
|
||||
# 用 CSizeT 数组存储指针值(64 位系统上 8 字节)
|
||||
field_names_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_types_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_defaults_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
field_annot_buf: t.CSizeT | t.CPtr = pool.alloc(8 * GenTypes.FIELD_MAX)
|
||||
if field_names_buf is None or field_types_buf is None or field_defaults_buf is None:
|
||||
return 0
|
||||
if field_annot_buf is None:
|
||||
return 0
|
||||
string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_defaults_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
string.memset(field_annot_buf, 0, 8 * GenTypes.FIELD_MAX)
|
||||
|
||||
field_count: int = 0
|
||||
|
||||
# ============================================================
|
||||
# 1.5 继承父类字段(字段展平)
|
||||
# ============================================================
|
||||
#
|
||||
# 父类字段排在子类字段之前,结构体布局:
|
||||
# [vtable_ptr?, parent_field1, ..., child_field1, ...]
|
||||
# 跳过父类的 __vtable__ 字段(子类会有自己的 vtable 指针)
|
||||
# ============================================================
|
||||
# 多继承字段展平:遍历所有父类(声明顺序),字段名去重(先声明优先)
|
||||
if parents_count > 0 and parents_buf is not None:
|
||||
for pi in range(parents_count):
|
||||
pname_addr: t.CSizeT = parents_buf[pi]
|
||||
if pname_addr == 0:
|
||||
continue
|
||||
pname: str = (str | t.CPtr)(t.CVoid(pname_addr, t.CPtr))
|
||||
if pname is None:
|
||||
continue
|
||||
# 用 SHA1 感知查找父类,规避跨模块同名找错
|
||||
parent_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module(
|
||||
pname, trans.ModuleSha1)
|
||||
if parent_entry is None:
|
||||
# 父类可能定义在另一个模块(不同 SHA1,如 HandlesBase.Mixin),
|
||||
# find_struct_by_module 不回退全局查找,此处手动回退到 find_struct,
|
||||
# 否则子类无法继承父类字段 → field_count==0 → __sizeof__ 失败
|
||||
parent_entry = self.Gen.StructGen.find_struct(pname)
|
||||
if parent_entry is None:
|
||||
# 父类尚未注册(依赖模块未翻译:Phase A 按文件序,子类模块可能
|
||||
# 先于父类模块,如 Generator.vp G < TypeGenMixin.vp T)。此时
|
||||
# **不能**继续注册——StructTable 在 StdlibAlloc=1 时用 perm_pool
|
||||
# 分配(init_struct_table L136-140),残缺条目跨 pass 存活,
|
||||
# 后续 pass 的 existing 早退(L2995-3006)永远无法修复 → 子类
|
||||
# __init__ 写父类字段(self.TraceFrames)每遍永久失败。
|
||||
# 整类 defer(不注册)+ 标记 _deps_pending 下遍重译;模块级
|
||||
# 变量/函数参数解析失败静默降级 i32(handle_module_level_var
|
||||
# L422-426 / FuncGenMixin L482-483),不致命,本遍文件不写盘。
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
# [PHASEADBG] 临时诊断:父类未注册即 pending 的根因(用后移除)
|
||||
stdio.printf("[PHASEADBG] 父类未注册: class=%s parent=%s\n", class_name, pname)
|
||||
return 0
|
||||
pfc: int = parent_entry.FieldCount
|
||||
for pfi in range(pfc):
|
||||
pfe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||||
parent_entry, pfi)
|
||||
if pfe is None:
|
||||
continue
|
||||
pfn: str = self.Gen.StructGen.get_field_name_ptr(pfe)
|
||||
if pfn is None:
|
||||
continue
|
||||
# 跳过父类的 vtable 指针字段
|
||||
if string.strcmp(pfn, "__vtable__") == 0:
|
||||
continue
|
||||
# 多继承去重:字段名已存在跳过(先声明父类优先)
|
||||
if self.Gen.ClassGenBase._field_name_exists(field_names_buf, field_count, pfn) != 0:
|
||||
continue
|
||||
if field_count < GenTypes.FIELD_MAX:
|
||||
pft: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_field_type_ptr(pfe)
|
||||
pfd: ast.AST | t.CPtr = self.Gen.StructGen.get_field_default_ptr(pfe)
|
||||
pfa: str = self.Gen.StructGen.get_field_annot_class_name(pfe)
|
||||
field_names_buf[field_count] = t.CSizeT(pfn)
|
||||
field_types_buf[field_count] = t.CSizeT(pft)
|
||||
if pfd is not None:
|
||||
field_defaults_buf[field_count] = t.CSizeT(pfd)
|
||||
else:
|
||||
field_defaults_buf[field_count] = 0
|
||||
if pfa is not None:
|
||||
stored_val: t.CSizeT = t.CSizeT(pfa)
|
||||
field_annot_buf[field_count] = stored_val
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
field_count += 1
|
||||
|
||||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
if children is None:
|
||||
return 0
|
||||
|
||||
cn: t.CSizeT = len(children)
|
||||
for ci in range(cn):
|
||||
stmt: ast.AST | t.CPtr = children.get(ci)
|
||||
if stmt is None:
|
||||
continue
|
||||
sk: int = stmt.kind()
|
||||
|
||||
if sk != ast.ASTKind.AnnAssign: continue
|
||||
|
||||
# AnnAssign(target=Name(id), annotation=type, value=...)
|
||||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt)
|
||||
if aa is None or aa.target is None:
|
||||
continue
|
||||
|
||||
# 获取字段名
|
||||
if aa.target.kind() != ast.ASTKind.Name:
|
||||
continue
|
||||
tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
|
||||
if tgt.id is None:
|
||||
continue
|
||||
|
||||
# 类体 CDefine 常量(任意位置,2026-08-10):注册到全局 CDefine 表。
|
||||
# 方法内裸名(如 ISINSTANCE_CLASS_MAX)经 translate_name_value 查
|
||||
# CDefine 表解析为常量值;类体开头的常量(MRO_MAX 等)由早期预注册
|
||||
# 路径注册,但方法之后的 AnnAssign 不经过那些路径 → 此处统一兜底注册。
|
||||
if self.Gen.AssignGen.is_cdefine_annotation(aa.annotation) != 0:
|
||||
if aa.value is not None:
|
||||
self.Gen.AssignGen._register_cdefine_from_value(pool, tgt.id, aa.value)
|
||||
# CDefine 字段类型固定 i32,直接收集后跳过通用注解解析:
|
||||
# resolve_annotation_type 不识别 "CDefine"(map_t_type/CTypedef
|
||||
# 表均无此名),类体尾部常量(ISINSTANCE_CLASS_MAX 是首个触发
|
||||
# 该路径的实例)Phase B 会 NameError: 't.CDefine' is not defined。
|
||||
# 与类头常量(MRO_MAX 等)的 i32 字段语义保持一致。
|
||||
if field_count < GenTypes.FIELD_MAX:
|
||||
cdef_ty_l: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if cdef_ty_l is not None:
|
||||
field_names_buf[field_count] = t.CSizeT(tgt.id)
|
||||
field_types_buf[field_count] = t.CSizeT(cdef_ty_l)
|
||||
if aa.value is not None:
|
||||
field_defaults_buf[field_count] = t.CSizeT(aa.value)
|
||||
else:
|
||||
field_defaults_buf[field_count] = 0
|
||||
field_count += 1
|
||||
continue
|
||||
|
||||
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
|
||||
# 这些字段只用于 with 上下文的静态可达性检查,不生成运行时代码
|
||||
# (FakeDuck:_str.__requires__=['__mbuddy__'])。此处解析 list[str]
|
||||
# 字面量注册到持久元数据表,供 requires 注入 / with provider 查询。
|
||||
if string.strcmp(tgt.id, "__provides__") == 0:
|
||||
self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_PROVIDES, class_name, aa.value)
|
||||
continue
|
||||
if string.strcmp(tgt.id, "__requires__") == 0:
|
||||
self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_REQUIRES, class_name, aa.value)
|
||||
continue
|
||||
if string.strcmp(tgt.id, "__require_must__") == 0:
|
||||
self.Gen.ClassGenBase._register_class_meta_list(pool, GenTypes.CLASS_META_REQUIRE_MUST, class_name, aa.value)
|
||||
continue
|
||||
|
||||
# 解析字段类型
|
||||
field_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||||
# 单参 t.CArray[elem] + 列表字面量 → 静态数组 [N x elem]
|
||||
# (与局部 AnnAssign 路径一致,对齐 TPC ParseListAnnotation 语义):
|
||||
# 否则字段保持 Ptr(elem)(如 t.CArray[str] → i8**),
|
||||
# for x in self.field 会误走指针迭代(元素非整数 → null 终止符
|
||||
# 检查失败报错)。推断为静态数组后走数组迭代(按长度 N)。
|
||||
if field_ty is not None:
|
||||
field_ty = self.Gen.AssignGen._infer_static_array_ty_from_literal(
|
||||
pool, aa.annotation, aa.value, field_ty)
|
||||
if field_ty is None:
|
||||
# BUG 5 方案1修改点1:消除 i32 静默回退
|
||||
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,延迟到下一遍
|
||||
# Phase B(declare_only=0):真正的类型解析错误,fast-fail 终止该类翻译
|
||||
# 不再用 i32 回退(会导致结构体布局错误 + GEP 索引错乱)
|
||||
# 例外:泛型 Subscript(如 list[AST|t.CPtr])未特化时回退为 Ptr(i8),
|
||||
# 因为泛型特化可能延迟到构造调用时。AnnotClassName 会携带 mangled name
|
||||
# 供 translate_attribute 做后续 bitcast。
|
||||
is_generic_sub: int = 0
|
||||
if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Subscript:
|
||||
is_generic_sub = 1
|
||||
if is_generic_sub != 0:
|
||||
# 泛型未特化:回退为 Ptr(i8),依赖 AnnotClassName 做后续类型恢复
|
||||
field_ty = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
else:
|
||||
# Phase A-pre(declare_only=1):依赖的类可能尚未注册,
|
||||
# 静默 return 0 让多遍收敛机制生效(下一遍依赖类已注册即可成功)
|
||||
if trans._declare_only == 1:
|
||||
return 0
|
||||
# Phase A(declare_only=0,Phase2.vp L573 多遍):依赖模块按
|
||||
# 文件序可能晚于本模块翻译(如 TypeGenMixin.vp G < HandlesType.vp
|
||||
# H,TraceFrames 注解的 HandlesType.TraceFrame 未注册)→ 标记
|
||||
# _deps_pending 下遍重译,不在本遍以残缺字段注册结构体。
|
||||
# 真正的类型错误由 Phase A 收敛检查暴露("Phase A 无法完成
|
||||
# 翻译: <file>,请检查依赖模块是否已编译/注册"),不静默掩盖。
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
# [PHASEADBG] 临时诊断:字段注解类型未解析即 pending 的根因(用后移除)
|
||||
dbg_ak: t.CInt = -1
|
||||
if aa.annotation is not None:
|
||||
dbg_ak = aa.annotation.kind()
|
||||
stdio.printf("[PHASEADBG] 字段类型未解析: class=%s field=%s annot_kind=%d\n",
|
||||
class_name, tgt.id, dbg_ak)
|
||||
return 0
|
||||
# 旧行为:fast-fail NameError(已移除——Phase A 依赖未就绪时
|
||||
# 误报真实错误,中断多遍收敛;真实错误交给收敛检查兜底)
|
||||
|
||||
# 存储到数组(指针转 CSizeT)
|
||||
if field_count < GenTypes.FIELD_MAX:
|
||||
diag_name_val: t.CSizeT = t.CSizeT(tgt.id)
|
||||
field_names_buf[field_count] = diag_name_val
|
||||
field_types_buf[field_count] = t.CSizeT(field_ty)
|
||||
# 存储默认值 AST 指针(None=无默认值)
|
||||
if aa.value is not None:
|
||||
field_defaults_buf[field_count] = t.CSizeT(aa.value)
|
||||
else:
|
||||
field_defaults_buf[field_count] = 0
|
||||
# 提取原始类型注解的类名(联合类型简化为 Ptr(i8) 时回退查找结构体)
|
||||
# BUG 1 方案3:传 pool 使泛型 Subscript 返回 mangled name(如 "list[ast.AST|t.CPtr]")
|
||||
if aa.annotation is not None:
|
||||
annot_cn: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(
|
||||
aa.annotation, trans._imported_modules, pool, trans._from_imports)
|
||||
if annot_cn is not None:
|
||||
diag_cn_val: t.CSizeT = t.CSizeT(annot_cn)
|
||||
field_annot_buf[field_count] = diag_cn_val
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
else:
|
||||
field_annot_buf[field_count] = 0
|
||||
field_count += 1
|
||||
|
||||
if field_count == 0:
|
||||
# PhaseA 预注册时,父类可能尚未注册(字母序单遍扫描),
|
||||
# 导致子类无法继承父类字段 → field_count==0。
|
||||
# 静默返回,Phase2.py 的多遍 PhaseA-pre 会在后续遍中重试。
|
||||
if trans._declare_only == 1 and parent_name is not None:
|
||||
return 0
|
||||
# 无字段类(接口/标记类):不能整体跳过——类可能只有方法
|
||||
# (如多继承中的 ShapeM/Vec2Extra),需注册类并翻译方法。
|
||||
# 空 struct 在 LLVM 中合法({});@t.CVTable 类由下方补 vtable 指针字段。
|
||||
|
||||
# ============================================================
|
||||
# 2. 创建 LLVM StructType
|
||||
# ============================================================
|
||||
# 构建 ParamNode 链表
|
||||
first_node: llvmlite.ParamNode | t.CPtr = None
|
||||
prev_node: llvmlite.ParamNode | t.CPtr = None
|
||||
total_field_count: int = field_count
|
||||
|
||||
# 如果有虚表,首字段添加 i8* vtable 指针
|
||||
if has_vtable == 1:
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
vtable_node: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__())
|
||||
if vtable_node is None:
|
||||
fb_vn: str = VLogger.fmt_buf()
|
||||
if fb_vn is not None:
|
||||
viperlib.snprintf(fb_vn, 1024, "failed to alloc vtable node for %s", class_name)
|
||||
VLogger.error(fb_vn, "CLASS")
|
||||
return 0
|
||||
string.memset(vtable_node, 0, llvmlite.ParamNode.__sizeof__())
|
||||
vtable_node.Ty = i8_ptr_ty
|
||||
first_node = vtable_node
|
||||
prev_node = vtable_node
|
||||
total_field_count = field_count + 1
|
||||
|
||||
for fi in range(field_count):
|
||||
fty_addr: t.CSizeT = field_types_buf[fi]
|
||||
if fty_addr == 0:
|
||||
continue
|
||||
fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr, t.CPtr))
|
||||
|
||||
# 创建 ParamNode
|
||||
pnode: llvmlite.ParamNode | t.CPtr = pool.alloc(llvmlite.ParamNode.__sizeof__())
|
||||
if pnode is None:
|
||||
continue
|
||||
string.memset(pnode, 0, llvmlite.ParamNode.__sizeof__())
|
||||
pnode.Ty = fty
|
||||
|
||||
if first_node is None:
|
||||
first_node = pnode
|
||||
if prev_node is not None:
|
||||
prev_node.Next = pnode
|
||||
prev_node = pnode
|
||||
|
||||
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
|
||||
# 注意: Phase 1b(declare_only=0)时 struct_ty 会注册到全局表并被后续
|
||||
# 文件翻译引用(vtable/self 参数类型打印),其 Name 必须跨 1b 每文件
|
||||
# reset_to(mark1) 存活 → 用 stdlib 深拷贝;Phase 1a 仍用 pool(无需跨文件)。
|
||||
type_name: str = class_name
|
||||
if trans.ModuleSha1 is not None:
|
||||
name_buf: str = pool.alloc(64)
|
||||
if name_buf is not None:
|
||||
viperlib.snprintf(name_buf, 64, "%s.%s", trans.ModuleSha1, class_name)
|
||||
type_name = name_buf
|
||||
if trans._declare_only == 0 and type_name is not None:
|
||||
tn_len: t.CSizeT = string.strlen(type_name)
|
||||
tn_copy: str = CompilerFactory.get_perm_pool().alloc(tn_len + 1)
|
||||
if tn_copy is not None:
|
||||
string.strcpy(tn_copy, type_name)
|
||||
type_name = tn_copy
|
||||
|
||||
# 创建 StructType(命名结构体)
|
||||
struct_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, first_node, total_field_count, type_name)
|
||||
if struct_ty is None:
|
||||
fb_st: str = VLogger.fmt_buf()
|
||||
if fb_st is not None:
|
||||
viperlib.snprintf(fb_st, 1024, "failed to create StructType for %s", class_name)
|
||||
VLogger.error(fb_st, "CLASS")
|
||||
return 0
|
||||
|
||||
# Phase 1b(declare_only=0)新注册的 struct_ty 会被注册到全局表并被后续文件
|
||||
# 翻译引用(vtable/self 参数类型打印/find_struct_by_type 指针匹配)。LLVMType
|
||||
# 对象和 Fields 链是 pool 分配的,本文件 reset_to(mark1) 后悬空。深拷贝整棵树
|
||||
# 到 stdlib,并替换 struct_ty 指针,保证 entry.Ty 与调用方持有的 struct_ty
|
||||
# 指向同一个 stdlib 拷贝(指针匹配不失效)且跨文件永久存活。
|
||||
# StdlibAlloc=1(Phase2 mark2 后)也必须深拷贝:Phase A-pre-inc(declare_only=1)
|
||||
# 预注册 includes 时若仍用 pool struct_ty,reset_to(mark2) 后 entry.Ty 悬空 →
|
||||
# 后续文件字段类型引用(resolve → Ptr(entry.Ty))→ opaque 扫描遍历悬空 fields
|
||||
# 崩溃(LoopTest _scan_type_for_cross_module_refs 0xFFFF 根因)。
|
||||
if trans._declare_only == 0 or self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||||
st_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), struct_ty)
|
||||
if st_copy is not None:
|
||||
struct_ty = st_copy
|
||||
type_name = llvmlite.get_struct_name(struct_ty)
|
||||
|
||||
# 注册命名结构体到模块(输出 %"name" = type { ... } 定义行)
|
||||
llvmlite.module_add_named_type(trans.Module, pool, struct_ty)
|
||||
|
||||
# 扫描字段类型,为跨模块结构体引用添加 opaque 声明
|
||||
# 例如 list[int].__pool__ 引用 memhub.MemManager,需要在当前模块添加 %"sha1.MemManager" = type opaque
|
||||
for fi in range(field_count):
|
||||
fty_addr_op: t.CSizeT = field_types_buf[fi]
|
||||
if fty_addr_op == 0:
|
||||
continue
|
||||
fty_op: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr_op, t.CPtr))
|
||||
llvmlite.module_ensure_opaque_for_type(trans.Module, pool, fty_op)
|
||||
|
||||
# ============================================================
|
||||
# 3. 注册到 HandlesStruct
|
||||
# ============================================================
|
||||
entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.register_struct(
|
||||
pool, class_name, struct_ty, trans.ModuleSha1)
|
||||
if entry is None:
|
||||
fb_re: str = VLogger.fmt_buf()
|
||||
if fb_re is not None:
|
||||
viperlib.snprintf(fb_re, 1024, "failed to register %s", class_name)
|
||||
VLogger.error(fb_re, "CLASS")
|
||||
return 0
|
||||
|
||||
# 标记 VTable 状态(直接用 entry,规避跨模块同名 find_struct 找错)
|
||||
if has_vtable == 1:
|
||||
entry.HasVTable = 1
|
||||
if is_novtable_deco == 1:
|
||||
entry.IsNoVTable = 1
|
||||
if parent_name is not None:
|
||||
# 1b 阶段父类名是 pool 字符串(本文件 AST/1a 预存),reset 后悬空;
|
||||
# _translate_oop_methods/_detect_vtable_status 会在后续文件
|
||||
# find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活
|
||||
if self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||||
pn_len: t.CSizeT = string.strlen(parent_name)
|
||||
pn_buf: str = CompilerFactory.get_perm_pool().alloc(pn_len + 1)
|
||||
if pn_buf is not None:
|
||||
string.strcpy(pn_buf, parent_name)
|
||||
entry.ParentName = pn_buf
|
||||
else:
|
||||
entry.ParentName = parent_name
|
||||
# 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活)
|
||||
if parents_count > 0 and parents_buf is not None:
|
||||
self.Gen.StructGen.set_parent_names(pool, class_name, parents_buf, parents_count)
|
||||
|
||||
# 添加字段信息
|
||||
# 如果有虚表,先添加 __vtable__ 字段占位(索引 0),用户字段从索引 1 开始
|
||||
if has_vtable == 1:
|
||||
i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
self.Gen.StructGen.add_field(pool, entry, "__vtable__", i8_ptr_ty2, None, None)
|
||||
|
||||
for fi in range(field_count):
|
||||
fname_addr: t.CSizeT = field_names_buf[fi]
|
||||
if fname_addr == 0:
|
||||
continue
|
||||
fname: str = (str | t.CPtr)(t.CVoid(fname_addr, t.CPtr))
|
||||
fty_addr2: t.CSizeT = field_types_buf[fi]
|
||||
if fty_addr2 == 0:
|
||||
continue
|
||||
fty2: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(t.CVoid(fty_addr2, t.CPtr))
|
||||
# 恢复默认值 AST 指针
|
||||
fdef_addr: t.CSizeT = field_defaults_buf[fi]
|
||||
fdef: ast.AST | t.CPtr = None
|
||||
if fdef_addr != 0:
|
||||
fdef = (ast.AST | t.CPtr)(t.CVoid(fdef_addr, t.CPtr))
|
||||
# 恢复注解类名指针
|
||||
fannot_addr: t.CSizeT = field_annot_buf[fi]
|
||||
fannot: str = None
|
||||
if fannot_addr != 0:
|
||||
fannot = (str)(t.CVoid(fannot_addr, t.CPtr))
|
||||
if fname is not None and fty2 is not None:
|
||||
self.Gen.StructGen.add_field(pool, entry, fname, fty2, fdef, fannot)
|
||||
|
||||
# Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体
|
||||
if trans._declare_only == 1:
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name, 1)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 4. OOP 方法处理:扫描 FunctionDef,标记 OOP,翻译方法,生成 __before_init__
|
||||
# ============================================================
|
||||
self.Gen.ClassGenVTable._translate_oop_methods(trans, cd, struct_ty, class_name)
|
||||
|
||||
return 0
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,25 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.ClassGenBase as ClassGenBase
|
||||
|
||||
# ============================================================
|
||||
# ClassGenMixin - 类定义/继承/泛型/vtable/enum/union/renum
|
||||
#
|
||||
# 500~1500 行/文件架构重构阶段 D:全部方法已拆至
|
||||
# ClassGenBase/Enum/Generic/VTable/Def,本文件保留类声明。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ClassGenMixin(ClassGenBase.ClassGenBase):
|
||||
"""类定义处理 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)"""
|
||||
@@ -0,0 +1,471 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
import w32.win32file as w32file
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
# ============================================================
|
||||
# DebugInfoGen - function-level DWARF metadata emitter (llvmlite text IR)
|
||||
#
|
||||
# Node layout mirrors TPC lib/core/LLVMCG/DebugInfo.py node-for-node:
|
||||
# !DIFile -> !{ null } -> !DISubroutineType -> distinct !DICompileUnit
|
||||
# -> distinct !DISubprogram (per define) -> !DILocation (per statement)
|
||||
# module tail: !llvm.dbg.cu + !llvm.module.flags (Debug Info Version 3)
|
||||
#
|
||||
# Enabled only while --traceback is on: the Phase layer mirrors
|
||||
# BuildPipeline._traceback_mode here via SetEnabled(). While disabled every
|
||||
# entry point returns before touching any llvmlite DI API, so the emitted IR
|
||||
# stays byte-identical to the pre-DWARF output.
|
||||
#
|
||||
# Scope/statement hooks are driven from the Gen layer:
|
||||
# Translator.translate -> BeginModule / Finalize
|
||||
# FuncGenDef.translate_function_def / ClassGenVTable._translate_method /
|
||||
# FuncGenMixin (nested + lambda) -> PushFunction / PopFunction
|
||||
# StmtGenMixin.translate_stmt -> SetStatement
|
||||
# ============================================================
|
||||
|
||||
# ---- module-scope state (reset per module by BeginModule) ----
|
||||
_g_enabled: int = 0
|
||||
_g_finalized: int = 0
|
||||
_g_mod: llvmlite.LLVMModule* = None
|
||||
_g_file_path: str = None
|
||||
_g_file_id: int = -1
|
||||
_g_null_id: int = -1
|
||||
_g_subtype_id: int = -1
|
||||
_g_cu_id: int = -1
|
||||
_g_cur_sp: int = -1
|
||||
_g_cur_entry_ref: str = None
|
||||
_g_cur_builder: llvmlite.IRBuilder* = None
|
||||
_g_depth: int = 0
|
||||
|
||||
# Push/Pop save stack: enclosing (sp id + 1, entry DILocation ref, builder)
|
||||
# per level. +1 so 0 means "no enclosing function" (sp ids are >= 0). The saved
|
||||
# builder is what makes SetStatement reject a builder that is not the one the
|
||||
# current DISubprogram was pushed on (e.g. an async state machine emitted inside
|
||||
# a bracketed function): such instructions must carry no !dbg, otherwise LLVM's
|
||||
# verifier rejects "!dbg attachment points at wrong subprogram for function".
|
||||
DBG_STACK_MAX: t.CDefine = 256
|
||||
_g_stk_sp: sizet* = None
|
||||
_g_stk_ref: str = None
|
||||
_g_stk_bld: str = None
|
||||
|
||||
# DILocation cache: direct-mapped, up to 8-way linear probe, key (sp, line, col).
|
||||
DBG_LOC_SLOTS: t.CDefine = 8192
|
||||
DBG_LOC_PROBE: t.CDefine = 8
|
||||
DBG_LOC_KEY_STRIDE: t.CDefine = 3
|
||||
_g_loc_key: sizet* = None
|
||||
_g_loc_ref: str = None
|
||||
_g_loc_used: bytes = None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SetEnabled / IsEnabled - mirror the --traceback switch
|
||||
# ============================================================
|
||||
def SetEnabled(flag: bool) -> int:
|
||||
"""Enable/disable DI emission (mirrors BuildPipeline._traceback_mode)."""
|
||||
global _g_enabled
|
||||
if flag:
|
||||
_g_enabled = 1
|
||||
else:
|
||||
_g_enabled = 0
|
||||
return 0
|
||||
|
||||
|
||||
def IsEnabled() -> int:
|
||||
return _g_enabled
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _EnsureStorage - lazily allocate the long-lived stack / cache buffers
|
||||
# ============================================================
|
||||
def _EnsureStorage() -> int:
|
||||
global _g_stk_sp, _g_stk_ref, _g_stk_bld, _g_loc_key, _g_loc_ref, _g_loc_used
|
||||
if _g_stk_sp is not None:
|
||||
return 0
|
||||
sbuf1: bytes = stdlib.malloc(DBG_STACK_MAX * 8)
|
||||
sbuf2: bytes = stdlib.malloc(DBG_STACK_MAX * 8)
|
||||
sbuf3: bytes = stdlib.malloc(DBG_STACK_MAX * 8)
|
||||
kbuf: bytes = stdlib.malloc(DBG_LOC_SLOTS * DBG_LOC_KEY_STRIDE * 8)
|
||||
rbuf: bytes = stdlib.malloc(DBG_LOC_SLOTS * 8)
|
||||
ubuf: bytes = stdlib.malloc(DBG_LOC_SLOTS)
|
||||
if sbuf1 is None or sbuf2 is None or sbuf3 is None or kbuf is None or rbuf is None or ubuf is None:
|
||||
VLogger.error("--traceback: DWARF 元数据缓冲分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
string.memset(sbuf1, 0, DBG_STACK_MAX * 8)
|
||||
string.memset(sbuf2, 0, DBG_STACK_MAX * 8)
|
||||
string.memset(sbuf3, 0, DBG_STACK_MAX * 8)
|
||||
string.memset(kbuf, 0, DBG_LOC_SLOTS * DBG_LOC_KEY_STRIDE * 8)
|
||||
string.memset(rbuf, 0, DBG_LOC_SLOTS * 8)
|
||||
string.memset(ubuf, 0, DBG_LOC_SLOTS)
|
||||
_g_stk_sp = (sizet*)(sbuf1)
|
||||
_g_stk_ref = sbuf2
|
||||
_g_stk_bld = sbuf3
|
||||
_g_loc_key = (sizet*)(kbuf)
|
||||
_g_loc_ref = rbuf
|
||||
_g_loc_used = ubuf
|
||||
return 0
|
||||
|
||||
|
||||
def _RefOf(pool: memhub.MemBuddy*, node_id: int) -> str:
|
||||
"""Allocate a persistent "!N" reference string for a DI node id."""
|
||||
buf: str = pool.alloc(24)
|
||||
if buf is None:
|
||||
return None
|
||||
viperlib.snprintf(buf, 24, "!%d", node_id)
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# BeginModule - start of one module translation
|
||||
# ============================================================
|
||||
def BeginModule(mod: llvmlite.LLVMModule*, file_path: str) -> int:
|
||||
"""Reset per-module DI state. Call once at the start of each module."""
|
||||
global _g_mod, _g_file_path, _g_finalized, _g_file_id, _g_null_id
|
||||
global _g_subtype_id, _g_cu_id, _g_cur_sp, _g_cur_entry_ref, _g_cur_builder, _g_depth
|
||||
if _g_enabled == 0:
|
||||
return 0
|
||||
if _EnsureStorage() != 0:
|
||||
return 1
|
||||
_g_mod = mod
|
||||
_g_file_path = file_path
|
||||
_g_finalized = 0
|
||||
_g_file_id = -1
|
||||
_g_null_id = -1
|
||||
_g_subtype_id = -1
|
||||
_g_cu_id = -1
|
||||
_g_cur_sp = -1
|
||||
_g_cur_entry_ref = None
|
||||
_g_cur_builder = None
|
||||
_g_depth = 0
|
||||
if _g_loc_used is not None:
|
||||
string.memset(_g_loc_used, 0, DBG_LOC_SLOTS)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _EnsureModuleNodes - DIFile / !{ null } / DISubroutineType / DICompileUnit
|
||||
# (created lazily at the first define, once per module)
|
||||
# ============================================================
|
||||
def _EnsureModuleNodes(pool: memhub.MemBuddy*) -> int:
|
||||
global _g_file_id, _g_null_id, _g_subtype_id, _g_cu_id
|
||||
if _g_cu_id >= 0:
|
||||
return 0
|
||||
mod: llvmlite.LLVMModule* = _g_mod
|
||||
if mod is None:
|
||||
return 1
|
||||
# DIFile: **绝对**路径(正斜杠),filename 保留整条路径。
|
||||
# 为什么必须绝对:本工程给 CurrentFile 的是**项目相对**路径(如
|
||||
# "./Test/LLvmLiteTest/App/main.vp"),LLVM 会把该目录写成 CU 的 DW_AT_comp_dir,
|
||||
# 而主文件条目用 `dir_index: 0` 指向 comp_dir;stackmap 写入端只解析
|
||||
# `llvm-dwarfdump --debug-line`(其中**没有** comp_dir)⇒ 行记录只能退化成裸文件名
|
||||
# "main.vp":运行期既显示不全,也无法按路径重读源码行(实证:曾整段栈都打印
|
||||
# `File "main.vp", line N` 而无源码行)。
|
||||
# 绝对化后,无论 LLVM 保留整条 name(写入端 `_tb_is_abs_path` 命中 ⇒ 原样采用)
|
||||
# 还是把它拆成 dir+basename(dir_index 指向同一个绝对目录 ⇒ 拼回绝对路径),
|
||||
# 结果都是绝对路径 —— 故本改动不需要动写入端。
|
||||
src: str = _g_file_path
|
||||
if src is None:
|
||||
src = ""
|
||||
slen: sizet = string.strlen(src)
|
||||
cap_n: sizet = slen + 4112
|
||||
nbuf: str = pool.alloc(cap_n)
|
||||
if nbuf is None:
|
||||
VLogger.error("--traceback: DIFile 路径缓冲分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
if slen > 0:
|
||||
string.strncpy(nbuf, src, slen)
|
||||
nbuf[slen] = '\0'
|
||||
if slen > 0 and nbuf[0] != '/' and not (slen >= 2 and nbuf[1] == ':'):
|
||||
# 相对路径 → 前置当前工作目录。用 w32file 低层调用(同 Repl.vp),
|
||||
# 不经 os._mbuddy:编译器进程未必初始化过那个内存管理器。
|
||||
CwdBuf: bytes = pool.alloc(4112)
|
||||
if CwdBuf is not None:
|
||||
CwdBuf[0] = '\0'
|
||||
nc: ULONG = w32file.GetCurrentDirectoryA(ULONG(4111), CwdBuf)
|
||||
if nc > 0:
|
||||
# 防御:缓冲区不足时 GetCurrentDirectoryA 的写入内容未定义,强制补 NUL
|
||||
CwdBuf[4110] = '\0'
|
||||
viperlib.snprintf(nbuf, cap_n, "%s/%s", CwdBuf, src)
|
||||
# 归一所有反斜杠(CWD 段同样可能含 '\')
|
||||
flen: sizet = string.strlen(nbuf)
|
||||
ni: sizet = 0
|
||||
for ni in range(flen):
|
||||
if nbuf[ni] == '\\':
|
||||
nbuf[ni] = '/'
|
||||
# filename 取整条路径;directory 另存其目录前缀(两段各自 NUL 结尾,互不污染)
|
||||
fname: str = nbuf
|
||||
directory: str = ""
|
||||
slash: str = string.strrchr(nbuf, '/')
|
||||
if slash is not None:
|
||||
dlen: sizet = string.strlen(nbuf) - string.strlen(slash + 1) - 1
|
||||
dirbuf: str = pool.alloc(dlen + 1)
|
||||
if dirbuf is not None:
|
||||
string.strncpy(dirbuf, nbuf, dlen)
|
||||
dirbuf[dlen] = '\0'
|
||||
directory = dirbuf
|
||||
dsize: sizet = string.strlen(fname) + string.strlen(directory) + 96
|
||||
dbuf: str = pool.alloc(dsize)
|
||||
if dbuf is None:
|
||||
VLogger.error("--traceback: DIFile 节点缓冲分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
viperlib.snprintf(dbuf, dsize, "!DIFile(filename: \"%s\", directory: \"%s\")", fname, directory)
|
||||
fid: int = llvmlite.module_add_di_node(mod, pool, dbuf)
|
||||
if fid < 0:
|
||||
VLogger.error("--traceback: DIFile 元数据节点分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
_g_file_id = fid
|
||||
# types: !{ null } placeholder list, then DISubroutineType referencing it
|
||||
nid: int = llvmlite.module_add_di_node(mod, pool, "!{ null }")
|
||||
if nid < 0:
|
||||
VLogger.error("--traceback: DISubroutineType 类型表分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
_g_null_id = nid
|
||||
tbuf: str = pool.alloc(64)
|
||||
if tbuf is None:
|
||||
VLogger.error("--traceback: DISubroutineType 缓冲分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
viperlib.snprintf(tbuf, 64, "!DISubroutineType(types: !%d)", _g_null_id)
|
||||
tid: int = llvmlite.module_add_di_node(mod, pool, tbuf)
|
||||
if tid < 0:
|
||||
VLogger.error("--traceback: DISubroutineType 元数据节点分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
_g_subtype_id = tid
|
||||
cbuf: str = pool.alloc(256)
|
||||
if cbuf is None:
|
||||
VLogger.error("--traceback: DICompileUnit 缓冲分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
viperlib.snprintf(cbuf, 256,
|
||||
"distinct !DICompileUnit(language: DW_LANG_C99, file: !%d, producer: \"TPC\", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)",
|
||||
_g_file_id)
|
||||
cid: int = llvmlite.module_add_di_node(mod, pool, cbuf)
|
||||
if cid < 0:
|
||||
VLogger.error("--traceback: DICompileUnit 元数据节点分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
_g_cu_id = cid
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _LocRefAt - read a cached DILocation ref string pointer
|
||||
# ============================================================
|
||||
def _LocRefAt(slot: int) -> str:
|
||||
slotp: str | t.CPtr = (str | t.CPtr)(uint64(_g_loc_ref) + sizet(slot) * 8)
|
||||
r: str = slotp[0]
|
||||
return r
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _EnsureLocation - DILocation ref for (sp, line, col), created + cached once
|
||||
# ============================================================
|
||||
def _EnsureLocation(pool: memhub.MemBuddy*, sp: int, line: int, col: int) -> str:
|
||||
if line <= 0:
|
||||
return _g_cur_entry_ref
|
||||
c: int = col
|
||||
if c <= 0:
|
||||
c = 1
|
||||
if _g_loc_used is None or _g_mod is None:
|
||||
return None
|
||||
h: uint64 = (uint64(sp) * 1000003 + uint64(line) * 31 + uint64(c)) & uint64(DBG_LOC_SLOTS - 1)
|
||||
pi: int = 0
|
||||
while pi < DBG_LOC_PROBE:
|
||||
slot: int = int((h + uint64(pi)) & uint64(DBG_LOC_SLOTS - 1))
|
||||
if _g_loc_used[slot] == 0:
|
||||
break
|
||||
kbase: int = slot * DBG_LOC_KEY_STRIDE
|
||||
if int(_g_loc_key[kbase]) == sp and int(_g_loc_key[kbase + 1]) == line \
|
||||
and int(_g_loc_key[kbase + 2]) == c:
|
||||
return _LocRefAt(slot)
|
||||
pi += 1
|
||||
lbuf: str = pool.alloc(96)
|
||||
if lbuf is None:
|
||||
return None
|
||||
viperlib.snprintf(lbuf, 96, "!DILocation(line: %d, column: %d, scope: !%d)", line, c, sp)
|
||||
lid: int = llvmlite.module_add_di_node(_g_mod, pool, lbuf)
|
||||
if lid < 0:
|
||||
VLogger.error("--traceback: DILocation 元数据节点分配失败,终止编译", "DWARF")
|
||||
return None
|
||||
lref: str = _RefOf(pool, lid)
|
||||
if lref is None:
|
||||
VLogger.error("--traceback: DILocation 引用缓冲分配失败,终止编译", "DWARF")
|
||||
return None
|
||||
if pi < DBG_LOC_PROBE:
|
||||
slot2: int = int((h + uint64(pi)) & uint64(DBG_LOC_SLOTS - 1))
|
||||
kbase2: int = slot2 * DBG_LOC_KEY_STRIDE
|
||||
_g_loc_key[kbase2] = sizet(sp)
|
||||
_g_loc_key[kbase2 + 1] = sizet(line)
|
||||
_g_loc_key[kbase2 + 2] = sizet(c)
|
||||
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_loc_ref) + sizet(slot2) * 8)
|
||||
rslot[0] = lref
|
||||
_g_loc_used[slot2] = 1
|
||||
return lref
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PushFunction - create the DISubprogram for one define
|
||||
# ============================================================
|
||||
def PushFunction(pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*,
|
||||
func: llvmlite.Function*, line: int, col: int) -> int:
|
||||
"""Attach a DISubprogram to one define and set the builder's entry DILocation.
|
||||
|
||||
Returns 1 when pushed (caller must call PopFunction), 0 when DI is disabled
|
||||
or not applicable. Every instruction emitted afterwards on `builder` carries
|
||||
", !dbg !N" until the next SetStatement.
|
||||
"""
|
||||
global _g_cur_sp, _g_cur_entry_ref, _g_cur_builder, _g_depth
|
||||
if _g_enabled == 0:
|
||||
return 0
|
||||
if pool is None or builder is None or func is None or _g_mod is None:
|
||||
return 0
|
||||
if _g_depth >= DBG_STACK_MAX:
|
||||
VLogger.error("--traceback: DWARF 函数嵌套深度超上限,终止编译", "DWARF")
|
||||
return 0
|
||||
if _EnsureModuleNodes(pool) != 0:
|
||||
return 0
|
||||
name: str = llvmlite.function_get_name(func)
|
||||
if name is None:
|
||||
VLogger.error("--traceback: 函数名为空,无法发射 DISubprogram,终止编译", "DWARF")
|
||||
return 0
|
||||
dline: int = line
|
||||
if dline <= 0:
|
||||
dline = 1
|
||||
dcol: int = col
|
||||
if dcol <= 0:
|
||||
dcol = 1
|
||||
ssize: sizet = string.strlen(name) + 320
|
||||
spbuf: str = pool.alloc(ssize)
|
||||
if spbuf is None:
|
||||
VLogger.error("--traceback: DISubprogram 缓冲分配失败,终止编译", "DWARF")
|
||||
return 0
|
||||
viperlib.snprintf(spbuf, ssize,
|
||||
"distinct !DISubprogram(name: \"%s\", scope: !%d, file: !%d, type: !%d, line: %d, scopeLine: %d, unit: !%d, spFlags: DISPFlagDefinition)",
|
||||
name, _g_file_id, _g_file_id, _g_subtype_id, dline, dline, _g_cu_id)
|
||||
sp_id: int = llvmlite.module_add_di_node(_g_mod, pool, spbuf)
|
||||
if sp_id < 0:
|
||||
VLogger.error("--traceback: DISubprogram 元数据节点分配失败,终止编译", "DWARF")
|
||||
return 0
|
||||
sp_ref: str = _RefOf(pool, sp_id)
|
||||
if sp_ref is None:
|
||||
VLogger.error("--traceback: DISubprogram 引用缓冲分配失败,终止编译", "DWARF")
|
||||
return 0
|
||||
llvmlite.function_set_dbg(func, sp_ref)
|
||||
# save the enclosing function's DI context (LIFO), then switch to this one
|
||||
_g_stk_sp[_g_depth] = sizet(_g_cur_sp + 1)
|
||||
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_ref) + sizet(_g_depth) * 8)
|
||||
rslot[0] = _g_cur_entry_ref
|
||||
bslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_bld) + sizet(_g_depth) * 8)
|
||||
bslot[0] = _g_cur_builder
|
||||
_g_depth += 1
|
||||
_g_cur_sp = sp_id
|
||||
_g_cur_builder = builder
|
||||
entry_ref: str = _EnsureLocation(pool, sp_id, dline, dcol)
|
||||
if entry_ref is None:
|
||||
VLogger.error("--traceback: 入口 DILocation 生成失败,终止编译", "DWARF")
|
||||
return 0
|
||||
_g_cur_entry_ref = entry_ref
|
||||
llvmlite.builder_set_debug_location(builder, entry_ref)
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PopFunction - restore the enclosing function's DI context
|
||||
# ============================================================
|
||||
def PopFunction(builder: llvmlite.IRBuilder*) -> int:
|
||||
global _g_cur_sp, _g_cur_entry_ref, _g_cur_builder, _g_depth
|
||||
if _g_enabled == 0:
|
||||
return 0
|
||||
if _g_depth <= 0:
|
||||
return 0
|
||||
_g_depth -= 1
|
||||
_g_cur_sp = int(_g_stk_sp[_g_depth]) - 1
|
||||
rslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_ref) + sizet(_g_depth) * 8)
|
||||
_g_cur_entry_ref = rslot[0]
|
||||
bslot: str | t.CPtr = (str | t.CPtr)(uint64(_g_stk_bld) + sizet(_g_depth) * 8)
|
||||
_g_cur_builder = (llvmlite.IRBuilder*)(bslot[0])
|
||||
if builder is not None:
|
||||
llvmlite.builder_clear_debug_location(builder)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SetStatement - point the current builder at a statement DILocation
|
||||
# ============================================================
|
||||
def SetStatement(pool: memhub.MemBuddy*, builder: llvmlite.IRBuilder*,
|
||||
line: int, col: int) -> int:
|
||||
"""Update the builder's DILocation to the current statement (line precision).
|
||||
|
||||
No-op outside a DI-attached define (module-level code / synthetic defines),
|
||||
so instructions outside a function body never reference a function's scope.
|
||||
"""
|
||||
if _g_enabled == 0 or pool is None or builder is None:
|
||||
return 0
|
||||
if _g_cur_sp < 0:
|
||||
return 0
|
||||
ref: str = _EnsureLocation(pool, _g_cur_sp, line, col)
|
||||
if ref is None:
|
||||
return 0
|
||||
llvmlite.builder_set_debug_location(builder, ref)
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _ModuleHasDefine - does the module emit any define (IsDeclared == 0)?
|
||||
# ============================================================
|
||||
def _ModuleHasDefine(mod: llvmlite.LLVMModule*) -> int:
|
||||
if mod is None:
|
||||
return 0
|
||||
cur: llvmlite.Function* = mod.FuncHead
|
||||
steps: int = 0
|
||||
while cur is not None:
|
||||
steps += 1
|
||||
if steps > 100000:
|
||||
break
|
||||
if llvmlite.function_is_declared(cur) == 0:
|
||||
return 1
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Finalize - register !llvm.dbg.cu / !llvm.module.flags before dump_ir
|
||||
# ============================================================
|
||||
def Finalize(pool: memhub.MemBuddy*) -> int:
|
||||
"""Module-level DI tail; idempotent per module, no-op when no SP was emitted."""
|
||||
global _g_finalized
|
||||
if _g_enabled == 0:
|
||||
return 0
|
||||
if _g_finalized != 0:
|
||||
return 0
|
||||
mod: llvmlite.LLVMModule* = _g_mod
|
||||
if mod is None or pool is None:
|
||||
return 0
|
||||
_g_finalized = 1
|
||||
# Self-check (mirrors TPC Phase2Translator.py:3444): a module that emits a
|
||||
# define but carries no DI at all loses line info for its frames.
|
||||
if mod.DIMetaCount == 0 and _ModuleHasDefine(mod) != 0:
|
||||
VLogger.warning("--traceback: 本模块发射了 define 但 IR 未携带 DWARF (!llvm.dbg.cu)——该模块帧在 Ctrl+C 栈里将只显示地址", "DWARF")
|
||||
if _g_cu_id < 0:
|
||||
return 0
|
||||
cu_ref: str = _RefOf(pool, _g_cu_id)
|
||||
if cu_ref is None:
|
||||
VLogger.error("--traceback: DICompileUnit 引用缓冲分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
llvmlite.module_add_named_metadata(mod, pool, "llvm.dbg.cu", cu_ref)
|
||||
fbuf: str = pool.alloc(64)
|
||||
if fbuf is None:
|
||||
VLogger.error("--traceback: 模块级调试标志缓冲分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
viperlib.snprintf(fbuf, 64, "!{i32 2, !\"Debug Info Version\", i32 3}")
|
||||
flags_id: int = llvmlite.module_add_di_node(mod, pool, fbuf)
|
||||
if flags_id < 0:
|
||||
VLogger.error("--traceback: llvm.module.flags 元数据节点分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
fl_ref: str = _RefOf(pool, flags_id)
|
||||
if fl_ref is None:
|
||||
VLogger.error("--traceback: llvm.module.flags 引用缓冲分配失败,终止编译", "DWARF")
|
||||
return 1
|
||||
llvmlite.module_add_named_metadata(mod, pool, "llvm.module.flags", fl_ref)
|
||||
return 0
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -8,92 +8,55 @@ import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||||
import lib.Stub.StubMerger.StubMergerCollect as StubMergerCollect
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenCdef - ExprGenMixin 拆分(阶段 D):跨模块 CDefine 查找
|
||||
#
|
||||
# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
"""跨模块 CDefine 查找"""
|
||||
|
||||
# ============================================================
|
||||
# _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径
|
||||
#
|
||||
# .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。
|
||||
# 从 StubMerger 全局存储器查找 SHA1 对应的相对路径,
|
||||
# 根据 rel_path 前缀选择基础目录:
|
||||
# - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path}
|
||||
# - 其他 → includes 文件,用 {Config.IncludesDir}/{rel_path}
|
||||
#
|
||||
# Returns:
|
||||
# stdlib.malloc 分配的路径字符串(调用者负责 free),None 失败
|
||||
# ============================================================
|
||||
# _build_source_path_from_sha1:通过 SHA1 从 StubMerger 全局存储器构建源 .vp/.py 文件路径(.vpi 未生成时回退读源 .py);rel_path 以 "lib/" 开头 → {Config.SourceDir}/{rel_path},其他 → {Config.IncludesDir}/{rel_path}。返回 stdlib.malloc 分配的路径字符串(调用者负责 free),失败返回 None
|
||||
def _build_source_path_from_sha1(self, sha1: str) -> str:
|
||||
"""通过 SHA1 从全局存储器构建源 .py 文件路径"""
|
||||
if sha1 is None:
|
||||
return None
|
||||
if Config.IncludesDir is None:
|
||||
return None
|
||||
if sha1 is None: return None
|
||||
if Config.IncludesDir is None: return None
|
||||
# 从 StubMerger 全局存储器获取相对路径数组
|
||||
rel_arr_ptr: bytes = StubMergerStore.GetSha1StoreRelArrPtr()
|
||||
count: int = StubMergerStore.GetSha1StoreCount()
|
||||
if rel_arr_ptr is None or count <= 0:
|
||||
return None
|
||||
if rel_arr_ptr is None or count <= 0: return None
|
||||
sha1_arr_ptr: bytes = StubMergerStore.GetSha1StoreArrPtr()
|
||||
if sha1_arr_ptr is None:
|
||||
return None
|
||||
if sha1_arr_ptr is None: return None
|
||||
# 遍历查找匹配的 SHA1
|
||||
idx_s: int = -1
|
||||
for i in range(count):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
sidx: sizet = sizet(i) * 17
|
||||
cur_sha1: str = sha1_arr_ptr + sidx
|
||||
if cur_sha1[0] == '\0':
|
||||
continue
|
||||
if cur_sha1[0] == '\0': continue
|
||||
if string.strcmp(cur_sha1, sha1) == 0:
|
||||
idx_s = i
|
||||
break
|
||||
if idx_s < 0:
|
||||
return None
|
||||
# 获取相对路径(MAX_REL_PATH_LEN=256,避免跨模块 CDefine 解析问题)
|
||||
MAX_RPL: t.CSizeT = 256
|
||||
ridx: t.CSizeT = t.CSizeT(idx_s) * MAX_RPL
|
||||
MAX_RPL: sizet = 256
|
||||
ridx: sizet = sizet(idx_s) * MAX_RPL
|
||||
rel_path: str = rel_arr_ptr + ridx
|
||||
if rel_path[0] == '\0':
|
||||
return None
|
||||
# 选择基础目录(优先级):
|
||||
# 1. 条目存储的 includes 根目录 IncDir(绝对路径,多 includes 目录
|
||||
# 支持):PopulateSha1MapStore 按每条目保存所属根目录,跨模块
|
||||
# CDefine 查找回退读源时按 IncDir 直接拼路径,避免"首 includes
|
||||
# 目录"启发式对非首目录文件失效(Gargantua 多 includes 目录:
|
||||
# stdint.vp 属于 TransPyC/includes,而 IncludesDir=首目录 ViperOS
|
||||
# → 拼错路径 → 文件不存在 → XMOD-CD 误报根因)。
|
||||
# 2. rel_path 前缀启发式:以 "lib/" 开头 → App 源文件(SourceDir);
|
||||
# "includes/" 开头 → includes 文件(去掉前缀);其他无前缀路径
|
||||
# (如 VKernel 的 "drivers/core/cpu/cpu.vp")先试 SourceDir,
|
||||
# 文件不存在再试 IncludesDir。
|
||||
# 选择基础目录(优先级):1) 条目存储的 includes 根目录 IncDir(绝对路径,支持多 includes 目录,避免"首 includes 目录"启发式对非首目录文件失效);2) rel_path 前缀启发式——以 "lib/" 开头 → App 源文件(SourceDir);"includes/" 开头 → includes 文件(去掉前缀);其他无前缀路径先试 SourceDir,不存在再试 IncludesDir
|
||||
base_dir: str = None
|
||||
rel_used: str = rel_path
|
||||
inc_arr_ptr: bytes = StubMergerStore.GetSha1StoreIncdirArrPtr()
|
||||
if inc_arr_ptr is not None:
|
||||
iidx: t.CSizeT = t.CSizeT(idx_s) * StubMerger.MAX_INC_DIR_LEN
|
||||
iidx: sizet = sizet(idx_s) * StubMerger.MAX_INC_DIR_LEN
|
||||
inc_dir: str = inc_arr_ptr + iidx
|
||||
if inc_dir[0] != '\0':
|
||||
base_dir = inc_dir
|
||||
@@ -112,26 +75,26 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if base_dir is None:
|
||||
base_dir = Config.SourceDir if Config.SourceDir is not None else Config.IncludesDir
|
||||
# 构建完整路径: {base_dir}/{rel_used}
|
||||
base_len: t.CSizeT = string.strlen(base_dir)
|
||||
rel_len: t.CSizeT = string.strlen(rel_used)
|
||||
path_len: t.CSizeT = base_len + rel_len + 2
|
||||
base_len: sizet = string.strlen(base_dir)
|
||||
rel_len: sizet = string.strlen(rel_used)
|
||||
path_len: sizet = base_len + rel_len + 2
|
||||
buf: str = stdlib.malloc(path_len)
|
||||
if buf is None:
|
||||
return None
|
||||
viperlib.snprintf(buf, path_len, "%s/%s", base_dir, rel_used)
|
||||
# 存在性检查:SourceDir 下不存在且 IncludesDir 不同 → 重试 IncludesDir
|
||||
pf_chk: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R)
|
||||
pf_chk: rawptr[fileio.File] = fileio.File(buf, fileio.MODE.R)
|
||||
if pf_chk.closed:
|
||||
pf_chk.close()
|
||||
if Config.IncludesDir is not None and base_dir != Config.IncludesDir:
|
||||
stdlib.free(buf)
|
||||
base_len2: t.CSizeT = string.strlen(Config.IncludesDir)
|
||||
path_len2: t.CSizeT = base_len2 + rel_len + 2
|
||||
base_len2: sizet = string.strlen(Config.IncludesDir)
|
||||
path_len2: sizet = base_len2 + rel_len + 2
|
||||
buf = stdlib.malloc(path_len2)
|
||||
if buf is None:
|
||||
return None
|
||||
viperlib.snprintf(buf, path_len2, "%s/%s", Config.IncludesDir, rel_used)
|
||||
pf_chk2: fileio.File | t.CPtr = fileio.File(buf, fileio.MODE.R)
|
||||
pf_chk2: rawptr[fileio.File] = fileio.File(buf, fileio.MODE.R)
|
||||
if pf_chk2.closed:
|
||||
pf_chk2.close()
|
||||
stdlib.free(buf)
|
||||
@@ -152,12 +115,12 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
#
|
||||
# pyi 文件格式: "NAME: t.CDefine = value"
|
||||
# ============================================================
|
||||
def _lookup_cross_module_cdefine(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
def _lookup_cross_module_cdefine(self, pool: memhub.MemBuddy*,
|
||||
name: str,
|
||||
from_imports: str,
|
||||
imported_modules: str = None,
|
||||
depth: int = 0,
|
||||
node: ast.AST | t.CPtr = None) -> t.CInt64T:
|
||||
node: ast.AST* = None) -> int64:
|
||||
"""跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到)
|
||||
|
||||
查找顺序:
|
||||
@@ -209,13 +172,13 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 与 _lookup_sha1_from_modname_raw 的截断逻辑一致(空格/冒号/NUL 分隔)。
|
||||
base_mod: str = None
|
||||
if mod_name_raw is not None:
|
||||
mbl: t.CSizeT = 0
|
||||
mbl: sizet = 0
|
||||
while mod_name_raw[mbl] != ' ' and mod_name_raw[mbl] != '\0' \
|
||||
and mod_name_raw[mbl] != ':':
|
||||
mbl += 1
|
||||
mb_buf: str = pool.alloc(mbl + 1)
|
||||
if mb_buf is not None:
|
||||
mi2: t.CSizeT
|
||||
mi2: sizet
|
||||
for mi2 in range(mbl):
|
||||
mb_buf[mi2] = mod_name_raw[mi2]
|
||||
mb_buf[mbl] = '\0'
|
||||
@@ -232,7 +195,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 仅 ALL_CAPS 全局唯一宏名才进入本函数(_is_cdefine_name_pattern 已过滤)。
|
||||
xkey_buf: str = None
|
||||
if base_mod is not None:
|
||||
xk_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
xk_len: sizet = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
xkey_buf = pool.alloc(xk_len)
|
||||
if xkey_buf is not None:
|
||||
viperlib.snprintf(xkey_buf, xk_len, "%s@%s", name, base_mod)
|
||||
@@ -244,7 +207,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
xd_v: double = string.atof(xval)
|
||||
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, xd_v)
|
||||
else:
|
||||
xv_i: t.CInt64T = string.atoll(xval)
|
||||
xv_i: int64 = string.atoll(xval)
|
||||
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, xv_i)
|
||||
return string.atoll(xval)
|
||||
|
||||
@@ -260,22 +223,22 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 设置 result_found=0 跳过步骤 3-9,直接到 9.6
|
||||
self.Gen.TypeGenCDef.set_cdefine_found(0)
|
||||
# 直接遍历 imported_modules
|
||||
im_len: t.CSizeT = string.strlen(imported_modules)
|
||||
im_ci: t.CSizeT = 0
|
||||
im_len: sizet = string.strlen(imported_modules)
|
||||
im_ci: sizet = 0
|
||||
while im_ci < im_len:
|
||||
while im_ci < im_len and imported_modules[im_ci] == ' ':
|
||||
im_ci += 1
|
||||
if im_ci >= im_len:
|
||||
break
|
||||
im_start: t.CSizeT = im_ci
|
||||
im_start: sizet = im_ci
|
||||
while im_ci < im_len and imported_modules[im_ci] != ' ':
|
||||
im_ci += 1
|
||||
im_end: t.CSizeT = im_ci
|
||||
im_nlen: t.CSizeT = im_end - im_start
|
||||
im_end: sizet = im_ci
|
||||
im_nlen: sizet = im_end - im_start
|
||||
if im_nlen > 0 and im_nlen < 256:
|
||||
im_buf: str = pool.alloc(im_nlen + 1)
|
||||
if im_buf is not None:
|
||||
mk: t.CSizeT = 0
|
||||
mk: sizet = 0
|
||||
while mk < im_nlen:
|
||||
im_buf[mk] = imported_modules[im_start + mk]
|
||||
mk += 1
|
||||
@@ -284,12 +247,12 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if sub_fi is not None:
|
||||
sub_fi[0] = '*'
|
||||
sub_fi[1] = ':'
|
||||
mk2: t.CSizeT = 0
|
||||
mk2: sizet = 0
|
||||
while mk2 < im_nlen:
|
||||
sub_fi[2 + mk2] = im_buf[mk2]
|
||||
mk2 += 1
|
||||
sub_fi[2 + im_nlen] = '\0'
|
||||
sub_val: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi, None, depth + 1, node)
|
||||
sub_val: int64 = self._lookup_cross_module_cdefine(pool, name, sub_fi, None, depth + 1, node)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
return sub_val
|
||||
return -1
|
||||
@@ -305,18 +268,18 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
return -1
|
||||
|
||||
# 6. 构建 vpi 文件路径
|
||||
td_len: t.CSizeT = string.strlen(temp_dir)
|
||||
td_len: sizet = string.strlen(temp_dir)
|
||||
pyi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "vpi")
|
||||
if pyi_path is None:
|
||||
return -1
|
||||
|
||||
# 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件
|
||||
PYI_READ_BUF_SIZE: t.CSizeT = 65536
|
||||
PYI_READ_BUF_SIZE: sizet = 65536
|
||||
pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE)
|
||||
if pyi_buf is None:
|
||||
stdlib.free(pyi_path)
|
||||
return -1
|
||||
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.R)
|
||||
pf: rawptr[fileio.File] = fileio.File(pyi_path, fileio.MODE.R)
|
||||
need_py_fallback: int = 0
|
||||
bytes_read: LONG = 0
|
||||
if pf.closed:
|
||||
@@ -331,8 +294,6 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
else:
|
||||
if bytes_read < PYI_READ_BUF_SIZE:
|
||||
pyi_buf[bytes_read] = 0
|
||||
else:
|
||||
pyi_buf[PYI_READ_BUF_SIZE - 1] = 0
|
||||
# vpi(存根签名文件)中的 CDefine 声明可能只带名字不带值
|
||||
# (Converter 旧版只对 CONST_INT/BOOL 等输出 "= value",CONST_FLOAT
|
||||
# 等不输出 → numpy 的 pi/e 在 stub 中无值),真正的值在源
|
||||
@@ -345,9 +306,9 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 一律回退读源文件。
|
||||
cd_sig: int = 0
|
||||
name_has_val: int = 0
|
||||
cs_name_len: t.CSizeT = string.strlen(name)
|
||||
cs_total: t.CSizeT = string.strlen(pyi_buf)
|
||||
cs_i: t.CSizeT = 0
|
||||
cs_name_len: sizet = string.strlen(name)
|
||||
cs_total: sizet = string.strlen(pyi_buf)
|
||||
cs_i: sizet = 0
|
||||
while cs_i + 9 < cs_total:
|
||||
if (pyi_buf[cs_i] == 't' and pyi_buf[cs_i + 1] == '.' and
|
||||
pyi_buf[cs_i + 2] == 'C' and pyi_buf[cs_i + 3] == 'D' and
|
||||
@@ -356,7 +317,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
pyi_buf[cs_i + 8] == 'e'):
|
||||
# 检查该行剩余部分是否有 '='(带值声明才在 vpi 中匹配)
|
||||
cd_eq: int = 0
|
||||
cs_j: t.CSizeT = cs_i + 9
|
||||
cs_j: sizet = cs_i + 9
|
||||
while cs_j < cs_total and pyi_buf[cs_j] != '\n':
|
||||
if pyi_buf[cs_j] == '=':
|
||||
cd_eq = 1
|
||||
@@ -365,7 +326,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if cd_eq != 0:
|
||||
cd_sig = 1
|
||||
# 定位该行行首,检查是否以 "name:" 开头(目标名带值)
|
||||
cs_line_start: t.CSizeT = cs_i
|
||||
cs_line_start: sizet = cs_i
|
||||
while cs_line_start > 0 and pyi_buf[cs_line_start - 1] != '\n':
|
||||
cs_line_start -= 1
|
||||
if cs_i - cs_line_start >= cs_name_len + 1:
|
||||
@@ -408,25 +369,23 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
return -1
|
||||
if bytes_read < PYI_READ_BUF_SIZE:
|
||||
pyi_buf[bytes_read] = 0
|
||||
else:
|
||||
pyi_buf[PYI_READ_BUF_SIZE - 1] = 0
|
||||
|
||||
# 8. 在 pyi_buf 中查找 "name: t.CDefine = value" 行
|
||||
# 格式: NAME: t.CDefine = value
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
total_len: t.CSizeT = string.strlen(pyi_buf)
|
||||
pos: t.CSizeT = 0
|
||||
result_val: t.CInt64T = 0
|
||||
name_len: sizet = string.strlen(name)
|
||||
total_len: sizet = string.strlen(pyi_buf)
|
||||
pos: sizet = 0
|
||||
result_val: int64 = 0
|
||||
result_found: int = 0
|
||||
res_is_double: int = 0
|
||||
res_is_str: int = 0
|
||||
while pos < total_len:
|
||||
# 找到行首
|
||||
line_start: t.CSizeT = pos
|
||||
line_start: sizet = pos
|
||||
# 找到行尾
|
||||
while pos < total_len and pyi_buf[pos] != '\n':
|
||||
pos += 1
|
||||
line_len: t.CSizeT = pos - line_start
|
||||
line_len: sizet = pos - line_start
|
||||
if pos < total_len:
|
||||
pos += 1 # 跳过 '\n'
|
||||
|
||||
@@ -446,7 +405,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 检查行是否包含 "t.CDefine"
|
||||
# 在行中查找 "t.CDefine"
|
||||
has_cdefine: int = 0
|
||||
ci: t.CSizeT = line_start + name_len + 1
|
||||
ci: sizet = line_start + name_len + 1
|
||||
while ci + 8 <= line_start + line_len:
|
||||
if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and
|
||||
pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and
|
||||
@@ -460,7 +419,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
continue
|
||||
|
||||
# 找到 "=" 后面的值
|
||||
eq_pos: t.CSizeT = line_start + name_len + 1
|
||||
eq_pos: sizet = line_start + name_len + 1
|
||||
while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '=':
|
||||
eq_pos += 1
|
||||
if eq_pos >= line_start + line_len:
|
||||
@@ -471,14 +430,14 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
|
||||
eq_pos += 1
|
||||
|
||||
# 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / t.CInt(...) 等类型构造函数
|
||||
# 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / int(...) 等类型构造函数
|
||||
# 格式: t.CUnsignedLong(-11) / t.CUnsignedLong(0xFFFFFFFF)
|
||||
# 如果是,跳过 "t.CXxx(" 前缀,解析括号内的值,忽略结尾 ')'
|
||||
is_type_ctor: int = 0
|
||||
if eq_pos + 2 < line_start + line_len:
|
||||
if pyi_buf[eq_pos] == 't' and pyi_buf[eq_pos + 1] == '.':
|
||||
# 找到 '(' 的位置
|
||||
paren_pos: t.CSizeT = eq_pos + 2
|
||||
paren_pos: sizet = eq_pos + 2
|
||||
while paren_pos < line_start + line_len and pyi_buf[paren_pos] != '(':
|
||||
paren_pos += 1
|
||||
if paren_pos < line_start + line_len and pyi_buf[paren_pos] == '(':
|
||||
@@ -502,8 +461,8 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-':
|
||||
is_neg = 1
|
||||
eq_pos += 1
|
||||
val_str_start: t.CSizeT = eq_pos
|
||||
val_str_len: t.CSizeT = 0
|
||||
val_str_start: sizet = eq_pos
|
||||
val_str_len: sizet = 0
|
||||
is_hex: int = 0
|
||||
is_float_val: int = 0
|
||||
is_name_val: int = 0
|
||||
@@ -530,7 +489,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
pyi_buf[eq_pos] == '_':
|
||||
is_name_val = 1
|
||||
while eq_pos < line_start + line_len:
|
||||
c_tk: t.CChar = pyi_buf[eq_pos]
|
||||
c_tk: char = pyi_buf[eq_pos]
|
||||
if (c_tk >= 'A' and c_tk <= 'Z') or (c_tk >= 'a' and c_tk <= 'z') or \
|
||||
(c_tk >= '0' and c_tk <= '9') or c_tk == '_':
|
||||
val_str_len += 1
|
||||
@@ -539,7 +498,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
break
|
||||
# 数字/hex 字符续读(字符串值已整体读取,跳过)
|
||||
while eq_pos < line_start + line_len and is_name_val == 0 and is_str_val == 0:
|
||||
ch: t.CChar = pyi_buf[eq_pos]
|
||||
ch: char = pyi_buf[eq_pos]
|
||||
if is_hex == 1:
|
||||
if ((ch >= '0' and ch <= '9') or
|
||||
(ch >= 'a' and ch <= 'f') or
|
||||
@@ -572,7 +531,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
val_buf[val_str_len] = '\0'
|
||||
|
||||
# 左 token 求值
|
||||
lval: t.CInt64T = 0
|
||||
lval: int64 = 0
|
||||
l_is_double: int = 0
|
||||
ldbl: double = 0.0
|
||||
if is_str_val != 0:
|
||||
@@ -598,10 +557,10 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
elif is_hex == 1:
|
||||
# 手动解析十六进制(跳过 0x 前缀)——64 位累加,
|
||||
# 0xFFFFFFFF=4294967295 保持全精度(常量生成端 i32 截断回 -1)
|
||||
hex_result: t.CInt64T = 0
|
||||
hex_result: int64 = 0
|
||||
hex_buf: str = val_buf + 2 # 跳过 "0x"
|
||||
for hi in range(val_str_len - 2):
|
||||
hc: t.CChar = hex_buf[hi]
|
||||
hc: char = hex_buf[hi]
|
||||
hd: int = 0
|
||||
if hc >= '0' and hc <= '9':
|
||||
hd = hc - '0'
|
||||
@@ -668,8 +627,8 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-':
|
||||
r_neg = 1
|
||||
eq_pos += 1
|
||||
r_start: t.CSizeT = eq_pos
|
||||
r_len: t.CSizeT = 0
|
||||
r_start: sizet = eq_pos
|
||||
r_len: sizet = 0
|
||||
r_hex: int = 0
|
||||
r_name: int = 0
|
||||
if eq_pos + 1 < line_start + line_len:
|
||||
@@ -682,7 +641,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
pyi_buf[eq_pos] == '_':
|
||||
r_name = 1
|
||||
while eq_pos < line_start + line_len:
|
||||
c_r: t.CChar = pyi_buf[eq_pos]
|
||||
c_r: char = pyi_buf[eq_pos]
|
||||
if (c_r >= 'A' and c_r <= 'Z') or (c_r >= 'a' and c_r <= 'z') or \
|
||||
(c_r >= '0' and c_r <= '9') or c_r == '_':
|
||||
r_len += 1
|
||||
@@ -690,7 +649,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
else:
|
||||
break
|
||||
while eq_pos < line_start + line_len and r_name == 0:
|
||||
c_r2: t.CChar = pyi_buf[eq_pos]
|
||||
c_r2: char = pyi_buf[eq_pos]
|
||||
if r_hex == 1:
|
||||
if ((c_r2 >= '0' and c_r2 <= '9') or
|
||||
(c_r2 >= 'a' and c_r2 <= 'f') or
|
||||
@@ -714,7 +673,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
for r_i in range(r_len):
|
||||
r_buf[r_i] = pyi_buf[r_start + r_i]
|
||||
r_buf[r_len] = '\0'
|
||||
rval: t.CInt64T = 0
|
||||
rval: int64 = 0
|
||||
if r_name != 0:
|
||||
# True/False 布尔字面量 → 1/0
|
||||
if string.strcmp(r_buf, "True") == 0:
|
||||
@@ -727,10 +686,10 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 名称未注册:无法求值,跳过该行
|
||||
continue
|
||||
elif r_hex != 0:
|
||||
rhex_v: t.CInt64T = 0
|
||||
rhex_v: int64 = 0
|
||||
rh_buf: str = r_buf + 2
|
||||
for rh_i in range(r_len - 2):
|
||||
rc: t.CChar = rh_buf[rh_i]
|
||||
rc: char = rh_buf[rh_i]
|
||||
rd: int = 0
|
||||
if rc >= '0' and rc <= '9':
|
||||
rd = rc - '0'
|
||||
@@ -796,39 +755,51 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if result_found == 0:
|
||||
# base_mod 已在函数开头计算(mod_name_raw 去前导点),
|
||||
# 供子模块递归构建 "base_mod.X" 全名。
|
||||
name_len_rc: t.CSizeT = string.strlen(name)
|
||||
rc_pos: t.CSizeT = 0
|
||||
name_len_rc: sizet = string.strlen(name)
|
||||
rc_pos: sizet = 0
|
||||
while rc_pos < total_len and result_found == 0:
|
||||
# 找到行首
|
||||
rc_line_start: t.CSizeT = rc_pos
|
||||
rc_line_start: sizet = rc_pos
|
||||
# 找到行尾
|
||||
while rc_pos < total_len and pyi_buf[rc_pos] != '\n':
|
||||
rc_pos += 1
|
||||
rc_line_len: t.CSizeT = rc_pos - rc_line_start
|
||||
rc_line_len: sizet = rc_pos - rc_line_start
|
||||
if rc_pos < total_len:
|
||||
rc_pos += 1
|
||||
|
||||
# 检查行是否以 "from ." 开头(相对导入子模块)
|
||||
# 检查行是否以 "from " 开头(模块导入)
|
||||
if rc_line_len < 12:
|
||||
continue
|
||||
if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \
|
||||
pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \
|
||||
pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.':
|
||||
pyi_buf[rc_line_start+4] != ' ':
|
||||
continue
|
||||
|
||||
# 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止)
|
||||
rc_sub_start: t.CSizeT = rc_line_start + 6
|
||||
rc_sub_end: t.CSizeT = rc_sub_start
|
||||
# 提取模块路径 token(从 rc_line_start+5 到空格/tab 为止,跳过前导点)
|
||||
# 两种写法都要支持:
|
||||
# 相对导入 `from .base import X` → 拼 base_mod.base
|
||||
# 绝对导入 `from vqt6._types import *` → 直接用 token 自身
|
||||
# 此前只认相对导入(硬要求 rc_line_start+5 是 '.'),绝对写法被
|
||||
# 直接跳过 → vqt6 包(__init__.vp 用 `from vqt6._types import *`
|
||||
# 重导出 QT_ALIGN_* 等)里的 CDefine 全部查不到 →
|
||||
# "跨模块 CDefine 未找到: 'vqt6.QT_ALIGN_CENTER'"。
|
||||
rc_is_rel: int = 0
|
||||
rc_sub_start: sizet = rc_line_start + 5
|
||||
while rc_sub_start < rc_line_start + rc_line_len and \
|
||||
pyi_buf[rc_sub_start] == '.':
|
||||
rc_is_rel = 1
|
||||
rc_sub_start += 1
|
||||
rc_sub_end: sizet = rc_sub_start
|
||||
while rc_sub_end < rc_line_start + rc_line_len and \
|
||||
pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t':
|
||||
rc_sub_end += 1
|
||||
rc_sub_len: t.CSizeT = rc_sub_end - rc_sub_start
|
||||
rc_sub_len: sizet = rc_sub_end - rc_sub_start
|
||||
if rc_sub_len == 0:
|
||||
continue
|
||||
|
||||
# 检查行是否包含 "import"
|
||||
rc_has_import: int = 0
|
||||
rc_ipos: t.CSizeT = rc_sub_end
|
||||
rc_ipos: sizet = rc_sub_end
|
||||
while rc_ipos + 6 <= rc_line_start + rc_line_len:
|
||||
if pyi_buf[rc_ipos] == 'i' and pyi_buf[rc_ipos+1] == 'm' and \
|
||||
pyi_buf[rc_ipos+2] == 'p' and pyi_buf[rc_ipos+3] == 'o' and \
|
||||
@@ -842,14 +813,14 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 检查 NAME 是否在导入列表中,或导入是 *
|
||||
# 处理多行导入:from .X import (... NAME, ...)
|
||||
# 从 "import" 之后扫描,如果有 "(" 则扫描到 ")" 为止
|
||||
rc_imp_start: t.CSizeT = rc_ipos + 6
|
||||
rc_imp_start: sizet = rc_ipos + 6
|
||||
rc_star: int = 0
|
||||
rc_name_match: int = 0
|
||||
|
||||
# 确定扫描范围:单行或跨行(括号内)
|
||||
rc_scan_end: t.CSizeT = rc_line_start + rc_line_len
|
||||
rc_scan_end: sizet = rc_line_start + rc_line_len
|
||||
rc_has_paren: int = 0
|
||||
rc_pp: t.CSizeT = rc_imp_start
|
||||
rc_pp: sizet = rc_imp_start
|
||||
while rc_pp < rc_line_start + rc_line_len:
|
||||
if pyi_buf[rc_pp] == '(':
|
||||
rc_has_paren = 1
|
||||
@@ -861,7 +832,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 多行导入:从 "(" 之后扫描到 ")" 为止
|
||||
rc_scan_end = rc_pp + 1
|
||||
rc_paren_closed: int = 0
|
||||
rc_sp: t.CSizeT = rc_pp + 1
|
||||
rc_sp: sizet = rc_pp + 1
|
||||
while rc_sp < total_len and rc_paren_closed == 0:
|
||||
if pyi_buf[rc_sp] == ')':
|
||||
rc_paren_closed = 1
|
||||
@@ -872,15 +843,15 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
rc_scan_end = total_len
|
||||
|
||||
# 在 rc_imp_start 到 rc_scan_end 范围内查找 NAME 和 *
|
||||
rc_cpos: t.CSizeT = rc_imp_start
|
||||
rc_cpos: sizet = rc_imp_start
|
||||
while rc_cpos < rc_scan_end:
|
||||
rc_ch: t.CChar = pyi_buf[rc_cpos]
|
||||
rc_ch: char = pyi_buf[rc_cpos]
|
||||
if rc_ch == '*':
|
||||
rc_star = 1
|
||||
# 检查 NAME 是否匹配(作为完整单词)
|
||||
if rc_cpos + name_len_rc <= rc_scan_end:
|
||||
rc_match: int = 1
|
||||
rc_ki: t.CSizeT
|
||||
rc_ki: sizet
|
||||
for rc_ki in range(name_len_rc):
|
||||
if pyi_buf[rc_cpos + rc_ki] != name[rc_ki]:
|
||||
rc_match = 0
|
||||
@@ -891,18 +862,18 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if rc_cpos == rc_imp_start:
|
||||
rc_before_ok = 1
|
||||
else:
|
||||
rc_before_ch: t.CChar = pyi_buf[rc_cpos - 1]
|
||||
rc_before_ch: char = pyi_buf[rc_cpos - 1]
|
||||
if rc_before_ch == ' ' or rc_before_ch == '\t' or \
|
||||
rc_before_ch == '(' or rc_before_ch == ',' or \
|
||||
rc_before_ch == '\n' or rc_before_ch == '\r':
|
||||
rc_before_ok = 1
|
||||
# 检查后字符是否是非标识符字符
|
||||
rc_after_ok: int = 0
|
||||
rc_after_pos: t.CSizeT = rc_cpos + name_len_rc
|
||||
rc_after_pos: sizet = rc_cpos + name_len_rc
|
||||
if rc_after_pos >= rc_scan_end:
|
||||
rc_after_ok = 1
|
||||
else:
|
||||
rc_after_ch: t.CChar = pyi_buf[rc_after_pos]
|
||||
rc_after_ch: char = pyi_buf[rc_after_pos]
|
||||
if rc_after_ch == ' ' or rc_after_ch == '\t' or \
|
||||
rc_after_ch == ')' or rc_after_ch == ',' or \
|
||||
rc_after_ch == '\r' or rc_after_ch == '\n':
|
||||
@@ -918,23 +889,42 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
rc_sub_buf: str = pool.alloc(rc_sub_len + 1)
|
||||
if rc_sub_buf is None:
|
||||
continue
|
||||
rc_si: t.CSizeT
|
||||
rc_si: sizet
|
||||
for rc_si in range(rc_sub_len):
|
||||
rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si]
|
||||
rc_sub_buf[rc_sub_len] = '\0'
|
||||
|
||||
# 构建完整子模块名 base_mod.X
|
||||
rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1
|
||||
rc_full_mod: str = pool.alloc(rc_full_len)
|
||||
if rc_full_mod is None:
|
||||
continue
|
||||
viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf)
|
||||
# 构建完整模块名:
|
||||
# 相对导入(rc_is_rel=1)→ <当前模块所属包> + "." + token
|
||||
# 基准必须是"包"(rel_path 的目录部分)而不是模块名本身:
|
||||
# pkg/sub/mod.vp 里的 `from .X import Y` 指向 pkg.sub.X,
|
||||
# 用 base_mod("pkg.sub.mod")会拼成 pkg.sub.mod.X(错)。
|
||||
# __init__.vp 时包名 == 模块名,此前只在这种情况碰巧正确
|
||||
# (CallGenBase._lookup_reexport_from_vpi 用的是包名,此处对齐)。
|
||||
# 绝对导入(rc_is_rel=0)→ 直接用 token(vqt6._types)
|
||||
# 自导入(目标模块 == base_mod)跳过,避免无意义递归
|
||||
rc_full_mod: str = None
|
||||
if rc_is_rel != 0:
|
||||
rc_base_mod: str = base_mod
|
||||
rc_pkg: str = self.Gen.CallGenBase._module_package_from_sha1(pool, sha1)
|
||||
if rc_pkg is not None:
|
||||
rc_base_mod = rc_pkg
|
||||
rc_full_len: sizet = string.strlen(rc_base_mod) + 1 + rc_sub_len + 1
|
||||
rc_full_buf: str = pool.alloc(rc_full_len)
|
||||
if rc_full_buf is None:
|
||||
continue
|
||||
viperlib.snprintf(rc_full_buf, rc_full_len, "%s.%s", rc_base_mod, rc_sub_buf)
|
||||
rc_full_mod = rc_full_buf
|
||||
else:
|
||||
if string.strcmp(rc_sub_buf, base_mod) == 0:
|
||||
continue
|
||||
rc_full_mod = rc_sub_buf
|
||||
|
||||
# 防循环:若 base_mod 已以 "."+rc_sub_buf 结尾(如 ast.base 再拼
|
||||
# .base → ast.base.base),说明子模块递归在重复追加同一模块段
|
||||
# (模块间循环 re-export / 后缀匹配容错命中自身),跳过该次递归
|
||||
# (NewAstTest CONST_INT 查找 dump:ast.base.base.base 无限增长根因)。
|
||||
rc_blen: t.CSizeT = string.strlen(base_mod)
|
||||
rc_blen: sizet = string.strlen(base_mod)
|
||||
if rc_blen > rc_sub_len + 1:
|
||||
rc_tail: str = base_mod + (rc_blen - rc_sub_len)
|
||||
if rc_tail[0] == '.' and \
|
||||
@@ -942,7 +932,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
continue
|
||||
|
||||
# 构建临时 from_imports "name:full_mod"
|
||||
rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1
|
||||
rc_fi_len: sizet = name_len_rc + 1 + string.strlen(rc_full_mod) + 1
|
||||
rc_fi: str = pool.alloc(rc_fi_len)
|
||||
if rc_fi is None:
|
||||
continue
|
||||
@@ -961,22 +951,22 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时,
|
||||
# 需要遍历 imported_modules 逐个查找
|
||||
if result_found == 0 and imported_modules is not None:
|
||||
im2_len: t.CSizeT = string.strlen(imported_modules)
|
||||
im2_ci: t.CSizeT = 0
|
||||
im2_len: sizet = string.strlen(imported_modules)
|
||||
im2_ci: sizet = 0
|
||||
while im2_ci < im2_len and result_found == 0:
|
||||
while im2_ci < im2_len and imported_modules[im2_ci] == ' ':
|
||||
im2_ci += 1
|
||||
if im2_ci >= im2_len:
|
||||
break
|
||||
im2_start: t.CSizeT = im2_ci
|
||||
im2_start: sizet = im2_ci
|
||||
while im2_ci < im2_len and imported_modules[im2_ci] != ' ':
|
||||
im2_ci += 1
|
||||
im2_end: t.CSizeT = im2_ci
|
||||
im2_nlen: t.CSizeT = im2_end - im2_start
|
||||
im2_end: sizet = im2_ci
|
||||
im2_nlen: sizet = im2_end - im2_start
|
||||
if im2_nlen > 0 and im2_nlen < 256:
|
||||
im2_buf: str = pool.alloc(im2_nlen + 1)
|
||||
if im2_buf is not None:
|
||||
mk3: t.CSizeT = 0
|
||||
mk3: sizet = 0
|
||||
while mk3 < im2_nlen:
|
||||
im2_buf[mk3] = imported_modules[im2_start + mk3]
|
||||
mk3 += 1
|
||||
@@ -985,12 +975,12 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if sub_fi2 is not None:
|
||||
sub_fi2[0] = '*'
|
||||
sub_fi2[1] = ':'
|
||||
mk4: t.CSizeT = 0
|
||||
mk4: sizet = 0
|
||||
while mk4 < im2_nlen:
|
||||
sub_fi2[2 + mk4] = im2_buf[mk4]
|
||||
mk4 += 1
|
||||
sub_fi2[2 + im2_nlen] = '\0'
|
||||
sub_val2: t.CInt64T = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None, depth + 1, node)
|
||||
sub_val2: int64 = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None, depth + 1, node)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
result_val = sub_val2
|
||||
result_found = 1
|
||||
@@ -1003,7 +993,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# 字符串 CDefine:值已在匹配循环 register_cdefine_string(val_buf
|
||||
# 是命中行的字符串内容,pool 分配跨函数有效),此处只写跨模块缓存
|
||||
if base_mod is not None:
|
||||
ck_len_s: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
ck_len_s: sizet = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
ckey_s: str = pool.alloc(ck_len_s)
|
||||
if ckey_s is not None:
|
||||
viperlib.snprintf(ckey_s, ck_len_s, "%s@%s", name, base_mod)
|
||||
@@ -1014,7 +1004,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# key 与入口查询一致:"name@源模块"(用截断后的 base_mod,
|
||||
# 与 mod_name_raw 一致——两者都是去点后的模块名,保证 key 匹配)
|
||||
if base_mod is not None:
|
||||
ck_len: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
ck_len: sizet = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
ckey_buf: str = pool.alloc(ck_len)
|
||||
if ckey_buf is not None:
|
||||
viperlib.snprintf(ckey_buf, ck_len, "%s@%s", name, base_mod)
|
||||
@@ -1025,7 +1015,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
else:
|
||||
# 浮点:从本地表取回 %.17g 文本,写入跨模块缓存(保精度)
|
||||
if base_mod is not None:
|
||||
ck_len2: t.CSizeT = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
ck_len2: sizet = string.strlen(name) + string.strlen(base_mod) + 2
|
||||
ckey2: str = pool.alloc(ck_len2)
|
||||
if ckey2 is not None:
|
||||
viperlib.snprintf(ckey2, ck_len2, "%s@%s", name, base_mod)
|
||||
@@ -1057,9 +1047,9 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if name is None:
|
||||
return 0
|
||||
has_upper: int = 0
|
||||
i: t.CSizeT = 0
|
||||
i: sizet = 0
|
||||
while name[i] != '\0':
|
||||
c: t.CChar = name[i]
|
||||
c: char = name[i]
|
||||
if c >= 'a' and c <= 'z':
|
||||
return 0
|
||||
if c >= 'A' and c <= 'Z':
|
||||
@@ -1069,14 +1059,31 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# ============================================================
|
||||
# 翻译变量引用(Name 节点)→ load
|
||||
# ============================================================
|
||||
def _const_int_for_cdefine(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
value: t.CInt64T) -> llvmlite.Value | t.CPtr:
|
||||
def _const_int_for_cdefine(self, pool: memhub.MemBuddy*,
|
||||
value: int64) -> llvmlite.Value*:
|
||||
"""CDefine 整数常量 → LLVM 常量(对齐 TPC TypeConvert 的 64 位升级)
|
||||
|
||||
**使用处宽度("W_min + 使用处宽度"规则)与物化宽度的关系**(与 TPC 同口径,
|
||||
对照表见 Debugger/define-constants.md):
|
||||
· 本函数是"取不到使用处宽度"的物化点(调用方 ExprGenName/ExprGenAttr 只有
|
||||
常量名与值,没有目标类型)⇒ 按语言默认整型宽度物化:能落进 32 位 ⇒ i32,
|
||||
否则 i64。**不**降到 W_min——降到 i8/i16 会把窄立即数喂进 i32 上下文与
|
||||
C 默认实参提升(printf 变参),属静默降级/ABI 破坏。
|
||||
· "使用处更宽 ⇒ 以该宽度物化"由**消费端**实现:translate_binop 按较宽侧
|
||||
zext/sext/coerce_to_type 对齐,赋值/形参按目标存储类型 coerce。
|
||||
· "使用处更窄 ⇒ fail-fast"在**注册处与声明处**实现:
|
||||
AssignGenMixin.require_cdefine_storable(显式类型 T 的位宽)与
|
||||
require_cdefine_use_width(`a: T = C`);超 64 位字面量由
|
||||
_int_text_exceeds_64 以**源码文本**判定(lexer 的 atoll 会在字面量层
|
||||
回绕,回绕后的 int64 不可信,故本函数不承担溢出判定)。
|
||||
|
||||
规则(与 translate_constant 的 i32 溢出升级一致,但保留 0xFFFFFFFF 语义):
|
||||
值超 32 位无符号范围(> 0xFFFFFFFF)→ i64 全精度常量
|
||||
(如 sys.maxsize = 9223372036854775807);
|
||||
否则 → i32 常量,内部 t.CInt 截断(0xFFFFFFFF → -1,保持既有
|
||||
值低于 i32 下限(< -2147483648)→ i64 全精度常量。符号位为 1 的 64 位
|
||||
模式(如 MEMBUDDY_CANARY_PATTERN = 0xA5A5A5A5A5A5A5A5)以 %lld 文本
|
||||
存回即负数 -6510615555426900571,仅按 u32 截断回比较会漏判;
|
||||
否则 → i32 常量,内部 int 截断(0xFFFFFFFF → -1,保持既有
|
||||
INVALID_HANDLE_VALUE / WAIT_FAILED = -1 语义不变,避免 i32 4294967295
|
||||
生成非法 LLVM IR 文本 "i32 4294967295")。
|
||||
|
||||
@@ -1084,8 +1091,103 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
(> 0x7FFFFFFF)在字面量层回绕成 i32(sext 后等于 -1),阈值恒成立导致所有
|
||||
正数 CDefine 都被升 i64(INVALID_FILE_ATTRIBUTES 0xFFFFFFFF 从 i32 -1 变
|
||||
i64 4294967295 → 与 _get_attrs 的 sext(-1) 比较失败,SysLibTest exists FAIL 根因)。
|
||||
改用截断回比较:t.CUInt32T(value) 回绕后还原,与 value 不等即超 u32 范围。
|
||||
改用截断回比较:uint32(value) 回绕后还原,与 value 不等即超 u32 范围。
|
||||
|
||||
负数侧漏判的现场:`(0xA5A5A5A5 << 32) | 0xA5A5A5A5`(includes/memhub.vp:123)
|
||||
经 CDefine 求值(ExprGenCdef 内 lval << rval 的 int64 回绕)得
|
||||
-6510615555426900571,再经 TypeGenCDef.register_cdefine_constant 的
|
||||
"%lld" 文本存回(TypeGenCDef.vp:156)仍为负数 → 原判据物化成 i32
|
||||
-1515870811:写入路径 inttoptr i32(x86 movl 零扩展)实存
|
||||
0x00000000A5A5A5A5,比较/打印路径 sext i32→i64 期望 0xFFFFFFFFA5A5A5A5
|
||||
⇒ MemBuddy canary 校验 rc=6 假阳性。下限判据与既有
|
||||
ExprGenConst.vp:108 / CallGenLeafKit.vp:1477 的写法一致。
|
||||
"""
|
||||
if value >= 0 and t.CUInt64T(t.CUInt32T(value)) != value:
|
||||
if (value >= 0 and uint64(uint32(value)) != value) or value < -2147483648:
|
||||
return llvmlite.const_int64(pool, value)
|
||||
return llvmlite.const_int32(pool, t.CInt(value))
|
||||
return llvmlite.const_int32(pool, int(value))
|
||||
|
||||
# ============================================================
|
||||
# cdefine_use_width_value - "使用处宽度"下的 CDefine 常量物化
|
||||
# (与 TPC HandlesExpr._HandleNameLlvm + ConstWidthHint 同口径)
|
||||
# ============================================================
|
||||
def _cdefine_bits_value(self, value: int64, bits: int) -> int64:
|
||||
"""把 CDefine 值归一到 bits 位的**有符号表示**(LLVM 整数字面量口径)。
|
||||
|
||||
前提:调用方已用 W_min 判据保证 value 落在
|
||||
[-(2^(bits-1)), 2^bits-1](两解释口径)。非负但最高位为 1 的值
|
||||
(如 0xFFFFFFFF)转成同一位模式的负数(i32 4294967295 → i32 -1),
|
||||
与 _const_int_for_cdefine 既有的 i32 截断口径一致,避免生成非法 IR 文本。
|
||||
"""
|
||||
if bits == 8:
|
||||
if value > 127:
|
||||
return value - 256
|
||||
return value
|
||||
if bits == 16:
|
||||
if value > 32767:
|
||||
return value - 65536
|
||||
return value
|
||||
if bits == 32:
|
||||
if value > 2147483647:
|
||||
return value - 4294967296
|
||||
return value
|
||||
return value
|
||||
|
||||
def cdefine_use_width_value(self, pool: memhub.MemBuddy*,
|
||||
node: ast.AST*, name: str,
|
||||
value: int64,
|
||||
target_ty: llvmlite.LLVMType*,
|
||||
use_ctx: str = None) -> llvmlite.Value*:
|
||||
"""CDefine 整数常量在**已知使用处类型**时的物化(与 TPC 同口径)。
|
||||
|
||||
返回 None ⇒ "取不到使用处宽度"(调用方沿用 _const_int_for_cdefine 的
|
||||
语言默认整型宽度 32/64)。只当 target_ty 是 i8/i16/i32/i64 时启用
|
||||
(i1 是比较/逻辑结果、指针不是整数使用处 ⇒ 落回默认,否则 `C == 0`
|
||||
之类会拿到位宽 1 而误报"使用处宽度不足"):
|
||||
使用处更宽(bits >= W_min)⇒ 按 bits 就地物化(立即数升宽无损);
|
||||
使用处更窄(bits < W_min)⇒ fail-fast(替换静默截断)。
|
||||
只被 CDefine 整数物化点调用 ⇒ 不改变非常量实参/返回值的既有 IR。
|
||||
|
||||
use_ctx:**真实站点种类**标签(如 "局部变量注解" / "模块级全局" / "形参" /
|
||||
"返回注解"),由 `translate_value` 的调用方按站点下传;None ⇒ 报文不写
|
||||
括注(**不得**再写死"形参 / 返回类型"——AnnAssign 的 `a: T = C` 现场也被
|
||||
本函数拦到时,硬编码标签会给出错误站点)。
|
||||
"""
|
||||
bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(target_ty)
|
||||
if bits != 8 and bits != 16 and bits != 32 and bits != 64:
|
||||
return None
|
||||
wmin: int = self.Gen.AssignGen.define_min_width(value)
|
||||
if bits < wmin:
|
||||
# "该使用处可表示的范围"与判据同一口径 = TPC `DefineWidthLoHi`
|
||||
# = [-(2^(bits-1)), 2^bits - 1](有符号/无符号两种解释的并集;
|
||||
# 判据本身只按**位宽**比较,故报文必须报"位宽 w 的可接受值域")。
|
||||
# 字面量纪律见 AssignGenMixin.define_min_width:2147483648 /
|
||||
# 4294967295 会被 TPC 压成 i32 并在提升时 sext,故用安全字面量
|
||||
# 2147483647 的算术等价式构造。
|
||||
m31: int64 = 2147483647
|
||||
lo: int64 = -m31 - 1
|
||||
hi: int64 = m31 * 2 + 1
|
||||
if bits == 8:
|
||||
lo = -128
|
||||
hi = 255
|
||||
elif bits == 16:
|
||||
lo = -32768
|
||||
hi = 65535
|
||||
ctx: str = ""
|
||||
if use_ctx is not None:
|
||||
# 本语言的 str 是 i8*,**没有** `str + str` 的拼接语义(`+` 会退化
|
||||
# 成裸指针 add → "invalid operand type for instruction")。
|
||||
# 构建字符串一律用本仓库惯用法:f-string 插值 / string.strcat /
|
||||
# viperlib.snprintf。
|
||||
ctx = f"({use_ctx})"
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node,
|
||||
f"[TPV] define 常量使用处宽度不足: 常量 '{name}' 的实际值 {value} "
|
||||
f"需要至少 {wmin} 位(最小可容纳宽度 W_min),"
|
||||
f"但使用处{ctx}只提供 {bits} 位"
|
||||
f"(该位宽按有符号/无符号两种解释可接受的范围: {lo}..{hi})。"
|
||||
f"禁止静默截断/降级,已终止编译。"
|
||||
f"修法: 把使用处{ctx}的类型加宽到至少 {wmin} 位"
|
||||
f"(如 t.CInt{wmin}T / CUInt{wmin}T 及更宽类型),或改用更小的常量值。",
|
||||
"TypeError")
|
||||
return None
|
||||
return llvmlite.const_int(pool, bits, self._cdefine_bits_value(value, bits))
|
||||
@@ -1,50 +1,32 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||||
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
|
||||
|
||||
# ============================================================
|
||||
# docstring 登记表容量常量(与 ExprGenMixin 保持一致,本地副本避免
|
||||
# 跨模块 CDefine 查找 bug:ExprGenCls(C) 在 ExprGenMixin(M) 之前按
|
||||
# 文件序编译时,跨模块 CDefine 全局表未注册 → NameError 未定义)
|
||||
# docstring 登记表容量常量(与 ExprGenMixin 保持一致,存疑
|
||||
# ============================================================
|
||||
DOC_MAX: t.CDefine = 512
|
||||
DOC_KEY_SZ: t.CDefine = 192
|
||||
DOC_VAL_SZ: t.CDefine = 4096
|
||||
define DOC_MAX = 512
|
||||
define DOC_KEY_SZ = 192
|
||||
define DOC_VAL_SZ = 4096
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenCls - ExprGenMixin 拆分(阶段 D):类名推断/docstring 登记
|
||||
#
|
||||
# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
novirtual class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
"""类名推断/docstring 登记"""
|
||||
|
||||
# ============================================================
|
||||
@@ -57,42 +39,32 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
# 符号依赖),未命中返回 null。幂等查重,多遍翻译安全。
|
||||
# ============================================================
|
||||
|
||||
def _extract_docstring_from_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> str:
|
||||
def _extract_docstring_from_body(self, body: list[ast.AST*]*) -> str:
|
||||
"""从函数/类体提取 docstring:body[0] 为 Expr(Constant str) 时返回内容"""
|
||||
if body is None or len(body) == 0:
|
||||
return None
|
||||
first: ast.AST | t.CPtr = body.get(0)
|
||||
if first is None or first.kind() != ast.ASTKind.Expr:
|
||||
return None
|
||||
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(first)
|
||||
if ex is None or ex.value is None or ex.value.kind() != ast.ASTKind.Constant:
|
||||
return None
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(ex.value)
|
||||
if cn is None or cn.const_kind != ast.CONST_STR:
|
||||
return None
|
||||
if body is None or len(body) == 0: return None
|
||||
first: ast.AST* = body.get(0)
|
||||
if first is None or first.kind() != ast.ASTKind.Expr: return None
|
||||
ex: rawptr[ast.Expr] = rawptr[ast.Expr](first)
|
||||
if ex is None or ex.value is None or ex.value.kind() != ast.ASTKind.Constant: return None
|
||||
cn: ast.Constant* = ast.Constant*(ex.value)
|
||||
if cn is None or cn.const_kind != ast.CONST_STR: return None
|
||||
return cn.str_val
|
||||
def register_docstring(self, module_sha1: str, symbol: str, doc: str) -> None:
|
||||
"""登记 docstring(key="{module_sha1}.{symbol}"),查重幂等"""
|
||||
if module_sha1 is None or symbol is None or doc is None:
|
||||
return
|
||||
if string.strlen(doc) == 0:
|
||||
return
|
||||
if module_sha1 is None or symbol is None or doc is None: return
|
||||
if string.strlen(doc) == 0: return
|
||||
if self.DocKeys is None:
|
||||
self.DocKeys = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_KEY_SZ)
|
||||
self.DocValues = CompilerFactory.get_perm_pool().alloc(DOC_MAX * DOC_VAL_SZ)
|
||||
if self.DocKeys is None or self.DocValues is None:
|
||||
return
|
||||
self.DocKeys = CompilerFactory.factory.PermPool.alloc(DOC_MAX * DOC_KEY_SZ)
|
||||
self.DocValues = CompilerFactory.factory.PermPool.alloc(DOC_MAX * DOC_VAL_SZ)
|
||||
if self.DocKeys is None or self.DocValues is None: return
|
||||
string.memset(self.DocKeys, 0, DOC_MAX * DOC_KEY_SZ)
|
||||
string.memset(self.DocValues, 0, DOC_MAX * DOC_VAL_SZ)
|
||||
if self.DocCount >= DOC_MAX:
|
||||
return
|
||||
ml: t.CSizeT = string.strlen(module_sha1)
|
||||
sl: t.CSizeT = string.strlen(symbol)
|
||||
if self.DocCount >= DOC_MAX: return
|
||||
ml: sizet = string.strlen(module_sha1)
|
||||
sl: sizet = string.strlen(symbol)
|
||||
key_buf: bytes = stdlib.malloc(ml + sl + 2)
|
||||
if key_buf is None:
|
||||
return
|
||||
if key_buf is None: return
|
||||
viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol)
|
||||
i: int
|
||||
for i in range(self.DocCount):
|
||||
if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0:
|
||||
stdlib.free(key_buf)
|
||||
@@ -103,86 +75,75 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
stdlib.free(key_buf)
|
||||
def lookup_docstring(self, module_sha1: str, symbol: str) -> str:
|
||||
"""查找 docstring 内容(key="{module_sha1}.{symbol}"),未找到返回 None"""
|
||||
if self.DocKeys is None or module_sha1 is None or symbol is None:
|
||||
return None
|
||||
ml: t.CSizeT = string.strlen(module_sha1)
|
||||
sl: t.CSizeT = string.strlen(symbol)
|
||||
if self.DocKeys is None or module_sha1 is None or symbol is None: return None
|
||||
ml: sizet = string.strlen(module_sha1)
|
||||
sl: sizet = string.strlen(symbol)
|
||||
key_buf: bytes = stdlib.malloc(ml + sl + 2)
|
||||
if key_buf is None:
|
||||
return None
|
||||
if key_buf is None: return None
|
||||
viperlib.snprintf(key_buf, ml + sl + 2, "%s.%s", module_sha1, symbol)
|
||||
i: int
|
||||
for i in range(self.DocCount):
|
||||
if string.strcmp(self.DocKeys + i * DOC_KEY_SZ, key_buf) == 0:
|
||||
stdlib.free(key_buf)
|
||||
return self.DocValues + i * DOC_VAL_SZ
|
||||
stdlib.free(key_buf)
|
||||
return None
|
||||
def extract_module_docstrings(self, tree: ast.AST | t.CPtr, module_sha1: str) -> None:
|
||||
def extract_module_docstrings(self, tree: ast.AST*, module_sha1: str) -> None:
|
||||
"""扫描模块 AST:登记模块级函数/类/方法的 docstring(幂等)"""
|
||||
if tree is None or module_sha1 is None:
|
||||
return
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is None:
|
||||
return
|
||||
cn: t.CSizeT = len(ch)
|
||||
if tree is None or module_sha1 is None: return
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is None: return
|
||||
cn: sizet = len(ch)
|
||||
for ci in range(cn):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
child: ast.AST* = ch.get(ci)
|
||||
if child is None: continue
|
||||
kd: int = child.kind()
|
||||
if kd == ast.ASTKind.FunctionDef:
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||||
fd: ast.FunctionDef* = ast.FunctionDef*(child)
|
||||
if fd is not None and fd.name is not None:
|
||||
fd_body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
|
||||
fd_body: list[ast.AST*]* = fd.children
|
||||
fdoc: str = self._extract_docstring_from_body(fd_body)
|
||||
if fdoc is not None:
|
||||
self.register_docstring(module_sha1, fd.name, fdoc)
|
||||
elif kd == ast.ASTKind.ClassDef:
|
||||
cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
|
||||
if cd is None or cd.name is None:
|
||||
continue
|
||||
cd_body0: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
cd: ast.ClassDef* = ast.ClassDef*(child)
|
||||
if cd is None or cd.name is None: continue
|
||||
cd_body0: list[ast.AST*]* = cd.children
|
||||
cdoc: str = self._extract_docstring_from_body(cd_body0)
|
||||
if cdoc is not None:
|
||||
self.register_docstring(module_sha1, cd.name, cdoc)
|
||||
# 类方法 docstring(key="{ClassName}.{method}")
|
||||
cd_body: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
cd_body: list[ast.AST*]* = cd.children
|
||||
if cd_body is not None:
|
||||
cbn: t.CSizeT = len(cd_body)
|
||||
cbn: sizet = len(cd_body)
|
||||
for mi in range(cbn):
|
||||
m: ast.AST | t.CPtr = cd_body.get(mi)
|
||||
if m is None or m.kind() != ast.ASTKind.FunctionDef:
|
||||
continue
|
||||
mfd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(m)
|
||||
if mfd is None or mfd.name is None:
|
||||
continue
|
||||
m: ast.AST* = cd_body.get(mi)
|
||||
if m is None or m.kind() != ast.ASTKind.FunctionDef: continue
|
||||
mfd: ast.FunctionDef* = ast.FunctionDef*(m)
|
||||
if mfd is None or mfd.name is None: continue
|
||||
mdoc: str = self._extract_docstring_from_body(mfd.children)
|
||||
if mdoc is not None:
|
||||
cl_nl: t.CSizeT = string.strlen(cd.name)
|
||||
mt_nl: t.CSizeT = string.strlen(mfd.name)
|
||||
cl_nl: sizet = string.strlen(cd.name)
|
||||
mt_nl: sizet = string.strlen(mfd.name)
|
||||
sym_buf: bytes = stdlib.malloc(cl_nl + mt_nl + 2)
|
||||
if sym_buf is not None:
|
||||
viperlib.snprintf(sym_buf, cl_nl + mt_nl + 2, "%s.%s", cd.name, mfd.name)
|
||||
self.register_docstring(module_sha1, sym_buf, mdoc)
|
||||
stdlib.free(sym_buf)
|
||||
def _resolve_doc_symbol_name(self, trans: HT.Translator | t.CPtr, name_id: str,
|
||||
def _resolve_doc_symbol_name(self, trans: HT.Translator*, name_id: str,
|
||||
out_mod: str, out_sym: str) -> int:
|
||||
"""解析 Name 符号的 docstring 归属,写入 out_mod/out_sym,成功返回 1
|
||||
|
||||
判定顺序:本地变量(函数变量)→ 结构体类(含跨模块预注册)→ 模块名。
|
||||
"""
|
||||
if trans is None or name_id is None or out_mod is None or out_sym is None:
|
||||
return 0
|
||||
if trans.ModuleSha1 is None:
|
||||
return 0
|
||||
if trans is None or name_id is None or out_mod is None or out_sym is None: return 0
|
||||
if trans.ModuleSha1 is None: return 0
|
||||
# 1. 本地变量(函数变量/全局变量)
|
||||
if self.Gen.VarGen.lookup_var(trans.SymTab, name_id) is not None:
|
||||
string.strcpy(out_mod, trans.ModuleSha1)
|
||||
string.strcpy(out_sym, name_id)
|
||||
return 1
|
||||
# 2. 结构体类(entry.ModuleSha1 区分跨模块预注册的类)
|
||||
se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(name_id)
|
||||
se: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(name_id)
|
||||
if se is not None:
|
||||
if se.ModuleSha1 is not None:
|
||||
string.strcpy(out_mod, se.ModuleSha1)
|
||||
@@ -203,8 +164,8 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
string.strcpy(out_mod, trans.ModuleSha1)
|
||||
string.strcpy(out_sym, name_id)
|
||||
return 1
|
||||
def _resolve_doc_symbol_attr(self, trans: HT.Translator | t.CPtr,
|
||||
at: ast.Attribute | t.CPtr,
|
||||
def _resolve_doc_symbol_attr(self, trans: HT.Translator*,
|
||||
at: ast.Attribute*,
|
||||
out_mod: str, out_sym: str) -> int:
|
||||
"""解析嵌套 Attribute 链的 docstring 归属,写入 out_mod/out_sym
|
||||
|
||||
@@ -212,28 +173,24 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
remote.RemoteClass.remote_method / LocalClass.local_method 等。
|
||||
最左 Name 判定:模块名 → 该模块 sha1;变量/类 → 类所属模块 sha1。
|
||||
"""
|
||||
if trans is None or at is None or out_mod is None or out_sym is None:
|
||||
return 0
|
||||
if trans.ModuleSha1 is None:
|
||||
return 0
|
||||
if trans is None or at is None or out_mod is None or out_sym is None: return 0
|
||||
if trans.ModuleSha1 is None: return 0
|
||||
# 收集 Attribute 链(最外层 attr 在前)
|
||||
DOC_CHAIN_MAX: t.CInt = 8
|
||||
DOC_CHAIN_MAX: int = 8
|
||||
items: bytes = stdlib.malloc(DOC_CHAIN_MAX * 128)
|
||||
if items is None:
|
||||
return 0
|
||||
if items is None: return 0
|
||||
n_items: int = 0
|
||||
cur: ast.AST | t.CPtr = (ast.AST | t.CPtr)(at)
|
||||
cur: ast.AST* = (ast.AST*)(at)
|
||||
while cur is not None and cur.kind() == ast.ASTKind.Attribute and n_items < DOC_CHAIN_MAX:
|
||||
cat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cur)
|
||||
if cat.attr is None:
|
||||
break
|
||||
cat: ast.Attribute* = ast.Attribute*(cur)
|
||||
if cat.attr is None: break
|
||||
string.strcpy(items + n_items * 128, cat.attr)
|
||||
n_items += 1
|
||||
cur = cat.value
|
||||
# 最左应为 Name
|
||||
head_id: str = None
|
||||
if cur is not None and cur.kind() == ast.ASTKind.Name:
|
||||
hnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cur)
|
||||
hnm: ast.Name* = ast.Name*(cur)
|
||||
head_id = hnm.id
|
||||
if head_id is None:
|
||||
stdlib.free(items)
|
||||
@@ -254,8 +211,7 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
string.strcpy(out_sym, head_id)
|
||||
stdlib.free(items)
|
||||
return 1
|
||||
total: t.CSizeT = 0
|
||||
j: int
|
||||
total: sizet = 0
|
||||
for j in range(n_items):
|
||||
total += string.strlen(items + j * 128) + 1
|
||||
sym_buf: bytes = stdlib.malloc(total + 1)
|
||||
@@ -273,7 +229,7 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
stdlib.free(items)
|
||||
return 1
|
||||
# 变量/类:symbol = head_id + '.' + items 反转
|
||||
total2: t.CSizeT = string.strlen(head_id)
|
||||
total2: sizet = string.strlen(head_id)
|
||||
for j in range(n_items):
|
||||
total2 += string.strlen(items + j * 128) + 1
|
||||
sym2: bytes = stdlib.malloc(total2 + 1)
|
||||
@@ -285,7 +241,7 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
for j in range(n_items):
|
||||
string.strcat(sym2, ".")
|
||||
string.strcat(sym2, items + (n_items - 1 - j) * 128)
|
||||
se2: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(head_id)
|
||||
se2: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(head_id)
|
||||
if se2 is not None and se2.ModuleSha1 is not None:
|
||||
string.strcpy(out_mod, se2.ModuleSha1)
|
||||
else:
|
||||
@@ -310,39 +266,30 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
# Attribute → 字段注解类名(_resolve_attr_field_class)
|
||||
# 仅采用已注册结构体;无法精确推断返回 None(fail-fast 由调用方暴露)。
|
||||
# ============================================================
|
||||
def infer_expr_class(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> str:
|
||||
def infer_expr_class(self, pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
node: ast.AST*,
|
||||
trans: HT.Translator*) -> str:
|
||||
"""从表达式推断结构体类名,无法推断返回 None"""
|
||||
if node is None or trans is None:
|
||||
return None
|
||||
if node is None or trans is None: return None
|
||||
k: int = node.kind()
|
||||
# Call: 类实例化 / 方法调用
|
||||
if k == ast.ASTKind.Call:
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl is None or cl.func is None:
|
||||
return None
|
||||
cl: ast.Call* = ast.Call*(node)
|
||||
if cl is None or cl.func is None: return None
|
||||
if cl.func.kind() == ast.ASTKind.Name:
|
||||
cand: str = ((ast.Name | t.CPtr)(cl.func)).id
|
||||
if cand is None:
|
||||
return None
|
||||
if self.Gen.StructGen.find_struct(cand) is not None:
|
||||
return cand
|
||||
cand: str = (ast.Name*(cl.func)).id
|
||||
if cand is None: return None
|
||||
if self.Gen.StructGen.find_struct(cand) is not None: return cand
|
||||
return None
|
||||
if cl.func.kind() == ast.ASTKind.Attribute:
|
||||
# 方法调用 a.cross(b):vpi 返回注解缓存精确解析返回类名
|
||||
# (方法可返回非同类对象,如 Transform.world_position → 'Vec3')。
|
||||
ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if ca is None or ca.attr is None or ca.value is None:
|
||||
return None
|
||||
ca: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
if ca is None or ca.attr is None or ca.value is None: return None
|
||||
# 模块级函数调用(Module.func()):接收者是已导入模块名而非类对象
|
||||
# (CompilerFactory.get_perm_pool())。返回注解可能是联合类型
|
||||
# (memhub.MemBuddy | t.CPtr),查 vpi 模块函数返回注解(cls=None)
|
||||
# 提取返回类,解决链式方法调用 .alloc() 推断失败退化裸名 @alloc
|
||||
# (链接 undefined symbol: alloc 根因)。
|
||||
if ca.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm2: str = ((ast.Name | t.CPtr)(ca.value)).id
|
||||
mod_nm2: str = (ast.Name*(ca.value)).id
|
||||
if mod_nm2 is not None and trans._from_imports is not None:
|
||||
mod_sha1_2: str = self.Gen.CallGenBase._lookup_mod_sha1(
|
||||
pool, trans._from_imports, mod_nm2)
|
||||
@@ -359,10 +306,8 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
if ret_cls2 is not None:
|
||||
return ret_cls2
|
||||
obj_cls: str = self.infer_expr_class(pool, mod, ca.value, trans)
|
||||
if obj_cls is None:
|
||||
return None
|
||||
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0:
|
||||
return None
|
||||
if obj_cls is None: return None
|
||||
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: return None
|
||||
cls_sha1: str = self.Gen.StructGen.get_struct_sha1(obj_cls)
|
||||
if cls_sha1 is None and trans.ModuleSha1 is not None:
|
||||
cls_sha1 = trans.ModuleSha1
|
||||
@@ -374,24 +319,19 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
temp_dir = self.Gen.CallGenBase.TempDir
|
||||
if temp_dir is not None:
|
||||
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir)
|
||||
annot_ret: str = VpiReader._lookup_vpi_ret_annot(
|
||||
cls_sha1, obj_cls, ca.attr)
|
||||
annot_ret: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, obj_cls, ca.attr)
|
||||
if annot_ret is not None:
|
||||
ret_cls = self._extract_annot_class_name(pool, annot_ret)
|
||||
return ret_cls
|
||||
return None
|
||||
# Name: 源变量注解
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm is None or nm.id is None:
|
||||
return None
|
||||
ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, nm.id)
|
||||
if ve is None:
|
||||
return None
|
||||
acn_n: str = ve.AnnotClassName
|
||||
if acn_n is None:
|
||||
return None
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm is None or nm.id is None: return None
|
||||
ve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||||
if ve is None: return None
|
||||
acn_n: str = self.Gen.VarGen.var_annot_class_name(ve)
|
||||
if acn_n is None: return None
|
||||
# 去模块前缀:json.JsonValue → JsonValue。AnnotClassName 可能带
|
||||
# 模块限定(extract_class_name_from_annotation 的 Attribute 分支返回
|
||||
# "memhub.MemBuddy" 形式),而 find_struct/_cls_has_dunder/
|
||||
@@ -403,26 +343,20 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
return acn_n
|
||||
# BinOp/UnaryOp: 运算符重载返回同类对象
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
if bop is None or bop.left is None:
|
||||
return None
|
||||
bop: ast.BinOp* = ast.BinOp*(node)
|
||||
if bop is None or bop.left is None: return None
|
||||
dunder: str = self.Gen.ExprGenOps._binop_to_dunder(bop.op)
|
||||
if dunder is None:
|
||||
return None
|
||||
if dunder is None: return None
|
||||
lhs_cls: str = self.infer_expr_class(pool, mod, bop.left, trans)
|
||||
if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0:
|
||||
return None
|
||||
if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: return None
|
||||
return lhs_cls
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||||
if uop is None or uop.operand is None:
|
||||
return None
|
||||
uop: ast.UnaryOp* = ast.UnaryOp*(node)
|
||||
if uop is None or uop.operand is None: return None
|
||||
dunder: str = self.Gen.ExprGenOps._unaryop_to_dunder(uop.op)
|
||||
if dunder is None:
|
||||
return None
|
||||
if dunder is None: return None
|
||||
opr_cls: str = self.infer_expr_class(pool, mod, uop.operand, trans)
|
||||
if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0:
|
||||
return None
|
||||
if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: return None
|
||||
return opr_cls
|
||||
# Attribute: 字段注解类名(属性链递归,如 p = r.origin)
|
||||
if k == ast.ASTKind.Attribute:
|
||||
@@ -435,23 +369,18 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
# SHA1(stub 中声明)即视为存在。仅在确实存在时采用推断类名,
|
||||
# 避免把原生运算误标为类类型。
|
||||
# ============================================================
|
||||
def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
class_name: str, dunder: str) -> int:
|
||||
def _cls_has_dunder(self, pool: memhub.MemBuddy*, mod: llvmlite.LLVMModule*, class_name: str, dunder: str) -> int:
|
||||
"""类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1"""
|
||||
if class_name is None or dunder is None or mod is None:
|
||||
return 0
|
||||
if class_name is None or dunder is None or mod is None: return 0
|
||||
lookup_name: str = pool.alloc(128)
|
||||
if lookup_name is None:
|
||||
return 0
|
||||
if lookup_name is None: return 0
|
||||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
|
||||
if self.Gen.CallGenBase.find_func_in_module(mod, lookup_name) is not None:
|
||||
return 1
|
||||
if self.Gen.CallGenBase.find_func_in_module(mod, lookup_name) is not None: return 1
|
||||
# 继承链祖先查找
|
||||
mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||||
mro_ptr: sizet* = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||||
mi: int = 1
|
||||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||||
anc: str = rawptr(mro_ptr[mi])
|
||||
if anc is not None:
|
||||
anc_lookup: str = pool.alloc(128)
|
||||
if anc_lookup is not None:
|
||||
@@ -460,8 +389,7 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
return 1
|
||||
mi += 1
|
||||
# 跨模块:类有 SHA1(stub 中声明该方法)视为存在
|
||||
if self.Gen.StructGen.get_struct_sha1(class_name) is not None:
|
||||
return 1
|
||||
if self.Gen.StructGen.get_struct_sha1(class_name) is not None: return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _extract_annot_class_name - 从返回注解文本提取结构体类名
|
||||
@@ -471,28 +399,28 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
# CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合
|
||||
# 多候选时取首个命中段。
|
||||
# ============================================================
|
||||
def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
annot: str) -> str:
|
||||
def _extract_annot_class_name(self, pool: memhub.MemBuddy*, annot: str) -> str:
|
||||
"""从返回注解文本提取已注册结构体类名,无命中返回 None"""
|
||||
if pool is None or annot is None:
|
||||
return None
|
||||
alen: t.CSizeT = string.strlen(annot)
|
||||
if alen == 0:
|
||||
return None
|
||||
if pool is None or annot is None: return None
|
||||
alen: sizet = string.strlen(annot)
|
||||
if alen == 0: return None
|
||||
seg: str = pool.alloc(256)
|
||||
if seg is None:
|
||||
return None
|
||||
start: t.CSizeT = 0
|
||||
i: t.CSizeT
|
||||
if seg is None: return None
|
||||
start: sizet = 0
|
||||
i: sizet
|
||||
for i in range(alen):
|
||||
if annot[i] == '|':
|
||||
s: t.CSizeT = start
|
||||
e: t.CSizeT = i
|
||||
s: sizet = start
|
||||
e: sizet = i
|
||||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||||
s += 1
|
||||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
|
||||
# 段尾另需剥 '*':实参归一后段文本是 `{sha}.AST*`(旧形态
|
||||
# `{sha}.AST | t.CPtr` 按 '|' 分段能落到 `{sha}.AST` 命中),与
|
||||
# ExprGenName._list_elem_obj_ty_from_struct_name 的尾剔除同口径;
|
||||
# 不剥则 find_struct 落空 → 返回 None → 链式 .get(0).kind() 分派退化。
|
||||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"' or annot[e - 1] == '*'):
|
||||
e -= 1
|
||||
seglen: t.CSizeT = e - s
|
||||
seglen: sizet = e - s
|
||||
if seglen > 0 and seglen < 256:
|
||||
string.strncpy(seg, annot + s, seglen)
|
||||
seg[seglen] = '\0'
|
||||
@@ -507,13 +435,17 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
return seg_bare2
|
||||
start = i + 1
|
||||
# 最后一段(无 '|' 后缀)
|
||||
s: t.CSizeT = start
|
||||
e: t.CSizeT = alen
|
||||
s: sizet = start
|
||||
e: sizet = alen
|
||||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||||
s += 1
|
||||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
|
||||
# 段尾另需剥 '*':实参归一后段文本是 `{sha}.AST*`(旧形态
|
||||
# `{sha}.AST | t.CPtr` 按 '|' 分段能落到 `{sha}.AST` 命中),与
|
||||
# ExprGenName._list_elem_obj_ty_from_struct_name 的尾剔除同口径;
|
||||
# 不剥则 find_struct 落空 → 返回 None → 链式 .get(0).kind() 分派退化。
|
||||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"' or annot[e - 1] == '*'):
|
||||
e -= 1
|
||||
seglen: t.CSizeT = e - s
|
||||
seglen: sizet = e - s
|
||||
if seglen > 0 and seglen < 256:
|
||||
string.strncpy(seg, annot + s, seglen)
|
||||
seg[seglen] = '\0'
|
||||
@@ -1,4 +1,3 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
@@ -8,49 +7,35 @@ import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.core.Gen.Translator as HT
|
||||
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenConst - ExprGenMixin 拆分(阶段 D):常量/全局字符串/list 字面量翻译
|
||||
#
|
||||
# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
novirtual class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
"""常量/全局字符串/list 字面量翻译"""
|
||||
|
||||
# ============================================================
|
||||
# 创建全局字符串常量
|
||||
# ============================================================
|
||||
def create_global_string(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
def create_global_string(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
str_val: str,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""创建全局字符串常量并返回 i8* bitcast"""
|
||||
escaped: str = self.escape_llvm_string(pool, str_val)
|
||||
if escaped is None:
|
||||
return None
|
||||
if escaped is None: return None
|
||||
|
||||
slen: t.CSizeT = string.strlen(str_val)
|
||||
slen: sizet = string.strlen(str_val)
|
||||
count: int = slen + 1
|
||||
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count)
|
||||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
arr_ty: llvmlite.LLVMType* = llvmlite.Array(pool, i8_ty, count)
|
||||
|
||||
# 使用模块级计数器(trans._label_counter)避免跨函数命名冲突
|
||||
str_idx: int = trans._label_counter
|
||||
@@ -65,7 +50,7 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
else:
|
||||
viperlib.snprintf(gv_name, 48, ".str.%d", str_idx)
|
||||
|
||||
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty)
|
||||
gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, gv_name, arr_ty)
|
||||
if gv is None:
|
||||
return None
|
||||
llvmlite.module_add_global(mod, gv)
|
||||
@@ -77,70 +62,69 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
gv.Linkage = "internal"
|
||||
gv.Initializer = escaped
|
||||
|
||||
arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty)
|
||||
arr_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, arr_ty)
|
||||
gv_ref_name: str = pool.alloc(64)
|
||||
if gv_ref_name is None:
|
||||
return None
|
||||
viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name)
|
||||
gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name)
|
||||
gv_ref: llvmlite.Value* = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name)
|
||||
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty)
|
||||
bc: llvmlite.Value* = llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty)
|
||||
return bc
|
||||
# ============================================================
|
||||
# 翻译常量表达式
|
||||
# ============================================================
|
||||
def translate_constant(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
def translate_constant(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
node: ast.AST*,
|
||||
trans: HT.Translator* = None,
|
||||
target_ty: llvmlite.LLVMType* = None) -> llvmlite.Value*:
|
||||
"""翻译常量(int/str/bool)"""
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
cn: ast.Constant* = ast.Constant*(node)
|
||||
if cn is None:
|
||||
return None
|
||||
ck: int = cn.const_kind
|
||||
if cn.const_kind == ast.CONST_INT:
|
||||
# 超出 i32 范围则用 i64(避免常量创建时被截断)
|
||||
iv: t.CInt64T = cn.int_val
|
||||
# 位宽选择:
|
||||
# 1) 目标上下文是 >32 位整数时直接取 i64 —— 必需:词法层 atoll 把
|
||||
# `0xFFFFFFFFFFFFFFFF` 按有符号 int64 回绕成 -1,仅按"是否超出
|
||||
# i32 范围"判定会把它物化成 i32 -1,随后强转路径 zext 到 i64
|
||||
# → 0x00000000FFFFFFFF(N1:THREAD_CREATE 失败码错)。
|
||||
# const_int 按十进制值打印,故 i64 -1 即全 1,语义正确。
|
||||
# 2) 否则维持旧规则:超出 i32 范围用 i64,其余 i32。
|
||||
iv: int64 = cn.int_val
|
||||
if target_ty is not None and self.is_ptr_type(target_ty) == 0 \
|
||||
and self.get_llvm_type_bits(target_ty) > 32:
|
||||
return llvmlite.const_int64(pool, iv)
|
||||
if iv > 2147483647 or iv < -2147483648:
|
||||
return llvmlite.const_int64(pool, iv)
|
||||
return llvmlite.const_int32(pool, iv)
|
||||
elif cn.const_kind == ast.CONST_FLOAT:
|
||||
# 浮点常量默认创建为 double(64 位),赋值时由 coerce_to_type 自动 fptrunc
|
||||
double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||||
double_ty: llvmlite.LLVMType* = llvmlite.Double(pool)
|
||||
return llvmlite.ConstFloat(pool, double_ty, cn.float_val)
|
||||
elif cn.const_kind == ast.CONST_CHAR:
|
||||
# 单引号单字符字面量:默认按字符值(i32,coerce_to_type 截断为 i8)。
|
||||
# 但当目标类型是指针(str/bytes/t.CPtr 等)时,对齐 TPC 引号推断
|
||||
# (HandlesExpr:"目标是 ptr 但值是 char → 走字符串路径"):物化为
|
||||
# 1 字符字符串。否则 coerce inttoptr 把字符值当指针(如 '"'=0x22),
|
||||
# 运行期 strlen 访问低地址 → ASan 崩溃(二代编 StringTest PyI 生成根因)。
|
||||
# 1a 阶段(declare_only=1)不 LoadDepVpi(vpi 未预生成)→ 依赖函数
|
||||
# found_func=None → translate_call 缺省参数补全不生效 → translate_value
|
||||
# 调用参数数 < define(如 target_ty 缺省)→ x64 ABI 被调方读第 9 参
|
||||
# 栈槽残留垃圾(0x4 等)。declare_only 不产出 IR,target_ty 无用,
|
||||
# 未对齐(8 对齐失败)即视为垃圾跳过,避免 is_ptr_type 解引用崩溃
|
||||
# (SlotsBugTest 1a string.vp 崩溃根因;1b found_func 非 None 正常填充)。
|
||||
if target_ty is not None and (t.CUInt64T(target_ty) & 7) == 0 \
|
||||
# 单引号单字符字面量(CONST_CHAR):默认按字符值(i32,coerce 截断为 i8);但当目标类型是指针(str/bytes/t.CPtr)时须物化为 1 字符字符串,否则 coerce inttoptr 把字符值当指针(如 '"'=0x22)→ 运行期 strlen 访问低地址崩溃。1a 阶段(declare_only=1)依赖函数 found_func=None,target_ty 未对齐即视为垃圾跳过,避免 is_ptr_type 解引用崩溃
|
||||
if target_ty is not None and (uint64(target_ty) & 7) == 0 \
|
||||
and self.is_ptr_type(target_ty) != 0:
|
||||
cbuf: bytes = stdlib.malloc(2)
|
||||
if cbuf is None:
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
cbuf[0] = t.CChar(cn.int_val)
|
||||
cbuf[0] = char(cn.int_val)
|
||||
cbuf[1] = '\0'
|
||||
r_cs: llvmlite.Value | t.CPtr = self.create_global_string(builder, pool, mod, cbuf, trans)
|
||||
r_cs: llvmlite.Value* = self.create_global_string(builder, pool, mod, cbuf, trans)
|
||||
stdlib.free(cbuf)
|
||||
return r_cs
|
||||
cv: t.CInt64T = cn.int_val
|
||||
cv: int64 = cn.int_val
|
||||
return llvmlite.const_int32(pool, cv)
|
||||
elif cn.const_kind == ast.CONST_STR:
|
||||
sv: str = cn.str_val
|
||||
if sv is None:
|
||||
return None
|
||||
r: llvmlite.Value | t.CPtr = self.create_global_string(builder, pool, mod, sv, trans)
|
||||
r: llvmlite.Value* = self.create_global_string(builder, pool, mod, sv, trans)
|
||||
return r
|
||||
elif cn.const_kind == ast.CONST_BOOL:
|
||||
if cn.int_val != 0:
|
||||
@@ -148,13 +132,13 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
return llvmlite.const_int32(pool, 0)
|
||||
elif cn.const_kind == ast.CONST_NONE:
|
||||
# None → i8* null(空指针常量),用于 `p is None` / `p is not None` 比较
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
if i8_ty is None:
|
||||
return None
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||||
if i8_ptr_ty is None:
|
||||
return None
|
||||
rv_none: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||||
rv_none: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||||
return rv_none
|
||||
return None
|
||||
# ============================================================
|
||||
@@ -162,8 +146,8 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
#
|
||||
# 用于 list 字面量 [a, b, c] 的元素类型推断
|
||||
# ============================================================
|
||||
def _infer_elem_type_from_value(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
value: llvmlite.Value | t.CPtr) -> str:
|
||||
def _infer_elem_type_from_value(self, pool: memhub.MemBuddy*,
|
||||
value: llvmlite.Value*) -> str:
|
||||
"""从 LLVM Value 的类型推断 list 元素类型名
|
||||
|
||||
fail-fast:值类型缺失/无法映射时返回 None(调用方携带节点报错终止),
|
||||
@@ -171,7 +155,7 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
"""
|
||||
if value is None or value.Ty is None:
|
||||
return None
|
||||
ty: llvmlite.LLVMType | t.CPtr = value.Ty
|
||||
ty: llvmlite.LLVMType* = value.Ty
|
||||
bits: int = self.get_llvm_type_bits(ty)
|
||||
if bits != 0:
|
||||
if bits == 32:
|
||||
@@ -197,7 +181,7 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
#
|
||||
# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb"
|
||||
# ============================================================
|
||||
def _find_pool_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
def _find_pool_var(self, trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""查找上下文中的 pool 变量,返回 alloca 或 None
|
||||
|
||||
查找顺序: pool → _mbuddy → mbuddy → mb
|
||||
@@ -208,7 +192,7 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
"""
|
||||
if trans is None:
|
||||
return None
|
||||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, "pool")
|
||||
alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, "pool")
|
||||
if alloca is not None:
|
||||
return alloca
|
||||
alloca = self.Gen.VarGen.lookup_var(trans.SymTab, "_mbuddy")
|
||||
@@ -226,26 +210,26 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
# 链接器合并同模板重复特化定义,zeroinitializer 保证编译链接通过。
|
||||
# 运行时若该模块未在入口 main 赋值 _mbuddy(null pool 上动态建 list),
|
||||
# 由真实崩溃暴露(fail-fast 哲学,不掩盖上游未初始化)。
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
if pool is None or trans.Module is None or trans.SymTab is None:
|
||||
return None
|
||||
# 先检查是否已注册到模块作用域(避免重复创建全局变量)
|
||||
existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(trans.SymTab, "_mbuddy")
|
||||
existing: llvmlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, "_mbuddy")
|
||||
if existing is not None:
|
||||
return existing
|
||||
# 创建 i8* 类型(t.CVoid | t.CPtr = i8*)
|
||||
i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb)
|
||||
# 创建 i8* 类型(t.CPtr = i8*)
|
||||
i8_ty_fb: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_fb: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_fb)
|
||||
# 当前模块 mangled 名(@<模块sha1>._mbuddy)
|
||||
mb_name_fb: str = self.Gen.FuncGenBase._mangle_name(trans, "_mbuddy")
|
||||
# 创建 linkonce_odr 定义(可被链接器合并,自给自足保证链接通过)
|
||||
gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mb_name_fb, i8_ptr_ty_fb)
|
||||
gv_ext: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, mb_name_fb, i8_ptr_ty_fb)
|
||||
if gv_ext is not None:
|
||||
gv_ext.Linkage = "linkonce_odr"
|
||||
gv_ext.Initializer = "zeroinitializer"
|
||||
llvmlite.module_add_global(trans.Module, gv_ext)
|
||||
# 创建 Value 引用(@<模块sha1>._mbuddy, 类型为 i8**)
|
||||
i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb)
|
||||
i8_ptr_ptr_ty_fb: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty_fb)
|
||||
ref_name_fb: str = pool.alloc(96)
|
||||
if ref_name_fb is not None:
|
||||
# mangled 名带 SHA1 前缀(数字开头),引用必须加引号(见 make_global_ref)
|
||||
@@ -253,80 +237,63 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
viperlib.snprintf(ref_name_fb, 96, "@\"%s\"", mb_name_fb)
|
||||
else:
|
||||
viperlib.snprintf(ref_name_fb, 96, "@%s", mb_name_fb)
|
||||
gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb)
|
||||
gv_ref_fb: llvmlite.Value* = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb)
|
||||
# 注册到模块作用域,避免重复创建
|
||||
self.Gen.VarGen.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb)
|
||||
return gv_ref_fb
|
||||
# ============================================================
|
||||
# translate_list_literal — 翻译 list 字面量 [a, b, c]
|
||||
#
|
||||
# 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列
|
||||
#
|
||||
# Args:
|
||||
# builder: IRBuilder
|
||||
# pool: 编译器内存池(MemBuddy)
|
||||
# mod: LLVMModule
|
||||
# node: ast.List 节点
|
||||
# elem_type_name: 元素类型名(如 "str", "int"),None 表示从元素推断
|
||||
# trans: Translator 对象
|
||||
#
|
||||
# Returns:
|
||||
# list 对象指针(Ptr(list[T] struct)),None 失败
|
||||
# ============================================================
|
||||
def translate_list_literal(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
# translate_list_literal:把 list 字面量 [a, b, c] 翻译为 list[T](pool) 构造 + append 调用序列。elem_type_name 为元素类型名(如 "str"/"int"),None 表示从元素推断。返回 list 对象指针(Ptr(list[T] struct)),失败返回 None
|
||||
def translate_list_literal(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
node: ast.AST*,
|
||||
elem_type_name: str,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列"""
|
||||
if node is None or trans is None:
|
||||
return None
|
||||
|
||||
list_node: ast.List | t.CPtr = (ast.List | t.CPtr)(node)
|
||||
list_node: ast.List* = ast.List*(node)
|
||||
if list_node is None:
|
||||
return None
|
||||
|
||||
elts: list[ast.AST | t.CPtr] | t.CPtr = list_node.elts
|
||||
elts_count: t.CSizeT = 0
|
||||
elts: list[ast.AST*]* = list_node.elts
|
||||
elts_count: sizet = 0
|
||||
if elts is not None:
|
||||
elts_count = len(elts)
|
||||
|
||||
# 推断元素类型
|
||||
inferred_type_name: str = elem_type_name
|
||||
first_elem_val: llvmlite.Value | t.CPtr = None
|
||||
first_elem_val: llvmlite.Value* = None
|
||||
if inferred_type_name is None:
|
||||
if elts_count > 0:
|
||||
first_elem_node: ast.AST | t.CPtr = elts.get(0)
|
||||
first_elem_node: ast.AST* = elts.get(0)
|
||||
first_elem_val = self.Gen.ExprGen.translate_value(builder, pool, mod, first_elem_node, None, 0, trans)
|
||||
if first_elem_val is None or first_elem_val.Ty is None:
|
||||
# fail-fast:首元素翻译失败/Value 类型缺失,立即终止编译(暴露上游根因)
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError")
|
||||
inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val)
|
||||
if inferred_type_name is None:
|
||||
# fail-fast:首元素 Value 类型无法映射为 list 元素类型,立即终止编译
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(first_elem_node, "list 字面量元素类型推断失败(Value 类型缺失)", "TypeError")
|
||||
else:
|
||||
# 空 list 无元素可推断,保持默认 str(list[str])
|
||||
inferred_type_name = "str"
|
||||
|
||||
# 查找 pool 变量
|
||||
pool_alloca: llvmlite.Value | t.CPtr = self._find_pool_var(trans)
|
||||
pool_alloca: llvmlite.Value* = self._find_pool_var(trans)
|
||||
if pool_alloca is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "list literal requires pool variable in context")
|
||||
return None
|
||||
|
||||
# load pool 变量值(i8*)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
pool_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca)
|
||||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||||
pool_val: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca)
|
||||
if pool_val is None:
|
||||
return None
|
||||
|
||||
# 特化 list[T] 类(elem_size=8:str 是指针,4 会导致双元素重叠损坏)
|
||||
type_args: list[str] | t.CPtr = list[str](pool, 8)
|
||||
type_args: list[str]* = list[str](pool, 8)
|
||||
type_args.append(inferred_type_name)
|
||||
spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_class(trans, "list", type_args)
|
||||
if spec_name is None:
|
||||
@@ -334,18 +301,18 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
return None
|
||||
|
||||
# 查找 struct entry
|
||||
struct_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(spec_name)
|
||||
struct_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(spec_name)
|
||||
if struct_entry is None:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "list literal specialized class not registered")
|
||||
return None
|
||||
struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty
|
||||
struct_ty: llvmlite.LLVMType* = struct_entry.Ty
|
||||
if struct_ty is None:
|
||||
return None
|
||||
|
||||
# alloca 临时 list 空间
|
||||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||||
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
|
||||
tmp: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, struct_ty)
|
||||
if tmp is None:
|
||||
return None
|
||||
|
||||
@@ -353,59 +320,51 @@ class ExprGenConst(ExprGenBase.ExprGenBase):
|
||||
# __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用
|
||||
# (与 _translate_struct_ctor/_translate_generic_ctor_call 保持一致,
|
||||
# 避免为无 __new__ 的类生成过度声明)
|
||||
storage_ptr: llvmlite.Value | t.CPtr = tmp
|
||||
storage_ptr: llvmlite.Value* = tmp
|
||||
has_new_flag: int = 0
|
||||
if struct_entry is not None:
|
||||
has_new_flag = struct_entry.HasNew
|
||||
if has_new_flag != 0:
|
||||
new_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||||
new_args: sizet* = pool.alloc(8 * 32)
|
||||
if new_args is None:
|
||||
return None
|
||||
string.memset(new_args, 0, 8 * 32)
|
||||
new_args[0] = t.CSizeT(pool_val)
|
||||
new_ptr: llvmlite.Value | t.CPtr = self.Gen.CallGenCall._call_method_on_ptr(
|
||||
pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans)
|
||||
new_args[0] = sizet(pool_val)
|
||||
new_ptr: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans)
|
||||
if new_ptr is not None:
|
||||
storage_ptr = new_ptr
|
||||
|
||||
# 调用 __before_init__(storage_ptr)
|
||||
self.Gen.CallGenCall._call_method_on_ptr(
|
||||
pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans)
|
||||
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans)
|
||||
|
||||
# 调用 __init__(storage_ptr, pool_val, elem_size=0)
|
||||
init_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||||
if init_args is None:
|
||||
return None
|
||||
init_args: sizet* = pool.alloc(8 * 32)
|
||||
if init_args is None: return None
|
||||
string.memset(init_args, 0, 8 * 32)
|
||||
init_args[0] = t.CSizeT(pool_val)
|
||||
elem_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
|
||||
init_args[1] = t.CSizeT(elem_size_val)
|
||||
self.Gen.CallGenCall._call_method_on_ptr(
|
||||
pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans)
|
||||
init_args[0] = sizet(pool_val)
|
||||
elem_size_val: llvmlite.Value* = llvmlite.const_int64(pool, 0)
|
||||
init_args[1] = sizet(elem_size_val)
|
||||
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans)
|
||||
|
||||
# 对每个元素调用 append(storage_ptr, elem_val)
|
||||
if elts_count > 0:
|
||||
# 第一个元素可能已经翻译过
|
||||
if first_elem_val is not None:
|
||||
append_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||||
append_args: sizet* = pool.alloc(8 * 32)
|
||||
if append_args is not None:
|
||||
string.memset(append_args, 0, 8 * 32)
|
||||
append_args[0] = t.CSizeT(first_elem_val)
|
||||
self.Gen.CallGenCall._call_method_on_ptr(
|
||||
pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans)
|
||||
append_args[0] = sizet(first_elem_val)
|
||||
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans)
|
||||
|
||||
# 翻译剩余元素
|
||||
i: t.CSizeT = 1
|
||||
while i < elts_count:
|
||||
elem_node_i: ast.AST | t.CPtr = elts.get(i)
|
||||
elem_val_i: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(builder, pool, mod, elem_node_i, None, 0, trans)
|
||||
for i in range(1, elts_count):
|
||||
elem_node_i: ast.AST* = elts.get(i)
|
||||
elem_val_i: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, elem_node_i, None, 0, trans)
|
||||
if elem_val_i is not None:
|
||||
ap_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||||
ap_args: sizet* = pool.alloc(8 * 32)
|
||||
if ap_args is not None:
|
||||
string.memset(ap_args, 0, 8 * 32)
|
||||
ap_args[0] = t.CSizeT(elem_val_i)
|
||||
self.Gen.CallGenCall._call_method_on_ptr(
|
||||
pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans)
|
||||
i += 1
|
||||
ap_args[0] = sizet(elem_val_i)
|
||||
self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans)
|
||||
|
||||
return storage_ptr
|
||||
@@ -4,95 +4,72 @@ import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.core.Gen.Translator as HT
|
||||
|
||||
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||||
|
||||
# ============================================================
|
||||
# f-string 翻译常量(与 ExprGenMixin 保持一致,本地副本避免跨模块
|
||||
# CDefine 查找 bug:ExprGenFstr(F) 在 ExprGenMixin(M) 之前按文件序
|
||||
# 编译时,跨模块 CDefine 全局表未注册 → NameError 未定义)
|
||||
# ============================================================
|
||||
FSTR_BUF_SIZE: t.CDefine = 1024
|
||||
FSTR_SPEC_MAX: t.CDefine = 64
|
||||
FSTR_FMT_MAX: t.CDefine = 64
|
||||
define FSTR_BUF_SIZE = 1024
|
||||
define FSTR_SPEC_MAX = 64
|
||||
define FSTR_FMT_MAX = 64
|
||||
|
||||
# ============================================================
|
||||
# ExprGenFstr - ExprGenMixin 拆分(阶段 D):f-string/格式化值翻译
|
||||
#
|
||||
# 继承 ExprGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
novirtual class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
"""f-string/格式化值翻译"""
|
||||
|
||||
# ============================================================
|
||||
# translate_joined_str - f-string 翻译(对齐 TPC _HandleJoinedStrLlvm)
|
||||
#
|
||||
# f"..."(JoinedStr)→ 拼接字面量与格式说明符 → snprintf 生成 i8*
|
||||
# 栈缓冲。之前 f-string 未翻译导致 print/赋值拿到 NULL 指针
|
||||
# 栈缓冲(每站点独立,线程安全);结果是**函数内临时值,禁止逃逸**
|
||||
# (return / 存字段 / 存全局 由 GenApi.fail_if_fstring_escape 拦;
|
||||
# 需逃逸用 GenApi.escape_fstring_copy 显式拷贝)。
|
||||
# 之前 f-string 未翻译导致 print/赋值拿到 NULL 指针
|
||||
# ("(null)"输出 + printf("%s", 垃圾) 崩溃 0xC0000005)。
|
||||
# ============================================================
|
||||
def translate_joined_str(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""f-string → snprintf 生成 i8* 栈缓冲"""
|
||||
if node is None or builder is None or trans is None:
|
||||
return None
|
||||
js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(node)
|
||||
if js is None or js.values is None:
|
||||
return None
|
||||
def translate_joined_str(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
node: ast.AST*,
|
||||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||||
"""f-string → snprintf 生成 i8* 栈缓冲(函数内临时值,禁止逃逸)"""
|
||||
if node is None or builder is None or trans is None: return None
|
||||
js: rawptr[ast.JoinedStr] = rawptr[ast.JoinedStr](node)
|
||||
if js is None or js.values is None: return None
|
||||
|
||||
# 编译期格式串缓冲(pool 分配)
|
||||
fmt_buf: str = pool.alloc(FSTR_BUF_SIZE)
|
||||
if fmt_buf is None:
|
||||
return None
|
||||
if fmt_buf is None: return None
|
||||
fmt_buf[0] = '\0'
|
||||
|
||||
# 运行时参数链表(Value.Next 链接,与 printf 调用一致)
|
||||
arg_head: llvmlite.Value | t.CPtr = None
|
||||
arg_tail: llvmlite.Value | t.CPtr = None
|
||||
arg_head: llvmlite.Value* = None
|
||||
arg_tail: llvmlite.Value* = None
|
||||
arg_count: int = 0
|
||||
|
||||
parts: list[ast.AST | t.CPtr] | t.CPtr = js.values
|
||||
pn: t.CSizeT = len(parts)
|
||||
parts: list[ast.AST*]* = js.values
|
||||
pn: sizet = len(parts)
|
||||
for pi in range(pn):
|
||||
part: ast.AST | t.CPtr = parts.get(pi)
|
||||
if part is None:
|
||||
continue
|
||||
part: ast.AST* = parts.get(pi)
|
||||
if part is None: continue
|
||||
if part.kind() == ast.ASTKind.Constant:
|
||||
pcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part)
|
||||
pcn: ast.Constant* = ast.Constant*(part)
|
||||
if pcn.const_kind == ast.CONST_STR and pcn.str_val is not None:
|
||||
self._fstr_append_literal(fmt_buf, pcn.str_val)
|
||||
continue
|
||||
if part.kind() != ast.ASTKind.FormattedValue:
|
||||
continue
|
||||
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part)
|
||||
if fv.value is None:
|
||||
continue
|
||||
val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, fv.value, None, 0, trans)
|
||||
continue
|
||||
if part.kind() != ast.ASTKind.FormattedValue: continue
|
||||
fv: rawptr[ast.FormattedValue] = rawptr[ast.FormattedValue](part)
|
||||
if fv.value is None: continue
|
||||
val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fv.value, None, 0, trans)
|
||||
if val is None:
|
||||
# fail-fast:f-string 格式化值翻译失败必须终止编译,绝不在
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||||
continue
|
||||
# 确定 C 格式说明符(format_spec 优先,否则按值类型推断)
|
||||
c_fmt: str = None
|
||||
@@ -107,8 +84,7 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1:
|
||||
string.strcat(fmt_buf, c_fmt)
|
||||
# 转换参数类型(i8/i16→i32、bool→i32、f32→f64)
|
||||
cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value(
|
||||
builder, pool, val, c_fmt, fv.value, trans)
|
||||
cast_val: llvmlite.Value* = self._fstr_cast_value(builder, pool, val, c_fmt, fv.value, trans)
|
||||
if cast_val is None:
|
||||
cast_val = val
|
||||
cast_val.Next = None
|
||||
@@ -120,30 +96,28 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
arg_count += 1
|
||||
|
||||
return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
||||
def translate_formatted_value(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
def translate_formatted_value(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
node: ast.AST*,
|
||||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||||
"""翻译裸 FormattedValue(f"{expr:spec}" 无字面量时解析器返回 FormattedValue 而非 JoinedStr)"""
|
||||
if node is None or builder is None or trans is None:
|
||||
return None
|
||||
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(node)
|
||||
fv: rawptr[ast.FormattedValue] = rawptr[ast.FormattedValue](node)
|
||||
if fv is None or fv.value is None:
|
||||
return None
|
||||
fmt_buf: str = pool.alloc(FSTR_BUF_SIZE)
|
||||
if fmt_buf is None:
|
||||
return None
|
||||
fmt_buf[0] = '\0'
|
||||
arg_head: llvmlite.Value | t.CPtr = None
|
||||
arg_tail: llvmlite.Value | t.CPtr = None
|
||||
arg_head: llvmlite.Value* = None
|
||||
arg_tail: llvmlite.Value* = None
|
||||
arg_count: int = 0
|
||||
val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, fv.value, None, 0, trans)
|
||||
val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, fv.value, None, 0, trans)
|
||||
if val is None:
|
||||
# fail-fast:裸 FormattedValue 翻译失败必须终止编译,绝不在
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式化值翻译失败(表达式返回 None)", "TypeError")
|
||||
else:
|
||||
c_fmt: str = None
|
||||
if fv.format_spec is not None:
|
||||
@@ -155,8 +129,7 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
self.Gen.TypeGenErr.fatal_error(fv.value, "f-string 格式无法推断(值类型缺失)", "TypeError")
|
||||
if string.strlen(fmt_buf) + string.strlen(c_fmt) < FSTR_BUF_SIZE - 1:
|
||||
string.strcat(fmt_buf, c_fmt)
|
||||
cast_val: llvmlite.Value | t.CPtr = self._fstr_cast_value(
|
||||
builder, pool, val, c_fmt, fv.value, trans)
|
||||
cast_val: llvmlite.Value* = self._fstr_cast_value(builder, pool, val, c_fmt, fv.value, trans)
|
||||
if cast_val is None:
|
||||
cast_val = val
|
||||
cast_val.Next = None
|
||||
@@ -164,37 +137,44 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
arg_tail = cast_val
|
||||
arg_count = 1
|
||||
return self._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
||||
def _fstr_finalize(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
def _fstr_finalize(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
fmt_buf: str,
|
||||
arg_head: llvmlite.Value | t.CPtr,
|
||||
arg_tail: llvmlite.Value | t.CPtr,
|
||||
arg_head: llvmlite.Value*,
|
||||
arg_tail: llvmlite.Value*,
|
||||
arg_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""f-string 尾部:全局格式串 + 固定栈缓冲 + snprintf,返回 i8*"""
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""f-string 尾部:全局格式串 + 每站点栈缓冲 + snprintf,返回 i8*(函数内临时值)"""
|
||||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
if fmt_buf is None or fmt_buf[0] == '\0':
|
||||
# 空 f-string(f"")→ 空字符串常量
|
||||
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, "", trans)
|
||||
# 格式串 → 全局字符串常量(i8*)
|
||||
fmt_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.create_global_string(
|
||||
builder, pool, mod, fmt_buf, trans)
|
||||
if fmt_ptr is None:
|
||||
return None
|
||||
# 固定栈缓冲 [FSTR_BUF_SIZE x i8],GEP(0,0) 取 i8*
|
||||
buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE)
|
||||
buf_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, buf_ty)
|
||||
if buf_alloca is None:
|
||||
return None
|
||||
zero_i32: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
buf_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||||
builder, buf_ty, i8_ty, buf_alloca, zero_i32)
|
||||
if buf_ptr is None:
|
||||
return None
|
||||
fmt_ptr: llvmlite.Value* = self.Gen.ExprGenConst.create_global_string(builder, pool, mod, fmt_buf, trans)
|
||||
if fmt_ptr is None: return None
|
||||
# 结果缓冲:**每站点独立栈缓冲**(entry 块 alloca;每次翻译本站点各建一个,
|
||||
# 站点之间不共享 ⇒ 同函数多个 f-string 不再互相覆盖)。
|
||||
#
|
||||
# 语义(用户 2026-09-27 决定):f-string 结果是**当前函数内的临时值**。
|
||||
# · 栈缓冲 ⇒ 线程安全(每个线程各自一份栈帧,同站点并发也不串味)
|
||||
# + 零运行时依赖(内核没有 C-ABI malloc,也不能假设任何分配器);
|
||||
# · 函数返回即失效 ⇒ **禁止逃逸**:return / 存字段 / 存全局 / 存容器一律
|
||||
# 由 GenApi.fail_if_fstring_escape 在翻译期 fail-fast 拦下。历史事故:
|
||||
# 旧实现让调用方把该栈指针 return 出去,再作 %s 喂 snprintf ⇒
|
||||
# ASan stack-buffer-underflow in vsnprintf(READ size 1,栈左红区)。
|
||||
# · 确需逃逸时**显式分配后拷贝**:GenApi.escape_fstring_copy
|
||||
# (stdlib.malloc + string.strcpy);编译器自身的报文构造即此写法
|
||||
# (AssignGenMixin.const_assign_msg)。
|
||||
buf_ty: llvmlite.LLVMType* = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE)
|
||||
buf_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, buf_ty)
|
||||
if buf_alloca is None: return None
|
||||
zero_i32: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||||
buf_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, buf_ty, i8_ty, buf_alloca, zero_i32)
|
||||
if buf_ptr is None: return None
|
||||
# snprintf(buf, FSTR_BUF_SIZE, fmt, args...)
|
||||
size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, FSTR_BUF_SIZE)
|
||||
size_val: llvmlite.Value* = llvmlite.const_int64(pool, FSTR_BUF_SIZE)
|
||||
buf_ptr.Next = size_val
|
||||
size_val.Next = fmt_ptr
|
||||
fmt_ptr.Next = arg_head
|
||||
@@ -205,16 +185,14 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
def _fstr_append_literal(self, fmt_buf: str,
|
||||
lit: str) -> None:
|
||||
"""追加字面量到格式串(% 转义为 %%)"""
|
||||
if fmt_buf is None or lit is None:
|
||||
return
|
||||
cur_len: t.CSizeT = string.strlen(fmt_buf)
|
||||
rem: t.CSizeT = FSTR_BUF_SIZE - 1 - cur_len
|
||||
if rem == 0:
|
||||
return
|
||||
src_len: t.CSizeT = string.strlen(lit)
|
||||
si: t.CSizeT = 0
|
||||
if fmt_buf is None or lit is None: return
|
||||
cur_len: sizet = string.strlen(fmt_buf)
|
||||
rem: sizet = FSTR_BUF_SIZE - 1 - cur_len
|
||||
if rem == 0: return
|
||||
src_len: sizet = string.strlen(lit)
|
||||
si: sizet = 0
|
||||
while si < src_len and rem > 0:
|
||||
ch: t.CChar = lit[si]
|
||||
ch: char = lit[si]
|
||||
if ch == '%':
|
||||
if rem < 2:
|
||||
break
|
||||
@@ -232,14 +210,14 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
"""追加原始字符串(不做 % 转义)"""
|
||||
if fmt_buf is None or s is None:
|
||||
return
|
||||
cur_len: t.CSizeT = string.strlen(fmt_buf)
|
||||
src_len: t.CSizeT = string.strlen(s)
|
||||
cur_len: sizet = string.strlen(fmt_buf)
|
||||
src_len: sizet = string.strlen(s)
|
||||
if cur_len + src_len < FSTR_BUF_SIZE:
|
||||
string.strcpy(fmt_buf + cur_len, s)
|
||||
def _fstr_parse_format_spec(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
spec_node: ast.AST | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
arg_node: ast.AST | t.CPtr) -> str:
|
||||
def _fstr_parse_format_spec(self, pool: memhub.MemBuddy*,
|
||||
spec_node: ast.AST*,
|
||||
val: llvmlite.Value*,
|
||||
arg_node: ast.AST*) -> str:
|
||||
"""Python format_spec → C printf 格式串(pool 分配),无法解析返回 None"""
|
||||
if spec_node is None or pool is None or val is None:
|
||||
return None
|
||||
@@ -250,50 +228,43 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
spec[0] = '\0'
|
||||
sk: int = spec_node.kind()
|
||||
if sk == ast.ASTKind.JoinedStr:
|
||||
jss: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(spec_node)
|
||||
if jss.values is None:
|
||||
return None
|
||||
vn: t.CSizeT = len(jss.values)
|
||||
jss: rawptr[ast.JoinedStr] = rawptr[ast.JoinedStr](spec_node)
|
||||
if jss.values is None: return None
|
||||
vn: sizet = len(jss.values)
|
||||
for vi in range(vn):
|
||||
vpart: ast.AST | t.CPtr = jss.values.get(vi)
|
||||
if vpart is None:
|
||||
continue
|
||||
if vpart.kind() != ast.ASTKind.Constant:
|
||||
return None
|
||||
vcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(vpart)
|
||||
if vcn.const_kind != ast.CONST_STR or vcn.str_val is None:
|
||||
return None
|
||||
vpart: ast.AST* = jss.values.get(vi)
|
||||
if vpart is None: continue
|
||||
if vpart.kind() != ast.ASTKind.Constant: return None
|
||||
vcn: ast.Constant* = ast.Constant*(vpart)
|
||||
if vcn.const_kind != ast.CONST_STR or vcn.str_val is None: return None
|
||||
if string.strlen(spec) + string.strlen(vcn.str_val) < FSTR_SPEC_MAX - 1:
|
||||
string.strcat(spec, vcn.str_val)
|
||||
elif sk == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(spec_node)
|
||||
cn: ast.Constant* = ast.Constant*(spec_node)
|
||||
if cn.const_kind != ast.CONST_STR or cn.str_val is None:
|
||||
return None
|
||||
string.strncpy(spec, cn.str_val, FSTR_SPEC_MAX - 1)
|
||||
else:
|
||||
return None
|
||||
slen: t.CSizeT = string.strlen(spec)
|
||||
if slen == 0:
|
||||
return None
|
||||
else: return None
|
||||
slen: sizet = string.strlen(spec)
|
||||
if slen == 0: return None
|
||||
|
||||
# 2. 逐段解析: [fill]align / sign / # / 0 / width / , / .precision / type
|
||||
pos: t.CSizeT = 0
|
||||
align_char: t.CChar = 0
|
||||
pos: sizet = 0
|
||||
align_char: char = 0
|
||||
if pos < slen:
|
||||
ch0: t.CChar = spec[pos]
|
||||
ch0: char = spec[pos]
|
||||
if ch0 == '<' or ch0 == '>' or ch0 == '^' or ch0 == '=':
|
||||
align_char = ch0
|
||||
pos += 1
|
||||
elif pos + 1 < slen:
|
||||
ch1: t.CChar = spec[pos + 1]
|
||||
ch1: char = spec[pos + 1]
|
||||
if ch1 == '<' or ch1 == '>' or ch1 == '^' or ch1 == '=':
|
||||
align_char = ch1
|
||||
pos += 2
|
||||
c_flags: str = pool.alloc(FSTR_FMT_MAX)
|
||||
c_width: str = pool.alloc(32)
|
||||
c_prec: str = pool.alloc(32)
|
||||
if c_flags is None or c_width is None or c_prec is None:
|
||||
return None
|
||||
if c_flags is None or c_width is None or c_prec is None: return None
|
||||
c_flags[0] = '\0'
|
||||
c_width[0] = '\0'
|
||||
c_prec[0] = '\0'
|
||||
@@ -317,7 +288,7 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
string.strcat(c_flags, "-")
|
||||
# width digits
|
||||
while pos < slen and spec[pos] >= '0' and spec[pos] <= '9':
|
||||
wl: t.CSizeT = string.strlen(c_width)
|
||||
wl: sizet = string.strlen(c_width)
|
||||
if wl < 30:
|
||||
c_width[wl] = spec[pos]
|
||||
c_width[wl + 1] = '\0'
|
||||
@@ -330,7 +301,7 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
string.strcat(c_prec, ".")
|
||||
pos += 1
|
||||
while pos < slen and spec[pos] >= '0' and spec[pos] <= '9':
|
||||
pl: t.CSizeT = string.strlen(c_prec)
|
||||
pl: sizet = string.strlen(c_prec)
|
||||
if pl < 30:
|
||||
c_prec[pl] = spec[pos]
|
||||
c_prec[pl + 1] = '\0'
|
||||
@@ -338,32 +309,28 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
if string.strlen(c_prec) == 1:
|
||||
return None # 只有 '.' 无效
|
||||
# type char
|
||||
fmt_type: t.CChar = 0
|
||||
fmt_type: char = 0
|
||||
if pos < slen:
|
||||
fmt_type = spec[pos]
|
||||
pos += 1
|
||||
if pos != slen:
|
||||
return None # 多余字符无法解析
|
||||
if pos != slen: return None # 多余字符无法解析
|
||||
|
||||
# 3. 长度修饰(按值类型位宽)
|
||||
len_mod: str = pool.alloc(4)
|
||||
if len_mod is None:
|
||||
return None
|
||||
if len_mod is None: return None
|
||||
len_mod[0] = '\0'
|
||||
ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
||||
if ibits == 64:
|
||||
string.strcpy(len_mod, "ll")
|
||||
elif ibits == 32:
|
||||
string.strcpy(len_mod, "l")
|
||||
elif ibits == 16:
|
||||
string.strcpy(len_mod, "h")
|
||||
elif ibits == 8:
|
||||
string.strcpy(len_mod, "hh")
|
||||
# 32 位**不写**长度修饰符(N14):`{x:08X}` 的实参是 i32,此前推导出
|
||||
# `l` → 格式串 `%08lX`(long)与实参宽度不符(LP64 下 printf 按 64 位
|
||||
# 读参 → 变参错位)。与同文件无 spec 路径 `_fstr_infer_c_fmt`(32 位用
|
||||
# `%u/%d`)以及 TPC 侧 HandlesExprFormat.py 保持一致。
|
||||
if ibits == 64: string.strcpy(len_mod, "ll")
|
||||
elif ibits == 16: string.strcpy(len_mod, "h")
|
||||
elif ibits == 8: string.strcpy(len_mod, "hh")
|
||||
|
||||
# 4. 组装 C 格式串
|
||||
out: str = pool.alloc(FSTR_FMT_MAX)
|
||||
if out is None:
|
||||
return None
|
||||
if out is None: return None
|
||||
out[0] = '\0'
|
||||
string.strcat(out, "%")
|
||||
string.strcat(out, c_flags)
|
||||
@@ -417,23 +384,19 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
else:
|
||||
return None
|
||||
return out
|
||||
def _fstr_infer_c_fmt(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
arg_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> str:
|
||||
def _fstr_infer_c_fmt(self, pool: memhub.MemBuddy*,
|
||||
val: llvmlite.Value*,
|
||||
arg_node: ast.AST*,
|
||||
trans: HT.Translator*) -> str:
|
||||
"""无 format_spec 时按值类型推断 C printf 格式(对齐 TPC 无 spec 分支,带 % 前缀)"""
|
||||
if val is None or pool is None:
|
||||
return None
|
||||
if val is None or pool is None: return None
|
||||
out: str = pool.alloc(16)
|
||||
if out is None:
|
||||
return None
|
||||
if out is None: return None
|
||||
out[0] = '\0'
|
||||
ibits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
|
||||
fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty)
|
||||
if ibits == 1:
|
||||
return "%d" # bool
|
||||
if ibits == 8:
|
||||
return "%c" # 字符
|
||||
if ibits == 1: return "%d" # bool
|
||||
if ibits == 8: return "%c" # 字符
|
||||
if ibits != 0:
|
||||
if self.Gen.ExprGenOps._node_type_unsigned(pool, arg_node, trans) != 0:
|
||||
if ibits == 64:
|
||||
@@ -453,29 +416,29 @@ class ExprGenFstr(ExprGenBase.ExprGenBase):
|
||||
# fail-fast:值类型缺失(非整数/浮点/指针),无法推断 C 格式,立即终止编译
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node, "f-string 格式无法推断(值类型缺失)", "TypeError")
|
||||
return None
|
||||
def _fstr_cast_value(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
def _fstr_cast_value(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
val: llvmlite.Value*,
|
||||
c_fmt: str,
|
||||
arg_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
arg_node: ast.AST*,
|
||||
trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)"""
|
||||
if val is None or c_fmt is None:
|
||||
return None
|
||||
# 找格式类型字符(最后一个字母,忽略 l/h 长度修饰)
|
||||
fmt_char: t.CChar = 0
|
||||
flen: t.CSizeT = string.strlen(c_fmt)
|
||||
fi: t.CSizeT = flen
|
||||
fmt_char: char = 0
|
||||
flen: sizet = string.strlen(c_fmt)
|
||||
fi: sizet = flen
|
||||
while fi > 0:
|
||||
fi -= 1
|
||||
ch: t.CChar = c_fmt[fi]
|
||||
ch: char = c_fmt[fi]
|
||||
if ch == '%':
|
||||
break
|
||||
if (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z'):
|
||||
if ch != 'l' and ch != 'h':
|
||||
fmt_char = ch
|
||||
break
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
if fmt_char == 's':
|
||||
return val
|
||||
if fmt_char == 'c':
|
||||
@@ -0,0 +1,127 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import memhub
|
||||
import llvmlite
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# docstring 登记表容量(__doc__ 魔法属性支持)
|
||||
#
|
||||
# DOC_MAX: 登记条目上限(预注册阶段所有 App/includes 文件的
|
||||
# 函数/类/方法 docstring,幂等查重)
|
||||
# DOC_KEY_SZ: key "{module_sha1}.{symbol}" 缓冲宽度
|
||||
# DOC_VAL_SZ: docstring 内容缓冲宽度
|
||||
# ============================================================
|
||||
define DOC_MAX = 512
|
||||
define DOC_KEY_SZ = 192
|
||||
define DOC_VAL_SZ = 4096
|
||||
|
||||
# ============================================================
|
||||
# f-string 翻译常量(对齐 TPC HandlesExprFormat)
|
||||
#
|
||||
# FSTR_BUF_SIZE: 运行时栈缓冲大小(snprintf 结果缓冲)
|
||||
# FSTR_SPEC_MAX: 编译期 format_spec 解析缓冲宽度
|
||||
# FSTR_FMT_MAX: 编译期 C printf 格式串缓冲宽度
|
||||
# ============================================================
|
||||
define FSTR_BUF_SIZE = 1024
|
||||
define FSTR_SPEC_MAX = 64
|
||||
define FSTR_FMT_MAX = 64
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenMixin - 表达式处理 Mixin(对象化 P3)
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenMixin - 表达式/常量/下标/属性访问/运算符
|
||||
# ============================================================
|
||||
novirtual class ExprGenMixin(ExprGenBase.ExprGenBase):
|
||||
"""表达式处理 Mixin(纯方法化迁移,无状态字段)"""
|
||||
|
||||
# ============================================================
|
||||
# 翻译值表达式(RHS 分派)— 模块级版本
|
||||
# ============================================================
|
||||
def translate_value(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
node: ast.AST*,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator* = None,
|
||||
target_ty: llvmlite.LLVMType* = None,
|
||||
use_ctx: str = None) -> llvmlite.Value*:
|
||||
"""翻译值表达式为 LLVM Value(深度守卫包装器,原逻辑见 _translate_value_impl)
|
||||
|
||||
target_ty: 目标类型上下文(如调用形参类型/赋值目标类型),用于单引号
|
||||
单字符字面量(CONST_CHAR)在字符串目标下物化为 1 字符字符串(对齐 TPC)。
|
||||
use_ctx: 使用处**真实站点种类**标签("局部变量注解" / "模块级全局" /
|
||||
"形参" / "返回注解" …),只被 CDefine 使用处宽度不足报文读取;不参与判定。
|
||||
"""
|
||||
if trans is not None:
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "表达式翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
rv: llvmlite.Value* = self._translate_value_impl(builder, pool, mod, node, funcs_ptr, func_count, trans, target_ty, use_ctx)
|
||||
if trans is not None:
|
||||
trans.TranslateDepth -= 1
|
||||
return rv
|
||||
|
||||
def _translate_value_impl(self, builder: llvmlite.IRBuilder*,
|
||||
pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
node: ast.AST*,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator* = None,
|
||||
target_ty: llvmlite.LLVMType* = None,
|
||||
use_ctx: str = None) -> llvmlite.Value*:
|
||||
"""翻译值表达式为 LLVM Value"""
|
||||
if node is None:
|
||||
return None
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
rv: llvmlite.Value* = self.Gen.ExprGenConst.translate_constant(builder, pool, mod, node, trans, target_ty)
|
||||
return rv
|
||||
elif k == ast.ASTKind.Name: return self.Gen.ExprGenName.translate_name_value(builder, pool, node, trans, target_ty, use_ctx)
|
||||
elif k == ast.ASTKind.BinOp: return self.Gen.ExprGenOps.translate_binop(pool, builder, mod, node, trans)
|
||||
elif k == ast.ASTKind.Call: return self.Gen.CallGen.translate_call(pool, builder, mod, node, funcs_ptr, func_count, trans)
|
||||
elif k == ast.ASTKind.Compare: return self.Gen.ExprGenOps.translate_compare(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.UnaryOp: return self.Gen.ExprGenOps.translate_unaryop(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.BoolOp: return self.Gen.ExprGenOps.translate_boolop(builder, pool, mod, node, funcs_ptr, func_count, trans)
|
||||
elif k == ast.ASTKind.Subscript: return self.Gen.ExprGenName.translate_subscript(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Attribute: return self.Gen.ExprGenAttr.translate_attribute(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.List: return self.Gen.ExprGenConst.translate_list_literal(builder, pool, mod, node, None, trans)
|
||||
elif k == ast.ASTKind.IfExp: return self.Gen.ExprGenOps.translate_ifexp(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Lambda: return self.Gen.FuncGen.translate_lambda(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.JoinedStr: return self.Gen.ExprGenFstr.translate_joined_str(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.FormattedValue: return self.Gen.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Await:
|
||||
# 协程 await(TPV-M1):await 目标是 async 函数调用时内联翻译
|
||||
# (子帧创建 + resume 到 DONE + 取子帧 ret 存父帧 await 槽 + 父挂起),
|
||||
# 返回子协程 ret 值(i32)。顶层 await(AnnAssign/Assign 的 value 直接
|
||||
# 是 Await)由 AsyncGen 段翻译特判处理,本分支覆盖表达式上下文中的
|
||||
# await(M1 覆盖有限场景,详见 AsyncGenMixin._emit_await)。
|
||||
aw: rawptr[ast.Await] = rawptr[ast.Await](node)
|
||||
if aw is not None and aw.value is not None and aw.value.kind() == ast.ASTKind.Call:
|
||||
aw_cl: ast.Call* = ast.Call*(aw.value)
|
||||
if aw_cl.func is not None and aw_cl.func.kind() == ast.ASTKind.Name:
|
||||
aw_nm: ast.Name* = ast.Name*(aw_cl.func)
|
||||
if aw_nm.id is not None and trans is not None:
|
||||
if self.Gen.AsyncGen.is_async_func(trans, aw_nm.id) != 0:
|
||||
return self.Gen.AsyncGen._emit_await(builder, pool, mod, trans, aw, aw_nm.id)
|
||||
return None
|
||||
elif k == ast.ASTKind.Starred:
|
||||
# *x 在值上下文(如 printf("%d", *k) 实参):解析器把调用参数位的
|
||||
# '*' 按 Python *args 解包语义归类为 Starred,但 Viper 未实现解包,
|
||||
# 全代码库无调用点使用;按 C 语义视为单目解引用(*ptr → load pointee,
|
||||
# 对齐 UnaryOp(Deref))。构造 Deref UnaryOp 复用既有翻译/错误路径。
|
||||
st: rawptr[ast.Starred] = rawptr[ast.Starred](node)
|
||||
if st is None or st.value is None: return None
|
||||
deref_node: ast.AST* = ast.UnaryOp(pool, ast.OpKind.Deref, st.value)
|
||||
if deref_node is None: return None
|
||||
return self.Gen.ExprGenOps.translate_unaryop(builder, pool, mod, deref_node, trans)
|
||||
return None
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,523 +0,0 @@
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenBase - ExprGenMixin 拆分(阶段 D):表达式基础工具(类型判断/指针层级/coerce)
|
||||
#
|
||||
# 最底层 Base(ExprGenMixin/Const/Fstr/Ops/Cdef/Name/Attr/Cls 均 1 级继承本类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprGenBase:
|
||||
"""表达式基础工具(类型判断/指针层级/coerce)"""
|
||||
|
||||
# --- docstring 登记表字段(__doc__ 魔法属性支持)---
|
||||
Gen: Generator.Generator | t.CPtr
|
||||
DocKeys: bytes
|
||||
DocValues: bytes
|
||||
DocCount: int
|
||||
|
||||
# --- OOM 诊断:跨模块 CDefine 查找调用计数(CONST_INT 参数翻译疑似循环查找) ---
|
||||
DiagCDefineCount: int
|
||||
# --- OOM 诊断:translate_name_value 调用计数(顶层 CDefine 查找 14593 次来源) ---
|
||||
DiagNameValueCount: int
|
||||
# --- OOM 诊断:translate_value 调用计数(CONST_INT 循环调用源定位) ---
|
||||
DiagTranslateValueCount: int
|
||||
# ============================================================
|
||||
# P3 迁移方法(函数体来自 HandlesExpr.vp 模块级函数,
|
||||
# 本模块函数调用改 self.,外部模块调用保留模块前缀)
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 从 AST 节点提取函数名
|
||||
# ============================================================
|
||||
def get_func_name(self, func_node: ast.AST | t.CPtr) -> str:
|
||||
"""从函数节点提取函数名"""
|
||||
if func_node is None:
|
||||
return None
|
||||
k: int = func_node.kind()
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node)
|
||||
return nm.id
|
||||
elif k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node)
|
||||
return at.attr
|
||||
return None
|
||||
# ============================================================
|
||||
# 转义 LLVM IR 字符串字面量
|
||||
# ============================================================
|
||||
def escape_llvm_string(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
src: str) -> str:
|
||||
"""将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """
|
||||
if src is None:
|
||||
return None
|
||||
slen: t.CSizeT = string.strlen(src)
|
||||
alloc_size: t.CSizeT = 4 * slen + 8
|
||||
buf: str = pool.alloc(alloc_size)
|
||||
if buf is None:
|
||||
return None
|
||||
pos: t.CSizeT = 0
|
||||
buf[pos] = 'c'
|
||||
pos += 1
|
||||
buf[pos] = '"'
|
||||
pos += 1
|
||||
for i in range(slen):
|
||||
ch: t.CChar = src[i]
|
||||
if ch == '\0':
|
||||
break
|
||||
if ch == '\"' or ch == '\\' or ch < 0x20:
|
||||
buf[pos] = '\\'
|
||||
pos += 1
|
||||
hi: int = (ch >> 4) & 0xF
|
||||
lo: int = ch & 0xF
|
||||
buf[pos] = Utils.nibble_to_hex_char(hi, 1)
|
||||
pos += 1
|
||||
buf[pos] = Utils.nibble_to_hex_char(lo, 1)
|
||||
pos += 1
|
||||
else:
|
||||
buf[pos] = ch
|
||||
pos += 1
|
||||
buf[pos] = '\\'
|
||||
pos += 1
|
||||
buf[pos] = '0'
|
||||
pos += 1
|
||||
buf[pos] = '0'
|
||||
pos += 1
|
||||
buf[pos] = '"'
|
||||
pos += 1
|
||||
buf[pos] = '\0'
|
||||
return buf
|
||||
# ============================================================
|
||||
# 获取 LLVM 整数类型的位宽
|
||||
# ============================================================
|
||||
def get_llvm_type_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""获取 LLVM 整数类型的位宽,非整数类型返回 0"""
|
||||
if ty is None:
|
||||
return 0
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Int(bits):
|
||||
return bits
|
||||
case _:
|
||||
return 0
|
||||
# ============================================================
|
||||
# 获取 LLVM 浮点类型的位宽
|
||||
# ============================================================
|
||||
def get_llvm_float_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""获取 LLVM 浮点类型的位宽,非浮点类型返回 0"""
|
||||
if ty is None:
|
||||
return 0
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Float(bits):
|
||||
return bits
|
||||
case _:
|
||||
return 0
|
||||
# ============================================================
|
||||
# is_ptr_type - 检查类型是否为 Ptr
|
||||
#
|
||||
# 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。
|
||||
# ============================================================
|
||||
def is_ptr_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""检查 ty 是否是 Ptr 类型,返回 1=是, 0=否"""
|
||||
if ty is None:
|
||||
return 0
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
return 1
|
||||
case _:
|
||||
return 0
|
||||
# ============================================================
|
||||
# get_ptr_level - 计算指针层级
|
||||
#
|
||||
# 返回值:
|
||||
# 0 = 非指针(数值/结构体等)
|
||||
# 1 = 一级指针(如 i8*, Struct*)
|
||||
# 2 = 二级指针(如 i8**, Struct**)
|
||||
# 3+ = 更高级指针
|
||||
#
|
||||
# 用于比较运算的类型安全检查:
|
||||
# - 数值(0) vs 数值(0) → 允许
|
||||
# - 一级指针(1) vs 一级指针(1) → 允许
|
||||
# - 数值(0) vs 指针(1+) → 禁止(fast-fail)
|
||||
# - 不同级指针(1 vs 2) → 禁止(fast-fail)
|
||||
# ============================================================
|
||||
def get_ptr_level(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""计算指针层级,0=非指针, 1=一级指针, 2=二级指针..."""
|
||||
if ty is None:
|
||||
return 0
|
||||
level: int = 0
|
||||
cur: llvmlite.LLVMType | t.CPtr = ty
|
||||
while cur is not None:
|
||||
# 同类编译 bug(见 TypeGenResolve L1463 注释):case body 直接
|
||||
# 更新 while 条件变量(cur = pointee)时自举编译出的 match 把赋值
|
||||
# 写到 subject 快照槽,while 条件读旧槽 → 死循环。改法:case
|
||||
# 绑定到局部变量,match 外更新循环变量。
|
||||
nxt_cur: llvmlite.LLVMType | t.CPtr = None
|
||||
match cur:
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
level += 1
|
||||
nxt_cur = pointee
|
||||
case _:
|
||||
break
|
||||
cur = nxt_cur
|
||||
return level
|
||||
# ============================================================
|
||||
# _is_zero_int_literal - 判断 AST 节点是否为整数字面量 0
|
||||
#
|
||||
# 用于指针判空比较(ptr != 0 / ptr == 0):指针与字面量 0 比较时
|
||||
# 0 视为 NULL,允许并转成 null 指针(比较类型检查的例外)。
|
||||
# ============================================================
|
||||
def _is_zero_int_literal(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""判断节点是否为整数字面量 0,返回 1=是 / 0=否"""
|
||||
if node is None:
|
||||
return 0
|
||||
if node.kind() != ast.ASTKind.Constant:
|
||||
return 0
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
if cn is None or cn.const_kind != ast.CONST_INT:
|
||||
return 0
|
||||
if cn.int_val == 0:
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# is_array_type - 检查类型是否为 Array
|
||||
#
|
||||
# 返回 1=是, 0=否。类型检查工具函数。
|
||||
# ============================================================
|
||||
def is_array_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""检查 ty 是否是 Array 类型,返回 1=是, 0=否"""
|
||||
if ty is None:
|
||||
return 0
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Array(_, _):
|
||||
return 1
|
||||
case _:
|
||||
return 0
|
||||
# ============================================================
|
||||
# _zext_index_to_i32 - 数组下标索引零扩展
|
||||
#
|
||||
# LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30,
|
||||
# 导致数组下标越界读(字节 >= 128 的乱码根因)。
|
||||
# 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。
|
||||
# 仅用于数组 GEP;指针负偏移(p[-1])不经过此路径,不受影响。
|
||||
# ============================================================
|
||||
def _zext_index_to_i32(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""将 <32 位整数下标零扩展到 i32(数组下标非负语义)"""
|
||||
if idx_val is None or idx_val.Ty is None or builder is None:
|
||||
return idx_val
|
||||
idx_bits: int = self.get_llvm_type_bits(idx_val.Ty)
|
||||
if idx_bits != 0 and idx_bits < 32:
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(builder.Pool)
|
||||
return llvmlite.build_zext(builder, idx_val, i32_ty)
|
||||
return idx_val
|
||||
# ============================================================
|
||||
# _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体
|
||||
#
|
||||
# 处理两种情况:
|
||||
# - ty 直接是 Struct → 检查是否注册
|
||||
# - ty 是 Ptr(Struct) → 检查 pointee 是否注册
|
||||
#
|
||||
# 返回类名字符串或 None。用于 subscript 操作中判断是否需要
|
||||
# 转发到 __getitem__/__setitem__ 而非生成 GEP。
|
||||
# ============================================================
|
||||
def _get_custom_struct_cls_nm(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> str:
|
||||
"""检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None"""
|
||||
if ty is None:
|
||||
return None
|
||||
# 直接检查 ty 是否是注册的结构体
|
||||
cls_nm_direct: str = self.Gen.StructGen.get_class_name_by_type(pool, ty)
|
||||
if cls_nm_direct is not None:
|
||||
return cls_nm_direct
|
||||
# 如果 ty 是 Ptr,检查 pointee
|
||||
if self.is_ptr_type(ty) != 0:
|
||||
pointee_cs: llvmlite.LLVMType | t.CPtr = ty.Pointee
|
||||
if pointee_cs is not None:
|
||||
return self.Gen.StructGen.get_class_name_by_type(pool, pointee_cs)
|
||||
return None
|
||||
# ============================================================
|
||||
# _is_list_subscript_base - 判断下标基座是否为 list[T] 变量
|
||||
#
|
||||
# 属性访问的 Subscript 基座(如 lst[i].x)需要区分:
|
||||
# - list[T] 变量:translate_subscript 走 __getitem__ 内联返回元素地址
|
||||
# - 普通结构体指针数组(如 pts: Point | t.CPtr):get_subscript_ptr 返回元素地址
|
||||
# 路由错误会让 list[T] 被当作结构体数组 GEP,访问错位崩溃。
|
||||
# ============================================================
|
||||
def _is_list_subscript_base(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
sub_node: ast.AST | t.CPtr) -> int:
|
||||
"""判断下标基座是否为 list[T] 变量(1=是)"""
|
||||
if sub_node is None or trans is None:
|
||||
return 0
|
||||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node)
|
||||
if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||||
if nm.id is None:
|
||||
return 0
|
||||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
if alloca is None or alloca.Ty is None:
|
||||
return 0
|
||||
if self.is_ptr_type(alloca.Ty) == 0:
|
||||
return 0
|
||||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
if pointee is None:
|
||||
return 0
|
||||
match pointee:
|
||||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||||
lsn_ls: str = None
|
||||
match inner_ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, lsn3):
|
||||
lsn_ls = lsn3
|
||||
case _:
|
||||
pass
|
||||
if lsn_ls is not None and string.strstr(lsn_ls, "list[") is not None:
|
||||
return 1
|
||||
case _:
|
||||
pass
|
||||
return 0
|
||||
# ============================================================
|
||||
# _sub_base_class_name - 解析下标基座变量的结构体类名
|
||||
# ============================================================
|
||||
def _sub_base_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
sub_node: ast.AST | t.CPtr) -> str:
|
||||
"""解析下标基座变量的结构体类名(无则 None)"""
|
||||
if sub_node is None or trans is None:
|
||||
return None
|
||||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node)
|
||||
if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name:
|
||||
return None
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||||
if nm.id is None:
|
||||
return None
|
||||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
if alloca is None or alloca.Ty is None:
|
||||
return None
|
||||
if self.is_ptr_type(alloca.Ty) == 0:
|
||||
return None
|
||||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
if pointee is None:
|
||||
return None
|
||||
if self.is_ptr_type(pointee) != 0:
|
||||
inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee
|
||||
if inner is not None:
|
||||
return self.Gen.StructGen.get_class_name_by_type(pool, inner)
|
||||
return self.Gen.StructGen.get_class_name_by_type(pool, pointee)
|
||||
# ============================================================
|
||||
# _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义
|
||||
#
|
||||
# 属性访问的 Subscript 基座路由依据:
|
||||
# - list[T] / OOP 定义 __getitem__ 的类(如 dict[key])→ translate_value
|
||||
# (translate_subscript 走 __getitem__ 内联/方法调用返回元素值或地址)
|
||||
# - 普通结构体指针数组(如 pts: Point | t.CPtr)→ get_subscript_ptr
|
||||
# (GEP 元素地址,避免结构体值 base=非指针 报错)
|
||||
# ============================================================
|
||||
def _sub_base_uses_getitem(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
sub_node: ast.AST | t.CPtr) -> int:
|
||||
"""下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)"""
|
||||
if self._is_list_subscript_base(pool, trans, sub_node) != 0:
|
||||
return 1
|
||||
cls_ugi: str = self._sub_base_class_name(pool, trans, sub_node)
|
||||
if cls_ugi is None:
|
||||
return 0
|
||||
lookup_ugi: str = pool.alloc(128)
|
||||
if lookup_ugi is None:
|
||||
return 0
|
||||
viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi)
|
||||
if self.Gen.CallGenBase.find_func_in_module(mod, lookup_ugi) is not None:
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用
|
||||
#
|
||||
# 用于支持 X|t.CPtr 类型变量的属性访问:
|
||||
# - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用
|
||||
# - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用
|
||||
# ============================================================
|
||||
def _deref_if_ptr_ptr(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针"""
|
||||
if obj_ptr is None or obj_ptr.Ty is None:
|
||||
return obj_ptr
|
||||
if self.is_ptr_type(obj_ptr.Ty) == 0:
|
||||
return obj_ptr
|
||||
pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee
|
||||
if pointee is None:
|
||||
return obj_ptr
|
||||
if self.is_ptr_type(pointee) == 0:
|
||||
return obj_ptr
|
||||
# obj_ptr 是 Ptr(Ptr(...)),load 解引用
|
||||
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr)
|
||||
if loaded is None:
|
||||
return obj_ptr
|
||||
return loaded
|
||||
# ============================================================
|
||||
# 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si
|
||||
# ============================================================
|
||||
def coerce_to_type(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr,
|
||||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""将 val 强制转换为 target_ty
|
||||
|
||||
整数: sext(扩展)/ trunc(截断)
|
||||
浮点: fpext(扩展)/ fptrunc(截断)
|
||||
int→float: sitofp
|
||||
float→int: fptosi
|
||||
|
||||
node: AST 节点(用于错误定位),可为 None
|
||||
"""
|
||||
if val is None or target_ty is None:
|
||||
return val
|
||||
# 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针)
|
||||
# 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理
|
||||
match val.Ty:
|
||||
case llvmlite.LLVMType.Func(_, _, _):
|
||||
if self.is_ptr_type(target_ty) != 0:
|
||||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||||
return val
|
||||
case _:
|
||||
pass
|
||||
# 整数转换
|
||||
val_bits: int = self.get_llvm_type_bits(val.Ty)
|
||||
target_bits: int = self.get_llvm_type_bits(target_ty)
|
||||
# 整数 → 指针: inttoptr(必须在纯整数转换之前检查,因为 ptr 的 bits 非零会误入 sext/trunc 路径)
|
||||
# 适用于: 跨模块方法返回 i64/i32(默认推断),目标变量是指针类型
|
||||
if val_bits != 0 and self.is_ptr_type(target_ty) != 0:
|
||||
return llvmlite.build_inttoptr(builder, val, target_ty)
|
||||
# 指针 → 整数: ptrtoint(当目标明确是整数而非指针时)
|
||||
# 注意: target_bits == 8 时跳过 ptrtoint,走后面的 build_load 解引用首字符
|
||||
# 修复: buf[idx] = '\0' 中 '\0' 是 CONST_STR → i8* 指针,
|
||||
# ptrtoint 会截断地址低 8 位(非 0),应 load 解引用取首字符 0
|
||||
if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and target_bits != 8 and self.is_ptr_type(target_ty) == 0:
|
||||
return llvmlite.build_ptrtoint(builder, val, target_ty)
|
||||
if val_bits != 0 and target_bits != 0:
|
||||
if val_bits == target_bits:
|
||||
return val
|
||||
if val_bits < target_bits:
|
||||
# i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...)
|
||||
# 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致
|
||||
if val_bits == 1:
|
||||
return llvmlite.build_zext(builder, val, target_ty)
|
||||
return llvmlite.build_sext(builder, val, target_ty)
|
||||
return llvmlite.build_trunc(builder, val, target_ty)
|
||||
# 浮点转换
|
||||
val_fbits: int = self.get_llvm_float_bits(val.Ty)
|
||||
target_fbits: int = self.get_llvm_float_bits(target_ty)
|
||||
# float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径)
|
||||
if (val_fbits != 0 and self.is_ptr_type(target_ty) != 0) or \
|
||||
(self.is_ptr_type(val.Ty) != 0 and target_fbits != 0):
|
||||
self.Gen.TypeGenErr.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError")
|
||||
return val
|
||||
if val_fbits != 0 and target_fbits != 0:
|
||||
if val_fbits == target_fbits:
|
||||
return val
|
||||
if val_fbits < target_fbits:
|
||||
return llvmlite.build_fpext(builder, val, target_ty)
|
||||
return llvmlite.build_fptrunc(builder, val, target_ty)
|
||||
# int → float
|
||||
if val_bits != 0 and target_fbits != 0:
|
||||
return llvmlite.build_si2fp(builder, val, target_ty)
|
||||
# float → int
|
||||
if val_fbits != 0 and target_bits != 0:
|
||||
return llvmlite.build_fp2si(builder, val, target_ty)
|
||||
# 指针 → 非指针值: build_load 解引用
|
||||
# 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值
|
||||
# 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load
|
||||
if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) == 0:
|
||||
return llvmlite.build_load(builder, target_ty, val)
|
||||
# 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针)
|
||||
if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) != 0:
|
||||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||||
return val
|
||||
# ============================================================
|
||||
# translate_ptr_arith - 指针算术: ptr + int / ptr - int
|
||||
#
|
||||
# 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC
|
||||
# ExprGen.emit_binary_op / HandlesAugAssign.py。
|
||||
# 旧实现用 ptrtoint + add + inttoptr(按字节加):i8* 元素大小 1
|
||||
# 恰好正确,但 i32*/struct* 等指针 `p + 3` 只前进 3 字节(应 12),
|
||||
# 导致 StringIterTest Test 4/8 失败(指针偏移/指针算术)。
|
||||
#
|
||||
# 数组 pointee([N x ty]*)先 decay 为元素指针(GEP 0,0),
|
||||
# 避免以整个数组为步长(对齐 TPC ExprGen L53-55)。
|
||||
# ============================================================
|
||||
def translate_ptr_arith(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
ptr_val: llvmlite.Value | t.CPtr,
|
||||
int_val: llvmlite.Value | t.CPtr,
|
||||
op: int) -> llvmlite.Value | t.CPtr:
|
||||
"""指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)"""
|
||||
if ptr_val is None or int_val is None or ptr_val.Ty is None:
|
||||
return None
|
||||
# 提取 pointee 类型(非指针 → 不处理返回 None)
|
||||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
match ptr_val.Ty:
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
elem_ty = pointee
|
||||
case _:
|
||||
return None
|
||||
if elem_ty is None:
|
||||
return None
|
||||
# 索引统一到 i64(对齐 TPC zext 到 i64)
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
idx: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, int_val, i64_ty, None)
|
||||
if idx is None:
|
||||
return None
|
||||
# ptr - int → 负索引(LLVM GEP 索引为加法语义)
|
||||
if op == ast.OpKind.Sub:
|
||||
neg_idx: llvmlite.Value | t.CPtr = llvmlite.build_sub(
|
||||
builder, llvmlite.const_int64(pool, 0), idx)
|
||||
if neg_idx is None:
|
||||
return None
|
||||
idx = neg_idx
|
||||
# 数组 pointee → 先 decay 为元素指针(getelementptr [N x ty], [N x ty]* %p, i32 0, i32 0)
|
||||
if self.is_array_type(elem_ty) != 0:
|
||||
inner_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
match elem_ty:
|
||||
case llvmlite.LLVMType.Array(inner, _):
|
||||
inner_ty = inner
|
||||
case _:
|
||||
return None
|
||||
if inner_ty is None:
|
||||
return None
|
||||
decayed: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||||
builder, elem_ty, inner_ty, ptr_val, llvmlite.const_int64(pool, 0))
|
||||
if decayed is None:
|
||||
return None
|
||||
return llvmlite.build_gep(builder, inner_ty, decayed, idx)
|
||||
return llvmlite.build_gep(builder, elem_ty, ptr_val, idx)
|
||||
def InitExprGen(self) -> int:
|
||||
"""初始化 ExprGen 族字段(构造时由 Generator 调用)"""
|
||||
if self is None:
|
||||
return 1
|
||||
self.DocKeys = None
|
||||
self.DocValues = None
|
||||
self.DocCount = 0
|
||||
self.DiagCDefineCount = 0
|
||||
self.DiagNameValueCount = 0
|
||||
self.DiagTranslateValueCount = 0
|
||||
return 0
|
||||
@@ -1,163 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import memhub
|
||||
import string
|
||||
import llvmlite
|
||||
import stdlib
|
||||
import stdio
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# docstring 登记表容量(__doc__ 魔法属性支持)
|
||||
#
|
||||
# DOC_MAX: 登记条目上限(预注册阶段所有 App/includes 文件的
|
||||
# 函数/类/方法 docstring,幂等查重)
|
||||
# DOC_KEY_SZ: key "{module_sha1}.{symbol}" 缓冲宽度
|
||||
# DOC_VAL_SZ: docstring 内容缓冲宽度
|
||||
# ============================================================
|
||||
DOC_MAX: t.CDefine = 512
|
||||
DOC_KEY_SZ: t.CDefine = 192
|
||||
DOC_VAL_SZ: t.CDefine = 4096
|
||||
|
||||
# ============================================================
|
||||
# f-string 翻译常量(对齐 TPC HandlesExprFormat)
|
||||
#
|
||||
# FSTR_BUF_SIZE: 运行时栈缓冲大小(snprintf 结果缓冲)
|
||||
# FSTR_SPEC_MAX: 编译期 format_spec 解析缓冲宽度
|
||||
# FSTR_FMT_MAX: 编译期 C printf 格式串缓冲宽度
|
||||
# ============================================================
|
||||
FSTR_BUF_SIZE: t.CDefine = 1024
|
||||
FSTR_SPEC_MAX: t.CDefine = 64
|
||||
FSTR_FMT_MAX: t.CDefine = 64
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenMixin - 表达式处理 Mixin(对象化 P3,wiki/14-oo-refactor.md)
|
||||
#
|
||||
# 从 HandlesExpr.vp(48 函数,无全局状态)与 HandlesExprOps.vp
|
||||
# 迁移:模块级纯函数 → 类方法(self 替代,参数保留含 builder/pool)。
|
||||
#
|
||||
# 迁移原则(与 P2 一致,行为零变化):
|
||||
# 1. 方法保留原函数签名(含 builder/pool 首参),仅函数体内
|
||||
# 本模块函数调用改为 self.xxx(...)
|
||||
# 2. 外部模块调用(HandlesExprCall.xxx / HandlesType.xxx 等)保留模块前缀
|
||||
# 3. HandlesExpr.vp / HandlesExprOps.vp 原函数保留为"委托":本地
|
||||
# 模块级单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型
|
||||
# 4. ExprHandle 类保留在 HandlesExpr.vp(translator handler 模式)
|
||||
#
|
||||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprGenMixin - 表达式/常量/下标/属性访问/运算符
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprGenMixin(ExprGenBase.ExprGenBase):
|
||||
"""表达式处理 Mixin(纯方法化迁移,无状态字段)"""
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译值表达式(RHS 分派)— 模块级版本
|
||||
# ============================================================
|
||||
def translate_value(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译值表达式为 LLVM Value(深度守卫包装器,原逻辑见 _translate_value_impl)
|
||||
|
||||
target_ty: 目标类型上下文(如调用形参类型/赋值目标类型),用于单引号
|
||||
单字符字面量(CONST_CHAR)在字符串目标下物化为 1 字符字符串(对齐 TPC)。
|
||||
"""
|
||||
if trans is not None:
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, "表达式翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
rv: llvmlite.Value | t.CPtr = self._translate_value_impl(
|
||||
builder, pool, mod, node, funcs_ptr, func_count, trans, target_ty)
|
||||
if trans is not None:
|
||||
trans.TranslateDepth -= 1
|
||||
return rv
|
||||
|
||||
def _translate_value_impl(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译值表达式为 LLVM Value"""
|
||||
if node is None:
|
||||
return None
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Constant:
|
||||
rv: llvmlite.Value | t.CPtr = self.Gen.ExprGenConst.translate_constant(builder, pool, mod, node, trans, target_ty)
|
||||
return rv
|
||||
elif k == ast.ASTKind.Name:
|
||||
return self.Gen.ExprGenName.translate_name_value(builder, pool, node, trans)
|
||||
elif k == ast.ASTKind.BinOp:
|
||||
return self.Gen.ExprGenOps.translate_binop(pool, builder, mod, node, trans)
|
||||
elif k == ast.ASTKind.Call:
|
||||
return self.Gen.CallGen.translate_call(pool, builder, mod, node,
|
||||
funcs_ptr, func_count, trans)
|
||||
elif k == ast.ASTKind.Compare:
|
||||
return self.Gen.ExprGenOps.translate_compare(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.UnaryOp:
|
||||
return self.Gen.ExprGenOps.translate_unaryop(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.BoolOp:
|
||||
return self.Gen.ExprGenOps.translate_boolop(builder, pool, mod, node,
|
||||
funcs_ptr, func_count, trans)
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
return self.Gen.ExprGenName.translate_subscript(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Attribute:
|
||||
return self.Gen.ExprGenAttr.translate_attribute(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.List:
|
||||
return self.Gen.ExprGenConst.translate_list_literal(builder, pool, mod, node, None, trans)
|
||||
elif k == ast.ASTKind.IfExp:
|
||||
return self.Gen.ExprGenOps.translate_ifexp(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Lambda:
|
||||
# 模块级委托:translate_lambda 定义在 FuncGenMixin(跨 Mixin
|
||||
# 方法不能 self. 直接调用,见 HandlesExpr.translate_lambda)
|
||||
return self.Gen.FuncGen.translate_lambda(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.JoinedStr:
|
||||
return self.Gen.ExprGenFstr.translate_joined_str(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.FormattedValue:
|
||||
# 解析器对 f"{expr:spec}"(单 FormattedValue 无字面量)返回裸 FormattedValue
|
||||
# 而非 JoinedStr(见 ast/parser.vp _parse_fstring),需单独翻译
|
||||
return self.Gen.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans)
|
||||
elif k == ast.ASTKind.Await:
|
||||
# 协程 await(TPV-M1):await 目标是 async 函数调用时内联翻译
|
||||
# (子帧创建 + resume 到 DONE + 取子帧 ret 存父帧 await 槽 + 父挂起),
|
||||
# 返回子协程 ret 值(i32)。顶层 await(AnnAssign/Assign 的 value 直接
|
||||
# 是 Await)由 AsyncGen 段翻译特判处理,本分支覆盖表达式上下文中的
|
||||
# await(M1 覆盖有限场景,详见 AsyncGenMixin._emit_await)。
|
||||
aw: ast.Await | t.CPtr = (ast.Await | t.CPtr)(node)
|
||||
if aw is not None and aw.value is not None and aw.value.kind() == ast.ASTKind.Call:
|
||||
aw_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aw.value)
|
||||
if aw_cl.func is not None and aw_cl.func.kind() == ast.ASTKind.Name:
|
||||
aw_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aw_cl.func)
|
||||
if aw_nm.id is not None and trans is not None:
|
||||
if self.Gen.AsyncGen.is_async_func(trans, aw_nm.id) != 0:
|
||||
return self.Gen.AsyncGen._emit_await(
|
||||
builder, pool, mod, trans, aw, aw_nm.id)
|
||||
return None
|
||||
return None
|
||||
@@ -0,0 +1,371 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import lib.core.Gen.Call.CallGenBase as CallGenBase
|
||||
|
||||
# ============================================================
|
||||
# FuncGenBase - FuncGenMixin 拆分(阶段 D):函数属性 / 命名 / mangle / create_function 基础工具
|
||||
# ============================================================
|
||||
novirtual class FuncGenBase(CallGenBase.CallGenBase):
|
||||
"""函数属性 / 命名 / mangle / create_function 基础工具"""
|
||||
|
||||
# ============================================================
|
||||
# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性
|
||||
#
|
||||
# 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式
|
||||
# 也支持 @c.Attribute(t.attr.llvm.xxx) 形式
|
||||
#
|
||||
# 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None
|
||||
# ============================================================
|
||||
def extract_func_attrs(self, pool: memhub.MemBuddy*,
|
||||
decorator_list: list[ast.AST*]*,
|
||||
imported_modules: str) -> str:
|
||||
"""从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串"""
|
||||
if decorator_list is None: return None
|
||||
dn: sizet = len(decorator_list)
|
||||
if dn == 0: return None
|
||||
|
||||
attrs_buf: str = pool.alloc(256)
|
||||
if attrs_buf is None: return None
|
||||
attrs_buf[0] = '\0'
|
||||
found_any: int = 0
|
||||
|
||||
for di in range(dn):
|
||||
deco: ast.AST* = decorator_list.get(di)
|
||||
if deco is None: continue
|
||||
dk: int = deco.kind()
|
||||
# 直接形式 `@t.attr.<name>`(与类侧 ClassGenBase._has_decorator 同口径,
|
||||
# 类定义早就接受两种写法):`inline def f(...)` 合成的就是这一形态,
|
||||
# 且**不要求** import c。此前只认 c.Attribute(...) ⇒ 没有 import c 的文件
|
||||
# 会静默不内联。不支持的属性名由 _append_llvm_attr 返回 0 自然忽略
|
||||
# (如 @t.CVTable / @t.NoVTable / packed / aligned 对函数无意义)。
|
||||
if dk == ast.ASTKind.Attribute:
|
||||
dan: str = self._get_attr_name_from_node(deco)
|
||||
if dan is not None and string.strcmp(dan, "section") != 0:
|
||||
if self._append_llvm_attr(attrs_buf, dan) != 0:
|
||||
found_any = 1
|
||||
continue
|
||||
if dk != ast.ASTKind.Call: continue
|
||||
call_node: ast.Call* = ast.Call*(deco)
|
||||
if call_node.func is None: continue
|
||||
cfk: int = call_node.func.kind()
|
||||
if cfk != ast.ASTKind.Attribute: continue
|
||||
|
||||
# 检测 c.Attribute
|
||||
func_attr: ast.Attribute* = ast.Attribute*(call_node.func)
|
||||
if func_attr.attr is None: continue
|
||||
if string.strcmp(func_attr.attr, "Attribute") != 0: continue
|
||||
if func_attr.value is None: continue
|
||||
fvk: int = func_attr.value.kind()
|
||||
if fvk != ast.ASTKind.Name: continue
|
||||
c_name: ast.Name* = ast.Name*(func_attr.value)
|
||||
if c_name.id is None: continue
|
||||
if string.strcmp(c_name.id, "c") != 0: continue
|
||||
imp_c: int = self.Gen.ImportsGen.is_module_imported(imported_modules, "c")
|
||||
if imp_c == 0: continue
|
||||
|
||||
# 遍历参数提取属性
|
||||
if call_node.args is None: continue
|
||||
args_list: list[ast.AST*]* = call_node.args
|
||||
an: sizet = len(args_list)
|
||||
for ai in range(an):
|
||||
arg_node: ast.AST* = args_list.get(ai)
|
||||
if arg_node is None: continue
|
||||
# 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx)
|
||||
attr_name: str = self._get_attr_name_from_node(arg_node)
|
||||
if attr_name is None: continue
|
||||
# B5:section 字符串属性(t.attr.section(".text.startup"))不能内联
|
||||
# 在函数签名行(llc: expected string constant),必须走属性组
|
||||
# #N(function_set_attr_group)→ 由 FuncGenDef 单独提取处理。
|
||||
if string.strcmp(attr_name, "section") == 0: continue
|
||||
# 映射到 LLVM 属性名并追加
|
||||
ar: int = self._append_llvm_attr(attrs_buf, attr_name)
|
||||
if ar != 0:
|
||||
found_any = 1
|
||||
|
||||
if found_any == 0: return None
|
||||
return attrs_buf
|
||||
def extract_func_section(self, pool: memhub.MemBuddy*,
|
||||
decorator_list: list[ast.AST*]*,
|
||||
imported_modules: str) -> str:
|
||||
"""提取 @c.Attribute(t.attr.section("xxx")) 为属性组文本 '"section"="xxx"'。
|
||||
|
||||
LLVM 字符串属性(带值)必须用属性组 #N(函数行输出 #N + 函数尾
|
||||
attributes #N = { ... }),不能内联(llc: expected string constant)。
|
||||
main.vp boot 函数 t.attr.section(".text.startup") 供链接器按段放置。
|
||||
"""
|
||||
if pool is None or decorator_list is None: return None
|
||||
dn: sizet = len(decorator_list)
|
||||
if dn == 0: return None
|
||||
for di in range(dn):
|
||||
deco: ast.AST* = decorator_list.get(di)
|
||||
if deco is None or deco.kind() != ast.ASTKind.Call: continue
|
||||
call_node: ast.Call* = ast.Call*(deco)
|
||||
if call_node.func is None or call_node.func.kind() != ast.ASTKind.Attribute: continue
|
||||
func_attr: ast.Attribute* = ast.Attribute*(call_node.func)
|
||||
if func_attr.attr is None or string.strcmp(func_attr.attr, "Attribute") != 0: continue
|
||||
if call_node.args is None: continue
|
||||
args_list: list[ast.AST*]* = call_node.args
|
||||
an: sizet = len(args_list)
|
||||
for ai in range(an):
|
||||
arg_node: ast.AST* = args_list.get(ai)
|
||||
if arg_node is None: continue
|
||||
attr_name: str = self._get_attr_name_from_node(arg_node)
|
||||
if attr_name is None or string.strcmp(attr_name, "section") != 0: continue
|
||||
sec_val: str = self._get_attr_call_arg_str(arg_node)
|
||||
if sec_val is None: continue
|
||||
sec_buf: str = pool.alloc(128)
|
||||
if sec_buf is None: return None
|
||||
viperlib.snprintf(sec_buf, 128, "\"section\"=\"%s\"", sec_val)
|
||||
return sec_buf
|
||||
return None
|
||||
def _get_attr_name_from_node(self, node: ast.AST*) -> str:
|
||||
"""从 AST 节点提取属性名
|
||||
|
||||
支持:
|
||||
- Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline"
|
||||
- Attribute: t.attr.packed -> "packed"
|
||||
- Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind"
|
||||
"""
|
||||
if node is None: return None
|
||||
k: int = node.kind()
|
||||
|
||||
# Call 节点: t.attr.always_inline()
|
||||
if k == ast.ASTKind.Call:
|
||||
call: ast.Call* = ast.Call*(node)
|
||||
if call.func is None or call.func.kind() != ast.ASTKind.Attribute: return None
|
||||
at: ast.Attribute* = ast.Attribute*(call.func)
|
||||
return at.attr
|
||||
|
||||
# Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at2: ast.Attribute* = ast.Attribute*(node)
|
||||
return at2.attr
|
||||
|
||||
return None
|
||||
def _get_attr_call_arg_str(self, node: ast.AST*) -> str:
|
||||
"""取 t.attr.xxx("val") 调用的首参字符串常量(如 section(".text.startup"))"""
|
||||
if node is None or node.kind() != ast.ASTKind.Call: return None
|
||||
cl: ast.Call* = ast.Call*(node)
|
||||
if cl.args is None or len(cl.args) == 0: return None
|
||||
a0: ast.AST* = cl.args.get(0)
|
||||
if a0 is None or a0.kind() != ast.ASTKind.Constant: return None
|
||||
cn: ast.Constant* = ast.Constant*(a0)
|
||||
if cn.const_kind != ast.CONST_STR: return None
|
||||
return cn.str_val
|
||||
def _append_llvm_attr(self, attrs_buf: str, attr_name: str) -> int:
|
||||
"""将属性名映射到 LLVM 属性名并追加到缓冲区
|
||||
|
||||
返回 1 表示已追加,0 表示不支持该属性
|
||||
"""
|
||||
if attrs_buf is None or attr_name is None: return 0
|
||||
|
||||
# 先确定映射的 LLVM 属性名
|
||||
llvm_name: str = None
|
||||
if string.strcmp(attr_name, "always_inline") == 0: llvm_name = "alwaysinline"
|
||||
elif string.strcmp(attr_name, "noinline") == 0: llvm_name = "noinline"
|
||||
elif string.strcmp(attr_name, "noreturn") == 0: llvm_name = "noreturn"
|
||||
elif string.strcmp(attr_name, "pure") == 0: llvm_name = "readonly"
|
||||
elif string.strcmp(attr_name, "const") == 0: llvm_name = "readnone"
|
||||
elif string.strcmp(attr_name, "nounwind") == 0: llvm_name = "nounwind"
|
||||
elif string.strcmp(attr_name, "noredzone") == 0: llvm_name = "noredzone"
|
||||
elif string.strcmp(attr_name, "stackrealign") == 0: llvm_name = '"stackrealign"'
|
||||
elif string.strcmp(attr_name, "willreturn") == 0: llvm_name = "willreturn"
|
||||
elif string.strcmp(attr_name, "mustprogress") == 0: llvm_name = "mustprogress"
|
||||
else:
|
||||
# packed/aligned/section/visibility/weak 等不支持作为函数内联属性
|
||||
return 0
|
||||
|
||||
# 支持的属性:如果缓冲区非空,先追加空格分隔
|
||||
if attrs_buf[0] != '\0':
|
||||
self._append_str(attrs_buf, " ", 256)
|
||||
self._append_str(attrs_buf, llvm_name, 256)
|
||||
return 1
|
||||
def _append_str(self, buf: str, s: str,
|
||||
max_len: sizet = 256) -> None:
|
||||
"""将字符串追加到 buf 末尾(有界,防 strcpy 越界写穿定长缓冲)"""
|
||||
if buf is None or s is None: return
|
||||
# 防御:TPV 方法默认参数注册存在缺陷(缺参调用 max_len 落到 0),
|
||||
# 显式兜底为 256,避免有界写入检查误判丢弃全部属性文本。
|
||||
if max_len == 0:
|
||||
max_len = 256
|
||||
cur_len: sizet = string.strlen(buf)
|
||||
s_len: sizet = string.strlen(s)
|
||||
if cur_len + s_len + 1 > max_len: return # 无剩余容量:丢弃本次追加,避免越界写 存疑
|
||||
string.strcpy(buf + cur_len, s)
|
||||
# ============================================================
|
||||
# _mangle_name - 为名称添加 SHA1 前缀
|
||||
#
|
||||
# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带
|
||||
# SHA1 前缀(16 hex + '.'),则原样返回。
|
||||
# ============================================================
|
||||
def _mangle_name(self, trans: HT.Translator*, name: str) -> str:
|
||||
"""为任意名称添加 SHA1 前缀(不做 main/export 检查)"""
|
||||
if trans is None or name is None: return name
|
||||
if trans.ModuleSha1 is None: return name
|
||||
name_len: sizet = string.strlen(name)
|
||||
# 已带 SHA1 前缀("{16hex}.")则跳过
|
||||
# [C10 收敛] 判定走唯一真源 `GenApi.sha1_prefix_len`。旧判据是 `name_len > 17`,
|
||||
# 与真源的 `>= 17` 只差"前缀之后为空串"这一退化形态(无实际意义),一并对齐。
|
||||
if GenApi.sha1_prefix_len(name) != 0: return name
|
||||
sha1: str = trans.ModuleSha1
|
||||
sha1_len: sizet = string.strlen(sha1)
|
||||
mangled: str = stdlib.malloc(sha1_len + name_len + 2)
|
||||
if mangled is None: return name
|
||||
string.strcpy(mangled, sha1)
|
||||
mangled[sha1_len] = '.'
|
||||
string.strcpy(mangled + sha1_len + 1, name)
|
||||
return mangled
|
||||
# ============================================================
|
||||
# _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀
|
||||
#
|
||||
# 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling,
|
||||
# 而非当前模块的 SHA1。
|
||||
# ============================================================
|
||||
def _mangle_name_with_sha1(self, sha1: str, name: str) -> str:
|
||||
"""用指定 SHA1 为名称添加前缀(不做 main/export 检查)"""
|
||||
if sha1 is None or name is None: return name
|
||||
name_len: sizet = string.strlen(name)
|
||||
# 已带 SHA1 前缀("{16hex}.")则跳过
|
||||
# [C10 收敛] 判定走唯一真源 `GenApi.sha1_prefix_len`(口径对齐同 _mangle_name)。
|
||||
if GenApi.sha1_prefix_len(name) != 0: return name
|
||||
sha1_len: sizet = string.strlen(sha1)
|
||||
mangled: str = stdlib.malloc(sha1_len + name_len + 2)
|
||||
if mangled is None: return name
|
||||
string.strcpy(mangled, sha1)
|
||||
mangled[sha1_len] = '.'
|
||||
string.strcpy(mangled + sha1_len + 1, name)
|
||||
return mangled
|
||||
# ============================================================
|
||||
# _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查)
|
||||
#
|
||||
# 规则:
|
||||
# - main 函数不加前缀(程序入口点)
|
||||
# - has_export 非 0 时不加前缀(t.CExport 导出函数)
|
||||
# - 已带 SHA1 前缀的不再加
|
||||
# - ModuleSha1 为 None 时不加前缀
|
||||
# ============================================================
|
||||
def _mangle_func_name(self, trans: HT.Translator*, name: str,
|
||||
has_export: int) -> str:
|
||||
"""为函数名添加 SHA1 前缀(检查 main/export)"""
|
||||
if trans is None or name is None: return name
|
||||
if has_export != 0: return name
|
||||
if string.strcmp(name, "main") == 0: return name
|
||||
return self._mangle_name(trans, name)
|
||||
# ============================================================
|
||||
# _body_has_raise - 函数体是否含 raise(非 StopIteration)
|
||||
#
|
||||
# 对齐 TPC HandlesFunctions.py L216-243 _body_contains_raise:函数签名
|
||||
# 追加 __eh_msg_out__/__eh_code_out__ 输出参数的条件。v1 只扫函数体
|
||||
# 顶层 raise(嵌套 if/for/try 内的 raise 未覆盖,后续扩展)。
|
||||
# ============================================================
|
||||
def _body_has_raise(self, fd: ast.FunctionDef*) -> int:
|
||||
"""函数体顶层是否含 raise(非 StopIteration),1=是 / 0=否"""
|
||||
if fd is None or fd.children is None:
|
||||
return 0
|
||||
body_f: list[ast.AST*]* = fd.children
|
||||
bn_f: sizet = len(body_f)
|
||||
for bi_f in range(bn_f):
|
||||
stmt_f: ast.AST* = body_f.get(bi_f)
|
||||
if stmt_f is None: continue
|
||||
if stmt_f.kind() != ast.ASTKind.Raise: continue
|
||||
rn_f: rawptr[ast.Raise] = rawptr[ast.Raise](stmt_f)
|
||||
if rn_f is None or rn_f.exc is None: continue
|
||||
ek_f: int = rn_f.exc.kind()
|
||||
is_stop_f: int = 0
|
||||
if ek_f == ast.ASTKind.Name:
|
||||
enm_f: ast.Name* = ast.Name*(rn_f.exc)
|
||||
if enm_f.id is not None and string.strcmp(enm_f.id, "StopIteration") == 0:
|
||||
is_stop_f = 1
|
||||
elif ek_f == ast.ASTKind.Call:
|
||||
ecl_f: ast.Call* = ast.Call*(rn_f.exc)
|
||||
if ecl_f.func is not None and ecl_f.func.kind() == ast.ASTKind.Name:
|
||||
ecn_f: ast.Name* = ast.Name*(ecl_f.func)
|
||||
if ecn_f.id is not None and string.strcmp(ecn_f.id, "StopIteration") == 0:
|
||||
is_stop_f = 1
|
||||
if is_stop_f == 0:
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# RejectCReturnDecorator - @c.CReturn 装饰器已移除,遇到即编译期报错
|
||||
#
|
||||
# 多返回值唯一入口是返回注解 `-> tuple[ty1, ty2, ...]`(tuple → struct 通路
|
||||
# 逐字保留)。任何装饰器形态出现 CReturn 一律 fail-fast,不静默忽略。
|
||||
# 供 FuncGenDef(pre_scan 前向声明 / translate_function_def 定义两阶段)复用;
|
||||
# Converter 为模块级函数,同报文另写一份(见 StubGen/Converter.vp)。
|
||||
# 无 CReturn 返回 0。
|
||||
# ============================================================
|
||||
def RejectCReturnDecorator(self, node: ast.AST*,
|
||||
decorators: list[ast.AST*]*) -> int:
|
||||
"""装饰器列表里出现 @c.CReturn 即 fatal_error(返回 0 = 无该装饰器)"""
|
||||
if decorators is None: return 0
|
||||
rcr_dn: sizet = len(decorators)
|
||||
for rcr_i in range(rcr_dn):
|
||||
rcr_deco: ast.AST* = decorators.get(rcr_i)
|
||||
if rcr_deco is None: continue
|
||||
# 兼容 @c.CReturn(...)(Call(func=Attribute))与裸 @c.CReturn(Attribute)两形态
|
||||
rcr_attr: ast.Attribute* = None
|
||||
if rcr_deco.kind() == ast.ASTKind.Call:
|
||||
rcr_call: ast.Call* = ast.Call*(rcr_deco)
|
||||
if rcr_call.func is not None and rcr_call.func.kind() == ast.ASTKind.Attribute:
|
||||
rcr_attr = ast.Attribute*(rcr_call.func)
|
||||
elif rcr_deco.kind() == ast.ASTKind.Attribute:
|
||||
rcr_attr = ast.Attribute*(rcr_deco)
|
||||
if rcr_attr is None or rcr_attr.attr is None: continue
|
||||
if string.strcmp(rcr_attr.attr, "CReturn") == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(node, "`@c.CReturn` 已移除:请改用返回注解 `-> tuple[ty1, ty2, ...]`(多返回值打包为 struct 返回)", "TypeError")
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# 创建 LLVM 函数(简单版本,仅声明)
|
||||
# ============================================================
|
||||
def create_function(self, pool: memhub.MemBuddy*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
name: str,
|
||||
args_node: ast.AST*,
|
||||
ret_ty: llvmlite.LLVMType*) -> llvmlite.Function*:
|
||||
"""创建 LLVM 函数并添加参数"""
|
||||
if name is None or mod is None: return None
|
||||
|
||||
func: llvmlite.Function* = llvmlite.create_function(pool, mod, name, ret_ty)
|
||||
if func is None: return None
|
||||
|
||||
if args_node is not None:
|
||||
ags: ast.Arguments* = ast.Arguments*(args_node)
|
||||
if ags.args is not None:
|
||||
alist: list[ast.AST*]* = ags.args
|
||||
an: sizet = len(alist)
|
||||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
for ai in range(an):
|
||||
arg: ast.Arg* = ast.Arg*(alist.get(ai))
|
||||
if arg is not None and arg.arg is not None:
|
||||
# t\.CVoid 表示空参:跳过
|
||||
if arg.annotation is not None:
|
||||
if arg.annotation.kind() == ast.ASTKind.Attribute:
|
||||
at_cf: ast.Attribute* = ast.Attribute*(arg.annotation)
|
||||
if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0: continue
|
||||
param_ty: llvmlite.LLVMType* = i32_ty
|
||||
if arg.annotation is not None:
|
||||
resolved: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, arg.annotation, None, None, None, 0)
|
||||
if resolved is None:
|
||||
# [S4 fail-fast] 有注解但解析失败:不再静默用 i32。
|
||||
# 本函数不传 trans/imports 上下文,解析失败即调用方未补齐
|
||||
# 上下文(暴露上游,不由本函数兜底)。
|
||||
self.Gen.TypeGenErr.fatal_error(arg, f"函数 '{name}' 形参 '{arg.arg}' 类型注解解析失败", "NameError")
|
||||
return None
|
||||
param_ty = resolved
|
||||
pname: str = pool.alloc(32)
|
||||
if pname is not None:
|
||||
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
|
||||
llvmlite.add_param(pool, func, param_ty, pname)
|
||||
|
||||
return func
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,445 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
|
||||
# ============================================================
|
||||
# FuncGenBase - FuncGenMixin 拆分(阶段 D):函数属性 / 命名 / mangle / create_function 基础工具
|
||||
#
|
||||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class FuncGenBase(CallGenBase.CallGenBase):
|
||||
"""函数属性 / 命名 / mangle / create_function 基础工具"""
|
||||
|
||||
# ============================================================
|
||||
# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性
|
||||
#
|
||||
# 支持 @c.Attribute(t.attr.xxx()) 和 @c.Attribute(t.attr.xxx) 形式
|
||||
# 也支持 @c.Attribute(t.attr.llvm.xxx) 形式
|
||||
#
|
||||
# 返回 LLVM IR 属性字符串(如 "alwaysinline nounwind"),无属性返回 None
|
||||
# ============================================================
|
||||
def extract_func_attrs(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
imported_modules: str) -> str:
|
||||
"""从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串"""
|
||||
if decorator_list is None:
|
||||
return None
|
||||
dn: t.CSizeT = len(decorator_list)
|
||||
if dn == 0:
|
||||
return None
|
||||
|
||||
attrs_buf: str = pool.alloc(256)
|
||||
if attrs_buf is None:
|
||||
return None
|
||||
attrs_buf[0] = '\0'
|
||||
found_any: int = 0
|
||||
|
||||
# [ATTR-DIAG] 运行时诊断:定位 @c.Attribute 属性为何未进入 IR(stackrealign)
|
||||
cur_file: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if cur_file is None:
|
||||
cur_file = "?"
|
||||
stdio.printf("[ATTR] extract_func_attrs: file='%s' dlist_len=%d\n", cur_file, dn)
|
||||
for di in range(dn):
|
||||
deco: ast.AST | t.CPtr = decorator_list.get(di)
|
||||
if deco is None:
|
||||
stdio.printf("[ATTR] deco[%d]=None\n", di)
|
||||
continue
|
||||
dk: int = deco.kind()
|
||||
stdio.printf("[ATTR] deco[%d] kind=%d\n", di, dk)
|
||||
if dk != ast.ASTKind.Call:
|
||||
continue
|
||||
call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco)
|
||||
if call_node.func is None:
|
||||
stdio.printf("[ATTR] call.func=None\n")
|
||||
continue
|
||||
cfk: int = call_node.func.kind()
|
||||
stdio.printf("[ATTR] call.func kind=%d\n", cfk)
|
||||
if cfk != ast.ASTKind.Attribute:
|
||||
continue
|
||||
|
||||
# 检测 c.Attribute
|
||||
func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func)
|
||||
if func_attr.attr is None:
|
||||
stdio.printf("[ATTR] func_attr.attr=None\n")
|
||||
continue
|
||||
stdio.printf("[ATTR] func_attr.attr='%s'\n", func_attr.attr)
|
||||
if string.strcmp(func_attr.attr, "Attribute") != 0:
|
||||
continue
|
||||
if func_attr.value is None:
|
||||
stdio.printf("[ATTR] func_attr.value=None\n")
|
||||
continue
|
||||
fvk: int = func_attr.value.kind()
|
||||
stdio.printf("[ATTR] func_attr.value kind=%d\n", fvk)
|
||||
if fvk != ast.ASTKind.Name:
|
||||
continue
|
||||
c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value)
|
||||
if c_name.id is None:
|
||||
stdio.printf("[ATTR] c_name.id=None\n")
|
||||
continue
|
||||
stdio.printf("[ATTR] c_name.id='%s'\n", c_name.id)
|
||||
if string.strcmp(c_name.id, "c") != 0:
|
||||
continue
|
||||
imp_c: int = self.Gen.ImportsGen.is_module_imported(imported_modules, "c")
|
||||
stdio.printf("[ATTR] is_module_imported('c')=%d\n", imp_c)
|
||||
if imp_c == 0:
|
||||
continue
|
||||
|
||||
# 遍历参数提取属性
|
||||
if call_node.args is None:
|
||||
stdio.printf("[ATTR] call.args=None\n")
|
||||
continue
|
||||
dbuf: bytes = pool.alloc(1024)
|
||||
if dbuf is not None:
|
||||
dbuf[0] = '\0'
|
||||
dpos: t.CSizeT = deco.dump(dbuf, 1024, 0)
|
||||
if dpos < 1024:
|
||||
dbuf[dpos] = '\0'
|
||||
stdio.printf("[ATTR] deco.dump='%s'\n", dbuf)
|
||||
args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args
|
||||
an: t.CSizeT = len(args_list)
|
||||
stdio.printf("[ATTR] args_len=%d\n", an)
|
||||
if call_node.keywords is not None:
|
||||
kwl: t.CSizeT = len(call_node.keywords)
|
||||
stdio.printf("[ATTR] keywords_len=%d\n", kwl)
|
||||
for kwi in range(kwl):
|
||||
kwnd: ast.AST | t.CPtr = call_node.keywords.get(kwi)
|
||||
if kwnd is not None:
|
||||
stdio.printf("[ATTR] kw[%d] kind=%d\n", kwi, kwnd.kind())
|
||||
for ai in range(an):
|
||||
arg_node: ast.AST | t.CPtr = args_list.get(ai)
|
||||
if arg_node is None:
|
||||
stdio.printf("[ATTR] arg[%d]=None\n", ai)
|
||||
continue
|
||||
stdio.printf("[ATTR] arg[%d] kind=%d\n", ai, arg_node.kind())
|
||||
|
||||
# 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx)
|
||||
attr_name: str = self._get_attr_name_from_node(arg_node)
|
||||
if attr_name is None:
|
||||
stdio.printf("[ATTR] arg[%d] name=None\n", ai)
|
||||
continue
|
||||
|
||||
# 映射到 LLVM 属性名并追加
|
||||
ar: int = self._append_llvm_attr(attrs_buf, attr_name)
|
||||
stdio.printf("[ATTR] arg[%d] name='%s' append=%d buf='%s' blen=%zu b0=0x%02x\n",
|
||||
ai, attr_name, ar, attrs_buf, string.strlen(attrs_buf), attrs_buf[0])
|
||||
if ar != 0:
|
||||
found_any = 1
|
||||
# 追加成功后,如果不是最后一个属性,添加空格分隔
|
||||
# 在下一次追加前由 _append_str 处理
|
||||
|
||||
stdio.printf("[ATTR] found_any=%d return='%s'\n", found_any, attrs_buf)
|
||||
if found_any == 0:
|
||||
return None
|
||||
return attrs_buf
|
||||
def _get_attr_name_from_node(self, node: ast.AST | t.CPtr) -> str:
|
||||
"""从 AST 节点提取属性名
|
||||
|
||||
支持:
|
||||
- Call(func=Attribute(...)): t.attr.always_inline() -> "always_inline"
|
||||
- Attribute: t.attr.packed -> "packed"
|
||||
- Attribute(t.attr.llvm.xxx): t.attr.llvm.nounwind -> "nounwind"
|
||||
"""
|
||||
if node is None:
|
||||
return None
|
||||
k: int = node.kind()
|
||||
|
||||
# Call 节点: t.attr.always_inline()
|
||||
if k == ast.ASTKind.Call:
|
||||
call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if call.func is None or call.func.kind() != ast.ASTKind.Attribute:
|
||||
return None
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call.func)
|
||||
return at.attr
|
||||
|
||||
# Attribute 节点: t.attr.packed 或 t.attr.llvm.nounwind
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
return at2.attr
|
||||
|
||||
return None
|
||||
def _append_llvm_attr(self, attrs_buf: str, attr_name: str) -> int:
|
||||
"""将属性名映射到 LLVM 属性名并追加到缓冲区
|
||||
|
||||
返回 1 表示已追加,0 表示不支持该属性
|
||||
"""
|
||||
if attrs_buf is None or attr_name is None:
|
||||
return 0
|
||||
|
||||
# 先确定映射的 LLVM 属性名
|
||||
llvm_name: str = None
|
||||
if string.strcmp(attr_name, "always_inline") == 0:
|
||||
llvm_name = "alwaysinline"
|
||||
elif string.strcmp(attr_name, "noinline") == 0:
|
||||
llvm_name = "noinline"
|
||||
elif string.strcmp(attr_name, "noreturn") == 0:
|
||||
llvm_name = "noreturn"
|
||||
elif string.strcmp(attr_name, "pure") == 0:
|
||||
llvm_name = "readonly"
|
||||
elif string.strcmp(attr_name, "const") == 0:
|
||||
llvm_name = "readnone"
|
||||
elif string.strcmp(attr_name, "nounwind") == 0:
|
||||
llvm_name = "nounwind"
|
||||
elif string.strcmp(attr_name, "noredzone") == 0:
|
||||
llvm_name = "noredzone"
|
||||
elif string.strcmp(attr_name, "stackrealign") == 0:
|
||||
# 动态重对齐栈(LLVM 序言 and rsp,-16)。入口函数(_start)由 bootloader
|
||||
# jmp 进入(rsp≡0 mod 16),而 llc 按 call 约定假设入口 rsp≡8 → 帧整体
|
||||
# 偏 8 → 所有调用 rsp≡8 → 变参函数保存 xmm 的 movaps #GP。stackrealign
|
||||
# 使序言动态对齐,与入口约定无关(sched started 后 movaps #GP 根因)。
|
||||
# 注意:stackrealign 是 LLVM 字符串属性,必须带引号("stackrealign"),
|
||||
# 与 noinline/nounwind 等枚举属性(无引号)区分,否则 llc 报
|
||||
# "expected '{' in function body"。
|
||||
llvm_name = '"stackrealign"'
|
||||
elif string.strcmp(attr_name, "willreturn") == 0:
|
||||
llvm_name = "willreturn"
|
||||
elif string.strcmp(attr_name, "mustprogress") == 0:
|
||||
llvm_name = "mustprogress"
|
||||
else:
|
||||
# packed/aligned/section/visibility/weak 等不支持作为函数内联属性
|
||||
return 0
|
||||
|
||||
# 支持的属性:如果缓冲区非空,先追加空格分隔
|
||||
if attrs_buf[0] != '\0':
|
||||
self._append_str(attrs_buf, " ", 256)
|
||||
self._append_str(attrs_buf, llvm_name, 256)
|
||||
return 1
|
||||
def _append_str(self, buf: str, s: str,
|
||||
max_len: t.CSizeT = 256) -> None:
|
||||
"""将字符串追加到 buf 末尾(有界,防 strcpy 越界写穿定长缓冲)"""
|
||||
if buf is None or s is None:
|
||||
return
|
||||
# 防御:TPV 方法默认参数注册存在缺陷(缺参调用 max_len 落到 0),
|
||||
# 显式兜底为 256,避免有界写入检查误判丢弃全部属性文本。
|
||||
if max_len == 0:
|
||||
max_len = 256
|
||||
cur_len: t.CSizeT = string.strlen(buf)
|
||||
s_len: t.CSizeT = string.strlen(s)
|
||||
stdio.printf("[ATTR] _append_str: max_len=%zu cur=%zu slen=%zu s='%s'\n", max_len, cur_len, s_len, s)
|
||||
if cur_len + s_len + 1 > max_len:
|
||||
return # 无剩余容量:丢弃本次追加,避免越界写
|
||||
string.strcpy(buf + cur_len, s)
|
||||
# ============================================================
|
||||
# _mangle_name - 为名称添加 SHA1 前缀
|
||||
#
|
||||
# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带
|
||||
# SHA1 前缀(16 hex + '.'),则原样返回。
|
||||
# ============================================================
|
||||
def _mangle_name(self, trans: HT.Translator | t.CPtr, name: str) -> str:
|
||||
"""为任意名称添加 SHA1 前缀(不做 main/export 检查)"""
|
||||
if trans is None or name is None:
|
||||
return name
|
||||
if trans.ModuleSha1 is None:
|
||||
return name
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
# 已带 SHA1 前缀(16 hex + '.')则跳过
|
||||
if name_len > 17:
|
||||
is_sha1: int = 1
|
||||
for i in range(16):
|
||||
c: t.CChar = name[i]
|
||||
if not (('0' <= c <= '9') or ('a' <= c <= 'f')):
|
||||
is_sha1 = 0
|
||||
break
|
||||
if is_sha1 != 0 and name[16] == '.':
|
||||
return name
|
||||
sha1: str = trans.ModuleSha1
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
mangled: str = stdlib.malloc(sha1_len + name_len + 2)
|
||||
if mangled is None:
|
||||
return name
|
||||
string.strcpy(mangled, sha1)
|
||||
mangled[sha1_len] = '.'
|
||||
string.strcpy(mangled + sha1_len + 1, name)
|
||||
return mangled
|
||||
# ============================================================
|
||||
# _mangle_name_with_sha1 — 用指定 SHA1 为名称添加前缀
|
||||
#
|
||||
# 用于跨模块 vtable 继承: 继承方法需要用父模块的 SHA1 做 mangling,
|
||||
# 而非当前模块的 SHA1。
|
||||
# ============================================================
|
||||
def _mangle_name_with_sha1(self, sha1: str, name: str) -> str:
|
||||
"""用指定 SHA1 为名称添加前缀(不做 main/export 检查)"""
|
||||
if sha1 is None or name is None:
|
||||
return name
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
# 已带 SHA1 前缀(16 hex + '.')则跳过
|
||||
if name_len > 17:
|
||||
is_sha1: int = 1
|
||||
for i in range(16):
|
||||
c2: t.CChar = name[i]
|
||||
if not (('0' <= c2 <= '9') or ('a' <= c2 <= 'f')):
|
||||
is_sha1 = 0
|
||||
break
|
||||
if is_sha1 != 0 and name[16] == '.':
|
||||
return name
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
mangled: str = stdlib.malloc(sha1_len + name_len + 2)
|
||||
if mangled is None:
|
||||
return name
|
||||
string.strcpy(mangled, sha1)
|
||||
mangled[sha1_len] = '.'
|
||||
string.strcpy(mangled + sha1_len + 1, name)
|
||||
return mangled
|
||||
# ============================================================
|
||||
# _mangle_func_name - 为函数名添加 SHA1 前缀(含 main/export 检查)
|
||||
#
|
||||
# 规则:
|
||||
# - main 函数不加前缀(程序入口点)
|
||||
# - has_export 非 0 时不加前缀(t.CExport 导出函数)
|
||||
# - 已带 SHA1 前缀的不再加
|
||||
# - ModuleSha1 为 None 时不加前缀
|
||||
# ============================================================
|
||||
def _mangle_func_name(self, trans: HT.Translator | t.CPtr, name: str,
|
||||
has_export: int) -> str:
|
||||
"""为函数名添加 SHA1 前缀(检查 main/export)"""
|
||||
if trans is None or name is None:
|
||||
return name
|
||||
if has_export != 0:
|
||||
return name
|
||||
if string.strcmp(name, "main") == 0:
|
||||
return name
|
||||
return self._mangle_name(trans, name)
|
||||
# ============================================================
|
||||
# _body_has_raise - 函数体是否含 raise(非 StopIteration)
|
||||
#
|
||||
# 对齐 TPC HandlesFunctions.py L216-243 _body_contains_raise:函数签名
|
||||
# 追加 __eh_msg_out__/__eh_code_out__ 输出参数的条件。v1 只扫函数体
|
||||
# 顶层 raise(嵌套 if/for/try 内的 raise 未覆盖,后续扩展)。
|
||||
# ============================================================
|
||||
def _body_has_raise(self, fd: ast.FunctionDef | t.CPtr) -> int:
|
||||
"""函数体顶层是否含 raise(非 StopIteration),1=是 / 0=否"""
|
||||
if fd is None or fd.children is None:
|
||||
return 0
|
||||
body_f: list[ast.AST | t.CPtr] | t.CPtr = fd.children
|
||||
bn_f: t.CSizeT = len(body_f)
|
||||
for bi_f in range(bn_f):
|
||||
stmt_f: ast.AST | t.CPtr = body_f.get(bi_f)
|
||||
if stmt_f is None:
|
||||
continue
|
||||
if stmt_f.kind() != ast.ASTKind.Raise:
|
||||
continue
|
||||
rn_f: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(stmt_f)
|
||||
if rn_f is None or rn_f.exc is None:
|
||||
continue
|
||||
ek_f: int = rn_f.exc.kind()
|
||||
is_stop_f: int = 0
|
||||
if ek_f == ast.ASTKind.Name:
|
||||
enm_f: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn_f.exc)
|
||||
if enm_f.id is not None and string.strcmp(enm_f.id, "StopIteration") == 0:
|
||||
is_stop_f = 1
|
||||
elif ek_f == ast.ASTKind.Call:
|
||||
ecl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn_f.exc)
|
||||
if ecl_f.func is not None and ecl_f.func.kind() == ast.ASTKind.Name:
|
||||
ecn_f: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl_f.func)
|
||||
if ecn_f.id is not None and string.strcmp(ecn_f.id, "StopIteration") == 0:
|
||||
is_stop_f = 1
|
||||
if is_stop_f == 0:
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _resolve_creturn_ret_ty - @c.CReturn(ty1, ty2, ...) → 多返回 struct 类型
|
||||
#
|
||||
# 对齐 TPC DeclarationGenerator:CReturn 声明函数返回多个值(如
|
||||
# GetMemoryStats @c.CReturn(t.CUInt64T, t.CUInt64T, t.CUInt64T) →
|
||||
# {i64, i64, i64})。pre_scan 前向声明与 translate_function_def 定义
|
||||
# 两阶段必须一致,否则 declare i32 + define {i64,i64,i64} → llc
|
||||
# "ret doesn't match function result type"。
|
||||
# ============================================================
|
||||
def _resolve_creturn_ret_ty(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
fd: ast.FunctionDef | t.CPtr,
|
||||
imported_modules: str,
|
||||
from_imports: str,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""解析 @c.CReturn 装饰器为 struct 返回类型;无 CReturn 返回 None"""
|
||||
if fd is None or fd.decorator_list is None:
|
||||
return None
|
||||
cr_head: llvmlite.ParamNode | t.CPtr = None
|
||||
cr_last: llvmlite.ParamNode | t.CPtr = None
|
||||
cr_count: int = 0
|
||||
cr_dn: t.CSizeT = len(fd.decorator_list)
|
||||
for cdi in range(cr_dn):
|
||||
deco_cr: ast.AST | t.CPtr = fd.decorator_list.get(cdi)
|
||||
if deco_cr is None or deco_cr.kind() != ast.ASTKind.Call:
|
||||
continue
|
||||
deco_call_cr: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco_cr)
|
||||
if deco_call_cr.func is None or deco_call_cr.func.kind() != ast.ASTKind.Attribute:
|
||||
continue
|
||||
deco_fa_cr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(deco_call_cr.func)
|
||||
if deco_fa_cr.attr is None or string.strcmp(deco_fa_cr.attr, "CReturn") != 0:
|
||||
continue
|
||||
cr_args: list[ast.AST | t.CPtr] | t.CPtr = deco_call_cr.args
|
||||
if cr_args is None:
|
||||
continue
|
||||
cr_an: t.CSizeT = len(cr_args)
|
||||
for cai in range(cr_an):
|
||||
cr_aty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, cr_args.get(cai), imported_modules, from_imports, trans, 0)
|
||||
if cr_aty is None:
|
||||
continue
|
||||
cr_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cr_aty)
|
||||
if cr_pn is not None:
|
||||
if cr_head is None:
|
||||
cr_head = cr_pn
|
||||
else:
|
||||
cr_last.Next = cr_pn
|
||||
cr_last = cr_pn
|
||||
cr_count += 1
|
||||
if cr_head is not None and cr_count > 0:
|
||||
return llvmlite.Struct(pool, cr_head, cr_count, None)
|
||||
return None
|
||||
# ============================================================
|
||||
# 创建 LLVM 函数(简单版本,仅声明)
|
||||
# ============================================================
|
||||
def create_function(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
name: str,
|
||||
args_node: ast.AST | t.CPtr,
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Function | t.CPtr:
|
||||
"""创建 LLVM 函数并添加参数"""
|
||||
if name is None or mod is None:
|
||||
return None
|
||||
|
||||
func: llvmlite.Function | t.CPtr = llvmlite.create_function(pool, mod, name, ret_ty)
|
||||
if func is None:
|
||||
return None
|
||||
|
||||
if args_node is not None:
|
||||
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
|
||||
if ags.args is not None:
|
||||
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
|
||||
an: t.CSizeT = len(alist)
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
for ai in range(an):
|
||||
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
|
||||
if arg is not None and arg.arg is not None:
|
||||
# t.CVoid 表示空参:跳过
|
||||
if arg.annotation is not None:
|
||||
if arg.annotation.kind() == ast.ASTKind.Attribute:
|
||||
at_cf: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation)
|
||||
if at_cf.attr is not None and string.strcmp(at_cf.attr, "CVoid") == 0:
|
||||
continue
|
||||
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
if arg.annotation is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||||
pool, arg.annotation, None, None, None, 0)
|
||||
if resolved is not None:
|
||||
param_ty = resolved
|
||||
pname: str = pool.alloc(32)
|
||||
if pname is not None:
|
||||
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
|
||||
llvmlite.add_param(pool, func, param_ty, pname)
|
||||
|
||||
return func
|
||||
+463
-286
File diff suppressed because it is too large.
Load diff
+434
-193
@@ -1,193 +1,434 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
|
||||
|
||||
# ============================================================
|
||||
# GenTypes - Gen 侧共享数据类型与常量(去除 Handles 层迁移目标)
|
||||
#
|
||||
# 原分布于 Handles 目录的数据类与常量集中于此,供 Gen 子对象、
|
||||
# 管线与保留实体文件引用。删除 Handles 目录后统一经本模块访问。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 类编译期元数据(原 HandlesType.CLASS_META_*)
|
||||
# ============================================================
|
||||
CLASS_META_PROVIDES: t.CDefine = 1
|
||||
CLASS_META_REQUIRES: t.CDefine = 2
|
||||
CLASS_META_REQUIRE_MUST: t.CDefine = 3
|
||||
|
||||
# ============================================================
|
||||
# 属性/静态/类方法元数据(原 HandlesClassDef.META_*)
|
||||
# ============================================================
|
||||
META_STATIC: t.CDefine = 1
|
||||
META_CLASS: t.CDefine = 2
|
||||
META_PROP_GETTER: t.CDefine = 4
|
||||
META_PROP_SETTER: t.CDefine = 8
|
||||
META_PROP_DELETER: t.CDefine = 16
|
||||
|
||||
# ============================================================
|
||||
# 结构体容量(原 HandlesStruct.FIELD_MAX/FIELD_NAME_MAX/PARENT_MAX/MRO_MAX)
|
||||
# ============================================================
|
||||
FIELD_MAX: t.CDefine = 256
|
||||
FIELD_NAME_MAX: t.CDefine = 64
|
||||
PARENT_MAX: t.CDefine = 64
|
||||
MRO_MAX: t.CDefine = 64
|
||||
|
||||
# ============================================================
|
||||
# for 迭代序列种类(原 HandlesFor.SEQ_KIND_*)
|
||||
# ============================================================
|
||||
SEQ_KIND_RANGE: t.CDefine = 1
|
||||
SEQ_KIND_STR: t.CDefine = 2
|
||||
SEQ_KIND_LIST: t.CDefine = 3
|
||||
|
||||
# ============================================================
|
||||
# TraceFrame - 仿 Python Traceback 调用栈帧(原 HandlesType.TraceFrame)
|
||||
# ============================================================
|
||||
class TraceFrame:
|
||||
"""仿 Python Traceback 调用栈帧(push_trace/pop_trace 使用)"""
|
||||
file_name: str
|
||||
lineno: int
|
||||
col_start: int
|
||||
col_end: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# VarEntry - 变量表条目(原 HandlesVar.VarEntry)
|
||||
# ============================================================
|
||||
class VarEntry:
|
||||
"""变量表条目"""
|
||||
Name: str
|
||||
Alloca: llvmlite.Value | t.CPtr
|
||||
Used: t.CInt
|
||||
AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
|
||||
IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Scope - 作用域节点(原 HandlesVar.Scope)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class Scope:
|
||||
"""作用域节点"""
|
||||
Parent: Scope | t.CPtr
|
||||
Vars: VarEntry | t.CPtr
|
||||
VarCount: t.CInt
|
||||
Kind: t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SymbolTable - 嵌套作用域符号表(原 HandlesVar.SymbolTable)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class SymbolTable:
|
||||
"""嵌套作用域符号表"""
|
||||
Pool: memhub.MemBuddy | t.CPtr
|
||||
Root: Scope | t.CPtr
|
||||
Current: Scope | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FieldEntry - 字段信息条目(原 HandlesStruct.FieldEntry)
|
||||
# ============================================================
|
||||
class FieldEntry:
|
||||
Name: str # 字段名(字符串)
|
||||
Index: int # 字段在结构体中的索引
|
||||
Ty: llvmlite.LLVMType | t.CPtr # 字段的 LLVM 类型
|
||||
DefaultVal: ast.AST | t.CPtr # 默认值 AST 节点(None=无默认值)
|
||||
AnnotClassName: str # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StructEntry - 结构体注册条目(原 HandlesStruct.StructEntry)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class StructEntry:
|
||||
Name: str # 类名
|
||||
Ty: llvmlite.LLVMType | t.CPtr # LLVM StructType
|
||||
FieldCount: int # 字段数量
|
||||
Fields: FieldEntry | t.CPtr # 字段数组(FIELD_MAX 个槽位)
|
||||
IsUnion: int # 1=联合体 / 0=普通结构体
|
||||
IsOOP: int # 1=OOP结构体(有方法) / 0=纯内存结构体
|
||||
HasInit: int # 1=有__init__方法 / 0=无
|
||||
HasNew: int # 1=有__new__方法 / 0=无
|
||||
HasVTable: int # 1=有虚表 / 0=无虚表
|
||||
IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记
|
||||
ParentName: str # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用)
|
||||
ParentNames: t.CSizeT | t.CPtr # 多继承父类名数组(每元素 str 指针,ParentCount 个;stdlib 深拷贝)
|
||||
ParentCount: t.CInt # 父类数量(0=无父类,1=单继承,>1=多继承)
|
||||
VTableMethodCount: int # 虚表中的方法数量
|
||||
VTableMethods: str # 虚表方法名数组(每个方法名 str,VTableMethodCount 个)
|
||||
ModuleSha1: str # 定义该类的模块 SHA1(None=无 SHA1)
|
||||
MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译)
|
||||
SpecTriggerSha1: str # 泛型特化类的触发文件 SHA1(None=非特化类)。特化类 ModuleSha1=模板
|
||||
# sha1(方法名带模板前缀),作废重译时 reset_module_methods_emitted
|
||||
# 按触发文件 sha1 精确重置 MethodsEmitted,防特化方法体残留 1 不补译
|
||||
# → 链接 undefined symbol(list[ast.ClassDef|t.CPtr].* 根因)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# EnumMember - 枚举成员(原 HandlesEnum.EnumMember)
|
||||
# ============================================================
|
||||
class EnumMember:
|
||||
Name: str # 成员名(字符串)
|
||||
Value: t.CInt64T # 成员的整数值
|
||||
Ty: llvmlite.LLVMType | t.CPtr # 成员的 LLVM 类型(用于混用类型场景)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# EnumEntry - 枚举类型条目(原 HandlesEnum.EnumEntry)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class EnumEntry:
|
||||
Name: str # 枚举类名
|
||||
BaseTy: llvmlite.LLVMType | t.CPtr # 基准类型(所有成员类型中最大的)
|
||||
MemberCount: int # 成员数量
|
||||
Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AsmOperand - 内联汇编操作数条目(原 HandlesExprCall.AsmOperand)
|
||||
# ============================================================
|
||||
class AsmOperand:
|
||||
"""内联汇编操作数条目"""
|
||||
Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca
|
||||
Constraint: str # 约束字符串 (如 "r", "=r")
|
||||
IsOutput: int # 1=输出, 0=输入
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FuncEntry - 函数表条目(原 HandlesExprCall.FuncEntry)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class FuncEntry:
|
||||
"""函数表条目"""
|
||||
Name: str
|
||||
Func: llvmlite.Function | t.CPtr
|
||||
Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值
|
||||
DefaultCount: int # 默认值数量
|
||||
ParamCount: int # 形参数量(不含 self)
|
||||
# TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全)
|
||||
# 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后,
|
||||
# vtable 生成 find_func_global 读类型改用此文本,避免悬空。
|
||||
TypeStr: str
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FuncDefaultsEntry - 默认参数表条目(原 HandlesExprCall.FuncDefaultsEntry)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class FuncDefaultsEntry:
|
||||
"""默认参数表条目"""
|
||||
Name: str
|
||||
Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset)
|
||||
DefaultCount: int
|
||||
ParamCount: int # 形参数量(不含 self)
|
||||
# 常量快照(stdlib 分配,跨文件永久存活):
|
||||
# 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR,
|
||||
# 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。
|
||||
ConstKinds: t.CInt | t.CPtr # const_kind 数组(DefaultCount 个 i32)
|
||||
ConstInts: t.CInt64T | t.CPtr # int_val 数组(DefaultCount 个 i64)
|
||||
ConstStrs: t.CSizeT | t.CPtr # str_val 指针数组(DefaultCount 个 i8*)
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
# TypeSpec:统一类型描述符(Debugger/_Type.md 第 6 节设计)。
|
||||
# 别名用 TSpec:模块内类名同为 TypeSpec,别名同名会被解析器误判为类静态方法。
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
|
||||
# ============================================================
|
||||
# GenTypes - Gen 侧共享数据类型与常量(去除 Handles 层迁移目标)
|
||||
#
|
||||
# 原分布于 Handles 目录的数据类与常量集中于此,供 Gen 子对象、
|
||||
# 管线与保留实体文件引用。删除 Handles 目录后统一经本模块访问。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 类编译期元数据(原 HandlesType.CLASS_META_*)
|
||||
# ============================================================
|
||||
CLASS_META_PROVIDES: t.CDefine = 1
|
||||
CLASS_META_REQUIRES: t.CDefine = 2
|
||||
CLASS_META_REQUIRE_MUST: t.CDefine = 3
|
||||
|
||||
# ============================================================
|
||||
# 属性/静态/类方法元数据(原 HandlesClassDef.META_*)
|
||||
# ============================================================
|
||||
META_STATIC: t.CDefine = 1
|
||||
META_CLASS: t.CDefine = 2
|
||||
META_PROP_GETTER: t.CDefine = 4
|
||||
META_PROP_SETTER: t.CDefine = 8
|
||||
META_PROP_DELETER: t.CDefine = 16
|
||||
|
||||
# ============================================================
|
||||
# 结构体容量(原 HandlesStruct.FIELD_MAX/FIELD_NAME_MAX/PARENT_MAX/MRO_MAX)
|
||||
# ============================================================
|
||||
FIELD_MAX: t.CDefine = 256
|
||||
FIELD_NAME_MAX: t.CDefine = 64
|
||||
PARENT_MAX: t.CDefine = 64
|
||||
MRO_MAX: t.CDefine = 64
|
||||
|
||||
# ============================================================
|
||||
# for 迭代序列种类(原 HandlesFor.SEQ_KIND_*)
|
||||
# ============================================================
|
||||
SEQ_KIND_RANGE: t.CDefine = 1
|
||||
SEQ_KIND_STR: t.CDefine = 2
|
||||
SEQ_KIND_LIST: t.CDefine = 3
|
||||
|
||||
# ============================================================
|
||||
# TraceFrame - 仿 Python Traceback 调用栈帧(原 HandlesType.TraceFrame)
|
||||
# ============================================================
|
||||
class TraceFrame:
|
||||
"""仿 Python Traceback 调用栈帧(push_trace/pop_trace 使用)"""
|
||||
file_name: str
|
||||
lineno: int
|
||||
col_start: int
|
||||
col_end: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# VarEntry - 变量表条目(原 HandlesVar.VarEntry)
|
||||
# ============================================================
|
||||
class VarEntry:
|
||||
"""变量表条目"""
|
||||
Name: str
|
||||
Alloca: llvmlite.Value*
|
||||
Used: int
|
||||
# TypeSpec(S3 起为**唯一类型承载**):由 add_var 用 SpecFromLLVMType 从
|
||||
# alloca.Ty 的 pointee 填充(PermPool 分配 ⇒ 跨文件安全),注解侧再由
|
||||
# set_var_annot_class_name 经 SpecWithSign / SpecWithSource 补整数符号性与
|
||||
# 注解来源名(Spec.SourceName,原 AnnotClassName 字段已并入),由
|
||||
# set_var_ptr_element 经 SpecWithElemBits 补「指针元素」语义(原
|
||||
# IsPtrElement 字段已并入 Spec.ElemBits)。
|
||||
Spec: TSpec.TypeSpec*
|
||||
# 1=该变量的 load/store 带 LLVM volatile 限定符(注解联合含 t.CVolatile)。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,条目数组步长同步。
|
||||
IsVolatile: int
|
||||
# 1=该变量是 rawptr[t.CVolatile | T](volatile 指针指向物,等价 C 的
|
||||
# volatile T*):解引用(p[i] / p.field / c.Deref(p))的 load/store 带 LLVM
|
||||
# volatile,禁止优化器重排序/消除对所指对象的每次访问。注意与 IsVolatile
|
||||
# 的区别:IsVolatile 限定"指针变量自身"的读写,本字段限定"指针所指物"。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,条目数组步长同步。
|
||||
PointeeVolatile: int
|
||||
# 1=该变量是 **const 对象**(注解含 t.CConst 且声明类型**不是指针**):
|
||||
# 整个作用域内禁止对该变量名赋值 / 增量赋值 / 元素赋值(fail-fast)。
|
||||
# 与 TPC 的 Gen.var_const_flags / global_const_flags 同判据、同报文,见
|
||||
# Debugger/type-descriptors.md。指针类型(如 `p: t.CConst | T | t.CPtr`)的
|
||||
# CConst 只约束 pointee,不使指针变量自身不可写,故不置 1。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,条目数组步长同步。
|
||||
IsConst: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Scope - 作用域节点(原 HandlesVar.Scope)
|
||||
# ============================================================
|
||||
novirtual class Scope:
|
||||
"""作用域节点"""
|
||||
Parent: Scope | t.CPtr
|
||||
Vars: VarEntry | t.CPtr
|
||||
VarCount: int
|
||||
Kind: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SymbolTable - 嵌套作用域符号表(原 HandlesVar.SymbolTable)
|
||||
# ============================================================
|
||||
novirtual class SymbolTable:
|
||||
"""嵌套作用域符号表"""
|
||||
Pool: memhub.MemBuddy*
|
||||
Root: Scope | t.CPtr
|
||||
Current: Scope | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FieldEntry - 字段信息条目(原 HandlesStruct.FieldEntry)
|
||||
# ============================================================
|
||||
class FieldEntry:
|
||||
Name: str # 字段名(字符串)
|
||||
Index: int # 字段在结构体中的索引
|
||||
Ty: llvmlite.LLVMType* # 字段的 LLVM 类型
|
||||
DefaultVal: ast.AST* # 默认值 AST 节点(None=无默认值)
|
||||
# TypeSpec(S3 起为**唯一类型承载**):由 add_field 用 SpecFromLLVMType 从
|
||||
# field_ty 填充(PermPool 分配 ⇒ 跨 1b reset 安全,无需 DeepCopyType),
|
||||
# 注解侧再经 SpecWithSign / SpecWithSource 补符号性与注解来源名
|
||||
# (Spec.SourceName,原 AnnotClassName 字段已并入)。
|
||||
Spec: TSpec.TypeSpec*
|
||||
# 1=该字段经对象访问的 load/store 带 LLVM volatile 限定符
|
||||
# (字段注解联合含 t.CVolatile,如 Spinlock.locked: t.CVolatile | t.CInt)。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,字段数组步长同步。
|
||||
IsVolatile: int
|
||||
# 1=该字段是 rawptr[t.CVolatile | T](volatile 指针指向物,等价 C 的
|
||||
# volatile T*):经该字段解引用(self.ptr[i] / self.ptr.field)的 load/store
|
||||
# 带 LLVM volatile。与 IsVolatile 的区别同 VarEntry.PointeeVolatile。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,字段数组步长同步。
|
||||
PointeeVolatile: int
|
||||
# 1=该字段是 **const 对象**(注解含 t.CConst 且字段类型**不是指针**):
|
||||
# 经对象给该字段赋值(obj.f = ... / self.f = ...)即 fail-fast,与
|
||||
# VarEntry.IsConst 同判据、同报文(TPC 侧对应 Gen.field_const_flags)。
|
||||
# 追加在末尾:既有字段偏移不变,__sizeof__() 自动纳入,字段数组步长同步。
|
||||
IsConst: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StructEntry - 结构体注册条目(原 HandlesStruct.StructEntry)
|
||||
# ============================================================
|
||||
novirtual class StructEntry:
|
||||
Name: str # 类名
|
||||
Ty: llvmlite.LLVMType* # LLVM StructType
|
||||
FieldCount: int # 字段数量
|
||||
Fields: FieldEntry | t.CPtr # 字段数组(FIELD_MAX 个槽位)
|
||||
IsUnion: int # 1=联合体 / 0=普通结构体
|
||||
IsPacked: int # 1=@c.Attribute(t.attr.packed) 打包结构体(无字段填充)
|
||||
Align: int # @c.Attribute(t.attr.aligned(N)) 对齐字节数(0=默认,如 fpu_context=16)
|
||||
IsOOP: int # 1=OOP结构体(有方法) / 0=纯内存结构体
|
||||
HasInit: int # 1=有__init__方法 / 0=无
|
||||
HasNew: int # 1=有__new__方法 / 0=无
|
||||
HasVTable: int # 1=有虚表 / 0=无虚表
|
||||
IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记
|
||||
ParentName: str # 父类名(None=无父类,多继承时为第一个父类,兼容旧调用)
|
||||
ParentNames: sizet* # 多继承父类名数组(每元素 str 指针,ParentCount 个;stdlib 深拷贝)
|
||||
ParentCount: int # 父类数量(0=无父类,1=单继承,>1=多继承)
|
||||
VTableMethodCount: int # 虚表中的方法数量
|
||||
VTableMethods: str # 虚表方法名数组(每个方法名 str,VTableMethodCount 个)
|
||||
ModuleSha1: str # 定义该类的模块 SHA1(None=无 SHA1)
|
||||
MethodsEmitted: int # 1=方法体已翻译 / 0=未译(Phase 1a mark_only 未译,Phase B 据此补译)
|
||||
SpecTriggerSha1: str # 泛型特化类的触发文件 SHA1(None=非特化类)。特化类 ModuleSha1=模板
|
||||
# sha1(方法名带模板前缀),作废重译时 reset_module_methods_emitted
|
||||
# 按触发文件 sha1 精确重置 MethodsEmitted,防特化方法体残留 1 不补译
|
||||
# → 链接 undefined symbol(list[ast.ClassDef|t.CPtr].* 根因)
|
||||
IsForwardDecl: int # 1=前向声明占位条目(Ty=不透明具名结构体 {sha}.Class,FieldCount=0;
|
||||
# 定义侧随后**原位填充**同一 Ty 对象并清零本标记)。
|
||||
# 语义对齐 TPC:未注册类 → 具名空 CStruct 占位 + 后续 set_body 填充。
|
||||
|
||||
|
||||
# ============================================================
|
||||
# EnumMember - 枚举成员(原 HandlesEnum.EnumMember)
|
||||
# ============================================================
|
||||
class EnumMember:
|
||||
Name: str # 成员名(字符串)
|
||||
Value: int64 # 成员的整数值
|
||||
Ty: llvmlite.LLVMType* # 成员的 LLVM 类型(用于混用类型场景)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# EnumEntry - 枚举类型条目(原 HandlesEnum.EnumEntry)
|
||||
# ============================================================
|
||||
novirtual class EnumEntry:
|
||||
Name: str # 枚举类名
|
||||
BaseTy: llvmlite.LLVMType* # 基准类型(所有成员类型中最大的)
|
||||
MemberCount: int # 成员数量
|
||||
Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AsmOperand - 内联汇编操作数条目(原 HandlesExprCall.AsmOperand)
|
||||
# ============================================================
|
||||
class AsmOperand:
|
||||
"""内联汇编操作数条目"""
|
||||
Value: llvmlite.Value* # 输入值或输出 alloca
|
||||
Constraint: str # 约束字符串 (如 "r", "=r")
|
||||
IsOutput: int # 1=输出, 0=输入
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FuncEntry - 函数表条目(原 HandlesExprCall.FuncEntry)
|
||||
# ============================================================
|
||||
novirtual class FuncEntry:
|
||||
"""函数表条目"""
|
||||
Name: str
|
||||
Func: llvmlite.Function*
|
||||
Defaults: t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值
|
||||
DefaultCount: int # 默认值数量
|
||||
ParamCount: int # 形参数量(不含 self)
|
||||
# TypeSpec(S3 条目双写):Kind=TS_FUNC 的**整签名**(Ret/Params/ParamCount/IsVarArg
|
||||
# 都在其内),由 update_global_func_spec 在形参 add_param 完成后用 NewTypeFunc 构造。
|
||||
# PermPool 驻留 ⇒ 跨 1b reset 安全。单字段即可完整表达签名,与 VarEntry/FieldEntry
|
||||
# 的 Spec 命名一致,避免参数数组重复。
|
||||
Spec: TSpec.TypeSpec*
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FuncDefaultsEntry - 默认参数表条目(原 HandlesExprCall.FuncDefaultsEntry)
|
||||
# ============================================================
|
||||
novirtual class FuncDefaultsEntry:
|
||||
"""默认参数表条目"""
|
||||
Name: str
|
||||
ModuleSha1: str # 定义该函数的模块 SHA1(限定名去重,避免跨模块同名串味)
|
||||
Defaults: t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset)
|
||||
DefaultCount: int
|
||||
ParamCount: int # 形参数量(不含 self)
|
||||
# 常量快照(stdlib 分配,跨文件永久存活):
|
||||
# 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR,
|
||||
# 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。
|
||||
ConstKinds: int | t.CPtr # const_kind 数组(DefaultCount 个 i32)
|
||||
ConstInts: int64 | t.CPtr # int_val 数组(DefaultCount 个 i64)
|
||||
ConstStrs: sizet* # str_val 指针数组(DefaultCount 个 i8*)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# REPL 会话(M2/M3):ctx 缓冲区布局 + 会话表条目 + 结果区头
|
||||
#
|
||||
# ctx 缓冲区由宿主(lib/core/Repl.vp)在 PermPool 一次性分配,片段函数以首形参
|
||||
# 接收(注解 bytes ⇒ i8*),同一进程内宿主与翻译器共享同一块内存。
|
||||
#
|
||||
# 布局(用户拍板子约定;字节全小端,无符号/有符号按位模式):
|
||||
#
|
||||
# 偏移 0 magic(u32 = 'REPL' = 0x5245504C) 4 version(u32 = 2)
|
||||
# 偏移 8 result_kind(i32) 12 保留(0)
|
||||
# 偏移 16 result_a(u64) 24 result_b(u64)
|
||||
# 偏移 32 var_count(i32) 36 last_frag(i32)
|
||||
# 偏移 40..63 保留(0)
|
||||
# 偏移 64 + i*16 第 i 个会话变量的槽(步长 16 字节),i < REPL_VAR_CAP
|
||||
# 偏移 1088 + j*16 第 j 个会话函数的指针槽(步长 16 字节),j < REPL_FUNC_CAP
|
||||
#
|
||||
# 版本与向后兼容(version 1 → 2,**纯尾部追加**):
|
||||
# v1 = 头 64B + 变量槽区 1024B(共 1088B);v2 在 1088 之后追加函数指针槽区
|
||||
# (REPL_FUNC_CAP*REPL_FUNC_SLOT_SIZE)。前 1088 字节的字段偏移/宽度/语义逐字
|
||||
# 未变 ⇒ 按 v1 生成的旧片段 DLL 与 v2 宿主混用仍然正确(旧片段只读写
|
||||
# < 1088 的字节);新片段读函数指针槽时宿主必为 v2 ⇒ 无版本协商需求。
|
||||
# 头 +4 写 2 仅作"含函数指针槽区"的显式标记(片段侧不校验该字段)。
|
||||
#
|
||||
# result_kind:
|
||||
# 0 = none 本片段无结果(声明类片段)
|
||||
# 1 = int/uint result_a = 值(补码位模式,宿主按有符号 64 位回显)
|
||||
# 2 = float64 result_a = IEEE754 double 位模式(宿主重解释后回显)
|
||||
# 3 = str/bytes result_a = 指针;result_b = 长度(0 = 以 NUL 结尾,宿主按
|
||||
# C 字符串处理——片段侧不额外调 strlen,故长度未知时写 0)
|
||||
# 4 = struct/其它 result_a = 值地址(结构体值装箱后的盒子地址 / 非字符串指针)
|
||||
#
|
||||
# 槽内存放形态(ReplVarEntry.Kind):
|
||||
# SCALAR — 标量/指针(≤8 字节)的值直接存槽;
|
||||
# BOX — 结构体值:片段侧 malloc 盒子(值存盒内),槽内存盒子指针。
|
||||
# 槽步长 16 字节(结构体/字符串统一走指针 ⇒ 宿主无需知道类型);负载一律
|
||||
# ≤8 字节且 8 字节对齐即合法(MemBuddy 用户指针实测 8 字节对齐)。
|
||||
# 槽数上限 REPL_VAR_CAP ⇒ 变量区尺寸 = REPL_SLOT_BASE + REPL_VAR_CAP*REPL_SLOT_SIZE。
|
||||
#
|
||||
# 函数指针槽(M3):槽内是会话函数在**定义片段 DLL** 里的入口地址(void*,8 字节;
|
||||
# DLL 常驻不卸载 ⇒ 地址在会话期内有效)。宿主在片段 DLL 加载成功后
|
||||
# GetProcAddress(裸名) 取得地址并写入槽;后续片段的调用点从槽 load 地址后
|
||||
# 间接调用 ⇒ 函数代码只有一份(在定义片段里),调用点不复制代码。
|
||||
# ============================================================
|
||||
REPL_CTX_MARKER: t.CDefine = 1397571916 # 宿主侧对象标记(自比对;非 ctx 头字段)
|
||||
REPL_CTX_MAGIC: t.CDefine = 0x5245504C # 'REPL'(ctx 头 +0,小端字节序为 R E P L)
|
||||
REPL_CTX_VERSION: t.CDefine = 2 # ctx 头 +4(1 → 2:尾部追加函数指针槽区)
|
||||
REPL_SLOT_SIZE: t.CDefine = 16 # 每个会话变量占用字节数(步长)
|
||||
REPL_SLOT_BASE: t.CDefine = 64 # 槽区起点 = 固定头字节数(= +40..63 保留之后)
|
||||
REPL_CTX_PARAM: t.CDefine = "__repl_ctx__" # 包裹模板里 ctx 形参名(与 Repl.vp 同源)
|
||||
REPL_VAR_CAP: t.CDefine = 64 # 会话变量上限(变量区 = 64 + 64*16 = 1088 字节)
|
||||
# 会话函数指针槽区(M3):起点紧跟变量区,步长与变量槽一致(16B,低 8 字节存地址)
|
||||
REPL_FUNC_BASE: t.CDefine = 1088 # = REPL_SLOT_BASE + REPL_VAR_CAP*REPL_SLOT_SIZE
|
||||
REPL_FUNC_SLOT_SIZE: t.CDefine = 16 # 每个会话函数占用字节数(步长)
|
||||
REPL_FUNC_CAP: t.CDefine = 32 # 会话函数上限(函数区 = 32*16 = 512 字节)
|
||||
# ctx 总字节数 = 64 + 64*16 + 32*16 = 1600(宿主 Repl._REPL_CTX_SIZE 必须一致)
|
||||
REPL_CTX_SIZE: t.CDefine = 1600
|
||||
# 会话函数的形参上限(签名 token 数组定长;超出 ⇒ 注册期明确报错)
|
||||
REPL_FUNC_PARAM_MAX: t.CDefine = 8
|
||||
# 片段入口函数名前缀(Repl.vp 生成 "__repl_frag_%d";用于区分"片段入口函数"与
|
||||
# 被提升的会话函数本体——前者是会话变量写入的作用域,后者只读会话槽)
|
||||
REPL_ENTRY_PREFIX: t.CDefine = "__repl_frag_"
|
||||
# 会话模块 SHA1(M4):片段翻译器的 ModuleSha1 取此**稳定**值 ⇒ 片段内定义的类型
|
||||
# 名形如 "<16位hex>.<Type>",且**跨片段逐字一致**——这是"先前片段定义的类在后续
|
||||
# 片段可见/可用"的基础(类型名是跨片段查找的唯一键)。
|
||||
# 派生:sha1("TransPyV-REPL-Session").hexdigest()[:16]
|
||||
# 得 71f67b7cb405f0e4(一次性计算,见 repl-design.md §M4 的可复算命令)。
|
||||
# 形态:16 位小写 hex 与 includes 模块 SHA1 同形 ⇒ 被既有判定
|
||||
# GenApi.is_sha1_hex16 / StructGen.find_struct 的"模块段即 SHA1"分支
|
||||
# 直接当作模块限定名处理(无需新增解析规则)。
|
||||
# 反例(为什么不给每个片段各设一个 sha1):类型名会随片段漂移,先前片段注册的
|
||||
# 结构体/方法在后续片段的 find_struct_by_module 全部落空。
|
||||
# 与裸名约定的关系:`export def`(含片段入口与会话函数)走 has_export 分支取裸名
|
||||
# (FuncGenDef.vp:482-485),**不受**该值影响;受影响的只有类/方法/模块级全局
|
||||
# 等经 _mangle_name/_mangle_name_with_sha1 命名的符号。
|
||||
REPL_SESSION_SHA1: t.CDefine = "71f67b7cb405f0e4"
|
||||
|
||||
# ctx 头字段偏移(与 ReplResult 字段顺序/宽度一一对应)
|
||||
REPL_RES_KIND_OFF: t.CDefine = 8 # i32
|
||||
REPL_RES_A_OFF: t.CDefine = 16 # u64
|
||||
REPL_RES_B_OFF: t.CDefine = 24 # u64
|
||||
REPL_RES_VARCOUNT_OFF: t.CDefine = 32 # i32
|
||||
REPL_RES_LASTFRAG_OFF: t.CDefine = 36 # i32
|
||||
|
||||
# 结果 Kind(宿主按此回显)
|
||||
REPL_RES_NONE: t.CDefine = 0 # 本片段无结果(如仅声明)
|
||||
REPL_RES_INT: t.CDefine = 1 # 整数(读 result_a 位模式)
|
||||
REPL_RES_FLOAT: t.CDefine = 2 # float64(读 result_a 的 double 位模式)
|
||||
REPL_RES_STR: t.CDefine = 3 # str/bytes(读 result_a 指针 + result_b 长度)
|
||||
REPL_RES_OBJ: t.CDefine = 4 # 结构体/其它指针(读 result_a 地址)
|
||||
|
||||
# 会话变量类型标签(ReplVarEntry.TyTag)
|
||||
REPL_TY_INT: t.CDefine = 1
|
||||
REPL_TY_FLOAT: t.CDefine = 2
|
||||
REPL_TY_STR: t.CDefine = 3 # i8*(str/bytes)
|
||||
REPL_TY_PTR: t.CDefine = 4 # 其他指针(Bits=pointee 位宽 / TyName=结构体名)
|
||||
REPL_TY_STRUCT: t.CDefine = 5 # 结构体值(按声明类型内联在槽里;≤ 槽容量)
|
||||
|
||||
# 会话变量存放形态(ReplVarEntry.Kind)
|
||||
REPL_KIND_UNTYPED: t.CDefine = 0 # 已登记槽位但尚未定型(未赋值/无注解)
|
||||
REPL_KIND_SCALAR: t.CDefine = 1 # 值内联存槽(标量/指针/≤16B 结构体值)
|
||||
|
||||
# 会话函数签名的返回类型 token(M3;只用于 ReplFuncEntry.RetTag)
|
||||
REPL_TY_VOID: t.CDefine = 0 # 无返回值(void;不作为形参 token)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ReplVarEntry - REPL 会话变量条目(跨片段存活,表本体在 PermPool)
|
||||
# ============================================================
|
||||
novirtual class ReplVarEntry:
|
||||
"""REPL 会话变量条目:名字 + ctx 槽偏移 + 定型信息
|
||||
|
||||
Name/TyName 必须是 PermPool 深拷贝——宿主的 AST 名字串属于片段 pool,
|
||||
行末 reset_to 后即失效,直接存指针会读到已回收内存。
|
||||
"""
|
||||
Name: str # 变量名(PermPool 深拷贝,NUL 结尾)
|
||||
TyName: str # 结构体名(TyTag=PTR 且 pointee 为结构体 / TyTag=STRUCT);否则 None
|
||||
Offset: int # ctx 内槽偏移(REPL_SLOT_BASE + i * REPL_SLOT_SIZE)
|
||||
Kind: int # REPL_KIND_*
|
||||
TyTag: int # REPL_TY_*
|
||||
Bits: int # 标量位宽;TyTag=PTR 时是 pointee 位宽(0=未知)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ReplFuncEntry - REPL 会话函数条目(M3;跨片段存活,表本体在 PermPool)
|
||||
#
|
||||
# 语义:片段 N 里 `def f(...)` 被提升为片段模块里的**顶层 export def**(裸名导出),
|
||||
# 该 DLL 加载后宿主 GetProcAddress 取到地址并写入 ctx 的函数指针槽;本条目记录
|
||||
# "名字 → 符号名 + 定义片段号 + 槽偏移 + 签名 token",后续片段的调用点据此
|
||||
# 从槽 load 地址并间接调用(与 M2 的会话变量槽同理:单一真相 + 间接寻址)。
|
||||
#
|
||||
# 签名 token(ParamTags/ParamBits 每形参 1 字节、RetTag/RetBits)与来源:
|
||||
# 定义片段翻译出的 IR 里 `define <ret> @f(i8* %__repl_ctx__, <P1> %p1, ...)`
|
||||
# 是 ABI 的唯一真相(注解 → LLVM 类型由 codegen 解析),宿主在注册前解析该
|
||||
# define 行并**只接受**可往返重建的 token 集合:
|
||||
# REPL_TY_INT(bits=1/8/16/32/64) / REPL_TY_FLOAT(bits=32/64) / REPL_TY_STR(i8*)
|
||||
# 其余类型(结构体值、数组、多级指针等)⇒ 注册期明确报错,绝不静默按 i32 兜底。
|
||||
# ============================================================
|
||||
novirtual class ReplFuncEntry:
|
||||
"""REPL 会话函数条目:名字 + 导出符号名 + ctx 函数指针槽 + 签名 token"""
|
||||
Name: str # 会话函数名(= 用户写的裸名;PermPool 深拷贝,NUL 结尾)
|
||||
SymName: str # 片段 DLL 里的导出符号名(PermPool 深拷贝;M3 = 裸名)
|
||||
FragNo: int # 定义该函数的片段号(重定义时更新为最新片段号)
|
||||
SlotOff: int # ctx 内函数指针槽偏移(REPL_FUNC_BASE + j*REPL_FUNC_SLOT_SIZE)
|
||||
RetTag: int # REPL_TY_VOID / REPL_TY_INT / REPL_TY_FLOAT / REPL_TY_STR
|
||||
RetBits: int # 对齐 ReplVarEntry.Bits 的口径(VOID 时为 0)
|
||||
ParamCount: int # 形参数(**不含**注入的 ctx 首形参)
|
||||
ParamTags: str # PermPool 字节数组(每形参 1 字节 tag,REPL_FUNC_PARAM_MAX 个)
|
||||
ParamBits: str # PermPool 字节数组(每形参 1 字节 bits,REPL_FUNC_PARAM_MAX 个)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ReplCtx - REPL 会话上下文(宿主建、翻译器读)
|
||||
#
|
||||
# 开关语义:trans.ReplCtx != None ⇒ REPL 模式(仅 Repl.vp 翻译片段前置位,
|
||||
# 翻译后清空)。Gen 侧全部拦截点都以此字段为唯一守卫——普通编译路径下该字段
|
||||
# 恒为 None,逐字走原路径。
|
||||
# ============================================================
|
||||
novirtual class ReplCtx:
|
||||
"""REPL 模式上下文(宿主持有;翻译器只读)"""
|
||||
Marker: int # REPL_CTX_MARKER(防误传非 ReplCtx 对象)
|
||||
Table: rawptr[ReplVarEntry] # 会话表数组(PermPool,容量 Cap)
|
||||
Count: int # 已登记条目数(= 已分配槽数)
|
||||
Cap: int # 容量(REPL_VAR_CAP)
|
||||
CtxParam: str # 片段函数 ctx 形参名(PermPool 深拷贝)
|
||||
SlotSize: int # 槽步长(REPL_SLOT_SIZE)
|
||||
# 影子条目(宿主建、PermPool):仅供"裸表达式结果"做类型分类用,不占会话槽、
|
||||
# 不进表(Count 不计入),Name 固定为 "<expr>" 以便错误消息可读。
|
||||
Scratch: rawptr[ReplVarEntry]
|
||||
# 宿主提供的永久池:会话表条目名/结构体名等**跨片段存活**的数据必须在此池
|
||||
# 深拷贝(片段的 trans.Pool 行末 reset_to 即回收,直接存其指针会悬垂)。
|
||||
Perm: memhub.MemBuddy*
|
||||
# 会话函数表(M3;宿主写、Gen 只读):数组容量 FuncCap,已登记 FuncCount 条。
|
||||
# 条目只在"定义片段 DLL 加载成功且 GetProcAddress 命中"后由宿主追加 ⇒ 片段
|
||||
# 翻译期看到的表恒为"先前片段的已就绪函数"(本片段新定义的同名函数走直接调用)。
|
||||
FuncTable: rawptr[ReplFuncEntry]
|
||||
FuncCount: int
|
||||
FuncCap: int # 容量(REPL_FUNC_CAP)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ReplResult - ctx 头(宿主按字段读;片段按 REPL_RES_*_OFF 字节偏移写)
|
||||
#
|
||||
# 字段顺序/宽度即 ctx 布局:Magic(+0,i32) Version(+4,i32) Kind(+8,i32)
|
||||
# Reserved0(+12,i32) A(+16,i64) B(+24,i64) VarCount(+32,i32) LastFrag(+36,i32)。
|
||||
# 宿主另有"同一头的浮点视图"(把 +16 的 8 字节按 double 读回,见 Repl.vp)。
|
||||
# ============================================================
|
||||
novirtual class ReplResult:
|
||||
"""ctx 固定头(前 64 字节中的前 40 字节;+40..63 为保留)"""
|
||||
Magic: int # REPL_CTX_MAGIC('REPL')
|
||||
Version: int # REPL_CTX_VERSION
|
||||
Kind: int # REPL_RES_*
|
||||
Reserved0: int # 保留(0)
|
||||
A: t.CInt64T # result_a
|
||||
B: t.CInt64T # result_b
|
||||
VarCount: int # 已分配槽数(宿主写,供检视)
|
||||
LastFrag: int # 最近执行的片段号(宿主写,供检视)
|
||||
+462
-468
@@ -1,468 +1,462 @@
|
||||
import string
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
import memhub
|
||||
import llvmlite
|
||||
import lib.core.Gen.BaseGenMixin as BaseGenMixin
|
||||
import lib.core.Gen.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.TypeGenMixin as TypeGenMixin
|
||||
import lib.core.Gen.TypeGenCDef as TypeGenCDef
|
||||
import lib.core.Gen.TypeGenCType as TypeGenCType
|
||||
import lib.core.Gen.TypeGenResolve as TypeGenResolve
|
||||
import lib.core.Gen.TypeGenErr as TypeGenErr
|
||||
import lib.core.Gen.StructGenMixin as StructGenMixin
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
import lib.core.Gen.ExprGenMixin as ExprGenMixin
|
||||
import lib.core.Gen.ExprGenConst as ExprGenConst
|
||||
import lib.core.Gen.ExprGenFstr as ExprGenFstr
|
||||
import lib.core.Gen.ExprGenOps as ExprGenOps
|
||||
import lib.core.Gen.ExprGenCdef as ExprGenCdef
|
||||
import lib.core.Gen.ExprGenName as ExprGenName
|
||||
import lib.core.Gen.ExprGenAttr as ExprGenAttr
|
||||
import lib.core.Gen.ExprGenCls as ExprGenCls
|
||||
import lib.core.Gen.CallGenBase as CallGenBase
|
||||
import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin
|
||||
import lib.core.Gen.CallGenLeafKit as CallGenLeafKit
|
||||
import lib.core.Gen.CallGenCtor as CallGenCtor
|
||||
import lib.core.Gen.CallGenCall as CallGenCall
|
||||
import lib.core.Gen.CallGenMixin as CallGenMixin
|
||||
import lib.core.Gen.CallGenDispatch as CallGenDispatch
|
||||
import lib.core.Gen.CallGenLib as CallGenLib
|
||||
import lib.core.Gen.CallGenVt as CallGenVt
|
||||
import lib.core.Gen.CallGenVa as CallGenVa
|
||||
import lib.core.Gen.CallGenProp as CallGenProp
|
||||
import lib.core.Gen.CallGenFd as CallGenFd
|
||||
import lib.core.Gen.FuncGenBase as FuncGenBase
|
||||
import lib.core.Gen.FuncGenDef as FuncGenDef
|
||||
import lib.core.Gen.FuncGenMixin as FuncGenMixin
|
||||
import lib.core.Gen.ClassGenBase as ClassGenBase
|
||||
import lib.core.Gen.ClassGenMixin as ClassGenMixin
|
||||
import lib.core.Gen.ClassGenEnum as ClassGenEnum
|
||||
import lib.core.Gen.ClassGenGeneric as ClassGenGeneric
|
||||
import lib.core.Gen.ClassGenVTable as ClassGenVTable
|
||||
import lib.core.Gen.ClassGenDef as ClassGenDef
|
||||
import lib.core.Gen.ImportsGenMixin as ImportsGenMixin
|
||||
import lib.core.Gen.StmtGenCifMixin as StmtGenCifMixin
|
||||
import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin
|
||||
import lib.core.Gen.StmtGenMixin as StmtGenMixin
|
||||
import lib.core.Gen.MatchGenMixin as MatchGenMixin
|
||||
import lib.core.Gen.AssignGenMixin as AssignGenMixin
|
||||
import lib.core.Gen.AsyncGenMixin as AsyncGenMixin
|
||||
import lib.core.Gen.VarGenMixin as VarGenMixin
|
||||
import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Generator - 生成器(双向引用组合架构)
|
||||
#
|
||||
# 不再 46 路多继承 Mixin;改为组合:Generator 持所有 GenMixin
|
||||
# 子对象指针(永久池分配,全生命周期),每个 Mixin 持 Gen 回指。
|
||||
# 跨子对象访问 = self.Gen.<Mixin 字段>.<字段/方法>(链式有风险,
|
||||
# 统一用中间变量取子对象再访问)。高亮可推导(显式类型注解)。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class Generator:
|
||||
"""生成器:持所有 GenMixin 子对象指针(双向引用组合)"""
|
||||
|
||||
# ---- 子对象指针(46 个,永久池) ----
|
||||
BaseGen: BaseGenMixin.BaseGenMixin | t.CPtr
|
||||
TypeGenBase: TypeGenBase.TypeGenBase | t.CPtr
|
||||
TypeGen: TypeGenMixin.TypeGenMixin | t.CPtr
|
||||
TypeGenCDef: TypeGenCDef.TypeGenCDef | t.CPtr
|
||||
TypeGenCType: TypeGenCType.TypeGenCType | t.CPtr
|
||||
TypeGenResolve: TypeGenResolve.TypeGenResolve | t.CPtr
|
||||
TypeGenErr: TypeGenErr.TypeGenErr | t.CPtr
|
||||
StructGen: StructGenMixin.StructGenMixin | t.CPtr
|
||||
ExprGenBase: ExprGenBase.ExprGenBase | t.CPtr
|
||||
ExprGen: ExprGenMixin.ExprGenMixin | t.CPtr
|
||||
ExprGenConst: ExprGenConst.ExprGenConst | t.CPtr
|
||||
ExprGenFstr: ExprGenFstr.ExprGenFstr | t.CPtr
|
||||
ExprGenOps: ExprGenOps.ExprGenOps | t.CPtr
|
||||
ExprGenCdef: ExprGenCdef.ExprGenCdef | t.CPtr
|
||||
ExprGenName: ExprGenName.ExprGenName | t.CPtr
|
||||
ExprGenAttr: ExprGenAttr.ExprGenAttr | t.CPtr
|
||||
ExprGenCls: ExprGenCls.ExprGenCls | t.CPtr
|
||||
CallGenBase: CallGenBase.CallGenBase | t.CPtr
|
||||
CallGenCBuiltin: CallGenCBuiltin.CallGenCBuiltin | t.CPtr
|
||||
CallGenLeafKit: CallGenLeafKit.CallGenLeafKit | t.CPtr
|
||||
CallGenCtor: CallGenCtor.CallGenCtor | t.CPtr
|
||||
CallGenCall: CallGenCall.CallGenCall | t.CPtr
|
||||
CallGen: CallGenMixin.CallGenMixin | t.CPtr
|
||||
CallGenDispatch: CallGenDispatch.CallGenDispatch | t.CPtr
|
||||
CallGenLib: CallGenLib.CallGenLib | t.CPtr
|
||||
CallGenVt: CallGenVt.CallGenVt | t.CPtr
|
||||
CallGenVa: CallGenVa.CallGenVa | t.CPtr
|
||||
CallGenProp: CallGenProp.CallGenProp | t.CPtr
|
||||
CallGenFd: CallGenFd.CallGenFd | t.CPtr
|
||||
FuncGenBase: FuncGenBase.FuncGenBase | t.CPtr
|
||||
FuncGenDef: FuncGenDef.FuncGenDef | t.CPtr
|
||||
FuncGen: FuncGenMixin.FuncGenMixin | t.CPtr
|
||||
ClassGenBase: ClassGenBase.ClassGenBase | t.CPtr
|
||||
ClassGen: ClassGenMixin.ClassGenMixin | t.CPtr
|
||||
ClassGenEnum: ClassGenEnum.ClassGenEnum | t.CPtr
|
||||
ClassGenGeneric: ClassGenGeneric.ClassGenGeneric | t.CPtr
|
||||
ClassGenVTable: ClassGenVTable.ClassGenVTable | t.CPtr
|
||||
ClassGenDef: ClassGenDef.ClassGenDef | t.CPtr
|
||||
ImportsGen: ImportsGenMixin.ImportsGenMixin | t.CPtr
|
||||
StmtGenCif: StmtGenCifMixin.StmtGenCifMixin | t.CPtr
|
||||
StmtGenDecl: StmtGenDeclMixin.StmtGenDeclMixin | t.CPtr
|
||||
StmtGen: StmtGenMixin.StmtGenMixin | t.CPtr
|
||||
MatchGen: MatchGenMixin.MatchGenMixin | t.CPtr
|
||||
AssignGen: AssignGenMixin.AssignGenMixin | t.CPtr
|
||||
AsyncGen: AsyncGenMixin.AsyncGenMixin | t.CPtr
|
||||
VarGen: VarGenMixin.VarGenMixin | t.CPtr
|
||||
TranslatorGen: TranslatorGenMixin.TranslatorGenMixin | t.CPtr
|
||||
|
||||
def __init__(self, pool: memhub.MemBuddy | t.CPtr):
|
||||
if self is None:
|
||||
return
|
||||
# ---- alloc 46 个子对象 + 回指(永久池,fail-fast) ----
|
||||
SubBaseGen: BaseGenMixin.BaseGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(BaseGenMixin.BaseGenMixin.__sizeof__())
|
||||
if SubBaseGen is None:
|
||||
stdio.printf("FAIL: BaseGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubBaseGen, 0, BaseGenMixin.BaseGenMixin.__sizeof__())
|
||||
SubBaseGen.Gen = self
|
||||
self.BaseGen = SubBaseGen
|
||||
SubTypeGenBase: TypeGenBase.TypeGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenBase.TypeGenBase.__sizeof__())
|
||||
if SubTypeGenBase is None:
|
||||
stdio.printf("FAIL: TypeGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenBase, 0, TypeGenBase.TypeGenBase.__sizeof__())
|
||||
SubTypeGenBase.Gen = self
|
||||
self.TypeGenBase = SubTypeGenBase
|
||||
SubTypeGen: TypeGenMixin.TypeGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenMixin.TypeGenMixin.__sizeof__())
|
||||
if SubTypeGen is None:
|
||||
stdio.printf("FAIL: TypeGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGen, 0, TypeGenMixin.TypeGenMixin.__sizeof__())
|
||||
SubTypeGen.Gen = self
|
||||
self.TypeGen = SubTypeGen
|
||||
SubTypeGenCDef: TypeGenCDef.TypeGenCDef | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenCDef.TypeGenCDef.__sizeof__())
|
||||
if SubTypeGenCDef is None:
|
||||
stdio.printf("FAIL: TypeGenCDef alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenCDef, 0, TypeGenCDef.TypeGenCDef.__sizeof__())
|
||||
SubTypeGenCDef.Gen = self
|
||||
self.TypeGenCDef = SubTypeGenCDef
|
||||
SubTypeGenCType: TypeGenCType.TypeGenCType | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenCType.TypeGenCType.__sizeof__())
|
||||
if SubTypeGenCType is None:
|
||||
stdio.printf("FAIL: TypeGenCType alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenCType, 0, TypeGenCType.TypeGenCType.__sizeof__())
|
||||
SubTypeGenCType.Gen = self
|
||||
self.TypeGenCType = SubTypeGenCType
|
||||
SubTypeGenResolve: TypeGenResolve.TypeGenResolve | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenResolve.TypeGenResolve.__sizeof__())
|
||||
if SubTypeGenResolve is None:
|
||||
stdio.printf("FAIL: TypeGenResolve alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenResolve, 0, TypeGenResolve.TypeGenResolve.__sizeof__())
|
||||
SubTypeGenResolve.Gen = self
|
||||
self.TypeGenResolve = SubTypeGenResolve
|
||||
SubTypeGenErr: TypeGenErr.TypeGenErr | t.CPtr = CompilerFactory.get_perm_pool().alloc(TypeGenErr.TypeGenErr.__sizeof__())
|
||||
if SubTypeGenErr is None:
|
||||
stdio.printf("FAIL: TypeGenErr alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenErr, 0, TypeGenErr.TypeGenErr.__sizeof__())
|
||||
SubTypeGenErr.Gen = self
|
||||
self.TypeGenErr = SubTypeGenErr
|
||||
SubStructGen: StructGenMixin.StructGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(StructGenMixin.StructGenMixin.__sizeof__())
|
||||
if SubStructGen is None:
|
||||
stdio.printf("FAIL: StructGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubStructGen, 0, StructGenMixin.StructGenMixin.__sizeof__())
|
||||
SubStructGen.Gen = self
|
||||
self.StructGen = SubStructGen
|
||||
SubExprGenBase: ExprGenBase.ExprGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenBase.ExprGenBase.__sizeof__())
|
||||
if SubExprGenBase is None:
|
||||
stdio.printf("FAIL: ExprGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenBase, 0, ExprGenBase.ExprGenBase.__sizeof__())
|
||||
SubExprGenBase.Gen = self
|
||||
self.ExprGenBase = SubExprGenBase
|
||||
SubExprGen: ExprGenMixin.ExprGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenMixin.ExprGenMixin.__sizeof__())
|
||||
if SubExprGen is None:
|
||||
stdio.printf("FAIL: ExprGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGen, 0, ExprGenMixin.ExprGenMixin.__sizeof__())
|
||||
SubExprGen.Gen = self
|
||||
self.ExprGen = SubExprGen
|
||||
SubExprGenConst: ExprGenConst.ExprGenConst | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenConst.ExprGenConst.__sizeof__())
|
||||
if SubExprGenConst is None:
|
||||
stdio.printf("FAIL: ExprGenConst alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenConst, 0, ExprGenConst.ExprGenConst.__sizeof__())
|
||||
SubExprGenConst.Gen = self
|
||||
self.ExprGenConst = SubExprGenConst
|
||||
SubExprGenFstr: ExprGenFstr.ExprGenFstr | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenFstr.ExprGenFstr.__sizeof__())
|
||||
if SubExprGenFstr is None:
|
||||
stdio.printf("FAIL: ExprGenFstr alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenFstr, 0, ExprGenFstr.ExprGenFstr.__sizeof__())
|
||||
SubExprGenFstr.Gen = self
|
||||
self.ExprGenFstr = SubExprGenFstr
|
||||
SubExprGenOps: ExprGenOps.ExprGenOps | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenOps.ExprGenOps.__sizeof__())
|
||||
if SubExprGenOps is None:
|
||||
stdio.printf("FAIL: ExprGenOps alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenOps, 0, ExprGenOps.ExprGenOps.__sizeof__())
|
||||
SubExprGenOps.Gen = self
|
||||
self.ExprGenOps = SubExprGenOps
|
||||
SubExprGenCdef: ExprGenCdef.ExprGenCdef | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenCdef.ExprGenCdef.__sizeof__())
|
||||
if SubExprGenCdef is None:
|
||||
stdio.printf("FAIL: ExprGenCdef alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenCdef, 0, ExprGenCdef.ExprGenCdef.__sizeof__())
|
||||
SubExprGenCdef.Gen = self
|
||||
self.ExprGenCdef = SubExprGenCdef
|
||||
SubExprGenName: ExprGenName.ExprGenName | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenName.ExprGenName.__sizeof__())
|
||||
if SubExprGenName is None:
|
||||
stdio.printf("FAIL: ExprGenName alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenName, 0, ExprGenName.ExprGenName.__sizeof__())
|
||||
SubExprGenName.Gen = self
|
||||
self.ExprGenName = SubExprGenName
|
||||
SubExprGenAttr: ExprGenAttr.ExprGenAttr | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenAttr.ExprGenAttr.__sizeof__())
|
||||
if SubExprGenAttr is None:
|
||||
stdio.printf("FAIL: ExprGenAttr alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenAttr, 0, ExprGenAttr.ExprGenAttr.__sizeof__())
|
||||
SubExprGenAttr.Gen = self
|
||||
self.ExprGenAttr = SubExprGenAttr
|
||||
SubExprGenCls: ExprGenCls.ExprGenCls | t.CPtr = CompilerFactory.get_perm_pool().alloc(ExprGenCls.ExprGenCls.__sizeof__())
|
||||
if SubExprGenCls is None:
|
||||
stdio.printf("FAIL: ExprGenCls alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenCls, 0, ExprGenCls.ExprGenCls.__sizeof__())
|
||||
SubExprGenCls.Gen = self
|
||||
self.ExprGenCls = SubExprGenCls
|
||||
SubCallGenBase: CallGenBase.CallGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenBase.CallGenBase.__sizeof__())
|
||||
if SubCallGenBase is None:
|
||||
stdio.printf("FAIL: CallGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenBase, 0, CallGenBase.CallGenBase.__sizeof__())
|
||||
SubCallGenBase.Gen = self
|
||||
self.CallGenBase = SubCallGenBase
|
||||
SubCallGenCBuiltin: CallGenCBuiltin.CallGenCBuiltin | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenCBuiltin.CallGenCBuiltin.__sizeof__())
|
||||
if SubCallGenCBuiltin is None:
|
||||
stdio.printf("FAIL: CallGenCBuiltin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenCBuiltin, 0, CallGenCBuiltin.CallGenCBuiltin.__sizeof__())
|
||||
SubCallGenCBuiltin.Gen = self
|
||||
self.CallGenCBuiltin = SubCallGenCBuiltin
|
||||
SubCallGenLeafKit: CallGenLeafKit.CallGenLeafKit | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenLeafKit.CallGenLeafKit.__sizeof__())
|
||||
if SubCallGenLeafKit is None:
|
||||
stdio.printf("FAIL: CallGenLeafKit alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenLeafKit, 0, CallGenLeafKit.CallGenLeafKit.__sizeof__())
|
||||
SubCallGenLeafKit.Gen = self
|
||||
self.CallGenLeafKit = SubCallGenLeafKit
|
||||
SubCallGenCtor: CallGenCtor.CallGenCtor | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenCtor.CallGenCtor.__sizeof__())
|
||||
if SubCallGenCtor is None:
|
||||
stdio.printf("FAIL: CallGenCtor alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenCtor, 0, CallGenCtor.CallGenCtor.__sizeof__())
|
||||
SubCallGenCtor.Gen = self
|
||||
self.CallGenCtor = SubCallGenCtor
|
||||
SubCallGenCall: CallGenCall.CallGenCall | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenCall.CallGenCall.__sizeof__())
|
||||
if SubCallGenCall is None:
|
||||
stdio.printf("FAIL: CallGenCall alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenCall, 0, CallGenCall.CallGenCall.__sizeof__())
|
||||
SubCallGenCall.Gen = self
|
||||
self.CallGenCall = SubCallGenCall
|
||||
SubCallGen: CallGenMixin.CallGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenMixin.CallGenMixin.__sizeof__())
|
||||
if SubCallGen is None:
|
||||
stdio.printf("FAIL: CallGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGen, 0, CallGenMixin.CallGenMixin.__sizeof__())
|
||||
SubCallGen.Gen = self
|
||||
self.CallGen = SubCallGen
|
||||
SubCallGenDispatch: CallGenDispatch.CallGenDispatch | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenDispatch.CallGenDispatch.__sizeof__())
|
||||
if SubCallGenDispatch is None:
|
||||
stdio.printf("FAIL: CallGenDispatch alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenDispatch, 0, CallGenDispatch.CallGenDispatch.__sizeof__())
|
||||
SubCallGenDispatch.Gen = self
|
||||
self.CallGenDispatch = SubCallGenDispatch
|
||||
SubCallGenLib: CallGenLib.CallGenLib | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenLib.CallGenLib.__sizeof__())
|
||||
if SubCallGenLib is None:
|
||||
stdio.printf("FAIL: CallGenLib alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenLib, 0, CallGenLib.CallGenLib.__sizeof__())
|
||||
SubCallGenLib.Gen = self
|
||||
self.CallGenLib = SubCallGenLib
|
||||
SubCallGenVt: CallGenVt.CallGenVt | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenVt.CallGenVt.__sizeof__())
|
||||
if SubCallGenVt is None:
|
||||
stdio.printf("FAIL: CallGenVt alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenVt, 0, CallGenVt.CallGenVt.__sizeof__())
|
||||
SubCallGenVt.Gen = self
|
||||
self.CallGenVt = SubCallGenVt
|
||||
SubCallGenVa: CallGenVa.CallGenVa | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenVa.CallGenVa.__sizeof__())
|
||||
if SubCallGenVa is None:
|
||||
stdio.printf("FAIL: CallGenVa alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenVa, 0, CallGenVa.CallGenVa.__sizeof__())
|
||||
SubCallGenVa.Gen = self
|
||||
self.CallGenVa = SubCallGenVa
|
||||
SubCallGenProp: CallGenProp.CallGenProp | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenProp.CallGenProp.__sizeof__())
|
||||
if SubCallGenProp is None:
|
||||
stdio.printf("FAIL: CallGenProp alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenProp, 0, CallGenProp.CallGenProp.__sizeof__())
|
||||
SubCallGenProp.Gen = self
|
||||
self.CallGenProp = SubCallGenProp
|
||||
SubCallGenFd: CallGenFd.CallGenFd | t.CPtr = CompilerFactory.get_perm_pool().alloc(CallGenFd.CallGenFd.__sizeof__())
|
||||
if SubCallGenFd is None:
|
||||
stdio.printf("FAIL: CallGenFd alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenFd, 0, CallGenFd.CallGenFd.__sizeof__())
|
||||
SubCallGenFd.Gen = self
|
||||
self.CallGenFd = SubCallGenFd
|
||||
SubFuncGenBase: FuncGenBase.FuncGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(FuncGenBase.FuncGenBase.__sizeof__())
|
||||
if SubFuncGenBase is None:
|
||||
stdio.printf("FAIL: FuncGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubFuncGenBase, 0, FuncGenBase.FuncGenBase.__sizeof__())
|
||||
SubFuncGenBase.Gen = self
|
||||
self.FuncGenBase = SubFuncGenBase
|
||||
SubFuncGenDef: FuncGenDef.FuncGenDef | t.CPtr = CompilerFactory.get_perm_pool().alloc(FuncGenDef.FuncGenDef.__sizeof__())
|
||||
if SubFuncGenDef is None:
|
||||
stdio.printf("FAIL: FuncGenDef alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubFuncGenDef, 0, FuncGenDef.FuncGenDef.__sizeof__())
|
||||
SubFuncGenDef.Gen = self
|
||||
self.FuncGenDef = SubFuncGenDef
|
||||
SubFuncGen: FuncGenMixin.FuncGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(FuncGenMixin.FuncGenMixin.__sizeof__())
|
||||
if SubFuncGen is None:
|
||||
stdio.printf("FAIL: FuncGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubFuncGen, 0, FuncGenMixin.FuncGenMixin.__sizeof__())
|
||||
SubFuncGen.Gen = self
|
||||
self.FuncGen = SubFuncGen
|
||||
SubClassGenBase: ClassGenBase.ClassGenBase | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenBase.ClassGenBase.__sizeof__())
|
||||
if SubClassGenBase is None:
|
||||
stdio.printf("FAIL: ClassGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenBase, 0, ClassGenBase.ClassGenBase.__sizeof__())
|
||||
SubClassGenBase.Gen = self
|
||||
self.ClassGenBase = SubClassGenBase
|
||||
SubClassGen: ClassGenMixin.ClassGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenMixin.ClassGenMixin.__sizeof__())
|
||||
if SubClassGen is None:
|
||||
stdio.printf("FAIL: ClassGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGen, 0, ClassGenMixin.ClassGenMixin.__sizeof__())
|
||||
SubClassGen.Gen = self
|
||||
self.ClassGen = SubClassGen
|
||||
SubClassGenEnum: ClassGenEnum.ClassGenEnum | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenEnum.ClassGenEnum.__sizeof__())
|
||||
if SubClassGenEnum is None:
|
||||
stdio.printf("FAIL: ClassGenEnum alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenEnum, 0, ClassGenEnum.ClassGenEnum.__sizeof__())
|
||||
SubClassGenEnum.Gen = self
|
||||
self.ClassGenEnum = SubClassGenEnum
|
||||
SubClassGenGeneric: ClassGenGeneric.ClassGenGeneric | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenGeneric.ClassGenGeneric.__sizeof__())
|
||||
if SubClassGenGeneric is None:
|
||||
stdio.printf("FAIL: ClassGenGeneric alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenGeneric, 0, ClassGenGeneric.ClassGenGeneric.__sizeof__())
|
||||
SubClassGenGeneric.Gen = self
|
||||
self.ClassGenGeneric = SubClassGenGeneric
|
||||
SubClassGenVTable: ClassGenVTable.ClassGenVTable | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenVTable.ClassGenVTable.__sizeof__())
|
||||
if SubClassGenVTable is None:
|
||||
stdio.printf("FAIL: ClassGenVTable alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenVTable, 0, ClassGenVTable.ClassGenVTable.__sizeof__())
|
||||
SubClassGenVTable.Gen = self
|
||||
self.ClassGenVTable = SubClassGenVTable
|
||||
SubClassGenDef: ClassGenDef.ClassGenDef | t.CPtr = CompilerFactory.get_perm_pool().alloc(ClassGenDef.ClassGenDef.__sizeof__())
|
||||
if SubClassGenDef is None:
|
||||
stdio.printf("FAIL: ClassGenDef alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenDef, 0, ClassGenDef.ClassGenDef.__sizeof__())
|
||||
SubClassGenDef.Gen = self
|
||||
self.ClassGenDef = SubClassGenDef
|
||||
SubImportsGen: ImportsGenMixin.ImportsGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(ImportsGenMixin.ImportsGenMixin.__sizeof__())
|
||||
if SubImportsGen is None:
|
||||
stdio.printf("FAIL: ImportsGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubImportsGen, 0, ImportsGenMixin.ImportsGenMixin.__sizeof__())
|
||||
SubImportsGen.Gen = self
|
||||
self.ImportsGen = SubImportsGen
|
||||
SubStmtGenCif: StmtGenCifMixin.StmtGenCifMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(StmtGenCifMixin.StmtGenCifMixin.__sizeof__())
|
||||
if SubStmtGenCif is None:
|
||||
stdio.printf("FAIL: StmtGenCifMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubStmtGenCif, 0, StmtGenCifMixin.StmtGenCifMixin.__sizeof__())
|
||||
SubStmtGenCif.Gen = self
|
||||
self.StmtGenCif = SubStmtGenCif
|
||||
SubStmtGenDecl: StmtGenDeclMixin.StmtGenDeclMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(StmtGenDeclMixin.StmtGenDeclMixin.__sizeof__())
|
||||
if SubStmtGenDecl is None:
|
||||
stdio.printf("FAIL: StmtGenDeclMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubStmtGenDecl, 0, StmtGenDeclMixin.StmtGenDeclMixin.__sizeof__())
|
||||
SubStmtGenDecl.Gen = self
|
||||
self.StmtGenDecl = SubStmtGenDecl
|
||||
SubStmtGen: StmtGenMixin.StmtGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(StmtGenMixin.StmtGenMixin.__sizeof__())
|
||||
if SubStmtGen is None:
|
||||
stdio.printf("FAIL: StmtGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubStmtGen, 0, StmtGenMixin.StmtGenMixin.__sizeof__())
|
||||
SubStmtGen.Gen = self
|
||||
self.StmtGen = SubStmtGen
|
||||
SubMatchGen: MatchGenMixin.MatchGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(MatchGenMixin.MatchGenMixin.__sizeof__())
|
||||
if SubMatchGen is None:
|
||||
stdio.printf("FAIL: MatchGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubMatchGen, 0, MatchGenMixin.MatchGenMixin.__sizeof__())
|
||||
SubMatchGen.Gen = self
|
||||
self.MatchGen = SubMatchGen
|
||||
SubAssignGen: AssignGenMixin.AssignGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(AssignGenMixin.AssignGenMixin.__sizeof__())
|
||||
if SubAssignGen is None:
|
||||
stdio.printf("FAIL: AssignGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubAssignGen, 0, AssignGenMixin.AssignGenMixin.__sizeof__())
|
||||
SubAssignGen.Gen = self
|
||||
self.AssignGen = SubAssignGen
|
||||
SubVarGen: VarGenMixin.VarGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(VarGenMixin.VarGenMixin.__sizeof__())
|
||||
if SubVarGen is None:
|
||||
stdio.printf("FAIL: VarGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubVarGen, 0, VarGenMixin.VarGenMixin.__sizeof__())
|
||||
SubVarGen.Gen = self
|
||||
self.VarGen = SubVarGen
|
||||
SubTranslatorGen: TranslatorGenMixin.TranslatorGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(TranslatorGenMixin.TranslatorGenMixin.__sizeof__())
|
||||
if SubTranslatorGen is None:
|
||||
stdio.printf("FAIL: TranslatorGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTranslatorGen, 0, TranslatorGenMixin.TranslatorGenMixin.__sizeof__())
|
||||
SubTranslatorGen.Gen = self
|
||||
self.TranslatorGen = SubTranslatorGen
|
||||
SubAsyncGen: AsyncGenMixin.AsyncGenMixin | t.CPtr = CompilerFactory.get_perm_pool().alloc(AsyncGenMixin.AsyncGenMixin.__sizeof__())
|
||||
if SubAsyncGen is None:
|
||||
stdio.printf("FAIL: AsyncGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubAsyncGen, 0, AsyncGenMixin.AsyncGenMixin.__sizeof__())
|
||||
SubAsyncGen.Gen = self
|
||||
self.AsyncGen = SubAsyncGen
|
||||
|
||||
# ---- 初始化各子对象字段(Init* 方法内联调用) ----
|
||||
SubBaseGen.InitBaseGen(pool)
|
||||
SubTypeGenBase.InitTypeGen()
|
||||
SubCallGenBase.InitCallGen()
|
||||
SubStructGen.InitStructGen()
|
||||
SubClassGenBase.InitClassGen()
|
||||
SubExprGenBase.InitExprGen()
|
||||
SubImportsGen.InitImportsGen()
|
||||
SubStmtGenCif.InitStmtGen()
|
||||
SubAssignGen.InitAssignGen()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局生成器单例(组合架构兼容层)
|
||||
# ============================================================
|
||||
_g_gen: Generator | t.CPtr = None
|
||||
import string
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
import memhub
|
||||
import llvmlite
|
||||
import lib.core.Gen.BaseGenMixin as BaseGenMixin
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.Type.TypeGenMixin as TypeGenMixin
|
||||
import lib.core.Gen.Type.TypeGenCDef as TypeGenCDef
|
||||
import lib.core.Gen.Type.TypeGenCType as TypeGenCType
|
||||
import lib.core.Gen.Type.TypeGenResolve as TypeGenResolve
|
||||
import lib.core.Gen.Type.TypeGenErr as TypeGenErr
|
||||
import lib.core.Gen.StructGenMixin as StructGenMixin
|
||||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||||
import lib.core.Gen.Expr.ExprGenMixin as ExprGenMixin
|
||||
import lib.core.Gen.Expr.ExprGenConst as ExprGenConst
|
||||
import lib.core.Gen.Expr.ExprGenFstr as ExprGenFstr
|
||||
import lib.core.Gen.Expr.ExprGenOps as ExprGenOps
|
||||
import lib.core.Gen.Expr.ExprGenCdef as ExprGenCdef
|
||||
import lib.core.Gen.Expr.ExprGenName as ExprGenName
|
||||
import lib.core.Gen.Expr.ExprGenAttr as ExprGenAttr
|
||||
import lib.core.Gen.Expr.ExprGenCls as ExprGenCls
|
||||
import lib.core.Gen.Call.CallGenBase as CallGenBase
|
||||
import lib.core.Gen.Call.CallGenCBuiltin as CallGenCBuiltin
|
||||
import lib.core.Gen.Call.CallGenLeafKit as CallGenLeafKit
|
||||
import lib.core.Gen.Call.CallGenCtor as CallGenCtor
|
||||
import lib.core.Gen.Call.CallGenCall as CallGenCall
|
||||
import lib.core.Gen.Call.CallGenMixin as CallGenMixin
|
||||
import lib.core.Gen.Call.CallGenDispatch as CallGenDispatch
|
||||
import lib.core.Gen.Call.CallGenLib as CallGenLib
|
||||
import lib.core.Gen.Call.CallGenVt as CallGenVt
|
||||
import lib.core.Gen.Call.CallGenVa as CallGenVa
|
||||
import lib.core.Gen.Call.CallGenProp as CallGenProp
|
||||
import lib.core.Gen.Call.CallGenFd as CallGenFd
|
||||
import lib.core.Gen.Func.FuncGenBase as FuncGenBase
|
||||
import lib.core.Gen.Func.FuncGenDef as FuncGenDef
|
||||
import lib.core.Gen.Func.FuncGenMixin as FuncGenMixin
|
||||
import lib.core.Gen.Class.ClassGenBase as ClassGenBase
|
||||
import lib.core.Gen.Class.ClassGenMixin as ClassGenMixin
|
||||
import lib.core.Gen.Class.ClassGenEnum as ClassGenEnum
|
||||
import lib.core.Gen.Class.ClassGenGeneric as ClassGenGeneric
|
||||
import lib.core.Gen.Class.ClassGenVTable as ClassGenVTable
|
||||
import lib.core.Gen.Class.ClassGenDef as ClassGenDef
|
||||
import lib.core.Gen.ImportsGenMixin as ImportsGenMixin
|
||||
import lib.core.Gen.Stmt.StmtGenCifMixin as StmtGenCifMixin
|
||||
import lib.core.Gen.Stmt.StmtGenDeclMixin as StmtGenDeclMixin
|
||||
import lib.core.Gen.Stmt.StmtGenMixin as StmtGenMixin
|
||||
import lib.core.Gen.MatchGenMixin as MatchGenMixin
|
||||
import lib.core.Gen.AssignGenMixin as AssignGenMixin
|
||||
import lib.core.Gen.AsyncGenMixin as AsyncGenMixin
|
||||
import lib.core.Gen.VarGenMixin as VarGenMixin
|
||||
import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Generator - 生成器(双向引用组合架构)
|
||||
# ============================================================
|
||||
novirtual class Generator:
|
||||
"""生成器:持所有 GenMixin 子对象指针(双向引用组合)"""
|
||||
|
||||
# ---- 子对象指针(46 个,永久池) ----
|
||||
BaseGen: rawptr[BaseGenMixin.BaseGenMixin]
|
||||
TypeGenBase: rawptr[TypeGenBase.TypeGenBase]
|
||||
TypeGen: rawptr[TypeGenMixin.TypeGenMixin]
|
||||
TypeGenCDef: rawptr[TypeGenCDef.TypeGenCDef]
|
||||
TypeGenCType: rawptr[TypeGenCType.TypeGenCType]
|
||||
TypeGenResolve: rawptr[TypeGenResolve.TypeGenResolve]
|
||||
TypeGenErr: rawptr[TypeGenErr.TypeGenErr]
|
||||
StructGen: rawptr[StructGenMixin.StructGenMixin]
|
||||
ExprGenBase: rawptr[ExprGenBase.ExprGenBase]
|
||||
ExprGen: rawptr[ExprGenMixin.ExprGenMixin]
|
||||
ExprGenConst: rawptr[ExprGenConst.ExprGenConst]
|
||||
ExprGenFstr: rawptr[ExprGenFstr.ExprGenFstr]
|
||||
ExprGenOps: rawptr[ExprGenOps.ExprGenOps]
|
||||
ExprGenCdef: rawptr[ExprGenCdef.ExprGenCdef]
|
||||
ExprGenName: rawptr[ExprGenName.ExprGenName]
|
||||
ExprGenAttr: rawptr[ExprGenAttr.ExprGenAttr]
|
||||
ExprGenCls: rawptr[ExprGenCls.ExprGenCls]
|
||||
CallGenBase: rawptr[CallGenBase.CallGenBase]
|
||||
CallGenCBuiltin: rawptr[CallGenCBuiltin.CallGenCBuiltin]
|
||||
CallGenLeafKit: rawptr[CallGenLeafKit.CallGenLeafKit]
|
||||
CallGenCtor: rawptr[CallGenCtor.CallGenCtor]
|
||||
CallGenCall: rawptr[CallGenCall.CallGenCall]
|
||||
CallGen: rawptr[CallGenMixin.CallGenMixin]
|
||||
CallGenDispatch: rawptr[CallGenDispatch.CallGenDispatch]
|
||||
CallGenLib: rawptr[CallGenLib.CallGenLib]
|
||||
CallGenVt: rawptr[CallGenVt.CallGenVt]
|
||||
CallGenVa: rawptr[CallGenVa.CallGenVa]
|
||||
CallGenProp: rawptr[CallGenProp.CallGenProp]
|
||||
CallGenFd: rawptr[CallGenFd.CallGenFd]
|
||||
FuncGenBase: rawptr[FuncGenBase.FuncGenBase]
|
||||
FuncGenDef: rawptr[FuncGenDef.FuncGenDef]
|
||||
FuncGen: rawptr[FuncGenMixin.FuncGenMixin]
|
||||
ClassGenBase: rawptr[ClassGenBase.ClassGenBase]
|
||||
ClassGen: rawptr[ClassGenMixin.ClassGenMixin]
|
||||
ClassGenEnum: rawptr[ClassGenEnum.ClassGenEnum]
|
||||
ClassGenGeneric: rawptr[ClassGenGeneric.ClassGenGeneric]
|
||||
ClassGenVTable: rawptr[ClassGenVTable.ClassGenVTable]
|
||||
ClassGenDef: rawptr[ClassGenDef.ClassGenDef]
|
||||
ImportsGen: rawptr[ImportsGenMixin.ImportsGenMixin]
|
||||
StmtGenCif: rawptr[StmtGenCifMixin.StmtGenCifMixin]
|
||||
StmtGenDecl: rawptr[StmtGenDeclMixin.StmtGenDeclMixin]
|
||||
StmtGen: rawptr[StmtGenMixin.StmtGenMixin]
|
||||
MatchGen: rawptr[MatchGenMixin.MatchGenMixin]
|
||||
AssignGen: rawptr[AssignGenMixin.AssignGenMixin]
|
||||
AsyncGen: rawptr[AsyncGenMixin.AsyncGenMixin]
|
||||
VarGen: rawptr[VarGenMixin.VarGenMixin]
|
||||
TranslatorGen: rawptr[TranslatorGenMixin.TranslatorGenMixin]
|
||||
|
||||
def __init__(self, pool: memhub.MemBuddy*):
|
||||
if self is None:
|
||||
return
|
||||
# ---- alloc 46 个子对象 + 回指(永久池,fail-fast) ----
|
||||
SubBaseGen: rawptr[BaseGenMixin.BaseGenMixin] = CompilerFactory.factory.PermPool.alloc(BaseGenMixin.BaseGenMixin.__sizeof__())
|
||||
if SubBaseGen is None:
|
||||
stdio.printf("FAIL: BaseGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubBaseGen, 0, BaseGenMixin.BaseGenMixin.__sizeof__())
|
||||
SubBaseGen.Gen = self
|
||||
self.BaseGen = SubBaseGen
|
||||
SubTypeGenBase: rawptr[TypeGenBase.TypeGenBase] = CompilerFactory.factory.PermPool.alloc(TypeGenBase.TypeGenBase.__sizeof__())
|
||||
if SubTypeGenBase is None:
|
||||
stdio.printf("FAIL: TypeGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenBase, 0, TypeGenBase.TypeGenBase.__sizeof__())
|
||||
SubTypeGenBase.Gen = self
|
||||
self.TypeGenBase = SubTypeGenBase
|
||||
SubTypeGen: rawptr[TypeGenMixin.TypeGenMixin] = CompilerFactory.factory.PermPool.alloc(TypeGenMixin.TypeGenMixin.__sizeof__())
|
||||
if SubTypeGen is None:
|
||||
stdio.printf("FAIL: TypeGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGen, 0, TypeGenMixin.TypeGenMixin.__sizeof__())
|
||||
SubTypeGen.Gen = self
|
||||
self.TypeGen = SubTypeGen
|
||||
SubTypeGenCDef: rawptr[TypeGenCDef.TypeGenCDef] = CompilerFactory.factory.PermPool.alloc(TypeGenCDef.TypeGenCDef.__sizeof__())
|
||||
if SubTypeGenCDef is None:
|
||||
stdio.printf("FAIL: TypeGenCDef alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenCDef, 0, TypeGenCDef.TypeGenCDef.__sizeof__())
|
||||
SubTypeGenCDef.Gen = self
|
||||
self.TypeGenCDef = SubTypeGenCDef
|
||||
SubTypeGenCType: rawptr[TypeGenCType.TypeGenCType] = CompilerFactory.factory.PermPool.alloc(TypeGenCType.TypeGenCType.__sizeof__())
|
||||
if SubTypeGenCType is None:
|
||||
stdio.printf("FAIL: TypeGenCType alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenCType, 0, TypeGenCType.TypeGenCType.__sizeof__())
|
||||
SubTypeGenCType.Gen = self
|
||||
self.TypeGenCType = SubTypeGenCType
|
||||
SubTypeGenResolve: rawptr[TypeGenResolve.TypeGenResolve] = CompilerFactory.factory.PermPool.alloc(TypeGenResolve.TypeGenResolve.__sizeof__())
|
||||
if SubTypeGenResolve is None:
|
||||
stdio.printf("FAIL: TypeGenResolve alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenResolve, 0, TypeGenResolve.TypeGenResolve.__sizeof__())
|
||||
SubTypeGenResolve.Gen = self
|
||||
self.TypeGenResolve = SubTypeGenResolve
|
||||
SubTypeGenErr: rawptr[TypeGenErr.TypeGenErr] = CompilerFactory.factory.PermPool.alloc(TypeGenErr.TypeGenErr.__sizeof__())
|
||||
if SubTypeGenErr is None:
|
||||
stdio.printf("FAIL: TypeGenErr alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTypeGenErr, 0, TypeGenErr.TypeGenErr.__sizeof__())
|
||||
SubTypeGenErr.Gen = self
|
||||
self.TypeGenErr = SubTypeGenErr
|
||||
SubStructGen: rawptr[StructGenMixin.StructGenMixin] = CompilerFactory.factory.PermPool.alloc(StructGenMixin.StructGenMixin.__sizeof__())
|
||||
if SubStructGen is None:
|
||||
stdio.printf("FAIL: StructGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubStructGen, 0, StructGenMixin.StructGenMixin.__sizeof__())
|
||||
SubStructGen.Gen = self
|
||||
self.StructGen = SubStructGen
|
||||
SubExprGenBase: rawptr[ExprGenBase.ExprGenBase] = CompilerFactory.factory.PermPool.alloc(ExprGenBase.ExprGenBase.__sizeof__())
|
||||
if SubExprGenBase is None:
|
||||
stdio.printf("FAIL: ExprGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenBase, 0, ExprGenBase.ExprGenBase.__sizeof__())
|
||||
SubExprGenBase.Gen = self
|
||||
self.ExprGenBase = SubExprGenBase
|
||||
SubExprGen: rawptr[ExprGenMixin.ExprGenMixin] = CompilerFactory.factory.PermPool.alloc(ExprGenMixin.ExprGenMixin.__sizeof__())
|
||||
if SubExprGen is None:
|
||||
stdio.printf("FAIL: ExprGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGen, 0, ExprGenMixin.ExprGenMixin.__sizeof__())
|
||||
SubExprGen.Gen = self
|
||||
self.ExprGen = SubExprGen
|
||||
SubExprGenConst: rawptr[ExprGenConst.ExprGenConst] = CompilerFactory.factory.PermPool.alloc(ExprGenConst.ExprGenConst.__sizeof__())
|
||||
if SubExprGenConst is None:
|
||||
stdio.printf("FAIL: ExprGenConst alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenConst, 0, ExprGenConst.ExprGenConst.__sizeof__())
|
||||
SubExprGenConst.Gen = self
|
||||
self.ExprGenConst = SubExprGenConst
|
||||
SubExprGenFstr: rawptr[ExprGenFstr.ExprGenFstr] = CompilerFactory.factory.PermPool.alloc(ExprGenFstr.ExprGenFstr.__sizeof__())
|
||||
if SubExprGenFstr is None:
|
||||
stdio.printf("FAIL: ExprGenFstr alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenFstr, 0, ExprGenFstr.ExprGenFstr.__sizeof__())
|
||||
SubExprGenFstr.Gen = self
|
||||
self.ExprGenFstr = SubExprGenFstr
|
||||
SubExprGenOps: rawptr[ExprGenOps.ExprGenOps] = CompilerFactory.factory.PermPool.alloc(ExprGenOps.ExprGenOps.__sizeof__())
|
||||
if SubExprGenOps is None:
|
||||
stdio.printf("FAIL: ExprGenOps alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenOps, 0, ExprGenOps.ExprGenOps.__sizeof__())
|
||||
SubExprGenOps.Gen = self
|
||||
self.ExprGenOps = SubExprGenOps
|
||||
SubExprGenCdef: rawptr[ExprGenCdef.ExprGenCdef] = CompilerFactory.factory.PermPool.alloc(ExprGenCdef.ExprGenCdef.__sizeof__())
|
||||
if SubExprGenCdef is None:
|
||||
stdio.printf("FAIL: ExprGenCdef alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenCdef, 0, ExprGenCdef.ExprGenCdef.__sizeof__())
|
||||
SubExprGenCdef.Gen = self
|
||||
self.ExprGenCdef = SubExprGenCdef
|
||||
SubExprGenName: rawptr[ExprGenName.ExprGenName] = CompilerFactory.factory.PermPool.alloc(ExprGenName.ExprGenName.__sizeof__())
|
||||
if SubExprGenName is None:
|
||||
stdio.printf("FAIL: ExprGenName alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenName, 0, ExprGenName.ExprGenName.__sizeof__())
|
||||
SubExprGenName.Gen = self
|
||||
self.ExprGenName = SubExprGenName
|
||||
SubExprGenAttr: rawptr[ExprGenAttr.ExprGenAttr] = CompilerFactory.factory.PermPool.alloc(ExprGenAttr.ExprGenAttr.__sizeof__())
|
||||
if SubExprGenAttr is None:
|
||||
stdio.printf("FAIL: ExprGenAttr alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenAttr, 0, ExprGenAttr.ExprGenAttr.__sizeof__())
|
||||
SubExprGenAttr.Gen = self
|
||||
self.ExprGenAttr = SubExprGenAttr
|
||||
SubExprGenCls: rawptr[ExprGenCls.ExprGenCls] = CompilerFactory.factory.PermPool.alloc(ExprGenCls.ExprGenCls.__sizeof__())
|
||||
if SubExprGenCls is None:
|
||||
stdio.printf("FAIL: ExprGenCls alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubExprGenCls, 0, ExprGenCls.ExprGenCls.__sizeof__())
|
||||
SubExprGenCls.Gen = self
|
||||
self.ExprGenCls = SubExprGenCls
|
||||
SubCallGenBase: rawptr[CallGenBase.CallGenBase] = CompilerFactory.factory.PermPool.alloc(CallGenBase.CallGenBase.__sizeof__())
|
||||
if SubCallGenBase is None:
|
||||
stdio.printf("FAIL: CallGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenBase, 0, CallGenBase.CallGenBase.__sizeof__())
|
||||
SubCallGenBase.Gen = self
|
||||
self.CallGenBase = SubCallGenBase
|
||||
SubCallGenCBuiltin: rawptr[CallGenCBuiltin.CallGenCBuiltin] = CompilerFactory.factory.PermPool.alloc(CallGenCBuiltin.CallGenCBuiltin.__sizeof__())
|
||||
if SubCallGenCBuiltin is None:
|
||||
stdio.printf("FAIL: CallGenCBuiltin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenCBuiltin, 0, CallGenCBuiltin.CallGenCBuiltin.__sizeof__())
|
||||
SubCallGenCBuiltin.Gen = self
|
||||
self.CallGenCBuiltin = SubCallGenCBuiltin
|
||||
SubCallGenLeafKit: rawptr[CallGenLeafKit.CallGenLeafKit] = CompilerFactory.factory.PermPool.alloc(CallGenLeafKit.CallGenLeafKit.__sizeof__())
|
||||
if SubCallGenLeafKit is None:
|
||||
stdio.printf("FAIL: CallGenLeafKit alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenLeafKit, 0, CallGenLeafKit.CallGenLeafKit.__sizeof__())
|
||||
SubCallGenLeafKit.Gen = self
|
||||
self.CallGenLeafKit = SubCallGenLeafKit
|
||||
SubCallGenCtor: rawptr[CallGenCtor.CallGenCtor] = CompilerFactory.factory.PermPool.alloc(CallGenCtor.CallGenCtor.__sizeof__())
|
||||
if SubCallGenCtor is None:
|
||||
stdio.printf("FAIL: CallGenCtor alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenCtor, 0, CallGenCtor.CallGenCtor.__sizeof__())
|
||||
SubCallGenCtor.Gen = self
|
||||
self.CallGenCtor = SubCallGenCtor
|
||||
SubCallGenCall: rawptr[CallGenCall.CallGenCall] = CompilerFactory.factory.PermPool.alloc(CallGenCall.CallGenCall.__sizeof__())
|
||||
if SubCallGenCall is None:
|
||||
stdio.printf("FAIL: CallGenCall alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenCall, 0, CallGenCall.CallGenCall.__sizeof__())
|
||||
SubCallGenCall.Gen = self
|
||||
self.CallGenCall = SubCallGenCall
|
||||
SubCallGen: rawptr[CallGenMixin.CallGenMixin] = CompilerFactory.factory.PermPool.alloc(CallGenMixin.CallGenMixin.__sizeof__())
|
||||
if SubCallGen is None:
|
||||
stdio.printf("FAIL: CallGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGen, 0, CallGenMixin.CallGenMixin.__sizeof__())
|
||||
SubCallGen.Gen = self
|
||||
self.CallGen = SubCallGen
|
||||
SubCallGenDispatch: rawptr[CallGenDispatch.CallGenDispatch] = CompilerFactory.factory.PermPool.alloc(CallGenDispatch.CallGenDispatch.__sizeof__())
|
||||
if SubCallGenDispatch is None:
|
||||
stdio.printf("FAIL: CallGenDispatch alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenDispatch, 0, CallGenDispatch.CallGenDispatch.__sizeof__())
|
||||
SubCallGenDispatch.Gen = self
|
||||
self.CallGenDispatch = SubCallGenDispatch
|
||||
SubCallGenLib: rawptr[CallGenLib.CallGenLib] = CompilerFactory.factory.PermPool.alloc(CallGenLib.CallGenLib.__sizeof__())
|
||||
if SubCallGenLib is None:
|
||||
stdio.printf("FAIL: CallGenLib alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenLib, 0, CallGenLib.CallGenLib.__sizeof__())
|
||||
SubCallGenLib.Gen = self
|
||||
self.CallGenLib = SubCallGenLib
|
||||
SubCallGenVt: rawptr[CallGenVt.CallGenVt] = CompilerFactory.factory.PermPool.alloc(CallGenVt.CallGenVt.__sizeof__())
|
||||
if SubCallGenVt is None:
|
||||
stdio.printf("FAIL: CallGenVt alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenVt, 0, CallGenVt.CallGenVt.__sizeof__())
|
||||
SubCallGenVt.Gen = self
|
||||
self.CallGenVt = SubCallGenVt
|
||||
SubCallGenVa: rawptr[CallGenVa.CallGenVa] = CompilerFactory.factory.PermPool.alloc(CallGenVa.CallGenVa.__sizeof__())
|
||||
if SubCallGenVa is None:
|
||||
stdio.printf("FAIL: CallGenVa alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenVa, 0, CallGenVa.CallGenVa.__sizeof__())
|
||||
SubCallGenVa.Gen = self
|
||||
self.CallGenVa = SubCallGenVa
|
||||
SubCallGenProp: rawptr[CallGenProp.CallGenProp] = CompilerFactory.factory.PermPool.alloc(CallGenProp.CallGenProp.__sizeof__())
|
||||
if SubCallGenProp is None:
|
||||
stdio.printf("FAIL: CallGenProp alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenProp, 0, CallGenProp.CallGenProp.__sizeof__())
|
||||
SubCallGenProp.Gen = self
|
||||
self.CallGenProp = SubCallGenProp
|
||||
SubCallGenFd: rawptr[CallGenFd.CallGenFd] = CompilerFactory.factory.PermPool.alloc(CallGenFd.CallGenFd.__sizeof__())
|
||||
if SubCallGenFd is None:
|
||||
stdio.printf("FAIL: CallGenFd alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubCallGenFd, 0, CallGenFd.CallGenFd.__sizeof__())
|
||||
SubCallGenFd.Gen = self
|
||||
self.CallGenFd = SubCallGenFd
|
||||
SubFuncGenBase: rawptr[FuncGenBase.FuncGenBase] = CompilerFactory.factory.PermPool.alloc(FuncGenBase.FuncGenBase.__sizeof__())
|
||||
if SubFuncGenBase is None:
|
||||
stdio.printf("FAIL: FuncGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubFuncGenBase, 0, FuncGenBase.FuncGenBase.__sizeof__())
|
||||
SubFuncGenBase.Gen = self
|
||||
self.FuncGenBase = SubFuncGenBase
|
||||
SubFuncGenDef: rawptr[FuncGenDef.FuncGenDef] = CompilerFactory.factory.PermPool.alloc(FuncGenDef.FuncGenDef.__sizeof__())
|
||||
if SubFuncGenDef is None:
|
||||
stdio.printf("FAIL: FuncGenDef alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubFuncGenDef, 0, FuncGenDef.FuncGenDef.__sizeof__())
|
||||
SubFuncGenDef.Gen = self
|
||||
self.FuncGenDef = SubFuncGenDef
|
||||
SubFuncGen: rawptr[FuncGenMixin.FuncGenMixin] = CompilerFactory.factory.PermPool.alloc(FuncGenMixin.FuncGenMixin.__sizeof__())
|
||||
if SubFuncGen is None:
|
||||
stdio.printf("FAIL: FuncGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubFuncGen, 0, FuncGenMixin.FuncGenMixin.__sizeof__())
|
||||
SubFuncGen.Gen = self
|
||||
self.FuncGen = SubFuncGen
|
||||
SubClassGenBase: rawptr[ClassGenBase.ClassGenBase] = CompilerFactory.factory.PermPool.alloc(ClassGenBase.ClassGenBase.__sizeof__())
|
||||
if SubClassGenBase is None:
|
||||
stdio.printf("FAIL: ClassGenBase alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenBase, 0, ClassGenBase.ClassGenBase.__sizeof__())
|
||||
SubClassGenBase.Gen = self
|
||||
self.ClassGenBase = SubClassGenBase
|
||||
SubClassGen: rawptr[ClassGenMixin.ClassGenMixin] = CompilerFactory.factory.PermPool.alloc(ClassGenMixin.ClassGenMixin.__sizeof__())
|
||||
if SubClassGen is None:
|
||||
stdio.printf("FAIL: ClassGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGen, 0, ClassGenMixin.ClassGenMixin.__sizeof__())
|
||||
SubClassGen.Gen = self
|
||||
self.ClassGen = SubClassGen
|
||||
SubClassGenEnum: rawptr[ClassGenEnum.ClassGenEnum] = CompilerFactory.factory.PermPool.alloc(ClassGenEnum.ClassGenEnum.__sizeof__())
|
||||
if SubClassGenEnum is None:
|
||||
stdio.printf("FAIL: ClassGenEnum alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenEnum, 0, ClassGenEnum.ClassGenEnum.__sizeof__())
|
||||
SubClassGenEnum.Gen = self
|
||||
self.ClassGenEnum = SubClassGenEnum
|
||||
SubClassGenGeneric: rawptr[ClassGenGeneric.ClassGenGeneric] = CompilerFactory.factory.PermPool.alloc(ClassGenGeneric.ClassGenGeneric.__sizeof__())
|
||||
if SubClassGenGeneric is None:
|
||||
stdio.printf("FAIL: ClassGenGeneric alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenGeneric, 0, ClassGenGeneric.ClassGenGeneric.__sizeof__())
|
||||
SubClassGenGeneric.Gen = self
|
||||
self.ClassGenGeneric = SubClassGenGeneric
|
||||
SubClassGenVTable: rawptr[ClassGenVTable.ClassGenVTable] = CompilerFactory.factory.PermPool.alloc(ClassGenVTable.ClassGenVTable.__sizeof__())
|
||||
if SubClassGenVTable is None:
|
||||
stdio.printf("FAIL: ClassGenVTable alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenVTable, 0, ClassGenVTable.ClassGenVTable.__sizeof__())
|
||||
SubClassGenVTable.Gen = self
|
||||
self.ClassGenVTable = SubClassGenVTable
|
||||
SubClassGenDef: rawptr[ClassGenDef.ClassGenDef] = CompilerFactory.factory.PermPool.alloc(ClassGenDef.ClassGenDef.__sizeof__())
|
||||
if SubClassGenDef is None:
|
||||
stdio.printf("FAIL: ClassGenDef alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubClassGenDef, 0, ClassGenDef.ClassGenDef.__sizeof__())
|
||||
SubClassGenDef.Gen = self
|
||||
self.ClassGenDef = SubClassGenDef
|
||||
SubImportsGen: rawptr[ImportsGenMixin.ImportsGenMixin] = CompilerFactory.factory.PermPool.alloc(ImportsGenMixin.ImportsGenMixin.__sizeof__())
|
||||
if SubImportsGen is None:
|
||||
stdio.printf("FAIL: ImportsGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubImportsGen, 0, ImportsGenMixin.ImportsGenMixin.__sizeof__())
|
||||
SubImportsGen.Gen = self
|
||||
self.ImportsGen = SubImportsGen
|
||||
SubStmtGenCif: rawptr[StmtGenCifMixin.StmtGenCifMixin] = CompilerFactory.factory.PermPool.alloc(StmtGenCifMixin.StmtGenCifMixin.__sizeof__())
|
||||
if SubStmtGenCif is None:
|
||||
stdio.printf("FAIL: StmtGenCifMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubStmtGenCif, 0, StmtGenCifMixin.StmtGenCifMixin.__sizeof__())
|
||||
SubStmtGenCif.Gen = self
|
||||
self.StmtGenCif = SubStmtGenCif
|
||||
SubStmtGenDecl: rawptr[StmtGenDeclMixin.StmtGenDeclMixin] = CompilerFactory.factory.PermPool.alloc(StmtGenDeclMixin.StmtGenDeclMixin.__sizeof__())
|
||||
if SubStmtGenDecl is None:
|
||||
stdio.printf("FAIL: StmtGenDeclMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubStmtGenDecl, 0, StmtGenDeclMixin.StmtGenDeclMixin.__sizeof__())
|
||||
SubStmtGenDecl.Gen = self
|
||||
self.StmtGenDecl = SubStmtGenDecl
|
||||
SubStmtGen: rawptr[StmtGenMixin.StmtGenMixin] = CompilerFactory.factory.PermPool.alloc(StmtGenMixin.StmtGenMixin.__sizeof__())
|
||||
if SubStmtGen is None:
|
||||
stdio.printf("FAIL: StmtGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubStmtGen, 0, StmtGenMixin.StmtGenMixin.__sizeof__())
|
||||
SubStmtGen.Gen = self
|
||||
self.StmtGen = SubStmtGen
|
||||
SubMatchGen: rawptr[MatchGenMixin.MatchGenMixin] = CompilerFactory.factory.PermPool.alloc(MatchGenMixin.MatchGenMixin.__sizeof__())
|
||||
if SubMatchGen is None:
|
||||
stdio.printf("FAIL: MatchGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubMatchGen, 0, MatchGenMixin.MatchGenMixin.__sizeof__())
|
||||
SubMatchGen.Gen = self
|
||||
self.MatchGen = SubMatchGen
|
||||
SubAssignGen: rawptr[AssignGenMixin.AssignGenMixin] = CompilerFactory.factory.PermPool.alloc(AssignGenMixin.AssignGenMixin.__sizeof__())
|
||||
if SubAssignGen is None:
|
||||
stdio.printf("FAIL: AssignGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubAssignGen, 0, AssignGenMixin.AssignGenMixin.__sizeof__())
|
||||
SubAssignGen.Gen = self
|
||||
self.AssignGen = SubAssignGen
|
||||
SubVarGen: rawptr[VarGenMixin.VarGenMixin] = CompilerFactory.factory.PermPool.alloc(VarGenMixin.VarGenMixin.__sizeof__())
|
||||
if SubVarGen is None:
|
||||
stdio.printf("FAIL: VarGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubVarGen, 0, VarGenMixin.VarGenMixin.__sizeof__())
|
||||
SubVarGen.Gen = self
|
||||
self.VarGen = SubVarGen
|
||||
SubTranslatorGen: rawptr[TranslatorGenMixin.TranslatorGenMixin] = CompilerFactory.factory.PermPool.alloc(TranslatorGenMixin.TranslatorGenMixin.__sizeof__())
|
||||
if SubTranslatorGen is None:
|
||||
stdio.printf("FAIL: TranslatorGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubTranslatorGen, 0, TranslatorGenMixin.TranslatorGenMixin.__sizeof__())
|
||||
SubTranslatorGen.Gen = self
|
||||
self.TranslatorGen = SubTranslatorGen
|
||||
SubAsyncGen: rawptr[AsyncGenMixin.AsyncGenMixin] = CompilerFactory.factory.PermPool.alloc(AsyncGenMixin.AsyncGenMixin.__sizeof__())
|
||||
if SubAsyncGen is None:
|
||||
stdio.printf("FAIL: AsyncGenMixin alloc failed\n")
|
||||
stdlib.exit(1)
|
||||
string.memset(SubAsyncGen, 0, AsyncGenMixin.AsyncGenMixin.__sizeof__())
|
||||
SubAsyncGen.Gen = self
|
||||
self.AsyncGen = SubAsyncGen
|
||||
|
||||
# ---- 初始化各子对象字段(Init* 方法内联调用) ----
|
||||
SubBaseGen.InitBaseGen(pool)
|
||||
SubTypeGenBase.InitTypeGen()
|
||||
SubCallGenBase.InitCallGen()
|
||||
SubStructGen.InitStructGen()
|
||||
SubClassGenBase.InitClassGen()
|
||||
SubExprGenBase.InitExprGen()
|
||||
SubImportsGen.InitImportsGen()
|
||||
SubStmtGenCif.InitStmtGen()
|
||||
SubAssignGen.InitAssignGen()
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局生成器单例(组合架构兼容层)
|
||||
# ============================================================
|
||||
_g_gen: Generator* = None
|
||||
+377
-201
@@ -3,6 +3,7 @@ import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import memhub
|
||||
import hashtable
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
@@ -11,25 +12,16 @@ import sys
|
||||
import w32.fileio as fileio
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ImportsGenMixin - 导入处理 Mixin(对象化 P6-D,wiki/14-oo-refactor.md)
|
||||
# ImportsGenMixin - 导入处理 Mixin
|
||||
#
|
||||
# 从 HandlesImports.vp 迁移:
|
||||
# 全局状态(_g_reexport_sha1s/_g_reexport_funcs/_g_reexport_srcs/
|
||||
# _g_reexport_count/_g_current_file)→ 本类字段
|
||||
# 模块级函数(add_imported_module/is_module_imported/...)→ 本类方法
|
||||
#
|
||||
# 迁移原则(与 P1-P5 Mixin 一致,行为零变化):
|
||||
# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段
|
||||
# 2. 本模块内部函数调用改为 self.方法;跨模块调用(StubMerger 等)保留模块前缀
|
||||
# 3. HandlesImports.vp 原函数保留为"委托":本地模块级单例 _g_gen
|
||||
# (BuildPipeline/main 注入)cast 成 Generator 类型后调本类方法
|
||||
#
|
||||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。
|
||||
# 职责:模块导入表(imported_modules/from_imports)维护、re-export 登记、
|
||||
# 相对导入解析与模块 SHA1 校验。@t.NoVTable:静态绑定(MRO 直接调用)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
@@ -42,50 +34,162 @@ MAX_REEXPORT: t.CDefine = 512
|
||||
# ============================================================
|
||||
# ImportsGenMixin - 导入处理
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ImportsGenMixin:
|
||||
novirtual class ImportsGenMixin:
|
||||
"""导入处理 Mixin(P6 方法化)"""
|
||||
|
||||
# --- 全局 re-export 映射表(原 _g_reexport_sha1s/_g_reexport_funcs/
|
||||
# _g_reexport_srcs/_g_reexport_count) ---
|
||||
Gen: Generator.Generator | t.CPtr
|
||||
Gen: Generator.Generator*
|
||||
ReexportSha1s: bytes
|
||||
ReexportFuncs: bytes
|
||||
ReexportSrcs: bytes
|
||||
ReexportCount: int
|
||||
|
||||
# --- 导入查找索引(把 O(串长) 的逐字符扫描降为 O(名字长) 哈希查找) ---
|
||||
# imported_modules/_from_imports 是空格拼接的扁平串("a b c" / "n:m[:orig]"),
|
||||
# 长度可达数千字符,而每个 Name 节点都会多次查询。索引与「当前串指针」绑定:
|
||||
# 调用方查询的总是 add_* 刚生成的当前串,故命中索引快路径;其余来源(stub 期
|
||||
# stdlib malloc 缓冲等)指针不匹配 → 回退逐字符扫描,语义完全不变。
|
||||
# 索引表用 PermPool 分配(跨文件/Phase 存活),由对应 add_* 增量维护;key/value
|
||||
# 均为指向该扁平串内部的指针,串在文件级 reset 前始终有效。
|
||||
CurImportedModulesPtr: str
|
||||
CurImportedModulesNames: hashtable.HashTable*
|
||||
CurFromImportsPtr: str
|
||||
CurFromImportsMods: hashtable.HashTable*
|
||||
CurFromImportsOrigs: hashtable.HashTable*
|
||||
|
||||
# 注意:不声明 CurrentFile 字段——TypeGenMixin 已声明(Generator 展平块
|
||||
# 只有一份,跨父类不去重规则下重复声明会导致字段错位)。本 Mixin 的
|
||||
# set_current_file 与 CurrentFile 读取统一经 HandlesType 委托(延迟 import
|
||||
# 规避 HandlesType↔HandlesImports 循环依赖)。
|
||||
|
||||
# _index_imported_module - 增量维护 imported_modules 查找索引
|
||||
# old_ptr 为追加前的串指针(None = 首个模块),new_ptr 为追加后的新串,
|
||||
# name_ptr 指向新串内的新模块名(key 直接引用串内部,无需复制)。
|
||||
# 仅当 old_ptr 恰为当前索引绑定的串时复用其索引;否则放弃索引绑定并回退
|
||||
# 逐字符扫描(语义不变)。
|
||||
def _index_imported_module(self, old_ptr: str, new_ptr: str,
|
||||
name_ptr: str) -> None:
|
||||
"""增量更新 imported_modules 索引(复用旧索引或新建,失败则解除绑定)"""
|
||||
if new_ptr is None or name_ptr is None:
|
||||
return
|
||||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
if perm is None:
|
||||
return
|
||||
idx: hashtable.HashTable* = None
|
||||
if old_ptr is None:
|
||||
# 新文件/新链首:建全新索引(旧索引随旧串一起废弃)
|
||||
idx = hashtable.HashTable(perm)
|
||||
elif old_ptr == self.CurImportedModulesPtr and self.CurImportedModulesNames is not None:
|
||||
# 正常路径:复用当前串的索引并追加(不重建,内存 O(导入数))
|
||||
idx = self.CurImportedModulesNames
|
||||
else:
|
||||
# 旧串非当前索引串(异常来源):解除绑定,回退逐字符扫描
|
||||
self.CurImportedModulesPtr = None
|
||||
self.CurImportedModulesNames = None
|
||||
return
|
||||
if idx is None:
|
||||
self.CurImportedModulesPtr = None
|
||||
self.CurImportedModulesNames = None
|
||||
return
|
||||
# 同名已在(重复导入)则跳过;否则写入(key/value 均指向 new_ptr 内部)
|
||||
if idx.__contains__(name_ptr) == 0:
|
||||
idx.set_str(name_ptr, name_ptr)
|
||||
self.CurImportedModulesPtr = new_ptr
|
||||
self.CurImportedModulesNames = idx
|
||||
|
||||
# _index_from_import - 增量维护 from_imports 查找索引
|
||||
# entry_off 为新增 entry("local:module[:orig]")在新串内相对首字节的偏移。
|
||||
# 模块表 key=local_name → 指向模块名切片;orig 表 key=local_name → 指向原始名
|
||||
# 切片(无别名时写入 None,以"名存在但无原始名"区别于未命中)。
|
||||
# 语义对齐逐字符扫描:精确名首次命中为准(不覆盖),star 模块名以最后一条为准。
|
||||
def _index_from_import(self, old_ptr: str, new_ptr: str, entry_off: sizet,
|
||||
local_name: str, module_name: str,
|
||||
original_name: str) -> None:
|
||||
"""增量更新 from_imports 索引(复用旧索引或新建,失败则解除绑定)"""
|
||||
if new_ptr is None or local_name is None or module_name is None:
|
||||
return
|
||||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
if perm is None:
|
||||
return
|
||||
idx_m: hashtable.HashTable* = None
|
||||
idx_o: hashtable.HashTable* = None
|
||||
if old_ptr is None:
|
||||
idx_m = hashtable.HashTable(perm)
|
||||
idx_o = hashtable.HashTable(perm)
|
||||
elif old_ptr == self.CurFromImportsPtr \
|
||||
and self.CurFromImportsMods is not None \
|
||||
and self.CurFromImportsOrigs is not None:
|
||||
idx_m = self.CurFromImportsMods
|
||||
idx_o = self.CurFromImportsOrigs
|
||||
else:
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
return
|
||||
if idx_m is None or idx_o is None:
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
return
|
||||
local_len: sizet = string.strlen(local_name)
|
||||
mod_len: sizet = string.strlen(module_name)
|
||||
# 哈希键必须是 NUL 结尾串:扁平串内 local 段以 ':' 结尾(非 NUL),直接当键会让
|
||||
# FNV 哈希到 "local:module..." 整段,与查询名 "local" 永不相等 → 索引恒 miss。
|
||||
# 故用 PermPool 分配 NUL 结尾的稳定副本作键(与索引表同寿命),值仍指向扁平串
|
||||
# 内模块名切片。
|
||||
key_ptr: str = perm.alloc(local_len + 1)
|
||||
if key_ptr is None:
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
return
|
||||
string.strncpy(key_ptr, local_name, local_len)
|
||||
key_ptr[local_len] = '\0'
|
||||
mod_ptr: str = new_ptr + entry_off + local_len + 1
|
||||
if local_len == 1 and local_name[0] == '*':
|
||||
# star import:模块名以最后一条为准(覆盖旧值,对齐 star_mod 语义)
|
||||
idx_m.set_str(key_ptr, mod_ptr)
|
||||
else:
|
||||
if idx_m.__contains__(key_ptr) == 0:
|
||||
idx_m.set_str(key_ptr, mod_ptr)
|
||||
if idx_o.__contains__(key_ptr) == 0:
|
||||
if original_name is not None and string.strcmp(original_name, local_name) != 0 \
|
||||
and string.strlen(original_name) > 0:
|
||||
idx_o.set_str(key_ptr, mod_ptr + mod_len + 1)
|
||||
else:
|
||||
# 首次出现即无别名(或别名为空)→ 该名查询返回 None(与逐字符扫描一致)
|
||||
idx_o.set_str(key_ptr, None)
|
||||
self.CurFromImportsPtr = new_ptr
|
||||
self.CurFromImportsMods = idx_m
|
||||
self.CurFromImportsOrigs = idx_o
|
||||
|
||||
# ============================================================
|
||||
# 添加已导入模块名
|
||||
# ============================================================
|
||||
def add_imported_module(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
def add_imported_module(self, pool: memhub.MemBuddy*,
|
||||
imported_modules: str,
|
||||
name: str) -> str:
|
||||
"""记录已导入的模块名,返回新的 imported_modules 字符串指针"""
|
||||
"""记录已导入的模块名,返回新的 imported_modules 字符串指针
|
||||
|
||||
字符串记账走 StubMergerStore.AppendImportedModule(单一真源,与 vpi
|
||||
注入期同源);本方法只额外维护查询索引。
|
||||
"""
|
||||
if name is None:
|
||||
return imported_modules
|
||||
if imported_modules is None:
|
||||
nlen: t.CSizeT = string.strlen(name)
|
||||
buf: str = pool.alloc(nlen + 1)
|
||||
if buf is not None:
|
||||
string.strcpy(buf, name)
|
||||
return buf
|
||||
return None
|
||||
else:
|
||||
old_len: t.CSizeT = string.strlen(imported_modules)
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
new_len: t.CSizeT = old_len + 1 + name_len
|
||||
buf2: str = pool.alloc(new_len + 1)
|
||||
if buf2 is not None:
|
||||
string.strcpy(buf2, imported_modules)
|
||||
buf2[old_len] = ' '
|
||||
string.strcpy(buf2 + old_len + 1, name)
|
||||
return buf2
|
||||
old_len: sizet = 0
|
||||
if imported_modules is not None:
|
||||
old_len = string.strlen(imported_modules)
|
||||
buf: str = StubMergerStore.AppendImportedModule(pool, imported_modules, name)
|
||||
if buf is None:
|
||||
return imported_modules
|
||||
if imported_modules is None:
|
||||
# 索引:首个模块名(key 指向 buf 内部)
|
||||
self._index_imported_module(None, buf, buf)
|
||||
else:
|
||||
# 索引:复用旧串索引并追加新名字(key 指向 buf 内的 name 段)
|
||||
self._index_imported_module(imported_modules, buf, buf + old_len + 1)
|
||||
return buf
|
||||
|
||||
# ============================================================
|
||||
# 检查模块是否已导入
|
||||
@@ -94,19 +198,27 @@ class ImportsGenMixin:
|
||||
"""检查模块是否已导入(词边界精确匹配,避免子串误匹配)"""
|
||||
if name is None or imported_modules is None:
|
||||
return 0
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
# [索引快路径] 传入串即当前索引绑定的串(trans 字段的常态)→ O(名字长) 哈希查;
|
||||
# 指针不匹配(stub 期 malloc 缓冲等)→ 回退下方逐字符扫描,语义不变。
|
||||
if imported_modules == self.CurImportedModulesPtr \
|
||||
and self.CurImportedModulesNames is not None:
|
||||
if self.CurImportedModulesNames.__contains__(name) != 0:
|
||||
return 1
|
||||
# 索引未命中:绝不据此返回 0(索引不完整会误判"未导入"),
|
||||
# 落到下方原逐字符扫描按真实串内容判定(正确性优先 | 性能次之)。
|
||||
name_len: sizet = string.strlen(name)
|
||||
cur: str = imported_modules
|
||||
total_len: t.CSizeT = string.strlen(imported_modules)
|
||||
ci: t.CSizeT = 0
|
||||
total_len: sizet = string.strlen(imported_modules)
|
||||
ci: sizet = 0
|
||||
while ci < total_len:
|
||||
while ci < total_len and cur[ci] == ' ':
|
||||
ci += 1
|
||||
if ci >= total_len:
|
||||
break
|
||||
word_start: t.CSizeT = ci
|
||||
word_start: sizet = ci
|
||||
while ci < total_len and cur[ci] != ' ':
|
||||
ci += 1
|
||||
word_len: t.CSizeT = ci - word_start
|
||||
word_len: sizet = ci - word_start
|
||||
if word_len == name_len:
|
||||
match: int = 1
|
||||
for ei in range(name_len):
|
||||
@@ -141,8 +253,8 @@ class ImportsGenMixin:
|
||||
return 0
|
||||
if StubMergerStore.LookupSha1ByModName(name) is None:
|
||||
return 0
|
||||
nl: t.CSizeT = string.strlen(name)
|
||||
dot_pos: t.CSizeT = 0
|
||||
nl: sizet = string.strlen(name)
|
||||
dot_pos: sizet = 0
|
||||
while dot_pos < nl:
|
||||
if name[dot_pos] == '.':
|
||||
pfx: str = stdlib.malloc(dot_pos + 1)
|
||||
@@ -159,7 +271,7 @@ class ImportsGenMixin:
|
||||
# ============================================================
|
||||
# 添加 from-import 名称映射
|
||||
# ============================================================
|
||||
def add_from_import(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
def add_from_import(self, pool: memhub.MemBuddy*,
|
||||
from_imports: str,
|
||||
local_name: str,
|
||||
module_name: str,
|
||||
@@ -170,29 +282,26 @@ class ImportsGenMixin:
|
||||
无别名: "local_name:module_name"
|
||||
有别名: "local_name:module_name:original_name"
|
||||
(original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰)
|
||||
|
||||
字符串记账走 StubMergerStore.AppendFromImport(单一真源,与 vpi 注入期
|
||||
同源;按精确长度分配,无旧的 256 缓冲静默截断);本方法只额外维护索引。
|
||||
"""
|
||||
if local_name is None or module_name is None:
|
||||
return from_imports
|
||||
entry: str = pool.alloc(256)
|
||||
if entry is None:
|
||||
return from_imports
|
||||
if original_name is not None and string.strcmp(original_name, local_name) != 0:
|
||||
viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name)
|
||||
else:
|
||||
viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name)
|
||||
if from_imports is None:
|
||||
return entry
|
||||
else:
|
||||
old_len: t.CSizeT = string.strlen(from_imports)
|
||||
entry_len: t.CSizeT = string.strlen(entry)
|
||||
new_len: t.CSizeT = old_len + 1 + entry_len
|
||||
buf: str = pool.alloc(new_len + 1)
|
||||
if buf is not None:
|
||||
string.strcpy(buf, from_imports)
|
||||
buf[old_len] = ' '
|
||||
string.strcpy(buf + old_len + 1, entry)
|
||||
return buf
|
||||
old_len: sizet = 0
|
||||
if from_imports is not None:
|
||||
old_len = string.strlen(from_imports)
|
||||
buf: str = StubMergerStore.AppendFromImport(
|
||||
pool, from_imports, local_name, module_name, original_name)
|
||||
if buf is None:
|
||||
return from_imports
|
||||
# 索引:首条 entry_off=0;追加时 entry 从 buf[old_len+1] 开始
|
||||
entry_off: sizet = 0
|
||||
if from_imports is not None:
|
||||
entry_off = old_len + 1
|
||||
self._index_from_import(from_imports, buf, entry_off,
|
||||
local_name, module_name, original_name)
|
||||
return buf
|
||||
|
||||
# ============================================================
|
||||
# 查找 from-import 名称 → 返回原始函数名(别名场景)
|
||||
@@ -205,10 +314,19 @@ class ImportsGenMixin:
|
||||
"""查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到"""
|
||||
if local_name is None or from_imports is None:
|
||||
return None
|
||||
name_len: t.CSizeT = string.strlen(local_name)
|
||||
# [索引快路径] 传入串即当前索引绑定的串 → O(名字长) 哈希查;否则回退扫描。
|
||||
# orig 表:名存在但存 None = 首次出现即无别名 → 返回 None(与扫描一致)。
|
||||
if from_imports == self.CurFromImportsPtr and self.CurFromImportsOrigs is not None:
|
||||
if self.CurFromImportsOrigs.__contains__(local_name) != 0:
|
||||
v_o: t.CPtr = self.CurFromImportsOrigs.__getitem__(local_name)
|
||||
if v_o is not None:
|
||||
return rawptr(v_o)
|
||||
# 索引未命中 | 值为 None(首个即无别名):绝不据此直接返回 None——
|
||||
# 真实串可能仍含该名,落到下方原逐字符扫描按串内容判定(正确性优先)。
|
||||
name_len: sizet = string.strlen(local_name)
|
||||
cur: str = from_imports
|
||||
ci: t.CSizeT = 0
|
||||
total_len: t.CSizeT = string.strlen(from_imports)
|
||||
ci: sizet = 0
|
||||
total_len: sizet = string.strlen(from_imports)
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
while ci < total_len and cur[ci] == ' ':
|
||||
@@ -216,12 +334,12 @@ class ImportsGenMixin:
|
||||
if ci >= total_len:
|
||||
break
|
||||
# 找到第一个 ':' 的位置
|
||||
colon1: t.CSizeT = ci
|
||||
colon1: sizet = ci
|
||||
while colon1 < total_len and cur[colon1] != ':' and cur[colon1] != ' ':
|
||||
colon1 += 1
|
||||
if colon1 >= total_len or cur[colon1] != ':':
|
||||
break
|
||||
entry_name_len: t.CSizeT = colon1 - ci
|
||||
entry_name_len: sizet = colon1 - ci
|
||||
# 跳过 star import
|
||||
if entry_name_len == 1 and cur[ci] == '*':
|
||||
ci = colon1
|
||||
@@ -231,7 +349,7 @@ class ImportsGenMixin:
|
||||
# 比较名称
|
||||
if entry_name_len == name_len:
|
||||
match: int = 1
|
||||
ei: t.CSizeT = 0
|
||||
ei: sizet = 0
|
||||
while ei < name_len:
|
||||
if cur[ci + ei] != local_name[ei]:
|
||||
match = 0
|
||||
@@ -239,17 +357,17 @@ class ImportsGenMixin:
|
||||
ei += 1
|
||||
if match == 1:
|
||||
# 找到匹配,检查是否有第三个字段(原始名)
|
||||
pos: t.CSizeT = colon1 + 1
|
||||
pos: sizet = colon1 + 1
|
||||
# 跳过模块名
|
||||
while pos < total_len and cur[pos] != ':' and cur[pos] != ' ' and cur[pos] != '\0':
|
||||
pos += 1
|
||||
if pos < total_len and cur[pos] == ':':
|
||||
# 有第三个字段: original_name
|
||||
orig_start: t.CSizeT = pos + 1
|
||||
orig_end: t.CSizeT = orig_start
|
||||
orig_start: sizet = pos + 1
|
||||
orig_end: sizet = orig_start
|
||||
while orig_end < total_len and cur[orig_end] != ' ' and cur[orig_end] != '\0':
|
||||
orig_end += 1
|
||||
orig_len: t.CSizeT = orig_end - orig_start
|
||||
orig_len: sizet = orig_end - orig_start
|
||||
if orig_len > 0:
|
||||
orig_buf: str = cur + orig_start
|
||||
# 返回指向内部的指针(调用方需在使用期内保持 from_imports 有效)
|
||||
@@ -279,10 +397,26 @@ class ImportsGenMixin:
|
||||
"""
|
||||
if name is None or from_imports is None:
|
||||
return None
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
# [索引快路径] 传入串即当前索引绑定的串 → O(名字长) 哈希查;否则回退扫描。
|
||||
# name 恰为 "*" 时与扫描一致:不做精确匹配,直接走 star 回退。
|
||||
if from_imports == self.CurFromImportsPtr and self.CurFromImportsMods is not None:
|
||||
name_is_star: int = 0
|
||||
if string.strlen(name) == 1 and name[0] == '*':
|
||||
name_is_star = 1
|
||||
if name_is_star == 0:
|
||||
v_f: t.CPtr = self.CurFromImportsMods.__getitem__(name)
|
||||
if v_f is not None:
|
||||
return rawptr(v_f)
|
||||
if allow_star_fallback != 0:
|
||||
sv_f: t.CPtr = self.CurFromImportsMods.__getitem__("*")
|
||||
if sv_f is not None:
|
||||
return rawptr(sv_f)
|
||||
# 索引精确名 | star 均未命中:绝不据此直接返回 None(索引不完整会漏报
|
||||
# "名已 import",_op_head NameError 即此类),落到下方原逐字符扫描按串内容判定。
|
||||
name_len: sizet = string.strlen(name)
|
||||
cur: str = from_imports
|
||||
ci: t.CSizeT = 0
|
||||
total_len: t.CSizeT = string.strlen(from_imports)
|
||||
ci: sizet = 0
|
||||
total_len: sizet = string.strlen(from_imports)
|
||||
star_mod: str = None
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
@@ -291,31 +425,31 @@ class ImportsGenMixin:
|
||||
if ci >= total_len:
|
||||
break
|
||||
# 找到 ':' 的位置
|
||||
colon_pos: t.CSizeT = ci
|
||||
colon_pos: sizet = ci
|
||||
while colon_pos < total_len and cur[colon_pos] != ':' and cur[colon_pos] != ' ':
|
||||
colon_pos += 1
|
||||
if colon_pos >= total_len or cur[colon_pos] != ':':
|
||||
break
|
||||
entry_name_len: t.CSizeT = colon_pos - ci
|
||||
entry_name_len: sizet = colon_pos - ci
|
||||
# 检测 star import ("*:module")
|
||||
if entry_name_len == 1 and cur[ci] == '*':
|
||||
mod_start: t.CSizeT = colon_pos + 1
|
||||
mod_end: t.CSizeT = mod_start
|
||||
mod_start: sizet = colon_pos + 1
|
||||
mod_end: sizet = mod_start
|
||||
while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0' and cur[mod_end] != ':':
|
||||
mod_end += 1
|
||||
star_mod = cur + mod_start
|
||||
# 比较名称
|
||||
elif entry_name_len == name_len:
|
||||
match: int = 1
|
||||
ei: t.CSizeT = 0
|
||||
ei: sizet = 0
|
||||
while ei < name_len:
|
||||
if cur[ci + ei] != name[ei]:
|
||||
match = 0
|
||||
break
|
||||
ei += 1
|
||||
if match == 1:
|
||||
mod_start2: t.CSizeT = colon_pos + 1
|
||||
mod_end2: t.CSizeT = mod_start2
|
||||
mod_start2: sizet = colon_pos + 1
|
||||
mod_end2: sizet = mod_start2
|
||||
# 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符)
|
||||
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':':
|
||||
mod_end2 += 1
|
||||
@@ -344,9 +478,9 @@ class ImportsGenMixin:
|
||||
return -1
|
||||
# 懒初始化
|
||||
if self.ReexportSha1s is None:
|
||||
self.ReexportSha1s = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 17)
|
||||
self.ReexportFuncs = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 64)
|
||||
self.ReexportSrcs = CompilerFactory.get_perm_pool().alloc(MAX_REEXPORT * 64)
|
||||
self.ReexportSha1s = CompilerFactory.factory.PermPool.alloc(MAX_REEXPORT * 17)
|
||||
self.ReexportFuncs = CompilerFactory.factory.PermPool.alloc(MAX_REEXPORT * 64)
|
||||
self.ReexportSrcs = CompilerFactory.factory.PermPool.alloc(MAX_REEXPORT * 64)
|
||||
if self.ReexportSha1s is None or self.ReexportFuncs is None or self.ReexportSrcs is None:
|
||||
return -1
|
||||
string.memset(self.ReexportSha1s, 0, MAX_REEXPORT * 17)
|
||||
@@ -356,8 +490,8 @@ class ImportsGenMixin:
|
||||
return -1
|
||||
# 幂等检查:查找是否已存在相同映射
|
||||
for i in range(self.ReexportCount):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
fidx: t.CSizeT = t.CSizeT(i) * 64
|
||||
sidx: sizet = sizet(i) * 17
|
||||
fidx: sizet = sizet(i) * 64
|
||||
if string.strcmp(self.ReexportSha1s + sidx, mod_sha1) == 0:
|
||||
if string.strcmp(self.ReexportFuncs + fidx, func_name) == 0:
|
||||
# 已存在,更新 source_module(以防变化;64 字节槽,strncpy 钳制)
|
||||
@@ -365,8 +499,8 @@ class ImportsGenMixin:
|
||||
self.ReexportSrcs[fidx + 63] = '\0'
|
||||
return 0
|
||||
# 添加新条目(槽位定长 17/64 字节,strcpy 无界会越界写相邻槽,全部 strncpy 钳制)
|
||||
idx2: t.CSizeT = t.CSizeT(self.ReexportCount) * 17
|
||||
fidx2: t.CSizeT = t.CSizeT(self.ReexportCount) * 64
|
||||
idx2: sizet = sizet(self.ReexportCount) * 17
|
||||
fidx2: sizet = sizet(self.ReexportCount) * 64
|
||||
string.strncpy(self.ReexportSha1s + idx2, mod_sha1, 16)
|
||||
self.ReexportSha1s[idx2 + 16] = '\0'
|
||||
string.strncpy(self.ReexportFuncs + fidx2, func_name, 63)
|
||||
@@ -389,8 +523,8 @@ class ImportsGenMixin:
|
||||
if self.ReexportSha1s is None or self.ReexportCount <= 0:
|
||||
return None
|
||||
for i in range(self.ReexportCount):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
fidx: t.CSizeT = t.CSizeT(i) * 64
|
||||
sidx: sizet = sizet(i) * 17
|
||||
fidx: sizet = sizet(i) * 64
|
||||
if string.strcmp(self.ReexportSha1s + sidx, mod_sha1) == 0:
|
||||
if string.strcmp(self.ReexportFuncs + fidx, func_name) == 0:
|
||||
return self.ReexportSrcs + fidx
|
||||
@@ -416,9 +550,9 @@ class ImportsGenMixin:
|
||||
# 解析后的完整模块名;绝对导入(level<=0)直接返回 module;
|
||||
# 无法解析时返回 module(回退到原始值)
|
||||
# ============================================================
|
||||
def _resolve_relative_module(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
def _resolve_relative_module(self, pool: memhub.MemBuddy*,
|
||||
current_package: str,
|
||||
level: t.CInt,
|
||||
level: int,
|
||||
module: str) -> str:
|
||||
"""解析相对导入为完整模块名"""
|
||||
if level <= 0:
|
||||
@@ -432,12 +566,12 @@ class ImportsGenMixin:
|
||||
|
||||
# 从 current_package 开始,上溯 (level-1) 级
|
||||
pkg: str = current_package
|
||||
up: t.CInt = level - 1
|
||||
up: int = level - 1
|
||||
while up > 0:
|
||||
pkg_len: t.CSizeT = string.strlen(pkg)
|
||||
last_dot: t.CSizeT = 0
|
||||
pkg_len: sizet = string.strlen(pkg)
|
||||
last_dot: sizet = 0
|
||||
found: int = 0
|
||||
i: t.CSizeT = 0
|
||||
i: sizet = 0
|
||||
while i < pkg_len:
|
||||
if pkg[i] == '.':
|
||||
last_dot = i
|
||||
@@ -466,8 +600,8 @@ class ImportsGenMixin:
|
||||
# 包已上溯到空(相对导入越界):回退到 module 原始值
|
||||
return module
|
||||
# 拼接 pkg + "." + module
|
||||
pkg_len2: t.CSizeT = string.strlen(pkg)
|
||||
mod_len: t.CSizeT = string.strlen(module)
|
||||
pkg_len2: sizet = string.strlen(pkg)
|
||||
mod_len: sizet = string.strlen(module)
|
||||
buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1)
|
||||
if buf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"相对导入解析失败:level={level} module='{module}'", "ImportError")
|
||||
@@ -489,18 +623,18 @@ class ImportsGenMixin:
|
||||
# "ast/parser.vp" → "ast"
|
||||
# "ast.vp" → None(顶级文件)
|
||||
# ============================================================
|
||||
def compute_package_from_relpath(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
def compute_package_from_relpath(self, pool: memhub.MemBuddy*,
|
||||
rel_path: str) -> str:
|
||||
"""从相对路径计算包名(目录部分,分隔符替换为 .)"""
|
||||
if rel_path is None:
|
||||
return None
|
||||
rlen: t.CSizeT = string.strlen(rel_path)
|
||||
rlen: sizet = string.strlen(rel_path)
|
||||
# 找最后一个 / 或 \
|
||||
last_sep: t.CSizeT = 0
|
||||
last_sep: sizet = 0
|
||||
found: int = 0
|
||||
i: t.CSizeT = 0
|
||||
i: sizet = 0
|
||||
while i < rlen:
|
||||
ch: t.CChar = rel_path[i]
|
||||
ch: char = rel_path[i]
|
||||
if ch == '/' or ch == '\\':
|
||||
last_sep = i
|
||||
found = 1
|
||||
@@ -509,13 +643,13 @@ class ImportsGenMixin:
|
||||
# 无目录分隔符 → 顶级文件,无包
|
||||
return None
|
||||
# 复制目录部分,将 / 和 \ 替换为 .
|
||||
dir_len: t.CSizeT = last_sep
|
||||
dir_len: sizet = last_sep
|
||||
buf: str = pool.alloc(dir_len + 1)
|
||||
if buf is None:
|
||||
return None
|
||||
j: t.CSizeT = 0
|
||||
j: sizet = 0
|
||||
while j < dir_len:
|
||||
ch2: t.CChar = rel_path[j]
|
||||
ch2: char = rel_path[j]
|
||||
if ch2 == '/' or ch2 == '\\':
|
||||
buf[j] = '.'
|
||||
else:
|
||||
@@ -533,6 +667,14 @@ class ImportsGenMixin:
|
||||
# ============================================================
|
||||
def set_current_file(self, file_path: str) -> None:
|
||||
"""设置当前正在编译的文件名(与 HandlesType.set_current_file 同步调用)"""
|
||||
# 文件级失效:索引绑定的是上一文件 arena 内的串指针,本文件 reset 后该
|
||||
# 地址可能被新分配复用(如 _merge_template_imports 的合并串)→ 必须解绑,
|
||||
# 否则可能命中陈旧索引返回错误结果。本文件的索引由后续 add_* 重新建立。
|
||||
self.CurImportedModulesPtr = None
|
||||
self.CurImportedModulesNames = None
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
self.Gen.TypeGenResolve.set_current_file(file_path)
|
||||
|
||||
# ============================================================
|
||||
@@ -544,7 +686,7 @@ class ImportsGenMixin:
|
||||
# File "<当前文件>", line <N>
|
||||
# ImportError: <msg>
|
||||
# ============================================================
|
||||
def _report_import_error(self, node: ast.AST | t.CPtr, msg: str) -> None:
|
||||
def _report_import_error(self, node: ast.AST*, msg: str) -> None:
|
||||
"""以 Python 风格报错并退出(本地实现,避免循环依赖)"""
|
||||
stdio.printf("Traceback (most recent call last):\n")
|
||||
lineno: int = 0
|
||||
@@ -556,7 +698,7 @@ class ImportsGenMixin:
|
||||
stdio.printf(' File "%s", line %d\n', file_name, lineno)
|
||||
# 显示行内内容(读源文件第 lineno 行的实际代码,便于快速定位)
|
||||
if lineno > 0 and file_name is not None:
|
||||
f_err: fileio.File | t.CPtr = fileio.File(file_name, fileio.MODE.R)
|
||||
f_err: rawptr[fileio.File] = fileio.File(file_name, fileio.MODE.R)
|
||||
if not f_err.closed:
|
||||
line_buf_err: bytes = stdlib.malloc(512)
|
||||
if line_buf_err is not None:
|
||||
@@ -567,7 +709,7 @@ class ImportsGenMixin:
|
||||
break
|
||||
cur_ln += 1
|
||||
if cur_ln == lineno:
|
||||
ll_err: t.CSizeT = string.strlen(line_buf_err)
|
||||
ll_err: sizet = string.strlen(line_buf_err)
|
||||
while ll_err > 0 and (line_buf_err[ll_err - 1] == '\n' or line_buf_err[ll_err - 1] == '\r'):
|
||||
ll_err -= 1
|
||||
line_buf_err[ll_err] = '\0'
|
||||
@@ -576,7 +718,8 @@ class ImportsGenMixin:
|
||||
stdlib.free(line_buf_err)
|
||||
f_err.close()
|
||||
stdio.printf("ImportError: %s\n", msg)
|
||||
sys.exit(1)
|
||||
# 终止点收敛:REPL 会话内 longjmp 回 REPL 循环(诊断已打印),批处理下终止
|
||||
VLogger.repl_abort()
|
||||
|
||||
# ============================================================
|
||||
# _is_local_module_file - 当前文件同目录存在 {mod_name}.vp/.py
|
||||
@@ -589,18 +732,18 @@ class ImportsGenMixin:
|
||||
cur: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if cur is None or mod_name is None:
|
||||
return 0
|
||||
cur_len: t.CSizeT = string.strlen(cur)
|
||||
cur_len: sizet = string.strlen(cur)
|
||||
if cur_len == 0:
|
||||
return 0
|
||||
sep_pos: t.CSizeT = cur_len
|
||||
sep_pos: sizet = cur_len
|
||||
while sep_pos > 0:
|
||||
sep_pos -= 1
|
||||
ch: t.CChar = cur[sep_pos]
|
||||
ch: char = cur[sep_pos]
|
||||
if ch == '/' or ch == '\\':
|
||||
sep_pos += 1
|
||||
break
|
||||
mod_len: t.CSizeT = string.strlen(mod_name)
|
||||
path_len: t.CSizeT = sep_pos + mod_len + 5
|
||||
mod_len: sizet = string.strlen(mod_name)
|
||||
path_len: sizet = sep_pos + mod_len + 5
|
||||
path_buf: bytes = stdlib.malloc(path_len + 1)
|
||||
if path_buf is None:
|
||||
return 0
|
||||
@@ -609,7 +752,7 @@ class ImportsGenMixin:
|
||||
path_buf[sep_pos] = '\0'
|
||||
string.strcat(path_buf, mod_name)
|
||||
string.strcat(path_buf, ".vp")
|
||||
fex: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||||
fex: rawptr[fileio.File] = fileio.File(path_buf, fileio.MODE.R)
|
||||
if not fex.closed:
|
||||
fex.close()
|
||||
stdlib.free(path_buf)
|
||||
@@ -617,18 +760,11 @@ class ImportsGenMixin:
|
||||
stdlib.free(path_buf)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _check_import_sha1 - 导入时校验模块 SHA1 是否已注册(fast-fail)
|
||||
#
|
||||
# 背景:若 includes 路径配置错误(如 project.json 指向不存在的
|
||||
# ./includes),includes 扫描结果为 0,模块不会注册 SHA1。此前
|
||||
# 错误延迟到实际调用 module.func() 时才报误导性的
|
||||
# "跨模块调用 'bd.alloc' 找不到模块 SHA1"。
|
||||
# 现在在 import 语句处立即检测并报错,快速定位配置问题。
|
||||
#
|
||||
# includes 路径配置错误时扫描结果为 0、模块不注册 SHA1,若延迟到实际跨模块调用才报错
|
||||
# 会误导("跨模块调用 'bd.alloc' 找不到模块 SHA1"),故在 import 语句处立即检测。
|
||||
# t/c 是内部库,不参与 includes 扫描,豁免检查。
|
||||
# ============================================================
|
||||
def _check_import_sha1(self, node: ast.AST | t.CPtr, mod_name: str) -> int:
|
||||
def _check_import_sha1(self, node: ast.AST*, mod_name: str) -> int:
|
||||
"""导入时校验模块 SHA1 是否已注册,未注册则立即报错退出
|
||||
|
||||
Args:
|
||||
@@ -665,50 +801,43 @@ class ImportsGenMixin:
|
||||
# translate_import - 处理 import 语句,更新 trans._imported_modules
|
||||
# (迁移自 HandlesImports.ImportsHandle.HandleImport)
|
||||
# ============================================================
|
||||
def translate_import(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""处理 import 语句,返回 0"""
|
||||
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node)
|
||||
def translate_import(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""处理 import 语句,返回 0
|
||||
|
||||
记账走 StubMergerStore.NotePlainImport(**该约定的唯一实现**):与 vpi
|
||||
注入期(VpiReader 顶层遍历)同口径,包含
|
||||
· `import X as Y` → from_imports 追加 "Y:X"(别名反查模块真名的唯一
|
||||
入口,见 StubMergerStore.LookupModNameByAlias);
|
||||
· `import a.b.c` → imported_modules 追加顶层包名 "a"。
|
||||
两侧各自只保留特有副作用(此处:导入 SHA1 校验)。
|
||||
注:NotePlainImport 为纯记账,不再续接 imported/from 两个查询索引 ⇒ 这两
|
||||
个串上的查找走 is_module_imported / lookup_from_import 的逐字符扫描回退
|
||||
(与 vpi 注入期上下文同款,正确性不受影响)。
|
||||
"""
|
||||
imp: ast.Import* = ast.Import*(node)
|
||||
if imp is None:
|
||||
return 0
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
|
||||
names: list[ast.AST*]* = imp.names
|
||||
if names is None:
|
||||
return 0
|
||||
nn: t.CSizeT = len(names)
|
||||
nn: sizet = len(names)
|
||||
pool_val: memhub.MemBuddy* = trans.Pool
|
||||
ctx: StubMergerStore.ImportCtx* = StubMergerStore.AllocImportCtx(
|
||||
pool_val, trans._imported_modules, trans._from_imports)
|
||||
if ctx is None:
|
||||
return 0
|
||||
for ni in range(nn):
|
||||
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
|
||||
alias: ast.Alias* = ast.Alias*(names.get(ni))
|
||||
if alias is not None and alias.name is not None:
|
||||
# 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查)
|
||||
# declare_only=1/2 是 struct 预注册/import 扫描阶段:此时 SHA1 表
|
||||
# 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报
|
||||
# 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报。
|
||||
if trans._declare_only == 0:
|
||||
self._check_import_sha1(node, alias.name)
|
||||
pool_val: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
im_val: str = trans._imported_modules
|
||||
trans._imported_modules = self.add_imported_module(
|
||||
pool_val, im_val, alias.name)
|
||||
# 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class())
|
||||
if alias.asname is not None:
|
||||
trans._imported_modules = self.add_imported_module(
|
||||
pool_val, trans._imported_modules, alias.asname)
|
||||
# 别名也加入 from_imports(asname:fullname),
|
||||
# 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1
|
||||
# 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator)
|
||||
trans._from_imports = self.add_from_import(
|
||||
pool_val, trans._from_imports, alias.asname, alias.name)
|
||||
else:
|
||||
# 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules,
|
||||
# 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查
|
||||
dot_ptr: str = string.strstr(alias.name, ".")
|
||||
if dot_ptr is not None:
|
||||
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name))
|
||||
if pkg_len > 0 and pkg_len < 256:
|
||||
pkg_buf: bytes = pool_val.alloc(pkg_len + 1)
|
||||
if pkg_buf is not None:
|
||||
string.strncpy(pkg_buf, alias.name, pkg_len)
|
||||
pkg_buf[pkg_len] = '\0'
|
||||
trans._imported_modules = self.add_imported_module(
|
||||
pool_val, trans._imported_modules, pkg_buf)
|
||||
StubMergerStore.NotePlainImport(pool_val, ctx, alias.name, alias.asname)
|
||||
trans._imported_modules = ctx.ImportedModules
|
||||
trans._from_imports = ctx.FromImports
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
@@ -719,45 +848,53 @@ class ImportsGenMixin:
|
||||
# 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt
|
||||
# 记录的模块名与 SHA1 映射表一致。
|
||||
# ============================================================
|
||||
def translate_import_from_module(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_import_from_module(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""处理 from X import Y 的模块部分,更新 trans._imported_modules"""
|
||||
impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
|
||||
impf: ast.ImportFrom* = ast.ImportFrom*(node)
|
||||
if impf is None:
|
||||
return 0
|
||||
# 解析模块名:相对导入需补充包前缀
|
||||
resolved: str = self._resolve_relative_module(
|
||||
trans.Pool, trans.CurrentPackage,
|
||||
resolved: str = self._resolve_relative_module(trans.Pool, trans.CurrentPackage,
|
||||
impf.level, impf.module)
|
||||
if resolved is not None:
|
||||
# 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查)
|
||||
if trans._declare_only == 0:
|
||||
# from . import Y(impf.module is None):resolved 是包目录名
|
||||
# (lib.core.Gen.Call 等无 __init__.vp 的目录包也允许这样导入,
|
||||
# 见 CallGenCall.vp L12 from . import CallGenBase),目录本身不是
|
||||
# 模块文件、无 SHA1 → 跳过包级校验;真实目标子模块(pkg.Y)由
|
||||
# 下方 L759-762 逐个校验(LookupSha1ByModName / 本地兄弟文件)。
|
||||
if trans._declare_only == 0 and impf.module is not None:
|
||||
self._check_import_sha1(node, resolved)
|
||||
trans._imported_modules = self.add_imported_module(
|
||||
trans.Pool, trans._imported_modules, resolved)
|
||||
trans._imported_modules = self.add_imported_module(trans.Pool, trans._imported_modules, resolved)
|
||||
# from . import Y(impf.module is None):resolved 是包名(vpsdk),
|
||||
# 各 name 是包的子模块 vpsdk.Y。须把完整子模块名也加入
|
||||
# _imported_modules,否则别名 "syscall" 精确匹配不到包名 "vpsdk"
|
||||
# → is_module_imported 返回 0 → syscall._syscall1 / syscall.LOAD_SO
|
||||
# 跨模块解析失败(vpsdk/dynlib.vp 根因)。
|
||||
# 各 name 是包的子模块 vpsdk.Y。须把完整子模块名也加入 _imported_modules,
|
||||
# 否则别名 "syscall" 精确匹配不到包名 "vpsdk" → is_module_imported 返回 0
|
||||
# → syscall._syscall1 / syscall.LOAD_SO 跨模块解析失败。
|
||||
if impf.module is None:
|
||||
names_m: list[ast.AST | t.CPtr] | t.CPtr = impf.names
|
||||
names_m: list[ast.AST*]* = impf.names
|
||||
if names_m is not None:
|
||||
nn_m: t.CSizeT = len(names_m)
|
||||
nn_m: sizet = len(names_m)
|
||||
for ni_m in range(nn_m):
|
||||
alias_m: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names_m.get(ni_m))
|
||||
alias_m: ast.Alias* = ast.Alias*(names_m.get(ni_m))
|
||||
if alias_m is not None and alias_m.name is not None:
|
||||
rl_m: t.CSizeT = string.strlen(resolved)
|
||||
rn_m: t.CSizeT = string.strlen(alias_m.name)
|
||||
rl_m: sizet = string.strlen(resolved)
|
||||
rn_m: sizet = string.strlen(alias_m.name)
|
||||
jb_m: str = trans.Pool.alloc(rl_m + rn_m + 2)
|
||||
if jb_m is not None:
|
||||
string.strcpy(jb_m, resolved)
|
||||
jb_m[rl_m] = '.'
|
||||
string.strcpy(jb_m + rl_m + 1, alias_m.name)
|
||||
if trans._declare_only == 0:
|
||||
self._check_import_sha1(node, jb_m)
|
||||
trans._imported_modules = self.add_imported_module(
|
||||
trans.Pool, trans._imported_modules, jb_m)
|
||||
# from . import Y 的 Y 不一定是包子模块文件:可能是包
|
||||
# __init__.vp 中定义的符号(类/常量,如 JsonValue),无独立
|
||||
# 文件、不注册 SHA1。仅当完整名已注册 SHA1(真子模块)或是
|
||||
# 本地文件时才校验+登记;否则跳过,符号映射由
|
||||
# translate_import_from_names 的 from-import / re-export 处理。
|
||||
if (StubMergerStore.LookupSha1ByModName(jb_m) is not None
|
||||
or self._is_local_module_file(alias_m.name) != 0):
|
||||
if trans._declare_only == 0:
|
||||
self._check_import_sha1(node, jb_m)
|
||||
trans._imported_modules = self.add_imported_module(trans.Pool, trans._imported_modules, jb_m)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
@@ -767,22 +904,53 @@ class ImportsGenMixin:
|
||||
# 同样使用解析后的完整模块名,确保 from-import 映射
|
||||
# (如 LLVMType:llvmlite.__types)能正确查到 SHA1。
|
||||
# ============================================================
|
||||
def translate_import_from_names(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
# _CheckStaticFromImport - static 符号 from-import 拦截
|
||||
#
|
||||
# `from mod import name` 命中源模块登记的 static 符号 → fail-fast(与
|
||||
# ExprGenAttr 的 `mod.name` 取值拦截、CallGenMixin 的 `mod.fn()` 调用拦截同源,
|
||||
# 覆盖 from-import 形态)。用源码原名判表——定义侧登记用的也是裸名。
|
||||
# 独立成函数:内联进 translate_import_from_names 会干扰其类型推断(同款处理
|
||||
# 见 ExprGenAttr._CheckStaticCrossModule 与 CallGenMixin._CheckStaticCallCrossModule)。
|
||||
# ============================================================
|
||||
def _CheckStaticFromImport(self, trans: HT.Translator*,
|
||||
fi_target: str,
|
||||
orig_name: str,
|
||||
node: ast.AST*) -> int:
|
||||
if trans is None or fi_target is None or orig_name is None:
|
||||
return 0
|
||||
if trans.ModuleSha1 is None:
|
||||
return 0
|
||||
# 快速短路:项目内无 static 符号时零开销(不查 sha1、不扫表)
|
||||
if self.Gen.CallGenBase.StaticCount <= 0:
|
||||
return 0
|
||||
sf_sha1: str = self.Gen.StructGen._resolve_module_sha1(fi_target, trans._from_imports)
|
||||
if sf_sha1 is None:
|
||||
return 0
|
||||
if string.strncmp(sf_sha1, trans.ModuleSha1, 16) == 0:
|
||||
return 0
|
||||
if self.Gen.CallGenBase.IsStaticSymbol(sf_sha1, orig_name) == 0:
|
||||
return 0
|
||||
self.Gen.TypeGenErr.fatal_error(node,
|
||||
f"'{fi_target}.{orig_name}' 是 static 符号,禁止跨模块使用(static 仅限定义模块内可见)",
|
||||
"NameError")
|
||||
return 0
|
||||
|
||||
|
||||
def translate_import_from_names(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""处理 from X import Y 的名称部分,更新 trans._from_imports"""
|
||||
impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
|
||||
impf: ast.ImportFrom* = ast.ImportFrom*(node)
|
||||
if impf is None:
|
||||
return 0
|
||||
# 解析模块名:相对导入需补充包前缀
|
||||
resolved: str = self._resolve_relative_module(
|
||||
trans.Pool, trans.CurrentPackage,
|
||||
resolved: str = self._resolve_relative_module(trans.Pool, trans.CurrentPackage,
|
||||
impf.level, impf.module)
|
||||
if resolved is not None:
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = impf.names
|
||||
names: list[ast.AST*]* = impf.names
|
||||
if names is not None:
|
||||
nn: t.CSizeT = len(names)
|
||||
nn: sizet = len(names)
|
||||
for ni in range(nn):
|
||||
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
|
||||
alias: ast.Alias* = ast.Alias*(names.get(ni))
|
||||
if alias is not None and alias.name is not None:
|
||||
local_name: str = alias.name
|
||||
orig_name: str = None
|
||||
@@ -790,25 +958,27 @@ class ImportsGenMixin:
|
||||
local_name = alias.asname
|
||||
orig_name = alias.name
|
||||
# from . import Y(impf.module is None):_resolve_relative_module
|
||||
# 返回的是包名(如 vpsdk),但 Y 是包的子模块 vpsdk.Y
|
||||
# (vpsdk/syscall.vp)。此前直接映射 local_name → 包名,
|
||||
# 导致 syscall.LOAD_SO 跨模块 CDefine / syscall._syscall1
|
||||
# 跨模块调用在包里找不到(vpsdk/dynlib.vp `from . import
|
||||
# syscall as syscall` 根因)。
|
||||
# 返回的是包名(如 vpsdk),但 Y 是包的子模块 vpsdk.Y。须映射
|
||||
# local_name → 完整子模块名,否则 syscall.LOAD_SO 跨模块 CDefine /
|
||||
# syscall._syscall1 跨模块调用在包里找不到。
|
||||
fi_target: str = resolved
|
||||
if impf.module is None and resolved is not None:
|
||||
fl_t: t.CSizeT = string.strlen(resolved)
|
||||
fn_t: t.CSizeT = string.strlen(alias.name)
|
||||
fl_t: sizet = string.strlen(resolved)
|
||||
fn_t: sizet = string.strlen(alias.name)
|
||||
jb_t: str = trans.Pool.alloc(fl_t + fn_t + 2)
|
||||
if jb_t is not None:
|
||||
string.strcpy(jb_t, resolved)
|
||||
jb_t[fl_t] = '.'
|
||||
string.strcpy(jb_t + fl_t + 1, alias.name)
|
||||
fi_target = jb_t
|
||||
trans._from_imports = self.add_from_import(
|
||||
trans.Pool, trans._from_imports,
|
||||
trans._from_imports = self.add_from_import(trans.Pool, trans._from_imports,
|
||||
local_name, fi_target, orig_name)
|
||||
# 命名空间隔离:from-import 的名称标记为可见结构体
|
||||
# static 符号(禁止跨模块使用):from mod import name 命中源
|
||||
# 模块登记的 static 符号 → fail-fast。逻辑收敛在
|
||||
# _CheckStaticFromImport 内(不内联——内联新增分支会干扰本函数
|
||||
# 的类型推断,与 ExprGenAttr/CallGenMixin 同款处理)。
|
||||
self._CheckStaticFromImport(trans, fi_target, alias.name, node)
|
||||
# 命名空间隔离:from-import 的名称标记为可见结构体
|
||||
self.Gen.StructGen.add_visible_struct(trans.Pool, local_name)
|
||||
# 注册 re-export 映射:当前模块 re-export 了 local_name,
|
||||
# 源模块为 fi_target(from . import Y 时是子模块名 vpsdk.Y,
|
||||
@@ -825,4 +995,10 @@ class ImportsGenMixin:
|
||||
self.ReexportFuncs = None
|
||||
self.ReexportSrcs = None
|
||||
self.ReexportCount = 0
|
||||
# 导入查找索引字段(索引表由 add_* 增量创建,PermPool 分配)
|
||||
self.CurImportedModulesPtr = None
|
||||
self.CurImportedModulesNames = None
|
||||
self.CurFromImportsPtr = None
|
||||
self.CurFromImportsMods = None
|
||||
self.CurFromImportsOrigs = None
|
||||
return 0
|
||||
+1331
-1355
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+181
-175
@@ -9,78 +9,69 @@ import stdlib
|
||||
import stdio
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.core.Gen.StmtGenCifMixin as StmtGenCifMixin
|
||||
import lib.core.Gen.Stmt.StmtGenCifMixin as StmtGenCifMixin
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StmtGenDeclMixin - StmtGen 拆分 2/3:声明/枚举/nonlocal 访问
|
||||
#
|
||||
# 按功能域从 StmtGenMixin.vp 拆出(500~1500 行/文件架构重构,试点):
|
||||
# translate_global/nonlocal/expr_stmt/pre_scan、break/continue、
|
||||
# nonlocal 闭包 env 访问、枚举注册表。继承 StmtGenCifMixin。
|
||||
#
|
||||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 常量(与 HandlesEnum 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||||
# 常量
|
||||
# ============================================================
|
||||
ENUM_MAX: t.CDefine = 64
|
||||
ENUM_MEMBER_MAX: t.CDefine = 128
|
||||
define ENUM_MAX = 64
|
||||
define ENUM_MEMBER_MAX = 128
|
||||
|
||||
# ============================================================
|
||||
# StmtGenDeclMixin - 声明/枚举/nonlocal(中层级)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
novirtual class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
"""声明/枚举/nonlocal 访问(StmtGen 拆分 2/3,继承 Cif)"""
|
||||
|
||||
def translate_global(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_global(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译 global 语句:记录 global 变量名"""
|
||||
gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node)
|
||||
gn: rawptr[ast.Global] = rawptr[ast.Global](node)
|
||||
if gn is None:
|
||||
return 0
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = gn.names
|
||||
names: list[ast.AST*]* = gn.names
|
||||
if names is None:
|
||||
return 0
|
||||
n: t.CSizeT = len(names)
|
||||
n: sizet = len(names)
|
||||
for i in range(n):
|
||||
nm_node: ast.AST | t.CPtr = names.get(i)
|
||||
nm_node: ast.AST* = names.get(i)
|
||||
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
|
||||
nm: ast.Name* = ast.Name*(nm_node)
|
||||
if nm.id is not None:
|
||||
HT.add_global_name(trans, nm.id)
|
||||
GenApi.add_global_name(trans, nm.id)
|
||||
return 0
|
||||
|
||||
def translate_nonlocal(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_nonlocal(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译 nonlocal 语句:记录 nonlocal 变量名及其类型
|
||||
|
||||
类型信息通过查找父作用域的 alloca 获取(用于 env 指针数组方案的类型恢复)。
|
||||
"""
|
||||
nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node)
|
||||
nl: rawptr[ast.Nonlocal] = rawptr[ast.Nonlocal](node)
|
||||
if nl is None:
|
||||
return 0
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = nl.names
|
||||
names: list[ast.AST*]* = nl.names
|
||||
if names is None:
|
||||
return 0
|
||||
n: t.CSizeT = len(names)
|
||||
n: sizet = len(names)
|
||||
for i in range(n):
|
||||
nm_node: ast.AST | t.CPtr = names.get(i)
|
||||
nm_node: ast.AST* = names.get(i)
|
||||
if nm_node is not None and nm_node.kind() == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(nm_node)
|
||||
nm: ast.Name* = ast.Name*(nm_node)
|
||||
if nm.id is not None:
|
||||
# 查找父作用域中的变量 alloca,获取类型信息
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
var_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||||
trans.SymTab, nm.id)
|
||||
var_ty: llvmlite.LLVMType* = None
|
||||
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||||
if var_alloca is not None and var_alloca.Ty is not None:
|
||||
var_ty = var_alloca.Ty.Pointee
|
||||
# Void 类型视为无效(Pointee 访问异常时可能返回 Void),
|
||||
@@ -92,24 +83,32 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
self.Gen.TypeGenErr.fatal_error(nm_node, f"nonlocal 变量 '{nm.id}' 类型无效(Void/无法解析)", "TypeError")
|
||||
case _:
|
||||
pass
|
||||
HT.add_nonlocal_name(trans, nm.id, var_ty)
|
||||
GenApi.add_nonlocal_name(trans, nm.id, var_ty)
|
||||
return 0
|
||||
|
||||
def translate_expr_stmt(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_expr_stmt(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译表达式语句(printf 调用等)"""
|
||||
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
|
||||
ex: rawptr[ast.Expr] = rawptr[ast.Expr](node)
|
||||
if ex is None:
|
||||
return 0
|
||||
call_node: ast.AST | t.CPtr = ex.value
|
||||
call_node: ast.AST* = ex.value
|
||||
if call_node is None:
|
||||
return 0
|
||||
ck: int = call_node.kind()
|
||||
if ck != ast.ASTKind.Call:
|
||||
# REPL 模式(M2):片段函数本体内的裸表达式语句(如 1+2 / x / x + 1)
|
||||
# 求值后写入 ctx 结果区,由宿主回显。调用表达式仍走下方原路径
|
||||
# (执行 + 丢弃返回值,同 print/printf 语义)。
|
||||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ "表达式语句除调用外一律忽略"
|
||||
# 的原行为逐字不变。
|
||||
if trans is not None and trans.ReplCtx is not None \
|
||||
and self.Gen.VarGen.repl_in_frag_scope(trans.SymTab) != 0:
|
||||
self.Gen.VarGen.repl_expr_result(trans, call_node)
|
||||
return 0
|
||||
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node)
|
||||
func_node: ast.AST | t.CPtr = cl.func
|
||||
cl: ast.Call* = ast.Call*(call_node)
|
||||
func_node: ast.AST* = cl.func
|
||||
if func_node is None:
|
||||
return 0
|
||||
|
||||
@@ -120,20 +119,37 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
|
||||
# printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf)
|
||||
if string.strcmp(func_name, "printf") == 0:
|
||||
self.Gen.CallGenLeafKit.translate_printf_call(
|
||||
trans.Pool, trans._cur_builder, trans.Module, cl, trans)
|
||||
self.Gen.CallGenLeafKit.translate_printf_call(trans.Pool, trans._cur_builder, trans.Module, cl, trans)
|
||||
elif string.strcmp(func_name, "print") == 0:
|
||||
self.Gen.CallGenLeafKit.translate_print_call(
|
||||
trans.Pool, trans._cur_builder, trans.Module, cl, trans)
|
||||
self.Gen.CallGenLeafKit.translate_print_call(trans.Pool, trans._cur_builder, trans.Module, cl, trans)
|
||||
else:
|
||||
# 通用函数调用(返回值丢弃)
|
||||
self.Gen.CallGen.translate_call(
|
||||
trans.Pool, trans._cur_builder, trans.Module, call_node,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
# M3:裸名调用**会话函数**(跨片段)时额外把返回值写进 ctx 结果区回显
|
||||
# (M2 的限制条目"调用表达式的结果不回显"对会话函数放开——用户在
|
||||
# `>>> f(41)` 后期望看到 `=> 42`)。结果区的类型分类直接用会话函数表里
|
||||
# 记录的返回类型 token(宿主从定义片段 IR 解析而来,是定义端 ABI 真相),
|
||||
# 不用影子条目推断 ⇒ 与调用点签名同源。
|
||||
# 守卫 trans.ReplCtx:非 REPL 恒 None ⇒ 原"执行 + 丢弃返回值"逐字不变;
|
||||
# 仅裸名(Name)且表中登记的会话函数走本分支(printf/print 等在上方已分流)。
|
||||
if trans is not None and trans.ReplCtx is not None \
|
||||
and func_node.kind() == ast.ASTKind.Name \
|
||||
and self.Gen.VarGen.repl_in_frag_scope(trans.SymTab) != 0:
|
||||
sfn_ent: rawptr[GenTypes.ReplFuncEntry] = \
|
||||
self.Gen.VarGen.repl_find_func_entry(trans.ReplCtx, func_name)
|
||||
if sfn_ent is not None and sfn_ent.RetTag != GenTypes.REPL_TY_VOID:
|
||||
sfn_v: llvmlite.Value* = self.Gen.CallGen.translate_call(trans.Pool, trans._cur_builder, trans.Module, call_node,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if sfn_v is not None:
|
||||
ctx_v: llvmlite.Value* = self.Gen.VarGen.repl_ctx_ptr(trans, trans.ReplCtx, call_node)
|
||||
if ctx_v is not None:
|
||||
self.Gen.VarGen.repl_emit_result(trans, ctx_v, sfn_v, sfn_ent.RetTag, sfn_ent.RetBits,
|
||||
call_node)
|
||||
return 0
|
||||
self.Gen.CallGen.translate_call(trans.Pool, trans._cur_builder, trans.Module, call_node, trans._funcs, trans._func_count, trans)
|
||||
return 0
|
||||
|
||||
def pre_scan_allocas(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def pre_scan_allocas(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""预扫描语句中的 AnnAssign,提前创建 alloca
|
||||
|
||||
递归分支/循环/异常体:if/else/for/while/try 分支内的 AnnAssign 局部
|
||||
@@ -150,87 +166,87 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
return self.Gen.AssignGen.translate_annassign_prescan(trans, node)
|
||||
if k == ast.ASTKind.If:
|
||||
ifn: ast.If | t.CPtr = (ast.If | t.CPtr)(node)
|
||||
ifn: rawptr[ast.If] = rawptr[ast.If](node)
|
||||
if ifn.children is not None:
|
||||
bn_pre_i: t.CSizeT = len(ifn.children)
|
||||
bn_pre_i: sizet = len(ifn.children)
|
||||
for bi_pre_i in range(bn_pre_i):
|
||||
self.pre_scan_allocas(trans, ifn.children.get(bi_pre_i))
|
||||
if ifn.orelse is not None:
|
||||
bn_pre_e: t.CSizeT = len(ifn.orelse)
|
||||
bn_pre_e: sizet = len(ifn.orelse)
|
||||
for bi_pre_e in range(bn_pre_e):
|
||||
self.pre_scan_allocas(trans, ifn.orelse.get(bi_pre_e))
|
||||
return 0
|
||||
if k == ast.ASTKind.For:
|
||||
for_n: ast.For | t.CPtr = (ast.For | t.CPtr)(node)
|
||||
for_n: ast.For* = ast.For*(node)
|
||||
if for_n.children is not None:
|
||||
bn_pre_f: t.CSizeT = len(for_n.children)
|
||||
bn_pre_f: sizet = len(for_n.children)
|
||||
for bi_pre_f in range(bn_pre_f):
|
||||
self.pre_scan_allocas(trans, for_n.children.get(bi_pre_f))
|
||||
if for_n.orelse is not None:
|
||||
bn_pre_fe: t.CSizeT = len(for_n.orelse)
|
||||
bn_pre_fe: sizet = len(for_n.orelse)
|
||||
for bi_pre_fe in range(bn_pre_fe):
|
||||
self.pre_scan_allocas(trans, for_n.orelse.get(bi_pre_fe))
|
||||
return 0
|
||||
if k == ast.ASTKind.While:
|
||||
wh_n: ast.While | t.CPtr = (ast.While | t.CPtr)(node)
|
||||
wh_n: rawptr[ast.While] = rawptr[ast.While](node)
|
||||
if wh_n.children is not None:
|
||||
bn_pre_w: t.CSizeT = len(wh_n.children)
|
||||
bn_pre_w: sizet = len(wh_n.children)
|
||||
for bi_pre_w in range(bn_pre_w):
|
||||
self.pre_scan_allocas(trans, wh_n.children.get(bi_pre_w))
|
||||
if wh_n.orelse is not None:
|
||||
bn_pre_we: t.CSizeT = len(wh_n.orelse)
|
||||
bn_pre_we: sizet = len(wh_n.orelse)
|
||||
for bi_pre_we in range(bn_pre_we):
|
||||
self.pre_scan_allocas(trans, wh_n.orelse.get(bi_pre_we))
|
||||
return 0
|
||||
if k == ast.ASTKind.Try:
|
||||
tr_n: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node)
|
||||
tr_n: ast.Try* = ast.Try*(node)
|
||||
if tr_n.children is not None:
|
||||
bn_pre_t: t.CSizeT = len(tr_n.children)
|
||||
bn_pre_t: sizet = len(tr_n.children)
|
||||
for bi_pre_t in range(bn_pre_t):
|
||||
self.pre_scan_allocas(trans, tr_n.children.get(bi_pre_t))
|
||||
if tr_n.handlers is not None:
|
||||
bn_pre_th: t.CSizeT = len(tr_n.handlers)
|
||||
bn_pre_th: sizet = len(tr_n.handlers)
|
||||
for bi_pre_th in range(bn_pre_th):
|
||||
eh_pre: ast.AST | t.CPtr = tr_n.handlers.get(bi_pre_th)
|
||||
eh_pre: ast.AST* = tr_n.handlers.get(bi_pre_th)
|
||||
if eh_pre is not None and eh_pre.kind() == ast.ASTKind.ExceptHandler:
|
||||
ehc_pre: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(eh_pre)
|
||||
ehc_pre: ast.ExceptHandler* = ast.ExceptHandler*(eh_pre)
|
||||
if ehc_pre.children is not None:
|
||||
bn_pre_ehb: t.CSizeT = len(ehc_pre.children)
|
||||
bn_pre_ehb: sizet = len(ehc_pre.children)
|
||||
for bi_pre_ehb in range(bn_pre_ehb):
|
||||
self.pre_scan_allocas(trans, ehc_pre.children.get(bi_pre_ehb))
|
||||
if tr_n.orelse is not None:
|
||||
bn_pre_to: t.CSizeT = len(tr_n.orelse)
|
||||
bn_pre_to: sizet = len(tr_n.orelse)
|
||||
for bi_pre_to in range(bn_pre_to):
|
||||
self.pre_scan_allocas(trans, tr_n.orelse.get(bi_pre_to))
|
||||
if tr_n.finalbody is not None:
|
||||
bn_pre_tf: t.CSizeT = len(tr_n.finalbody)
|
||||
bn_pre_tf: sizet = len(tr_n.finalbody)
|
||||
for bi_pre_tf in range(bn_pre_tf):
|
||||
self.pre_scan_allocas(trans, tr_n.finalbody.get(bi_pre_tf))
|
||||
return 0
|
||||
if k == ast.ASTKind.With:
|
||||
wth: ast.With | t.CPtr = (ast.With | t.CPtr)(node)
|
||||
wth: ast.With* = ast.With*(node)
|
||||
if wth.children is not None:
|
||||
bn_pre_wb: t.CSizeT = len(wth.children)
|
||||
bn_pre_wb: sizet = len(wth.children)
|
||||
for bi_pre_wb in range(bn_pre_wb):
|
||||
self.pre_scan_allocas(trans, wth.children.get(bi_pre_wb))
|
||||
return 0
|
||||
if k == ast.ASTKind.Match:
|
||||
mt_n: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node)
|
||||
mt_n: ast.Match* = ast.Match*(node)
|
||||
if mt_n.cases is not None:
|
||||
bn_pre_mc: t.CSizeT = len(mt_n.cases)
|
||||
bn_pre_mc: sizet = len(mt_n.cases)
|
||||
for bi_pre_mc in range(bn_pre_mc):
|
||||
mc_pre: ast.AST | t.CPtr = mt_n.cases.get(bi_pre_mc)
|
||||
mc_pre: ast.AST* = mt_n.cases.get(bi_pre_mc)
|
||||
if mc_pre is not None and mc_pre.kind() == ast.ASTKind.MatchCase:
|
||||
mcc_pre: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(mc_pre)
|
||||
mcc_pre: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](mc_pre)
|
||||
if mcc_pre.children is not None:
|
||||
bn_pre_mcb: t.CSizeT = len(mcc_pre.children)
|
||||
bn_pre_mcb: sizet = len(mcc_pre.children)
|
||||
for bi_pre_mcb in range(bn_pre_mcb):
|
||||
self.pre_scan_allocas(trans, mcc_pre.children.get(bi_pre_mcb))
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def pre_scan_scope_decls(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""预扫描 Global/Nonlocal 声明,提前注册作用域名称"""
|
||||
if node is None:
|
||||
return 0
|
||||
@@ -241,11 +257,11 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
return self.translate_nonlocal(trans, node)
|
||||
return 0
|
||||
|
||||
def translate_break(self, trans: HT.Translator | t.CPtr) -> int:
|
||||
def translate_break(self, trans: HT.Translator*) -> int:
|
||||
"""翻译 break 语句:跳转到循环 end 块"""
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
func: llvmlite.Function* = trans._cur_func
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
@@ -260,15 +276,15 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
trans._label_counter = cnt + 1
|
||||
name_buf: str = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
|
||||
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
dead_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||||
llvmlite.position_at_end(builder, dead_bb)
|
||||
return 0
|
||||
|
||||
def translate_continue(self, trans: HT.Translator | t.CPtr) -> int:
|
||||
def translate_continue(self, trans: HT.Translator*) -> int:
|
||||
"""翻译 continue 语句:跳转到循环 cond/incr 块"""
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
func: llvmlite.Function* = trans._cur_func
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
@@ -283,11 +299,11 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
trans._label_counter = cnt + 1
|
||||
name_buf: str = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
|
||||
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
dead_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
|
||||
llvmlite.position_at_end(builder, dead_bb)
|
||||
return 0
|
||||
|
||||
def get_stmt_kind_name(self, node: ast.AST | t.CPtr) -> str:
|
||||
def get_stmt_kind_name(self, node: ast.AST*) -> str:
|
||||
"""获取语句类型名"""
|
||||
if node is None:
|
||||
return None
|
||||
@@ -297,7 +313,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
# 簇 D:nonlocal/闭包 env 访问(迁移自 HandlesNonlocal.vp)
|
||||
# ============================================================
|
||||
|
||||
def _is_void_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
def _is_void_type(self, ty: llvmlite.LLVMType*) -> int:
|
||||
"""判断是否为 Void 类型,是则返回 1,否则 0"""
|
||||
if ty is None:
|
||||
return 0
|
||||
@@ -307,113 +323,112 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
case _:
|
||||
return 0
|
||||
|
||||
def get_env_ptr_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
def get_env_ptr_var(self, trans: HT.Translator*) -> llvmlite.Value*:
|
||||
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
|
||||
env_var: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||||
trans.SymTab, "_env_ptr")
|
||||
env_var: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, "_env_ptr")
|
||||
if env_var is not None:
|
||||
return env_var
|
||||
# 创建 alloca 存储 env
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty)
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||||
alloca: llvmlite.Value* = llvmlite.build_alloca(builder, i8_ptr_ty)
|
||||
if alloca is None:
|
||||
return None
|
||||
self.Gen.VarGen.define_var(trans.SymTab, "_env_ptr", alloca)
|
||||
return alloca
|
||||
|
||||
def _load_raw_var_ptr(self, trans: HT.Translator | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
def _load_raw_var_ptr(self, trans: HT.Translator*,
|
||||
name: str) -> llvmlite.Value*:
|
||||
"""从闭包 env 加载 nonlocal 变量的原始指针(i8*)
|
||||
|
||||
返回 i8* 类型的 Value,调用方需 bitcast 为具体类型指针后 load/store。
|
||||
"""
|
||||
idx: int = HT.get_nonlocal_index(trans, name)
|
||||
idx: int = GenApi.get_nonlocal_index(trans, name)
|
||||
if idx < 0:
|
||||
return None
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||||
i8_ptr_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ptr_ty)
|
||||
|
||||
# 1. 加载 env_ptr
|
||||
env_alloca: llvmlite.Value | t.CPtr = self.get_env_ptr_var(trans)
|
||||
env_alloca: llvmlite.Value* = self.get_env_ptr_var(trans)
|
||||
if env_alloca is None:
|
||||
return None
|
||||
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
|
||||
env_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, env_alloca)
|
||||
if env_ptr is None:
|
||||
return None
|
||||
|
||||
# 2. GEP to offset (idx * 8) — env 存储指针数组,每槽 8 字节
|
||||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 8)
|
||||
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||||
offset_val: llvmlite.Value* = llvmlite.const_int32(pool, idx * 8)
|
||||
addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||||
if addr is None:
|
||||
return None
|
||||
|
||||
# 3. Bitcast to i8** and load the raw pointer
|
||||
ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty)
|
||||
ptr_addr: llvmlite.Value* = llvmlite.build_bitcast(builder, addr, i8_ptr_ptr_ty)
|
||||
if ptr_addr is None:
|
||||
return None
|
||||
return llvmlite.build_load(builder, i8_ptr_ty, ptr_addr)
|
||||
|
||||
def load_nonlocal_var(self, trans: HT.Translator | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
def load_nonlocal_var(self, trans: HT.Translator*,
|
||||
name: str) -> llvmlite.Value*:
|
||||
"""从闭包 env 加载 nonlocal 变量值
|
||||
|
||||
通过 HT.get_nonlocal_type 获取变量类型,bitcast 原始指针后 load。
|
||||
"""
|
||||
raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name)
|
||||
raw_ptr: llvmlite.Value* = self._load_raw_var_ptr(trans, name)
|
||||
if raw_ptr is None:
|
||||
return None
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
|
||||
# 获取变量类型(从注册时存储的类型信息)
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
|
||||
var_ty: llvmlite.LLVMType* = GenApi.get_nonlocal_type(trans, name)
|
||||
if var_ty is None or self._is_void_type(var_ty) != 0:
|
||||
# 类型缺失/无效直接报错终止(fail-fast),避免生成 "load void, void*" 非法 IR
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
|
||||
|
||||
# bitcast raw i8* to var_ty*
|
||||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||||
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|
||||
var_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, var_ty)
|
||||
var_ptr: llvmlite.Value* = llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|
||||
if var_ptr is None:
|
||||
return None
|
||||
return llvmlite.build_load(builder, var_ty, var_ptr)
|
||||
|
||||
def get_nonlocal_var_ptr(self, trans: HT.Translator | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
def get_nonlocal_var_ptr(self, trans: HT.Translator*,
|
||||
name: str) -> llvmlite.Value*:
|
||||
"""获取 nonlocal 变量的存储指针(var_ty*),用于 store 操作
|
||||
|
||||
返回的指针指向父函数的 alloca,store 操作对父函数可见。
|
||||
"""
|
||||
raw_ptr: llvmlite.Value | t.CPtr = self._load_raw_var_ptr(trans, name)
|
||||
raw_ptr: llvmlite.Value* = self._load_raw_var_ptr(trans, name)
|
||||
if raw_ptr is None:
|
||||
return None
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
|
||||
# 获取变量类型
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = HT.get_nonlocal_type(trans, name)
|
||||
var_ty: llvmlite.LLVMType* = GenApi.get_nonlocal_type(trans, name)
|
||||
if var_ty is None or self._is_void_type(var_ty) != 0:
|
||||
# 类型缺失/无效直接报错终止(fail-fast),避免生成 "bitcast ... to void*" 非法 IR
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法 load", "TypeError")
|
||||
|
||||
# bitcast raw i8* to var_ty*
|
||||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||||
var_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, var_ty)
|
||||
return llvmlite.build_bitcast(builder, raw_ptr, var_ptr_ty)
|
||||
|
||||
# ============================================================
|
||||
# 簇 E:枚举注册表(迁移自 HandlesEnum.vp)
|
||||
# ============================================================
|
||||
|
||||
def init_enum_table(self, pool: memhub.MemBuddy | t.CPtr) -> int:
|
||||
def init_enum_table(self, pool: memhub.MemBuddy*) -> int:
|
||||
"""初始化枚举注册表,返回 1 成功
|
||||
|
||||
表用 stdlib 分配(跨 Phase1 1b 的 mark/reset_to 存活——枚举表是
|
||||
@@ -423,77 +438,72 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
if self.EnumTable is not None:
|
||||
return 1
|
||||
|
||||
entry_size: t.CSizeT = GenTypes.EnumEntry.__sizeof__()
|
||||
self.EnumTable = CompilerFactory.get_perm_pool().alloc(entry_size * ENUM_MAX)
|
||||
entry_size: sizet = GenTypes.EnumEntry.__sizeof__()
|
||||
self.EnumTable = CompilerFactory.factory.PermPool.alloc(entry_size * ENUM_MAX)
|
||||
if self.EnumTable is None:
|
||||
return 0
|
||||
string.memset(self.EnumTable, 0, entry_size * ENUM_MAX)
|
||||
self.EnumCount = 0
|
||||
return 1
|
||||
|
||||
def _get_enum_entry(self, i: int) -> GenTypes.EnumEntry | t.CPtr:
|
||||
def _get_enum_entry(self, i: int) -> rawptr[GenTypes.EnumEntry]:
|
||||
"""获取第 i 个枚举条目"""
|
||||
if self.EnumTable is None or i < 0 or i >= ENUM_MAX:
|
||||
return None
|
||||
entry_size: t.CSizeT = GenTypes.EnumEntry.__sizeof__()
|
||||
addr: t.CUInt64T = t.CUInt64T(self.EnumTable) + i * entry_size
|
||||
return (GenTypes.EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||||
entry_size: sizet = GenTypes.EnumEntry.__sizeof__()
|
||||
addr: uint64 = uint64(self.EnumTable) + i * entry_size
|
||||
return rawptr[GenTypes.EnumEntry](addr)
|
||||
|
||||
def _get_enum_member(self, enum_entry: GenTypes.EnumEntry | t.CPtr,
|
||||
i: int) -> GenTypes.EnumMember | t.CPtr:
|
||||
def _get_enum_member(self, enum_entry: rawptr[GenTypes.EnumEntry],
|
||||
i: int) -> rawptr[GenTypes.EnumMember]:
|
||||
"""获取枚举中第 i 个成员条目"""
|
||||
if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX:
|
||||
return None
|
||||
member_size: t.CSizeT = GenTypes.EnumMember.__sizeof__()
|
||||
addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size
|
||||
return (GenTypes.EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||||
member_size: sizet = GenTypes.EnumMember.__sizeof__()
|
||||
addr: uint64 = uint64(enum_entry.Members) + i * member_size
|
||||
return rawptr[GenTypes.EnumMember](addr)
|
||||
|
||||
def register_enum(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
def register_enum(self, pool: memhub.MemBuddy*,
|
||||
name: str,
|
||||
base_ty: llvmlite.LLVMType | t.CPtr) -> GenTypes.EnumEntry | t.CPtr:
|
||||
base_ty: llvmlite.LLVMType*) -> rawptr[GenTypes.EnumEntry]:
|
||||
"""注册枚举类型,返回 EnumEntry 指针"""
|
||||
if self.init_enum_table(pool) == 0:
|
||||
return None
|
||||
|
||||
# 检查是否已注册
|
||||
existing: GenTypes.EnumEntry | t.CPtr = self.find_enum(name)
|
||||
existing: rawptr[GenTypes.EnumEntry] = self.find_enum(name)
|
||||
if existing is not None:
|
||||
return existing
|
||||
|
||||
if self.EnumCount >= ENUM_MAX:
|
||||
fb_et: str = VLogger.fmt_buf()
|
||||
if fb_et is not None:
|
||||
viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name)
|
||||
VLogger.error(fb_et, "ENUM")
|
||||
VLogger.error(f"table full, cannot register {name}", "ENUM")
|
||||
return None
|
||||
|
||||
entry: GenTypes.EnumEntry | t.CPtr = self._get_enum_entry(self.EnumCount)
|
||||
entry: rawptr[GenTypes.EnumEntry] = self._get_enum_entry(self.EnumCount)
|
||||
if entry is None:
|
||||
return None
|
||||
|
||||
# 分配成员数组(永久池:跨 mark/reset 存活,对齐 EnumTable 永久池化)
|
||||
member_size: t.CSizeT = GenTypes.EnumMember.__sizeof__()
|
||||
entry.Members = CompilerFactory.get_perm_pool().alloc(member_size * ENUM_MEMBER_MAX)
|
||||
member_size: sizet = GenTypes.EnumMember.__sizeof__()
|
||||
entry.Members = CompilerFactory.factory.PermPool.alloc(member_size * ENUM_MEMBER_MAX)
|
||||
if entry.Members is None:
|
||||
return None
|
||||
string.memset(entry.Members, 0, member_size * ENUM_MEMBER_MAX)
|
||||
|
||||
# 复制类名(永久池深拷贝)
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||||
name_len: sizet = string.strlen(name)
|
||||
name_buf: str = CompilerFactory.factory.PermPool.alloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, name)
|
||||
entry.Name = name_buf
|
||||
|
||||
# BaseTy 深拷贝:LLVMType 是 pool 分配,StdlibAlloc=1(Phase2 mark2 后)
|
||||
# 时 reset 回收悬空 → Phase B 枚举访问 ConstInt(悬空 BaseTy) 生成 void
|
||||
# 值(DecoratorMarkerTest `store void 2` llc 报错根因)。Phase1 1a
|
||||
# (StdlibAlloc=0,mark1 前)保持 pool 存活,无需拷贝。
|
||||
# 注意:StdlibAlloc 是 StructGenMixin 字段,本 Mixin 方法体不能直接
|
||||
# self.StdlibAlloc(NoVTable 按本 Mixin 字段布局编译),走模块级委托。
|
||||
# BaseTy 深拷贝:LLVMType 是 pool 分配,StdlibAlloc=1 时 reset 回收悬空 → Phase B
|
||||
# 枚举访问 ConstInt(悬空 BaseTy) 生成 void 值(llc 报错)。Phase1 1a(mark1 前)
|
||||
# 保持 pool 存活,无需拷贝。
|
||||
# 注意:StdlibAlloc 是 StructGenMixin 字段,本 Mixin 方法体不能直接 self.StdlibAlloc
|
||||
# (NoVTable 按本 Mixin 字段布局编译),走模块级委托。
|
||||
if self.Gen.StructGen.get_stdlib_alloc() != 0:
|
||||
base_ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(
|
||||
CompilerFactory.get_perm_pool(), base_ty)
|
||||
base_ty_copy: llvmlite.LLVMType* = llvmlite.DeepCopyType(CompilerFactory.factory.PermPool, base_ty)
|
||||
if base_ty_copy is not None:
|
||||
entry.BaseTy = base_ty_copy
|
||||
else:
|
||||
@@ -505,11 +515,11 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
self.EnumCount += 1
|
||||
return entry
|
||||
|
||||
def add_enum_member(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
enum_entry: GenTypes.EnumEntry | t.CPtr,
|
||||
def add_enum_member(self, pool: memhub.MemBuddy*,
|
||||
enum_entry: rawptr[GenTypes.EnumEntry],
|
||||
member_name: str,
|
||||
member_val: t.CInt64T,
|
||||
member_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
member_val: int64,
|
||||
member_ty: llvmlite.LLVMType*) -> int:
|
||||
"""向枚举添加成员,返回成员索引(-1 失败)"""
|
||||
if enum_entry is None or member_name is None or member_ty is None:
|
||||
return -1
|
||||
@@ -517,27 +527,23 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
# 去重:同名成员已存在则跳过(跨模块同名枚举合并注册 / 同模块
|
||||
# 重复处理幂等——如 w32.fileio 与 fat32_types 都有 FRESULT)
|
||||
for ei_d in range(enum_entry.MemberCount):
|
||||
ex_d: GenTypes.EnumMember | t.CPtr = self._get_enum_member(
|
||||
enum_entry, ei_d)
|
||||
ex_d: rawptr[GenTypes.EnumMember] = self._get_enum_member(enum_entry, ei_d)
|
||||
if ex_d is not None and ex_d.Name is not None:
|
||||
if string.strcmp(ex_d.Name, member_name) == 0:
|
||||
return ei_d
|
||||
|
||||
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
|
||||
fb_em: str = VLogger.fmt_buf()
|
||||
if fb_em is not None:
|
||||
viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name)
|
||||
VLogger.error(fb_em, "ENUM")
|
||||
VLogger.error(f"member table full for {enum_entry.Name}", "ENUM")
|
||||
return -1
|
||||
|
||||
idx: int = enum_entry.MemberCount
|
||||
me: GenTypes.EnumMember | t.CPtr = self._get_enum_member(enum_entry, idx)
|
||||
me: rawptr[GenTypes.EnumMember] = self._get_enum_member(enum_entry, idx)
|
||||
if me is None:
|
||||
return -1
|
||||
|
||||
# 复制成员名(永久池深拷贝:成员表跨 mark/reset 存活)
|
||||
name_len: t.CSizeT = string.strlen(member_name)
|
||||
name_buf: str = CompilerFactory.get_perm_pool().alloc(name_len + 1)
|
||||
name_len: sizet = string.strlen(member_name)
|
||||
name_buf: str = CompilerFactory.factory.PermPool.alloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, member_name)
|
||||
me.Name = name_buf
|
||||
@@ -548,27 +554,27 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
enum_entry.MemberCount = idx + 1
|
||||
return idx
|
||||
|
||||
def find_enum(self, name: str) -> GenTypes.EnumEntry | t.CPtr:
|
||||
def find_enum(self, name: str) -> rawptr[GenTypes.EnumEntry]:
|
||||
"""按枚举类名查找,返回 EnumEntry 或 None"""
|
||||
if name is None or self.EnumTable is None:
|
||||
return None
|
||||
for i in range(self.EnumCount):
|
||||
entry: GenTypes.EnumEntry | t.CPtr = self._get_enum_entry(i)
|
||||
entry: rawptr[GenTypes.EnumEntry] = self._get_enum_entry(i)
|
||||
if entry is not None and entry.Name is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
return entry
|
||||
return None
|
||||
|
||||
def lookup_enum_member(self, enum_name: str,
|
||||
member_name: str) -> GenTypes.EnumMember | t.CPtr:
|
||||
member_name: str) -> rawptr[GenTypes.EnumMember]:
|
||||
"""按枚举类名和成员名查找,返回 EnumMember 或 None"""
|
||||
if enum_name is None or member_name is None:
|
||||
return None
|
||||
entry: GenTypes.EnumEntry | t.CPtr = self.find_enum(enum_name)
|
||||
entry: rawptr[GenTypes.EnumEntry] = self.find_enum(enum_name)
|
||||
if entry is None:
|
||||
return None
|
||||
for mi in range(entry.MemberCount):
|
||||
me: GenTypes.EnumMember | t.CPtr = self._get_enum_member(entry, mi)
|
||||
me: rawptr[GenTypes.EnumMember] = self._get_enum_member(entry, mi)
|
||||
if me is not None and me.Name is not None:
|
||||
if string.strcmp(me.Name, member_name) == 0:
|
||||
return me
|
||||
@@ -582,9 +588,9 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def get_enum_base_type(self, enum_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
def get_enum_base_type(self, enum_name: str) -> llvmlite.LLVMType*:
|
||||
"""按枚举类名获取基准类型"""
|
||||
entry: GenTypes.EnumEntry | t.CPtr = self.find_enum(enum_name)
|
||||
entry: rawptr[GenTypes.EnumEntry] = self.find_enum(enum_name)
|
||||
if entry is not None:
|
||||
return entry.BaseTy
|
||||
return None
|
||||
@@ -1,6 +1,6 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import lib.core.Gen.CallGenFd as CallGenFd
|
||||
import lib.core.Gen.Call.CallGenFd as CallGenFd
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
@@ -11,49 +11,44 @@ import stdlib
|
||||
import stdio
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin
|
||||
import lib.core.Gen.Stmt.StmtGenDeclMixin as StmtGenDeclMixin
|
||||
import lib.core.Gen.DebugInfoGen as DebugInfoGen
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StmtGenMixin - 语句/流程翻译 Mixin(P6 对象化重构 A 组,拆分后顶层)
|
||||
#
|
||||
# 按功能域拆分(500~1500 行/文件架构重构,试点):
|
||||
# 顶层保留语句分派中枢簇 A(translate_stmt/try/raise/with/delete/
|
||||
# _eh_ret_default/_with_ctx_call);global/nonlocal/枚举/CIf 已拆至
|
||||
# StmtGenDeclMixin / StmtGenCifMixin(本类继承链 1/3、2/3)。
|
||||
# 外部引用(Generator.vp import + HandlesBody 委托)零改动。
|
||||
#
|
||||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# StmtGenMixin - 语句分派中枢(顶层)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
novirtual class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
"""语句/流程翻译 Mixin(拆分后顶层,继承 Decl)"""
|
||||
|
||||
def translate_stmt(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_stmt(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译单条语句,返回新增的变量数(深度守卫包装器,原逻辑见 _translate_stmt_impl)"""
|
||||
if trans is not None:
|
||||
# --traceback: statement-level DWARF location (no-op outside a
|
||||
# DI-attached define or when DI is disabled). 此后本语句生成的每条
|
||||
# 指令自动带 ", !dbg !N",保证函数体内每个 call 都有合法 !dbg。
|
||||
if node is not None and trans._cur_builder is not None:
|
||||
DebugInfoGen.SetStatement(trans.Pool, trans._cur_builder,
|
||||
node.lineno, node.col_offset + 1)
|
||||
if trans.TranslateDepth >= HT.TRANSLATE_MAX_DEPTH:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, "语句翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, "语句翻译嵌套过深(疑似 AST 自引用环或翻译 bug)", "RecursionError")
|
||||
trans.TranslateDepth += 1
|
||||
mret: int = self._translate_stmt_impl(trans, node)
|
||||
if trans is not None:
|
||||
trans.TranslateDepth -= 1
|
||||
return mret
|
||||
|
||||
def _translate_stmt_impl(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def _translate_stmt_impl(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译单条语句,返回新增的变量数"""
|
||||
if node is None:
|
||||
return 0
|
||||
@@ -109,68 +104,61 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"未知语句类型 kind={k}", "SyntaxError")
|
||||
return 0
|
||||
|
||||
def translate_delete(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_delete(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译 del 语句,返回 0"""
|
||||
if trans is None or node is None:
|
||||
return 0
|
||||
dnode: ast.Delete | t.CPtr = (ast.Delete | t.CPtr)(node)
|
||||
dnode: rawptr[ast.Delete] = rawptr[ast.Delete](node)
|
||||
if dnode is None or dnode.targets is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
mod: llvmlite.LLVMModule* = trans.Module
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
if pool is None or mod is None or builder is None:
|
||||
return 0
|
||||
tn: t.CSizeT = len(dnode.targets)
|
||||
tn: sizet = len(dnode.targets)
|
||||
for ti in range(tn):
|
||||
tgt: ast.AST | t.CPtr = dnode.targets.get(ti)
|
||||
tgt: ast.AST* = dnode.targets.get(ti)
|
||||
if tgt is None:
|
||||
continue
|
||||
# del obj.attr → property deleter
|
||||
if tgt.kind() == ast.ASTKind.Attribute:
|
||||
del_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tgt)
|
||||
del_at: ast.Attribute* = ast.Attribute*(tgt)
|
||||
if del_at is not None:
|
||||
self.Gen.CallGenProp._try_property_deleter(
|
||||
pool, builder, mod, del_at, trans)
|
||||
# del obj[key] → __delitem__(obj, key)
|
||||
# (对齐 TPC HandlesDelete.py L14-25;此前 Subscript 目标被静默
|
||||
# 忽略,HashTableTest Test 11 的 del ht3[del_buf] 未执行 → len 不变)
|
||||
self.Gen.CallGenProp._try_property_deleter(pool, builder, mod, del_at, trans)
|
||||
# del obj[key] → __delitem__(obj, key)(对齐 TPC HandlesDelete.py)。
|
||||
# 不能静默忽略 Subscript 目标——否则 del 不生效(len 不变)。
|
||||
elif tgt.kind() == ast.ASTKind.Subscript:
|
||||
dl_sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(tgt)
|
||||
dl_sub: ast.Subscript* = ast.Subscript*(tgt)
|
||||
if dl_sub is not None and dl_sub.value is not None and dl_sub.slice is not None:
|
||||
dl_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, dl_sub.value, None, 0, trans)
|
||||
dl_idx: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, dl_sub.slice, None, 0, trans)
|
||||
dl_obj: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, dl_sub.value, None, 0, trans)
|
||||
dl_idx: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, dl_sub.slice, None, 0, trans)
|
||||
if dl_obj is not None and dl_idx is not None:
|
||||
dl_st: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(
|
||||
dl_obj)
|
||||
dl_st: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(dl_obj)
|
||||
if dl_st is not None:
|
||||
dl_cls: str = self.Gen.StructGen.get_class_name_by_type(pool, dl_st)
|
||||
if dl_cls is not None:
|
||||
dl_lookup: str = pool.alloc(128)
|
||||
if dl_lookup is not None:
|
||||
viperlib.snprintf(dl_lookup, 128, "%s.__delitem__", dl_cls)
|
||||
dl_fn: llvmlite.Function | t.CPtr = self.Gen.CallGenBase.find_func_in_module(
|
||||
mod, dl_lookup)
|
||||
dl_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, dl_lookup)
|
||||
if dl_fn is not None:
|
||||
dl_ret: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(dl_fn)
|
||||
dl_ret: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(dl_fn)
|
||||
dl_fn_name: str = llvmlite.function_get_name(dl_fn)
|
||||
if dl_ret is not None and dl_fn_name is not None:
|
||||
# self 参数(容器)按 __delitem__ 首参类型对齐
|
||||
dl_self: llvmlite.Value | t.CPtr = dl_obj
|
||||
dl_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(dl_fn)
|
||||
dl_self: llvmlite.Value* = dl_obj
|
||||
dl_first: llvmlite.Param* = llvmlite.function_get_param_head(dl_fn)
|
||||
if dl_first is not None:
|
||||
dl_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(dl_first)
|
||||
dl_self_ty: llvmlite.LLVMType* = llvmlite.param_get_ty(dl_first)
|
||||
if dl_self_ty is not None:
|
||||
dl_self = llvmlite.build_bitcast(builder, dl_obj, dl_self_ty)
|
||||
if dl_self is not None:
|
||||
# 参数链表: self → key(独立 null 结尾)
|
||||
dl_self.Next = dl_idx
|
||||
dl_idx.Next = None
|
||||
llvmlite.build_call(
|
||||
builder, dl_fn_name, dl_self, 2, dl_ret, 0)
|
||||
llvmlite.build_call(builder, dl_fn_name, dl_self, 2, dl_ret, 0)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
@@ -188,34 +176,34 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# v1 未实现 finalbody(TestFBProject 未使用;finally+return 交互复杂,
|
||||
# 后续按 TPC HandlesTry.py L188-214 的 pending_ret 方案扩展)。
|
||||
# ============================================================
|
||||
def translate_try(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_try(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译 try/except 语句,返回 0"""
|
||||
if trans is None or node is None:
|
||||
return 0
|
||||
tr: ast.Try | t.CPtr = (ast.Try | t.CPtr)(node)
|
||||
tr: ast.Try* = ast.Try*(node)
|
||||
if tr is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
func: llvmlite.Function* = trans._cur_func
|
||||
if pool is None or builder is None or func is None:
|
||||
return 0
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
|
||||
return 0
|
||||
|
||||
# ---- 1. 异常编码/消息 alloca(当前 try 上下文)----
|
||||
i32_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_t: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_t)
|
||||
i32_ty_t: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
i8_ty_t: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_t: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty_t)
|
||||
if i32_ty_t is None or i8_ptr_ty_t is None:
|
||||
return 0
|
||||
exception_code: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i32_ty_t)
|
||||
eh_message: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i8_ptr_ty_t)
|
||||
exception_code: llvmlite.Value* = llvmlite.build_alloca(builder, i32_ty_t)
|
||||
eh_message: llvmlite.Value* = llvmlite.build_alloca(builder, i8_ptr_ty_t)
|
||||
if exception_code is None or eh_message is None:
|
||||
return 0
|
||||
init_code_t: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
init_msg_t: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_t, "null")
|
||||
init_code_t: llvmlite.Value* = llvmlite.const_int32(pool, 0)
|
||||
init_msg_t: llvmlite.Value* = llvmlite.ConstNull(pool, i8_ptr_ty_t, "null")
|
||||
if init_code_t is not None:
|
||||
llvmlite.build_store(builder, init_code_t, exception_code)
|
||||
if init_msg_t is not None:
|
||||
@@ -228,43 +216,43 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
if bb_buf_t is None:
|
||||
return 0
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.dispatch.%d", lc_t)
|
||||
dispatch_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
dispatch_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.after.%d", lc_t)
|
||||
after_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
after_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.unhandled.%d", lc_t)
|
||||
unhandled_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
unhandled_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.body.%d", lc_t)
|
||||
try_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
try_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
if dispatch_bb is None or after_bb is None or unhandled_bb is None or try_bb is None:
|
||||
return 0
|
||||
else_bb: llvmlite.BasicBlock | t.CPtr = None
|
||||
else_bb: rawptr[llvmlite.BasicBlock] = None
|
||||
if tr.orelse is not None and len(tr.orelse) > 0:
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.else.%d", lc_t)
|
||||
else_bb = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
n_handlers_t: t.CSizeT = 0
|
||||
n_handlers_t: sizet = 0
|
||||
if tr.handlers is not None:
|
||||
n_handlers_t = len(tr.handlers)
|
||||
# 注意:list[ptr](pool, N) 第二参数是 elem_size 不是容量!
|
||||
# 指针元素必须显式传 8(T.__sizeof__ 对联合类型不可靠),
|
||||
# 否则 append 按 N 字节步长错位存取 → 读出垃圾指针(崩溃)。
|
||||
except_bbs: list[llvmlite.BasicBlock | t.CPtr] | t.CPtr = \
|
||||
list[llvmlite.BasicBlock | t.CPtr](pool, 8)
|
||||
match_bbs: list[llvmlite.BasicBlock | t.CPtr] | t.CPtr = \
|
||||
list[llvmlite.BasicBlock | t.CPtr](pool, 8)
|
||||
except_bbs: list[rawptr[llvmlite.BasicBlock]] | t.CPtr = \
|
||||
list[rawptr[llvmlite.BasicBlock]](pool, 8)
|
||||
match_bbs: list[rawptr[llvmlite.BasicBlock]] | t.CPtr = \
|
||||
list[rawptr[llvmlite.BasicBlock]](pool, 8)
|
||||
if except_bbs is None or match_bbs is None:
|
||||
return 0
|
||||
for i_t in range(n_handlers_t):
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.except.%d.%d", lc_t, i_t)
|
||||
eb_t: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
eb_t: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.match.%d.%d", lc_t, i_t)
|
||||
mb_t: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
mb_t: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
except_bbs.append(eb_t)
|
||||
match_bbs.append(mb_t)
|
||||
|
||||
# ---- 3. 保存外层 try 上下文,设置本 try 上下文 ----
|
||||
old_dispatch_t: llvmlite.BasicBlock | t.CPtr = trans._eh_dispatch_bb
|
||||
old_code_t: llvmlite.Value | t.CPtr = trans._eh_code_ptr
|
||||
old_msg_t: llvmlite.Value | t.CPtr = trans._eh_msg_ptr
|
||||
old_dispatch_t: rawptr[llvmlite.BasicBlock] = trans._eh_dispatch_bb
|
||||
old_code_t: llvmlite.Value* = trans._eh_code_ptr
|
||||
old_msg_t: llvmlite.Value* = trans._eh_msg_ptr
|
||||
trans._eh_dispatch_bb = dispatch_bb
|
||||
trans._eh_code_ptr = exception_code
|
||||
trans._eh_msg_ptr = eh_message
|
||||
@@ -273,9 +261,9 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
llvmlite.build_br(builder, try_bb)
|
||||
llvmlite.position_at_end(builder, try_bb)
|
||||
if tr.children is not None:
|
||||
tb_n: t.CSizeT = len(tr.children)
|
||||
tb_n: sizet = len(tr.children)
|
||||
for tbi in range(tb_n):
|
||||
stmt_t: ast.AST | t.CPtr = tr.children.get(tbi)
|
||||
stmt_t: ast.AST* = tr.children.get(tbi)
|
||||
if stmt_t is not None:
|
||||
self.translate_stmt(trans, stmt_t)
|
||||
# 正常走完 try 体:清异常码,进 else(若有)或 After
|
||||
@@ -293,39 +281,34 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# 无 except(非法 try,防御):直接吞掉
|
||||
llvmlite.build_br(builder, unhandled_bb)
|
||||
else:
|
||||
eh_code_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i32_ty_t, exception_code)
|
||||
next_check_t: llvmlite.BasicBlock | t.CPtr = None
|
||||
eh_code_val: llvmlite.Value* = llvmlite.build_load(builder, i32_ty_t, exception_code)
|
||||
next_check_t: rawptr[llvmlite.BasicBlock] = None
|
||||
for i_t in range(n_handlers_t):
|
||||
hdr_t: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(
|
||||
tr.handlers.get(i_t))
|
||||
match_bb_t: llvmlite.BasicBlock | t.CPtr = match_bbs.get(i_t)
|
||||
hdr_t: ast.ExceptHandler* = ast.ExceptHandler*(tr.handlers.get(i_t))
|
||||
match_bb_t: rawptr[llvmlite.BasicBlock] = match_bbs.get(i_t)
|
||||
if i_t > 0 and next_check_t is not None:
|
||||
llvmlite.position_at_end(builder, next_check_t)
|
||||
eh_code_val = llvmlite.build_load(
|
||||
builder, i32_ty_t, exception_code)
|
||||
eh_code_val = llvmlite.build_load(builder, i32_ty_t, exception_code)
|
||||
if hdr_t is None or hdr_t.type is None:
|
||||
# 裸 except:无条件匹配
|
||||
llvmlite.build_br(builder, match_bb_t)
|
||||
else:
|
||||
# 展开匹配编码集(handler.type 自身 + 全部子孙异常类)
|
||||
hname_t: str = None
|
||||
htype_t: ast.AST | t.CPtr = hdr_t.type
|
||||
htype_t: ast.AST* = hdr_t.type
|
||||
if htype_t.kind() == ast.ASTKind.Name:
|
||||
hname_t = ((ast.Name | t.CPtr)(htype_t)).id
|
||||
hname_t = (ast.Name*(htype_t)).id
|
||||
elif htype_t.kind() == ast.ASTKind.Attribute:
|
||||
hname_t = ((ast.Attribute | t.CPtr)(htype_t)).attr
|
||||
# 匹配编码缓冲:必须是 t.CInt*(i32 步长)——collect_descendant_codes
|
||||
# 按 out_codes[i](4 字节)写入;若用 t.CSizeT*(8 字节)读,
|
||||
# 多码时读出 (code[i+1]<<32)|code[i] 的 64 位拼接垃圾(单码时
|
||||
# 高位恰为 0 掩盖;Test 2/3/8 父类多码捕获失败的根因)。
|
||||
codes_buf_t: t.CInt | t.CPtr = pool.alloc(64 * 4)
|
||||
hname_t = (ast.Attribute*(htype_t)).attr
|
||||
# 匹配编码缓冲:必须是 int*(i32 步长)——collect_descendant_codes 按
|
||||
# out_codes[i](4 字节)写入;用 sizet*(8 字节)读会读出 64 位拼接垃圾
|
||||
# (多码时 code[i+1]<<32|code[i];单码时高位恰为 0 掩盖)。
|
||||
codes_buf_t: int | t.CPtr = pool.alloc(64 * 4)
|
||||
if codes_buf_t is None:
|
||||
return 0
|
||||
n_codes_t: int = 0
|
||||
if hname_t is not None and self.Gen.ClassGenBase.is_exception_name(hname_t) != 0:
|
||||
n_codes_t = self.Gen.ClassGenBase.collect_descendant_codes(
|
||||
hname_t, codes_buf_t, 64)
|
||||
n_codes_t = self.Gen.ClassGenBase.collect_descendant_codes(hname_t, codes_buf_t, 64)
|
||||
else:
|
||||
c0_t: int = 1
|
||||
if hname_t is not None:
|
||||
@@ -334,24 +317,20 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
c0_t = 1
|
||||
codes_buf_t[0] = c0_t
|
||||
n_codes_t = 1
|
||||
match_cond_t: llvmlite.Value | t.CPtr = None
|
||||
match_cond_t: llvmlite.Value* = None
|
||||
for ci_t in range(n_codes_t):
|
||||
code_val_t: llvmlite.Value | t.CPtr = llvmlite.const_int32(
|
||||
pool, codes_buf_t[ci_t])
|
||||
is_match_t: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_EQ, eh_code_val, code_val_t)
|
||||
code_val_t: llvmlite.Value* = llvmlite.const_int32(pool, codes_buf_t[ci_t])
|
||||
is_match_t: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, eh_code_val, code_val_t)
|
||||
if match_cond_t is None:
|
||||
match_cond_t = is_match_t
|
||||
elif is_match_t is not None:
|
||||
match_cond_t = llvmlite.build_or(
|
||||
builder, match_cond_t, is_match_t)
|
||||
match_cond_t = llvmlite.build_or(builder, match_cond_t, is_match_t)
|
||||
if i_t < n_handlers_t - 1:
|
||||
viperlib.snprintf(bb_buf_t, 64, "try.check.%d.%d", lc_t, i_t)
|
||||
next_check_t = llvmlite.create_block(pool, func, bb_buf_t)
|
||||
else:
|
||||
next_check_t = unhandled_bb
|
||||
llvmlite.build_cond_br(
|
||||
builder, match_cond_t, match_bb_t, next_check_t)
|
||||
llvmlite.build_cond_br(builder, match_cond_t, match_bb_t, next_check_t)
|
||||
# MatchBB:绑定 handler 变量(e = 消息指针),跳 ExceptBB
|
||||
llvmlite.position_at_end(builder, match_bb_t)
|
||||
if hdr_t is not None and hdr_t.name is not None and hdr_t.name[0] != '\0':
|
||||
@@ -359,30 +338,26 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# 重复 define_var 不 shadow——多 try 共用 `as e` 时各 MatchBB
|
||||
# 各自 store 消息,各 ExceptBB 读同一入口 alloca,避免
|
||||
# 非支配 alloca 触发 "does not dominate all uses")。
|
||||
h_ent_t: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||||
trans.SymTab, hdr_t.name)
|
||||
h_ent_t: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, hdr_t.name)
|
||||
if h_ent_t is not None and h_ent_t.Alloca is not None:
|
||||
h_alloca_t: llvmlite.Value | t.CPtr = h_ent_t.Alloca
|
||||
h_alloca_t: llvmlite.Value* = h_ent_t.Alloca
|
||||
else:
|
||||
h_alloca_t = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty_t)
|
||||
if h_alloca_t is not None:
|
||||
self.Gen.VarGen.define_var(trans.SymTab, hdr_t.name, h_alloca_t)
|
||||
if h_alloca_t is not None:
|
||||
h_msg_t: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i8_ptr_ty_t, eh_message)
|
||||
h_msg_t: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty_t, eh_message)
|
||||
if h_msg_t is not None:
|
||||
llvmlite.build_store(builder, h_msg_t, h_alloca_t)
|
||||
except_bb_t: llvmlite.BasicBlock | t.CPtr = except_bbs.get(i_t)
|
||||
except_bb_t: rawptr[llvmlite.BasicBlock] = except_bbs.get(i_t)
|
||||
llvmlite.build_br(builder, except_bb_t)
|
||||
|
||||
# ---- 6. UnhandledBB:无 except 匹配 → 向上传播或吞掉 ----
|
||||
llvmlite.position_at_end(builder, unhandled_bb)
|
||||
if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \
|
||||
and trans._eh_code_out_param is not None:
|
||||
un_msg_t: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i8_ptr_ty_t, eh_message)
|
||||
un_code_t: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, i32_ty_t, exception_code)
|
||||
un_msg_t: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty_t, eh_message)
|
||||
un_code_t: llvmlite.Value* = llvmlite.build_load(builder, i32_ty_t, exception_code)
|
||||
if un_msg_t is not None:
|
||||
llvmlite.build_store(builder, un_msg_t, trans._eh_msg_out_param)
|
||||
if un_code_t is not None:
|
||||
@@ -395,14 +370,13 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
|
||||
# ---- 7. Except 体 ----
|
||||
for i_t in range(n_handlers_t):
|
||||
hdr2_t: ast.ExceptHandler | t.CPtr = (ast.ExceptHandler | t.CPtr)(
|
||||
tr.handlers.get(i_t))
|
||||
except_bb2_t: llvmlite.BasicBlock | t.CPtr = except_bbs.get(i_t)
|
||||
hdr2_t: ast.ExceptHandler* = ast.ExceptHandler*(tr.handlers.get(i_t))
|
||||
except_bb2_t: rawptr[llvmlite.BasicBlock] = except_bbs.get(i_t)
|
||||
llvmlite.position_at_end(builder, except_bb2_t)
|
||||
if hdr2_t is not None and hdr2_t.children is not None:
|
||||
hn2_t: t.CSizeT = len(hdr2_t.children)
|
||||
hn2_t: sizet = len(hdr2_t.children)
|
||||
for hi2 in range(hn2_t):
|
||||
stmt2_t: ast.AST | t.CPtr = hdr2_t.children.get(hi2)
|
||||
stmt2_t: ast.AST* = hdr2_t.children.get(hi2)
|
||||
if stmt2_t is not None:
|
||||
self.translate_stmt(trans, stmt2_t)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
@@ -412,9 +386,9 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
if else_bb is not None:
|
||||
llvmlite.position_at_end(builder, else_bb)
|
||||
if tr.orelse is not None:
|
||||
en_t: t.CSizeT = len(tr.orelse)
|
||||
en_t: sizet = len(tr.orelse)
|
||||
for ei in range(en_t):
|
||||
stmt3_t: ast.AST | t.CPtr = tr.orelse.get(ei)
|
||||
stmt3_t: ast.AST* = tr.orelse.get(ei)
|
||||
if stmt3_t is not None:
|
||||
self.translate_stmt(trans, stmt3_t)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
@@ -427,8 +401,8 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
trans._eh_msg_ptr = old_msg_t
|
||||
return 0
|
||||
|
||||
def translate_raise(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_raise(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译 raise 语句,返回 0
|
||||
|
||||
对齐 TPC HandlesRaise.py 的 try-except 语义(v1 迁移):
|
||||
@@ -442,12 +416,12 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
"""
|
||||
if trans is None or node is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
mod: llvmlite.LLVMModule* = trans.Module
|
||||
if pool is None or builder is None or mod is None:
|
||||
return 0
|
||||
rn: ast.Raise | t.CPtr = (ast.Raise | t.CPtr)(node)
|
||||
rn: rawptr[ast.Raise] = rawptr[ast.Raise](node)
|
||||
if rn is None or rn.exc is None:
|
||||
# bare raise(无 exc):v1 无活动异常可再抛,仅返回默认值
|
||||
self._eh_ret_default(trans, pool, builder)
|
||||
@@ -458,61 +432,57 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
ek: int = rn.exc.kind()
|
||||
is_stop_iter: int = 0
|
||||
if ek == ast.ASTKind.Name:
|
||||
enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn.exc)
|
||||
enm: ast.Name* = ast.Name*(rn.exc)
|
||||
if enm.id is not None and string.strcmp(enm.id, "StopIteration") == 0:
|
||||
is_stop_iter = 1
|
||||
elif ek == ast.ASTKind.Call:
|
||||
ecl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn.exc)
|
||||
ecl: ast.Call* = ast.Call*(rn.exc)
|
||||
if ecl.func is not None and ecl.func.kind() == ast.ASTKind.Name:
|
||||
ecn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl.func)
|
||||
ecn: ast.Name* = ast.Name*(ecl.func)
|
||||
if ecn.id is not None and string.strcmp(ecn.id, "StopIteration") == 0:
|
||||
is_stop_iter = 1
|
||||
if is_stop_iter != 0:
|
||||
if trans._stop_iter_flag_ptr is not None:
|
||||
i1_ty_r: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||||
i1_ty_r: llvmlite.LLVMType* = llvmlite.Int1(pool)
|
||||
if i1_ty_r is not None:
|
||||
one_i1_r: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||||
pool, i1_ty_r, 1, "1")
|
||||
one_i1_r: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty_r, 1, "1")
|
||||
if one_i1_r is not None:
|
||||
llvmlite.build_store(
|
||||
builder, one_i1_r, trans._stop_iter_flag_ptr)
|
||||
llvmlite.build_store(builder, one_i1_r, trans._stop_iter_flag_ptr)
|
||||
self._eh_ret_default(trans, pool, builder)
|
||||
return 0
|
||||
|
||||
# ---- 非 StopIteration:计算异常编码与消息 ----
|
||||
exc_code: int = 1
|
||||
exc_msg: llvmlite.Value | t.CPtr = None
|
||||
exc_msg: llvmlite.Value* = None
|
||||
if ek == ast.ASTKind.Constant:
|
||||
cst_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rn.exc)
|
||||
cst_r: ast.Constant* = ast.Constant*(rn.exc)
|
||||
if cst_r is not None and cst_r.const_kind == ast.CONST_INT:
|
||||
exc_code = cst_r.int_val
|
||||
elif ek == ast.ASTKind.Name:
|
||||
enm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rn.exc)
|
||||
enm2: ast.Name* = ast.Name*(rn.exc)
|
||||
if enm2.id is not None:
|
||||
exc_code = self.Gen.ClassGenBase.lookup_exception_code(enm2.id)
|
||||
if exc_code == 0:
|
||||
exc_code = 1
|
||||
elif ek == ast.ASTKind.Call:
|
||||
ecl2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rn.exc)
|
||||
ecl2: ast.Call* = ast.Call*(rn.exc)
|
||||
if ecl2.func is not None and ecl2.func.kind() == ast.ASTKind.Name:
|
||||
ecn2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ecl2.func)
|
||||
ecn2: ast.Name* = ast.Name*(ecl2.func)
|
||||
if ecn2.id is not None:
|
||||
exc_code = self.Gen.ClassGenBase.lookup_exception_code(ecn2.id)
|
||||
if exc_code == 0:
|
||||
exc_code = 1
|
||||
if ecl2.args is not None and len(ecl2.args) > 0:
|
||||
exc_msg = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, ecl2.args.get(0), None, 0, trans)
|
||||
exc_msg = self.Gen.ExprGen.translate_value(builder, pool, mod, ecl2.args.get(0), None, 0, trans)
|
||||
|
||||
# ---- 异常分发 ----
|
||||
# 1. try 内:写入 try 的 eh_code/eh_message alloca,分支 DispatchBB
|
||||
if trans._eh_dispatch_bb is not None and trans._eh_code_ptr is not None:
|
||||
code_val_r: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, exc_code)
|
||||
code_val_r: llvmlite.Value* = llvmlite.const_int32(pool, exc_code)
|
||||
if code_val_r is not None:
|
||||
llvmlite.build_store(builder, code_val_r, trans._eh_code_ptr)
|
||||
if exc_msg is None:
|
||||
exc_msg = llvmlite.ConstNull(
|
||||
pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null")
|
||||
exc_msg = llvmlite.ConstNull(pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null")
|
||||
if exc_msg is not None and trans._eh_msg_ptr is not None:
|
||||
llvmlite.build_store(builder, exc_msg, trans._eh_msg_ptr)
|
||||
llvmlite.build_br(builder, trans._eh_dispatch_bb)
|
||||
@@ -520,12 +490,11 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# 2. 函数有 EH 输出参数:写入 out 参数(异常向调用方传播)
|
||||
if trans._cur_func_has_eh != 0 and trans._eh_msg_out_param is not None \
|
||||
and trans._eh_code_out_param is not None:
|
||||
code_val_r2: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, exc_code)
|
||||
code_val_r2: llvmlite.Value* = llvmlite.const_int32(pool, exc_code)
|
||||
if code_val_r2 is not None:
|
||||
llvmlite.build_store(builder, code_val_r2, trans._eh_code_out_param)
|
||||
if exc_msg is None:
|
||||
exc_msg = llvmlite.ConstNull(
|
||||
pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null")
|
||||
exc_msg = llvmlite.ConstNull(pool, llvmlite.Ptr(pool, llvmlite.Int8(pool)), "null")
|
||||
if exc_msg is not None:
|
||||
llvmlite.build_store(builder, exc_msg, trans._eh_msg_out_param)
|
||||
self._eh_ret_default(trans, pool, builder)
|
||||
@@ -541,33 +510,33 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# (void→ret_void,ptr→null,float→0.0,其余→零值)。当前块已
|
||||
# 终结(前一条是 raise/return)时跳过,避免在终止块后插指令。
|
||||
# ============================================================
|
||||
def _eh_ret_default(self, trans: HT.Translator | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr) -> int:
|
||||
def _eh_ret_default(self, trans: HT.Translator*,
|
||||
pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*) -> int:
|
||||
"""异常路径返回当前函数默认零值,返回 0"""
|
||||
if trans is None or builder is None:
|
||||
return 0
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
|
||||
return 0
|
||||
cur_func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
cur_func: llvmlite.Function* = trans._cur_func
|
||||
if cur_func is None:
|
||||
return 0
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func)
|
||||
ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(cur_func)
|
||||
if ret_ty is None:
|
||||
return 0
|
||||
match ret_ty:
|
||||
case llvmlite.LLVMType.Void():
|
||||
llvmlite.build_ret_void(builder)
|
||||
case llvmlite.LLVMType.Ptr(_pe):
|
||||
null_v: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
|
||||
null_v: llvmlite.Value* = llvmlite.ConstNull(pool, ret_ty, "null")
|
||||
if null_v is not None:
|
||||
llvmlite.build_ret(builder, null_v)
|
||||
case llvmlite.LLVMType.Float(_fb):
|
||||
zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0)
|
||||
zero_f: llvmlite.Value* = llvmlite.ConstFloat(pool, ret_ty, 0.0)
|
||||
if zero_f is not None:
|
||||
llvmlite.build_ret(builder, zero_f)
|
||||
case _:
|
||||
zero_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, ret_ty)
|
||||
zero_v: llvmlite.Value* = llvmlite.ConstZero(pool, ret_ty)
|
||||
if zero_v is not None:
|
||||
llvmlite.build_ret(builder, zero_v)
|
||||
return 0
|
||||
@@ -588,64 +557,61 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# 退出后恢复,避免内层覆盖导致外层 __exit__ 解析到错误对象。
|
||||
# 对齐 TPC HandlesWith 语义(不含 __provides__ provider 机制)。
|
||||
# ============================================================
|
||||
def translate_with(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
def translate_with(self, trans: HT.Translator*,
|
||||
node: ast.AST*) -> int:
|
||||
"""翻译 with 语句,返回 0"""
|
||||
if trans is None or node is None:
|
||||
return 0
|
||||
wt: ast.With | t.CPtr = (ast.With | t.CPtr)(node)
|
||||
wt: ast.With* = ast.With*(node)
|
||||
if wt is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
pool: memhub.MemBuddy* = trans.Pool
|
||||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||||
mod: llvmlite.LLVMModule* = trans.Module
|
||||
if pool is None or builder is None or mod is None:
|
||||
return 0
|
||||
items: list[ast.AST | t.CPtr] | t.CPtr = wt.items
|
||||
items: list[ast.AST*]* = wt.items
|
||||
if items is None:
|
||||
return 0
|
||||
n: t.CSizeT = len(items)
|
||||
n: sizet = len(items)
|
||||
|
||||
# 保存外层 __with_ctx(嵌套 with 时退出后恢复)
|
||||
old_ctx_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||||
trans.SymTab, "__with_ctx")
|
||||
old_ctx_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, "__with_ctx")
|
||||
|
||||
# 记录每个 item 的类名(__exit__ 调用时设置 __with_ctx 类型用)
|
||||
ctx_class_buf: t.CSizeT | t.CPtr = pool.alloc(8 * n)
|
||||
ctx_class_buf: sizet* = pool.alloc(8 * n)
|
||||
if ctx_class_buf is None:
|
||||
return 0
|
||||
string.memset(ctx_class_buf, 0, 8 * n)
|
||||
|
||||
# 1. 全部 item:构造 context 对象 + 调用 __enter__ + asname 绑定
|
||||
for i in range(n):
|
||||
item_node: ast.AST | t.CPtr = items.get(i)
|
||||
item_node: ast.AST* = items.get(i)
|
||||
if item_node is None:
|
||||
continue
|
||||
if item_node.kind() != ast.ASTKind.WithItem:
|
||||
continue
|
||||
item: ast.WithItem | t.CPtr = (ast.WithItem | t.CPtr)(item_node)
|
||||
item: rawptr[ast.WithItem] = rawptr[ast.WithItem](item_node)
|
||||
if item is None or item.context_expr is None:
|
||||
continue
|
||||
# 翻译 context_expr(对象构造,如 MemPool(arena, 4096))
|
||||
ctx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, item.context_expr,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
ctx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, item.context_expr, trans._funcs, trans._func_count, trans)
|
||||
if ctx_val is None:
|
||||
continue
|
||||
# 提取类名(注解类名,Attribute 时带模块前缀,如 "memhub.MemPool"——
|
||||
# 与 AnnAssign 的 extract_class_name_from_annotation 一致,跨模块
|
||||
# 方法调用靠 AnnotClassName 回退按模块名查 SHA1)
|
||||
cls_name: str = None
|
||||
ce: ast.AST | t.CPtr = item.context_expr
|
||||
ce: ast.AST* = item.context_expr
|
||||
if ce.kind() == ast.ASTKind.Call:
|
||||
cfn: ast.AST | t.CPtr = ((ast.Call | t.CPtr)(ce)).func
|
||||
cfn: ast.AST* = (ast.Call*(ce)).func
|
||||
if cfn is not None:
|
||||
if cfn.kind() == ast.ASTKind.Attribute:
|
||||
ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cfn)
|
||||
ca: ast.Attribute* = ast.Attribute*(cfn)
|
||||
if ca.value is not None and ca.value.kind() == ast.ASTKind.Name:
|
||||
cmn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value)
|
||||
cmn: ast.Name* = ast.Name*(ca.value)
|
||||
if cmn.id is not None:
|
||||
ml2: t.CSizeT = string.strlen(cmn.id) + string.strlen(ca.attr) + 2
|
||||
ml2: sizet = string.strlen(cmn.id) + string.strlen(ca.attr) + 2
|
||||
mbuf: str = pool.alloc(ml2)
|
||||
if mbuf is not None:
|
||||
viperlib.snprintf(mbuf, ml2, "%s.%s", cmn.id, ca.attr)
|
||||
@@ -653,39 +619,34 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
if cls_name is None:
|
||||
cls_name = ca.attr
|
||||
elif cfn.kind() == ast.ASTKind.Name:
|
||||
cls_name = ((ast.Name | t.CPtr)(cfn)).id
|
||||
cls_name = (ast.Name*(cfn)).id
|
||||
# context 对象存入 __with_ctx(方法调用解析 self 用)
|
||||
ctx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(
|
||||
builder, ctx_val.Ty)
|
||||
ctx_alloca: llvmlite.Value* = llvmlite.build_alloca(builder, ctx_val.Ty)
|
||||
if ctx_alloca is None:
|
||||
continue
|
||||
llvmlite.build_store(builder, ctx_val, ctx_alloca)
|
||||
self.Gen.VarGen.define_var(trans.SymTab, "__with_ctx", ctx_alloca)
|
||||
if cls_name is not None:
|
||||
self.Gen.VarGen.set_var_annot_class_name(
|
||||
trans.SymTab, "__with_ctx", cls_name)
|
||||
ctx_class_buf[i] = t.CSizeT(cls_name)
|
||||
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, "__with_ctx", cls_name)
|
||||
ctx_class_buf[i] = sizet(cls_name)
|
||||
# 调用 __enter__()
|
||||
enter_val: llvmlite.Value | t.CPtr = self._with_ctx_call(
|
||||
trans, pool, builder, mod, "__enter__")
|
||||
enter_val: llvmlite.Value* = self._with_ctx_call(trans, pool, builder, mod, "__enter__")
|
||||
# asname 绑定(__enter__ 返回值,缺失时退回 context 对象)
|
||||
if item.optional_vars is not None:
|
||||
ov: ast.AST | t.CPtr = item.optional_vars
|
||||
ov: ast.AST* = item.optional_vars
|
||||
if ov.kind() == ast.ASTKind.Name:
|
||||
asname: str = ((ast.Name | t.CPtr)(ov)).id
|
||||
asname: str = (ast.Name*(ov)).id
|
||||
if asname is not None:
|
||||
bind_val: llvmlite.Value | t.CPtr = enter_val
|
||||
bind_val: llvmlite.Value* = enter_val
|
||||
if bind_val is None:
|
||||
bind_val = ctx_val
|
||||
if bind_val is not None:
|
||||
asn_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(
|
||||
builder, bind_val.Ty)
|
||||
asn_alloca: llvmlite.Value* = llvmlite.build_alloca(builder, bind_val.Ty)
|
||||
if asn_alloca is not None:
|
||||
llvmlite.build_store(builder, bind_val, asn_alloca)
|
||||
self.Gen.VarGen.define_var(trans.SymTab, asname, asn_alloca)
|
||||
if cls_name is not None:
|
||||
self.Gen.VarGen.set_var_annot_class_name(
|
||||
trans.SymTab, asname, cls_name)
|
||||
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, asname, cls_name)
|
||||
# FakeDuck: __provides__ 元数据 → 生成 _push_provider 调用
|
||||
# (对齐 TPC HandlesWith.py L138-159;经 gen 单例委托 CallGenMixin。
|
||||
# 类名去模块前缀后查 __provides__ 表,如 memhub.MemBuddy → MemBuddy)
|
||||
@@ -695,15 +656,14 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
if fd_dot is not None:
|
||||
fd_cls_bare = fd_dot + 1
|
||||
if fd_cls_bare is not None:
|
||||
self.Gen.CallGenFd._emit_provider_push(
|
||||
trans, pool, builder, mod, fd_cls_bare, ctx_val)
|
||||
self.Gen.CallGenFd._emit_provider_push(trans, pool, builder, mod, fd_cls_bare, ctx_val)
|
||||
|
||||
# 2. 翻译 body
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = wt.children
|
||||
body: list[ast.AST*]* = wt.children
|
||||
if body is not None:
|
||||
bn: t.CSizeT = len(body)
|
||||
bn: sizet = len(body)
|
||||
for bi in range(bn):
|
||||
st: ast.AST | t.CPtr = body.get(bi)
|
||||
st: ast.AST* = body.get(bi)
|
||||
if st is not None:
|
||||
self.translate_stmt(trans, st)
|
||||
|
||||
@@ -711,23 +671,21 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
# (对齐 TPC HandlesWith.py L167-174;逆序弹栈,经 gen 单例委托)
|
||||
for pi_pop in range(n):
|
||||
if ctx_class_buf[pi_pop] != 0:
|
||||
cls_pop: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[pi_pop], t.CPtr))
|
||||
cls_pop: str = rawptr(ctx_class_buf[pi_pop])
|
||||
fd_cls_bare_p: str = cls_pop
|
||||
if cls_pop is not None:
|
||||
fd_dot_p: str = string.strrchr(cls_pop, '.')
|
||||
if fd_dot_p is not None:
|
||||
fd_cls_bare_p = fd_dot_p + 1
|
||||
if fd_cls_bare_p is not None:
|
||||
self.Gen.CallGenFd._emit_provider_pop(
|
||||
trans, pool, builder, mod, fd_cls_bare_p)
|
||||
self.Gen.CallGenFd._emit_provider_pop(trans, pool, builder, mod, fd_cls_bare_p)
|
||||
|
||||
# 3. 逆序调用 __exit__()(Python with 语义:后进先出)
|
||||
for i in range(n):
|
||||
ci: int = n - 1 - i
|
||||
if ctx_class_buf[ci] != 0:
|
||||
cls_ci: str = (str | t.CPtr)(t.CVoid(ctx_class_buf[ci], t.CPtr))
|
||||
self.Gen.VarGen.set_var_annot_class_name(
|
||||
trans.SymTab, "__with_ctx", cls_ci)
|
||||
cls_ci: str = rawptr(ctx_class_buf[ci])
|
||||
self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, "__with_ctx", cls_ci)
|
||||
self._with_ctx_call(trans, pool, builder, mod, "__exit__")
|
||||
|
||||
# 4. 恢复外层 __with_ctx
|
||||
@@ -735,24 +693,17 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
|
||||
self.Gen.VarGen.define_var(trans.SymTab, "__with_ctx", old_ctx_alloca)
|
||||
return 0
|
||||
|
||||
def _with_ctx_call(self, trans: HT.Translator | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
method_name: str) -> llvmlite.Value | t.CPtr:
|
||||
def _with_ctx_call(self, trans: HT.Translator*,
|
||||
pool: memhub.MemBuddy*,
|
||||
builder: llvmlite.IRBuilder*,
|
||||
mod: llvmlite.LLVMModule*,
|
||||
method_name: str) -> llvmlite.Value*:
|
||||
"""构造并翻译 __with_ctx.<method_name>() 调用(__enter__/__exit__)"""
|
||||
if pool is None or method_name is None:
|
||||
return None
|
||||
name_node: ast.AST | t.CPtr = ast.Name(pool, "__with_ctx", ast.ASTCtx.Load)
|
||||
if name_node is None:
|
||||
return None
|
||||
attr_node: ast.AST | t.CPtr = ast.Attribute(
|
||||
pool, name_node, method_name, ast.ASTCtx.Load)
|
||||
if attr_node is None:
|
||||
return None
|
||||
call_node: ast.AST | t.CPtr = ast.Call(pool, attr_node, None, None)
|
||||
if call_node is None:
|
||||
return None
|
||||
return self.Gen.ExprGen.translate_value(
|
||||
builder, pool, mod, call_node,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if pool is None or method_name is None: return None
|
||||
name_node: ast.AST* = ast.Name(pool, "__with_ctx", ast.ASTCtx.Load)
|
||||
if name_node is None: return None
|
||||
attr_node: ast.AST* = ast.Attribute(pool, name_node, method_name, ast.ASTCtx.Load)
|
||||
if attr_node is None: return None
|
||||
call_node: ast.AST* = ast.Call(pool, attr_node, None, None)
|
||||
if call_node is None: return None
|
||||
return self.Gen.ExprGen.translate_value(builder, pool, mod, call_node, trans._funcs, trans._func_count, trans)
|
||||
+1240
-492
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,298 @@
|
||||
import lib.core.Gen.Type.TypeGenMixin as TypeGenMixin
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import hashtable
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
# TypeSpec 模块导入别名用 TSpec(模块内类名也叫 TypeSpec,别名同名会被解析器
|
||||
# 当成"类 TypeSpec 的静态方法",导致跨模块调用被 mangled 成 <sha1>.TypeSpec.<fn>
|
||||
# 并隐式补 self 实参 → undefined symbol)。
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenBase - 类型表基础设施:字段 + InitTypeGen + trace/临时目录/generic 上下文
|
||||
# ============================================================
|
||||
novirtual class TypeGenBase:
|
||||
"""字段 + InitTypeGen + trace/临时目录/generic 上下文"""
|
||||
|
||||
# --- 仿 Python Traceback 调用栈(原 _g_trace_frames/_g_trace_count) ---
|
||||
Gen: Generator.Generator*
|
||||
TraceFrames: rawptr[GenTypes.TraceFrame] # malloc 数组(TypeGenMixin.TRACE_MAX 槽)
|
||||
TraceCount: int
|
||||
|
||||
# --- 全局泛型特化上下文(原 _g_generic_tp_names/_g_generic_type_args) ---
|
||||
GenericTpNames: list[str]*
|
||||
GenericTypeArgs: list[str]*
|
||||
# 嵌套安全栈:set_generic_context 压入外层值,clear_generic_context 弹出
|
||||
# 恢复(原单槽赋值:嵌套特化/泛型函数翻译退出时把外层上下文清成 None →
|
||||
# 外层方法体后续的 T 替换丢失 → T.__sizeof__() NameError,VectorGenericTest
|
||||
# 特化 Vector[int].__init__ 回归根因)。
|
||||
GenericCtxStack: sizet* # i64* 固定数组:每层 2 个槽(tp_names, type_args 指针)
|
||||
GenericCtxDepth: int
|
||||
|
||||
# --- 全局 CDefine 编译期常量表(原 _g_cdefine_*) ---
|
||||
CDefineNames: list[str]*
|
||||
CDefineValues: list[str]*
|
||||
CDefineDoubleFlags: list[int] | t.CPtr
|
||||
CDefineStrFlags: list[int] | t.CPtr # 1=字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2")
|
||||
CDefineIsDouble: int
|
||||
CDefineIsStr: int
|
||||
CDefineFound: int
|
||||
# --- CDefine 名 → 槽下标 索引(开放寻址 | 线性探测;槽存 index+1,0=空槽) ---
|
||||
# 与 CDefineNames 同池分配、同 clear_cdefine_constants 复位;CDefineNames 只
|
||||
# 追加不重排 ⇒ 存槽下标稳定;Built == len(CDefineNames) 才可信,不可信/未命中
|
||||
# 一律回退线性扫描(正确性保证)。
|
||||
CDefineNameIdx: sizet*
|
||||
CDefineNameIdxCap: int
|
||||
CDefineNameIdxBuilt: int
|
||||
|
||||
# --- 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用) ---
|
||||
# 缓存 reset_to(mark2)/clear_cdefine_constants 不清除 → 跨文件复用,
|
||||
# CONST_INT 递归查找只做一次。
|
||||
XmodCdefNames: list[str]*
|
||||
XmodCdefValues: list[str]*
|
||||
XmodCdefDoubleFlags: list[int] | t.CPtr
|
||||
XmodCdefStrFlags: list[int] | t.CPtr
|
||||
|
||||
# --- 当前模块 SHA1(原 _g_current_module_sha1) ---
|
||||
CurrentModuleSha1: str
|
||||
|
||||
# --- 全局 CTypedef 表(原 _g_ctypedef_*) ---
|
||||
CTypedefNames: list[str]*
|
||||
CTypedefTypeStrs: list[str]*
|
||||
CTypedefFound: int
|
||||
# CTypedef 名 → 槽下标 索引(开放寻址 | 线性探测;槽存 index+1,0=空槽)。
|
||||
# 与 CTypedefNames 同池分配、同 clear_ctypedefs 复位;CTypedefNames 只追加
|
||||
# 不重排(同名注册原地更新类型串)⇒ 存槽下标稳定;Built == len(CTypedefNames)
|
||||
# 才可信,不可信/未命中一律回退线性扫描(正确性保证)。
|
||||
CTypedefNameIdx: sizet*
|
||||
CTypedefNameIdxCap: int
|
||||
CTypedefNameIdxBuilt: int
|
||||
CTypedefResolveDepth: int
|
||||
CTypedefVisiting: list[str]*
|
||||
# builtins 源扫描标记:注解解析"最后匹配"兜底(_lookup_builtins_typedef)
|
||||
# 每文件最多读一次 includes/builtins.vp;随 clear_ctypedefs 复位
|
||||
BuiltinsTypedefScanned: int
|
||||
# builtins 最后匹配诊断("变量类型注解解析失败"详细报错用):
|
||||
# LastBuiltinsTypedefName = 最后一次请求的名称;LastBuiltinsTypedefResult =
|
||||
# 展开后的类型表达式(未命中 = None)。随 clear_ctypedefs 复位。
|
||||
# 两个被指串由以下自有缓冲承载(stdlib.malloc,clear_ctypedefs 释放):
|
||||
# 调用方常传临时缓冲(VpiReader._resolve_single_vpi_type_str 的段缓冲
|
||||
# malloc 后立刻 free),直接存指针会悬垂 → _build_ann_fail_msg 的
|
||||
# snprintf 读已释放内存(ASan heap-use-after-free)。
|
||||
LastBuiltinsTypedefName: str
|
||||
LastBuiltinsTypedefResult: str
|
||||
LastBuiltinsTypedefNameBuf: bytes
|
||||
LastBuiltinsTypedefResultBuf: bytes
|
||||
# builtins import 别名缓冲(stdlib.malloc,格式 "alias\0target\0" 连续段):
|
||||
# _lookup_builtins_typedef 扫描 builtins.vp import 行填充;库 typedef 模块限定
|
||||
# 引用按别名还原真实模块名(__stdint.size_t → stdint.size_t)。
|
||||
# 用 malloc 而非 pool list——pool 每文件 reset_to 后 list 悬空;malloc 跨 pool
|
||||
# 生命周期存活,clear_ctypedefs 释放置空。
|
||||
ImportAliasBuf: bytes
|
||||
|
||||
# --- 库 typedef 按模块一次性门禁(_lookup_library_typedef 性能优化) ---
|
||||
# 库模块 typedef 缓存(PermPool 永久分配,跨文件/Phase 存活):
|
||||
# LibTypedefScannedMods: key=库模块名 → 已扫描标记(命中=该模块源已读并入缓存);
|
||||
# LibTypedefTypeMap: key="模块名|typedef 名" → 源中原始类型表达式。
|
||||
# 每次查询都读 64KB 库源全文扫描会使单文件 translate 耗时 7–12s;库源单次编译内
|
||||
# 不变,故缓存命中结果与逐次读源等价。
|
||||
LibTypedefScannedMods: hashtable.HashTable*
|
||||
LibTypedefTypeMap: hashtable.HashTable*
|
||||
|
||||
# --- 常量整数表达式计算成功标志(原 _g_const_eval_ok) ---
|
||||
ConstEvalOk: int
|
||||
|
||||
# --- 全局当前文件名(原 _g_current_filename) ---
|
||||
CurrentFile: str
|
||||
|
||||
# --- TypeSpec 驻留表(统一类型描述符,Debugger/_Type.md 第 6 节) ---
|
||||
# 惰性创建(ensure_spec_arena);由类型子系统自身持有,避免模块级全局表。
|
||||
# 实例与内部数组均 PermPool 分配 ⇒ 跨文件/跨 mark 存活。
|
||||
Specs: TSpec.TypeSpecArena*
|
||||
def InitTypeGen(self) -> int:
|
||||
"""初始化类型 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)"""
|
||||
if self is None: return 1
|
||||
self.TraceFrames = None
|
||||
self.TraceCount = 0
|
||||
self.GenericTpNames = None
|
||||
self.GenericTypeArgs = None
|
||||
self.GenericCtxStack = None
|
||||
self.GenericCtxDepth = 0
|
||||
self.CDefineNames = None
|
||||
self.CDefineValues = None
|
||||
self.CDefineDoubleFlags = None
|
||||
self.CDefineStrFlags = None
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
self.CDefineFound = 0
|
||||
self.CDefineNameIdx = None
|
||||
self.CDefineNameIdxCap = 0
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
self.XmodCdefNames = None
|
||||
self.XmodCdefValues = None
|
||||
self.XmodCdefDoubleFlags = None
|
||||
self.XmodCdefStrFlags = None
|
||||
self.CurrentModuleSha1 = None
|
||||
self.CTypedefNames = None
|
||||
self.CTypedefTypeStrs = None
|
||||
self.CTypedefFound = 0
|
||||
self.CTypedefNameIdx = None
|
||||
self.CTypedefNameIdxCap = 0
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
self.CTypedefResolveDepth = 0
|
||||
self.CTypedefVisiting = None
|
||||
self.BuiltinsTypedefScanned = 0
|
||||
self.LastBuiltinsTypedefName = None
|
||||
self.LastBuiltinsTypedefResult = None
|
||||
self.LastBuiltinsTypedefNameBuf = None
|
||||
self.LastBuiltinsTypedefResultBuf = None
|
||||
self.ImportAliasBuf = None
|
||||
# 库 typedef 持久缓存字段(不随 clear_ctypedefs 复位 → 跨文件/Phase 存活)
|
||||
self.LibTypedefScannedMods = None
|
||||
self.LibTypedefTypeMap = None
|
||||
self.ConstEvalOk = 0
|
||||
self.CurrentFile = None
|
||||
self.Specs = None
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# ensure_spec_arena - 惰性创建 TypeSpec 驻留表(幂等)
|
||||
#
|
||||
# 用 PermPool 分配 arena 本体;表内部缓冲由 TSpec.SpecArenaInit 分配
|
||||
# (同样 PermPool)。失败返回 None(调用方按 fail-fast 处理,不静默退化)。
|
||||
# ============================================================
|
||||
def ensure_spec_arena(self) -> TSpec.TypeSpecArena*:
|
||||
"""确保 TypeSpec 驻留表已创建,返回 arena;失败返回 None"""
|
||||
if self.Specs is not None: return self.Specs
|
||||
size: sizet = TSpec.TypeSpecArena.__sizeof__()
|
||||
arena: TSpec.TypeSpecArena* = TSpec.TypeSpecArena*(CompilerFactory.factory.PermPool.alloc(size))
|
||||
if arena is None: return None
|
||||
string.memset(arena, 0, size)
|
||||
if TSpec.SpecArenaInit(arena, 0) != 0: return None
|
||||
self.Specs = arena
|
||||
return arena
|
||||
# ============================================================
|
||||
# P2 迁移方法(函数体来自 HandlesType.vp,全局变量改 self.字段,
|
||||
# 同模块函数调用改 self.方法;签名与 HandlesType 原函数一致)
|
||||
# ============================================================
|
||||
|
||||
def _ensure_trace_init(self) -> int:
|
||||
"""确保调用栈已初始化(懒加载,用 malloc 不依赖 pool)"""
|
||||
if self.TraceFrames is not None: return 1
|
||||
entry_size: sizet = GenTypes.TraceFrame.__sizeof__()
|
||||
self.TraceFrames = CompilerFactory.factory.PermPool.alloc(entry_size * TypeGenMixin.TRACE_MAX)
|
||||
if self.TraceFrames is None: return 0
|
||||
string.memset(self.TraceFrames, 0, entry_size * TypeGenMixin.TRACE_MAX)
|
||||
return 1
|
||||
def _get_trace_frame(self, i: int) -> rawptr[GenTypes.TraceFrame]:
|
||||
"""获取第 i 个 TraceFrame 槽位"""
|
||||
if self.TraceFrames is None or i < 0 or i >= TypeGenMixin.TRACE_MAX: return None
|
||||
entry_size: sizet = GenTypes.TraceFrame.__sizeof__()
|
||||
addr: uint64 = uint64(self.TraceFrames) + i * entry_size
|
||||
return rawptr[GenTypes.TraceFrame](addr)
|
||||
def push_trace(self, file_name: str, lineno: int, col_start: int = 0, col_end: int = 0) -> None:
|
||||
"""压入一个翻译上下文帧(进入新的翻译作用域时调用)"""
|
||||
if self._ensure_trace_init() == 0: return
|
||||
if self.TraceCount >= TypeGenMixin.TRACE_MAX: return
|
||||
frame: rawptr[GenTypes.TraceFrame] = self._get_trace_frame(self.TraceCount)
|
||||
if frame is None: return
|
||||
frame.file_name = file_name
|
||||
frame.lineno = lineno
|
||||
frame.col_start = col_start
|
||||
frame.col_end = col_end
|
||||
self.TraceCount += 1
|
||||
def pop_trace(self) -> None:
|
||||
"""弹出栈顶帧(退出翻译作用域时调用)"""
|
||||
if self.TraceCount <= 0: return
|
||||
self.TraceCount -= 1
|
||||
frame: rawptr[GenTypes.TraceFrame] = self._get_trace_frame(self.TraceCount)
|
||||
if frame is not None:
|
||||
frame.file_name = None
|
||||
frame.lineno = 0
|
||||
frame.col_start = 0
|
||||
frame.col_end = 0
|
||||
def clear_trace(self) -> None:
|
||||
"""清空调用栈(每个文件翻译开始前调用)"""
|
||||
for i in range(self.TraceCount):
|
||||
frame: rawptr[GenTypes.TraceFrame] = self._get_trace_frame(i)
|
||||
if frame is not None:
|
||||
frame.file_name = None
|
||||
frame.lineno = 0
|
||||
frame.col_start = 0
|
||||
frame.col_end = 0
|
||||
self.TraceCount = 0
|
||||
def set_temp_dir(self, temp_dir: str) -> None:
|
||||
"""设置全局 temp_dir(统一写入 CallGenBase.TempDir,跨子对象经 Gen 指针)"""
|
||||
self.Gen.CallGenBase.SetTempDir(temp_dir)
|
||||
def get_temp_dir(self) -> str:
|
||||
"""获取全局 temp_dir(从 CallGenBase 读取)"""
|
||||
return self.Gen.CallGenBase.TempDir
|
||||
def set_current_module_sha1(self, sha1: str) -> None:
|
||||
"""设置当前正在编译的模块 SHA1(Phase1 在模块开始翻译前调用)"""
|
||||
self.CurrentModuleSha1 = sha1
|
||||
def _dbg_check_ast_floats(self, mb: memhub.MemBuddy*,
|
||||
tree: ast.AST*, tag: str):
|
||||
"""已移除调试插桩(占位保留签名,避免外部调用引用失败)"""
|
||||
pass
|
||||
def set_generic_context(self, tp_names: list[str]*,
|
||||
type_args: list[str]*):
|
||||
"""设置泛型特化上下文(进入泛型类方法体翻译时调用),嵌套安全
|
||||
|
||||
先压栈当前(外层)上下文,再设置新值。clear_generic_context 弹出恢复,
|
||||
避免嵌套特化/泛型函数翻译退出时清空外层上下文(T.__sizeof__() 回归根因)。
|
||||
"""
|
||||
if self.GenericCtxStack is None:
|
||||
self.GenericCtxStack = stdlib.malloc(8 * 2 * 32)
|
||||
if self.GenericCtxStack is None:
|
||||
self.GenericTpNames = tp_names
|
||||
self.GenericTypeArgs = type_args
|
||||
return
|
||||
self.GenericCtxDepth = 0
|
||||
if self.GenericCtxDepth < 32:
|
||||
self.GenericCtxStack[self.GenericCtxDepth * 2] = sizet(self.GenericTpNames)
|
||||
self.GenericCtxStack[self.GenericCtxDepth * 2 + 1] = sizet(self.GenericTypeArgs)
|
||||
self.GenericCtxDepth += 1
|
||||
self.GenericTpNames = tp_names
|
||||
self.GenericTypeArgs = type_args
|
||||
|
||||
def clear_generic_context(self):
|
||||
"""清除泛型特化上下文(离开泛型类方法体翻译时调用),恢复外层而非置 None"""
|
||||
if self.GenericCtxDepth > 0:
|
||||
self.GenericCtxDepth -= 1
|
||||
self.GenericTpNames = (list[str]*)(self.GenericCtxStack[self.GenericCtxDepth * 2])
|
||||
self.GenericTypeArgs = (list[str]*)(self.GenericCtxStack[self.GenericCtxDepth * 2 + 1])
|
||||
else:
|
||||
self.GenericTpNames = None
|
||||
self.GenericTypeArgs = None
|
||||
def resolve_generic_type_name(self, name: str) -> str:
|
||||
"""如果 name 是泛型类型参数,返回对应的具体类型名;否则返回 name 本身
|
||||
|
||||
用于表达式中的 T 替换(如 T.__sizeof__() → int.__sizeof__())
|
||||
"""
|
||||
if name is None:
|
||||
return name
|
||||
rv_d: str = name
|
||||
if self.GenericTpNames is not None and self.GenericTypeArgs is not None:
|
||||
rg_n: sizet = len(self.GenericTpNames)
|
||||
rg_i: sizet
|
||||
for rg_i in range(rg_n):
|
||||
rg_tpn: str = self.GenericTpNames.get(rg_i)
|
||||
if rg_tpn is not None and string.strcmp(name, rg_tpn) == 0:
|
||||
rg_ta: str = self.GenericTypeArgs.get(rg_i)
|
||||
if rg_ta is not None:
|
||||
rv_d = rg_ta
|
||||
break
|
||||
return rv_d
|
||||
@@ -0,0 +1,550 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
|
||||
# ============================================================
|
||||
# CDefine 名索引(名 → 槽下标,开放寻址 | 线性探测)
|
||||
#
|
||||
# 槽数 = 4096(2 的幂;负载 < 0.5 上限 2048 条,超限标记不可信回退线性扫描)。
|
||||
# 槽存槽下标 + 1(0=空槽)。CDefineNames 只追加不重排 ⇒ 槽下标稳定;
|
||||
# Built == len(CDefineNames) 才可信。
|
||||
# ============================================================
|
||||
define CDEFINE_IDX_CAP = 4096
|
||||
# 索引哈希常量(32 位 FNV-1a)
|
||||
define CDEF_IDX_FNV_OFFSET = 2166136261
|
||||
define CDEF_IDX_FNV_PRIME = 16777619
|
||||
define CDEF_IDX_FNV_MASK = 4294967295
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenCDef - TypeGenMixin 拆分(阶段 D):CDefine 编译期常量表(register/lookup/is/set/clear)
|
||||
# ============================================================
|
||||
novirtual class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
"""CDefine 编译期常量表(register/lookup/is/set/clear)"""
|
||||
|
||||
# ============================================================
|
||||
# CDefine 名索引(开放寻址;槽存 index+1,0=空槽)
|
||||
# ============================================================
|
||||
def _cdef_idx_hash(self, name: str) -> uint64:
|
||||
"""名 → 64 位哈希(32 位 FNV-1a,逐字节到 NUL 结束)"""
|
||||
h: uint64 = uint64(CDEF_IDX_FNV_OFFSET)
|
||||
if name is None:
|
||||
return h
|
||||
i: sizet = 0
|
||||
while name[i] != '\0':
|
||||
h = (h ^ uint64(int(name[i]))) * uint64(CDEF_IDX_FNV_PRIME)
|
||||
h = h & uint64(CDEF_IDX_FNV_MASK)
|
||||
i += 1
|
||||
return h
|
||||
|
||||
def _cdef_idx_slot(self, si: sizet) -> sizet*:
|
||||
"""取索引第 si 个槽(8 字节,存槽下标+1;0=空槽)"""
|
||||
return (sizet*)(uint64(self.CDefineNameIdx) + uint64(si) * 8)
|
||||
|
||||
def _cdef_idx_init(self, pool: memhub.MemBuddy*) -> None:
|
||||
"""创建/清零名索引(与 CDefineNames 同池);失败则标记不可信"""
|
||||
idx: sizet* = pool.alloc(sizet(CDEFINE_IDX_CAP) * 8)
|
||||
if idx is None:
|
||||
self.CDefineNameIdx = None
|
||||
self.CDefineNameIdxCap = 0
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
return
|
||||
string.memset(idx, 0, sizet(CDEFINE_IDX_CAP) * 8)
|
||||
self.CDefineNameIdx = idx
|
||||
self.CDefineNameIdxCap = CDEFINE_IDX_CAP
|
||||
self.CDefineNameIdxBuilt = 0
|
||||
|
||||
def _cdef_idx_find(self, name: str) -> int:
|
||||
"""在名索引中探测 name,返回命中槽下标(>=0);未命中/不可用返回 -1"""
|
||||
if self.CDefineNameIdx is None or self.CDefineNameIdxCap <= 0 or name is None:
|
||||
return -1
|
||||
if self.CDefineNameIdxBuilt != int(len(self.CDefineNames)):
|
||||
return -1
|
||||
h: uint64 = self._cdef_idx_hash(name)
|
||||
mask: sizet = sizet(self.CDefineNameIdxCap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < self.CDefineNameIdxCap:
|
||||
slot: sizet* = self._cdef_idx_slot(si)
|
||||
sv: sizet = slot[0]
|
||||
if sv == 0:
|
||||
return -1
|
||||
se: int = int(sv) - 1
|
||||
nm: str = self.CDefineNames.get(sizet(se))
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
return se
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
def _cdef_idx_insert(self, slot_index: int, name: str) -> int:
|
||||
"""把 (name → slot_index) 记入索引;0=成功 / 1=失败"""
|
||||
if self.CDefineNameIdx is None or self.CDefineNameIdxCap <= 0 or name is None:
|
||||
return 1
|
||||
h: uint64 = self._cdef_idx_hash(name)
|
||||
mask: sizet = sizet(self.CDefineNameIdxCap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < self.CDefineNameIdxCap:
|
||||
slot: sizet* = self._cdef_idx_slot(si)
|
||||
if slot[0] == 0:
|
||||
slot[0] = sizet(slot_index + 1)
|
||||
return 0
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return 1
|
||||
|
||||
def _cdef_idx_sync_append(self, name: str) -> None:
|
||||
"""CDefineNames.append 后同步索引(槽下标 = len-1);不可信则保持不可信"""
|
||||
n: int = int(len(self.CDefineNames))
|
||||
if self.CDefineNameIdxBuilt == n - 1 and self._cdef_idx_insert(n - 1, name) == 0:
|
||||
self.CDefineNameIdxBuilt = n
|
||||
else:
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
|
||||
# ============================================================
|
||||
# CDefine 表本体的池归一
|
||||
#
|
||||
# 表指针挂在**进程级单例** _g_gen.TypeGenCDef 上,不在任何 pool 的管辖
|
||||
# 范围内;而调用方传进来的 pool 在翻译期是「每文件 reset_to 回收」的瞬时池
|
||||
# (Phase1 1a/1b、Phase2 PhaseA、StubMerger 扫描、Repl 每片段都按 mark/reset
|
||||
# 轮转)。表本体若落在该池:reset 之后表指针**悬空但非 None** ⇒ `is None`
|
||||
# 守卫失效 ⇒ 下一次 register_cdefine_* 的 append 写进已回收内存(堆损坏;
|
||||
# 检测模式下该区被 free 填成 0xCD ⇒ append 的接收者 = 0xcdcdcdcdcdcdcdcd)。
|
||||
# 故表本体(四个 list + 名索引)一律落 PermPool(进程级永久池,从不 reset),
|
||||
# 与"文件级/片段级 reset"彻底解耦。
|
||||
# PermPool 不可用(无 CompilerFactory.factory 的极简单元程序)时退回入参
|
||||
# pool —— 与既有语义一致,只是不再有"表本体跨 reset 存活"的隐式假设。
|
||||
# ============================================================
|
||||
def _cdefine_table_pool(self,
|
||||
pool: memhub.MemBuddy*) -> memhub.MemBuddy*:
|
||||
"""CDefine 表本体的池:恒取 PermPool(不可用则退回入参 pool)"""
|
||||
if CompilerFactory.factory is not None \
|
||||
and CompilerFactory.factory.PermPool is not None:
|
||||
return CompilerFactory.factory.PermPool
|
||||
return pool
|
||||
|
||||
def register_cdefine_constant(self, pool: memhub.MemBuddy*,
|
||||
name: str, value: int64) -> None:
|
||||
"""注册 CDefine 编译期常量到本地表
|
||||
|
||||
值以十进制字符串存储(64 位 %lld)。大整数 CDefine(如
|
||||
sys.maxsize = 9223372036854775807)必须全精度保存,否则 %d 32 位截断
|
||||
成 -1(0xFFFFFFFF)→ 读回 4294967295(SysLibTest maxsize FAIL 根因)。
|
||||
0xFFFFFFFF 仍存为 "4294967295",常量生成端 const_int32 内部截断回 -1。
|
||||
|
||||
名称深拷贝到 pool(与 register_xmod_cdefine 对 key 深拷贝同一教训):
|
||||
调用方传入的 name 可能指向临时缓冲——VpiReader 注入 .vpi 时 Name.id 是
|
||||
零拷贝指向 vpi_buf(见 ParseVpiIntoModule 的 token 零拷贝注释),而
|
||||
vpi_buf 在注入函数末尾即 stdlib.free。只存指针会让 CDefineNames 持有
|
||||
悬空名:之后 lookup 的 strcmp 若命中被回收/复用内存里恰好出现的同名文本,
|
||||
就会返回别的条目的值(Phase1.SHA1_LEN=17 被读成 0 的根因)。
|
||||
"""
|
||||
if name is None:
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
|
||||
tn: list[str]* = list[str](tp, 64)
|
||||
tv: list[str]* = list[str](tp, 64)
|
||||
td: list[int] | t.CPtr = list[int](tp, 64)
|
||||
tsf: list[int] | t.CPtr = list[int](tp, 64)
|
||||
# 建表失败(池不可用/耗尽)⇒ 明确报错并返回,绝不让下面的 append
|
||||
# 落到 None 或未初始化地址(原实现无检查 ⇒ append 写进 NULL/0xCD 区崩)
|
||||
if tn is None or tv is None or td is None or tsf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 表分配失败(表本体池不可用或耗尽)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
self._cdef_idx_init(tp)
|
||||
# 表就绪守卫:表本体缺失/半初始化(建表失败或外部置空)⇒ fail-fast,
|
||||
# 不写垃圾(append 之前必有非空断言)
|
||||
if self.CDefineNames is None or self.CDefineValues is None \
|
||||
or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 表未就绪(CDefineNames/Values/Flags 为空)", "MemoryError")
|
||||
return
|
||||
name_copy: str = pool.alloc(string.strlen(name) + 1)
|
||||
if name_copy is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(name_copy, name)
|
||||
self.CDefineNames.append(name_copy)
|
||||
self._cdef_idx_sync_append(name_copy)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
viperlib.snprintf(val_buf, 32, "%lld", value)
|
||||
self.CDefineValues.append(val_buf)
|
||||
else:
|
||||
self.CDefineValues.append("0")
|
||||
# fail-fast:CDefine 值缓冲区分配失败必须终止编译
|
||||
# (与浮点/字符串分支口径一致,不再静默写 "0" 污染常量表)
|
||||
if val_buf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine '{name}' 值缓冲区分配失败", "MemoryError")
|
||||
if self.CDefineDoubleFlags is not None:
|
||||
self.CDefineDoubleFlags.append(0)
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.append(0)
|
||||
def register_cdefine_double(self, pool: memhub.MemBuddy*,
|
||||
name: str, value: double) -> None:
|
||||
"""注册浮点 CDefine 编译期常量(如 U_M_PI: t.CDefine = 3.14159...)
|
||||
|
||||
值以 %f 文本存储并标记浮点,供 translate_value 返回浮点常量。
|
||||
|
||||
名称同样深拷贝到 pool(理由见 register_cdefine_constant:注入 .vpi 时
|
||||
Name.id 指向的 vpi_buf 会被释放,只存指针会留下悬空名)。
|
||||
"""
|
||||
if name is None:
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
|
||||
tn: list[str]* = list[str](tp, 64)
|
||||
tv: list[str]* = list[str](tp, 64)
|
||||
td: list[int] | t.CPtr = list[int](tp, 64)
|
||||
tsf: list[int] | t.CPtr = list[int](tp, 64)
|
||||
if tn is None or tv is None or td is None or tsf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 浮点表分配失败(表本体池不可用或耗尽)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
self._cdef_idx_init(tp)
|
||||
# 表就绪守卫(同 register_cdefine_constant):append 之前必有非空断言
|
||||
if self.CDefineNames is None or self.CDefineValues is None \
|
||||
or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 浮点表未就绪(CDefineNames/Values/Flags 为空)", "MemoryError")
|
||||
return
|
||||
name_copy_d: str = pool.alloc(string.strlen(name) + 1)
|
||||
if name_copy_d is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 浮点 '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(name_copy_d, name)
|
||||
self.CDefineNames.append(name_copy_d)
|
||||
self._cdef_idx_sync_append(name_copy_d)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
# 用 CRT stdio.snprintf 而非 viperlib.snprintf:viperlib 自实现格式化器的
|
||||
# %g 浮点路径有 bug(%.17g 输出错误值,如 pi 显示 3.1397985 而非 3.1415926,
|
||||
# 位模式 %a 正确),会导致 CDefine 表存错文本 → lookup 生成错 LLVM 常量。
|
||||
stdio.snprintf(val_buf, 32, "%.17g", value)
|
||||
self.CDefineValues.append(val_buf)
|
||||
else:
|
||||
self.CDefineValues.append("0")
|
||||
if self.CDefineDoubleFlags is not None:
|
||||
self.CDefineDoubleFlags.append(1)
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.append(0)
|
||||
# fail-fast:CDefine 值缓冲区分配失败必须终止编译,
|
||||
if val_buf is None:
|
||||
VLogger.error("CDefine 浮点值缓冲区分配失败", "CDEF-DBG")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 浮点值缓冲区分配失败", "MemoryError")
|
||||
def register_cdefine_string(self, pool: memhub.MemBuddy*,
|
||||
name: str, value: str) -> None:
|
||||
"""注册字符串 CDefine 编译期常量(如 ZLIB_VERSION: t.CDefine = "1.3.2")
|
||||
|
||||
字符串值深拷贝到 pool(AST 节点的 str_val 可能被 pool 操作覆写,
|
||||
与浮点 CDefine 的恢复同理)。名称同样深拷贝(理由见
|
||||
register_cdefine_constant:注入 .vpi 的 Name.id 指向会被释放的 vpi_buf)。
|
||||
"""
|
||||
if pool is None or name is None:
|
||||
return
|
||||
if value is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串值缺失: {name}", "InternalCompilerError")
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
tp: memhub.MemBuddy* = self._cdefine_table_pool(pool)
|
||||
tn: list[str]* = list[str](tp, 64)
|
||||
tv: list[str]* = list[str](tp, 64)
|
||||
td: list[int] | t.CPtr = list[int](tp, 64)
|
||||
tsf: list[int] | t.CPtr = list[int](tp, 64)
|
||||
if tn is None or tv is None or td is None or tsf is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 字符串表分配失败(表本体池不可用或耗尽)", "MemoryError")
|
||||
return
|
||||
self.CDefineNames = tn
|
||||
self.CDefineValues = tv
|
||||
self.CDefineDoubleFlags = td
|
||||
self.CDefineStrFlags = tsf
|
||||
self._cdef_idx_init(tp)
|
||||
# 表就绪守卫(同 register_cdefine_constant):append 之前必有非空断言
|
||||
if self.CDefineNames is None or self.CDefineValues is None \
|
||||
or self.CDefineDoubleFlags is None or self.CDefineStrFlags is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 字符串表未就绪(CDefineNames/Values/Flags 为空)", "MemoryError")
|
||||
return
|
||||
ncopy_s: str = pool.alloc(string.strlen(name) + 1)
|
||||
if ncopy_s is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串 '{name}' 名称缓冲区分配失败", "MemoryError")
|
||||
return
|
||||
string.strcpy(ncopy_s, name)
|
||||
self.CDefineNames.append(ncopy_s)
|
||||
self._cdef_idx_sync_append(ncopy_s)
|
||||
vlen: sizet = string.strlen(value)
|
||||
vcopy: str = pool.alloc(vlen + 1)
|
||||
if vcopy is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串值分配失败: {name}", "MemoryError")
|
||||
return
|
||||
string.strcpy(vcopy, value)
|
||||
self.CDefineValues.append(vcopy)
|
||||
if self.CDefineDoubleFlags is not None:
|
||||
self.CDefineDoubleFlags.append(0)
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.append(1)
|
||||
# 同步设置"最近注册/查表结果为字符串"标志(is_cdefine_str() 读取)。
|
||||
# 跨模块字符串 CDefine 读回只调本函数 + 尾部 set_cdefine_found;不设标志会让
|
||||
# 属性路径 is_cdefine_str()==0 → 退化为整数分支返回 0 → IR 生成 inttoptr i32 0
|
||||
# → 运行期按 NULL 字符串处理崩溃。
|
||||
self.CDefineIsStr = 1
|
||||
self.CDefineFound = 1
|
||||
# ============================================================
|
||||
# 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用)
|
||||
# ============================================================
|
||||
def register_xmod_cdefine(self, name: str, value_str: str,
|
||||
is_double: int, is_str: int) -> None:
|
||||
"""注册跨模块 CDefine 查找结果到 perm_pool 全局缓存(跨文件复用)
|
||||
|
||||
Args:
|
||||
name: CDefine 常量名(如 CONST_INT)
|
||||
value_str: 值文本(十进制/浮点/字符串)
|
||||
is_double: 1=浮点值
|
||||
is_str: 1=字符串值
|
||||
"""
|
||||
if name is None or value_str is None:
|
||||
return
|
||||
# 去重:同名已缓存则跳过(首次查找结果为准,CDefine 全局唯一约定)
|
||||
if self.XmodCdefNames is not None:
|
||||
x_n: sizet = len(self.XmodCdefNames)
|
||||
x_i: sizet
|
||||
for x_i in range(x_n):
|
||||
x_nm: str = self.XmodCdefNames.get(x_i)
|
||||
if x_nm is not None and string.strcmp(x_nm, name) == 0:
|
||||
return
|
||||
perm: memhub.MemBuddy* = CompilerFactory.factory.PermPool
|
||||
if self.XmodCdefNames is None:
|
||||
self.XmodCdefNames = list[str](perm, 64)
|
||||
self.XmodCdefValues = list[str](perm, 64)
|
||||
self.XmodCdefDoubleFlags = list[int](perm, 64)
|
||||
self.XmodCdefStrFlags = list[int](perm, 64)
|
||||
# key/value 深拷贝到 perm_pool:入参(pool.alloc 临时缓冲)在
|
||||
# reset_to(mark2) 后悬空,append 只存指针 → 必须深拷贝跨 reset 存活
|
||||
klen: sizet = string.strlen(name)
|
||||
kcopy: str = perm.alloc(klen + 1)
|
||||
if kcopy is None:
|
||||
return
|
||||
string.strcpy(kcopy, name)
|
||||
vlen: sizet = string.strlen(value_str)
|
||||
vcopy: str = perm.alloc(vlen + 1)
|
||||
if vcopy is None:
|
||||
return
|
||||
string.strcpy(vcopy, value_str)
|
||||
self.XmodCdefNames.append(kcopy)
|
||||
self.XmodCdefValues.append(vcopy)
|
||||
if self.XmodCdefDoubleFlags is not None:
|
||||
self.XmodCdefDoubleFlags.append(is_double)
|
||||
if self.XmodCdefStrFlags is not None:
|
||||
self.XmodCdefStrFlags.append(is_str)
|
||||
def lookup_xmod_cdefine(self, name: str) -> str:
|
||||
"""查找跨模块 CDefine 缓存,命中设置 found/is_double/is_str 标志
|
||||
|
||||
Returns:
|
||||
值文本(命中),未命中返回 None
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if name is None or self.XmodCdefNames is None:
|
||||
return None
|
||||
n: sizet = len(self.XmodCdefNames)
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
nm: str = self.XmodCdefNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.XmodCdefValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
if self.XmodCdefStrFlags is not None and self.XmodCdefStrFlags.get(i) == 1:
|
||||
self.CDefineIsStr = 1
|
||||
elif self.XmodCdefDoubleFlags is not None and self.XmodCdefDoubleFlags.get(i) == 1:
|
||||
self.CDefineIsDouble = 1
|
||||
return val_str
|
||||
return None
|
||||
def lookup_cdefine_constant(self, name: str) -> int64:
|
||||
"""查找 CDefine 编译期常量
|
||||
|
||||
返回找到的值(64 位,大整数 CDefine 如 sys.maxsize 全精度)。
|
||||
由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1),
|
||||
用全局 _g_cdefine_found 标志区分"未找到"和值为 -1。
|
||||
调用方应在调用后检查 _g_cdefine_found。
|
||||
浮点 CDefine 项返回整数部分(与 _g_cdefine_is_double 标志配合)。
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None:
|
||||
return 0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n | 查询名非空)时直接定位唯一候选下标
|
||||
# (= 原扫描首个命中)。CDefine 名注册后不再改写、每次注册都同步入索引
|
||||
# (失败即置 Built=-1)⇒ 可信时未命中即"确无",直接返回 0(= 原全表扫描
|
||||
# 结果);索引不可用时回退下方原全表线性扫描。
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) \
|
||||
and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0:
|
||||
return 0
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(cd_start, cd_end):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1:
|
||||
# 字符串 CDefine(如 ZLIB_VERSION="1.3.2"):整数查询路径
|
||||
# 标记 is_str,调用方改用 lookup_cdefine_string 取字符串。
|
||||
self.CDefineIsStr = 1
|
||||
return 0
|
||||
if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1:
|
||||
self.CDefineIsDouble = 1
|
||||
return string.atoll(val_str)
|
||||
return string.atoll(val_str)
|
||||
return 0
|
||||
def lookup_cdefine_double(self, name: str) -> double:
|
||||
"""查找 CDefine 编译期常量,返回 double 值(浮点/整数统一)
|
||||
|
||||
与 lookup_cdefine_constant 共享 _g_cdefine_found / _g_cdefine_is_double
|
||||
(found=1 且 is_double=1 → 浮点 CDefine,应返回浮点常量)。
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None:
|
||||
return 0.0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n | 查询名非空)时直接定位唯一候选下标
|
||||
# (= 原扫描首个命中)。CDefine 名注册后不再改写、每次注册都同步入索引
|
||||
# (失败即置 Built=-1)⇒ 可信时未命中即"确无",直接返回 0.0(= 原全表扫描
|
||||
# 结果);索引不可用时回退下方原全表线性扫描。
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) \
|
||||
and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0:
|
||||
return 0.0
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(cd_start, cd_end):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp。
|
||||
if nm is not None and nm[0] == name[0] and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1:
|
||||
self.CDefineIsStr = 1
|
||||
return 0.0
|
||||
if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1:
|
||||
self.CDefineIsDouble = 1
|
||||
ret_d: double = string.atof(val_str)
|
||||
return ret_d
|
||||
ret_i2: double = double(string.atoll(val_str))
|
||||
return ret_i2
|
||||
return 0.0
|
||||
def lookup_cdefine_string(self, name: str) -> str:
|
||||
"""查找 CDefine 编译期字符串值(found=1 且 is_str=1 时有效)
|
||||
|
||||
返回的字符串指针位于 pool 内(当前模块生命周期内有效),
|
||||
调用方应尽快用于 create_global_string 拷贝到 LLVM 常量。
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None:
|
||||
return None
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n | 查询名非空)时直接定位唯一候选下标
|
||||
# (= 原扫描首个命中)。CDefine 名注册后不再改写、每次注册都同步入索引
|
||||
# (失败即置 Built=-1)⇒ 可信时未命中即"确无",直接返回 None(= 原全表扫描
|
||||
# 结果);索引不可用时回退下方原全表线性扫描。
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) \
|
||||
and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit < 0:
|
||||
return None
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(cd_start, cd_end):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1:
|
||||
self.CDefineIsStr = 1
|
||||
return val_str
|
||||
return val_str
|
||||
return None
|
||||
def is_cdefine_str(self) -> int:
|
||||
"""检查最近一次 CDefine 查找命中的是否是字符串常量"""
|
||||
return self.CDefineIsStr
|
||||
def is_cdefine_double(self) -> int:
|
||||
"""检查最近一次 CDefine 查找命中的是否是浮点常量"""
|
||||
return self.CDefineIsDouble
|
||||
def is_cdefine_found(self) -> int:
|
||||
"""检查上次 lookup_cdefine_constant 是否找到值"""
|
||||
return self.CDefineFound
|
||||
def set_cdefine_found(self, val: int) -> None:
|
||||
"""设置 cdefine_found 标志(供跨模块查找函数使用)"""
|
||||
self.CDefineFound = val
|
||||
def clear_cdefine_constants(self) -> None:
|
||||
"""清空 CDefine 常量表(模块切换时调用)
|
||||
|
||||
表本体自首次创建起常驻 PermPool(见 _cdefine_table_pool)⇒ 此处只
|
||||
**清空内容**、不丢弃表指针:
|
||||
- 丢指针会退回"下一次 register_cdefine_* 按**调用方 pool** 重建",
|
||||
表本体又落回会被 reset_to 回收的瞬时池(冷 temp 下翻译 includes
|
||||
时才走到注册路径 ⇒ 表本体跨 reset 悬空 ⇒ append 写进已回收/未
|
||||
初始化内存的根因);
|
||||
- 空表与既有语义完全等价:lookup 命中空表即"未命中",
|
||||
register 首次 append 即写回第 0 槽。
|
||||
"""
|
||||
if self.CDefineNames is not None:
|
||||
self.CDefineNames.clear()
|
||||
if self.CDefineValues is not None:
|
||||
self.CDefineValues.clear()
|
||||
if self.CDefineDoubleFlags is not None:
|
||||
self.CDefineDoubleFlags.clear()
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.clear()
|
||||
# 名索引清槽(槽存 index+1,0=空槽)+ Built 归零(空表与索引同步;
|
||||
# 与"新建表后首次 register"的索引状态逐字一致)
|
||||
if self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
string.memset(self.CDefineNameIdx, 0,
|
||||
sizet(self.CDefineNameIdxCap) * 8)
|
||||
self.CDefineNameIdxBuilt = 0
|
||||
else:
|
||||
self.CDefineNameIdx = None
|
||||
self.CDefineNameIdxCap = 0
|
||||
self.CDefineNameIdxBuilt = -1
|
||||
self.CDefineIsStr = 0
|
||||
@@ -0,0 +1,767 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
# ============================================================
|
||||
# CTypedef 名索引(名 → 槽下标,开放寻址 | 线性探测)
|
||||
#
|
||||
# 槽数 = 4096(2 的幂;负载 < 0.5 上限 2048 条,超限标记不可信回退线性扫描)。
|
||||
# 槽存槽下标 + 1(0=空槽)。CTypedefNames 只追加不重排(同名注册原地更新类型串)
|
||||
# ⇒ 槽下标稳定;Built == len(CTypedefNames) 才可信。
|
||||
# ============================================================
|
||||
define CTYPEDEF_IDX_CAP = 4096
|
||||
# 索引哈希常量(32 位 FNV-1a,与 StructGenMixin 范式一致)
|
||||
define CTYPEDEF_IDX_FNV_OFFSET = 2166136261
|
||||
define CTYPEDEF_IDX_FNV_PRIME = 16777619
|
||||
define CTYPEDEF_IDX_FNV_MASK = 4294967295
|
||||
|
||||
|
||||
def _ctypedef_idx_hash(name: str) -> uint64:
|
||||
"""CTypedef 名 → 64 位哈希(32 位 FNV-1a,逐字节到 NUL 结束)"""
|
||||
h: uint64 = uint64(CTYPEDEF_IDX_FNV_OFFSET)
|
||||
if name is None: return h
|
||||
i: sizet = 0
|
||||
while name[i] != '\0':
|
||||
h = (h ^ uint64(int(name[i]))) * uint64(CTYPEDEF_IDX_FNV_PRIME)
|
||||
h = h & uint64(CTYPEDEF_IDX_FNV_MASK)
|
||||
i += 1
|
||||
return h
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenCType - CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr)
|
||||
#
|
||||
# 继承链仅 1 级(TPV self 调用仅支持 1 级父类);跨 Mixin 调用统一走 HandlesType 委托。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
"""CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr)"""
|
||||
|
||||
# ============================================================
|
||||
# 本类**不**重复声明 CTypedef* 字段:它们由父类 TypeGenBase 的**类体**声明
|
||||
# (TypeGenBase.vp:73-84),跨模块可见性随父类声明一并提供(继承前缀)。
|
||||
# 判据:字段只在其**归属类**的类体声明一次;子类若再声明同名继承字段,该名字
|
||||
# 会变成子类"自有字段",自有表与继承前缀出现重名条目 ⇒ `base + 表内下标`
|
||||
# 的继承字段偏移整体错位(现场:TypeGenResolve.vp 的
|
||||
# `self.Gen.TypeGenCType.LastBuiltinsTypedefResult = "t.CPtr"` 落到 i32 槽 →
|
||||
# "指针隐式转整数已禁止" fail-fast;正确槽是同名继承字段的 i8* 槽)。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# CTypedef 名索引(开放寻址;槽存 index+1,0=空槽)
|
||||
# ============================================================
|
||||
def _ctypedef_idx_slot(self, si: sizet) -> sizet*:
|
||||
"""取索引第 si 个槽(8 字节,存槽下标+1;0=空槽)"""
|
||||
return (sizet*)(uint64(self.CTypedefNameIdx) + uint64(si) * 8)
|
||||
|
||||
def _ctypedef_idx_init(self, pool: memhub.MemBuddy*) -> None:
|
||||
"""创建/清零名索引(与 CTypedefNames 同池);失败则标记不可信"""
|
||||
idx: sizet* = pool.alloc(sizet(CTYPEDEF_IDX_CAP) * 8)
|
||||
if idx is None:
|
||||
self.CTypedefNameIdx = None
|
||||
self.CTypedefNameIdxCap = 0
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
return
|
||||
string.memset(idx, 0, sizet(CTYPEDEF_IDX_CAP) * 8)
|
||||
self.CTypedefNameIdx = idx
|
||||
self.CTypedefNameIdxCap = CTYPEDEF_IDX_CAP
|
||||
self.CTypedefNameIdxBuilt = 0
|
||||
|
||||
def _ctypedef_idx_find(self, name: str) -> int:
|
||||
"""在名索引中探测 name,返回命中槽下标(>=0);未命中/不可用返回 -1"""
|
||||
if self.CTypedefNameIdx is None or self.CTypedefNameIdxCap <= 0 or name is None:
|
||||
return -1
|
||||
if self.CTypedefNameIdxBuilt != int(len(self.CTypedefNames)):
|
||||
return -1
|
||||
h: uint64 = _ctypedef_idx_hash(name)
|
||||
mask: sizet = sizet(self.CTypedefNameIdxCap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < self.CTypedefNameIdxCap:
|
||||
slot: sizet* = self._ctypedef_idx_slot(si)
|
||||
sv: sizet = slot[0]
|
||||
if sv == 0:
|
||||
return -1
|
||||
se: int = int(sv) - 1
|
||||
nm: str = self.CTypedefNames.get(sizet(se))
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
return se
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
def _ctypedef_idx_insert(self, slot_index: int, name: str) -> int:
|
||||
"""把 (name → slot_index) 记入索引;0=成功 / 1=失败"""
|
||||
if self.CTypedefNameIdx is None or self.CTypedefNameIdxCap <= 0 or name is None:
|
||||
return 1
|
||||
h: uint64 = _ctypedef_idx_hash(name)
|
||||
mask: sizet = sizet(self.CTypedefNameIdxCap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < self.CTypedefNameIdxCap:
|
||||
slot: sizet* = self._ctypedef_idx_slot(si)
|
||||
if slot[0] == 0:
|
||||
slot[0] = sizet(slot_index + 1)
|
||||
return 0
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return 1
|
||||
|
||||
def _ctypedef_idx_sync_append(self, name: str) -> None:
|
||||
"""CTypedefNames.append 后同步索引(槽下标 = len-1);不可信则保持不可信"""
|
||||
n: int = int(len(self.CTypedefNames))
|
||||
if self.CTypedefNameIdxBuilt == n - 1 and self._ctypedef_idx_insert(n - 1, name) == 0:
|
||||
self.CTypedefNameIdxBuilt = n
|
||||
else:
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
|
||||
# ============================================================
|
||||
# CTypedef 表本体的池归一
|
||||
#
|
||||
# 表指针挂在**进程级单例** _g_gen.TypeGenCType 上,不在任何 pool 的管辖
|
||||
# 范围内;而调用方传进来的 pool 在翻译期是「每文件 reset_to 回收」的瞬时池
|
||||
# (Phase1 1a/1b、Phase2 PhaseA、Repl 每片段/每模块都按 mark/reset 轮转)。
|
||||
# 表本体若落在该池:reset 之后表指针**悬空但非 None** ⇒ `is None` 守卫失效
|
||||
# ⇒ 下一次 register_ctypedef 的 append 写进已回收内存(堆损坏;检测模式下
|
||||
# 该区被 free 填成 0xCD ⇒ append 收到 rdi=0xcdcdcdcdcdcdcdcd 后崩)。
|
||||
# 故表本体(表对象 + 名索引 + visiting 表)一律落 PermPool(进程级永久池,
|
||||
# 从不 reset),与"文件级/片段级 reset"彻底解耦。
|
||||
# PermPool 不可用(无 CompilerFactory.factory 的极简单元程序)时退回入参
|
||||
# pool —— 与既有语义一致,只是不再有"表本体跨 reset 存活"的隐式假设。
|
||||
# ============================================================
|
||||
def _ctypedef_table_pool(self,
|
||||
pool: memhub.MemBuddy*) -> memhub.MemBuddy*:
|
||||
"""CTypedef 表本体的池:恒取 PermPool(不可用则退回入参 pool)"""
|
||||
if CompilerFactory.factory is not None \
|
||||
and CompilerFactory.factory.PermPool is not None:
|
||||
return CompilerFactory.factory.PermPool
|
||||
return pool
|
||||
|
||||
def register_ctypedef(self, pool: memhub.MemBuddy*,
|
||||
name: str, type_str: str) -> None:
|
||||
"""注册 CTypedef 到本地表
|
||||
|
||||
Args:
|
||||
pool: 内存池
|
||||
name: CTypedef 名称(如 "HANDLE")
|
||||
type_str: 类型表达式字符串(如 "VOIDPTR" 或 "t.CPtr")
|
||||
"""
|
||||
if name is None or type_str is None or pool is None:
|
||||
return
|
||||
# rawptr 是编译器内置语法(TPC/TPV 双端),不可重定义:
|
||||
# 忽略任何对 rawptr 的 typedef 注册,防止覆盖内置裸指针语义
|
||||
# (rawptr[T] 固定 = 指向原始类型 T 的裸指针)。
|
||||
if string.strcmp(name, "rawptr") == 0:
|
||||
return
|
||||
# 复制 name/type_str 到 pool:调用方可能传入零拷贝 AST 字符串
|
||||
# (如 .vpi 读取缓冲区),缓冲区随后被 free 会导致表项悬空、
|
||||
# lookup_ctypedef strcmp 失配、typedef 退化为 i8*(testcheck
|
||||
# SetConsoleOutputCP 的 UINT 根因)。表须持有自己的字符串副本。
|
||||
name_len: sizet = string.strlen(name)
|
||||
name_copy: str = pool.alloc(name_len + 1)
|
||||
if name_copy is None:
|
||||
return
|
||||
string.strcpy(name_copy, name)
|
||||
type_len: sizet = string.strlen(type_str)
|
||||
type_copy: str = pool.alloc(type_len + 1)
|
||||
if type_copy is None:
|
||||
return
|
||||
string.strcpy(type_copy, type_str)
|
||||
if self.CTypedefNames is None:
|
||||
tp: memhub.MemBuddy* = self._ctypedef_table_pool(pool)
|
||||
tn: list[str]* = list[str](tp, 64)
|
||||
ts: list[str]* = list[str](tp, 64)
|
||||
# 建表失败(池不可用/耗尽)⇒ 明确报错并返回,绝不让下面的 append
|
||||
# 落到 None 或未初始化地址(原实现无检查 ⇒ 写进 0xCDCD 区崩)
|
||||
if tn is None or ts is None:
|
||||
VLogger.error("CTypedef 表分配失败(表本体池不可用或耗尽)", "TypeGen")
|
||||
return
|
||||
self.CTypedefNames = tn
|
||||
self.CTypedefTypeStrs = ts
|
||||
# 名索引随表创建(同池 = PermPool;分配失败则标记不可信,查找回退线性扫描)
|
||||
self._ctypedef_idx_init(tp)
|
||||
# 表就绪守卫:表本体缺失(建表失败/被外部置空)⇒ fail-fast,不写垃圾
|
||||
if self.CTypedefNames is None or self.CTypedefTypeStrs is None:
|
||||
VLogger.error("CTypedef 表未就绪(CTypedefNames/CTypedefTypeStrs 为空)", "TypeGen")
|
||||
return
|
||||
# 去重:若已存在同名 CTypedef,更新其类型字符串
|
||||
exist_n: sizet = len(self.CTypedefNames)
|
||||
ei: sizet
|
||||
for ei in range(exist_n):
|
||||
en: str = self.CTypedefNames.get(ei)
|
||||
if en is not None and string.strcmp(en, name_copy) == 0:
|
||||
# 已存在,更新类型字符串
|
||||
self.CTypedefTypeStrs.set(ei, type_copy)
|
||||
return
|
||||
self.CTypedefNames.append(name_copy)
|
||||
self.CTypedefTypeStrs.append(type_copy)
|
||||
# 追加后同步名索引(槽下标 = 追加前 len = 新 len-1)
|
||||
self._ctypedef_idx_sync_append(name_copy)
|
||||
def store_builtins_diag(self, which: int, text: str) -> str:
|
||||
"""把 builtins 诊断串复制进自有缓冲并返回该缓冲(which: 0=Name, 1=Result)
|
||||
|
||||
调用方(VpiReader._resolve_single_vpi_type_str)传的往往是
|
||||
stdlib.malloc 的临时段缓冲,返回前即 free——直接存指针会让
|
||||
_build_ann_fail_msg 的 snprintf 读已释放内存(ASan
|
||||
heap-use-after-free)。诊断字段必须持有自己的副本。
|
||||
text 为 None 时返回 None("未命中"标记)。
|
||||
"""
|
||||
if text is None:
|
||||
return None
|
||||
# 诊断串按需 realloc 到精确长度:固定 TYPEDEF_DIAG_BUF(256) + strncpy(buf, text, 255)
|
||||
# 会静默截断超长诊断串 ⇒ 报错文本丢掉关键名字(归因信息失效)。
|
||||
# 缓冲仍为自有字段(生命周期不变:仍在 reset/析构时统一 stdlib.free)。
|
||||
need: sizet = string.strlen(text) + 1
|
||||
if which == 0:
|
||||
if self.LastBuiltinsTypedefNameBuf is None:
|
||||
self.LastBuiltinsTypedefNameBuf = stdlib.malloc(need)
|
||||
else:
|
||||
self.LastBuiltinsTypedefNameBuf = stdlib.realloc(self.LastBuiltinsTypedefNameBuf, need)
|
||||
buf: str = self.LastBuiltinsTypedefNameBuf
|
||||
else:
|
||||
if self.LastBuiltinsTypedefResultBuf is None:
|
||||
self.LastBuiltinsTypedefResultBuf = stdlib.malloc(need)
|
||||
else:
|
||||
self.LastBuiltinsTypedefResultBuf = stdlib.realloc(self.LastBuiltinsTypedefResultBuf, need)
|
||||
buf = self.LastBuiltinsTypedefResultBuf
|
||||
if buf is None:
|
||||
return None
|
||||
string.strcpy(buf, text)
|
||||
return buf
|
||||
|
||||
def lookup_ctypedef(self, name: str) -> str:
|
||||
"""查找 CTypedef,返回类型表达式字符串
|
||||
|
||||
返回找到的类型表达式字符串,未找到返回 None。
|
||||
调用方应在调用后检查 _g_ctypedef_found 标志区分"未找到"和"空字符串"。
|
||||
"""
|
||||
self.CTypedefFound = 0
|
||||
if name is None:
|
||||
return None
|
||||
if self.CTypedefNames is None:
|
||||
return None
|
||||
n: sizet = len(self.CTypedefNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选槽下标。CTypedef 表
|
||||
# 注册时按名去重(register_ctypedef 已存在则原地更新类型串、不追加)⇒ 名
|
||||
# 唯一且注册后不再改写,索引完整覆盖全表 ⇒ 未命中即"确无",直接返回 None
|
||||
# (= 原全表扫描结果);索引不可用/不可信 → 回退下方原全表扫描。
|
||||
if self.CTypedefNameIdxBuilt == int(n) \
|
||||
and self.CTypedefNameIdx is not None and self.CTypedefNameIdxCap > 0:
|
||||
ti: int = self._ctypedef_idx_find(name)
|
||||
if ti < 0:
|
||||
return None
|
||||
ts_hit: str = self.CTypedefTypeStrs.get(sizet(ti))
|
||||
self.CTypedefFound = 1
|
||||
return ts_hit
|
||||
for i in range(n):
|
||||
nm: str = self.CTypedefNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
ts: str = self.CTypedefTypeStrs.get(i)
|
||||
self.CTypedefFound = 1
|
||||
return ts
|
||||
return None
|
||||
def is_ctypedef_found(self) -> int:
|
||||
"""检查上次 lookup_ctypedef 是否找到值"""
|
||||
return self.CTypedefFound
|
||||
def lookup_ctypedef_span(self, text: str, start: sizet, end: sizet) -> str:
|
||||
"""按名字切片查 CTypedef(零分配,不复制子串)
|
||||
|
||||
与 lookup_ctypedef 同表;命中置 CTypedefFound=1 并返回类型表达式串,
|
||||
未命中返回 None(CTypedefFound=0)。用于符号性独立真源的别名链展开。
|
||||
"""
|
||||
self.CTypedefFound = 0
|
||||
if text is None or end <= start:
|
||||
return None
|
||||
if self.CTypedefNames is None:
|
||||
return None
|
||||
want: sizet = end - start
|
||||
n: sizet = len(self.CTypedefNames)
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
nm: str = self.CTypedefNames.get(i)
|
||||
if nm is None:
|
||||
continue
|
||||
# 快速路径:命中要求 nm[0]==text[start](逐字节比较的 k=0 项),
|
||||
# 首字节不同者无需 strlen 即可判定不命中(不影响任何原命中项)。
|
||||
if nm[0] != text[start] or string.strlen(nm) != want:
|
||||
continue
|
||||
hit: int = 1
|
||||
k: sizet = 0
|
||||
while k < want:
|
||||
if nm[k] != text[start + k]:
|
||||
hit = 0
|
||||
break
|
||||
k += 1
|
||||
if hit != 0:
|
||||
ts: str = self.CTypedefTypeStrs.get(i)
|
||||
self.CTypedefFound = 1
|
||||
return ts
|
||||
return None
|
||||
# 符号性真源(无符号判定的读入口)
|
||||
#
|
||||
# 实现:精确名白名单(TSpec.SpecSignFromTypeNameSpan)+ 别名链逐层展开;
|
||||
# 不表态时返回 TS_SIGN_UNKNOWN(由调用方决定是否回退旧路径)。
|
||||
# 不用 strstr 子串扫描 + 单层展开:会误判 BYTEPTR(含 BYTE)、sha1 前缀名(含
|
||||
# uint32),且多层别名(WCHAR→WORD→uint16)漏判。
|
||||
def spec_sign_of_annot(self, text: str, depth: int = 0) -> int:
|
||||
"""按注解文本判定其整数值符号性(独立真源),未覆盖返回 TS_SIGN_UNKNOWN"""
|
||||
if text is None or depth > 16:
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
return self._spec_sign_of_span(text, 0, string.strlen(text), depth)
|
||||
def _spec_sign_of_span(self, text: str, start: sizet, end: sizet,
|
||||
depth: int) -> int:
|
||||
"""顶层 '|' 分段,返回首个能确定的符号性(`X | t.CPtr` 取 X)"""
|
||||
seg_start: sizet = start
|
||||
bracket_depth: int = 0
|
||||
i: sizet = start
|
||||
while i <= end:
|
||||
is_split: int = 0
|
||||
if i == end:
|
||||
is_split = 1
|
||||
elif text[i] == '|' and bracket_depth == 0:
|
||||
is_split = 1
|
||||
if is_split != 0:
|
||||
r: int = self._spec_sign_of_segment(text, seg_start, i, depth)
|
||||
if r != TSpec.TS_SIGN_UNKNOWN:
|
||||
return r
|
||||
seg_start = i + 1
|
||||
elif text[i] == '[' or text[i] == '(':
|
||||
bracket_depth += 1
|
||||
elif text[i] == ']' or text[i] == ')':
|
||||
if bracket_depth > 0:
|
||||
bracket_depth -= 1
|
||||
i += 1
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
def _spec_sign_of_segment(self, text: str, start: sizet, end: sizet,
|
||||
depth: int) -> int:
|
||||
"""单个片段:去空白/括号 → 指针后缀 → 下标取元素 → 末段名 → 别名链展开"""
|
||||
s: sizet = start
|
||||
e: sizet = end
|
||||
while s < e:
|
||||
if text[s] != ' ' and text[s] != '\t' and text[s] != '\n':
|
||||
break
|
||||
s += 1
|
||||
while e > s:
|
||||
if text[e - 1] != ' ' and text[e - 1] != '\t' and text[e - 1] != '\n':
|
||||
break
|
||||
e -= 1
|
||||
# 去外层成对括号(如 "(uint32)")
|
||||
while e > s + 1:
|
||||
if text[s] != '(' or text[e - 1] != ')':
|
||||
break
|
||||
s += 1
|
||||
e -= 1
|
||||
while s < e:
|
||||
if text[s] != ' ' and text[s] != '\t':
|
||||
break
|
||||
s += 1
|
||||
while e > s:
|
||||
if text[e - 1] != ' ' and text[e - 1] != '\t':
|
||||
break
|
||||
e -= 1
|
||||
if e <= s:
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
# C 指针后缀 '*' → 指针,不表态(指针语义由 PtrLevel 表达)
|
||||
if text[e - 1] == '*':
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
# 泛型/数组/rawptr 下标:IDENT[INNER, ...] → 取 INNER(元素决定值符号性)
|
||||
bracket: sizet = 0
|
||||
has_bracket: int = 0
|
||||
k: sizet = s
|
||||
while k < e:
|
||||
if text[k] == '[':
|
||||
bracket = k
|
||||
has_bracket = 1
|
||||
break
|
||||
k += 1
|
||||
if has_bracket != 0:
|
||||
inner_s: sizet = bracket + 1
|
||||
inner_e: sizet = inner_s
|
||||
d: int = 0
|
||||
while inner_e < e:
|
||||
if text[inner_e] == '[' or text[inner_e] == '(':
|
||||
d += 1
|
||||
elif text[inner_e] == ']':
|
||||
if d == 0:
|
||||
break
|
||||
d -= 1
|
||||
elif text[inner_e] == ')':
|
||||
if d > 0:
|
||||
d -= 1
|
||||
elif text[inner_e] == ',':
|
||||
if d == 0:
|
||||
break
|
||||
inner_e += 1
|
||||
return self._spec_sign_of_span(text, inner_s, inner_e, depth)
|
||||
# 去模块限定前缀:取最后一个 '.' 之后的名字
|
||||
name_s: sizet = s
|
||||
w: sizet = s
|
||||
while w < e:
|
||||
if text[w] == '.':
|
||||
name_s = w + 1
|
||||
w += 1
|
||||
exact: int = TSpec.SpecSignFromTypeNameSpan(text, name_s, e)
|
||||
if exact != TSpec.TS_SIGN_UNKNOWN:
|
||||
return exact
|
||||
# 精确名未覆盖 → 沿 CTypedef 链展开(depth 限制防环)
|
||||
if depth >= 16:
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
ts: str = self.lookup_ctypedef_span(text, name_s, e)
|
||||
if ts is None or self.CTypedefFound == 0:
|
||||
return TSpec.TS_SIGN_UNKNOWN
|
||||
return self._spec_sign_of_span(ts, 0, string.strlen(ts), depth + 1)
|
||||
def clear_ctypedefs(self) -> None:
|
||||
"""清空 CTypedef 表(模块切换时调用)
|
||||
|
||||
表本体自首次创建起常驻 PermPool(见 _ctypedef_table_pool)⇒ 此处只
|
||||
**清空内容**、不丢弃表指针:
|
||||
- 丢指针会退回"下一次 register_ctypedef 按**调用方 pool** 重建",
|
||||
表本体又落回会被 reset_to 回收的瞬时池(冷 temp 下翻译 includes
|
||||
时才走到注册路径 ⇒ 表本体跨 reset 悬空 ⇒ append 写进已回收/未
|
||||
初始化内存的根因);
|
||||
- 空表与既有语义完全等价:lookup 命中空表即"未命中",
|
||||
register 首次 append 即写回第 0 槽。
|
||||
"""
|
||||
if self.CTypedefNames is not None:
|
||||
self.CTypedefNames.clear()
|
||||
if self.CTypedefTypeStrs is not None:
|
||||
self.CTypedefTypeStrs.clear()
|
||||
# 名索引清槽(槽存 index+1,0=空槽)+ Built 归零(空表与索引同步;
|
||||
# 与"新建表后首次 register"的索引状态逐字一致)
|
||||
if self.CTypedefNameIdx is not None and self.CTypedefNameIdxCap > 0:
|
||||
string.memset(self.CTypedefNameIdx, 0,
|
||||
sizet(self.CTypedefNameIdxCap) * 8)
|
||||
self.CTypedefNameIdxBuilt = 0
|
||||
else:
|
||||
self.CTypedefNameIdx = None
|
||||
self.CTypedefNameIdxCap = 0
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
self.CTypedefResolveDepth = 0
|
||||
if self.CTypedefVisiting is not None:
|
||||
self.CTypedefVisiting.clear()
|
||||
# builtins 源扫描标记随表清空复位:每文件最多读一次 includes/builtins.vp
|
||||
# (_lookup_builtins_typedef 的"最后匹配"兜底,见 TypeGenResolve)
|
||||
self.BuiltinsTypedefScanned = 0
|
||||
self.LastBuiltinsTypedefName = None
|
||||
self.LastBuiltinsTypedefResult = None
|
||||
# 别名缓冲 / 诊断缓冲均为 stdlib.malloc 分配,跨 pool 生命周期;
|
||||
# 此处释放防泄漏(诊断缓冲按需再分配)
|
||||
if self.LastBuiltinsTypedefNameBuf is not None:
|
||||
stdlib.free(self.LastBuiltinsTypedefNameBuf)
|
||||
self.LastBuiltinsTypedefNameBuf = None
|
||||
if self.LastBuiltinsTypedefResultBuf is not None:
|
||||
stdlib.free(self.LastBuiltinsTypedefResultBuf)
|
||||
self.LastBuiltinsTypedefResultBuf = None
|
||||
if self.ImportAliasBuf is not None:
|
||||
stdlib.free(self.ImportAliasBuf)
|
||||
self.ImportAliasBuf = None
|
||||
def _ctypedef_push_visiting(self, pool: memhub.MemBuddy*, name: str) -> int:
|
||||
"""将 CTypedef 名加入正在解析列表(循环检测)
|
||||
|
||||
Returns:
|
||||
0=成功加入(无循环),1=检测到循环
|
||||
"""
|
||||
if name is None:
|
||||
return 0
|
||||
if self.CTypedefVisiting is None:
|
||||
# 与 CTypedef 表同池(PermPool):clear_ctypedefs 只清空、指针不丢,
|
||||
# 避免这张表也落在会被 reset_to 回收的调用方池上
|
||||
vp: memhub.MemBuddy* = self._ctypedef_table_pool(pool)
|
||||
self.CTypedefVisiting = list[str](vp, 32)
|
||||
if self.CTypedefVisiting is None:
|
||||
return 0
|
||||
vn: sizet = len(self.CTypedefVisiting)
|
||||
vi: sizet
|
||||
for vi in range(vn):
|
||||
vs: str = self.CTypedefVisiting.get(vi)
|
||||
if vs is not None and string.strcmp(vs, name) == 0:
|
||||
return 1 # 循环检测
|
||||
self.CTypedefVisiting.append(name)
|
||||
return 0
|
||||
def _ctypedef_pop_visiting(self) -> None:
|
||||
"""从正在解析列表弹出最后一个 CTypedef 名"""
|
||||
if self.CTypedefVisiting is None:
|
||||
return
|
||||
vn: sizet = len(self.CTypedefVisiting)
|
||||
if vn > 0:
|
||||
self.CTypedefVisiting.pop()
|
||||
def _is_ctypedef_annotation(self, annotation: ast.AST*) -> int:
|
||||
"""检测类型注解是否为 t.CTypedef
|
||||
|
||||
Args:
|
||||
annotation: 类型注解 AST 节点
|
||||
|
||||
Returns:
|
||||
1=是 t.CTypedef,0=否
|
||||
"""
|
||||
if annotation is None:
|
||||
return 0
|
||||
k_v: int = annotation.kind()
|
||||
if k_v != ast.ASTKind.Attribute:
|
||||
return 0
|
||||
at: ast.Attribute* = ast.Attribute*(annotation)
|
||||
# 字段访问改用 ast 模块访问器(直接访问 at.attr 可能按 stub 类型生成错误 GEP,
|
||||
# 读垃圾地址 → strcmp 崩溃)。
|
||||
at_attr_v: str = ast.attribute_get_attr(at)
|
||||
if at_attr_v is None:
|
||||
return 0
|
||||
# 限长比较替代 strcmp:attr 是零拷贝引用 src_buf 的 token 字符串,可能无 NUL
|
||||
# 结尾("CTypedef" 后紧跟空格/其他字符),strcmp 会读穿到页边界 → 崩溃。
|
||||
# strncmp 只读 8 字节,再校验第 9 字节为终止/分隔符(防 "CTypedefXXX" 误匹配)。
|
||||
if string.strncmp(at_attr_v, "CTypedef", 8) != 0:
|
||||
return 0
|
||||
sep_ch_d: char = at_attr_v[8]
|
||||
if sep_ch_d != '\0' and sep_ch_d != ' ' and sep_ch_d != '\n' \
|
||||
and sep_ch_d != '\r' and sep_ch_d != '\t' and sep_ch_d != '|':
|
||||
return 0
|
||||
at_val_v: ast.AST* = ast.attribute_get_value(at)
|
||||
if at_val_v is None or at_val_v.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
mod_nm: ast.Name* = ast.Name*(at_val_v)
|
||||
mod_id_v: str = ast.name_get_id(mod_nm)
|
||||
if mod_id_v is None:
|
||||
return 0
|
||||
# 同样限长比较("t" 无 NUL 结尾时 strcmp 读穿)
|
||||
if string.strncmp(mod_id_v, "t", 1) != 0:
|
||||
return 0
|
||||
sep_ch_m: char = mod_id_v[1]
|
||||
if sep_ch_m != '\0' and sep_ch_m != ' ' and sep_ch_m != '\n' \
|
||||
and sep_ch_m != '\r' and sep_ch_m != '\t' and sep_ch_m != '|':
|
||||
return 0
|
||||
return 1
|
||||
def ScanCTypedefDeclarations(self, pool: memhub.MemBuddy*,
|
||||
tree: ast.AST*) -> int:
|
||||
"""扫描 AST 顶层节点,注册所有 NAME: t.CTypedef = Type 声明
|
||||
|
||||
在 _translate_module_level 中、模块级变量预注册之前调用,
|
||||
确保 CTypedef 名称在类型解析时可用。
|
||||
|
||||
Args:
|
||||
pool: 内存池
|
||||
tree: 模块 AST 根节点
|
||||
|
||||
Returns:
|
||||
注册的 CTypedef 数量
|
||||
"""
|
||||
if pool is None or tree is None:
|
||||
return 0
|
||||
ch: list[ast.AST*]* = tree.children
|
||||
if ch is None:
|
||||
return 0
|
||||
n: sizet = len(ch)
|
||||
count: int = 0
|
||||
i: sizet
|
||||
for i in range(n):
|
||||
child: ast.AST* = ch.get(i)
|
||||
if child is None:
|
||||
continue
|
||||
if child.kind() != ast.ASTKind.AnnAssign:
|
||||
continue
|
||||
aa: ast.AnnAssign* = ast.AnnAssign*(child)
|
||||
if aa.annotation is None:
|
||||
continue
|
||||
# 检测注解是否为 t.CTypedef
|
||||
if self._is_ctypedef_annotation(aa.annotation) == 0:
|
||||
continue
|
||||
# 提取目标名称(必须是 Name 节点)
|
||||
if aa.target is None or aa.target.kind() != ast.ASTKind.Name:
|
||||
continue
|
||||
tgt: ast.Name* = ast.Name*(aa.target)
|
||||
tgt_id_v: str = ast.name_get_id(tgt)
|
||||
if tgt_id_v is None:
|
||||
continue
|
||||
# 提取类型表达式字符串(从 value AST 节点)
|
||||
if aa.value is None:
|
||||
continue
|
||||
type_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, aa.value)
|
||||
if type_str is None:
|
||||
continue
|
||||
# 注册 CTypedef
|
||||
self.register_ctypedef(pool, tgt_id_v, type_str)
|
||||
count += 1
|
||||
return count
|
||||
def register_ctypedef_from_source(self, pool: memhub.MemBuddy*,
|
||||
src: str) -> int:
|
||||
"""从源码文本逐行扫描注册 CTypedef(`typedef N = V` 或 `N: t.CTypedef = V`)
|
||||
|
||||
stdint.vp 崩溃根因修复:AST 字符串字段(attr/id)token 零拷贝指向
|
||||
src_buf,跨阶段内容不稳定(悬空),ScanCTypedefDeclarations 读
|
||||
attr 会 0xC0000005。本函数在 src_buf 有效期内(Phase1 1b translate
|
||||
前)用纯文本匹配注册,不依赖 AST 节点内容。
|
||||
"""
|
||||
if pool is None or src is None:
|
||||
return 0
|
||||
# 文件边界防护:clear_ctypedefs 只在 translate 前调用(Phase1Main
|
||||
# L800),文件级 reset_to(mark1) 回收本文件翻译期 pool 分配后,上一
|
||||
# 文件的 CTypedefNames 表指针悬空(非 None,list 本身也 pool 分配)。
|
||||
# 本函数去重遍历(register_ctypedef 内 strcmp)读已回收内存 →
|
||||
# 0xC0000005(1.log: stdint.vp 翻译时 strcmp 读地址 0x4)。先清表
|
||||
# 重建,杜绝悬空遍历。翻译期 Handle 按需注册不受影响(L800 会再清)。
|
||||
self.clear_ctypedefs()
|
||||
src_len: sizet = string.strlen(src)
|
||||
count: int = 0
|
||||
line_start: sizet = 0
|
||||
i: sizet = 0
|
||||
# 行解析缓冲("NAME\0VALUE\0"),整文件复用(register_ctypedef 内部自会复制)
|
||||
td_buf: str = pool.alloc(320)
|
||||
while i <= src_len:
|
||||
if i == src_len or src[i] == '\n':
|
||||
line_len: sizet = i - line_start
|
||||
if line_len > 0 and td_buf is not None:
|
||||
# 两种等价形态统一解析:语法糖 `typedef N = V`(builtins.vp 现用
|
||||
# 形态)与注解 `N: t.CTypedef = V`(stdint.vp 等库模块)。
|
||||
if self.Gen.TypeGenResolve._parse_typedef_line(td_buf, src, line_start, line_len) != 0:
|
||||
name_buf: str = td_buf
|
||||
ty_buf: str = td_buf + string.strlen(td_buf) + 1
|
||||
self.register_ctypedef(pool, name_buf, ty_buf)
|
||||
count += 1
|
||||
line_start = i + 1
|
||||
i += 1
|
||||
return count
|
||||
def _eval_const_int_expr(self, node: ast.AST*,
|
||||
pool: memhub.MemBuddy* = None,
|
||||
from_imports: str = None,
|
||||
imported_modules: str = None,
|
||||
depth: int = 0) -> int:
|
||||
"""递归计算常量整数表达式
|
||||
|
||||
pool/from_imports/imported_modules:跨模块 CDefine 查找上下文
|
||||
(t.CArray count 引用依赖模块的 CDefine,如 SHA512_BLOCK_LEN 定义在
|
||||
hashlib/__sha512.vp,本地 CDefine 表每模块清空,需跨模块回退查找)。
|
||||
depth:递归深度守卫(防御 AST 损坏成自引用环导致的无限递归——
|
||||
本函数被 resolve_annotation_type 的 t.CArray count 解析调用,其内部
|
||||
BinOp 自递归不经过 resolve_annotation_type 的 depth 守卫)。
|
||||
"""
|
||||
if node is None:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
# 递归深度守卫:BinOp 左右子树成环时无限递归直至栈耗尽。
|
||||
# fail-fast 终止(fatal_type_error → sys.exit(1)),不静默回落。
|
||||
if depth > 64:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "常量表达式递归过深(AST 环或嵌套超过 64 层)")
|
||||
k: int = node.kind()
|
||||
|
||||
# Constant: 整数字面量
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant* = ast.Constant*(node)
|
||||
if cn.const_kind == ast.CONST_INT:
|
||||
self.ConstEvalOk = 1
|
||||
return cn.int_val
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
# Name: CDefine 常量名(本地表优先,未命中走跨模块查找)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is None:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
val: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm.id)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
|
||||
# 本地表未命中:跨模块 CDefine 查找
|
||||
# 用 HandlesExpr 模块级委托(self._lookup_cross_module_cdefine 是
|
||||
# ExprGenMixin 方法,TypeGenMixin 直接调用会生成未定义引用)
|
||||
if (from_imports is not None or imported_modules is not None) \
|
||||
and pool is not None:
|
||||
x_val: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, nm.id, from_imports, imported_modules)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
self.ConstEvalOk = 1
|
||||
return x_val
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
self.ConstEvalOk = 1
|
||||
return val
|
||||
|
||||
# Attribute: 模块限定常量名,如 hashlib.MD5_DIGEST_LEN
|
||||
# (t.CArray[uint8, hashlib.MD5_DIGEST_LEN] 的 count 是 Attribute,
|
||||
# 复用跨模块 CDefine 查找:*:模块 → 源文件提取;re-export 常量由
|
||||
# _lookup_cross_module_cdefine 的 from-import 递归子模块兜底)
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is None:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
at_mod: ast.Name* = ast.Name*(at.value)
|
||||
if at_mod.id is not None:
|
||||
if (from_imports is not None or imported_modules is not None) \
|
||||
and pool is not None:
|
||||
mod_len: sizet = string.strlen(at_mod.id)
|
||||
fi_buf: str = pool.alloc(mod_len + 3)
|
||||
if fi_buf is not None:
|
||||
fi_buf[0] = '*'
|
||||
fi_buf[1] = ':'
|
||||
for mi in range(mod_len):
|
||||
fi_buf[2 + mi] = at_mod.id[mi]
|
||||
fi_buf[2 + mod_len] = '\0'
|
||||
av: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, fi_buf, imported_modules)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
self.ConstEvalOk = 1
|
||||
return av
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
# BinOp: 算术/位运算
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(node)
|
||||
# 递归计算左操作数
|
||||
lv: int = self._eval_const_int_expr(bop.left, pool, from_imports, imported_modules, depth + 1)
|
||||
if self.ConstEvalOk == 0:
|
||||
return 0
|
||||
# 递归计算右操作数
|
||||
rv: int = self._eval_const_int_expr(bop.right, pool, from_imports, imported_modules, depth + 1)
|
||||
if self.ConstEvalOk == 0:
|
||||
return 0
|
||||
# 根据运算符执行计算
|
||||
if bop.op == ast.OpKind.Add:
|
||||
self.ConstEvalOk = 1
|
||||
return lv + rv
|
||||
if bop.op == ast.OpKind.Sub:
|
||||
self.ConstEvalOk = 1
|
||||
return lv - rv
|
||||
if bop.op == ast.OpKind.Mult:
|
||||
self.ConstEvalOk = 1
|
||||
return lv * rv
|
||||
if bop.op == ast.OpKind.Div:
|
||||
# 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355)
|
||||
if rv == 0:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
self.ConstEvalOk = 1
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.FloorDiv:
|
||||
if rv == 0:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
self.ConstEvalOk = 1
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
self.ConstEvalOk = 1
|
||||
return lv | rv
|
||||
if bop.op == ast.OpKind.BitAnd:
|
||||
self.ConstEvalOk = 1
|
||||
return lv & rv
|
||||
# 不支持的运算符
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
# 不支持的节点类型
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
@@ -0,0 +1,492 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.Translator as HT
|
||||
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenErr - 错误上报/源行读取/类型推断(fatal_error/infer_* 等)
|
||||
# ============================================================
|
||||
novirtual class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
"""错误上报/源行读取/类型推断(fatal_error/infer_* 等)"""
|
||||
|
||||
def _read_source_line(self, file_path: str, lineno: int) -> str:
|
||||
"""从源文件读取第 lineno 行内容"""
|
||||
if file_path is None or lineno <= 0: return None
|
||||
f: rawptr[fileio.File] = fileio.File(file_path, fileio.MODE.R)
|
||||
if f.closed: return None
|
||||
# 按文件实际大小分配缓冲区:固定 256KB 会截断大源文件,末尾行号读不到 →
|
||||
# 误报"文件不存在或行号超出范围"(如 CallGenMixin.vp 555KB/9236 行的第
|
||||
# 8390 行)。64MB 上限防御异常超大文件整体读取。
|
||||
fsize: LONGLONG = f.size()
|
||||
if fsize <= 0 or fsize > 67108864:
|
||||
f.close()
|
||||
return None
|
||||
src_size: sizet = sizet(fsize)
|
||||
buf: bytes = stdlib.malloc(src_size + 1)
|
||||
if buf is None:
|
||||
f.close()
|
||||
return None
|
||||
bytes_read: LONG = f.read_all(buf, ULONG(src_size + 1))
|
||||
f.close()
|
||||
if bytes_read <= 0:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
# 逐行查找第 lineno 行
|
||||
cur_line: int = 1
|
||||
line_start: sizet = 0
|
||||
for i in range(bytes_read):
|
||||
if buf[i] == '\n':
|
||||
if cur_line == lineno:
|
||||
line_len: sizet = i - line_start
|
||||
if line_len > 0 and buf[line_start + line_len - 1] == '\r':
|
||||
line_len -= 1
|
||||
line_buf: bytes = stdlib.malloc(line_len + 1)
|
||||
if line_buf is not None:
|
||||
string.strncpy(line_buf, buf + line_start, line_len)
|
||||
line_buf[line_len] = '\0'
|
||||
stdlib.free(buf)
|
||||
return line_buf
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
cur_line += 1
|
||||
line_start = i + 1
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
def read_source_line(self, file_path: str, lineno: int) -> str:
|
||||
"""公开包装:从源文件读取第 lineno 行内容(供 traceback 展示)"""
|
||||
return self._read_source_line(file_path, lineno)
|
||||
def dump_parse_traceback(self, file_path: str) -> None:
|
||||
"""解析失败时以 Python 风格输出 traceback(仿 fatal_error)"""
|
||||
err_line: int = ast.get_parse_err_line()
|
||||
err_col: int = ast.get_parse_err_col()
|
||||
err_msg: str = ast.get_parse_err_msg()
|
||||
stdio.printf("Traceback (most recent call last, compile-time error):\n")
|
||||
if file_path is None or file_path[0] == 0:
|
||||
file_path = "<unknown>"
|
||||
if err_line > 0:
|
||||
stdio.printf(' File "%s", line %d\n', file_path, err_line)
|
||||
src: str = self._read_source_line(file_path, err_line)
|
||||
if src is not None:
|
||||
stdio.printf(" %s\n", src)
|
||||
# 列标记:在出错 token 起始列下方标 ^(parser 的 col_offset 是 0-based,
|
||||
# 前缀 4 空格 + err_col 个空格后落点恰好是该 token 首字符)
|
||||
if err_col > 0:
|
||||
stdio.printf(" ")
|
||||
for _ in range(err_col):
|
||||
stdio.printf(" ")
|
||||
stdio.printf("^\n")
|
||||
stdlib.free(src)
|
||||
else:
|
||||
stdio.printf(' File "%s"\n', file_path)
|
||||
if err_msg is None or err_msg[0] == 0:
|
||||
err_msg = "语法错误"
|
||||
stdio.printf("SyntaxError: %s\n", err_msg)
|
||||
def fatal_error(self, node: ast.AST*, msg: str,
|
||||
err_type: str = "SyntaxError",
|
||||
col_start: int = 0, col_end: int = 0):
|
||||
"""以 Python 风格报错并退出(支持多帧、错误类型、列范围)
|
||||
|
||||
向后兼容:err_type/col_start/col_end 有默认值,旧调用 fatal_error(node, msg) 仍可用。
|
||||
"""
|
||||
stdio.printf("Traceback (most recent call last, compile-time error):\n")
|
||||
# 输出调用栈帧(从底到顶)
|
||||
for i in range(self.Gen.TypeGenBase.TraceCount):
|
||||
frame: rawptr[GenTypes.TraceFrame] = self.Gen.TypeGenBase._get_trace_frame(i)
|
||||
if frame is not None and frame.file_name is not None:
|
||||
if frame.lineno > 0:
|
||||
stdio.printf(' File "%s", line %d\n', frame.file_name, frame.lineno)
|
||||
src: str = self._read_source_line(frame.file_name, frame.lineno)
|
||||
if src is not None:
|
||||
stdio.printf(" %s\n", src)
|
||||
stdlib.free(src)
|
||||
else:
|
||||
stdio.printf(' File "%s"\n', frame.file_name)
|
||||
# 输出当前帧(node 对应的位置)
|
||||
lineno: int = 0
|
||||
if node is not None:
|
||||
lineno = node.lineno
|
||||
file_name: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if file_name is None:
|
||||
file_name = "<unknown>"
|
||||
# 行号兜底:克隆/构造节点 lineno 可能为 0(如泛型特化 _clone_arguments 的
|
||||
# ast.Arg 构造器硬编码 0,astaux.vp L139)。此时回退到 trace 栈最后一个
|
||||
# 有效帧(文件+行号)作为出错位置,避免输出误导性的 "line 0"。
|
||||
if lineno <= 0 and self.Gen.TypeGenBase.TraceCount > 0:
|
||||
ti_b: int = self.Gen.TypeGenBase.TraceCount - 1
|
||||
while ti_b >= 0:
|
||||
tfb: rawptr[GenTypes.TraceFrame] = self.Gen.TypeGenBase._get_trace_frame(ti_b)
|
||||
if tfb is not None and tfb.file_name is not None and tfb.lineno > 0:
|
||||
file_name = tfb.file_name
|
||||
lineno = tfb.lineno
|
||||
break
|
||||
ti_b -= 1
|
||||
# 行号合理性防御:先读取该行源码,验证 node.lineno 是否落在当前文件内。
|
||||
# 若读不到(文件不存在或行号超出范围),说明文件/行号归属不可信
|
||||
# (如 AST 树被内存复用/串扰后跨文件报错),打印警告而非误导性行号。
|
||||
src_line: str = None
|
||||
line_ok: int = 1
|
||||
if lineno > 0 and string.strcmp(file_name, "<unknown>") != 0:
|
||||
src_line = self._read_source_line(file_name, lineno)
|
||||
if src_line is None:
|
||||
line_ok = 0
|
||||
if line_ok == 0:
|
||||
stdio.printf(' File "%s", line %d (!! 无法读取该行源码:文件不存在或行号超出范围,错误可能来自被复用的 AST 树,请以错误消息为准)\n',
|
||||
file_name, lineno)
|
||||
else:
|
||||
stdio.printf(' File "%s", line %d\n', file_name, lineno)
|
||||
if src_line is not None:
|
||||
stdio.printf(" %s\n", src_line)
|
||||
# 列范围标记:在源代码行下方用 ^ 标记出错范围
|
||||
if col_start > 0 and col_end >= col_start:
|
||||
stdio.printf(" ")
|
||||
j: int
|
||||
for j in range(col_end):
|
||||
if j >= col_start - 1 and j < col_end:
|
||||
stdio.printf("^")
|
||||
else:
|
||||
stdio.printf(" ")
|
||||
stdio.printf("\n")
|
||||
stdlib.free(src_line)
|
||||
# 输出错误类型 + 消息
|
||||
if err_type is None or err_type[0] == 0:
|
||||
err_type = "SyntaxError"
|
||||
stdio.printf("%s: %s\n", err_type, msg)
|
||||
# 退出前强制刷出:stdout 重定向到文件时是全缓冲,直接终止进程会把整段
|
||||
# traceback 丢掉(实测 2.log 只剩一行 VLogger 输出)。
|
||||
stdio.fflush(None)
|
||||
# 终止点收敛:REPL 会话内经 VLogger.repl_abort longjmp 回 REPL 循环
|
||||
# (Traceback 已打印,进程存活);批处理下该出口即 sys.exit(1),逐字不变。
|
||||
VLogger.repl_abort()
|
||||
|
||||
def fatal_type_error(self, node: ast.AST*, msg: str,
|
||||
col_start: int = 0, col_end: int = 0):
|
||||
"""以 Python 风格报错并退出(TypeError 版本)"""
|
||||
self.fatal_error(node, msg, "TypeError", col_start, col_end)
|
||||
def try_extract_callable_ret(self, pool: memhub.MemBuddy*,
|
||||
annot: ast.AST*,
|
||||
imported_modules: str,
|
||||
from_imports: str,
|
||||
trans: HT.Translator*) -> llvmlite.LLVMType*:
|
||||
"""提取函数指针注解(t.Callable[[A,B], R] / callable[[A,B], R])的返回类型
|
||||
LLVMType;非 Callable 注解或无签名形态([]、[[]])返回 None"""
|
||||
if annot is None or annot.kind() != ast.ASTKind.Subscript:
|
||||
return None
|
||||
sub_cr: ast.Subscript* = ast.Subscript*(annot)
|
||||
# 构造子判据走 TypeGenResolve 单一真源(Attribute 形态 t.Callable 与
|
||||
# 裸名形态 callable / Callable 等价)
|
||||
if self.Gen.TypeGenResolve._IsCallableSubscriptValue(sub_cr.value) == 0:
|
||||
return None
|
||||
# slice 必须是 Tuple(elts=[args_list, ret_node])
|
||||
if sub_cr.slice is None or sub_cr.slice.kind() != ast.ASTKind.Tuple:
|
||||
return None
|
||||
tp_cr: ast.Tuple* = ast.Tuple*(sub_cr.slice)
|
||||
if tp_cr.elts is None or len(tp_cr.elts) != 2:
|
||||
return None
|
||||
ret_node_cr: ast.AST* = tp_cr.elts.get(1)
|
||||
if ret_node_cr is None:
|
||||
return None
|
||||
return self.Gen.TypeGenResolve.resolve_annotation_type(pool, ret_node_cr, imported_modules, from_imports, trans, 0)
|
||||
def has_decorator_marker(self, node: ast.AST*,
|
||||
marker_name: str,
|
||||
depth: int = 0) -> int:
|
||||
"""检测类型注解中是否包含指定的装饰器标记"""
|
||||
if node is None or marker_name is None:
|
||||
return 0
|
||||
# 递归深度守卫:vpi stub 注入时对每个函数 returns 调用本函数,
|
||||
# vpi tree 深层节点可能被覆盖损坏成回指环(VpiReader L810-813),
|
||||
# BinOp 递归无守卫会无限递归直至栈耗尽。fail-fast 终止。
|
||||
if depth > 128:
|
||||
self.fatal_type_error(node, "装饰器标记检测递归过深(AST 环或嵌套超过 128 层)")
|
||||
|
||||
k: int = node.kind()
|
||||
|
||||
# Attribute 节点: t.CExtern, t.State, t.CExport, t.CInline
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(node)
|
||||
if at.attr is not None:
|
||||
if string.strcmp(at.attr, marker_name) == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# BinOp 节点: int | t.CExtern(递归检测左右子节点)
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(node)
|
||||
if self.has_decorator_marker(bop.left, marker_name, depth + 1) != 0:
|
||||
return 1
|
||||
if self.has_decorator_marker(bop.right, marker_name, depth + 1) != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
return 0
|
||||
|
||||
def has_pointee_volatile_marker(self, node: ast.AST*) -> int:
|
||||
"""检测指针注解 rawptr[...] 的下标实参是否含 t.CVolatile 标记,1=是 / 0=否
|
||||
|
||||
语义:rawptr[t.CVolatile | T] 等价 C 的 volatile T*,即"指针所指对象按
|
||||
volatile 访问"——解引用(p[i] / p.field / c.Deref(p))的 load/store 带
|
||||
LLVM volatile。与 has_decorator_marker 的区别:后者检测变量/字段**自身**
|
||||
的可见性限定(如 `locked: t.CVolatile | t.CInt`),对 Subscript 节点返回 0;
|
||||
本函数专检 rawptr 的 pointee 侧标记(下标实参子树),两者互不串味。
|
||||
标注形态(vast.parse 实证):
|
||||
rawptr[t.CVolatile | t.CInt]
|
||||
→ Subscript(value=Name('rawptr'),
|
||||
slice=BinOp(BitOr, Attribute(t,CVolatile), Attribute(t,CInt)))
|
||||
多级指针 rawptr[rawptr[t.CVolatile|T]] 的 slice 是 Subscript,
|
||||
has_decorator_marker 不递归 Subscript ⇒ 返回 0(明确不支持,见限制清单)。
|
||||
"""
|
||||
if node is None or node.kind() != ast.ASTKind.Subscript:
|
||||
return 0
|
||||
sub: ast.Subscript* = ast.Subscript*(node)
|
||||
if sub.value is None or sub.value.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
rp_nm: ast.Name* = ast.Name*(sub.value)
|
||||
if rp_nm.id is None or string.strcmp(rp_nm.id, "rawptr") != 0:
|
||||
return 0
|
||||
if sub.slice is None:
|
||||
return 0
|
||||
return self.has_decorator_marker(sub.slice, "CVolatile", 0)
|
||||
|
||||
def is_const_object_marker(self, node: ast.AST*,
|
||||
var_ty: llvmlite.LLVMType*) -> int:
|
||||
"""变量/字段本身是否 **const 对象**(1=是 / 0=否)。
|
||||
|
||||
判据与 TPC 的 BaseGen._IsConstObject **逐条一致**(见 Debugger/type-descriptors.md):
|
||||
① 注解子树含 t.CConst(has_decorator_marker,与 TPC 的 _AnnotationHasQualifier 同口径);
|
||||
② 声明类型的 LLVM 形态**不是指针**(TPC 用 PtrCount==0 表达同一件事)。
|
||||
`t.CConst` 在本语言里承载「指向的数据 const」(对齐 TPC 的 DataConst 语义),
|
||||
对非指针类型该限定退化为「该对象自身 const」⇒ 登记为 const 变量/字段;
|
||||
对指针类型(`p: t.CConst | T | t.CPtr`)限定只作用于 pointee ⇒ 指针变量自身
|
||||
仍可重新赋值,不登记。
|
||||
"""
|
||||
if self.has_decorator_marker(node, "CConst", 0) == 0:
|
||||
return 0
|
||||
if var_ty is None:
|
||||
return 0
|
||||
if var_ty.kind() == llvmlite.LLVMType.Ptr:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def is_pass_body(self, body: list[ast.AST*]*) -> int:
|
||||
"""检测函数体是否为 pass(空体或仅含 pass 语句)"""
|
||||
if body is None:
|
||||
return 1
|
||||
bn: sizet = len(body)
|
||||
if bn == 0:
|
||||
return 1
|
||||
if bn == 1:
|
||||
stmt: ast.AST* = body.get(0)
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.Pass:
|
||||
return 1
|
||||
return 0
|
||||
# 获取 LLVM 整数类型的位宽
|
||||
# 实现已收拢到 TSpec.SpecTypeBits(该块在 TypeSpec 模块中的唯一实现),此处只做委托。
|
||||
# 私有调用点(self.get_llvm_type_bits)保持原样不受影响。
|
||||
def get_llvm_type_bits(self, ty: llvmlite.LLVMType*) -> int:
|
||||
"""获取 LLVM 整数类型的位宽,非整数类型返回 0(委托 SpecTypeBits)"""
|
||||
return TSpec.SpecTypeBits(ty)
|
||||
def infer_expr_type(self, pool: memhub.MemBuddy*,
|
||||
node: ast.AST*,
|
||||
param_types: str) -> llvmlite.LLVMType*:
|
||||
"""推断表达式的 LLVM 类型
|
||||
|
||||
param_types 格式: "name:bits,name:bits,..."
|
||||
"""
|
||||
if node is None:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
k: int = node.kind()
|
||||
|
||||
if k == ast.ASTKind.Constant:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
elif k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(node)
|
||||
if nm.id is not None and param_types is not None:
|
||||
# 在 param_types 中查找: "name:bits" 格式
|
||||
# 键按精确长度分配:固定 64 缓冲 + snprintf("%s:") 会静默截断超长参数名,
|
||||
# 截断后的键可能与**别的参数前缀**匹配成功 ⇒ 取到错误的位宽(类型误判)。
|
||||
id_len: sizet = string.strlen(nm.id)
|
||||
search_key: str = pool.alloc(id_len + 2)
|
||||
if search_key is not None:
|
||||
string.strcpy(search_key, nm.id)
|
||||
search_key[id_len] = ':'
|
||||
search_key[id_len + 1] = '\0'
|
||||
found: str = string.strstr(param_types, search_key)
|
||||
if found is not None:
|
||||
colon_pos: sizet = id_len + 1
|
||||
bits_str: str = found + colon_pos
|
||||
bits: int = 0
|
||||
for bi in range(4):
|
||||
ch: char = bits_str[bi]
|
||||
if ch >= '0' and ch <= '9':
|
||||
bits = bits * 10 + (ch - '0')
|
||||
else:
|
||||
break
|
||||
if bits == 64:
|
||||
return llvmlite.Int64(pool)
|
||||
elif bits == 16:
|
||||
return llvmlite.Int16(pool)
|
||||
elif bits == 8:
|
||||
return llvmlite.Int8(pool)
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
elif k == ast.ASTKind.BinOp:
|
||||
binop: ast.BinOp* = ast.BinOp*(node)
|
||||
lhs_ty: llvmlite.LLVMType* = self.infer_expr_type(pool, binop.left, param_types)
|
||||
rhs_ty: llvmlite.LLVMType* = self.infer_expr_type(pool, binop.right, param_types)
|
||||
lhs_bits: int = self.get_llvm_type_bits(lhs_ty)
|
||||
rhs_bits: int = self.get_llvm_type_bits(rhs_ty)
|
||||
if lhs_bits >= rhs_bits:
|
||||
return lhs_ty
|
||||
return rhs_ty
|
||||
|
||||
return llvmlite.Int32(pool)
|
||||
def infer_return_type(self, pool: memhub.MemBuddy*,
|
||||
body: list[ast.AST*]*,
|
||||
param_types: str) -> llvmlite.LLVMType*:
|
||||
"""扫描函数体中的 return 语句,推断返回类型"""
|
||||
if body is None:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
ret_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
bn: sizet = len(body)
|
||||
for bi in range(bn):
|
||||
stmt: ast.AST* = body.get(bi)
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.Return:
|
||||
rt: rawptr[ast.Return] = rawptr[ast.Return](stmt)
|
||||
if rt.value is not None:
|
||||
expr_ty: llvmlite.LLVMType* = self.infer_expr_type(pool, rt.value, param_types)
|
||||
if expr_ty is not None:
|
||||
cur_bits: int = self.get_llvm_type_bits(ret_ty)
|
||||
new_bits: int = self.get_llvm_type_bits(expr_ty)
|
||||
if new_bits > cur_bits:
|
||||
ret_ty = expr_ty
|
||||
return ret_ty
|
||||
def body_has_value_return(self, pool: memhub.MemBuddy*,
|
||||
body: list[ast.AST*]*) -> int:
|
||||
"""扫描函数体,判断是否存在返回非 None 值的 return
|
||||
|
||||
递归检查控制流语句(if/while/for/try/with/match)内层 return,但跳过
|
||||
嵌套函数/类定义(FunctionDef/ClassDef 由自身翻译时独立检查,避免外层
|
||||
检查误伤嵌套作用域)。裸 return / return None(CONST_NONE)/ 无 return
|
||||
均不算返回非 None 值。
|
||||
供无返回类型注解函数的 fail-fast 检查使用:返回具体值必须有显式 ->
|
||||
注解,编译器不替用户推断返回类型(推断位宽会掩盖返回契约)。
|
||||
"""
|
||||
if body is None:
|
||||
return 0
|
||||
bn: sizet = len(body)
|
||||
for bi in range(bn):
|
||||
stmt: ast.AST* = body.get(bi)
|
||||
if stmt is None:
|
||||
continue
|
||||
k: int = stmt.kind()
|
||||
if k == ast.ASTKind.Return:
|
||||
rt: rawptr[ast.Return] = rawptr[ast.Return](stmt)
|
||||
if rt.value is not None:
|
||||
# return None(CONST_NONE)不算返回非 None 值
|
||||
if rt.value.kind() == ast.ASTKind.Constant:
|
||||
cn: ast.Constant* = ast.Constant*(rt.value)
|
||||
if cn.const_kind == ast.CONST_NONE:
|
||||
continue
|
||||
return 1
|
||||
elif k == ast.ASTKind.FunctionDef or k == ast.ASTKind.ClassDef:
|
||||
continue
|
||||
elif k == ast.ASTKind.If or k == ast.ASTKind.While or \
|
||||
k == ast.ASTKind.For or k == ast.ASTKind.Try or \
|
||||
k == ast.ASTKind.With or k == ast.ASTKind.Match:
|
||||
sub: list[ast.AST*]* = stmt.children
|
||||
if sub is not None and len(sub) > 0:
|
||||
if self.body_has_value_return(pool, sub) != 0:
|
||||
return 1
|
||||
return 0
|
||||
def build_param_types_str(self, pool: memhub.MemBuddy*,
|
||||
args_node: ast.AST*) -> str:
|
||||
"""构建参数类型编码字符串 "name:bits,name:bits,..."
|
||||
|
||||
[D5·截断纪律] 旧实现按 `an * 32 + 1` 预估缓冲,再用 `_strappend` 以
|
||||
`remain - 1` 截断且**不报错**:参数名偏长(或参数偏多)时编码串被静默
|
||||
截断 ⇒ `infer_expr_type` 的 `strstr(param_types, "name:")` 查找失配 /
|
||||
命中他人前缀 ⇒ 静默回落 Int32(类型误判)。现改为**上界预估 + 单遍就地
|
||||
拼接**:段一是只扫参数名的上界(name + ':' + 位宽 + ',' + NUL),段二是
|
||||
解析类型后逐条目就地格式化并立即拼接 —— 缓冲恒够,不存在截断;
|
||||
`_strappend` 一并删除(唯一调用点在本函数)。
|
||||
"""
|
||||
if args_node is None:
|
||||
return None
|
||||
ags: ast.Arguments* = ast.Arguments*(args_node)
|
||||
if ags.args is None:
|
||||
return None
|
||||
alist: list[ast.AST*]* = ags.args
|
||||
an: sizet = len(alist)
|
||||
if an == 0:
|
||||
return None
|
||||
|
||||
# 1) 上界估长(**只扫参数名**,不解析类型,也不暂存结果指针):
|
||||
# 每条 = name + ':' + 位宽(int32 十进制最长 11 字符含符号)+ ',';再加 NUL。
|
||||
# 必须"上界"而非"精确":把条目指针存进 sizet 数组再取出转回指针 strcat 会出错;
|
||||
# 上界缓冲不需要数组往返,每条目就地格式化、立即拼接。
|
||||
bound: sizet = 1 # 末尾 NUL
|
||||
pre_i: sizet
|
||||
for pre_i in range(an):
|
||||
pre_arg: ast.Arg* = ast.Arg*(alist.get(pre_i))
|
||||
if pre_arg is None or pre_arg.arg is None:
|
||||
continue
|
||||
bound += string.strlen(pre_arg.arg) + 1 + 12 + 1
|
||||
buf: str = pool.alloc(bound)
|
||||
if buf is None:
|
||||
return None
|
||||
buf[0] = '\0'
|
||||
|
||||
# 2) 单遍:解析类型 → 就地格式化条目 → 立即拼接(缓冲为上界,不会截断)
|
||||
cnt: sizet = 0
|
||||
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
|
||||
for ai in range(an):
|
||||
arg: ast.Arg* = ast.Arg*(alist.get(ai))
|
||||
if arg is None or arg.arg is None:
|
||||
continue
|
||||
param_ty: llvmlite.LLVMType* = i32_ty
|
||||
if arg.annotation is not None:
|
||||
# 统一口径:CTypedef 动态表优先,miss 回退 map_t_type
|
||||
# (阶段 2:删除 map_t_type 硬编码别名后,BYTE 等靠库 typedef)
|
||||
if arg.annotation.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(arg.annotation)
|
||||
if at.attr is not None:
|
||||
resolved: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_typedef_or_map(pool, at.attr, None, None)
|
||||
if resolved is not None:
|
||||
param_ty = resolved
|
||||
bits: int = self.get_llvm_type_bits(param_ty)
|
||||
if bits == 0:
|
||||
bits = 32
|
||||
nlen: sizet = string.strlen(arg.arg)
|
||||
# 条目缓冲:name + ':' + 位宽(预留 16 字节,足够 %d 任意取值)+ NUL
|
||||
ent: str = pool.alloc(nlen + 1 + 16 + 1)
|
||||
if ent is None:
|
||||
continue
|
||||
string.strcpy(ent, arg.arg)
|
||||
ent[nlen] = ':'
|
||||
viperlib.snprintf(ent + nlen + 1, 16, "%d", bits)
|
||||
if cnt > 0:
|
||||
string.strcat(buf, ",")
|
||||
string.strcat(buf, ent)
|
||||
cnt += 1
|
||||
if cnt == 0:
|
||||
return None
|
||||
return buf
|
||||
@@ -11,16 +11,14 @@ import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Gen.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.Translator as HT
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenMixin - 类型映射与解析 Mixin(对象化 P2,wiki/14-oo-refactor.md)
|
||||
#
|
||||
# 500~1500 行/文件架构重构阶段 D:全部方法已拆至
|
||||
# TypeGenBase/CDef/CType/Resolve/Err,本文件保留类声明(Generator 继承链入口)。
|
||||
# TypeGenMixin - 类型映射与解析 Mixin(Generator 继承链入口)
|
||||
#
|
||||
# 方法已全部拆至 TypeGenBase/CDef/CType/Resolve/Err,本文件保留类声明。
|
||||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。
|
||||
# ============================================================
|
||||
|
||||
@@ -28,13 +26,12 @@ import lib.core.Gen.TypeGenBase as TypeGenBase
|
||||
# ============================================================
|
||||
# 常量(与 HandlesType 保持一致)
|
||||
# ============================================================
|
||||
TRACE_MAX: t.CDefine = 32
|
||||
MAX_CTYPEDEF_DEPTH: t.CDefine = 10
|
||||
define TRACE_MAX = 32
|
||||
define MAX_CTYPEDEF_DEPTH = 10
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenMixin - 类型映射/注解解析/编译期常量表/错误上报
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class TypeGenMixin(TypeGenBase.TypeGenBase):
|
||||
novirtual class TypeGenMixin(TypeGenBase.TypeGenBase):
|
||||
"""类型映射与解析 Mixin(阶段 D 拆分后顶层,方法全部在子 Mixin)"""
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,229 +0,0 @@
|
||||
import lib.core.Gen.TypeGenMixin as TypeGenMixin
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenBase - TypeGenMixin 拆分(阶段 D):字段 + InitTypeGen + trace/临时目录/generic 上下文
|
||||
#
|
||||
# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class TypeGenBase:
|
||||
"""字段 + InitTypeGen + trace/临时目录/generic 上下文"""
|
||||
|
||||
# --- 仿 Python Traceback 调用栈(原 _g_trace_frames/_g_trace_count) ---
|
||||
Gen: Generator.Generator | t.CPtr
|
||||
TraceFrames: GenTypes.TraceFrame | t.CPtr # malloc 数组(TypeGenMixin.TRACE_MAX 槽)
|
||||
TraceCount: int
|
||||
|
||||
# --- 全局泛型特化上下文(原 _g_generic_tp_names/_g_generic_type_args) ---
|
||||
GenericTpNames: list[str] | t.CPtr
|
||||
GenericTypeArgs: list[str] | t.CPtr
|
||||
# 嵌套安全栈:set_generic_context 压入外层值,clear_generic_context 弹出
|
||||
# 恢复(原单槽赋值:嵌套特化/泛型函数翻译退出时把外层上下文清成 None →
|
||||
# 外层方法体后续的 T 替换丢失 → T.__sizeof__() NameError,VectorGenericTest
|
||||
# 特化 Vector[int].__init__ 回归根因)。
|
||||
GenericCtxStack: t.CSizeT | t.CPtr # i64* 固定数组:每层 2 个槽(tp_names, type_args 指针)
|
||||
GenericCtxDepth: int
|
||||
|
||||
# --- 全局 CDefine 编译期常量表(原 _g_cdefine_*) ---
|
||||
CDefineNames: list[str] | t.CPtr
|
||||
CDefineValues: list[str] | t.CPtr
|
||||
CDefineDoubleFlags: list[int] | t.CPtr
|
||||
CDefineStrFlags: list[int] | t.CPtr # 1=字符串值(如 ZLIB_VERSION: t.CDefine = "1.3.2")
|
||||
CDefineIsDouble: int
|
||||
CDefineIsStr: int
|
||||
CDefineFound: int
|
||||
|
||||
# --- 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用) ---
|
||||
# 2026-08-14:跨模块 CDefine 查找(_lookup_cross_module_cdefine)结果缓存到
|
||||
# perm_pool,reset_to(mark2)/clear_cdefine_constants 不清除 → 跨文件复用,
|
||||
# CONST_INT 递归查找只做一次(NewAstTest OOM 根因)。
|
||||
XmodCdefNames: list[str] | t.CPtr
|
||||
XmodCdefValues: list[str] | t.CPtr
|
||||
XmodCdefDoubleFlags: list[int] | t.CPtr
|
||||
XmodCdefStrFlags: list[int] | t.CPtr
|
||||
|
||||
# --- 当前模块 SHA1(原 _g_current_module_sha1) ---
|
||||
CurrentModuleSha1: str
|
||||
|
||||
# --- 全局 CTypedef 表(原 _g_ctypedef_*) ---
|
||||
CTypedefNames: list[str] | t.CPtr
|
||||
CTypedefTypeStrs: list[str] | t.CPtr
|
||||
CTypedefFound: int
|
||||
CTypedefResolveDepth: int
|
||||
CTypedefVisiting: list[str] | t.CPtr
|
||||
|
||||
# --- 常量整数表达式计算成功标志(原 _g_const_eval_ok) ---
|
||||
ConstEvalOk: int
|
||||
|
||||
# --- 全局当前文件名(原 _g_current_file) ---
|
||||
CurrentFile: str
|
||||
def InitTypeGen(self) -> int:
|
||||
"""初始化类型 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)"""
|
||||
if self is None:
|
||||
return 1
|
||||
self.TraceFrames = None
|
||||
self.TraceCount = 0
|
||||
self.GenericTpNames = None
|
||||
self.GenericTypeArgs = None
|
||||
self.GenericCtxStack = None
|
||||
self.GenericCtxDepth = 0
|
||||
self.CDefineNames = None
|
||||
self.CDefineValues = None
|
||||
self.CDefineDoubleFlags = None
|
||||
self.CDefineStrFlags = None
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
self.CDefineFound = 0
|
||||
self.XmodCdefNames = None
|
||||
self.XmodCdefValues = None
|
||||
self.XmodCdefDoubleFlags = None
|
||||
self.XmodCdefStrFlags = None
|
||||
self.CurrentModuleSha1 = None
|
||||
self.CTypedefNames = None
|
||||
self.CTypedefTypeStrs = None
|
||||
self.CTypedefFound = 0
|
||||
self.CTypedefResolveDepth = 0
|
||||
self.CTypedefVisiting = None
|
||||
self.ConstEvalOk = 0
|
||||
self.CurrentFile = None
|
||||
return 0
|
||||
# ============================================================
|
||||
# P2 迁移方法(函数体来自 HandlesType.vp,全局变量改 self.字段,
|
||||
# 同模块函数调用改 self.方法;签名与 HandlesType 原函数一致)
|
||||
# ============================================================
|
||||
|
||||
def _ensure_trace_init(self) -> int:
|
||||
"""确保调用栈已初始化(懒加载,用 malloc 不依赖 pool)"""
|
||||
if self.TraceFrames is not None:
|
||||
return 1
|
||||
entry_size: t.CSizeT = GenTypes.TraceFrame.__sizeof__()
|
||||
self.TraceFrames = CompilerFactory.get_perm_pool().alloc(entry_size * TypeGenMixin.TRACE_MAX)
|
||||
if self.TraceFrames is None:
|
||||
return 0
|
||||
string.memset(self.TraceFrames, 0, entry_size * TypeGenMixin.TRACE_MAX)
|
||||
return 1
|
||||
def _get_trace_frame(self, i: int) -> GenTypes.TraceFrame | t.CPtr:
|
||||
"""获取第 i 个 TraceFrame 槽位"""
|
||||
if self.TraceFrames is None or i < 0 or i >= TypeGenMixin.TRACE_MAX:
|
||||
return None
|
||||
entry_size: t.CSizeT = GenTypes.TraceFrame.__sizeof__()
|
||||
addr: t.CUInt64T = t.CUInt64T(self.TraceFrames) + i * entry_size
|
||||
return (GenTypes.TraceFrame | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||||
def push_trace(self, file_name: str, lineno: int, col_start: int = 0, col_end: int = 0) -> None:
|
||||
"""压入一个翻译上下文帧(进入新的翻译作用域时调用)"""
|
||||
if self._ensure_trace_init() == 0:
|
||||
return
|
||||
if self.TraceCount >= TypeGenMixin.TRACE_MAX:
|
||||
return
|
||||
frame: GenTypes.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount)
|
||||
if frame is None:
|
||||
return
|
||||
frame.file_name = file_name
|
||||
frame.lineno = lineno
|
||||
frame.col_start = col_start
|
||||
frame.col_end = col_end
|
||||
self.TraceCount += 1
|
||||
def pop_trace(self) -> None:
|
||||
"""弹出栈顶帧(退出翻译作用域时调用)"""
|
||||
if self.TraceCount <= 0:
|
||||
return
|
||||
self.TraceCount -= 1
|
||||
frame: GenTypes.TraceFrame | t.CPtr = self._get_trace_frame(self.TraceCount)
|
||||
if frame is not None:
|
||||
frame.file_name = None
|
||||
frame.lineno = 0
|
||||
frame.col_start = 0
|
||||
frame.col_end = 0
|
||||
def clear_trace(self) -> None:
|
||||
"""清空调用栈(每个文件翻译开始前调用)"""
|
||||
i: int
|
||||
for i in range(self.TraceCount):
|
||||
frame: GenTypes.TraceFrame | t.CPtr = self._get_trace_frame(i)
|
||||
if frame is not None:
|
||||
frame.file_name = None
|
||||
frame.lineno = 0
|
||||
frame.col_start = 0
|
||||
frame.col_end = 0
|
||||
self.TraceCount = 0
|
||||
def set_temp_dir(self, temp_dir: str) -> None:
|
||||
"""设置全局 temp_dir(统一写入 CallGenBase.TempDir,跨子对象经 Gen 指针)"""
|
||||
self.Gen.CallGenBase.SetTempDir(temp_dir)
|
||||
def get_temp_dir(self) -> str:
|
||||
"""获取全局 temp_dir(从 CallGenBase 读取)"""
|
||||
return self.Gen.CallGenBase.TempDir
|
||||
def set_current_module_sha1(self, sha1: str) -> None:
|
||||
"""设置当前正在编译的模块 SHA1(Phase1 在模块开始翻译前调用)"""
|
||||
self.CurrentModuleSha1 = sha1
|
||||
def _dbg_check_ast_floats(self, mb: memhub.MemBuddy | t.CPtr,
|
||||
tree: ast.AST | t.CPtr, tag: str):
|
||||
"""已移除调试插桩(占位保留签名,避免外部调用引用失败)"""
|
||||
pass
|
||||
def set_generic_context(self, tp_names: list[str] | t.CPtr,
|
||||
type_args: list[str] | t.CPtr):
|
||||
"""设置泛型特化上下文(进入泛型类方法体翻译时调用),嵌套安全
|
||||
|
||||
先压栈当前(外层)上下文,再设置新值。clear_generic_context 弹出恢复,
|
||||
避免嵌套特化/泛型函数翻译退出时清空外层上下文(T.__sizeof__() 回归根因)。
|
||||
"""
|
||||
if self.GenericCtxStack is None:
|
||||
self.GenericCtxStack = stdlib.malloc(8 * 2 * 32)
|
||||
if self.GenericCtxStack is None:
|
||||
self.GenericTpNames = tp_names
|
||||
self.GenericTypeArgs = type_args
|
||||
return
|
||||
self.GenericCtxDepth = 0
|
||||
if self.GenericCtxDepth < 32:
|
||||
self.GenericCtxStack[self.GenericCtxDepth * 2] = t.CSizeT(self.GenericTpNames)
|
||||
self.GenericCtxStack[self.GenericCtxDepth * 2 + 1] = t.CSizeT(self.GenericTypeArgs)
|
||||
self.GenericCtxDepth += 1
|
||||
self.GenericTpNames = tp_names
|
||||
self.GenericTypeArgs = type_args
|
||||
|
||||
def clear_generic_context(self):
|
||||
"""清除泛型特化上下文(离开泛型类方法体翻译时调用),恢复外层而非置 None"""
|
||||
if self.GenericCtxDepth > 0:
|
||||
self.GenericCtxDepth -= 1
|
||||
self.GenericTpNames = (list[str] | t.CPtr)(t.CVoid(
|
||||
self.GenericCtxStack[self.GenericCtxDepth * 2], t.CPtr))
|
||||
self.GenericTypeArgs = (list[str] | t.CPtr)(t.CVoid(
|
||||
self.GenericCtxStack[self.GenericCtxDepth * 2 + 1], t.CPtr))
|
||||
else:
|
||||
self.GenericTpNames = None
|
||||
self.GenericTypeArgs = None
|
||||
def resolve_generic_type_name(self, name: str) -> str:
|
||||
"""如果 name 是泛型类型参数,返回对应的具体类型名;否则返回 name 本身
|
||||
|
||||
用于表达式中的 T 替换(如 T.__sizeof__() → int.__sizeof__())
|
||||
"""
|
||||
if name is None:
|
||||
return name
|
||||
rv_d: str = name
|
||||
if self.GenericTpNames is not None and self.GenericTypeArgs is not None:
|
||||
rg_n: t.CSizeT = len(self.GenericTpNames)
|
||||
rg_i: t.CSizeT
|
||||
for rg_i in range(rg_n):
|
||||
rg_tpn: str = self.GenericTpNames.get(rg_i)
|
||||
if rg_tpn is not None and string.strcmp(name, rg_tpn) == 0:
|
||||
rg_ta: str = self.GenericTypeArgs.get(rg_i)
|
||||
if rg_ta is not None:
|
||||
rv_d = rg_ta
|
||||
break
|
||||
return rv_d
|
||||
@@ -1,298 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
import lib.core.Gen.TypeGenBase as TypeGenBase
|
||||
|
||||
# ============================================================
|
||||
# TypeGenCDef - TypeGenMixin 拆分(阶段 D):CDefine 编译期常量表(register/lookup/is/set/clear)
|
||||
#
|
||||
# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
"""CDefine 编译期常量表(register/lookup/is/set/clear)"""
|
||||
|
||||
def register_cdefine_constant(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, value: t.CInt64T) -> None:
|
||||
"""注册 CDefine 编译期常量到本地表
|
||||
|
||||
值以十进制字符串存储(64 位 %lld)。大整数 CDefine(如
|
||||
sys.maxsize = 9223372036854775807)必须全精度保存,否则 %d 32 位截断
|
||||
成 -1(0xFFFFFFFF)→ 读回 4294967295(SysLibTest maxsize FAIL 根因)。
|
||||
0xFFFFFFFF 仍存为 "4294967295",常量生成端 const_int32 内部截断回 -1。
|
||||
"""
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self.CDefineNames.append(name)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
viperlib.snprintf(val_buf, 32, "%lld", value)
|
||||
self.CDefineValues.append(val_buf)
|
||||
else:
|
||||
self.CDefineValues.append("0")
|
||||
if self.CDefineDoubleFlags is not None:
|
||||
self.CDefineDoubleFlags.append(0)
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.append(0)
|
||||
def register_cdefine_double(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, value: double) -> None:
|
||||
"""注册浮点 CDefine 编译期常量(如 U_M_PI: t.CDefine = 3.14159...)
|
||||
|
||||
值以 %f 文本存储并标记浮点,供 translate_value 返回浮点常量。
|
||||
"""
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self.CDefineNames.append(name)
|
||||
val_buf: str = pool.alloc(32)
|
||||
if val_buf is not None:
|
||||
# 用 CRT stdio.snprintf 而非 viperlib.snprintf:viperlib 自实现格式化器的
|
||||
# %g 浮点路径有 bug(%.17g 输出错误值,如 pi 显示 3.1397985 而非 3.1415926,
|
||||
# 位模式 %a 正确),会导致 CDefine 表存错文本 → lookup 生成错 LLVM 常量。
|
||||
stdio.snprintf(val_buf, 32, "%.17g", value)
|
||||
self.CDefineValues.append(val_buf)
|
||||
else:
|
||||
self.CDefineValues.append("0")
|
||||
if self.CDefineDoubleFlags is not None:
|
||||
self.CDefineDoubleFlags.append(1)
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.append(0)
|
||||
# fail-fast:CDefine 值缓冲区分配失败必须终止编译,
|
||||
if val_buf is None:
|
||||
VLogger.error("CDefine 浮点值缓冲区分配失败", "CDEF-DBG")
|
||||
self.Gen.TypeGenErr.fatal_error(None, "CDefine 浮点值缓冲区分配失败", "MemoryError")
|
||||
def register_cdefine_string(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, value: str) -> None:
|
||||
"""注册字符串 CDefine 编译期常量(如 ZLIB_VERSION: t.CDefine = "1.3.2")
|
||||
|
||||
字符串值深拷贝到 pool(AST 节点的 str_val 可能被 pool 操作覆写,
|
||||
与浮点 CDefine 的恢复同理)。
|
||||
"""
|
||||
if pool is None or name is None:
|
||||
return
|
||||
if value is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串值缺失: {name}", "InternalCompilerError")
|
||||
return
|
||||
if self.CDefineNames is None:
|
||||
self.CDefineNames = list[str](pool, 64)
|
||||
self.CDefineValues = list[str](pool, 64)
|
||||
self.CDefineDoubleFlags = list[int](pool, 64)
|
||||
self.CDefineStrFlags = list[int](pool, 64)
|
||||
self.CDefineNames.append(name)
|
||||
vlen: t.CSizeT = string.strlen(value)
|
||||
vcopy: str = pool.alloc(vlen + 1)
|
||||
if vcopy is None:
|
||||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 字符串值分配失败: {name}", "MemoryError")
|
||||
return
|
||||
string.strcpy(vcopy, value)
|
||||
self.CDefineValues.append(vcopy)
|
||||
if self.CDefineDoubleFlags is not None:
|
||||
self.CDefineDoubleFlags.append(0)
|
||||
if self.CDefineStrFlags is not None:
|
||||
self.CDefineStrFlags.append(1)
|
||||
# 同步设置"最近注册/查表结果为字符串"标志(is_cdefine_str() 读取)。
|
||||
# 跨模块字符串 CDefine 读回(_lookup_cross_module_cdefine 字符串分支只调
|
||||
# 本函数 + 尾部 set_cdefine_found,无 lookup_cdefine_string 回查)→ 若此处
|
||||
# 不设标志,属性路径 is_cdefine_str()==0 → 退化为整数分支返回 0 →
|
||||
# IR 生成 inttoptr i32 0(NULL)→ 运行时报 (null-) + strlen(NULL-) 崩溃
|
||||
# (test_pyzlib.vp pyzlib.ZLIB_VERSION 根因)。
|
||||
self.CDefineIsStr = 1
|
||||
self.CDefineFound = 1
|
||||
# ============================================================
|
||||
# 跨模块 CDefine 查找缓存(perm_pool 永久分配,跨文件复用)
|
||||
# ============================================================
|
||||
def register_xmod_cdefine(self, name: str, value_str: str,
|
||||
is_double: int, is_str: int) -> None:
|
||||
"""注册跨模块 CDefine 查找结果到 perm_pool 全局缓存(跨文件复用)
|
||||
|
||||
Args:
|
||||
name: CDefine 常量名(如 CONST_INT)
|
||||
value_str: 值文本(十进制/浮点/字符串)
|
||||
is_double: 1=浮点值
|
||||
is_str: 1=字符串值
|
||||
"""
|
||||
if name is None or value_str is None:
|
||||
return
|
||||
# 去重:同名已缓存则跳过(首次查找结果为准,CDefine 全局唯一约定)
|
||||
if self.XmodCdefNames is not None:
|
||||
x_n: t.CSizeT = len(self.XmodCdefNames)
|
||||
x_i: t.CSizeT
|
||||
for x_i in range(x_n):
|
||||
x_nm: str = self.XmodCdefNames.get(x_i)
|
||||
if x_nm is not None and string.strcmp(x_nm, name) == 0:
|
||||
return
|
||||
perm: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||||
if self.XmodCdefNames is None:
|
||||
self.XmodCdefNames = list[str](perm, 64)
|
||||
self.XmodCdefValues = list[str](perm, 64)
|
||||
self.XmodCdefDoubleFlags = list[int](perm, 64)
|
||||
self.XmodCdefStrFlags = list[int](perm, 64)
|
||||
# key/value 深拷贝到 perm_pool:入参(pool.alloc 临时缓冲)在
|
||||
# reset_to(mark2) 后悬空,append 只存指针 → 必须深拷贝跨 reset 存活
|
||||
klen: t.CSizeT = string.strlen(name)
|
||||
kcopy: str = perm.alloc(klen + 1)
|
||||
if kcopy is None:
|
||||
return
|
||||
string.strcpy(kcopy, name)
|
||||
vlen: t.CSizeT = string.strlen(value_str)
|
||||
vcopy: str = perm.alloc(vlen + 1)
|
||||
if vcopy is None:
|
||||
return
|
||||
string.strcpy(vcopy, value_str)
|
||||
self.XmodCdefNames.append(kcopy)
|
||||
self.XmodCdefValues.append(vcopy)
|
||||
if self.XmodCdefDoubleFlags is not None:
|
||||
self.XmodCdefDoubleFlags.append(is_double)
|
||||
if self.XmodCdefStrFlags is not None:
|
||||
self.XmodCdefStrFlags.append(is_str)
|
||||
def lookup_xmod_cdefine(self, name: str) -> str:
|
||||
"""查找跨模块 CDefine 缓存,命中设置 found/is_double/is_str 标志
|
||||
|
||||
Returns:
|
||||
值文本(命中),未命中返回 None
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if name is None or self.XmodCdefNames is None:
|
||||
return None
|
||||
n: t.CSizeT = len(self.XmodCdefNames)
|
||||
i: t.CSizeT
|
||||
for i in range(n):
|
||||
nm: str = self.XmodCdefNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.XmodCdefValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
if self.XmodCdefStrFlags is not None and self.XmodCdefStrFlags.get(i) == 1:
|
||||
self.CDefineIsStr = 1
|
||||
elif self.XmodCdefDoubleFlags is not None and self.XmodCdefDoubleFlags.get(i) == 1:
|
||||
self.CDefineIsDouble = 1
|
||||
return val_str
|
||||
return None
|
||||
def lookup_cdefine_constant(self, name: str) -> t.CInt64T:
|
||||
"""查找 CDefine 编译期常量
|
||||
|
||||
返回找到的值(64 位,大整数 CDefine 如 sys.maxsize 全精度)。
|
||||
由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1),
|
||||
用全局 _g_cdefine_found 标志区分"未找到"和值为 -1。
|
||||
调用方应在调用后检查 _g_cdefine_found。
|
||||
浮点 CDefine 项返回整数部分(与 _g_cdefine_is_double 标志配合)。
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None:
|
||||
return 0
|
||||
n: t.CSizeT = len(self.CDefineNames)
|
||||
i: t.CSizeT
|
||||
for i in range(n):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1:
|
||||
# 字符串 CDefine(如 ZLIB_VERSION="1.3.2"):整数查询路径
|
||||
# 标记 is_str,调用方改用 lookup_cdefine_string 取字符串。
|
||||
self.CDefineIsStr = 1
|
||||
return 0
|
||||
if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1:
|
||||
self.CDefineIsDouble = 1
|
||||
return string.atoll(val_str)
|
||||
return string.atoll(val_str)
|
||||
return 0
|
||||
def lookup_cdefine_double(self, name: str) -> double:
|
||||
"""查找 CDefine 编译期常量,返回 double 值(浮点/整数统一)
|
||||
|
||||
与 lookup_cdefine_constant 共享 _g_cdefine_found / _g_cdefine_is_double
|
||||
(found=1 且 is_double=1 → 浮点 CDefine,应返回浮点常量)。
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None:
|
||||
return 0.0
|
||||
n: t.CSizeT = len(self.CDefineNames)
|
||||
i: t.CSizeT
|
||||
for i in range(n):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1:
|
||||
self.CDefineIsStr = 1
|
||||
return 0.0
|
||||
if self.CDefineDoubleFlags is not None and self.CDefineDoubleFlags.get(i) == 1:
|
||||
self.CDefineIsDouble = 1
|
||||
ret_d: double = string.atof(val_str)
|
||||
return ret_d
|
||||
ret_i2: double = double(string.atoll(val_str))
|
||||
return ret_i2
|
||||
return 0.0
|
||||
def lookup_cdefine_string(self, name: str) -> str:
|
||||
"""查找 CDefine 编译期字符串值(found=1 且 is_str=1 时有效)
|
||||
|
||||
返回的字符串指针位于 pool 内(当前模块生命周期内有效),
|
||||
调用方应尽快用于 create_global_string 拷贝到 LLVM 常量。
|
||||
"""
|
||||
self.CDefineFound = 0
|
||||
self.CDefineIsDouble = 0
|
||||
self.CDefineIsStr = 0
|
||||
if self.CDefineNames is None:
|
||||
return None
|
||||
n: t.CSizeT = len(self.CDefineNames)
|
||||
i: t.CSizeT
|
||||
for i in range(n):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
val_str: str = self.CDefineValues.get(i)
|
||||
if val_str is not None:
|
||||
self.CDefineFound = 1
|
||||
if self.CDefineStrFlags is not None and self.CDefineStrFlags.get(i) == 1:
|
||||
self.CDefineIsStr = 1
|
||||
return val_str
|
||||
return val_str
|
||||
return None
|
||||
def is_cdefine_str(self) -> int:
|
||||
"""检查最近一次 CDefine 查找命中的是否是字符串常量"""
|
||||
return self.CDefineIsStr
|
||||
def is_cdefine_double(self) -> int:
|
||||
"""检查最近一次 CDefine 查找命中的是否是浮点常量"""
|
||||
return self.CDefineIsDouble
|
||||
def is_cdefine_found(self) -> int:
|
||||
"""检查上次 lookup_cdefine_constant 是否找到值"""
|
||||
return self.CDefineFound
|
||||
def set_cdefine_found(self, val: int) -> None:
|
||||
"""设置 cdefine_found 标志(供跨模块查找函数使用)"""
|
||||
self.CDefineFound = val
|
||||
def clear_cdefine_constants(self) -> None:
|
||||
"""清空 CDefine 常量表(模块切换时调用)"""
|
||||
self.CDefineNames = None
|
||||
self.CDefineValues = None
|
||||
self.CDefineDoubleFlags = None
|
||||
self.CDefineStrFlags = None
|
||||
self.CDefineIsStr = 0
|
||||
@@ -1,423 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
import lib.core.Gen.TypeGenBase as TypeGenBase
|
||||
|
||||
# ============================================================
|
||||
# TypeGenCType - TypeGenMixin 拆分(阶段 D):CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr)
|
||||
#
|
||||
# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
"""CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr)"""
|
||||
|
||||
def register_ctypedef(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, type_str: str) -> None:
|
||||
"""注册 CTypedef 到本地表
|
||||
|
||||
Args:
|
||||
pool: 内存池
|
||||
name: CTypedef 名称(如 "HANDLE")
|
||||
type_str: 类型表达式字符串(如 "VOIDPTR" 或 "t.CVoid | t.CPtr")
|
||||
"""
|
||||
if name is None or type_str is None or pool is None:
|
||||
return
|
||||
if self.CTypedefNames is None:
|
||||
self.CTypedefNames = list[str](pool, 64)
|
||||
self.CTypedefTypeStrs = list[str](pool, 64)
|
||||
# 去重:若已存在同名 CTypedef,更新其类型字符串
|
||||
if self.CTypedefNames is not None:
|
||||
exist_n: t.CSizeT = len(self.CTypedefNames)
|
||||
ei: t.CSizeT
|
||||
for ei in range(exist_n):
|
||||
en: str = self.CTypedefNames.get(ei)
|
||||
if en is not None and string.strcmp(en, name) == 0:
|
||||
# 已存在,更新类型字符串
|
||||
self.CTypedefTypeStrs.set(ei, type_str)
|
||||
return
|
||||
self.CTypedefNames.append(name) # 存疑
|
||||
self.CTypedefTypeStrs.append(type_str)
|
||||
def lookup_ctypedef(self, name: str) -> str:
|
||||
"""查找 CTypedef,返回类型表达式字符串
|
||||
|
||||
返回找到的类型表达式字符串,未找到返回 None。
|
||||
调用方应在调用后检查 _g_ctypedef_found 标志区分"未找到"和"空字符串"。
|
||||
"""
|
||||
self.CTypedefFound = 0
|
||||
if name is None:
|
||||
return None
|
||||
if self.CTypedefNames is None:
|
||||
return None
|
||||
n: t.CSizeT = len(self.CTypedefNames)
|
||||
i: t.CSizeT
|
||||
for i in range(n):
|
||||
nm: str = self.CTypedefNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
ts: str = self.CTypedefTypeStrs.get(i)
|
||||
self.CTypedefFound = 1
|
||||
return ts
|
||||
return None
|
||||
def is_ctypedef_found(self) -> int:
|
||||
"""检查上次 lookup_ctypedef 是否找到值"""
|
||||
return self.CTypedefFound
|
||||
def clear_ctypedefs(self) -> None:
|
||||
"""清空 CTypedef 表(模块切换时调用)"""
|
||||
self.CTypedefNames = None
|
||||
self.CTypedefTypeStrs = None
|
||||
self.CTypedefResolveDepth = 0
|
||||
self.CTypedefVisiting = None
|
||||
def _ctypedef_push_visiting(self, pool: memhub.MemBuddy | t.CPtr, name: str) -> int:
|
||||
"""将 CTypedef 名加入正在解析列表(循环检测)
|
||||
|
||||
Returns:
|
||||
0=成功加入(无循环),1=检测到循环
|
||||
"""
|
||||
if name is None:
|
||||
return 0
|
||||
if self.CTypedefVisiting is None:
|
||||
self.CTypedefVisiting = list[str](pool, 32)
|
||||
if self.CTypedefVisiting is None:
|
||||
return 0
|
||||
vn: t.CSizeT = len(self.CTypedefVisiting)
|
||||
vi: t.CSizeT
|
||||
for vi in range(vn):
|
||||
vs: str = self.CTypedefVisiting.get(vi)
|
||||
if vs is not None and string.strcmp(vs, name) == 0:
|
||||
return 1 # 循环检测
|
||||
self.CTypedefVisiting.append(name)
|
||||
return 0
|
||||
def _ctypedef_pop_visiting(self) -> None:
|
||||
"""从正在解析列表弹出最后一个 CTypedef 名"""
|
||||
if self.CTypedefVisiting is None:
|
||||
return
|
||||
vn: t.CSizeT = len(self.CTypedefVisiting)
|
||||
if vn > 0:
|
||||
self.CTypedefVisiting.pop()
|
||||
def _is_ctypedef_annotation(self, annotation: ast.AST | t.CPtr) -> int:
|
||||
"""检测类型注解是否为 t.CTypedef
|
||||
|
||||
Args:
|
||||
annotation: 类型注解 AST 节点
|
||||
|
||||
Returns:
|
||||
1=是 t.CTypedef,0=否
|
||||
"""
|
||||
if annotation is None:
|
||||
return 0
|
||||
k_v: int = annotation.kind()
|
||||
if k_v != ast.ASTKind.Attribute:
|
||||
return 0
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annotation)
|
||||
# 字段访问改用 ast 模块访问器(跨模块 stub 字段访问陷阱防护:
|
||||
# TypeGenCType 直接访问 at.attr 可能按 stub 类型生成错误 GEP,
|
||||
# 读垃圾地址 → strcmp 0xC0000005 崩溃,stdint.vp 根因)。
|
||||
at_attr_v: str = ast.attribute_get_attr(at)
|
||||
if at_attr_v is None:
|
||||
return 0
|
||||
# 限长比较替代 strcmp:attr 是零拷贝引用 src_buf 的 token 字符串,
|
||||
# 可能无 NUL 结尾("CTypedef" 后紧跟空格/其他字符),strcmp 会
|
||||
# 无限读穿到页边界 → 0xC0000005(stdint.vp 崩溃根因)。strncmp
|
||||
# 只读 8 字节,再校验第 9 字节为终止/分隔符(防 "CTypedefXXX" 误匹配)。
|
||||
if string.strncmp(at_attr_v, "CTypedef", 8) != 0:
|
||||
return 0
|
||||
sep_ch_d: t.CChar = at_attr_v[8]
|
||||
if sep_ch_d != '\0' and sep_ch_d != ' ' and sep_ch_d != '\n' \
|
||||
and sep_ch_d != '\r' and sep_ch_d != '\t' and sep_ch_d != '|':
|
||||
return 0
|
||||
at_val_v: ast.AST | t.CPtr = ast.attribute_get_value(at)
|
||||
if at_val_v is None or at_val_v.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_val_v)
|
||||
mod_id_v: str = ast.name_get_id(mod_nm)
|
||||
if mod_id_v is None:
|
||||
return 0
|
||||
# 同样限长比较("t" 无 NUL 结尾时 strcmp 读穿)
|
||||
if string.strncmp(mod_id_v, "t", 1) != 0:
|
||||
return 0
|
||||
sep_ch_m: t.CChar = mod_id_v[1]
|
||||
if sep_ch_m != '\0' and sep_ch_m != ' ' and sep_ch_m != '\n' \
|
||||
and sep_ch_m != '\r' and sep_ch_m != '\t' and sep_ch_m != '|':
|
||||
return 0
|
||||
return 1
|
||||
def ScanCTypedefDeclarations(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
tree: ast.AST | t.CPtr) -> int:
|
||||
"""扫描 AST 顶层节点,注册所有 NAME: t.CTypedef = Type 声明
|
||||
|
||||
在 _translate_module_level 中、模块级变量预注册之前调用,
|
||||
确保 CTypedef 名称在类型解析时可用。
|
||||
|
||||
Args:
|
||||
pool: 内存池
|
||||
tree: 模块 AST 根节点
|
||||
|
||||
Returns:
|
||||
注册的 CTypedef 数量
|
||||
"""
|
||||
if pool is None or tree is None:
|
||||
return 0
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is None:
|
||||
return 0
|
||||
n: t.CSizeT = len(ch)
|
||||
count: int = 0
|
||||
i: t.CSizeT
|
||||
for i in range(n):
|
||||
child: ast.AST | t.CPtr = ch.get(i)
|
||||
if child is None:
|
||||
continue
|
||||
if child.kind() != ast.ASTKind.AnnAssign:
|
||||
continue
|
||||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(child)
|
||||
if aa.annotation is None:
|
||||
continue
|
||||
# 检测注解是否为 t.CTypedef
|
||||
if self._is_ctypedef_annotation(aa.annotation) == 0:
|
||||
continue
|
||||
# 提取目标名称(必须是 Name 节点)
|
||||
if aa.target is None or aa.target.kind() != ast.ASTKind.Name:
|
||||
continue
|
||||
tgt: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
|
||||
tgt_id_v: str = ast.name_get_id(tgt)
|
||||
if tgt_id_v is None:
|
||||
continue
|
||||
# 提取类型表达式字符串(从 value AST 节点)
|
||||
if aa.value is None:
|
||||
continue
|
||||
type_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, aa.value)
|
||||
if type_str is None:
|
||||
continue
|
||||
# 注册 CTypedef
|
||||
self.register_ctypedef(pool, tgt_id_v, type_str)
|
||||
count += 1
|
||||
return count
|
||||
def register_ctypedef_from_source(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
src: str) -> int:
|
||||
"""从源码文本逐行扫描注册 CTypedef(NAME: t.CTypedef = TYPE)
|
||||
|
||||
stdint.vp 崩溃根因修复:AST 字符串字段(attr/id)token 零拷贝指向
|
||||
src_buf,跨阶段内容不稳定(悬空),ScanCTypedefDeclarations 读
|
||||
attr 会 0xC0000005。本函数在 src_buf 有效期内(Phase1 1b translate
|
||||
前)用纯文本匹配注册,不依赖 AST 节点内容。
|
||||
"""
|
||||
if pool is None or src is None:
|
||||
return 0
|
||||
# 文件边界防护:clear_ctypedefs 只在 translate 前调用(Phase1Main
|
||||
# L800),文件级 reset_to(mark1) 回收本文件翻译期 pool 分配后,上一
|
||||
# 文件的 CTypedefNames 表指针悬空(非 None,list 本身也 pool 分配)。
|
||||
# 本函数去重遍历(register_ctypedef 内 strcmp)读已回收内存 →
|
||||
# 0xC0000005(1.log: stdint.vp 翻译时 strcmp 读地址 0x4)。先清表
|
||||
# 重建,杜绝悬空遍历。翻译期 Handle 按需注册不受影响(L800 会再清)。
|
||||
self.clear_ctypedefs()
|
||||
src_len: t.CSizeT = string.strlen(src)
|
||||
count: int = 0
|
||||
line_start: t.CSizeT = 0
|
||||
i: t.CSizeT = 0
|
||||
while i <= src_len:
|
||||
if i == src_len or src[i] == '\n':
|
||||
line_len: t.CSizeT = i - line_start
|
||||
if line_len > 0:
|
||||
# 找行内第一个 ':'(跳过注释行)
|
||||
j: t.CSizeT = 0
|
||||
found_colon: int = 0
|
||||
while j < line_len:
|
||||
ch_c: t.CChar = src[line_start + j]
|
||||
if ch_c == ':':
|
||||
found_colon = 1
|
||||
break
|
||||
if ch_c == '#' or ch_c == '\r':
|
||||
break
|
||||
j += 1
|
||||
if found_colon != 0:
|
||||
# 左段 NAME(trim 尾随空格)
|
||||
name_len: t.CSizeT = j
|
||||
while name_len > 0 and src[line_start + name_len - 1] == ' ':
|
||||
name_len -= 1
|
||||
if name_len > 0 and name_len < 128:
|
||||
# 右段必须含 "t.CTypedef"
|
||||
rest: str = src + line_start + j + 1
|
||||
if string.strstr(rest, "t.CTypedef") is not None:
|
||||
# 提取 "=" 后的类型表达式(trim 空格)
|
||||
eq_ptr: str = string.strstr(rest, "=")
|
||||
if eq_ptr is not None:
|
||||
ty_start: str = eq_ptr + 1
|
||||
while ty_start[0] == ' ':
|
||||
ty_start += 1
|
||||
ty_end: t.CSizeT = string.strlen(ty_start)
|
||||
while ty_end > 0 and (ty_start[ty_end - 1] == ' '
|
||||
or ty_start[ty_end - 1] == '\r'):
|
||||
ty_end -= 1
|
||||
if ty_end > 0:
|
||||
name_buf: str = pool.alloc(name_len + 1)
|
||||
ty_buf: str = pool.alloc(ty_end + 1)
|
||||
if name_buf is not None and ty_buf is not None:
|
||||
string.strncpy(name_buf, src + line_start, name_len)
|
||||
name_buf[name_len] = '\0'
|
||||
string.strncpy(ty_buf, ty_start, ty_end)
|
||||
ty_buf[ty_end] = '\0'
|
||||
self.register_ctypedef(pool, name_buf, ty_buf)
|
||||
count += 1
|
||||
line_start = i + 1
|
||||
i += 1
|
||||
return count
|
||||
def _eval_const_int_expr(self, node: ast.AST | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr = None,
|
||||
from_imports: str = None,
|
||||
imported_modules: str = None,
|
||||
depth: int = 0) -> int:
|
||||
"""递归计算常量整数表达式
|
||||
|
||||
pool/from_imports/imported_modules:跨模块 CDefine 查找上下文
|
||||
(t.CArray count 引用依赖模块的 CDefine,如 SHA512_BLOCK_LEN 定义在
|
||||
hashlib/__sha512.vp,本地 CDefine 表每模块清空,需跨模块回退查找)。
|
||||
depth:递归深度守卫(防御 AST 损坏成自引用环导致的无限递归——
|
||||
本函数被 resolve_annotation_type 的 t.CArray count 解析调用,其内部
|
||||
BinOp 自递归不经过 resolve_annotation_type 的 depth 守卫)。
|
||||
"""
|
||||
if node is None:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
# 递归深度守卫:BinOp 左右子树成环时无限递归直至栈耗尽。
|
||||
# fail-fast 终止(fatal_type_error → sys.exit(1)),不静默回落。
|
||||
if depth > 64:
|
||||
self.Gen.TypeGenErr.fatal_type_error(node, "常量表达式递归过深(AST 环或嵌套超过 64 层)")
|
||||
k: int = node.kind()
|
||||
|
||||
# Constant: 整数字面量
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||
if cn.const_kind == ast.CONST_INT:
|
||||
self.ConstEvalOk = 1
|
||||
return cn.int_val
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
# Name: CDefine 常量名(本地表优先,未命中走跨模块查找)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm.id is None:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
val: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm.id)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() == 0:
|
||||
# 本地表未命中:跨模块 CDefine 查找
|
||||
# 用 HandlesExpr 模块级委托(self._lookup_cross_module_cdefine 是
|
||||
# ExprGenMixin 方法,TypeGenMixin 直接调用会生成未定义引用)
|
||||
if (from_imports is not None or imported_modules is not None) \
|
||||
and pool is not None:
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
x_val: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(
|
||||
pool, nm.id, from_imports, imported_modules)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
self.ConstEvalOk = 1
|
||||
return x_val
|
||||
# 定位日志:跨模块 CDefine 查找失败(t.CArray count 场景)
|
||||
fb_cdf: str = VLogger.fmt_buf()
|
||||
if fb_cdf is not None:
|
||||
viperlib.snprintf(fb_cdf, 1024,
|
||||
"[CDEF-MISS] name=%s fi=%s im=%s",
|
||||
nm.id,
|
||||
from_imports if from_imports is not None else "(null)",
|
||||
imported_modules if imported_modules is not None else "(null)")
|
||||
VLogger.error(fb_cdf, "CDEF")
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
self.ConstEvalOk = 1
|
||||
return val
|
||||
|
||||
# Attribute: 模块限定常量名,如 hashlib.MD5_DIGEST_LEN
|
||||
# (t.CArray[t.CUInt8T, hashlib.MD5_DIGEST_LEN] 的 count 是 Attribute,
|
||||
# 复用跨模块 CDefine 查找:*:模块 → 源文件提取;re-export 常量由
|
||||
# _lookup_cross_module_cdefine 的 from-import 递归子模块兜底)
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
if at.attr is None:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
at_mod: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if at_mod.id is not None:
|
||||
if (from_imports is not None or imported_modules is not None) \
|
||||
and pool is not None:
|
||||
mod_len: t.CSizeT = string.strlen(at_mod.id)
|
||||
fi_buf: str = pool.alloc(mod_len + 3)
|
||||
if fi_buf is not None:
|
||||
fi_buf[0] = '*'
|
||||
fi_buf[1] = ':'
|
||||
for mi in range(mod_len):
|
||||
fi_buf[2 + mi] = at_mod.id[mi]
|
||||
fi_buf[2 + mod_len] = '\0'
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
av: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(
|
||||
pool, at.attr, fi_buf, imported_modules)
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
self.ConstEvalOk = 1
|
||||
return av
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
# BinOp: 算术/位运算
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
# 递归计算左操作数
|
||||
lv: int = self._eval_const_int_expr(bop.left, pool, from_imports, imported_modules, depth + 1)
|
||||
if self.ConstEvalOk == 0:
|
||||
return 0
|
||||
# 递归计算右操作数
|
||||
rv: int = self._eval_const_int_expr(bop.right, pool, from_imports, imported_modules, depth + 1)
|
||||
if self.ConstEvalOk == 0:
|
||||
return 0
|
||||
# 根据运算符执行计算
|
||||
if bop.op == ast.OpKind.Add:
|
||||
self.ConstEvalOk = 1
|
||||
return lv + rv
|
||||
if bop.op == ast.OpKind.Sub:
|
||||
self.ConstEvalOk = 1
|
||||
return lv - rv
|
||||
if bop.op == ast.OpKind.Mult:
|
||||
self.ConstEvalOk = 1
|
||||
return lv * rv
|
||||
if bop.op == ast.OpKind.Div:
|
||||
# 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355)
|
||||
if rv == 0:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
self.ConstEvalOk = 1
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.FloorDiv:
|
||||
if rv == 0:
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
self.ConstEvalOk = 1
|
||||
return lv // rv
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
self.ConstEvalOk = 1
|
||||
return lv | rv
|
||||
if bop.op == ast.OpKind.BitAnd:
|
||||
self.ConstEvalOk = 1
|
||||
return lv & rv
|
||||
# 不支持的运算符
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
# 不支持的节点类型
|
||||
self.ConstEvalOk = 0
|
||||
return 0
|
||||
|
||||
@@ -1,396 +0,0 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.Generator as Generator
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
|
||||
import lib.core.Gen.TypeGenBase as TypeGenBase
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenErr - TypeGenMixin 拆分(阶段 D):错误上报/源行读取/类型推断(fatal_error/infer_* 等)
|
||||
#
|
||||
# 继承 TypeGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||||
# 跨 Mixin 调用统一走 HandlesType 委托(经 _g_gen)。
|
||||
# @t.NoVTable:静态绑定。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class TypeGenErr(TypeGenBase.TypeGenBase):
|
||||
"""错误上报/源行读取/类型推断(fatal_error/infer_* 等)"""
|
||||
|
||||
def _read_source_line(self, file_path: str, lineno: int) -> str:
|
||||
"""从源文件读取第 lineno 行内容"""
|
||||
if file_path is None or lineno <= 0:
|
||||
return None
|
||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
return None
|
||||
# 按文件实际大小分配缓冲区:固定 256KB 会截断大源文件,末尾行号读不到 →
|
||||
# 误报"文件不存在或行号超出范围"(如 CallGenMixin.vp 555KB/9236 行的第
|
||||
# 8390 行)。64MB 上限防御异常超大文件整体读取。
|
||||
fsize: LONGLONG = f.size()
|
||||
if fsize <= 0 or fsize > 67108864:
|
||||
f.close()
|
||||
return None
|
||||
src_size: t.CSizeT = t.CSizeT(fsize)
|
||||
buf: bytes = stdlib.malloc(src_size + 1)
|
||||
if buf is None:
|
||||
f.close()
|
||||
return None
|
||||
bytes_read: LONG = f.read_all(buf, ULONG(src_size + 1))
|
||||
f.close()
|
||||
if bytes_read <= 0:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
# 逐行查找第 lineno 行
|
||||
cur_line: int = 1
|
||||
line_start: t.CSizeT = 0
|
||||
for i in range(bytes_read):
|
||||
if buf[i] == '\n':
|
||||
if cur_line == lineno:
|
||||
line_len: t.CSizeT = i - line_start
|
||||
if line_len > 0 and buf[line_start + line_len - 1] == '\r':
|
||||
line_len -= 1
|
||||
line_buf: bytes = stdlib.malloc(line_len + 1)
|
||||
if line_buf is not None:
|
||||
string.strncpy(line_buf, buf + line_start, line_len)
|
||||
line_buf[line_len] = '\0'
|
||||
stdlib.free(buf)
|
||||
return line_buf
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
cur_line += 1
|
||||
line_start = i + 1
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
def read_source_line(self, file_path: str, lineno: int) -> str:
|
||||
"""公开包装:从源文件读取第 lineno 行内容(供 traceback 展示)"""
|
||||
return self._read_source_line(file_path, lineno)
|
||||
def dump_parse_traceback(self, file_path: str) -> None:
|
||||
"""解析失败时以 Python 风格输出 traceback(仿 fatal_error)"""
|
||||
err_line: int = ast.get_parse_err_line()
|
||||
err_col: int = ast.get_parse_err_col()
|
||||
err_msg: str = ast.get_parse_err_msg()
|
||||
stdio.printf("Traceback (most recent call last):\n")
|
||||
if file_path is None or file_path[0] == 0:
|
||||
file_path = "<unknown>"
|
||||
if err_line > 0:
|
||||
stdio.printf(' File "%s", line %d\n', file_path, err_line)
|
||||
src: str = self._read_source_line(file_path, err_line)
|
||||
if src is not None:
|
||||
stdio.printf(" %s\n", src)
|
||||
# 列标记:在出错 token 起始列下方标 ^(parser 的 col_offset 是 0-based,
|
||||
# 前缀 4 空格 + err_col 个空格后落点恰好是该 token 首字符)
|
||||
if err_col > 0:
|
||||
stdio.printf(" ")
|
||||
c: int
|
||||
for c in range(err_col):
|
||||
stdio.printf(" ")
|
||||
stdio.printf("^\n")
|
||||
stdlib.free(src)
|
||||
else:
|
||||
stdio.printf(' File "%s"\n', file_path)
|
||||
if err_msg is None or err_msg[0] == 0:
|
||||
err_msg = "语法错误"
|
||||
stdio.printf("SyntaxError: %s\n", err_msg)
|
||||
def fatal_error(self, node: ast.AST | t.CPtr, msg: str,
|
||||
err_type: str = "SyntaxError",
|
||||
col_start: int = 0, col_end: int = 0):
|
||||
"""以 Python 风格报错并退出(支持多帧、错误类型、列范围)
|
||||
|
||||
向后兼容:err_type/col_start/col_end 有默认值,旧调用 fatal_error(node, msg) 仍可用。
|
||||
"""
|
||||
stdio.printf("Traceback (most recent call last):\n")
|
||||
# 输出调用栈帧(从底到顶)
|
||||
i: int
|
||||
for i in range(self.Gen.TypeGenBase.TraceCount):
|
||||
frame: GenTypes.TraceFrame | t.CPtr = self.Gen.TypeGenBase._get_trace_frame(i)
|
||||
if frame is not None and frame.file_name is not None:
|
||||
if frame.lineno > 0:
|
||||
stdio.printf(' File "%s", line %d\n', frame.file_name, frame.lineno)
|
||||
src: str = self._read_source_line(frame.file_name, frame.lineno)
|
||||
if src is not None:
|
||||
stdio.printf(" %s\n", src)
|
||||
stdlib.free(src)
|
||||
else:
|
||||
stdio.printf(' File "%s"\n', frame.file_name)
|
||||
# 输出当前帧(node 对应的位置)
|
||||
lineno: int = 0
|
||||
if node is not None:
|
||||
lineno = node.lineno
|
||||
file_name: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if file_name is None:
|
||||
file_name = "<unknown>"
|
||||
# 行号兜底:克隆/构造节点 lineno 可能为 0(如泛型特化 _clone_arguments 的
|
||||
# ast.Arg 构造器硬编码 0,astaux.vp L139)。此时回退到 trace 栈最后一个
|
||||
# 有效帧(文件+行号)作为出错位置,避免输出误导性的 "line 0"。
|
||||
if lineno <= 0 and self.Gen.TypeGenBase.TraceCount > 0:
|
||||
ti_b: int = self.Gen.TypeGenBase.TraceCount - 1
|
||||
while ti_b >= 0:
|
||||
tfb: GenTypes.TraceFrame | t.CPtr = self.Gen.TypeGenBase._get_trace_frame(ti_b)
|
||||
if tfb is not None and tfb.file_name is not None and tfb.lineno > 0:
|
||||
file_name = tfb.file_name
|
||||
lineno = tfb.lineno
|
||||
break
|
||||
ti_b -= 1
|
||||
# 行号合理性防御:先读取该行源码,验证 node.lineno 是否落在当前文件内。
|
||||
# 若读不到(文件不存在或行号超出范围),说明文件/行号归属不可信
|
||||
# (如 AST 树被内存复用/串扰后跨文件报错),打印警告而非误导性行号。
|
||||
src_line: str = None
|
||||
line_ok: int = 1
|
||||
if lineno > 0 and string.strcmp(file_name, "<unknown>") != 0:
|
||||
src_line = self._read_source_line(file_name, lineno)
|
||||
if src_line is None:
|
||||
line_ok = 0
|
||||
if line_ok == 0:
|
||||
stdio.printf(' File "%s", line %d (!! 无法读取该行源码:文件不存在或行号超出范围,错误可能来自被复用的 AST 树,请以错误消息为准)\n',
|
||||
file_name, lineno)
|
||||
else:
|
||||
stdio.printf(' File "%s", line %d\n', file_name, lineno)
|
||||
if src_line is not None:
|
||||
stdio.printf(" %s\n", src_line)
|
||||
# 列范围标记:在源代码行下方用 ^ 标记出错范围
|
||||
if col_start > 0 and col_end >= col_start:
|
||||
stdio.printf(" ")
|
||||
j: int
|
||||
for j in range(col_end):
|
||||
if j >= col_start - 1 and j < col_end:
|
||||
stdio.printf("^")
|
||||
else:
|
||||
stdio.printf(" ")
|
||||
stdio.printf("\n")
|
||||
stdlib.free(src_line)
|
||||
# 输出错误类型 + 消息
|
||||
if err_type is None or err_type[0] == 0:
|
||||
err_type = "SyntaxError"
|
||||
stdio.printf("%s: %s\n", err_type, msg)
|
||||
sys.exit(1)
|
||||
|
||||
def fatal_type_error(self, node: ast.AST | t.CPtr, msg: str,
|
||||
col_start: int = 0, col_end: int = 0):
|
||||
"""以 Python 风格报错并退出(TypeError 版本)"""
|
||||
self.fatal_error(node, msg, "TypeError", col_start, col_end)
|
||||
def try_extract_callable_ret(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
annot: ast.AST | t.CPtr,
|
||||
imported_modules: str,
|
||||
from_imports: str,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""提取 t.Callable 注解的返回类型 LLVMType;非 Callable 注解返回 None"""
|
||||
if annot is None or annot.kind() != ast.ASTKind.Subscript:
|
||||
return None
|
||||
sub_cr: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
|
||||
if sub_cr.value is None or sub_cr.value.kind() != ast.ASTKind.Attribute:
|
||||
return None
|
||||
at_cr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub_cr.value)
|
||||
if at_cr.attr is None or string.strcmp(at_cr.attr, "Callable") != 0:
|
||||
return None
|
||||
# slice 必须是 Tuple(elts=[args_list, ret_node])
|
||||
if sub_cr.slice is None or sub_cr.slice.kind() != ast.ASTKind.Tuple:
|
||||
return None
|
||||
tp_cr: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub_cr.slice)
|
||||
if tp_cr.elts is None or len(tp_cr.elts) != 2:
|
||||
return None
|
||||
ret_node_cr: ast.AST | t.CPtr = tp_cr.elts.get(1)
|
||||
if ret_node_cr is None:
|
||||
return None
|
||||
return self.Gen.TypeGenResolve.resolve_annotation_type(pool, ret_node_cr, imported_modules, from_imports, trans, 0)
|
||||
def has_decorator_marker(self, node: ast.AST | t.CPtr,
|
||||
marker_name: str,
|
||||
depth: int = 0) -> int:
|
||||
"""检测类型注解中是否包含指定的装饰器标记"""
|
||||
if node is None or marker_name is None:
|
||||
return 0
|
||||
# 递归深度守卫:vpi stub 注入时对每个函数 returns 调用本函数,
|
||||
# vpi tree 深层节点可能被覆盖损坏成回指环(VpiReader L810-813),
|
||||
# BinOp 递归无守卫会无限递归直至栈耗尽。fail-fast 终止。
|
||||
if depth > 128:
|
||||
self.fatal_type_error(node, "装饰器标记检测递归过深(AST 环或嵌套超过 128 层)")
|
||||
|
||||
k: int = node.kind()
|
||||
|
||||
# Attribute 节点: t.CExtern, t.State, t.CExport, t.CInline
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||||
if at.attr is not None:
|
||||
if string.strcmp(at.attr, marker_name) == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# BinOp 节点: int | t.CExtern(递归检测左右子节点)
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
if self.has_decorator_marker(bop.left, marker_name, depth + 1) != 0:
|
||||
return 1
|
||||
if self.has_decorator_marker(bop.right, marker_name, depth + 1) != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
return 0
|
||||
def is_pass_body(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> int:
|
||||
"""检测函数体是否为 pass(空体或仅含 pass 语句)"""
|
||||
if body is None:
|
||||
return 1
|
||||
bn: t.CSizeT = len(body)
|
||||
if bn == 0:
|
||||
return 1
|
||||
if bn == 1:
|
||||
stmt: ast.AST | t.CPtr = body.get(0)
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.Pass:
|
||||
return 1
|
||||
return 0
|
||||
def get_llvm_type_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""获取 LLVM 整数类型的位宽,非整数类型返回 0"""
|
||||
if ty is None:
|
||||
return 0
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Int(bits):
|
||||
return bits
|
||||
case _:
|
||||
return 0
|
||||
def infer_expr_type(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
param_types: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""推断表达式的 LLVM 类型
|
||||
|
||||
param_types 格式: "name:bits,name:bits,..."
|
||||
"""
|
||||
if node is None:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
k: int = node.kind()
|
||||
|
||||
if k == ast.ASTKind.Constant:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
elif k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm.id is not None and param_types is not None:
|
||||
# 在 param_types 中查找: "name:bits" 格式
|
||||
search_key: str = pool.alloc(64)
|
||||
if search_key is not None:
|
||||
viperlib.snprintf(search_key, 64, "%s:", nm.id)
|
||||
found: str = string.strstr(param_types, search_key)
|
||||
if found is not None:
|
||||
colon_pos: t.CSizeT = string.strlen(nm.id) + 1
|
||||
bits_str: str = found + colon_pos
|
||||
bits: int = 0
|
||||
for bi in range(4):
|
||||
ch: t.CChar = bits_str[bi]
|
||||
if ch >= '0' and ch <= '9':
|
||||
bits = bits * 10 + (ch - '0')
|
||||
else:
|
||||
break
|
||||
if bits == 64:
|
||||
return llvmlite.Int64(pool)
|
||||
elif bits == 16:
|
||||
return llvmlite.Int16(pool)
|
||||
elif bits == 8:
|
||||
return llvmlite.Int8(pool)
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
elif k == ast.ASTKind.BinOp:
|
||||
binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
lhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type(
|
||||
pool, binop.left, param_types)
|
||||
rhs_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type(
|
||||
pool, binop.right, param_types)
|
||||
lhs_bits: int = self.get_llvm_type_bits(lhs_ty)
|
||||
rhs_bits: int = self.get_llvm_type_bits(rhs_ty)
|
||||
if lhs_bits >= rhs_bits:
|
||||
return lhs_ty
|
||||
return rhs_ty
|
||||
|
||||
return llvmlite.Int32(pool)
|
||||
def infer_return_type(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
param_types: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""扫描函数体中的 return 语句,推断返回类型"""
|
||||
if body is None:
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
bn: t.CSizeT = len(body)
|
||||
for bi in range(bn):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None and stmt.kind() == ast.ASTKind.Return:
|
||||
rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(stmt)
|
||||
if rt.value is not None:
|
||||
expr_ty: llvmlite.LLVMType | t.CPtr = self.infer_expr_type(
|
||||
pool, rt.value, param_types)
|
||||
if expr_ty is not None:
|
||||
cur_bits: int = self.get_llvm_type_bits(ret_ty)
|
||||
new_bits: int = self.get_llvm_type_bits(expr_ty)
|
||||
if new_bits > cur_bits:
|
||||
ret_ty = expr_ty
|
||||
return ret_ty
|
||||
def build_param_types_str(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
args_node: ast.AST | t.CPtr) -> str:
|
||||
"""构建参数类型编码字符串 "name:bits,name:bits,..." """
|
||||
if args_node is None:
|
||||
return None
|
||||
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
|
||||
if ags.args is None:
|
||||
return None
|
||||
alist: list[ast.AST | t.CPtr] | t.CPtr = ags.args
|
||||
an: t.CSizeT = len(alist)
|
||||
if an == 0:
|
||||
return None
|
||||
|
||||
buf_size: t.CSizeT = an * 32 + 1
|
||||
buf: str = pool.alloc(buf_size)
|
||||
if buf is None:
|
||||
return None
|
||||
buf[0] = '\0'
|
||||
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
for ai in range(an):
|
||||
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
|
||||
if arg is not None and arg.arg is not None:
|
||||
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
if arg.annotation is not None:
|
||||
# 直接调用 map_t_type 解析 Attribute 注解
|
||||
if arg.annotation.kind() == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg.annotation)
|
||||
if at.attr is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.map_t_type(pool, at.attr)
|
||||
if resolved is not None:
|
||||
param_ty = resolved
|
||||
bits: int = self.get_llvm_type_bits(param_ty)
|
||||
if bits == 0:
|
||||
bits = 32
|
||||
tmp: str = pool.alloc(32)
|
||||
if tmp is not None:
|
||||
viperlib.snprintf(tmp, 32, "%s:%d", arg.arg, bits)
|
||||
if ai > 0:
|
||||
self._strappend(buf, buf_size, ",")
|
||||
self._strappend(buf, buf_size, tmp)
|
||||
return buf
|
||||
def _strappend(self, dst: str, dst_size: t.CSizeT, src: str):
|
||||
"""将 src 追加到 dst 末尾"""
|
||||
if dst is None or src is None:
|
||||
return
|
||||
dlen: t.CSizeT = string.strlen(dst)
|
||||
slen: t.CSizeT = string.strlen(src)
|
||||
remain: t.CSizeT = dst_size - dlen
|
||||
if remain <= 0:
|
||||
return
|
||||
# 内联 min(slen, remain - 1) 避免 builtin min 未定义(TransPyV 无 builtin min)
|
||||
limit: t.CSizeT = slen
|
||||
cap: t.CSizeT = remain - 1
|
||||
if cap < limit:
|
||||
limit = cap
|
||||
for i in range(limit):
|
||||
dst[dlen + i] = src[i]
|
||||
dst[dlen + i] = '\0' # i 退出值存疑
|
||||
File diff suppressed because it is too large.
Load diff
+1352
-173
File diff suppressed because it is too large.
Load diff
@@ -1,4 +1,4 @@
|
||||
# ============================================================
|
||||
# Gen - 对象化生成器(P1 骨架 + P2 TypeGenMixin)
|
||||
# Generator: 翻译状态容器 + Mixin 组合(BaseGen 状态 + TypeGen 类型映射,
|
||||
# Generator: 翻译状态容器
|
||||
# ============================================================
|
||||
@@ -1,197 +0,0 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.CallGenLeafKit as CallGenLeafKit
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
|
||||
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
|
||||
# ============================================================
|
||||
# ExprCallTable - HandlesExprCall 拆分(阶段 E):ExprCallTable
|
||||
#
|
||||
# 直接移动模式:委托函数迁至此模块,原 HandlesExprCall.vp 仅
|
||||
# 保留 _g_gen/常量/类;调用方经本模块前缀访问。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 初始化函数表
|
||||
# ============================================================
|
||||
def init_func_table(pool: memhub.MemBuddy | t.CPtr,
|
||||
max_count: int) -> GenTypes.FuncEntry | t.CPtr:
|
||||
"""分配并清零函数表数组(委托到 gen.init_func_table)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit.init_func_table(pool, max_count)
|
||||
return None
|
||||
# ============================================================
|
||||
# 查找函数
|
||||
# ============================================================
|
||||
def find_func_in_table(funcs: GenTypes.FuncEntry | t.CPtr,
|
||||
func_count: int,
|
||||
name: str) -> llvmlite.Function | t.CPtr:
|
||||
"""在函数表中按名称查找,返回 Function 指针或 None(委托到 gen.find_func_in_table)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit.find_func_in_table(funcs, func_count, name)
|
||||
return None
|
||||
# ============================================================
|
||||
# 添加函数到函数表
|
||||
# ============================================================
|
||||
def add_func_to_table(funcs: GenTypes.FuncEntry | t.CPtr,
|
||||
func_count: int,
|
||||
name: str,
|
||||
func: llvmlite.Function | t.CPtr,
|
||||
max_count: int,
|
||||
defaults: t.CVoid | t.CPtr = None,
|
||||
default_count: int = 0,
|
||||
param_count: int = 0,
|
||||
pool: memhub.MemBuddy | t.CPtr = None) -> int:
|
||||
"""添加函数到函数表,返回 0 成功(委托到 gen.add_func_to_table)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit.add_func_to_table(funcs, func_count, name, func, max_count,
|
||||
defaults, default_count, param_count, pool)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 全局函数注册表(跨模块函数查找)
|
||||
#
|
||||
# 所有模块翻译的函数都会注册到此表(通过 add_func_to_table 自动注册)。
|
||||
# 主要用途: vtable 初始化时查找跨模块继承方法的 Function 对象,
|
||||
# 以获取函数类型信息构造 bitcast 字符串。
|
||||
# ============================================================
|
||||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||||
def _init_global_func_table() -> int:
|
||||
"""初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)(委托到 gen._init_global_func_table)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit._init_global_func_table()
|
||||
return 0
|
||||
# _build_func_type_str — 从 Function 对象生成函数类型文本(stdlib 存储)
|
||||
#
|
||||
# 格式: ret_ty(param1_ty, param2_ty, ...),与 vtable bitcast 需要一致。
|
||||
# 用 stdlib.malloc 分配返回,跨文件永久存活(1b reset 不回收)。
|
||||
# 返回 None 表示失败。
|
||||
def _build_func_type_str(pool: memhub.MemBuddy | t.CPtr,
|
||||
func: llvmlite.Function | t.CPtr) -> str:
|
||||
"""生成函数类型文本(stdlib 分配)(委托到 gen._build_func_type_str)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit._build_func_type_str(pool, func)
|
||||
return None
|
||||
def _register_global_func(name: str, func: llvmlite.Function | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr = None) -> int:
|
||||
"""注册函数到全局表(已存在则跳过),返回 0 成功(委托到 gen._register_global_func)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit._register_global_func(name, func, pool)
|
||||
return 0
|
||||
def update_global_func_typestr(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str,
|
||||
func: llvmlite.Function | t.CPtr) -> int:
|
||||
"""更新全局函数表的 TypeStr(在函数参数全部添加完成后调用)(委托到 gen.update_global_func_typestr)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit.update_global_func_typestr(pool, name, func)
|
||||
return 0
|
||||
def find_func_global(name: str) -> llvmlite.Function | t.CPtr:
|
||||
"""在全局函数表中按名称查找,返回 Function 指针或 None(委托到 gen.find_func_global)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit.find_func_global(name)
|
||||
return None
|
||||
def find_func_entry_global(name: str) -> GenTypes.FuncEntry | t.CPtr:
|
||||
"""在全局函数表中按名称查找,返回完整 GenTypes.FuncEntry(含 TypeStr)或 None(委托到 gen.find_func_entry_global)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit.find_func_entry_global(name)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局默认参数注册表(跨模块默认参数填充)
|
||||
#
|
||||
# 独立于 _global_funcs,因为 _register_global_func 可能在
|
||||
# add_func_to_table 之前被调用(如 stub 注入),此时 defaults 还不可用。
|
||||
# ============================================================
|
||||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||||
def _init_global_defaults_table() -> int:
|
||||
"""初始化全局默认参数表(委托到 gen._init_global_defaults_table)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit._init_global_defaults_table()
|
||||
return 0
|
||||
def _register_global_defaults(name: str,
|
||||
defaults: t.CVoid | t.CPtr,
|
||||
default_count: int,
|
||||
param_count: int) -> int:
|
||||
"""注册函数默认参数到全局表,返回 0 成功(委托到 gen._register_global_defaults)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit._register_global_defaults(name, defaults, default_count, param_count)
|
||||
return 0
|
||||
def find_func_defaults(name: str) -> GenTypes.FuncDefaultsEntry | t.CPtr:
|
||||
"""按函数名查找默认参数信息,返回 GenTypes.FuncDefaultsEntry 或 None(委托到 gen.find_func_defaults)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit.find_func_defaults(name)
|
||||
return None
|
||||
# _build_const_from_snapshot — 从常量快照重建常量 IR 值
|
||||
#
|
||||
# 用于跨模块默认参数填充:gd_entry.Defaults(pool 内 AST)可能已被 reset 回收,
|
||||
# 改用注册时提取的 stdlib 常量快照(ConstKinds/ConstInts/ConstStrs)重建常量 IR。
|
||||
# 返回 llvmlite.Value*,失败返回 None。
|
||||
def _build_const_from_snapshot(pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
gd_entry: GenTypes.FuncDefaultsEntry | t.CPtr,
|
||||
di: int,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""从快照重建第 di 个默认值常量 IR(委托到 gen._build_const_from_snapshot)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(HandlesExprCall._g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.CallGenLeafKit._build_const_from_snapshot(pool, mod, gd_entry, di, trans, builder)
|
||||
return None
|
||||
def find_func_entry_in_table(funcs: GenTypes.FuncEntry | t.CPtr,
|
||||
func_count: int,
|
||||
name: str) -> GenTypes.FuncEntry | t.CPtr:
|
||||
"""在函数表中按名称查找,返回完整 GenTypes.FuncEntry 或 None"""
|
||||
if name is None or funcs is None:
|
||||
return None
|
||||
entry_size: t.CSizeT = GenTypes.FuncEntry.__sizeof__()
|
||||
i: int = 0
|
||||
while i < func_count:
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size
|
||||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry.Name is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
return entry
|
||||
i += 1
|
||||
return None
|
||||
@@ -1,262 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import string
|
||||
import viperlib
|
||||
import memhub
|
||||
import hashtable
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeKind - 类型种类枚举
|
||||
#
|
||||
# 替代 TransPyC 中 CType.position frozenset 的元属性系统。
|
||||
# 每个 TypeInfo 通过 Kind 字段标记其种类,避免 Python ClassVar 反射。
|
||||
# ============================================================
|
||||
class TypeKind(t.CEnum):
|
||||
Basic: t.State # 基本类型(int/char/float/double/bool 等)
|
||||
Pointer: t.State # 指针(T*)— 指针层数由 TypeInfo.PtrCount 表达
|
||||
Struct: t.State # 结构体/类
|
||||
Union: t.State # 联合体
|
||||
Enum: t.State # 枚举
|
||||
Typedef: t.State # 类型别名
|
||||
Function: t.State # 函数指针
|
||||
Array: t.State # 数组 T[N]
|
||||
Void: t.State # void
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeInfo - 类型信息结构
|
||||
#
|
||||
# 设计原则(相对 TransPyC CTypeInfo 的简化):
|
||||
# - POD 数据结构,无虚函数,无 Python 元特性(ClassVar/Generic/frozenset)
|
||||
# - 通过 mbuddy 分配,调用方管理生命周期(参考 llvmlite Module 模式)
|
||||
# - 通过 Kind 枚举代替 position frozenset
|
||||
# - PtrCount 表达指针层数(0=非指针, 1=T*, 2=T**)
|
||||
# - IsSigned 三态:-1=不适用(void/float), 0=unsigned, 1=signed
|
||||
#
|
||||
# 字段布局(8 字段):
|
||||
# Kind : i32 类型种类(TypeKind 枚举值)
|
||||
# Name : i8* 类型名(如 'int', 'CInt', 'MyStruct'),可能为 None
|
||||
# Size : i32 位宽(0=void/未知;int=32, char=8, double=64, long long=64)
|
||||
# Align : i32 对齐字节数(0=默认)
|
||||
# IsSigned : i32 -1=N/A, 0=unsigned, 1=signed
|
||||
# PtrCount : i32 指针层数
|
||||
# IsConst : i32 const 限定符(0/1)
|
||||
# IsVolatile : i32 volatile 限定符(0/1)
|
||||
#
|
||||
# 注意:Size 使用位宽(bit width)而非字节数,与 LLVM IR 的 i{N} 和
|
||||
# TransPyC CType.Size 约定一致(CInt.Size=32, CChar.Size=8)。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class TypeInfo:
|
||||
Kind: int
|
||||
Name: str
|
||||
Size: int
|
||||
Align: int
|
||||
IsSigned: int
|
||||
PtrCount: int
|
||||
IsConst: int
|
||||
IsVolatile: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeRegistry - 类型注册表
|
||||
#
|
||||
# 维护 name(str) → TypeInfo* 映射,基于 HashTable 实现 O(1) 查找。
|
||||
# 替代 TransPyC CTypeRegistry 的 _name_to_class dict。
|
||||
# 内置基本类型(int/char/void/...)由 InitBasicTypes 注册。
|
||||
# ============================================================
|
||||
class TypeRegistry:
|
||||
_ht: hashtable.HashTable | t.CPtr
|
||||
__mbuddy__: memhub.MemBuddy | t.CPtr
|
||||
|
||||
def Register(self, ti: TypeInfo | t.CPtr) -> int:
|
||||
"""注册一个 TypeInfo。ti.Name 字段必须已设置。
|
||||
|
||||
Returns:
|
||||
1 表示成功,0 表示失败(ti 为 None 或 Name 为 None)
|
||||
"""
|
||||
if ti is None:
|
||||
return 0
|
||||
if ti.Name is None:
|
||||
return 0
|
||||
self._ht[ti.Name] = ti
|
||||
return 1
|
||||
|
||||
def Lookup(self, name: str) -> TypeInfo | t.CPtr:
|
||||
"""按名称查找 TypeInfo。
|
||||
|
||||
Returns:
|
||||
找到返回 TypeInfo*,找不到返回 None
|
||||
"""
|
||||
if name is None:
|
||||
return None
|
||||
return self._ht[name]
|
||||
|
||||
def Has(self, name: str) -> int:
|
||||
"""检查类型是否已注册。"""
|
||||
if name is None:
|
||||
return 0
|
||||
return name in self._ht
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewTypeInfo - 工厂函数:分配并初始化一个 TypeInfo
|
||||
#
|
||||
# 默认值:Kind=Basic, IsSigned=-1, 其余=0/None
|
||||
# ============================================================
|
||||
def NewTypeInfo(pool: memhub.MemBuddy | t.CPtr) -> TypeInfo | t.CPtr:
|
||||
ptr: TypeInfo | t.CPtr = pool.alloc(TypeInfo.__sizeof__())
|
||||
if ptr is None:
|
||||
return None
|
||||
string.memset(ptr, 0, TypeInfo.__sizeof__())
|
||||
ptr.Kind = TypeKind.Basic
|
||||
ptr.IsSigned = -1
|
||||
return ptr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewTypeRegistry - 工厂函数:创建类型注册表
|
||||
# ============================================================
|
||||
def NewTypeRegistry(pool: memhub.MemBuddy | t.CPtr) -> TypeRegistry | t.CPtr:
|
||||
ptr: TypeRegistry | t.CPtr = pool.alloc(TypeRegistry.__sizeof__())
|
||||
if ptr is None:
|
||||
return None
|
||||
string.memset(ptr, 0, TypeRegistry.__sizeof__())
|
||||
ptr.__mbuddy__ = pool
|
||||
ptr._ht = hashtable.HashTable(pool)
|
||||
return ptr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeToLLVM - 将 TypeInfo 转换为 LLVM IR 类型字符串
|
||||
#
|
||||
# 规则:
|
||||
# - Kind == Void 或 (Size==0 且 IsSigned==-1 且 PtrCount==0) → "void"
|
||||
# - void 有 PtrCount > 0 → "i8" + PtrCount 个 "*"
|
||||
# - IsSigned == -1 且 Size > 0 → 浮点: half/float/double/fp128
|
||||
# - IsSigned != -1 且 Size > 0 → 整数: i{Size}
|
||||
# - 未知 → "i8*"
|
||||
#
|
||||
# Args:
|
||||
# buf: 输出缓冲区(i8*)
|
||||
# buf_size: 缓冲区容量
|
||||
# ti: TypeInfo 指针
|
||||
#
|
||||
# Returns:
|
||||
# 写入的字符数(不含 NUL),失败返回 -1
|
||||
# ============================================================
|
||||
def TypeToLLVM(buf: str, buf_size: t.CSizeT,
|
||||
ti: TypeInfo | t.CPtr) -> int:
|
||||
if buf is None:
|
||||
return -1
|
||||
if ti is None:
|
||||
return -1
|
||||
if buf_size == 0:
|
||||
return -1
|
||||
|
||||
# 判定 void
|
||||
is_void: int = 0
|
||||
if ti.Kind == TypeKind.Void:
|
||||
is_void = 1
|
||||
elif ti.Size == 0 and ti.IsSigned == -1 and ti.PtrCount == 0:
|
||||
is_void = 1
|
||||
|
||||
# 写入 base 类型字符串到 buf
|
||||
base_len: int = 0
|
||||
if is_void == 1:
|
||||
if ti.PtrCount == 0:
|
||||
# "void"
|
||||
if buf_size < 5:
|
||||
return -1
|
||||
string.strcpy(buf, "void")
|
||||
base_len = 4
|
||||
else:
|
||||
# void* → i8*(LLVM 中 void* 表示为 i8*)
|
||||
if buf_size < 4:
|
||||
return -1
|
||||
string.strcpy(buf, "i8")
|
||||
base_len = 2
|
||||
elif ti.IsSigned == -1:
|
||||
# 浮点
|
||||
if ti.Size == 16:
|
||||
if buf_size < 5:
|
||||
return -1
|
||||
string.strcpy(buf, "half")
|
||||
base_len = 4
|
||||
elif ti.Size == 32:
|
||||
if buf_size < 6:
|
||||
return -1
|
||||
string.strcpy(buf, "float")
|
||||
base_len = 5
|
||||
elif ti.Size == 64:
|
||||
if buf_size < 7:
|
||||
return -1
|
||||
string.strcpy(buf, "double")
|
||||
base_len = 6
|
||||
elif ti.Size == 128:
|
||||
if buf_size < 6:
|
||||
return -1
|
||||
string.strcpy(buf, "fp128")
|
||||
base_len = 5
|
||||
else:
|
||||
# 未知浮点尺寸 → double 兜底
|
||||
if buf_size < 7:
|
||||
return -1
|
||||
string.strcpy(buf, "double")
|
||||
base_len = 6
|
||||
else:
|
||||
# 整数: i{Size},用 snprintf 安全写入
|
||||
if ti.Size <= 0:
|
||||
# 无效尺寸 → i8 兜底
|
||||
if buf_size < 4:
|
||||
return -1
|
||||
string.strcpy(buf, "i8")
|
||||
base_len = 2
|
||||
else:
|
||||
viperlib.snprintf(buf, buf_size, "i%d", ti.Size)
|
||||
base_len = string.strlen(buf)
|
||||
|
||||
# 追加 PtrCount 个 "*"
|
||||
if base_len + ti.PtrCount + 1 > buf_size:
|
||||
return -1
|
||||
pos: int = base_len
|
||||
for i in range(ti.PtrCount):
|
||||
buf[pos] = '*'
|
||||
pos += 1
|
||||
buf[pos] = 0
|
||||
return pos
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Mixin - 所有 Handle 的非多态基类(对应 TransPyC 的 BaseHandle)
|
||||
#
|
||||
# @t.NoVTable 继承:字段展平嵌入子类,无 vtable 开销(对应 C++ 非多态继承)。
|
||||
# 子类继承 Trans 字段 + 共享工具方法,编译器自动生成子类方法包装
|
||||
# (self bitcast 为父类指针后调用),子类可直接调用继承的方法。
|
||||
#
|
||||
# 用法:
|
||||
# @t.NoVTable
|
||||
# class AssignHandle(Mixin):
|
||||
# _CurrentClass: str
|
||||
# def __init__(self, trans):
|
||||
# self.InitMixin(trans)
|
||||
# self._CurrentClass = None
|
||||
# def Handle(self, node) -> int:
|
||||
# rhs = self.Trans.ExprH.HandleValue(node.value)
|
||||
# ...
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class Mixin:
|
||||
"""所有 Handle 的非多态基类:持有 Translator 回指针 + 共享委托方法"""
|
||||
Trans: HT.Translator | t.CPtr
|
||||
|
||||
def InitMixin(self, trans: HT.Translator | t.CPtr) -> int:
|
||||
"""初始化 Mixin 字段(子类 __init__ 中调用)"""
|
||||
self.Trans = trans
|
||||
return 0
|
||||
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: t.CVoid | t.CPtr
|
||||
@@ -1,953 +0,0 @@
|
||||
import lib.core.Gen.ExprGenAttr as ExprGenAttr
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
import lib.core.Gen.ExprGenCdef as ExprGenCdef
|
||||
import lib.core.Gen.ExprGenCls as ExprGenCls
|
||||
import lib.core.Gen.ExprGenConst as ExprGenConst
|
||||
import lib.core.Gen.ExprGenFstr as ExprGenFstr
|
||||
import lib.core.Gen.ExprGenMixin as ExprGenMixin
|
||||
import lib.core.Gen.ExprGenName as ExprGenName
|
||||
import lib.core.Gen.ExprGenOps as ExprGenOps
|
||||
import lib.core.Gen.FuncGenMixin as FuncGenMixin
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import memhub
|
||||
import string
|
||||
import llvmlite
|
||||
import stdlib
|
||||
import stdio
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.core.Gen.Generator as Generator
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesExpr - 表达式处理(P3 对象化后的委托层)
|
||||
#
|
||||
# 全部模块级函数已迁移为 lib.core.Gen.ExprGenMixin 的方法
|
||||
# (全局状态迁入 gen 字段),本模块保留同名模块级函数作为
|
||||
# "一行委托":延迟 import Gen 取全局单例(BuildPipeline/main
|
||||
# 创建后 set_global_gen 注册),再调用 gen 的对应方法。签名与
|
||||
# 旧函数完全一致,调用方零改动。
|
||||
#
|
||||
# ExprHandle 类及其 NewExprHandle 工厂保留(translator handler 模式)。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
|
||||
# ============================================================
|
||||
_g_gen: Generator.Generator | t.CPtr = None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法
|
||||
# (gen 未注册时正常流程不会发生;有返回值函数返回默认值)
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 从 AST 节点提取函数名
|
||||
# ============================================================
|
||||
def get_func_name(func_node: ast.AST | t.CPtr) -> str:
|
||||
"""从函数节点提取函数名(委托到 gen.get_func_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.get_func_name(func_node)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 转义 LLVM IR 字符串字面量
|
||||
# ============================================================
|
||||
def escape_llvm_string(pool: memhub.MemBuddy | t.CPtr,
|
||||
src: str) -> str:
|
||||
"""将字符串转换为 LLVM IR 字符串字面量 c"...\\00"(委托到 gen.escape_llvm_string)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.escape_llvm_string(pool, src)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 获取 LLVM 整数类型的位宽
|
||||
# ============================================================
|
||||
def get_llvm_type_bits(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""获取 LLVM 整数类型的位宽,非整数类型返回 0(委托到 gen.get_llvm_type_bits)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.get_llvm_type_bits(ty)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 获取 LLVM 浮点类型的位宽
|
||||
# ============================================================
|
||||
def get_llvm_float_bits(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""获取 LLVM 浮点类型的位宽,非浮点类型返回 0(委托到 gen.get_llvm_float_bits)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.get_llvm_float_bits(ty)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# is_ptr_type - 检查类型是否为 Ptr
|
||||
#
|
||||
# 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。
|
||||
# ============================================================
|
||||
def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""检查 ty 是否是 Ptr 类型,返回 1=是, 0=否(委托到 gen.is_ptr_type)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.is_ptr_type(ty)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# get_ptr_level - 计算指针层级
|
||||
#
|
||||
# 返回值:
|
||||
# 0 = 非指针(数值/结构体等)
|
||||
# 1 = 一级指针(如 i8*, Struct*)
|
||||
# 2 = 二级指针(如 i8**, Struct**)
|
||||
# 3+ = 更高级指针
|
||||
# ============================================================
|
||||
def get_ptr_level(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""计算指针层级,0=非指针, 1=一级指针, 2=二级指针...(委托到 gen.get_ptr_level)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.get_ptr_level(ty)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# is_array_type - 检查类型是否为 Array
|
||||
#
|
||||
# 返回 1=是, 0=否。类型检查工具函数。
|
||||
# ============================================================
|
||||
def is_array_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""检查 ty 是否是 Array 类型,返回 1=是, 0=否(委托到 gen.is_array_type)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.is_array_type(ty)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _zext_index_to_i32 - 数组下标索引零扩展
|
||||
#
|
||||
# LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30,
|
||||
# 导致数组下标越界读(字节 >= 128 的乱码根因)。
|
||||
# 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。
|
||||
# ============================================================
|
||||
def _zext_index_to_i32(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""将 <32 位整数下标零扩展到 i32(数组下标非负语义)(委托到 gen._zext_index_to_i32)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase._zext_index_to_i32(builder, idx_val)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体
|
||||
#
|
||||
# 处理两种情况:
|
||||
# - ty 直接是 Struct → 检查是否注册
|
||||
# - ty 是 Ptr(Struct) → 检查 pointee 是否注册
|
||||
# ============================================================
|
||||
def _get_custom_struct_cls_nm(pool: memhub.MemBuddy | t.CPtr,
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> str:
|
||||
"""检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None(委托到 gen._get_custom_struct_cls_nm)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase._get_custom_struct_cls_nm(pool, ty)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _is_list_subscript_base - 判断下标基座是否为 list[T] 变量
|
||||
# ============================================================
|
||||
def _is_list_subscript_base(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
sub_node: ast.AST | t.CPtr) -> int:
|
||||
"""判断下标基座是否为 list[T] 变量(1=是)(委托到 gen._is_list_subscript_base)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase._is_list_subscript_base(pool, trans, sub_node)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _sub_base_class_name - 解析下标基座变量的结构体类名
|
||||
# ============================================================
|
||||
def _sub_base_class_name(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
sub_node: ast.AST | t.CPtr) -> str:
|
||||
"""解析下标基座变量的结构体类名(无则 None)(委托到 gen._sub_base_class_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase._sub_base_class_name(pool, trans, sub_node)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义
|
||||
# ============================================================
|
||||
def _sub_base_uses_getitem(pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
sub_node: ast.AST | t.CPtr) -> int:
|
||||
"""下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)(委托到 gen._sub_base_uses_getitem)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase._sub_base_uses_getitem(pool, mod, trans, sub_node)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用
|
||||
# ============================================================
|
||||
def _deref_if_ptr_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针(委托到 gen._deref_if_ptr_ptr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase._deref_if_ptr_ptr(builder, obj_ptr)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si
|
||||
# ============================================================
|
||||
def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
target_ty: llvmlite.LLVMType | t.CPtr,
|
||||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""将 val 强制转换为 target_ty(委托到 gen.coerce_to_type)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.coerce_to_type(builder, val, target_ty, node)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# translate_ptr_arith - 指针算术: ptr + int / ptr - int
|
||||
#
|
||||
# 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC
|
||||
# ExprGen.emit_binary_op / HandlesAugAssign.py。
|
||||
# ============================================================
|
||||
def translate_ptr_arith(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
ptr_val: llvmlite.Value | t.CPtr,
|
||||
int_val: llvmlite.Value | t.CPtr,
|
||||
op: int) -> llvmlite.Value | t.CPtr:
|
||||
"""指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)(委托到 gen.translate_ptr_arith)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenBase.translate_ptr_arith(pool, builder, ptr_val, int_val, op)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 创建全局字符串常量
|
||||
# ============================================================
|
||||
def create_global_string(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
str_val: str,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""创建全局字符串常量并返回 i8* bitcast(委托到 gen.create_global_string)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenConst.create_global_string(builder, pool, mod, str_val, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块引用 AST → 模块路径字符串(递归拼接 Attribute 链)
|
||||
# ============================================================
|
||||
def attr_module_path_str(pool: memhub.MemBuddy | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> str:
|
||||
"""把模块引用 AST 转成模块路径字符串(Name('sys')→"sys"、
|
||||
Attribute(Attribute(Name('os'),'_win32'))→"os._win32";非模块引用形态返回 None)
|
||||
|
||||
跨 mixin 委托:CallGenMixin 等不能 self. 直接调用 ExprGenMixin 的方法
|
||||
(@t.NoVTable 静态绑定会 mangle 成当前类名 → undefined reference)。
|
||||
"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr._attr_module_path_str(pool, node)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译常量表达式
|
||||
# ============================================================
|
||||
def translate_constant(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译常量(int/str/bool)(委托到 gen.translate_constant)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenConst.translate_constant(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名
|
||||
# ============================================================
|
||||
def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr,
|
||||
value: llvmlite.Value | t.CPtr) -> str:
|
||||
"""从 LLVM Value 的类型推断 list 元素类型名(委托到 gen._infer_elem_type_from_value)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenConst._infer_elem_type_from_value(pool, value)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _find_pool_var — 查找上下文中的 pool 变量
|
||||
#
|
||||
# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb"
|
||||
# ============================================================
|
||||
def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""查找上下文中的 pool 变量,返回 alloca 或 None(委托到 gen._find_pool_var)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenConst._find_pool_var(trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# translate_list_literal — 翻译 list 字面量 [a, b, c]
|
||||
#
|
||||
# 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列
|
||||
# ============================================================
|
||||
def translate_list_literal(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
elem_type_name: str,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列(委托到 gen.translate_list_literal)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenConst.translate_list_literal(builder, pool, mod, node, elem_type_name, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译值表达式(RHS 分派)— 模块级版本
|
||||
# ============================================================
|
||||
def translate_value(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译值表达式为 LLVM Value(委托到 gen.translate_value)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGen.translate_value(builder, pool, mod, node, funcs_ptr, func_count, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译 lambda 表达式 — 模块级委托
|
||||
#
|
||||
# translate_lambda 定义在 FuncGenMixin(跨 Mixin 方法),ExprGenMixin
|
||||
# 不能 self. 直接调用(NoVTable 下方法 mangle 成定义类符号,跨 Mixin
|
||||
# self 调用会解析失败),与 translate_value 同模式走模块级委托。
|
||||
# ============================================================
|
||||
def translate_lambda(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译 lambda 表达式,返回闭包指针(i8*)(委托到 gen.translate_lambda)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.FuncGen.translate_lambda(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译三元表达式 IfExp(test, body, orelse)
|
||||
# ============================================================
|
||||
def translate_ifexp(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译三元表达式 (body if test else orelse),返回 phi 结果 Value(委托到 gen.translate_ifexp)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps.translate_ifexp(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译比较表达式 Compare(left, ops, comparators)
|
||||
# ============================================================
|
||||
def should_zext_widen(pool: memhub.MemBuddy | t.CPtr,
|
||||
narrow_val: llvmlite.Value | t.CPtr,
|
||||
wide_val: llvmlite.Value | t.CPtr,
|
||||
narrow_node: ast.AST | t.CPtr = None) -> int:
|
||||
"""判断整数拓宽方向:1=zext(无符号语义),0=sext(委托到 gen.should_zext_widen)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps.should_zext_widen(pool, narrow_val, wide_val, narrow_node)
|
||||
return 0
|
||||
|
||||
|
||||
def _node_type_unsigned(pool: memhub.MemBuddy | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知)(委托到 gen._node_type_unsigned)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps._node_type_unsigned(pool, node, trans)
|
||||
return 0
|
||||
|
||||
|
||||
def _type_name_unsigned(type_name: str) -> int:
|
||||
"""类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)(委托到 gen._type_name_unsigned)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps._type_name_unsigned(type_name)
|
||||
return 0
|
||||
|
||||
|
||||
def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译比较表达式,返回 i1 结果(委托到 gen.translate_compare)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps.translate_compare(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译一元运算表达式 UnaryOp(op, operand)
|
||||
# ============================================================
|
||||
def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译一元运算(-x, +x, not x, ~x)(委托到 gen.translate_unaryop)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps.translate_unaryop(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1
|
||||
# ============================================================
|
||||
def translate_boolop(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
funcs_ptr: t.CPtr = None,
|
||||
func_count: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译布尔运算(and/or)的短路求值,返回 i1(委托到 gen.translate_boolop)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps.translate_boolop(builder, pool, mod, node, funcs_ptr, func_count, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径
|
||||
# ============================================================
|
||||
def _build_source_path_from_sha1(sha1: str) -> str:
|
||||
"""通过 SHA1 从全局存储器构建源 .py 文件路径(委托到 gen._build_source_path_from_sha1)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenCdef._build_source_path_from_sha1(sha1)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量
|
||||
# ============================================================
|
||||
def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str,
|
||||
from_imports: str,
|
||||
imported_modules: str = None,
|
||||
depth: int = 0,
|
||||
node: ast.AST | t.CPtr = None) -> t.CInt64T:
|
||||
"""跨模块查找 CDefine 常量,返回值(64 位)或 -1(未找到)(委托到 gen._lookup_cross_module_cdefine)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenCdef._lookup_cross_module_cdefine(pool, name, from_imports, imported_modules, depth, node)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定
|
||||
# ============================================================
|
||||
def _is_cdefine_name_pattern(name: str) -> int:
|
||||
"""检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)(委托到 gen._is_cdefine_name_pattern)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenCdef._is_cdefine_name_pattern(name)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译变量引用(Name 节点)→ load
|
||||
# ============================================================
|
||||
def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译变量引用(Name 节点)→ load(委托到 gen.translate_name_value)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenName.translate_name_value(builder, pool, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprHandle - 表达式处理器(Mixin 继承模式)
|
||||
#
|
||||
# HandleValue 提供 trans 接口,委托到模块级 translate_value
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprHandle(HandlesBase.Mixin):
|
||||
"""表达式处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# HandleValue - 翻译值表达式为 LLVM Value
|
||||
# ============================================================
|
||||
def HandleValue(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译值表达式,从 self.Trans 获取共享状态"""
|
||||
return translate_value(
|
||||
self.Trans._cur_builder, self.Trans.Pool, self.Trans.Module,
|
||||
node,
|
||||
self.Trans._funcs, self.Trans._func_count, self.Trans)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewExprHandle - 工厂函数
|
||||
# ============================================================
|
||||
def NewExprHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> ExprHandle | t.CPtr:
|
||||
h: ExprHandle | t.CPtr = pool.alloc(ExprHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, ExprHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
|
||||
|
||||
# ============================================================
|
||||
# list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑
|
||||
#
|
||||
# list 结构布局 (6 字段 × 8 字节):
|
||||
# __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40)
|
||||
# 返回元素地址 (i8*),调用方根据元素类型 load 正确的值
|
||||
# ============================================================
|
||||
def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
lm_obj: llvmlite.Value | t.CPtr,
|
||||
idx_val: llvmlite.Value | t.CPtr,
|
||||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)(委托到 gen.list_getitem_inline)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenName.list_getitem_inline(builder, pool, lm_obj, idx_val, node)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型
|
||||
# ============================================================
|
||||
def _list_elem_type_from_name(pool: memhub.MemBuddy | t.CPtr,
|
||||
struct_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""从 list 类型名提取元素 LLVM 类型(委托到 gen._list_elem_type_from_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenName._list_elem_type_from_name(pool, struct_name)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑
|
||||
# ============================================================
|
||||
def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
lm_obj: llvmlite.Value | t.CPtr,
|
||||
idx_val: llvmlite.Value | t.CPtr,
|
||||
rhs_val: llvmlite.Value | t.CPtr,
|
||||
node: ast.AST | t.CPtr = None) -> int:
|
||||
"""内联生成 list __setitem__ 逻辑,返回 0(委托到 gen.list_setitem_inline)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenName.list_setitem_inline(builder, pool, lm_obj, idx_val, rhs_val, node)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型
|
||||
#
|
||||
# 返回 list 对象指针 (Ptr(list[T])) 或 None
|
||||
# ============================================================
|
||||
def is_list_subscript(node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None(委托到 gen.is_list_subscript)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenName.is_list_subscript(node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i]
|
||||
# ============================================================
|
||||
def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译下标表达式,返回加载的元素值(委托到 gen.translate_subscript)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenName.translate_subscript(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# find_global_in_module - 在模块全局变量链表中按名称查找
|
||||
#
|
||||
# 查找策略:
|
||||
# 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy)
|
||||
# 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy")
|
||||
# ============================================================
|
||||
def find_global_in_module(mod: llvmlite.LLVMModule | t.CPtr,
|
||||
name: str) -> llvmlite.GlobalVariable | t.CPtr:
|
||||
"""在模块全局变量链表中按名称查找全局变量(委托到 gen.find_global_in_module)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr.find_global_in_module(mod, name)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# make_global_ref - 创建全局变量引用 (@name,类型为 ty*)
|
||||
# ============================================================
|
||||
def make_global_ref(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str,
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""创建全局变量引用 (类型为 ty*,名称为 @name)(委托到 gen.make_global_ref)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr.make_global_ref(pool, name, ty)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _is_t_type_object_name - 检查 name 是否是 t.py 中的类型对象名
|
||||
# ============================================================
|
||||
def _is_t_type_object_name(name: str) -> int:
|
||||
"""检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等)(委托到 gen._is_t_type_object_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr._is_t_type_object_name(name)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _resolve_module_attribute_global - 解析模块属性访问的全局变量引用
|
||||
# ============================================================
|
||||
def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
at: ast.Attribute | t.CPtr,
|
||||
ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)(委托到 gen._resolve_module_attribute_global)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr._resolve_module_attribute_global(pool, mod, trans, at, ty_hint)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针
|
||||
# ============================================================
|
||||
def _get_cderef_attr_base(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
at_value: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)(委托到 gen._get_cderef_attr_base)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr._get_cderef_attr_base(builder, pool, mod, at_value, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译属性访问 Attribute(value, attr, ctx) — obj.field
|
||||
# ============================================================
|
||||
def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译属性访问,返回加载的字段值(委托到 gen.translate_attribute)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr.translate_attribute(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 获取下标表达式的元素指针(不加载值,用于赋值)
|
||||
# ============================================================
|
||||
def get_subscript_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""获取下标表达式的元素指针(用于赋值 lhs)(委托到 gen.get_subscript_ptr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenName.get_subscript_ptr(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 获取属性访问的字段指针(不加载值,用于赋值)
|
||||
# ============================================================
|
||||
def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""获取属性访问的字段指针(用于赋值 lhs)(委托到 gen.get_attribute_ptr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr.get_attribute_ptr(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译 f-string(JoinedStr → snprintf 生成 i8* 栈缓冲)— 模块级委托
|
||||
# ============================================================
|
||||
def translate_joined_str(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译 f-string(委托到 gen.translate_joined_str,定义于 ExprGenFstr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenFstr.translate_joined_str(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译裸 FormattedValue(f"{expr:spec}" 无字面量)— 模块级委托
|
||||
# ============================================================
|
||||
def translate_formatted_value(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译裸 FormattedValue(委托到 gen.translate_formatted_value,定义于 ExprGenFstr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenFstr.translate_formatted_value(builder, pool, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CDefine 整数常量 → LLVM 常量(64 位升级规则)— 模块级委托
|
||||
# ============================================================
|
||||
def _const_int_for_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
value: t.CInt64T) -> llvmlite.Value | t.CPtr:
|
||||
"""CDefine 整数常量 → LLVM 常量(委托到 gen._const_int_for_cdefine,定义于 ExprGenCdef)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenCdef._const_int_for_cdefine(pool, value)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 解析嵌套 Attribute 链的 docstring 归属 — 模块级委托
|
||||
# ============================================================
|
||||
def _resolve_doc_symbol_attr(trans: HT.Translator | t.CPtr,
|
||||
at: ast.Attribute | t.CPtr,
|
||||
out_mod: str, out_sym: str) -> int:
|
||||
"""解析嵌套 Attribute 链的 docstring 归属(委托到 gen._resolve_doc_symbol_attr,定义于 ExprGenCls)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenCls._resolve_doc_symbol_attr(trans, at, out_mod, out_sym)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 解析 Name 符号的 docstring 归属 — 模块级委托
|
||||
# ============================================================
|
||||
def _resolve_doc_symbol_name(trans: HT.Translator | t.CPtr, name_id: str,
|
||||
out_mod: str, out_sym: str) -> int:
|
||||
"""解析 Name 符号的 docstring 归属(委托到 gen._resolve_doc_symbol_name,定义于 ExprGenCls)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenCls._resolve_doc_symbol_name(trans, name_id, out_mod, out_sym)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 查找 docstring 内容(key="{module_sha1}.{symbol}")— 模块级委托
|
||||
# ============================================================
|
||||
def lookup_docstring(module_sha1: str, symbol: str) -> str:
|
||||
"""查找 docstring 内容(委托到 gen.lookup_docstring,定义于 ExprGenCls)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenCls.lookup_docstring(module_sha1, symbol)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 解析属性链(a.b.c)中 c 字段的注解类名 — 模块级委托
|
||||
# ============================================================
|
||||
def _resolve_attr_field_class(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
attr_node: ast.AST | t.CPtr) -> str:
|
||||
"""解析属性链最终字段的注解类名(委托到 gen._resolve_attr_field_class,定义于 ExprGenAttr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenAttr._resolve_attr_field_class(pool, trans, attr_node)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译二元运算(自动类型提升)— 模块级委托
|
||||
# ============================================================
|
||||
def translate_binop(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译二元运算(委托到 gen.translate_binop,定义于 ExprGenOps)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps.translate_binop(pool, builder, mod, node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# binop op → dunder 方法名(如 Add → "__add__")— 模块级委托
|
||||
# ============================================================
|
||||
def _binop_to_dunder(op: int) -> str:
|
||||
"""binop op → dunder 方法名(委托到 gen._binop_to_dunder,定义于 ExprGenOps)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps._binop_to_dunder(op)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# unaryop op → dunder 方法名(如 USub → "__neg__")— 模块级委托
|
||||
# ============================================================
|
||||
def _unaryop_to_dunder(op: int) -> str:
|
||||
"""unaryop op → dunder 方法名(委托到 gen._unaryop_to_dunder,定义于 ExprGenOps)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenOps._unaryop_to_dunder(op)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# f-string 尾部:全局格式串 + 固定栈缓冲 + snprintf — 模块级委托
|
||||
# ============================================================
|
||||
def _fstr_finalize(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
fmt_buf: str,
|
||||
arg_head: llvmlite.Value | t.CPtr,
|
||||
arg_tail: llvmlite.Value | t.CPtr,
|
||||
arg_count: int,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""f-string 尾部(委托到 gen._fstr_finalize,定义于 ExprGenFstr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenFstr._fstr_finalize(builder, pool, mod, fmt_buf, arg_head, arg_tail, arg_count, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 追加字面量到格式串(% 转义)— 模块级委托
|
||||
# ============================================================
|
||||
def _fstr_append_literal(fmt_buf: str, lit: str) -> None:
|
||||
"""追加字面量到格式串(委托到 gen._fstr_append_literal,定义于 ExprGenFstr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g.ExprGenFstr._fstr_append_literal(fmt_buf, lit)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Python format_spec → C printf 格式串 — 模块级委托
|
||||
# ============================================================
|
||||
def _fstr_parse_format_spec(pool: memhub.MemBuddy | t.CPtr,
|
||||
spec_node: ast.AST | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
arg_node: ast.AST | t.CPtr) -> str:
|
||||
"""Python format_spec → C printf 格式串(委托到 gen._fstr_parse_format_spec,定义于 ExprGenFstr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenFstr._fstr_parse_format_spec(pool, spec_node, val, arg_node)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 无 format_spec 时按值类型推断 C printf 格式 — 模块级委托
|
||||
# ============================================================
|
||||
def _fstr_infer_c_fmt(pool: memhub.MemBuddy | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
arg_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> str:
|
||||
"""按值类型推断 C printf 格式(委托到 gen._fstr_infer_c_fmt,定义于 ExprGenFstr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenFstr._fstr_infer_c_fmt(pool, val, arg_node, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 按 C 格式转换值类型(i8/i16→i32、bool→i32、f32→f64)— 模块级委托
|
||||
# ============================================================
|
||||
def _fstr_cast_value(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
c_fmt: str,
|
||||
arg_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""按 C 格式转换值类型(委托到 gen._fstr_cast_value,定义于 ExprGenFstr)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.ExprGenFstr._fstr_cast_value(builder, pool, val, c_fmt, arg_node, trans)
|
||||
return None
|
||||
@@ -1,137 +0,0 @@
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.Gen.Generator as Generator
|
||||
|
||||
# ============================================================
|
||||
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
|
||||
# ============================================================
|
||||
_g_gen: Generator.Generator | t.CPtr = None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 本地常量(阶段 E 拆分时随函数块误删,补回;子模块经 HandlesExprCall.常量 引用)
|
||||
# ============================================================
|
||||
_CEXPORT_MAX: t.CDefine = 256
|
||||
ASM_MAX_OPERANDS: t.CDefine = 16
|
||||
ASM_TEXT_BUF_SIZE: t.CDefine = 2048
|
||||
ASM_CONST_BUF_SIZE: t.CDefine = 512
|
||||
ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||||
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AsmOperand - 内联汇编操作数条目
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class AsmOperand:
|
||||
"""内联汇编操作数条目"""
|
||||
Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca
|
||||
Constraint: str # 约束字符串 (如 "r", "=r")
|
||||
IsOutput: int # 1=输出, 0=输入
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FuncEntry 结构体(用于函数表)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class FuncEntry:
|
||||
"""函数表条目"""
|
||||
Name: str
|
||||
Func: llvmlite.Function | t.CPtr
|
||||
Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr]),None=无默认值
|
||||
DefaultCount: int # 默认值数量
|
||||
ParamCount: int # 形参数量(不含 self)
|
||||
# TypeStr: 函数类型文本(stdlib 深拷贝,跨文件安全)
|
||||
# 1b 每文件 reset_to(mark1) 回收 pool 内 Function 对象后,
|
||||
# vtable 生成 find_func_global 读类型改用此文本,避免悬空。
|
||||
TypeStr: str
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class FuncDefaultsEntry:
|
||||
"""默认参数表条目"""
|
||||
Name: str
|
||||
Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset)
|
||||
DefaultCount: int
|
||||
ParamCount: int # 形参数量(不含 self)
|
||||
# 常量快照(stdlib 分配,跨文件永久存活):
|
||||
# 注册时提取每个默认值 Constant 的值,跨模块调用时优先用快照重建常量 IR,
|
||||
# 避免读取已被 1b reset_to(mark1) 回收的 pool 内 AST。
|
||||
ConstKinds: t.CInt | t.CPtr # const_kind 数组(DefaultCount 个 i32)
|
||||
ConstInts: t.CInt64T | t.CPtr # int_val 数组(DefaultCount 个 i64)
|
||||
ConstStrs: t.CSizeT | t.CPtr # str_val 指针数组(DefaultCount 个 i8*)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ExprCallHandle - 函数调用处理器(Mixin 继承模式)
|
||||
#
|
||||
# HandleCall / HandlePrintfCall 提供 trans 接口
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ExprCallHandle(HandlesBase.Mixin):
|
||||
"""函数调用处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# HandleCall - 翻译函数调用,返回 call 结果 Value
|
||||
# ============================================================
|
||||
def HandleCall(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译函数调用,从 self.Trans 获取共享状态"""
|
||||
return GenApi.translate_call(
|
||||
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
|
||||
node,
|
||||
self.Trans._funcs, self.Trans._func_count, self.Trans)
|
||||
|
||||
# ============================================================
|
||||
# HandlePrintfCall - 翻译 printf 调用
|
||||
# ============================================================
|
||||
def HandlePrintfCall(self, cl: ast.Call | t.CPtr):
|
||||
"""翻译 printf 调用,从 self.Trans 获取共享状态"""
|
||||
GenApi.translate_printf_call(
|
||||
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
|
||||
cl, self.Trans)
|
||||
|
||||
# ============================================================
|
||||
# HandlePrintCall - 翻译 print 调用
|
||||
# ============================================================
|
||||
def HandlePrintCall(self, cl: ast.Call | t.CPtr):
|
||||
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
|
||||
GenApi.translate_print_call(
|
||||
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
|
||||
cl, self.Trans)
|
||||
@@ -1,758 +0,0 @@
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.Handles.ExprCallTable as ExprCallTable
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Gen.Generator as Generator
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesTranslator - 翻译器状态管理 + 主入口
|
||||
#
|
||||
# 从 translator.py 拆分出来,负责:
|
||||
# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入)
|
||||
# 2. translate() - 主翻译入口
|
||||
# 3. dump_ir() - IR 输出
|
||||
#
|
||||
# 语句/表达式翻译全部委托给 Handles 模块:
|
||||
# HandlesMain - wrapper main 创建 + children 遍历
|
||||
# HandlesBody - 语句分派
|
||||
# HandlesExpr - 表达式翻译
|
||||
# HandlesFunctions - 函数定义处理
|
||||
# 注意:str = bytes = t.CChar | t.CPtr = i8*
|
||||
#
|
||||
# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为
|
||||
# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级
|
||||
# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。
|
||||
# ============================================================
|
||||
|
||||
# 常量
|
||||
MAX_VARS: t.CDefine = 1024
|
||||
MAX_FUNCS: t.CDefine = 1024
|
||||
MAX_GLOBAL_NAMES: t.CDefine = 32
|
||||
# 协程表容量(TPV-M1):async 函数数 / 协程变量·局部名数
|
||||
MAX_CORO_FUNCS: t.CDefine = 256
|
||||
MAX_CORO_VARS: t.CDefine = 256
|
||||
MAX_CORO_TRY: t.CDefine = 16
|
||||
|
||||
# 翻译主环最大递归深度(translate_stmt/translate_value 嵌套)。AST 自引用环
|
||||
# 或翻译 bug 可致翻译主环(语句/表达式/调用)无限递归 → ASan stack-overflow。
|
||||
# match 守卫(MatchTranslateDepth)只保护 match 递归,本常量保护语句/表达式
|
||||
# 翻译环(fail-fast,对齐 TypeGenResolve 深度守卫模式)。
|
||||
TRANSLATE_MAX_DEPTH: t.CDefine = 256
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
|
||||
# ============================================================
|
||||
_g_gen: Generator.Generator | t.CPtr = None
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class Translator:
|
||||
"""翻译器:管理编译状态,委托 Handles 模块执行翻译"""
|
||||
|
||||
# LLVM 上下文(共享状态)
|
||||
Module: llvmlite.LLVMModule | t.CPtr
|
||||
Pool: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# 函数表
|
||||
_funcs: GenTypes.FuncEntry | t.CPtr
|
||||
_func_count: t.CInt
|
||||
|
||||
# 协程(TPV-M1 async def / await / coro.coro_run)
|
||||
# _async_funcs: 已注册 async 函数裸名表(char* 数组,8 字节/项)
|
||||
# _coro_var_async: 变量名→async 函数名 成对表(char* 数组,16 字节/项)
|
||||
# _coro_locals: 当前 async 函数局部变量名表(char* 数组,8 字节/项)
|
||||
# _coro_frames: async 名→帧类型 成对表(16 字节/项 = char* + LLVMType*)
|
||||
_async_funcs: str
|
||||
_async_func_count: t.CInt
|
||||
_coro_var_async: str
|
||||
_coro_var_async_count: t.CInt
|
||||
_coro_locals: str
|
||||
_coro_local_count: t.CInt
|
||||
_coro_frames: str
|
||||
_coro_frame_count: t.CInt
|
||||
# resume_<name> 翻译上下文(AsyncGenMixin 段翻译共享)
|
||||
_coro_state_ptr: llvmlite.Value | t.CPtr
|
||||
_coro_done_ptr: llvmlite.Value | t.CPtr
|
||||
_coro_ret_ptr: llvmlite.Value | t.CPtr
|
||||
_coro_exit_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_coro_await_slot: llvmlite.Value | t.CPtr
|
||||
_coro_frame: llvmlite.Value | t.CPtr
|
||||
_coro_next_state: t.CInt
|
||||
_coro_nseg: t.CInt
|
||||
# M2:async 参数表(char* 数组,8 字节/项)+ 预扫描计数
|
||||
_coro_params: str
|
||||
_coro_param_count: t.CInt
|
||||
_coro_hoist_count: t.CInt # __await_N 槽计数(预扫描与翻译共用,序一致)
|
||||
_coro_await_count: t.CInt # 总 await 数(= 恢复块数 = switch case 数)
|
||||
_coro_local_base: t.CInt # 局部槽起始 index(= 3 + nparams)
|
||||
_coro_extra_base: t.CInt # 额外槽(__await_N)起始 index
|
||||
_coro_break_bb: llvmlite.BasicBlock | t.CPtr # While break 目标(M2 单层)
|
||||
_coro_continue_bb: llvmlite.BasicBlock | t.CPtr # While continue 目标
|
||||
_coro_state_bbs: t.CSizeT | t.CPtr # 预建 state 块数组(await 恢复块定位)
|
||||
# M3-M7 协程扩展
|
||||
_coro_exc_ptr: llvmlite.Value | t.CPtr # 帧 exc 槽(i32,M4)
|
||||
_coro_msg_ptr: llvmlite.Value | t.CPtr # 帧 msg 槽(i8*,M7)
|
||||
_coro_wake_ptr: llvmlite.Value | t.CPtr # 帧 wake 槽(i64,M3 coro_sleep)
|
||||
_coro_try_stack: t.CSizeT | t.CPtr # try 栈:except/finally 块指针数组(8B/项)
|
||||
_coro_try_stack_count: t.CInt
|
||||
_coro_for_counter: t.CInt # range-For 编号(M3,翻译期递增)
|
||||
_coro_scan_for_count: t.CInt # 预扫描期 For 计数
|
||||
_coro_uses_sleep: t.CInt # 函数体是否用 coro_sleep(预扫描置位)
|
||||
_coro_extra_types: str # 额外槽类型表(i8 数组:1=i32 2=i64)
|
||||
_coro_extra_count: t.CInt # 额外槽总数
|
||||
_coro_await_slots: t.CInt | t.CPtr # __await_N 的帧相对槽 index(预扫描填)
|
||||
_coro_for_slots: t.CInt | t.CPtr # range-For N 的 __f_idx 帧相对槽 index(预扫描填)
|
||||
# per-async wake 槽 index 表(coro_run/gather 轮询反查用)
|
||||
_coro_wake_names: str # char* 数组(8B/项)
|
||||
_coro_wake_idxs: t.CInt | t.CPtr # i32 数组(4B/项,-1=无 wake 槽)
|
||||
_coro_wake_count: t.CInt
|
||||
|
||||
# 导入模块跟踪
|
||||
_imported_modules: str
|
||||
_from_imports: str
|
||||
|
||||
# 当前翻译上下文
|
||||
_cur_func: llvmlite.Function | t.CPtr
|
||||
_cur_builder: llvmlite.IRBuilder | t.CPtr
|
||||
|
||||
# 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。
|
||||
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → bitcast i32* load,
|
||||
# 对齐 TPC HandlesSpecialCall._infer_deref_target_type(DictTest 500→-12 根因:
|
||||
# i8* Deref 固定读 1 字节 + sext 截断)。
|
||||
CurAssignAnnot: ast.AST | t.CPtr
|
||||
|
||||
# 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。
|
||||
# 供 c.Deref 判定"是否为赋值直接 RHS":仅 v: int = c.Deref(p) 时用
|
||||
# CurAssignAnnot 推断读取宽度;嵌套在 while 条件/比较/binop/类型转换
|
||||
# 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p)))不推断,
|
||||
# 否则 i8* 会被残留 CurAssignAnnot 误判为 i32* 读 4 字节(对齐 TPC
|
||||
# _infer_deref_target_type 的直接 RHS 检查)。
|
||||
CurAssignNode: ast.AST | t.CPtr
|
||||
|
||||
# 循环控制流目标(break/continue)
|
||||
_break_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_continue_bb: llvmlite.BasicBlock | t.CPtr
|
||||
|
||||
# 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调)
|
||||
_label_counter: t.CInt
|
||||
|
||||
# 追加90:控制流 merge 块可达性(1=有 br 进入可达/0=全分支 return 结构性不可达)
|
||||
_ctrl_merge_reachable: t.CInt
|
||||
|
||||
# match 翻译递归深度(match → case body → translate_value → 嵌套 match)。
|
||||
# 守卫:AST 自引用环(子节点回指祖先)或翻译 bug 导致的无限递归在此
|
||||
# fail-fast(对齐 TypeGenResolve 深度守卫,防 ASan stack-overflow)。
|
||||
MatchTranslateDepth: t.CInt
|
||||
|
||||
# 翻译主环递归深度(translate_stmt/translate_value 入口计数)。match 守卫
|
||||
# 只覆盖 match 递归;语句/表达式/调用环(如 translate_value ↔ translate_call)
|
||||
# 由本字段守卫,超 TRANSLATE_MAX_DEPTH 即 fail-fast(防 ASan stack-overflow)。
|
||||
TranslateDepth: t.CInt
|
||||
|
||||
# global 声明的变量名集合(当前函数内)
|
||||
_global_names: str
|
||||
_global_name_count: t.CInt
|
||||
|
||||
# nonlocal 声明的变量名集合(当前函数内)
|
||||
_nonlocal_names: str
|
||||
_nonlocal_name_count: t.CInt
|
||||
# nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应)
|
||||
# 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型
|
||||
_nonlocal_types: str
|
||||
|
||||
# 闭包相关:当前函数名(用于嵌套函数提升命名)
|
||||
_cur_func_name: str
|
||||
|
||||
# *args 变长参数支持:当前函数的 va_list 指针(i8* alloca)
|
||||
# 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用
|
||||
_va_list_ptr: llvmlite.Value | t.CPtr
|
||||
# *args 参数名(如 "args"),用于符号表注册
|
||||
_vararg_name: str
|
||||
|
||||
# OOP iter 协议:当前 __next__ 方法的隐藏 stop-flag 参数(i1*)。
|
||||
# _translate_method 注入 __stop_iter_flag__ 参数时设置;translate_raise
|
||||
# 检测 raise StopIteration 时对该指针 store 1(对齐 TPC HandlesRaise.py)。
|
||||
# 非 __next__ 函数中为 None。
|
||||
_stop_iter_flag_ptr: llvmlite.Value | t.CPtr
|
||||
|
||||
# try-except 机制(对齐 TPC HandlesTry.py):当前最内层 try 的
|
||||
# 分发块 + 异常编码/消息 alloca。translate_try 设置,translate_raise
|
||||
# 与调用侧 EH 检测写入/跳转。try 外为 None。
|
||||
_eh_dispatch_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_eh_code_ptr: llvmlite.Value | t.CPtr
|
||||
_eh_msg_ptr: llvmlite.Value | t.CPtr
|
||||
# 当前函数的 __eh_msg_out__(i8**)/__eh_code_out__(i32*)输出参数
|
||||
# (函数签名含 raise 时由 translate_function_def/_translate_method 注入)。
|
||||
# 无 EH 参数时 _cur_func_has_eh == 0。
|
||||
_eh_msg_out_param: llvmlite.Value | t.CPtr
|
||||
_eh_code_out_param: llvmlite.Value | t.CPtr
|
||||
_cur_func_has_eh: int
|
||||
|
||||
# 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间)
|
||||
ModuleSha1: str
|
||||
# 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...)
|
||||
# None 表示当前文件是顶级模块(无包),相对导入无法解析
|
||||
CurrentPackage: str
|
||||
# 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移)
|
||||
_closure_env_offsets: t.CInt
|
||||
_closure_env_count: t.CInt
|
||||
# lambda 表达式全局唯一 ID 计数器(生成提升函数名 __lambda_{id})
|
||||
# 独立于 _closure_env_count:后者随函数进入被 clear_scope_names 重置,
|
||||
# lambda ID 需跨函数全局唯一(提升函数名避免冲突)
|
||||
_lambda_count: t.CInt
|
||||
# 函数链内 nonlocal 变量集合(预扫描收集,含嵌套函数声明的 nonlocal)。
|
||||
# 用于"不同层捕获不同变量"场景(如 level1→a, level2→b):b 定义在最外层
|
||||
# 但 level1 不捕获——level1 env 无 b 槽,level2 无法经 env 链获取 b 的堆。
|
||||
# 解决:在最外层函数中为链内所有 nonlocal 建堆,并把堆地址 store 到
|
||||
# 模块级映射变量 @nlheap.{sha1}.{name};内层闭包创建时从映射 load。
|
||||
_nl_chain_names: t.CVoid | t.CPtr
|
||||
_nl_chain_count: t.CInt
|
||||
# 链内 nonlocal 堆预建标志(每函数只建一次):translate_function_def 进入
|
||||
# 新函数时重置为 0;_prepare_chain_nonlocals 首次调用置 1。多个嵌套函数
|
||||
# 定义共享同一堆(防重复 malloc + 二次重定向 VarEntry.Alloca)。
|
||||
_nl_chain_done: t.CInt
|
||||
|
||||
# 泛型特化上下文:当前正在特化的类型参数名/实参名列表
|
||||
# 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型
|
||||
# None 表示不在泛型特化上下文中
|
||||
GenericTypeParamNames: list[str] | t.CPtr
|
||||
GenericTypeArgs: list[str] | t.CPtr
|
||||
|
||||
# Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译
|
||||
_declare_only: t.CInt
|
||||
|
||||
# Phase A 依赖未就绪标志:1=本文件翻译时依赖模块的 text.ll 尚未生成
|
||||
# (同项目源文件按顺序翻译,main.vp 先于其 import 的 mbuddytest.vp),
|
||||
# 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。
|
||||
_deps_pending: t.CInt
|
||||
|
||||
# 嵌套作用域符号表
|
||||
SymTab: GenTypes.SymbolTable | t.CPtr
|
||||
|
||||
def __init__(self):
|
||||
self.Module = None
|
||||
self.Pool = None
|
||||
self._funcs = None
|
||||
self._func_count = 0
|
||||
self._cur_func = None
|
||||
self._cur_builder = None
|
||||
self._break_bb = None
|
||||
self._continue_bb = None
|
||||
self._label_counter = 0
|
||||
self._imported_modules = None
|
||||
self._from_imports = None
|
||||
self._global_names = None
|
||||
self._global_name_count = 0
|
||||
self._nonlocal_names = None
|
||||
self._nonlocal_name_count = 0
|
||||
self._nonlocal_types = None
|
||||
self._cur_func_name = None
|
||||
self._va_list_ptr = None
|
||||
self._vararg_name = None
|
||||
self._stop_iter_flag_ptr = None
|
||||
self._eh_dispatch_bb = None
|
||||
self._eh_code_ptr = None
|
||||
self._eh_msg_ptr = None
|
||||
self._eh_msg_out_param = None
|
||||
self._eh_code_out_param = None
|
||||
self._cur_func_has_eh = 0
|
||||
self.ModuleSha1 = None
|
||||
self.CurrentPackage = None
|
||||
self._closure_env_offsets = 0
|
||||
self._closure_env_count = 0
|
||||
self._lambda_count = 0
|
||||
self._nl_chain_names = None
|
||||
self._nl_chain_count = 0
|
||||
self._nl_chain_done = 0
|
||||
self.GenericTypeParamNames = None
|
||||
self.GenericTypeArgs = None
|
||||
self._declare_only = 0
|
||||
self._deps_pending = 0
|
||||
self.SymTab = None
|
||||
self._async_funcs = None
|
||||
self._async_func_count = 0
|
||||
self._coro_var_async = None
|
||||
self._coro_var_async_count = 0
|
||||
self._coro_locals = None
|
||||
self._coro_local_count = 0
|
||||
self._coro_frames = None
|
||||
self._coro_frame_count = 0
|
||||
self._coro_state_ptr = None
|
||||
self._coro_done_ptr = None
|
||||
self._coro_ret_ptr = None
|
||||
self._coro_exit_bb = None
|
||||
self._coro_await_slot = None
|
||||
self._coro_frame = None
|
||||
self._coro_next_state = 1
|
||||
self._coro_nseg = 0
|
||||
self._coro_params = None
|
||||
self._coro_param_count = 0
|
||||
self._coro_hoist_count = 0
|
||||
self._coro_await_count = 0
|
||||
self._coro_local_base = 3
|
||||
self._coro_extra_base = 3
|
||||
self._coro_break_bb = None
|
||||
self._coro_continue_bb = None
|
||||
self._coro_state_bbs = None
|
||||
self._coro_exc_ptr = None
|
||||
self._coro_msg_ptr = None
|
||||
self._coro_wake_ptr = None
|
||||
self._coro_try_stack = None
|
||||
self._coro_try_stack_count = 0
|
||||
self._coro_for_counter = 0
|
||||
self._coro_scan_for_count = 0
|
||||
self._coro_uses_sleep = 0
|
||||
self._coro_extra_types = None
|
||||
self._coro_extra_count = 0
|
||||
self._coro_await_slots = None
|
||||
self._coro_for_slots = None
|
||||
self._coro_wake_names = None
|
||||
self._coro_wake_idxs = None
|
||||
self._coro_wake_count = 0
|
||||
|
||||
# ============================================================
|
||||
# 状态初始化
|
||||
# ============================================================
|
||||
def _init_state(self, pool: memhub.MemBuddy | t.CPtr):
|
||||
"""初始化变量表、函数表和子 Handle"""
|
||||
self.Pool = pool
|
||||
if self._funcs is None:
|
||||
self._funcs = GenApi.init_func_table(pool, MAX_FUNCS)
|
||||
# 嵌套作用域符号表(新版)
|
||||
if self.SymTab is None:
|
||||
self.SymTab = GenApi.init_symbol_table(pool)
|
||||
# global/nonlocal 名称集合缓冲区(32 个 char* 指针 = 256 字节)
|
||||
if self._global_names is None:
|
||||
self._global_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||||
if self._global_names is not None:
|
||||
string.memset(self._global_names, 0, MAX_GLOBAL_NAMES * 8)
|
||||
self._global_name_count = 0
|
||||
if self._nonlocal_names is None:
|
||||
self._nonlocal_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||||
if self._nonlocal_names is not None:
|
||||
string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8)
|
||||
self._nonlocal_name_count = 0
|
||||
# nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应)
|
||||
if self._nonlocal_types is None:
|
||||
self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
|
||||
if self._nonlocal_types is not None:
|
||||
string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8)
|
||||
|
||||
# 协程表(TPV-M1):async 函数名 / 变量→async 映射 / 局部名 / 帧类型
|
||||
if self._async_funcs is None:
|
||||
self._async_funcs = stdlib.malloc(MAX_CORO_FUNCS * 8)
|
||||
if self._async_funcs is not None:
|
||||
string.memset(self._async_funcs, 0, MAX_CORO_FUNCS * 8)
|
||||
self._async_func_count = 0
|
||||
if self._coro_var_async is None:
|
||||
self._coro_var_async = stdlib.malloc(MAX_CORO_VARS * 16)
|
||||
if self._coro_var_async is not None:
|
||||
string.memset(self._coro_var_async, 0, MAX_CORO_VARS * 16)
|
||||
self._coro_var_async_count = 0
|
||||
if self._coro_locals is None:
|
||||
self._coro_locals = stdlib.malloc(MAX_CORO_VARS * 8)
|
||||
if self._coro_locals is not None:
|
||||
string.memset(self._coro_locals, 0, MAX_CORO_VARS * 8)
|
||||
if self._coro_params is None:
|
||||
self._coro_params = stdlib.malloc(MAX_CORO_VARS * 8)
|
||||
if self._coro_params is not None:
|
||||
string.memset(self._coro_params, 0, MAX_CORO_VARS * 8)
|
||||
if self._coro_try_stack is None:
|
||||
self._coro_try_stack = stdlib.malloc(MAX_CORO_TRY * 8)
|
||||
if self._coro_try_stack is not None:
|
||||
string.memset(self._coro_try_stack, 0, MAX_CORO_TRY * 8)
|
||||
if self._coro_extra_types is None:
|
||||
self._coro_extra_types = stdlib.malloc(MAX_CORO_VARS)
|
||||
if self._coro_extra_types is not None:
|
||||
string.memset(self._coro_extra_types, 0, MAX_CORO_VARS)
|
||||
if self._coro_await_slots is None:
|
||||
self._coro_await_slots = stdlib.malloc(MAX_CORO_VARS * 4)
|
||||
if self._coro_await_slots is not None:
|
||||
string.memset(self._coro_await_slots, 0, MAX_CORO_VARS * 4)
|
||||
if self._coro_for_slots is None:
|
||||
self._coro_for_slots = stdlib.malloc(MAX_CORO_VARS * 4)
|
||||
if self._coro_for_slots is not None:
|
||||
string.memset(self._coro_for_slots, 0, MAX_CORO_VARS * 4)
|
||||
if self._coro_wake_names is None:
|
||||
self._coro_wake_names = stdlib.malloc(MAX_CORO_FUNCS * 8)
|
||||
if self._coro_wake_names is not None:
|
||||
string.memset(self._coro_wake_names, 0, MAX_CORO_FUNCS * 8)
|
||||
if self._coro_wake_idxs is None:
|
||||
self._coro_wake_idxs = stdlib.malloc(MAX_CORO_FUNCS * 4)
|
||||
if self._coro_wake_idxs is not None:
|
||||
string.memset(self._coro_wake_idxs, 0, MAX_CORO_FUNCS * 4)
|
||||
self._coro_local_count = 0
|
||||
if self._coro_frames is None:
|
||||
self._coro_frames = stdlib.malloc(MAX_CORO_FUNCS * 16)
|
||||
if self._coro_frames is not None:
|
||||
string.memset(self._coro_frames, 0, MAX_CORO_FUNCS * 16)
|
||||
self._coro_frame_count = 0
|
||||
|
||||
# ============================================================
|
||||
# 主翻译入口
|
||||
# ============================================================
|
||||
def translate(self, tree: ast.AST | t.CPtr) -> int:
|
||||
"""将 AST 翻译为 LLVM IR"""
|
||||
if tree is None:
|
||||
return 1
|
||||
if _mbuddy is None:
|
||||
return 1
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = _mbuddy
|
||||
|
||||
# 初始化状态
|
||||
self._init_state(pool)
|
||||
|
||||
# 创建 LLVM 模块
|
||||
mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main")
|
||||
if mod is None:
|
||||
VLogger.error("NewModule returned NULL", "TR")
|
||||
return 1
|
||||
self.Module = mod
|
||||
|
||||
# 设置目标(优先使用 project.vpj 中的配置)
|
||||
triple: str = Config.TargetTriple
|
||||
if triple is None:
|
||||
triple = "x86_64-pc-windows-msvc"
|
||||
llvmlite.module_set_target(mod, triple)
|
||||
|
||||
# 类型
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
# 声明 printf
|
||||
printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, "printf", i32_ty)
|
||||
if printf_func is None:
|
||||
VLogger.error("CreateDeclare printf returned NULL", "TR")
|
||||
return 1
|
||||
llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt")
|
||||
printf_func.IsVarArg = 1
|
||||
# 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用)
|
||||
# declare void @llvm.va_start(i8*)
|
||||
# declare void @llvm.va_end(i8*)
|
||||
void_ty_decl: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||||
va_start_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, "llvm.va_start", void_ty_decl)
|
||||
if va_start_func is not None:
|
||||
llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap")
|
||||
va_end_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, "llvm.va_end", void_ty_decl)
|
||||
if va_end_func is not None:
|
||||
llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap")
|
||||
|
||||
# 声明 malloc(闭包分配用)
|
||||
malloc_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, "malloc", i8_ptr_ty)
|
||||
if malloc_func is not None:
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
llvmlite.add_param(pool, malloc_func, i64_ty, "size")
|
||||
|
||||
# 检查用户是否定义了 main 函数
|
||||
has_user_main: int = 0
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is not None:
|
||||
cn_count: t.CSizeT = len(ch)
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is not None and child.kind() == ast.ASTKind.FunctionDef:
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||||
if fd is not None and fd.name is not None:
|
||||
if string.strcmp(fd.name, "main") == 0:
|
||||
has_user_main = 1
|
||||
break
|
||||
|
||||
if self._declare_only != 0:
|
||||
# Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder
|
||||
self._translate_module_level(pool, mod, tree)
|
||||
elif has_user_main == 0:
|
||||
# 无用户 main → 只翻译模块级语句,不创建 wrapper main
|
||||
# 修复:避免每个文件都生成 define i32 @main() 导致链接时 main 冲突
|
||||
# 只有包含 def main() 的入口文件才会有 define i32 @main()
|
||||
self._translate_module_level(pool, mod, tree)
|
||||
else:
|
||||
# 用户已定义 main → 委托 HandlesMain 翻译模块级
|
||||
self._translate_module_level(pool, mod, tree)
|
||||
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 包装 main 函数(无用户 main 时)→ 委托 HandlesMain
|
||||
# ============================================================
|
||||
def _translate_wrapper_main(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
tree: ast.AST | t.CPtr,
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr):
|
||||
"""委托 GenApi.create_wrapper_main() 创建包装 main(trans 单参)"""
|
||||
added: int = GenApi.create_wrapper_main(self, tree, i32_ty)
|
||||
|
||||
# ============================================================
|
||||
# 模块级翻译(用户已定义 main)→ 委托 HandlesMain
|
||||
# ============================================================
|
||||
def _translate_module_level(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
tree: ast.AST | t.CPtr):
|
||||
"""委托 GenApi.translate_children() 翻译模块级语句(trans 单参)"""
|
||||
# 全量翻译模式下,先处理导入语句,再创建前向声明,解决前向引用问题
|
||||
if self._declare_only == 0:
|
||||
# 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充
|
||||
# (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入)
|
||||
# 记录最后处理的 import 行号,供 vpi 注入错误上下文帧定位
|
||||
cur_imp_lineno: int = 0
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is not None:
|
||||
cn_count: t.CSizeT = len(ch)
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
kd: int = child.kind()
|
||||
if kd == ast.ASTKind.Import:
|
||||
cur_imp_lineno = child.lineno
|
||||
GenApi.translate_import(self, child)
|
||||
elif kd == ast.ASTKind.ImportFrom:
|
||||
cur_imp_lineno = child.lineno
|
||||
GenApi.translate_import_from_module(self, child)
|
||||
GenApi.translate_import_from_names(self, child)
|
||||
# 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用
|
||||
# (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器
|
||||
# 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由
|
||||
# Phase1 注册,但源文件不显式 import 它们(TPC 在翻译前自动注入
|
||||
# import _list/_dict);TPV 用可见性机制等效替代——否则裸名
|
||||
# `d: dict` 注解 resolve_annotation_type 时 is_struct_visible=0
|
||||
# 解析失败(DictTest 的 "变量类型注解解析失败")。
|
||||
self._inject_auto_container_visibility(pool, tree)
|
||||
# 扫描当前模块的 CTypedef 声明已由 Phase1 1b 文本扫描注册
|
||||
# (RegisterCTypedefFromSource,见 Phase1Main.vp)——AST 字符串字段
|
||||
# token 零拷贝指向 src_buf,跨阶段内容不稳定,此处 AST 扫描读 attr
|
||||
# 会 0xC0000005(stdint.vp 崩溃根因),故移除。
|
||||
# 跨模块 .vpi 注入:加载依赖模块的 .vpi 文件,
|
||||
# 将函数 declare 声明注入到当前模块,解决跨模块函数调用找不到函数的问题
|
||||
# 严格保证 declare_only == 0 时才注入(避免 Phase A-pre-inc 死锁)
|
||||
if self._imported_modules is not None:
|
||||
# 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置
|
||||
GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno)
|
||||
StubMergerBuild.LoadDepVpiIntoModule(
|
||||
pool, mod, self._imported_modules, self._from_imports,
|
||||
GenApi.get_temp_dir(), self)
|
||||
GenApi.pop_trace()
|
||||
# 预注册模块级变量(AnnAssign/Assign)到 SymTab
|
||||
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
|
||||
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
|
||||
# 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None
|
||||
# 预处理先于 translate_children 注册所有模块级变量,
|
||||
# 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var
|
||||
# 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209)
|
||||
if ch is not None:
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
kd_mv: int = child.kind()
|
||||
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
|
||||
GenApi.handle_module_level_var(self, child)
|
||||
# 创建前向声明
|
||||
GenApi.forward_declare_functions(self, tree)
|
||||
added: int = GenApi.translate_children(self, tree)
|
||||
|
||||
# ============================================================
|
||||
# 容器模块自动可见性注入(对齐 TPC _inject_auto_imports)
|
||||
#
|
||||
# TPC 在翻译前自动注入 `import _list / import _dict (+json)` 到源文件,
|
||||
# 使 list/dict 内建容器类在符号表中可见。TPV 用可见性机制等效替代:
|
||||
# _list.vp/_dict.vp 已由 Phase1 注册(可达集合含它们),这里只需在
|
||||
# 当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。
|
||||
#
|
||||
# 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致):
|
||||
# - AnnAssign 注解裸名 Name(list/dict):d: dict
|
||||
# - 构造调用 func 裸名 Name(list/dict):dict(bd)
|
||||
# - Subscript 的 value 裸名 Name(list/dict):list[int]
|
||||
# ============================================================
|
||||
def _inject_auto_container_visibility(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
tree: ast.AST | t.CPtr):
|
||||
"""检测 list/dict 容器使用,注入容器类可见性"""
|
||||
if tree is None or tree.children is None:
|
||||
return
|
||||
# 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针)
|
||||
need_list_box: t.CPtr = stdlib.malloc(4)
|
||||
need_dict_box: t.CPtr = stdlib.malloc(4)
|
||||
if need_list_box is None or need_dict_box is None:
|
||||
if need_list_box is not None:
|
||||
stdlib.free(need_list_box)
|
||||
if need_dict_box is not None:
|
||||
stdlib.free(need_dict_box)
|
||||
return
|
||||
need_list_box[0] = 0
|
||||
need_dict_box[0] = 0
|
||||
self._scan_container_usage(tree, need_list_box, need_dict_box)
|
||||
if need_dict_box[0] != 0:
|
||||
# dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析)
|
||||
GenApi.add_visible_struct(pool, "dict")
|
||||
if self._imported_modules is None or \
|
||||
GenApi.is_module_imported(self._imported_modules, "_dict") == 0:
|
||||
self._imported_modules = GenApi.add_imported_module(
|
||||
pool, self._imported_modules, "_dict")
|
||||
if need_list_box[0] != 0:
|
||||
GenApi.add_visible_struct(pool, "list")
|
||||
if self._imported_modules is None or \
|
||||
GenApi.is_module_imported(self._imported_modules, "_list") == 0:
|
||||
self._imported_modules = GenApi.add_imported_module(
|
||||
pool, self._imported_modules, "_list")
|
||||
stdlib.free(need_list_box)
|
||||
stdlib.free(need_dict_box)
|
||||
|
||||
def _scan_container_usage(self, node: ast.AST | t.CPtr,
|
||||
need_list_box: t.CPtr,
|
||||
need_dict_box: t.CPtr):
|
||||
"""递归扫描 AST 语句结构,检测 list/dict 容器使用"""
|
||||
if node is None:
|
||||
return
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
aa_s: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa_s.annotation is not None:
|
||||
self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box)
|
||||
elif k == ast.ASTKind.Call:
|
||||
cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||||
if cl_s.func is not None:
|
||||
self._check_container_type_node(cl_s.func, need_list_box, need_dict_box)
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub_s.value is not None:
|
||||
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
|
||||
elif k == ast.ASTKind.List:
|
||||
# [] 字面量:容器模板仍需注册
|
||||
need_list_box[0] = 1
|
||||
elif k == ast.ASTKind.Dict:
|
||||
# {} 字面量:容器模板仍需注册
|
||||
need_dict_box[0] = 1
|
||||
# 递归语句块子节点
|
||||
if node.children is not None:
|
||||
ch_s: list[ast.AST | t.CPtr] | t.CPtr = node.children
|
||||
n_s: t.CSizeT = len(ch_s)
|
||||
for ci_s in range(n_s):
|
||||
self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box)
|
||||
|
||||
def _check_container_type_node(self, node: ast.AST | t.CPtr,
|
||||
need_list_box: t.CPtr,
|
||||
need_dict_box: t.CPtr):
|
||||
"""检测类型位置节点是否为 list/dict(支持 Name 与 Subscript 外层)"""
|
||||
if node is None:
|
||||
return
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.Name:
|
||||
nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm_s.id is not None:
|
||||
if string.strcmp(nm_s.id, "dict") == 0:
|
||||
need_dict_box[0] = 1
|
||||
elif string.strcmp(nm_s.id, "list") == 0:
|
||||
need_list_box[0] = 1
|
||||
elif k == ast.ASTKind.Subscript:
|
||||
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
|
||||
if sub_s.value is not None:
|
||||
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# IR 输出
|
||||
# ============================================================
|
||||
def dump_ir(self, buf: bytes, size: t.CSizeT, mode: int):
|
||||
"""将 LLVM IR 输出到缓冲区
|
||||
|
||||
mode: 0=完整, 1=stub(仅声明), 2=text(仅代码)
|
||||
"""
|
||||
if self.Module is None or buf is None:
|
||||
return
|
||||
if _mbuddy is None:
|
||||
return
|
||||
buf[0] = '\0'
|
||||
llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# global/nonlocal 名称管理(模块级辅助函数,委托到 gen 方法)
|
||||
# ============================================================
|
||||
def add_global_name(trans: HT.Translator | t.CPtr, name: str):
|
||||
"""添加一个 global 变量名(委托到 gen.add_global_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g.TranslatorGen.add_global_name(trans, name)
|
||||
|
||||
|
||||
def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""检查 name 是否在当前函数的 global 集合中(委托到 gen.is_global_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.TranslatorGen.is_global_name(trans, name)
|
||||
return 0
|
||||
|
||||
|
||||
def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str,
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = None):
|
||||
"""添加一个 nonlocal 变量名(委托到 gen.add_nonlocal_name)
|
||||
|
||||
Args:
|
||||
name: nonlocal 变量名
|
||||
var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复,
|
||||
None 时回退为 i32)
|
||||
"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g.TranslatorGen.add_nonlocal_name(trans, name, var_ty)
|
||||
|
||||
|
||||
def get_nonlocal_type(trans: HT.Translator | t.CPtr,
|
||||
name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""获取 nonlocal 变量的 LLVM 类型(委托到 gen.get_nonlocal_type)
|
||||
|
||||
Returns: 找到的类型指针,找不到返回 None
|
||||
"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.TranslatorGen.get_nonlocal_type(trans, name)
|
||||
return None
|
||||
|
||||
|
||||
def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""检查 name 是否在当前函数的 nonlocal 集合中(委托到 gen.is_nonlocal_name)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.TranslatorGen.is_nonlocal_name(trans, name)
|
||||
return 0
|
||||
|
||||
|
||||
def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1(委托到 gen.get_nonlocal_index)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.TranslatorGen.get_nonlocal_index(trans, name)
|
||||
return 0
|
||||
|
||||
|
||||
def clear_scope_names(trans: HT.Translator | t.CPtr):
|
||||
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)(委托到 gen.clear_scope_names)"""
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g.TranslatorGen.clear_scope_names(trans)
|
||||
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
@@ -1,9 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
# Handles 实体模块(去除委托层后保留:数据类/Translator/实体逻辑)
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.ExprCallTable as ExprCallTable
|
||||
+507
-377
@@ -1,377 +1,507 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import w32.win32file as win32file
|
||||
import w32.win32base as win32base
|
||||
import hashlib
|
||||
import viperlib
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# IncludesScanner - includes 目录递归扫描
|
||||
#
|
||||
# 递归扫描 includes 目录,收集所有 .vp/.py 文件路径和 SHA1,
|
||||
# 为 Phase1 stub 生成和 Phase2 stub 合并提供基础数据。
|
||||
#
|
||||
# 使用 Win32 FindFirstFileA/FindNextFileA 实现目录遍历。
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# 文件路径最大长度
|
||||
MAX_PATH_LEN: t.CDefine = 512
|
||||
# 单次扫描最大文件数
|
||||
MAX_FILES: t.CDefine = 1024
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FileEntry - 文件条目(路径 + SHA1)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class FileEntry:
|
||||
"""扫描到的文件条目"""
|
||||
Path: str # 文件绝对路径
|
||||
Sha1: str # SHA1 前16字符(16字节+null)
|
||||
RelPath: str # 相对于 includes 根目录的路径
|
||||
ModuleName: str # 模块名(如 "ast.parser")
|
||||
IncDir: str # 所属 includes 根目录(多 includes 目录支持)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ScanResult - 扫描结果
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ScanResult:
|
||||
"""扫描结果集合"""
|
||||
Entries: FileEntry | t.CPtr # FileEntry 数组
|
||||
Count: t.CInt
|
||||
Capacity: t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# create_scan_result - 创建扫描结果容器
|
||||
# ============================================================
|
||||
def create_scan_result(pool: memhub.MemBuddy | t.CPtr) -> ScanResult | t.CPtr:
|
||||
"""创建扫描结果容器,预分配 MAX_FILES 个槽位"""
|
||||
if pool is None:
|
||||
return None
|
||||
size: t.CSizeT = MAX_FILES * FileEntry.__sizeof__()
|
||||
# 使用 stdlib.malloc 避免 mbuddy 池耗尽(与 StubMerger 保持一致)
|
||||
entries: FileEntry | t.CPtr = stdlib.malloc(size)
|
||||
if entries is None:
|
||||
return None
|
||||
string.memset(entries, 0, size)
|
||||
|
||||
result: ScanResult | t.CPtr = stdlib.malloc(ScanResult.__sizeof__())
|
||||
if result is None:
|
||||
return None
|
||||
string.memset(result, 0, ScanResult.__sizeof__())
|
||||
result.Entries = entries
|
||||
result.Count = 0
|
||||
result.Capacity = MAX_FILES
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
# add_file_entry - 向扫描结果添加文件条目
|
||||
# ============================================================
|
||||
def add_file_entry(result: ScanResult | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
abs_path: str, rel_path: str,
|
||||
sha1: str, inc_dir: str) -> int:
|
||||
"""添加文件条目到扫描结果,返回 0 成功(inc_dir 为所属 includes 根目录)"""
|
||||
if result is None or pool is None:
|
||||
return 1
|
||||
if result.Count >= result.Capacity:
|
||||
return 1
|
||||
|
||||
# 计算模块名:rel_path 中 / 替换为 .,去掉 .vp/.py 扩展名(__init__.vp 特判由 Utils 统一处理)
|
||||
mod_buf: str = Utils.PathToModuleName(rel_path, 0)
|
||||
if mod_buf is None:
|
||||
return 1
|
||||
|
||||
# 获取条目地址
|
||||
entry_size: t.CSizeT = FileEntry.__sizeof__()
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + result.Count * entry_size
|
||||
entry: FileEntry | t.CPtr = (FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry is None:
|
||||
return 1
|
||||
|
||||
# 复制路径字符串
|
||||
abs_len: t.CSizeT = string.strlen(abs_path)
|
||||
abs_buf: str = stdlib.malloc(abs_len + 1)
|
||||
if abs_buf is None:
|
||||
return 1
|
||||
string.strcpy(abs_buf, abs_path)
|
||||
entry.Path = abs_buf
|
||||
|
||||
# 复制 SHA1
|
||||
sha1_buf: str = stdlib.malloc(17)
|
||||
if sha1_buf is None:
|
||||
return 1
|
||||
string.strcpy(sha1_buf, sha1)
|
||||
entry.Sha1 = sha1_buf
|
||||
|
||||
# 复制相对路径
|
||||
rel_buf: str = stdlib.malloc(string.strlen(rel_path) + 1)
|
||||
if rel_buf is None:
|
||||
return 1
|
||||
string.strcpy(rel_buf, rel_path)
|
||||
entry.RelPath = rel_buf
|
||||
|
||||
# 复制模块名
|
||||
entry.ModuleName = mod_buf
|
||||
|
||||
# 复制所属 includes 根目录(多 includes 目录支持,Phase2 拼路径用)
|
||||
if inc_dir is not None:
|
||||
inc_len: t.CSizeT = string.strlen(inc_dir)
|
||||
inc_buf: str = stdlib.malloc(inc_len + 1)
|
||||
if inc_buf is None:
|
||||
return 1
|
||||
string.strcpy(inc_buf, inc_dir)
|
||||
entry.IncDir = inc_buf
|
||||
|
||||
result.Count += 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# compute_file_sha1 - 读取文件内容并计算 SHA1
|
||||
#
|
||||
# 与 Projectrans.py 一致:CRLF → LF 转换后计算 SHA1。
|
||||
# Projectrans.py 用 Python 文本模式读取(自动 CRLF→LF),
|
||||
# IncludesScanner 用二进制模式读取,需手动去除 \r。
|
||||
# ============================================================
|
||||
def compute_file_sha1(pool: memhub.MemBuddy | t.CPtr,
|
||||
file_path: str) -> str:
|
||||
"""读取文件内容并计算 SHA1 前16字符(CRLF→LF 后计算,与 Projectrans.py 一致)"""
|
||||
if pool is None or file_path is None:
|
||||
return None
|
||||
|
||||
# 读取文件内容(stdlib.malloc 分配,避免 mbuddy 池耗尽)
|
||||
# BUF_SIZE 与翻译侧 SRC_BUF_SIZE(1MB)一致:若截断到 128KB,
|
||||
# 超过 128KB 的文件尾部内容变更不会改变 SHA1 → 增量缓存永不失效。
|
||||
BUF_SIZE: t.CSizeT = 1048576
|
||||
buf: bytes = Utils.read_file_to_buf(file_path, BUF_SIZE)
|
||||
if buf is None:
|
||||
return None
|
||||
|
||||
# 原地去除 \r(CRLF → LF),与 Projectrans.py 文本模式读取一致
|
||||
buf_len: t.CSizeT = string.strlen(buf)
|
||||
write_pos: t.CSizeT = 0
|
||||
for ch in buf:
|
||||
if ch != '\r':
|
||||
buf[write_pos] = ch
|
||||
write_pos += 1
|
||||
|
||||
# 添加 null 终止符
|
||||
buf[write_pos] = 0
|
||||
|
||||
# 计算 SHA1
|
||||
ctx: hashlib.sha1 | t.CPtr = hashlib.sha1()
|
||||
if ctx is None:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
ctx.update(buf)
|
||||
|
||||
digest: bytes = stdlib.malloc(hashlib.SHA1_DIGEST_LEN)
|
||||
if digest is None:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
ctx.final(digest)
|
||||
|
||||
# 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符,stdlib 分配保持原行为)
|
||||
hex_buf: str = Utils.bytes_to_hex(pool, digest, 8, 0, 1)
|
||||
stdlib.free(buf)
|
||||
stdlib.free(digest)
|
||||
return hex_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# scan_directory_recursive - 递归扫描目录
|
||||
#
|
||||
# 使用 FindFirstFileA/FindNextFileA 遍历目录树,
|
||||
# 对每个 .vp/.py 文件计算 SHA1 并添加到结果中。
|
||||
# ============================================================
|
||||
def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
root_dir: str,
|
||||
rel_prefix: str,
|
||||
result: ScanResult | t.CPtr,
|
||||
inc_dir: str) -> int:
|
||||
"""递归扫描目录,收集 .vp/.py 文件(inc_dir 为所属 includes 根目录)"""
|
||||
if pool is None or root_dir is None or result is None:
|
||||
return 1
|
||||
# 子目录递归失败计数(不静默忽略,汇总处 fail-fast 终止)
|
||||
subdir_failed: int = 0
|
||||
|
||||
# 构造搜索模式: root_dir/*
|
||||
root_len: t.CSizeT = string.strlen(root_dir)
|
||||
pattern: bytes = stdlib.malloc(root_len + 4)
|
||||
if pattern is None:
|
||||
return 1
|
||||
viperlib.snprintf(pattern, root_len + 4, "%s/*", root_dir)
|
||||
|
||||
# 使用 FindFirstFileA 开始搜索
|
||||
find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
if find_data is None:
|
||||
return 1
|
||||
string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
|
||||
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
|
||||
if handle == win32base.INVALID_HANDLE_VALUE:
|
||||
return 1
|
||||
|
||||
# 遍历所有文件和子目录
|
||||
while True:
|
||||
# 跳过 . 和 ..
|
||||
fname: str = find_data.cFileName
|
||||
if fname is not None:
|
||||
fname0: t.CChar = fname[0]
|
||||
if fname0 == '.':
|
||||
fname1: t.CChar = fname[1]
|
||||
if fname1 == '\0':
|
||||
# "."
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
elif fname1 == '.':
|
||||
fname2: t.CChar = fname[2]
|
||||
if fname2 == '\0':
|
||||
# ".."
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
|
||||
# 检查是否为目录
|
||||
is_dir: int = find_data.dwFileAttributes & win32file.FILE_ATTRIBUTE_DIRECTORY
|
||||
|
||||
# 构造完整路径
|
||||
fname_len: t.CSizeT = string.strlen(fname)
|
||||
full_path: bytes = Utils.JoinPath(root_dir, fname)
|
||||
if full_path is None:
|
||||
break
|
||||
|
||||
# 构造相对路径
|
||||
prefix_len: t.CSizeT = 0
|
||||
if rel_prefix is not None:
|
||||
prefix_len = string.strlen(rel_prefix)
|
||||
rel_path: bytes = None
|
||||
if rel_prefix is not None and prefix_len > 0:
|
||||
rel_path = Utils.JoinPath(rel_prefix, fname)
|
||||
else:
|
||||
rel_path = stdlib.malloc(fname_len + 1)
|
||||
if rel_path is None:
|
||||
break
|
||||
string.strcpy(rel_path, fname)
|
||||
if rel_path is None:
|
||||
break
|
||||
|
||||
if is_dir != 0:
|
||||
# 递归扫描子目录
|
||||
if scan_directory_recursive(pool, full_path, rel_path, result, inc_dir) != 0:
|
||||
subdir_failed += 1
|
||||
else:
|
||||
# 检查是否为 .vp 源文件(Viper 源仅 .vp,不再识别 .py)
|
||||
is_py: int = 0
|
||||
if Utils.is_vp_at(fname, 0, fname_len) != 0:
|
||||
is_py = 1
|
||||
|
||||
if is_py != 0:
|
||||
# 跳过 __pycache__ 目录下的文件
|
||||
is_pycache: int = 0
|
||||
if rel_prefix is not None:
|
||||
if string.strcmp(rel_prefix, "__pycache__") == 0:
|
||||
is_pycache = 1
|
||||
|
||||
if is_pycache == 0:
|
||||
# 计算 SHA1
|
||||
sha1: str = compute_file_sha1(pool, full_path)
|
||||
if sha1 is not None:
|
||||
add_file_entry(result, pool, full_path, rel_path, sha1, inc_dir)
|
||||
fb: str = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "扫描: %s -> %s", rel_path, sha1)
|
||||
VLogger.debug(fb, "scan")
|
||||
else:
|
||||
fb_sha: str = VLogger.fmt_buf()
|
||||
if fb_sha is not None:
|
||||
viperlib.snprintf(fb_sha, 1024, "SHA1 计算失败: %s", full_path)
|
||||
VLogger.warning(fb_sha, "scan")
|
||||
|
||||
# 继续搜索下一个文件
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
|
||||
win32file.FindClose(handle)
|
||||
if subdir_failed > 0:
|
||||
fb_sdf: str = VLogger.fmt_buf()
|
||||
if fb_sdf is not None:
|
||||
viperlib.snprintf(fb_sdf, 1024, "子目录扫描失败 %d 个", subdir_failed)
|
||||
VLogger.error(fb_sdf, "scan")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# scan_includes - 扫描 includes 目录入口
|
||||
#
|
||||
# 扫描指定的 includes 目录,返回所有 .vp/.py 文件的路径和 SHA1。
|
||||
# ============================================================
|
||||
def scan_includes(pool: memhub.MemBuddy | t.CPtr,
|
||||
includes_dirs: str) -> ScanResult | t.CPtr:
|
||||
"""扫描 includes 目录(支持空格分隔的多目录),返回所有 .vp/.py 文件的扫描结果"""
|
||||
if pool is None or includes_dirs is None:
|
||||
return None
|
||||
|
||||
result: ScanResult | t.CPtr = create_scan_result(pool)
|
||||
if result is None:
|
||||
return None
|
||||
|
||||
# 解析空格分隔的多 includes 目录(如 "../../includes ./includes"),逐目录递归扫描合并
|
||||
dirs_total: t.CSizeT = string.strlen(includes_dirs)
|
||||
d_i: t.CSizeT = 0
|
||||
while d_i < dirs_total:
|
||||
while d_i < dirs_total and includes_dirs[d_i] == ' ':
|
||||
d_i += 1
|
||||
if d_i >= dirs_total:
|
||||
break
|
||||
d_start: t.CSizeT = d_i
|
||||
while d_i < dirs_total and includes_dirs[d_i] != ' ':
|
||||
d_i += 1
|
||||
d_len: t.CSizeT = d_i - d_start
|
||||
if d_len == 0:
|
||||
continue
|
||||
dir_buf: bytes = stdlib.malloc(d_len + 1)
|
||||
if dir_buf is None:
|
||||
VLogger.error("includes 目录分配失败,终止扫描", "scan")
|
||||
string.strncpy(dir_buf, includes_dirs + d_start, d_len)
|
||||
dir_buf[d_len] = '\0'
|
||||
scan_directory_recursive(pool, dir_buf, None, result, dir_buf)
|
||||
stdlib.free(dir_buf)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
# find_entry_by_module - 按模块名查找文件条目
|
||||
# ============================================================
|
||||
def find_entry_by_module(result: ScanResult | t.CPtr,
|
||||
module_name: str) -> FileEntry | t.CPtr:
|
||||
"""按模块名查找文件条目"""
|
||||
if result is None or module_name is None:
|
||||
return None
|
||||
entry_size: t.CSizeT = FileEntry.__sizeof__()
|
||||
for i in range(result.Count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
|
||||
entry: FileEntry | t.CPtr = (FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry is not None:
|
||||
if entry.ModuleName is not None:
|
||||
if string.strcmp(entry.ModuleName, module_name) == 0:
|
||||
return entry
|
||||
return None
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import w32.win32file as win32file
|
||||
import w32.win32base as win32base
|
||||
import hashlib
|
||||
import viperlib
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# IncludesScanner - includes 目录递归扫描(Win32 FindFirstFileA/FindNextFileA)
|
||||
# 递归收集 .vp 文件路径与 SHA1,供 Phase1 stub 生成 / Phase2 stub 合并使用
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy*
|
||||
|
||||
# 文件路径最大长度
|
||||
define MAX_PATH_LEN = 512
|
||||
# 单次扫描最大文件数
|
||||
define MAX_FILES = 1024
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FileEntry - 文件条目(路径 + SHA1)
|
||||
# ============================================================
|
||||
novirtual class FileEntry:
|
||||
"""扫描到的文件条目"""
|
||||
Path: str # 文件绝对路径
|
||||
Sha1: str # SHA1 前16字符(16字节+null)
|
||||
RelPath: str # 相对于 includes 根目录的路径
|
||||
ModuleName: str # 模块名(如 "ast.parser")
|
||||
IncDir: str # 所属 includes 根目录(多 includes 目录支持)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ScanResult - 扫描结果
|
||||
# ============================================================
|
||||
novirtual class ScanResult:
|
||||
"""扫描结果集合"""
|
||||
Entries: FileEntry* # FileEntry 数组
|
||||
Count: int
|
||||
Capacity: int
|
||||
|
||||
|
||||
# ============================================================
|
||||
# create_scan_result - 创建扫描结果容器
|
||||
# ============================================================
|
||||
def create_scan_result(pool: memhub.MemBuddy*) -> ScanResult*:
|
||||
"""创建扫描结果容器,预分配 MAX_FILES 个槽位"""
|
||||
if pool is None: return None
|
||||
size: sizet = MAX_FILES * FileEntry.__sizeof__()
|
||||
# 使用 stdlib.malloc 避免 mbuddy 池耗尽(与 StubMerger 保持一致)
|
||||
entries: FileEntry* = stdlib.malloc(size)
|
||||
if entries is None: return None
|
||||
string.memset(entries, 0, size)
|
||||
|
||||
result: ScanResult* = stdlib.malloc(ScanResult.__sizeof__())
|
||||
if result is None: return None
|
||||
string.memset(result, 0, ScanResult.__sizeof__())
|
||||
result.Entries = entries
|
||||
result.Count = 0
|
||||
result.Capacity = MAX_FILES
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
# add_file_entry - 向扫描结果添加文件条目
|
||||
# ============================================================
|
||||
def add_file_entry(result: ScanResult*,
|
||||
pool: memhub.MemBuddy*,
|
||||
abs_path: str, rel_path: str,
|
||||
sha1: str, inc_dir: str) -> int:
|
||||
"""添加文件条目到扫描结果,返回 0 成功(inc_dir 为所属 includes 根目录)"""
|
||||
if result is None or pool is None: return 1
|
||||
if result.Count >= result.Capacity: return 1
|
||||
|
||||
# 计算模块名:rel_path 中 / 替换为 .,去掉 .vp/.py 扩展名(__init__.vp 特判由 Utils 统一处理)
|
||||
mod_buf: str = Utils.PathToModuleName(rel_path, 0)
|
||||
if mod_buf is None: return 1
|
||||
|
||||
# 获取条目地址
|
||||
entry_size: sizet = FileEntry.__sizeof__()
|
||||
entry_addr: uint64 = uint64(result.Entries) + result.Count * entry_size
|
||||
entry: FileEntry* = (FileEntry*)(entry_addr)
|
||||
if entry is None: return 1
|
||||
|
||||
# 复制路径字符串
|
||||
abs_len: sizet = string.strlen(abs_path)
|
||||
abs_buf: str = stdlib.malloc(abs_len + 1)
|
||||
if abs_buf is None: return 1
|
||||
string.strcpy(abs_buf, abs_path)
|
||||
entry.Path = abs_buf
|
||||
|
||||
# 复制 SHA1
|
||||
sha1_buf: str = stdlib.malloc(17)
|
||||
if sha1_buf is None: return 1
|
||||
string.strcpy(sha1_buf, sha1)
|
||||
entry.Sha1 = sha1_buf
|
||||
|
||||
# 复制相对路径
|
||||
rel_buf: str = stdlib.malloc(string.strlen(rel_path) + 1)
|
||||
if rel_buf is None: return 1
|
||||
string.strcpy(rel_buf, rel_path)
|
||||
entry.RelPath = rel_buf
|
||||
|
||||
# 复制模块名
|
||||
entry.ModuleName = mod_buf
|
||||
|
||||
# 复制所属 includes 根目录(多 includes 目录支持,Phase2 拼路径用)
|
||||
if inc_dir is not None:
|
||||
inc_len: sizet = string.strlen(inc_dir)
|
||||
inc_buf: str = stdlib.malloc(inc_len + 1)
|
||||
if inc_buf is None:
|
||||
return 1
|
||||
string.strcpy(inc_buf, inc_dir)
|
||||
entry.IncDir = inc_buf
|
||||
|
||||
result.Count += 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# compute_file_sha1 - 读取文件内容并计算 SHA1(CRLF→LF 后计算,与 Projectrans.py 一致)
|
||||
# ============================================================
|
||||
def compute_file_sha1(pool: memhub.MemBuddy*, file_path: str) -> str:
|
||||
"""读取文件内容并计算 SHA1 前16字符(CRLF→LF 后计算,与 Projectrans.py 一致)"""
|
||||
if pool is None or file_path is None: return None
|
||||
|
||||
# 读取文件内容(stdlib.malloc 分配,避免 mbuddy 池耗尽);BUF_SIZE 须与翻译侧 SRC_BUF_SIZE(1MB)一致,否则尾部变更不改 SHA1 导致缓存永不失效
|
||||
BUF_SIZE: sizet = 1048576
|
||||
buf: bytes = Utils.read_file_to_buf(file_path, BUF_SIZE)
|
||||
if buf is None: return None
|
||||
|
||||
# 原地去除 \r(CRLF → LF),与 Projectrans.py 文本模式读取一致
|
||||
buf_len: sizet = string.strlen(buf)
|
||||
write_pos: sizet = 0
|
||||
for ch in buf:
|
||||
if ch != '\r':
|
||||
buf[write_pos] = ch
|
||||
write_pos += 1
|
||||
|
||||
# 添加 null 终止符
|
||||
buf[write_pos] = 0
|
||||
|
||||
# 计算 SHA1
|
||||
ctx: rawptr[hashlib.sha1] = hashlib.sha1()
|
||||
if ctx is None:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
ctx.update(buf)
|
||||
|
||||
digest: bytes = stdlib.malloc(hashlib.SHA1_DIGEST_LEN)
|
||||
if digest is None:
|
||||
stdlib.free(buf)
|
||||
return None
|
||||
ctx.final(digest)
|
||||
|
||||
# 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符,stdlib 分配保持原行为)
|
||||
hex_buf: str = Utils.bytes_to_hex(pool, digest, 8, 0, 1)
|
||||
stdlib.free(buf)
|
||||
stdlib.free(digest)
|
||||
return hex_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# scan_directory_recursive - 递归扫描目录(FindFirstFileA/FindNextFileA 遍历目录树)
|
||||
# ============================================================
|
||||
def scan_directory_recursive(pool: memhub.MemBuddy*,
|
||||
root_dir: str,
|
||||
rel_prefix: str,
|
||||
result: ScanResult*,
|
||||
inc_dir: str) -> int:
|
||||
"""递归扫描目录,收集 .vp/.py 文件(inc_dir 为所属 includes 根目录)"""
|
||||
if pool is None or root_dir is None or result is None:
|
||||
return 1
|
||||
# 子目录递归失败计数(不静默忽略,汇总处 fail-fast 终止)
|
||||
subdir_failed: int = 0
|
||||
|
||||
# 构造搜索模式: root_dir/*
|
||||
root_len: sizet = string.strlen(root_dir)
|
||||
pattern: bytes = stdlib.malloc(root_len + 4)
|
||||
if pattern is None:
|
||||
return 1
|
||||
viperlib.snprintf(pattern, root_len + 4, "%s/*", root_dir)
|
||||
|
||||
# find_data 缓冲 +16 余量:TPV 的 WIN32_FIND_DATAA.__sizeof__() 小于 Windows 实际写入,越界写会破坏相邻堆块
|
||||
fd_size_s: sizet = win32file.WIN32_FIND_DATAA.__sizeof__()
|
||||
find_data: rawptr[win32file.WIN32_FIND_DATAA] = stdlib.malloc(fd_size_s + 16)
|
||||
if find_data is None:
|
||||
return 1
|
||||
string.memset(find_data, 0, fd_size_s + 16)
|
||||
|
||||
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
|
||||
if handle == win32base.INVALID_HANDLE_VALUE:
|
||||
return 1
|
||||
|
||||
# 遍历所有文件和子目录
|
||||
while True:
|
||||
# 跳过 . 和 ..
|
||||
fname: str = find_data.cFileName
|
||||
if fname is not None:
|
||||
fname0: char = fname[0]
|
||||
if fname0 == '.':
|
||||
fname1: char = fname[1]
|
||||
if fname1 == '\0':
|
||||
# "."
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
elif fname1 == '.':
|
||||
fname2: char = fname[2]
|
||||
if fname2 == '\0':
|
||||
# ".."
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
|
||||
# 检查是否为目录
|
||||
is_dir: int = find_data.dwFileAttributes & win32file.FILE_ATTRIBUTE_DIRECTORY
|
||||
|
||||
# 构造完整路径
|
||||
fname_len: sizet = string.strlen(fname)
|
||||
full_path: bytes = Utils.JoinPath(root_dir, fname)
|
||||
if full_path is None:
|
||||
break
|
||||
|
||||
# 构造相对路径
|
||||
prefix_len: sizet = 0
|
||||
if rel_prefix is not None:
|
||||
prefix_len = string.strlen(rel_prefix)
|
||||
rel_path: bytes = None
|
||||
if rel_prefix is not None and prefix_len > 0:
|
||||
rel_path = Utils.JoinPath(rel_prefix, fname)
|
||||
else:
|
||||
rel_path = stdlib.malloc(fname_len + 1)
|
||||
if rel_path is None:
|
||||
break
|
||||
string.strcpy(rel_path, fname)
|
||||
if rel_path is None:
|
||||
break
|
||||
|
||||
if is_dir != 0:
|
||||
# 递归扫描子目录
|
||||
if scan_directory_recursive(pool, full_path, rel_path, result, inc_dir) != 0:
|
||||
subdir_failed += 1
|
||||
else:
|
||||
# 检查是否为 .vp 源文件(Viper 源仅 .vp,不再识别 .py)
|
||||
is_py: int = 0
|
||||
if Utils.is_vp_at(fname, 0, fname_len) != 0:
|
||||
is_py = 1
|
||||
|
||||
if is_py != 0:
|
||||
# 跳过 __pycache__ 目录下的文件
|
||||
is_pycache: int = 0
|
||||
if rel_prefix is not None:
|
||||
if string.strcmp(rel_prefix, "__pycache__") == 0:
|
||||
is_pycache = 1
|
||||
|
||||
if is_pycache == 0:
|
||||
# 计算 SHA1
|
||||
sha1: str = compute_file_sha1(pool, full_path)
|
||||
if sha1 is not None:
|
||||
add_file_entry(result, pool, full_path, rel_path, sha1, inc_dir)
|
||||
VLogger.debug(f"扫描: {rel_path} -> {sha1}", "scan")
|
||||
else:
|
||||
VLogger.warning(f"SHA1 计算失败: {full_path}", "scan")
|
||||
|
||||
# 继续搜索下一个文件
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
|
||||
win32file.FindClose(handle)
|
||||
if subdir_failed > 0:
|
||||
VLogger.error(f"子目录扫描失败 {subdir_failed} 个", "scan")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# scan_includes - 扫描 includes 目录入口(返回所有 .vp 文件路径与 SHA1)
|
||||
# ============================================================
|
||||
def scan_includes(pool: memhub.MemBuddy*,
|
||||
includes_dirs: str) -> ScanResult*:
|
||||
"""扫描 includes 目录(支持空格分隔的多目录),返回所有 .vp/.py 文件的扫描结果"""
|
||||
if pool is None or includes_dirs is None:
|
||||
return None
|
||||
|
||||
result: ScanResult* = create_scan_result(pool)
|
||||
if result is None:
|
||||
return None
|
||||
|
||||
# 解析空格分隔的多 includes 目录(如 "../../includes ./includes"),逐目录递归扫描合并
|
||||
dirs_total: sizet = string.strlen(includes_dirs)
|
||||
d_i: sizet = 0
|
||||
while d_i < dirs_total:
|
||||
while d_i < dirs_total and includes_dirs[d_i] == ' ':
|
||||
d_i += 1
|
||||
if d_i >= dirs_total:
|
||||
break
|
||||
d_start: sizet = d_i
|
||||
while d_i < dirs_total and includes_dirs[d_i] != ' ':
|
||||
d_i += 1
|
||||
d_len: sizet = d_i - d_start
|
||||
if d_len == 0:
|
||||
continue
|
||||
dir_buf: bytes = stdlib.malloc(d_len + 1)
|
||||
if dir_buf is None:
|
||||
VLogger.error("includes 目录分配失败,终止扫描", "scan")
|
||||
string.strncpy(dir_buf, includes_dirs + d_start, d_len)
|
||||
dir_buf[d_len] = '\0'
|
||||
scan_directory_recursive(pool, dir_buf, None, result, dir_buf)
|
||||
stdlib.free(dir_buf)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# ============================================================
|
||||
# find_entry_by_module - 按模块名查找文件条目
|
||||
# ============================================================
|
||||
def find_entry_by_module(result: ScanResult*,
|
||||
module_name: str) -> FileEntry*:
|
||||
"""按模块名查找文件条目"""
|
||||
if result is None or module_name is None:
|
||||
return None
|
||||
entry_size: sizet = FileEntry.__sizeof__()
|
||||
for i in range(result.Count):
|
||||
entry_addr: uint64 = uint64(result.Entries) + i * entry_size
|
||||
entry: FileEntry* = (FileEntry*)(entry_addr)
|
||||
if entry is not None:
|
||||
if entry.ModuleName is not None:
|
||||
if string.strcmp(entry.ModuleName, module_name) == 0:
|
||||
return entry
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _PathExistsA - 路径存在性检查(GetFileAttributesA)
|
||||
# ============================================================
|
||||
def _PathExistsA(path: str) -> int:
|
||||
"""路径是否存在(1=存在,0=不存在/参数错误)
|
||||
|
||||
用 GetFileAttributesA(无输出缓冲)替代 FindFirstFileA:后者写
|
||||
WIN32_FIND_DATAA 结构,而 TPV 该结构 sizeof 小于 Windows 实际写入
|
||||
(约 592 字节,差距 >270 字节),会越界写坏相邻堆块(BFS 输出槽
|
||||
0x2e 崩溃根因)。GetFileAttributesA 只返回属性值,无越界风险。
|
||||
"""
|
||||
if path is None:
|
||||
return 0
|
||||
attr: ULONG = win32file.GetFileAttributesA(path)
|
||||
if attr == 0xFFFFFFFF: # INVALID_FILE_ATTRIBUTES
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _TryResolveModuleFile - 尝试单个候选路径并写输出
|
||||
#
|
||||
# Args:
|
||||
# inc_dir: includes 根目录
|
||||
# rel_seg: 模块名转出的相对路径段(ast/parser)
|
||||
# rel_len: rel_seg 长度
|
||||
# suffix: 候选后缀(".vp" 或 "/__init__.vp")
|
||||
# out_abs_path/out_rel_path/out_inc_dir: 输出槽(t.CPtr 指针)
|
||||
#
|
||||
# Returns:
|
||||
# 1 命中(已写输出),0 未命中
|
||||
# ============================================================
|
||||
def _TryResolveModuleFile(inc_dir: str, rel_seg: bytes, rel_len: sizet,
|
||||
suffix: str,
|
||||
out_abs_path: t.CPtr, out_rel_path: t.CPtr,
|
||||
out_inc_dir: t.CPtr) -> int:
|
||||
if inc_dir is None or rel_seg is None or suffix is None:
|
||||
return 0
|
||||
inc_len: sizet = string.strlen(inc_dir)
|
||||
suf_len: sizet = string.strlen(suffix)
|
||||
# 候选绝对路径: {inc}/{rel}{suffix}(手写拼接,避免 %. *s 精度修饰符)
|
||||
cand_len: sizet = inc_len + 1 + rel_len + suf_len
|
||||
cand: bytes = stdlib.malloc(cand_len + 1)
|
||||
if cand is None:
|
||||
return 0
|
||||
string.strcpy(cand, inc_dir)
|
||||
cand[inc_len] = '/'
|
||||
string.strncpy(cand + inc_len + 1, rel_seg, rel_len)
|
||||
string.strcpy(cand + inc_len + 1 + rel_len, suffix)
|
||||
if _PathExistsA(cand) == 0:
|
||||
stdlib.free(cand)
|
||||
return 0
|
||||
# 相对 includes 根目录的路径: {rel}{suffix}
|
||||
rel_path: bytes = stdlib.malloc(rel_len + suf_len + 1)
|
||||
if rel_path is None:
|
||||
stdlib.free(cand)
|
||||
return 0
|
||||
string.strncpy(rel_path, rel_seg, rel_len)
|
||||
rel_path[rel_len] = '\0'
|
||||
string.strcat(rel_path, suffix)
|
||||
# 所属 includes 根目录深拷贝:先全部分配就绪再统一写槽,
|
||||
# 避免 inc 分配失败时 abs/rel 已转移所有权造成的半写状态
|
||||
inc_buf: bytes = None
|
||||
if out_inc_dir is not None:
|
||||
inc_buf = stdlib.malloc(inc_len + 1)
|
||||
if inc_buf is None:
|
||||
stdlib.free(cand)
|
||||
stdlib.free(rel_path)
|
||||
return 0
|
||||
string.strcpy(inc_buf, inc_dir)
|
||||
# 写输出槽(stdlib 深拷贝,调用方负责 free)
|
||||
# 槽联合必须用 (sizet*):t.CPtr|t.CPtr 会被折叠成 t.CPtr,
|
||||
# [0] 变成 1 字节访问 → 指针被截断(0x2e 崩溃根因)。CSizeT 成员为
|
||||
# 8 字节,写入用 sizet(ptr) 直接转换;读取用 t\.CVoid(u64, t.CPtr)
|
||||
# 转回指针(t\.CVoid 仅配合 t.CPtr 表示 void* 强转)。
|
||||
if out_abs_path is not None:
|
||||
abs_slot: sizet* = (sizet*)(out_abs_path)
|
||||
abs_slot[0] = sizet(cand)
|
||||
else:
|
||||
stdlib.free(cand)
|
||||
if out_rel_path is not None:
|
||||
rel_slot: sizet* = (sizet*)(out_rel_path)
|
||||
rel_slot[0] = sizet(rel_path)
|
||||
else:
|
||||
stdlib.free(rel_path)
|
||||
if out_inc_dir is not None and inc_buf is not None:
|
||||
inc_slot: sizet* = (sizet*)(out_inc_dir)
|
||||
inc_slot[0] = sizet(inc_buf)
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ResolveModuleToPath - 模块名→文件路径(按文件系统按需解析,不做全量目录遍历)
|
||||
#
|
||||
# 解析规则(多 includes 目录逐个尝试,模块优先于包):
|
||||
# {inc_dir}/{mod.replace('.','/')}.vp (文件模块)
|
||||
# {inc_dir}/{mod.replace('.','/')}/__init__.vp (包模块)
|
||||
#
|
||||
# Args:
|
||||
# includes_dirs: 空格分隔的多个 includes 根目录
|
||||
# mod_name: 绝对模块名
|
||||
# out_abs_path: 输出绝对路径(stdlib.malloc,调用方负责 free)
|
||||
# out_rel_path: 输出相对 includes 根目录的路径(同上,如 ast/parser.vp)
|
||||
# out_inc_dir: 输出所属 includes 根目录(同上)
|
||||
#
|
||||
# Returns:
|
||||
# 0 找到;1 未找到/参数错误
|
||||
# ============================================================
|
||||
def ResolveModuleToPath(includes_dirs: str, mod_name: str,
|
||||
out_abs_path: t.CPtr, out_rel_path: t.CPtr,
|
||||
out_inc_dir: t.CPtr) -> int:
|
||||
if includes_dirs is None or mod_name is None:
|
||||
return 1
|
||||
mn_len: sizet = string.strlen(mod_name)
|
||||
if mn_len == 0:
|
||||
return 1
|
||||
# mod_name → 相对路径段(. → /):ast.parser → ast/parser
|
||||
rel_seg: bytes = stdlib.malloc(mn_len + 1)
|
||||
if rel_seg is None:
|
||||
return 1
|
||||
rel_len: sizet = 0
|
||||
for mi in range(mn_len):
|
||||
ch_m: char = mod_name[mi]
|
||||
if ch_m == '.':
|
||||
rel_seg[rel_len] = '/'
|
||||
else:
|
||||
rel_seg[rel_len] = ch_m
|
||||
rel_len += 1
|
||||
rel_seg[rel_len] = '\0'
|
||||
|
||||
found: int = 0
|
||||
d_total: sizet = string.strlen(includes_dirs)
|
||||
d_i: sizet = 0
|
||||
while d_i < d_total:
|
||||
while d_i < d_total and includes_dirs[d_i] == ' ':
|
||||
d_i += 1
|
||||
if d_i >= d_total:
|
||||
break
|
||||
d_start: sizet = d_i
|
||||
while d_i < d_total and includes_dirs[d_i] != ' ':
|
||||
d_i += 1
|
||||
d_len: sizet = d_i - d_start
|
||||
if d_len == 0:
|
||||
continue
|
||||
inc_dir_buf: bytes = stdlib.malloc(d_len + 1)
|
||||
if inc_dir_buf is None:
|
||||
continue
|
||||
string.strncpy(inc_dir_buf, includes_dirs + d_start, d_len)
|
||||
inc_dir_buf[d_len] = '\0'
|
||||
# 候选 1: {inc}/{rel}.vp(文件模块)
|
||||
if _TryResolveModuleFile(inc_dir_buf, rel_seg, rel_len, ".vp",
|
||||
out_abs_path, out_rel_path, out_inc_dir) != 0:
|
||||
found = 1
|
||||
stdlib.free(inc_dir_buf)
|
||||
break
|
||||
# 候选 2: {inc}/{rel}/__init__.vp(包模块)
|
||||
if _TryResolveModuleFile(inc_dir_buf, rel_seg, rel_len, "/__init__.vp",
|
||||
out_abs_path, out_rel_path, out_inc_dir) != 0:
|
||||
found = 1
|
||||
stdlib.free(inc_dir_buf)
|
||||
if found != 0:
|
||||
break
|
||||
stdlib.free(rel_seg)
|
||||
if found != 0:
|
||||
return 0
|
||||
return 1
|
||||
File diff suppressed because it is too large.
Load diff
+275
-305
@@ -1,305 +1,275 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
import memhub
|
||||
import sys
|
||||
import w32.win32console as w32cmd
|
||||
import w32.win32file as w32file
|
||||
import w32.win32base as win32base
|
||||
|
||||
|
||||
# ============================================================
|
||||
# VLogger - 原生日志系统(Windows 控制台彩色输出)
|
||||
#
|
||||
# 输出格式与 TPC (lib/core/VLogger.py) 对齐:
|
||||
# ├ INFO: message
|
||||
# ├ INFO[category]: message
|
||||
# ├ WARN: message
|
||||
# ├ ERROR: message
|
||||
# ├ SUCCESS: message
|
||||
# ├ DEBUG: message
|
||||
# ╠ CRITICAL: message (红底白字,致命错误)
|
||||
# ╠ CRITICAL[category]: message
|
||||
#
|
||||
# 分段着色:前缀符号(├/╠) 用级别色,LEVEL 标签用亮色,消息用默认色
|
||||
# CRITICAL 级别使用 ╠ 前缀和红底白字标签,与 TPC critical 对齐
|
||||
# ============================================================
|
||||
|
||||
# 日志级别
|
||||
class LogLevel(t.CEnum):
|
||||
DEBUG = 0
|
||||
INFO = 1
|
||||
WARNING = 2
|
||||
ERROR = 3
|
||||
SUCCESS = 4
|
||||
CRITICAL = 5
|
||||
|
||||
|
||||
# Win32 控制台前景色属性
|
||||
FOREGROUND_BLUE: t.CDefine = 0x0001
|
||||
FOREGROUND_GREEN: t.CDefine = 0x0002
|
||||
FOREGROUND_RED: t.CDefine = 0x0004
|
||||
FOREGROUND_INTENSITY: t.CDefine = 0x0008
|
||||
FOREGROUND_WHITE: t.CDefine = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
FOREGROUND_CYAN: t.CDefine = FOREGROUND_BLUE | FOREGROUND_GREEN
|
||||
FOREGROUND_YELLOW: t.CDefine = FOREGROUND_RED | FOREGROUND_GREEN
|
||||
FOREGROUND_MAGENTA: t.CDefine = FOREGROUND_RED | FOREGROUND_BLUE
|
||||
|
||||
# Win32 控制台背景色属性
|
||||
BACKGROUND_RED: t.CDefine = 0x0040
|
||||
BACKGROUND_GREEN: t.CDefine = 0x0020
|
||||
BACKGROUND_BLUE: t.CDefine = 0x0010
|
||||
BACKGROUND_INTENSITY: t.CDefine = 0x0080
|
||||
BACKGROUND_WHITE: t.CDefine = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class Logger:
|
||||
_level: int
|
||||
_console_handle: win32base.HANDLE
|
||||
_use_color: int
|
||||
__mbuddy__: memhub.MemBuddy | t.CPtr
|
||||
|
||||
def __init__(self, level: int = 1):
|
||||
self._level = level
|
||||
self._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE)
|
||||
self._use_color = 1
|
||||
self.__mbuddy__ = _mbuddy
|
||||
|
||||
def _set_color(self, attr: WORD) -> int:
|
||||
uc: int = self._use_color
|
||||
if uc:
|
||||
ch: win32base.HANDLE = self._console_handle
|
||||
ret: int = w32cmd.SetConsoleTextAttribute(ch, attr)
|
||||
return ret
|
||||
return 0
|
||||
|
||||
def _reset_color(self) -> int:
|
||||
if self._use_color:
|
||||
return w32cmd.SetConsoleTextAttribute(self._console_handle, FOREGROUND_WHITE)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _log - 核心日志输出(分段着色)
|
||||
#
|
||||
# 格式: ├ LEVEL: msg 或 ├ LEVEL[category]: msg
|
||||
# 分三段着色:
|
||||
# 1. 前缀符号 ├ (sym_color)
|
||||
# 2. LEVEL 标签 (level_color)
|
||||
# 3. 消息内容 (默认白色)
|
||||
# ============================================================
|
||||
def _log(self, level: int, prefix_sym: str, level_str: str, msg: str,
|
||||
sym_color: WORD, level_color: WORD,
|
||||
category: str = "") -> int:
|
||||
# 前缀符号着色
|
||||
self._set_color(sym_color)
|
||||
stdio.printf("%s ", prefix_sym)
|
||||
# LEVEL 标签着色
|
||||
self._set_color(level_color)
|
||||
stdio.printf("%s", level_str)
|
||||
self._reset_color()
|
||||
# category 可选
|
||||
if category is not None and category[0] != 0:
|
||||
stdio.printf(" [%s]", category)
|
||||
stdio.printf(": %s\n", msg)
|
||||
return 0
|
||||
|
||||
def debug(self, msg: str, category: str = "") -> int:
|
||||
return self._log(LogLevel.DEBUG, "├", "DEBUG", msg,
|
||||
FOREGROUND_INTENSITY, FOREGROUND_INTENSITY, category)
|
||||
|
||||
def info(self, msg: str, category: str = "") -> int:
|
||||
ret: int = self._log(LogLevel.INFO, "├", "INFO", msg,
|
||||
FOREGROUND_GREEN,
|
||||
FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
||||
return ret
|
||||
|
||||
def warning(self, msg: str, category: str = "") -> int:
|
||||
return self._log(LogLevel.WARNING, "├", "WARN", msg,
|
||||
FOREGROUND_YELLOW,
|
||||
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
||||
category)
|
||||
|
||||
def error(self, msg: str, category: str = "") -> int:
|
||||
ret: int = self._log(LogLevel.ERROR, "├", "ERROR", msg,
|
||||
FOREGROUND_RED,
|
||||
FOREGROUND_RED | FOREGROUND_INTENSITY, category)
|
||||
# 错误立即终止进程(避免错误后继续执行导致连锁崩溃)
|
||||
sys.exit(1)
|
||||
return ret
|
||||
|
||||
def success(self, msg: str, category: str = "") -> int:
|
||||
return self._log(LogLevel.SUCCESS, "├", "SUCCESS", msg,
|
||||
FOREGROUND_GREEN,
|
||||
FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
||||
|
||||
def critical(self, msg: str, category: str = "") -> int:
|
||||
# CRITICAL 使用 ╠ 前缀(红底白字标签,对齐 TPC critical 风格)
|
||||
return self._log(LogLevel.CRITICAL, "╠", "CRITICAL", msg,
|
||||
FOREGROUND_RED,
|
||||
BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY,
|
||||
category)
|
||||
|
||||
def set_level(self, level: int) -> int:
|
||||
self._level = level
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 高级日志方法
|
||||
# ============================================================
|
||||
|
||||
def banner(self, msg: str) -> int:
|
||||
"""输出分节标题(蓝色高亮,与 TPC banner 风格对齐)。"""
|
||||
self._set_color(FOREGROUND_BLUE | FOREGROUND_INTENSITY)
|
||||
stdio.printf("\n=== %s ===\n\n", msg)
|
||||
self._reset_color()
|
||||
return 0
|
||||
|
||||
def compile_error(self, msg: str, file: str = "", line: int = 0) -> int:
|
||||
"""格式化编译错误输出(红底白字标题 + 位置 + 错误信息)。"""
|
||||
self._set_color(BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY)
|
||||
stdio.printf(" 编译错误 ")
|
||||
self._set_color(FOREGROUND_RED | FOREGROUND_INTENSITY)
|
||||
stdio.printf("\n")
|
||||
if file is not None:
|
||||
if file[0] != 0 and line > 0:
|
||||
stdio.printf(" 位置: %s:%d\n", file, line)
|
||||
elif file[0] != 0:
|
||||
stdio.printf(" 文件: %s\n", file)
|
||||
stdio.printf(" 错误: %s\n", msg)
|
||||
self._reset_color()
|
||||
return 0
|
||||
|
||||
def compile_warning(self, msg: str, file: str = "", line: int = 0) -> int:
|
||||
"""格式化编译警告输出(黄底黑字标题 + 位置 + 警告信息)。"""
|
||||
self._set_color(BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_INTENSITY)
|
||||
stdio.printf(" 编译警告 ")
|
||||
self._set_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY)
|
||||
stdio.printf("\n")
|
||||
if file is not None:
|
||||
if file[0] != 0 and line > 0:
|
||||
stdio.printf(" 位置: %s:%d\n", file, line)
|
||||
elif file[0] != 0:
|
||||
stdio.printf(" 文件: %s\n", file)
|
||||
stdio.printf(" 警告: %s\n", msg)
|
||||
self._reset_color()
|
||||
return 0
|
||||
|
||||
|
||||
# 全局 mbuddy 指针(由 lib.InitLib 注入)
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# 全局 logger 指针
|
||||
_g_logger: Logger | t.CPtr
|
||||
|
||||
# 全局格式化缓冲区(用于带变量的日志消息,1024 字节)
|
||||
_fmt_buf: str
|
||||
|
||||
|
||||
def fmt_buf() -> str:
|
||||
"""获取全局格式化缓冲区(1024 字节)。
|
||||
|
||||
用法:
|
||||
buf: str = VLogger.fmt_buf()
|
||||
if buf is not None:
|
||||
viperlib.snprintf(buf, 1024, "翻译: %s (sha1=%s)", rp, sha1)
|
||||
log.info(buf, "Phase1")
|
||||
"""
|
||||
global _fmt_buf
|
||||
if _fmt_buf is None:
|
||||
_fmt_buf = stdlib.malloc(1024)
|
||||
return _fmt_buf
|
||||
|
||||
|
||||
def get_logger() -> Logger | t.CPtr:
|
||||
"""获取全局 logger 实例。若不存在则通过 _mbuddy 分配并初始化。"""
|
||||
global _g_logger
|
||||
if _g_logger is None:
|
||||
if _mbuddy is None:
|
||||
return None
|
||||
raw: t.CVoid | t.CPtr = _mbuddy.alloc(Logger.__sizeof__())
|
||||
if raw is None:
|
||||
return None
|
||||
_g_logger = raw
|
||||
_g_logger.__before_init__()
|
||||
_g_logger.__init__(LogLevel.INFO)
|
||||
return _g_logger
|
||||
|
||||
|
||||
def set_logger(logger: Logger | t.CPtr) -> int:
|
||||
"""设置全局 logger 实例。"""
|
||||
global _g_logger
|
||||
_g_logger = logger
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# --nowarn-register 开关(追加):抑制 Phase A 依赖类 WARN 输出——
|
||||
# ①"外部函数返回类型未登记"(HandlesExprCall)②"Phase A 依赖未就绪,
|
||||
# 下遍重试"(PhaseA-DBG)。自举编译中大量出现,刷屏影响日志收敛。
|
||||
# 仅抑制输出,不影响内部逻辑(默认 i32 推断、标记重试等照常执行)。
|
||||
# ============================================================
|
||||
_nowarn_register_flag: t.CInt = 0
|
||||
|
||||
|
||||
def set_nowarn_register(flag: int) -> None:
|
||||
"""设置 --nowarn-register(1=抑制 Phase A 依赖类 WARN 输出)"""
|
||||
global _nowarn_register_flag
|
||||
_nowarn_register_flag = flag
|
||||
|
||||
|
||||
def nowarn_register() -> int:
|
||||
"""查询 --nowarn-register 开关状态(1=抑制)"""
|
||||
return _nowarn_register_flag
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块级便捷函数(与 TPC 的 lib.core.VLogger 对齐)
|
||||
#
|
||||
# 调用方式: VLogger.info("msg", "category")
|
||||
# 无需先 get_logger(),方便各模块直接使用
|
||||
# ============================================================
|
||||
|
||||
def info(msg: str, category: str = "") -> int:
|
||||
"""输出 INFO 级别日志。"""
|
||||
log: Logger | t.CPtr = get_logger()
|
||||
if log is not None: return log.info(msg, category)
|
||||
return 0
|
||||
|
||||
|
||||
def warning(msg: str, category: str = "") -> int:
|
||||
"""输出 WARN 级别日志。"""
|
||||
log: Logger | t.CPtr = get_logger()
|
||||
if log is not None: return log.warning(msg, category)
|
||||
return 0
|
||||
|
||||
|
||||
def error(msg: str, category: str = "") -> int:
|
||||
"""输出 ERROR 级别日志并立即终止进程。"""
|
||||
log: Logger | t.CPtr = get_logger()
|
||||
if log is not None: return log.error(msg, category)
|
||||
# logger 不可用时也直接退出
|
||||
sys.exit(1)
|
||||
return 0
|
||||
|
||||
|
||||
def success(msg: str, category: str = "") -> int:
|
||||
"""输出 SUCCESS 级别日志。"""
|
||||
log: Logger | t.CPtr = get_logger()
|
||||
if log is not None: return log.success(msg, category)
|
||||
return 0
|
||||
|
||||
|
||||
def critical(msg: str, category: str = "") -> int:
|
||||
"""输出 CRITICAL 级别日志(致命错误,红底白字)。"""
|
||||
log: Logger | t.CPtr = get_logger()
|
||||
if log is not None: return log.critical(msg, category)
|
||||
return 0
|
||||
|
||||
|
||||
def debug(msg: str, category: str = "") -> int:
|
||||
"""输出 DEBUG 级别日志。"""
|
||||
log: Logger | t.CPtr = get_logger()
|
||||
if log is not None: return log.debug(msg, category)
|
||||
return 0
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
import memhub
|
||||
import sys
|
||||
import w32.win32console as w32cmd
|
||||
import w32.win32file as w32file
|
||||
import w32.win32base as win32base
|
||||
|
||||
|
||||
# ============================================================
|
||||
# VLogger - 原生日志系统(Windows 控制台彩色输出)
|
||||
# 输出格式: ├ LEVEL: message / ├ LEVEL[category]: message(与 TPC lib/core/VLogger.py 对齐)
|
||||
# ============================================================
|
||||
|
||||
# 错误恢复(REPL/JIT 模式):error 打印后 longjmp 跳回 REPL 的 setjmp 点。
|
||||
# mingw-w64 x86_64:longjmp 原型为 void longjmp(jmp_buf, int);setjmp 宏展开为
|
||||
# _setjmp(buf, NULL)(jmp_buf 实为 _JBTYPE[16],见 Repl.vp 的 _REPL_JMPBUF_SIZE)。
|
||||
extern def longjmp(buf: rawptr, val: int)
|
||||
|
||||
|
||||
# REPL 恢复点指针(由 Repl 在会话开始时注册、会话结束时清除)。
|
||||
# 生命周期 = 整个 REPL 会话:Repl 每轮片段都会重新武装(Repl.run 每轮 _setjmp +
|
||||
# Repl.ReplExecFragment 入口重注册),故它覆盖整条片段流水线(翻译 → 写 .ll →
|
||||
# llc → clang++ → LoadLibrary → GetProcAddress → 调用 → 回显),而不只是翻译期。
|
||||
# 批处理路径从不调用 set_repl_jmpbuf ⇒ 恒为 None ⇒ 所有出口退回 sys.exit(1)。
|
||||
_repl_jmpbuf: rawptr = None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# repl_abort - TPV 内"诊断后终止"的唯一出口
|
||||
#
|
||||
# 约定:调用方**已打印**诊断(Traceback / VLogger.error / [OOM] 等),本函数只决定
|
||||
# "跳回 REPL 继续"还是"终止进程":
|
||||
# * REPL 会话(_repl_jmpbuf 已注册):fflush 后 longjmp 回 Repl.run 的恢复点,
|
||||
# 进程存活、提示符继续(宽容 Traceback);
|
||||
# * 批处理 / 未武装:sys.exit(1),与改动前的 fail-fast 行为逐字一致。
|
||||
# 收敛点:Logger.error、模块级 error、TypeGenErr.fatal_error、
|
||||
# ImportsGenMixin._report_import_error、CallGenBase/VpiReader 的链表哨兵。
|
||||
# ============================================================
|
||||
def repl_abort() -> int:
|
||||
"""诊断后的统一出口:已注册恢复点则 longjmp 回 REPL,否则终止进程。"""
|
||||
if _repl_jmpbuf is not None:
|
||||
stdio.fflush(None)
|
||||
longjmp(_repl_jmpbuf, 1)
|
||||
sys.exit(1)
|
||||
return 0
|
||||
|
||||
|
||||
def set_repl_jmpbuf(buf: t.CPtr) -> int:
|
||||
"""注册 REPL 的 jmp_buf(会话开始;每片段入口可幂等重注册)。"""
|
||||
global _repl_jmpbuf
|
||||
_repl_jmpbuf = buf
|
||||
return 0
|
||||
|
||||
|
||||
def clear_repl_jmpbuf() -> int:
|
||||
"""清除已注册的 jmp_buf(REPL 会话结束时调用;中途不清)。"""
|
||||
global _repl_jmpbuf
|
||||
_repl_jmpbuf = None
|
||||
return 0
|
||||
|
||||
# 日志级别
|
||||
enum LogLevel:
|
||||
DEBUG, INFO, WARNING, ERROR, SUCCESS, CRITICAL
|
||||
|
||||
|
||||
# Win32 控制台前景色属性
|
||||
define FOREGROUND_BLUE = 0x0001
|
||||
define FOREGROUND_GREEN = 0x0002
|
||||
define FOREGROUND_RED = 0x0004
|
||||
define FOREGROUND_INTENSITY = 0x0008
|
||||
define FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
define FOREGROUND_CYAN = FOREGROUND_BLUE | FOREGROUND_GREEN
|
||||
define FOREGROUND_YELLOW = FOREGROUND_RED | FOREGROUND_GREEN
|
||||
define FOREGROUND_MAGENTA = FOREGROUND_RED | FOREGROUND_BLUE
|
||||
|
||||
# Win32 控制台背景色属性
|
||||
define BACKGROUND_RED = 0x0040
|
||||
define BACKGROUND_GREEN = 0x0020
|
||||
define BACKGROUND_BLUE = 0x0010
|
||||
define BACKGROUND_INTENSITY = 0x0080
|
||||
define BACKGROUND_WHITE = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
|
||||
|
||||
novirtual class Logger:
|
||||
_level: int
|
||||
_console_handle: win32base.HANDLE
|
||||
_use_color: int
|
||||
jit_flag: bool
|
||||
__mbuddy__: memhub.MemBuddy*
|
||||
|
||||
def __init__(self, level: int = 1):
|
||||
self._level = level
|
||||
self._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE)
|
||||
self._use_color = 1
|
||||
self.jit_flag = False
|
||||
self.__mbuddy__ = _mbuddy
|
||||
|
||||
def _set_color(self, attr: WORD) -> int:
|
||||
uc: int = self._use_color
|
||||
if uc:
|
||||
ch: win32base.HANDLE = self._console_handle
|
||||
ret: int = w32cmd.SetConsoleTextAttribute(ch, attr)
|
||||
return ret
|
||||
return 0
|
||||
|
||||
def _reset_color(self) -> int:
|
||||
if self._use_color:
|
||||
return w32cmd.SetConsoleTextAttribute(self._console_handle, FOREGROUND_WHITE)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _log - 核心日志输出(分段着色:前缀符号 ├ / LEVEL 标签 / 消息内容)
|
||||
# 格式: ├ LEVEL: msg 或 ├ LEVEL[category]: msg
|
||||
# ============================================================
|
||||
def _log(self, level: int, prefix_sym: str, level_str: str, msg: str,
|
||||
sym_color: WORD, level_color: WORD,
|
||||
category: str = "") -> int:
|
||||
# 前缀符号着色
|
||||
self._set_color(sym_color)
|
||||
stdio.printf("%s ", prefix_sym)
|
||||
# LEVEL 标签着色
|
||||
self._set_color(level_color)
|
||||
stdio.printf("%s", level_str)
|
||||
self._reset_color()
|
||||
# category 可选
|
||||
if category is not None and category[0] != 0:
|
||||
stdio.printf(" [%s]", category)
|
||||
stdio.printf(": %s\n", msg)
|
||||
return 0
|
||||
|
||||
def debug(self, msg: str, category: str = "") -> int:
|
||||
return self._log(LogLevel.DEBUG, "├", "DEBUG", msg, FOREGROUND_INTENSITY, FOREGROUND_INTENSITY, category)
|
||||
|
||||
def info(self, msg: str, category: str = "") -> int:
|
||||
ret: int = self._log(LogLevel.INFO, "├", "INFO", msg, FOREGROUND_GREEN, FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
||||
return ret
|
||||
|
||||
def warning(self, msg: str, category: str = "") -> int:
|
||||
return self._log(LogLevel.WARNING, "├", "WARN", msg, FOREGROUND_YELLOW, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
||||
|
||||
def error(self, msg: str, category: str = "") -> int:
|
||||
ret: int = self._log(LogLevel.ERROR, "├", "ERROR", msg, FOREGROUND_RED, FOREGROUND_RED | FOREGROUND_INTENSITY, category)
|
||||
# JIT/REPL 模式:诊断已打印,经统一出口跳回 REPL 循环(未武装时该出口仍终止进程)
|
||||
if self.jit_flag:
|
||||
repl_abort()
|
||||
return ret
|
||||
# 批处理模式:错误立即终止进程(行为与改动前逐字一致)
|
||||
sys.exit(1)
|
||||
return ret
|
||||
|
||||
def success(self, msg: str, category: str = "") -> int:
|
||||
return self._log(LogLevel.SUCCESS, "├", "SUCCESS", msg, FOREGROUND_GREEN, FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
||||
|
||||
def critical(self, msg: str, category: str = "") -> int:
|
||||
# CRITICAL 使用 ╠ 前缀(红底白字标签,对齐 TPC critical 风格)
|
||||
return self._log(LogLevel.CRITICAL, "╠", "CRITICAL", msg, FOREGROUND_RED, BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY, category)
|
||||
|
||||
def set_level(self, level: int) -> int:
|
||||
self._level = level
|
||||
return 0
|
||||
|
||||
def set_jit_flag(self, v: bool) -> int:
|
||||
"""设置 JIT/REPL 模式标志:True 时 error 改为 longjmp 回 REPL 循环。"""
|
||||
self.jit_flag = v
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# 高级日志方法
|
||||
# ============================================================
|
||||
|
||||
def banner(self, msg: str) -> int:
|
||||
"""输出分节标题(蓝色高亮,与 TPC banner 风格对齐)。"""
|
||||
self._set_color(FOREGROUND_BLUE | FOREGROUND_INTENSITY)
|
||||
stdio.printf("\n=== %s ===\n\n", msg)
|
||||
self._reset_color()
|
||||
return 0
|
||||
|
||||
def compile_error(self, msg: str, file: str = "", line: int = 0) -> int:
|
||||
"""格式化编译错误输出(红底白字标题 + 位置 + 错误信息)。"""
|
||||
self._set_color(BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY)
|
||||
stdio.printf(" 编译错误 ")
|
||||
self._set_color(FOREGROUND_RED | FOREGROUND_INTENSITY)
|
||||
stdio.printf("\n")
|
||||
if file is not None:
|
||||
if file[0] != 0 and line > 0:
|
||||
stdio.printf(" 位置: %s:%d\n", file, line)
|
||||
elif file[0] != 0:
|
||||
stdio.printf(" 文件: %s\n", file)
|
||||
stdio.printf(" 错误: %s\n", msg)
|
||||
self._reset_color()
|
||||
return 0
|
||||
|
||||
def compile_warning(self, msg: str, file: str = "", line: int = 0) -> int:
|
||||
"""格式化编译警告输出(黄底黑字标题 + 位置 + 警告信息)。"""
|
||||
self._set_color(BACKGROUND_RED | BACKGROUND_GREEN | FOREGROUND_INTENSITY)
|
||||
stdio.printf(" 编译警告 ")
|
||||
self._set_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY)
|
||||
stdio.printf("\n")
|
||||
if file is not None:
|
||||
if file[0] != 0 and line > 0:
|
||||
stdio.printf(" 位置: %s:%d\n", file, line)
|
||||
elif file[0] != 0:
|
||||
stdio.printf(" 文件: %s\n", file)
|
||||
stdio.printf(" 警告: %s\n", msg)
|
||||
self._reset_color()
|
||||
return 0
|
||||
|
||||
|
||||
# 全局 mbuddy 指针(由 lib.InitLib 注入)
|
||||
_mbuddy: memhub.MemBuddy*
|
||||
|
||||
# 全局 logger 指针
|
||||
logger: Logger*
|
||||
log: Logger*
|
||||
|
||||
def init_logger():
|
||||
"""初始化全局 logger 实例。"""
|
||||
global logger, log
|
||||
raw: t.CPtr = _mbuddy.alloc(Logger.__sizeof__())
|
||||
# if raw is None: return None 存疑,如何去管理内存?
|
||||
logger = raw
|
||||
logger.__before_init__()
|
||||
logger.__init__(LogLevel.INFO)
|
||||
log = logger
|
||||
# if fmtbuffer is None: return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# --nowarn-register 开关:抑制 Phase A 依赖类 WARN 输出(仅抑制输出,不影响内部逻辑)
|
||||
# ============================================================
|
||||
_nowarn_register: int = 0
|
||||
|
||||
# ============================================================
|
||||
# 模块级便捷函数(与 TPC 的 lib.core.VLogger 对齐,无需先 get_logger())
|
||||
# ============================================================
|
||||
|
||||
def info(msg: str, category: str = "") -> int:
|
||||
"""输出 INFO 级别日志。"""
|
||||
if log is not None: return log.info(msg, category)
|
||||
return 0
|
||||
|
||||
|
||||
def warning(msg: str, category: str = "") -> int:
|
||||
"""输出 WARN 级别日志。"""
|
||||
if log is not None: return log.warning(msg, category)
|
||||
return 0
|
||||
|
||||
|
||||
def error(msg: str, category: str = "") -> int:
|
||||
"""输出 ERROR 级别日志:批处理模式终止进程;JIT/REPL 模式 longjmp 回 REPL。"""
|
||||
if log is not None: return log.error(msg, category)
|
||||
# logger 不可用时也走统一出口(REPL 已注册恢复点时仍可恢复)
|
||||
repl_abort()
|
||||
return 0
|
||||
|
||||
|
||||
def success(msg: str, category: str = "") -> int:
|
||||
"""输出 SUCCESS 级别日志。"""
|
||||
if log is not None: return log.success(msg, category)
|
||||
return 0
|
||||
|
||||
|
||||
def critical(msg: str, category: str = "") -> int:
|
||||
"""输出 CRITICAL 级别日志(致命错误,红底白字)。"""
|
||||
if log is not None: return log.critical(msg, category)
|
||||
return 0
|
||||
|
||||
|
||||
def debug(msg: str, category: str = "") -> int:
|
||||
"""输出 DEBUG 级别日志。"""
|
||||
if log is not None: return log.debug(msg, category)
|
||||
return 0
|
||||
Loaded 100 of 131 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user