将 .py 和 .pyi 后缀名改为了 .vp 和 .vpi 后缀名
This commit is contained in:
1 parent
f79c8ca643
commit
cfc30d735c
322 files changed
+246
-31772
No files matched your search
@@ -1,397 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import stdlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
from json.__parser import parse as json_parse
|
||||
from json import JsonValue, JSON_OBJECT, JSON_INT
|
||||
import w32.fileio as fileio
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Config - 工程配置
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemManager | t.CPtr
|
||||
|
||||
# 配置值(从 project.vpj 加载)
|
||||
SourceDir: str
|
||||
BuildDir: str
|
||||
TempDir: str # = {BuildDir}/temp(自动计算)
|
||||
OutputDir: str # = {BuildDir}/output(自动计算)
|
||||
ProjectName: str
|
||||
ProjectVersion: str
|
||||
CompilerCmd: str
|
||||
CompilerFlags: str # 编译器参数(空格分隔,从 compiler.flags 数组拼接)
|
||||
LinkerCmd: str
|
||||
LinkerFlags: str # 链接器参数(空格分隔,从 linker.flags 数组拼接)
|
||||
LinkerOutput: str
|
||||
TargetTriple: str
|
||||
TargetDataLayout: str
|
||||
Sha1SliceLevel: t.CInt # SHA1 切片层数(目录分散等级)
|
||||
StrictMode: t.CInt
|
||||
IncludesDir: str # includes 目录路径(从 includes 数组首元素)
|
||||
|
||||
|
||||
def Load_project_config(path: str) -> int:
|
||||
"""加载工程配置文件(project.vpj)
|
||||
|
||||
Args:
|
||||
path: 配置文件路径
|
||||
|
||||
Returns:
|
||||
0 表示成功,非 0 表示失败
|
||||
"""
|
||||
global SourceDir, BuildDir, TempDir, OutputDir, ProjectName, ProjectVersion
|
||||
global CompilerCmd, CompilerFlags, LinkerCmd, LinkerFlags, LinkerOutput
|
||||
global TargetTriple, TargetDataLayout, Sha1SliceLevel, StrictMode
|
||||
global IncludesDir
|
||||
|
||||
if path is None:
|
||||
return 1
|
||||
if _mbuddy is None:
|
||||
return 1
|
||||
|
||||
# 打开文件
|
||||
f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.R)
|
||||
if f is None:
|
||||
return 1
|
||||
if f.closed:
|
||||
return 1
|
||||
|
||||
# 分配读取缓冲区
|
||||
CFG_BUF_SIZE: t.CSizeT = 8192
|
||||
buf: bytes = _mbuddy.alloc(CFG_BUF_SIZE)
|
||||
if buf is None:
|
||||
f.close()
|
||||
return 1
|
||||
|
||||
bytes_read: t.CInt64T = f.read_all(buf, CFG_BUF_SIZE)
|
||||
f.close()
|
||||
|
||||
if bytes_read <= 0:
|
||||
return 1
|
||||
|
||||
# 解析 JSON
|
||||
root: JsonValue | t.CPtr = json_parse(_mbuddy, buf)
|
||||
if root is None:
|
||||
return 1
|
||||
if not root.is_object():
|
||||
return 1
|
||||
|
||||
# 读取顶层字段(使用显式 __getitem__ 调用,兼容旧编译器二进制)
|
||||
sd_val: JsonValue | t.CPtr = root.__getitem__("source_dir")
|
||||
SourceDir = sd_val.as_string() if sd_val is not None else None
|
||||
# build_dir: 统一构建目录(默认 ./.tpv_build),temp 和 output 作为其子目录
|
||||
bd_val: JsonValue | t.CPtr = root.__getitem__("build_dir")
|
||||
if bd_val is not None and bd_val.is_string():
|
||||
BuildDir = bd_val.as_string()
|
||||
else:
|
||||
BuildDir = "./.tpv_build"
|
||||
name_val: JsonValue | t.CPtr = root.__getitem__("name")
|
||||
ProjectName = name_val.as_string() if name_val is not None else None
|
||||
ver_val: JsonValue | t.CPtr = root.__getitem__("version")
|
||||
ProjectVersion = ver_val.as_string() if ver_val is not None else None
|
||||
|
||||
# 读取 compiler 子对象
|
||||
compiler: JsonValue | t.CPtr = root.__getitem__("compiler")
|
||||
if compiler is not None and compiler.is_object():
|
||||
cc_cmd_val: JsonValue | t.CPtr = compiler.__getitem__("cmd")
|
||||
CompilerCmd = cc_cmd_val.as_string() if cc_cmd_val is not None else None
|
||||
# 读取 compiler.flags 数组,拼接成空格分隔的字符串
|
||||
cc_flags_val: JsonValue | t.CPtr = compiler.__getitem__("flags")
|
||||
CompilerFlags = _join_flags_array(cc_flags_val)
|
||||
|
||||
# 读取 linker 子对象
|
||||
linker: JsonValue | t.CPtr = root.__getitem__("linker")
|
||||
if linker is not None and linker.is_object():
|
||||
ld_cmd_val: JsonValue | t.CPtr = linker.__getitem__("cmd")
|
||||
LinkerCmd = ld_cmd_val.as_string() if ld_cmd_val is not None else None
|
||||
ld_out_val: JsonValue | t.CPtr = linker.__getitem__("output")
|
||||
LinkerOutput = ld_out_val.as_string() if ld_out_val is not None else None
|
||||
# 读取 linker.flags 数组,拼接成空格分隔的字符串
|
||||
ld_flags_val: JsonValue | t.CPtr = linker.__getitem__("flags")
|
||||
LinkerFlags = _join_flags_array(ld_flags_val)
|
||||
|
||||
# 读取 target 子对象
|
||||
target: JsonValue | t.CPtr = root.__getitem__("target")
|
||||
if target is not None and target.is_object():
|
||||
tgt_triple_val: JsonValue | t.CPtr = target.__getitem__("triple")
|
||||
TargetTriple = tgt_triple_val.as_string() if tgt_triple_val is not None else None
|
||||
tgt_dl_val: JsonValue | t.CPtr = target.__getitem__("datalayout")
|
||||
TargetDataLayout = tgt_dl_val.as_string() if tgt_dl_val is not None else None
|
||||
|
||||
# 读取 options 子对象
|
||||
# Sha1SliceLevel: SHA1 切片层数(默认 1,每层取 SHA1 前 2 字符作为子目录)
|
||||
# level=0 → 不切片,文件直接放 base_dir
|
||||
# level=1 → b7/{sha1}.ext
|
||||
# level=2 → b7/90/{sha1}.ext
|
||||
options: JsonValue | t.CPtr = root.__getitem__("options")
|
||||
Sha1SliceLevel = 1
|
||||
StrictMode = 1
|
||||
if options is not None and options.is_object():
|
||||
sl: JsonValue | t.CPtr = options.__getitem__("sha1_slice_level")
|
||||
if sl is not None and sl.is_int():
|
||||
Sha1SliceLevel = sl.as_int()
|
||||
sm: JsonValue | t.CPtr = options.__getitem__("strict_mode")
|
||||
if sm is not None and sm.is_bool():
|
||||
StrictMode = 1 if sm.as_bool() else 0
|
||||
|
||||
# 读取 includes 数组(取首个元素作为 includes 目录)
|
||||
includes_val: JsonValue | t.CPtr = root.__getitem__("includes")
|
||||
if includes_val is not None and includes_val.is_array():
|
||||
arr_len: t.CSizeT = includes_val.__len__()
|
||||
if arr_len > 0:
|
||||
first_inc: JsonValue | t.CPtr = includes_val.get_item(0)
|
||||
if first_inc is not None and first_inc.is_string():
|
||||
IncludesDir = first_inc.as_string()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def _join_flags_array(flags_val: JsonValue | t.CPtr) -> str:
|
||||
"""将 JSON 字符串数组拼接成空格分隔的字符串
|
||||
|
||||
用于 linker.flags 和 compiler.flags 数组。
|
||||
用 while + 索引遍历,避免 list 迭代器 bug。
|
||||
|
||||
Args:
|
||||
flags_val: JsonValue,应为字符串数组
|
||||
|
||||
Returns:
|
||||
空格分隔的字符串,或 None 如果 flags_val 为 None 或非数组或空数组
|
||||
"""
|
||||
if flags_val is None:
|
||||
return None
|
||||
if not flags_val.is_array():
|
||||
return None
|
||||
|
||||
arr_len: t.CSizeT = flags_val.__len__()
|
||||
if arr_len == 0:
|
||||
return None
|
||||
|
||||
# 第一遍:计算总长度(所有 flag 长度 + 空格分隔符)
|
||||
total_len: t.CSizeT = 0
|
||||
i: t.CSizeT = 0
|
||||
while i < arr_len:
|
||||
item: JsonValue | t.CPtr = flags_val.get_item(i)
|
||||
if item is not None and item.is_string():
|
||||
s: str = item.as_string()
|
||||
if s is not None:
|
||||
total_len += string.strlen(s) + 1 # +1 for space
|
||||
i += 1
|
||||
|
||||
if total_len == 0:
|
||||
return None
|
||||
|
||||
# 分配缓冲区(total_len 已含每个 flag 后的空格,最后一个是 '\0')
|
||||
buf: str = _mbuddy.alloc(total_len + 1)
|
||||
if buf is None:
|
||||
return None
|
||||
|
||||
# 第二遍:拼接(flag 之间用空格分隔)
|
||||
pos: t.CSizeT = 0
|
||||
i = 0
|
||||
while i < arr_len:
|
||||
item = flags_val.get_item(i)
|
||||
if item is not None and item.is_string():
|
||||
s = item.as_string()
|
||||
if s is not None:
|
||||
slen: t.CSizeT = string.strlen(s)
|
||||
if pos > 0:
|
||||
buf[pos] = ' '
|
||||
pos += 1
|
||||
string.strcpy(buf + pos, s)
|
||||
pos += slen
|
||||
i += 1
|
||||
buf[pos] = '\0'
|
||||
return buf
|
||||
|
||||
|
||||
def _join_path(rel: str, project_dir: str) -> str:
|
||||
"""将相对路径与 project_dir 拼接为绝对路径
|
||||
|
||||
- ./App + Test → Test/App
|
||||
- ./temp + Test → Test/temp
|
||||
- ../includes + Test → Test/../includes(OS 解析为 includes)
|
||||
- 绝对路径保持不变
|
||||
- None 返回 None
|
||||
"""
|
||||
if rel is None:
|
||||
return None
|
||||
# 绝对路径(以 / 或 \ 开头)保持不变
|
||||
if rel[0] == '/' or rel[0] == '\\':
|
||||
return rel
|
||||
|
||||
rel_len: t.CSizeT = string.strlen(rel)
|
||||
dir_len: t.CSizeT = string.strlen(project_dir)
|
||||
|
||||
# 处理 ../ 或 ..\\ 前缀:拼接 project_dir/../...
|
||||
if rel_len >= 3 and rel[0] == '.' and rel[1] == '.':
|
||||
if rel[2] == '/' or rel[2] == '\\':
|
||||
if dir_len == 0:
|
||||
return rel
|
||||
total_len: t.CSizeT = dir_len + 1 + rel_len + 1
|
||||
buf: str = _mbuddy.alloc(total_len)
|
||||
if buf is None:
|
||||
return rel
|
||||
viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel)
|
||||
return buf
|
||||
|
||||
# 处理 ./ 或 .\\ 前缀:拼接 project_dir + rel[2:]
|
||||
rel_off: t.CSizeT = 0
|
||||
if rel_len >= 2 and rel[0] == '.':
|
||||
if rel[1] == '/' or rel[1] == '\\':
|
||||
rel_off = 2
|
||||
else:
|
||||
return rel # 不是 ./ 开头,保持不变
|
||||
else:
|
||||
return rel # 不是 . 开头,保持不变
|
||||
|
||||
if dir_len == 0:
|
||||
# project_dir 为空(当前目录),去掉 ./ 前缀即可
|
||||
return rel + rel_off
|
||||
# 拼接: project_dir + "/" + rel[rel_off:]
|
||||
total_len = dir_len + 1 + (rel_len - rel_off) + 1
|
||||
buf = _mbuddy.alloc(total_len)
|
||||
if buf is None:
|
||||
return rel # 分配失败,返回原路径
|
||||
viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel + rel_off)
|
||||
return buf
|
||||
|
||||
|
||||
def resolve_paths(project_dir: str) -> int:
|
||||
"""解析并规范化工程路径(src/build/includes)
|
||||
|
||||
将 project.vpj 中的相对路径(以 ./ 开头)转换为基于 project_dir 的路径。
|
||||
BuildDir 解析后,TempDir = {BuildDir}/temp,OutputDir = {BuildDir}/output。
|
||||
|
||||
Args:
|
||||
project_dir: 工程根目录(project.vpj 所在目录)
|
||||
|
||||
Returns:
|
||||
0 表示成功,非 0 表示失败
|
||||
"""
|
||||
global SourceDir, BuildDir, TempDir, OutputDir, IncludesDir
|
||||
if project_dir is None:
|
||||
return 1
|
||||
if _mbuddy is None:
|
||||
return 1
|
||||
|
||||
SourceDir = _join_path(SourceDir, project_dir)
|
||||
BuildDir = _join_path(BuildDir, project_dir)
|
||||
|
||||
# TempDir = {BuildDir}/temp
|
||||
if BuildDir is not None:
|
||||
bd_len: t.CSizeT = string.strlen(BuildDir)
|
||||
temp_buf: str = _mbuddy.alloc(bd_len + 8)
|
||||
if temp_buf is not None:
|
||||
viperlib.snprintf(temp_buf, bd_len + 8, "%s/temp", BuildDir)
|
||||
TempDir = temp_buf
|
||||
# OutputDir = {BuildDir}/output
|
||||
output_buf: str = _mbuddy.alloc(bd_len + 8)
|
||||
if output_buf is not None:
|
||||
viperlib.snprintf(output_buf, bd_len + 8, "%s/output", BuildDir)
|
||||
OutputDir = output_buf
|
||||
|
||||
# includes 路径可能是 ../includes 形式,需要基于 project_dir 解析
|
||||
if IncludesDir is not None:
|
||||
IncludesDir = _join_path(IncludesDir, project_dir)
|
||||
return 0
|
||||
|
||||
|
||||
def get_includes_binary_dir() -> str:
|
||||
"""获取 includes.binary 目录路径(includes 目录 + .binary 后缀)
|
||||
|
||||
includes 目录如 ../includes,则 includes.binary 为 ../includes.binary
|
||||
"""
|
||||
if IncludesDir is None:
|
||||
return None
|
||||
inc_len: t.CSizeT = string.strlen(IncludesDir)
|
||||
buf: str = _mbuddy.alloc(inc_len + 8)
|
||||
if buf is None:
|
||||
return None
|
||||
viperlib.snprintf(buf, inc_len + 8, "%s.binary", IncludesDir)
|
||||
return buf
|
||||
|
||||
|
||||
def print_config():
|
||||
"""打印当前配置"""
|
||||
buf: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if buf is None:
|
||||
return
|
||||
if ProjectName is not None:
|
||||
viperlib.snprintf(buf, 1024, "project: %s v%s", ProjectName,
|
||||
ProjectVersion if ProjectVersion is not None else "?")
|
||||
VLogger.info(buf, "config")
|
||||
if SourceDir is not None:
|
||||
viperlib.snprintf(buf, 1024, "source_dir: %s", SourceDir)
|
||||
VLogger.info(buf, "config")
|
||||
if BuildDir is not None:
|
||||
viperlib.snprintf(buf, 1024, "build_dir: %s", BuildDir)
|
||||
VLogger.info(buf, "config")
|
||||
if TempDir is not None:
|
||||
viperlib.snprintf(buf, 1024, "temp_dir: %s", TempDir)
|
||||
VLogger.info(buf, "config")
|
||||
if OutputDir is not None:
|
||||
viperlib.snprintf(buf, 1024, "output_dir: %s", OutputDir)
|
||||
VLogger.info(buf, "config")
|
||||
if CompilerCmd is not None:
|
||||
viperlib.snprintf(buf, 1024, "compiler: %s", CompilerCmd)
|
||||
VLogger.info(buf, "config")
|
||||
if LinkerCmd is not None:
|
||||
viperlib.snprintf(buf, 1024, "linker: %s -> %s", LinkerCmd,
|
||||
LinkerOutput if LinkerOutput is not None else "?")
|
||||
VLogger.info(buf, "config")
|
||||
if IncludesDir is not None:
|
||||
viperlib.snprintf(buf, 1024, "includes: %s", IncludesDir)
|
||||
VLogger.info(buf, "config")
|
||||
viperlib.snprintf(buf, 1024, "sha1_slice_level: %d", Sha1SliceLevel)
|
||||
VLogger.info(buf, "config")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# slice_subdir - 根据 SHA1 和切片层数返回子目录路径
|
||||
#
|
||||
# 每层取 SHA1 的 2 个字符作为子目录名:
|
||||
# level=0 → None(不切片)
|
||||
# level=1 → "b7"
|
||||
# level=2 → "b7/90"
|
||||
# level=3 → "b7/90/23"
|
||||
#
|
||||
# Args:
|
||||
# sha1: SHA1 字符串(至少 2*level 字符)
|
||||
# level: 切片层数
|
||||
#
|
||||
# Returns:
|
||||
# 子目录路径字符串(mbuddy 分配,无需释放),level<=0 时返回 None
|
||||
# ============================================================
|
||||
def slice_subdir(sha1: str, level: int) -> str:
|
||||
"""根据 SHA1 和切片层数返回子目录路径"""
|
||||
if level <= 0 or sha1 is None:
|
||||
return None
|
||||
if _mbuddy is None:
|
||||
return None
|
||||
# 每层 2 字符 + 分隔符,最后无分隔符 + null
|
||||
# buf 大小: level * 2 + (level - 1) + 1 = level * 3
|
||||
buf_len: t.CSizeT = t.CSizeT(level * 3)
|
||||
buf: str = _mbuddy.alloc(buf_len)
|
||||
if buf is None:
|
||||
return None
|
||||
pos: int = 0
|
||||
i: int = 0
|
||||
while i < level:
|
||||
if i > 0:
|
||||
buf[pos] = '/'
|
||||
pos += 1
|
||||
idx: int = i * 2
|
||||
buf[pos] = sha1[idx]
|
||||
buf[pos + 1] = sha1[idx + 1]
|
||||
pos += 2
|
||||
i += 1
|
||||
buf[pos] = '\0'
|
||||
return buf
|
||||
@@ -1,130 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
import hashlib
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Utils - 工程工具函数
|
||||
#
|
||||
# 提供 SHA1 计算和目录清理等通用工具函数。
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 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 个十六进制字符)
|
||||
hex_buf: str = pool.alloc(17)
|
||||
if hex_buf is None:
|
||||
return None
|
||||
for i in range(8):
|
||||
hi: int = (digest[i] >> 4) & 0xF
|
||||
lo: int = digest[i] & 0xF
|
||||
if hi < 10:
|
||||
hex_buf[i * 2] = '0' + hi
|
||||
else:
|
||||
hex_buf[i * 2] = 'a' + (hi - 10)
|
||||
if lo < 10:
|
||||
hex_buf[i * 2 + 1] = '0' + lo
|
||||
else:
|
||||
hex_buf[i * 2 + 1] = 'a' + (lo - 10)
|
||||
hex_buf[16] = '\0'
|
||||
return hex_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 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 1:
|
||||
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:
|
||||
fname_len: t.CSizeT = string.strlen(fname)
|
||||
full_path: bytes = stdlib.malloc(dir_len + fname_len + 2)
|
||||
if full_path is not None:
|
||||
viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", dir_path, fname)
|
||||
# 检查是否为目录(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
|
||||
@@ -1,12 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
from .Config import Load_project_config, resolve_paths
|
||||
from .Utils import compute_sha1, CleanDir
|
||||
|
||||
__all__ = [
|
||||
'Load_project_config',
|
||||
'resolve_paths',
|
||||
'compute_sha1',
|
||||
'CleanDir',
|
||||
]
|
||||
@@ -1,28 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lib 包入口 - 声明全局 _mbuddy 内存池指针
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 内存池指针(由 App/main.py 初始化后注入)
|
||||
# 注意: 使用 MemBuddy 类型而非 MemManager,避免虚函数分派不工作时调用父类 alloc 返回 None
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
|
||||
def InitLib(mb: memhub.MemBuddy | t.CPtr) -> int:
|
||||
"""初始化 lib 包的全局 _mbuddy 指针,并级联注入到所有子模块。
|
||||
|
||||
Args:
|
||||
mb: memhub.MemBuddy 实例指针
|
||||
|
||||
Returns:
|
||||
0 表示成功,非 0 表示失败
|
||||
"""
|
||||
if mb is None:
|
||||
return 1
|
||||
VLogger._mbuddy = mb
|
||||
return 0
|
||||
@@ -1,624 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import subprocess
|
||||
import viperlib
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
# ============================================================
|
||||
# BuildPipeline - 编译管线
|
||||
#
|
||||
# 负责将 LLVM IR 编译为可执行文件:
|
||||
# 1. 写 .ll 文件到 temp 目录
|
||||
# 2. 调用 llc 编译 .ll → .obj
|
||||
# 3. 调用 clang++ 链接 .obj → .exe
|
||||
# ============================================================
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# 源代码缓冲区大小(1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TranslateFileGetTrans - 翻译单个文件,返回 Translator 对象
|
||||
#
|
||||
# 读取文件 → AST 解析 → LLVM IR 翻译,返回 Translator 对象供
|
||||
# 调用者 dump_ir。命名空间隔离:includes 文件宽松模式(全部可见),
|
||||
# 用户文件严格模式(仅本地+import)。
|
||||
#
|
||||
# Args:
|
||||
# mb: 内存池
|
||||
# file_path: 源文件路径
|
||||
# sha1_val: 文件内容的 SHA1 前16字符(用于函数名混淆)
|
||||
#
|
||||
# Returns:
|
||||
# Translator 对象(None 失败)
|
||||
# ============================================================
|
||||
def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
sha1_val: str,
|
||||
current_package: str = None,
|
||||
declare_only: int = 0) -> HandlesTranslator.Translator | t.CPtr:
|
||||
"""翻译文件,返回 Translator 对象(调用者负责 dump_ir),None 失败
|
||||
|
||||
current_package: 当前文件所属包名(用于解析相对导入),None 表示顶级模块
|
||||
declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体)
|
||||
"""
|
||||
if file_path is None:
|
||||
return None
|
||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
return None
|
||||
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
if src_buf is None:
|
||||
f.close()
|
||||
return None
|
||||
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
||||
f.close()
|
||||
if bytes_read <= 0:
|
||||
stdlib.free(src_buf)
|
||||
return None
|
||||
if bytes_read < SRC_BUF_SIZE:
|
||||
src_buf[bytes_read] = 0
|
||||
else:
|
||||
src_buf[SRC_BUF_SIZE - 1] = 0
|
||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||
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)
|
||||
# parse 完成后 AST 树已独立,释放源代码缓冲区(避免 1MB/文件泄漏)
|
||||
stdlib.free(src_buf)
|
||||
if tree is None:
|
||||
return None
|
||||
tr: HandlesTranslator.Translator | t.CPtr = mb.alloc(HandlesTranslator.Translator.__sizeof__())
|
||||
tr.__before_init__()
|
||||
tr.__init__()
|
||||
tr.ModuleSha1 = sha1_val
|
||||
tr.CurrentPackage = current_package
|
||||
tr._declare_only = declare_only
|
||||
# 设置当前文件名(供报错使用)
|
||||
HandlesType.set_current_file(file_path)
|
||||
# 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离
|
||||
HandlesType.clear_cdefine_constants()
|
||||
# 命名空间隔离:includes 文件宽松模式(全部可见),用户文件严格模式(仅本地+import)
|
||||
strict_mode: int = 1
|
||||
if string.strstr(file_path, "includes") is not None:
|
||||
strict_mode = 0
|
||||
HandlesStruct.reset_visible_structs(mb, strict_mode)
|
||||
ret: int = tr.translate(tree)
|
||||
if ret != 0:
|
||||
return None
|
||||
return tr
|
||||
|
||||
|
||||
class BuildResult:
|
||||
Success: t.CInt
|
||||
OutputPath: str
|
||||
ErrorMsg: str
|
||||
|
||||
def __new__(self) -> t.CPtr:
|
||||
return t.CPtr(_mbuddy.alloc(BuildResult.__sizeof__()))
|
||||
|
||||
def __init__(self):
|
||||
self.Success = 0
|
||||
self.OutputPath = None
|
||||
self.ErrorMsg = None
|
||||
|
||||
|
||||
def ensure_dir(path: str) -> int:
|
||||
"""递归创建目录(类似 mkdir -p),目录已存在视为成功
|
||||
|
||||
Args:
|
||||
path: 目录路径(支持 / 或 \\ 分隔符)
|
||||
|
||||
Returns:
|
||||
0 成功(包括目录已存在),非 0 失败
|
||||
"""
|
||||
if path is None:
|
||||
return 1
|
||||
|
||||
path_len: t.CSizeT = string.strlen(path)
|
||||
if path_len == 0:
|
||||
return 0
|
||||
|
||||
# 复制路径到可写缓冲区(逐级截断用)
|
||||
buf: bytes = _mbuddy.alloc(path_len + 1)
|
||||
if buf is None:
|
||||
return 1
|
||||
string.strcpy(buf, path)
|
||||
|
||||
# 遇到分隔符时临时截断,创建每一层目录
|
||||
# CreateDirectoryA 在目录已存在时返回 0(失败),忽略即可
|
||||
i: int = 0
|
||||
plen: int = path_len
|
||||
while i < plen:
|
||||
ch: int = buf[i]
|
||||
if ch == 47 or ch == 92: # '/' = 47, '\\' = 92
|
||||
saved: int = ch
|
||||
buf[i] = '\0'
|
||||
w32.win32file.CreateDirectoryA(buf, None)
|
||||
buf[i] = saved
|
||||
i += 1
|
||||
|
||||
# 创建最终目录
|
||||
w32.win32file.CreateDirectoryA(buf, None)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# build_sliced_path - 构建切片路径并确保目录存在
|
||||
#
|
||||
# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录:
|
||||
# level=0 → {base_dir}/{sha1}.{ext}
|
||||
# level=1 → {base_dir}/b7/{sha1}.{ext}
|
||||
# level=2 → {base_dir}/b7/90/{sha1}.{ext}
|
||||
#
|
||||
# 自动调用 ensure_dir 创建子目录。
|
||||
#
|
||||
# Args:
|
||||
# base_dir: 基础目录(如 temp_dir)
|
||||
# sha1: SHA1 字符串
|
||||
# ext: 文件扩展名(如 "stub.ll")
|
||||
#
|
||||
# Returns:
|
||||
# 完整文件路径(mbuddy 分配),None 失败
|
||||
# ============================================================
|
||||
def build_sliced_path(base_dir: str, sha1: str, ext: str) -> str:
|
||||
"""构建切片路径并确保目录存在"""
|
||||
if base_dir is None or sha1 is None or ext is None:
|
||||
return None
|
||||
|
||||
subdir: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel)
|
||||
base_len: t.CSizeT = string.strlen(base_dir)
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
ext_len: t.CSizeT = string.strlen(ext)
|
||||
|
||||
if subdir is not None:
|
||||
sub_len: t.CSizeT = string.strlen(subdir)
|
||||
# ensure_dir({base_dir}/{subdir})
|
||||
dir_path: str = _mbuddy.alloc(base_len + sub_len + 2)
|
||||
if dir_path is not None:
|
||||
viperlib.snprintf(dir_path, base_len + sub_len + 2, "%s/%s", base_dir, subdir)
|
||||
ensure_dir(dir_path)
|
||||
# 文件路径: {base_dir}/{subdir}/{sha1}.{ext}
|
||||
path_len: t.CSizeT = base_len + sub_len + sha1_len + ext_len + 4
|
||||
path: str = _mbuddy.alloc(path_len)
|
||||
if path is None:
|
||||
return None
|
||||
viperlib.snprintf(path, path_len, "%s/%s/%s.%s", base_dir, subdir, sha1, ext)
|
||||
return path
|
||||
else:
|
||||
# 无切片: {base_dir}/{sha1}.{ext}
|
||||
path_len = base_len + sha1_len + ext_len + 3
|
||||
path = _mbuddy.alloc(path_len)
|
||||
if path is None:
|
||||
return None
|
||||
viperlib.snprintf(path, path_len, "%s/%s.%s", base_dir, sha1, ext)
|
||||
return path
|
||||
|
||||
|
||||
def write_ir_to_file(ir_buf: bytes, ir_len: t.CSizeT, output_dir: str, module_name: str) -> int:
|
||||
"""将 IR 缓冲区写入 .ll 文件
|
||||
|
||||
Args:
|
||||
ir_buf: IR 文本缓冲区
|
||||
ir_len: IR 文本长度
|
||||
output_dir: 输出目录(temp 或 output)
|
||||
module_name: 模块名(SHA1)
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
if ir_buf is None or output_dir is None or module_name is None:
|
||||
return 1
|
||||
|
||||
# 构造切片路径: output_dir/{sha1前缀}/{module_name}.ll
|
||||
path: str = build_sliced_path(output_dir, module_name, "ll")
|
||||
if path is None:
|
||||
return 1
|
||||
|
||||
# 打开文件写入
|
||||
f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.W)
|
||||
if f.closed:
|
||||
return 1
|
||||
|
||||
written: t.CInt64T = f.write(ir_buf, ir_len)
|
||||
f.close()
|
||||
if written < 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: str, cc_flags: str) -> int:
|
||||
"""调用 llc 将 .ll 编译为 .obj
|
||||
|
||||
Args:
|
||||
ir_path: .ll 文件路径
|
||||
output_dir: 输出目录
|
||||
module_name: 模块名(SHA1,用于生成 .obj 文件名)
|
||||
cc_cmd: 编译器命令(如 "llc")
|
||||
cc_flags: 编译器参数(如 "-filetype=obj -relocation-model=pic")
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
if ir_path is None or cc_cmd is None or output_dir is None or module_name is None:
|
||||
return 1
|
||||
|
||||
# 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj
|
||||
obj_path: str = build_sliced_path(output_dir, module_name, "obj")
|
||||
if obj_path is None:
|
||||
return 1
|
||||
|
||||
# 构造命令: llc -filetype=obj -o {obj_path} ir_path
|
||||
cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(obj_path) + string.strlen(ir_path) + 64
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
return 1
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", cc_cmd, cc_flags, obj_path, ir_path)
|
||||
|
||||
# 用 stdlib.system() 直接在控制台运行,输出直接显示
|
||||
# 避免 subprocess 管道捕获丢失输出
|
||||
sys_ret: int = stdlib.system(cmd)
|
||||
if sys_ret != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "编译失败 (module=%s, cmd=%s)", module_name, cmd)
|
||||
VLogger.error(fb, "LLC")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _CollectObjFilesImpl(base_dir: str, bd_len: t.CSizeT,
|
||||
out_buf: bytes, out_pos: t.CSizeT, out_size: t.CSizeT) -> t.CSizeT:
|
||||
"""递归扫描 base_dir,收集 .obj 文件路径到 out_buf,返回新的 out_pos
|
||||
|
||||
支持切片子目录(如 dir/43/{sha1}.obj)。
|
||||
"""
|
||||
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
if find_data is None:
|
||||
return out_pos
|
||||
string.memset(find_data, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
|
||||
pattern: bytes = _mbuddy.alloc(bd_len + 8)
|
||||
if pattern is None:
|
||||
return out_pos
|
||||
viperlib.snprintf(pattern, bd_len + 8, "%s/*", base_dir)
|
||||
|
||||
handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, find_data)
|
||||
_mbuddy.free(pattern)
|
||||
if handle == w32.win32base.INVALID_HANDLE_VALUE:
|
||||
return out_pos
|
||||
|
||||
while True:
|
||||
fname: str = find_data.cFileName
|
||||
if fname is not None:
|
||||
fname_len: t.CSizeT = string.strlen(fname)
|
||||
if fname_len > 0:
|
||||
# 跳过 . 和 ..
|
||||
is_dot: int = 0
|
||||
if fname_len == 1 and fname[0] == '.':
|
||||
is_dot = 1
|
||||
elif fname_len == 2 and fname[0] == '.' and fname[1] == '.':
|
||||
is_dot = 1
|
||||
if is_dot == 0:
|
||||
attrs: ULONG = find_data.dwFileAttributes
|
||||
is_dir: int = 0
|
||||
if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
|
||||
is_dir = 1
|
||||
if is_dir != 0:
|
||||
# 递归扫描子目录
|
||||
sub_dir: bytes = _mbuddy.alloc(bd_len + fname_len + 2)
|
||||
if sub_dir is not None:
|
||||
viperlib.snprintf(sub_dir, bd_len + fname_len + 2, "%s/%s", base_dir, fname)
|
||||
sub_len: t.CSizeT = string.strlen(sub_dir)
|
||||
out_pos = _CollectObjFilesImpl(sub_dir, sub_len, out_buf, out_pos, out_size)
|
||||
_mbuddy.free(sub_dir)
|
||||
else:
|
||||
# 检查是否是 .obj 文件
|
||||
if fname_len > 4:
|
||||
if fname[fname_len - 4] == '.' and fname[fname_len - 3] == 'o' and fname[fname_len - 2] == 'b' and fname[fname_len - 1] == 'j':
|
||||
need: t.CSizeT = bd_len + 1 + fname_len + 2
|
||||
if out_pos + need < out_size:
|
||||
if out_pos > 0:
|
||||
out_buf[out_pos] = ' '
|
||||
out_pos += 1
|
||||
viperlib.snprintf(out_buf + out_pos, need, "%s/%s", base_dir, fname)
|
||||
out_pos += bd_len + 1 + fname_len
|
||||
else:
|
||||
break
|
||||
|
||||
if w32.win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
|
||||
w32.win32file.FindClose(handle)
|
||||
return out_pos
|
||||
|
||||
|
||||
def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT:
|
||||
"""递归扫描 includes_binary_dir 目录,收集所有 .obj 文件路径到 out_buf
|
||||
|
||||
支持切片子目录(如 includes_binary_dir/43/{sha1}.obj)。
|
||||
|
||||
Args:
|
||||
includes_binary_dir: includes.binary 目录路径
|
||||
out_buf: 输出缓冲区(用于存放空格分隔的 .obj 文件路径)
|
||||
out_size: 输出缓冲区大小
|
||||
|
||||
Returns:
|
||||
写入的字节数(不含 null 终止符),0 表示无文件或错误
|
||||
"""
|
||||
if includes_binary_dir is None or out_buf is None or out_size == 0:
|
||||
return 0
|
||||
|
||||
out_buf[0] = '\0'
|
||||
dir_len: t.CSizeT = string.strlen(includes_binary_dir)
|
||||
out_pos: t.CSizeT = _CollectObjFilesImpl(includes_binary_dir, dir_len, out_buf, 0, out_size)
|
||||
out_buf[out_pos] = '\0'
|
||||
return out_pos
|
||||
|
||||
|
||||
def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_flags: str, linker_output: str,
|
||||
includes_binary_dir: str) -> int:
|
||||
"""调用 clang++ 链接 .obj 为 .exe
|
||||
|
||||
Args:
|
||||
output_dir: 输出目录(包含 .obj 文件)
|
||||
module_name: 模块名(SHA1)
|
||||
linker_cmd: 链接器命令(如 "clang++")
|
||||
linker_flags: 链接器参数
|
||||
linker_output: 输出文件名(如 "test.exe")
|
||||
includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj)
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
if output_dir is None or linker_cmd is None or module_name is None:
|
||||
return 1
|
||||
|
||||
# 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj
|
||||
obj_path: str = build_sliced_path(output_dir, module_name, "obj")
|
||||
if obj_path is None:
|
||||
return 1
|
||||
|
||||
# 收集 includes.binary 的 .obj 文件路径
|
||||
EXTRA_BUF_SIZE: t.CSizeT = 32768
|
||||
extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE)
|
||||
if extra_objs is None:
|
||||
return 1
|
||||
extra_len: t.CSizeT = 0
|
||||
if includes_binary_dir is not None:
|
||||
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
|
||||
if extra_len > 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "附加 %d 字节的 includes.binary .obj 文件", extra_len)
|
||||
VLogger.info(fb, "link")
|
||||
else:
|
||||
fb = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "includes.binary 无 .obj 文件: %s", includes_binary_dir)
|
||||
VLogger.warning(fb, "link")
|
||||
|
||||
# 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags
|
||||
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
|
||||
cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(obj_path) + string.strlen(linker_flags) + string.strlen(output_dir) + string.strlen(linker_output) + extra_len + 128
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
return 1
|
||||
if extra_len > 0:
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s/%s %s",
|
||||
linker_cmd, obj_path, extra_objs,
|
||||
output_dir, linker_output, linker_flags)
|
||||
else:
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s %s",
|
||||
linker_cmd, obj_path, output_dir, linker_output,
|
||||
linker_flags)
|
||||
|
||||
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
||||
if result is None:
|
||||
VLogger.error("subprocess.run 返回 None", "link")
|
||||
return 1
|
||||
if result.returncode != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d", result.returncode)
|
||||
VLogger.error(fb, "link")
|
||||
fb = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "命令: %s", cmd)
|
||||
VLogger.error(fb, "link")
|
||||
# 显示链接器错误输出
|
||||
# 注意: subprocess 在 Windows 下将 stderr 合并到 stdout,result.stderr 总是 None
|
||||
if result.stdout is not None:
|
||||
VLogger.error(result.stdout, "link")
|
||||
else:
|
||||
VLogger.error("无输出捕获", "link")
|
||||
if result.stderr is not None:
|
||||
VLogger.error(result.stderr, "link")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
|
||||
temp_dir: str, output_dir: str, module_name: str,
|
||||
cc_cmd: str, cc_flags: str) -> int:
|
||||
"""编译 IR 到 .obj(不链接)
|
||||
|
||||
Args:
|
||||
ir_buf: LLVM IR 文本缓冲区
|
||||
ir_len: IR 文本长度
|
||||
temp_dir: 临时目录
|
||||
output_dir: 输出目录
|
||||
module_name: 模块名(SHA1)
|
||||
cc_cmd: 编译器命令
|
||||
cc_flags: 编译器参数
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
if ir_buf is None or temp_dir is None or output_dir is None or module_name is None:
|
||||
return 1
|
||||
|
||||
# Step 1: 写 .ll 文件
|
||||
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
|
||||
if ret != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", module_name)
|
||||
VLogger.error(fb, "compile")
|
||||
return 1
|
||||
|
||||
# Step 2: 构造切片 .ll 路径并编译 → .obj
|
||||
ir_path: str = build_sliced_path(temp_dir, module_name, "ll")
|
||||
if ir_path is None:
|
||||
return 1
|
||||
|
||||
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
|
||||
if ret != 0:
|
||||
fb = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "llc 编译失败: %s", module_name)
|
||||
VLogger.error(fb, "compile")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
|
||||
linker_cmd: str, linker_flags: str, linker_output: str,
|
||||
includes_binary_dir: str) -> int:
|
||||
"""链接多个 .obj 文件为 .exe
|
||||
|
||||
Args:
|
||||
obj_paths: 空格分隔的 .obj 文件完整路径字符串
|
||||
obj_paths_len: obj_paths 长度
|
||||
linker_cmd: 链接器命令(如 "clang++")
|
||||
linker_flags: 链接器参数
|
||||
linker_output: 输出文件完整路径
|
||||
includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj)
|
||||
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
if obj_paths is None or obj_paths_len == 0 or linker_cmd is None:
|
||||
return 1
|
||||
|
||||
# 收集 includes.binary 的 .obj 文件路径
|
||||
EXTRA_BUF_SIZE: t.CSizeT = 32768
|
||||
extra_objs: bytes = _mbuddy.alloc(EXTRA_BUF_SIZE)
|
||||
if extra_objs is None:
|
||||
return 1
|
||||
extra_len: t.CSizeT = 0
|
||||
if includes_binary_dir is not None:
|
||||
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
|
||||
|
||||
# 构造命令: clang++ obj_paths extra_objs -o linker_output linker_flags
|
||||
cmd_len: t.CSizeT = string.strlen(linker_cmd) + obj_paths_len + string.strlen(linker_flags) + string.strlen(linker_output) + extra_len + 128
|
||||
cmd: bytes = _mbuddy.alloc(cmd_len)
|
||||
if cmd is None:
|
||||
return 1
|
||||
if extra_len > 0:
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s %s",
|
||||
linker_cmd, obj_paths, extra_objs,
|
||||
linker_output, linker_flags)
|
||||
else:
|
||||
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s",
|
||||
linker_cmd, obj_paths, linker_output, linker_flags)
|
||||
|
||||
# 用 subprocess.run 捕获 clang++ 的 stdout/stderr 输出
|
||||
# 之前用 stdlib.system() 无法捕获具体错误(undefined reference 等),
|
||||
# 导致 1.txt 中只看到"链接失败,返回码: 1"而看不到未解析符号
|
||||
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
||||
if result is None:
|
||||
VLogger.error("subprocess.run 返回 None", "link")
|
||||
return 1
|
||||
if result.returncode != 0:
|
||||
# 先用 stdio.printf 直接输出 clang++ 的完整错误输出(含 undefined reference)
|
||||
# 必须在 VLogger.error 之前输出,因为 VLogger.error 会调用 sys.exit(1) 终止进程
|
||||
if result.stdout is not None:
|
||||
stdio.printf("=== clang++ 链接错误输出 ===\n%s\n", result.stdout)
|
||||
if result.stderr is not None:
|
||||
stdio.printf("=== clang++ stderr ===\n%s\n", result.stderr)
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", result.returncode, cmd)
|
||||
VLogger.error(fb, "link")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def run_pipeline(ir_buf: bytes, ir_len: t.CSizeT,
|
||||
temp_dir: str, output_dir: str, module_name: str,
|
||||
cc_cmd: str, cc_flags: str,
|
||||
linker_cmd: str, linker_flags: str, linker_output: str,
|
||||
includes_binary_dir: str) -> BuildResult | t.CPtr:
|
||||
"""执行完整编译管线
|
||||
|
||||
Args:
|
||||
ir_buf: LLVM IR 文本缓冲区
|
||||
ir_len: IR 文本长度
|
||||
temp_dir: 临时目录
|
||||
output_dir: 输出目录
|
||||
module_name: 模块名
|
||||
cc_cmd: 编译器命令
|
||||
cc_flags: 编译器参数
|
||||
linker_cmd: 链接器命令
|
||||
linker_flags: 链接器参数
|
||||
linker_output: 输出文件名
|
||||
includes_binary_dir: includes.binary 目录路径(链接时附加预编译 .obj)
|
||||
|
||||
Returns:
|
||||
BuildResult 对象
|
||||
"""
|
||||
result: BuildResult | t.CPtr = BuildResult()
|
||||
if result is None:
|
||||
return None
|
||||
|
||||
# Step 0: 确保 temp/output 目录存在(自动创建,避免写文件失败)
|
||||
ensure_dir(temp_dir)
|
||||
ensure_dir(output_dir)
|
||||
|
||||
# Step 1: 写 .ll 文件
|
||||
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
|
||||
if ret != 0:
|
||||
result.Success = 0
|
||||
result.ErrorMsg = "写 .ll 文件失败"
|
||||
return result
|
||||
|
||||
# Step 2: llc 编译 .ll → .obj
|
||||
# 构造切片 .ll 文件路径
|
||||
ir_path: str = build_sliced_path(temp_dir, module_name, "ll")
|
||||
if ir_path is None:
|
||||
result.Success = 0
|
||||
result.ErrorMsg = "内存分配失败"
|
||||
return result
|
||||
|
||||
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
|
||||
if ret != 0:
|
||||
result.Success = 0
|
||||
result.ErrorMsg = "llc 编译失败"
|
||||
return result
|
||||
|
||||
# Step 3: clang++ 链接 .obj → .exe(附加 includes.binary 预编译 .obj)
|
||||
ret = link_obj_to_exe(output_dir, module_name, linker_cmd, linker_flags, linker_output,
|
||||
includes_binary_dir)
|
||||
if ret != 0:
|
||||
result.Success = 0
|
||||
result.ErrorMsg = "链接失败"
|
||||
return result
|
||||
|
||||
result.Success = 1
|
||||
return result
|
||||
@@ -1,504 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesAnnAssign - AnnAssign 语句处理(Mixin 继承模式)
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数)
|
||||
#
|
||||
# 支持两种形式:
|
||||
# 1. Attribute(Name('t'), 'CDefine')
|
||||
# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解)
|
||||
# ============================================================
|
||||
def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int:
|
||||
"""检测注解是否为 t.CDefine,返回 1 表示是,0 表示否"""
|
||||
if annot is None:
|
||||
return 0
|
||||
k: int = annot.kind()
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||||
if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0:
|
||||
return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||
if is_cdefine_annotation(bop.left) != 0:
|
||||
return 1
|
||||
if is_cdefine_annotation(bop.right) != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数)
|
||||
#
|
||||
# 支持的表达式形式:
|
||||
# 1. Constant(INT) — 如 0x0002, 42
|
||||
# 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN
|
||||
# 3. Name — 引用已注册的 CDefine 常量
|
||||
# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数
|
||||
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
|
||||
# ============================================================
|
||||
def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
|
||||
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp)"""
|
||||
if val_node is None:
|
||||
return 0
|
||||
k: int = val_node.kind()
|
||||
|
||||
# Case 1: Constant(INT) — 如 0x0002
|
||||
if k == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||||
if cn.const_kind != ast.CONST_INT:
|
||||
return 0
|
||||
return cn.int_val
|
||||
|
||||
# Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(val_node)
|
||||
left_val: int = extract_cdefine_int_value(bop.left)
|
||||
right_val: int = extract_cdefine_int_value(bop.right)
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
return left_val | right_val
|
||||
if bop.op == ast.OpKind.BitAnd:
|
||||
return left_val & right_val
|
||||
if bop.op == ast.OpKind.Add:
|
||||
return left_val + right_val
|
||||
if bop.op == ast.OpKind.Sub:
|
||||
return left_val - right_val
|
||||
return 0
|
||||
|
||||
# Case 3: Name — 引用已注册的 CDefine 常量
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||||
if nm.id is not None:
|
||||
looked_up: int = HandlesType.lookup_cdefine_constant(nm.id)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
return looked_up
|
||||
return 0
|
||||
|
||||
# Case 4: Call — 如 t.CUnsignedLong(-11)
|
||||
if k == ast.ASTKind.Call:
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
|
||||
if cl.args is not None and cl.args.__len__() > 0:
|
||||
first_arg: ast.AST | t.CPtr = cl.args.get(0)
|
||||
arg_val: int = extract_cdefine_int_value(first_arg)
|
||||
return arg_val
|
||||
return 0
|
||||
|
||||
# Case 5: UnaryOp — 如 -11
|
||||
if k == ast.ASTKind.UnaryOp:
|
||||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(val_node)
|
||||
operand_val: int = extract_cdefine_int_value(uop.operand)
|
||||
if uop.op == ast.OpKind.USub:
|
||||
return -operand_val
|
||||
if uop.op == ast.OpKind.UAdd:
|
||||
return operand_val
|
||||
if uop.op == ast.OpKind.Invert:
|
||||
return ~operand_val
|
||||
return 0
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _annotation_contains_name - 递归检查注解中是否包含指定名称
|
||||
#
|
||||
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
|
||||
# ============================================================
|
||||
def _annotation_contains_name(annot: ast.AST | t.CPtr, name: str) -> int:
|
||||
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含"""
|
||||
if annot is None or name is None:
|
||||
return 0
|
||||
k: int = annot.kind()
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||||
if at.attr is not None and string.strcmp(at.attr, name) == 0:
|
||||
return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
|
||||
if nm.id is not None and string.strcmp(nm.id, name) == 0:
|
||||
return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||
if _annotation_contains_name(bop.left, name) != 0:
|
||||
return 1
|
||||
if _annotation_contains_name(bop.right, name) != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
|
||||
#
|
||||
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
|
||||
#
|
||||
# 规则:
|
||||
# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1
|
||||
# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0
|
||||
# 纯 bytes / str → i8*(1 字节步长)→ 返回 0
|
||||
#
|
||||
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
|
||||
# ============================================================
|
||||
def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int:
|
||||
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式"""
|
||||
if annot is None:
|
||||
return 0
|
||||
k: int = annot.kind()
|
||||
if k != ast.ASTKind.BinOp:
|
||||
return 0
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||
if bop.op != ast.OpKind.BitOr:
|
||||
return 0
|
||||
if _annotation_contains_name(annot, "str") != 0:
|
||||
return 1
|
||||
if _annotation_contains_name(annot, "bytes") != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _init_global_array_from_list — 从列表字面量初始化全局数组
|
||||
#
|
||||
# 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。
|
||||
# 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。
|
||||
#
|
||||
# Args:
|
||||
# builder: IRBuilder
|
||||
# pool: 编译器内存池
|
||||
# mod: LLVMModule
|
||||
# array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*)
|
||||
# list_node: ast.List 节点
|
||||
# trans: Translator 对象
|
||||
#
|
||||
# Returns:
|
||||
# 0 成功,1 失败
|
||||
# ============================================================
|
||||
def _init_global_array_from_list(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
array_alloca: llvmlite.Value | t.CPtr,
|
||||
list_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> int:
|
||||
"""从列表字面量初始化全局数组,为每个元素生成 GEP + store"""
|
||||
if builder is None or array_alloca is None or list_node is None:
|
||||
return 1
|
||||
|
||||
# 获取数组类型(Pointee of [N x elem_ty]*)
|
||||
arr_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if array_alloca.Ty is not None:
|
||||
arr_ty = array_alloca.Ty.Pointee
|
||||
if arr_ty is None:
|
||||
return 1
|
||||
|
||||
# 匹配数组类型获取元素类型
|
||||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
match arr_ty:
|
||||
case llvmlite.LLVMType.Array(et, _):
|
||||
elem_ty = et
|
||||
if elem_ty is None:
|
||||
return 1
|
||||
|
||||
# 获取列表元素
|
||||
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
|
||||
if lst is None or lst.elts is None:
|
||||
return 1
|
||||
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
|
||||
elts_count: t.CSizeT = elts.__len__()
|
||||
|
||||
# 为每个元素生成 GEP + store
|
||||
i: t.CSizeT = 0
|
||||
while i < elts_count:
|
||||
elem_node: ast.AST | t.CPtr = elts.get(i)
|
||||
elem_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, elem_node, None, 0, trans)
|
||||
if elem_val is not None:
|
||||
idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i)
|
||||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||||
builder, arr_ty, elem_ty, array_alloca, idx_val)
|
||||
if elem_ptr is not None:
|
||||
# 类型转换(如 i32 → i8 截断)
|
||||
store_val: llvmlite.Value | t.CPtr = elem_val
|
||||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||||
store_val = HandlesExpr.coerce_to_type(
|
||||
builder, elem_val, elem_ptr.Ty.Pointee)
|
||||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||||
i += 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class AnnAssignHandle(HandlesBase.Mixin):
|
||||
"""AnnAssign 语句处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# PreScan - 预扫描 AnnAssign,为有类型注解的变量提前创建 alloca
|
||||
#
|
||||
# 返回新增的变量数
|
||||
# ============================================================
|
||||
def PreScan(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部"""
|
||||
if node is None:
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
if k != ast.ASTKind.AnnAssign:
|
||||
return 0
|
||||
|
||||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa is None or aa.target is None:
|
||||
return 0
|
||||
target: ast.AST | t.CPtr = aa.target
|
||||
if target.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||||
if nm.id is None:
|
||||
return 0
|
||||
|
||||
# CDefine 注解: 不创建 alloca,但注册常量到全局表
|
||||
# 供后续 t.CArray[elem_ty, NAME] 编译期解析使用
|
||||
if is_cdefine_annotation(aa.annotation) != 0:
|
||||
pool_ps: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
val_ps: int = extract_cdefine_int_value(aa.value)
|
||||
HandlesType.register_cdefine_constant(pool_ps, nm.id, val_ps)
|
||||
return 0
|
||||
|
||||
# global/nonlocal 变量不需要局部 alloca
|
||||
if HT.is_global_name(self.Trans, nm.id) != 0:
|
||||
return 0
|
||||
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
|
||||
return 0
|
||||
|
||||
# 模块级全局变量已由 handle_module_level_var 注册到模块作用域,
|
||||
# 不需要创建局部 alloca(否则会导致局部变量遮蔽全局变量)
|
||||
if HandlesVar.lookup_module_var(self.Trans.SymTab, nm.id) is not None:
|
||||
return 0
|
||||
|
||||
# 检查是否已存在
|
||||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
|
||||
self.Trans.SymTab, nm.id)
|
||||
if existing is not None:
|
||||
return 0
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||||
|
||||
# 从 annotation 推断类型(修复:原硬编码 i32 导致 str 等类型错误)
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
annot: ast.AST | t.CPtr = aa.annotation
|
||||
if annot is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
|
||||
if resolved is None:
|
||||
# 尝试特化泛型类注解(如 list[str])
|
||||
# resolve_annotation_type 返回 None 可能是因为泛型类未特化
|
||||
if annot.kind() == ast.ASTKind.Subscript:
|
||||
sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
|
||||
if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name:
|
||||
sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value)
|
||||
if sub_nm.id is not None:
|
||||
template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(sub_nm.id)
|
||||
if template_cd is not None:
|
||||
type_args_ps: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(pool, sub_annot.slice)
|
||||
if type_args_ps is not None and type_args_ps.__len__() > 0:
|
||||
spec_name_ps: str = HandlesClassDef._specialize_generic_class(
|
||||
self.Trans, sub_nm.id, type_args_ps)
|
||||
if spec_name_ps is not None:
|
||||
resolved = HandlesType.resolve_annotation_type(
|
||||
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
|
||||
if resolved is not None:
|
||||
var_ty = resolved
|
||||
|
||||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||||
HandlesStruct.ensure_struct_def_in_module(pool, self.Trans.Module, var_ty)
|
||||
alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, var_ty)
|
||||
if alloca is not None:
|
||||
if HandlesVar.define_var(
|
||||
self.Trans.SymTab, nm.id, alloca) == 0:
|
||||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||||
if annot is not None:
|
||||
cls_nm_ps: str = HandlesType.extract_class_name_from_annotation(
|
||||
annot, self.Trans._imported_modules)
|
||||
if cls_nm_ps is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
self.Trans.SymTab, nm.id, cls_nm_ps)
|
||||
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
|
||||
if _is_ptr_element_annotation(annot) != 0:
|
||||
HandlesVar.set_var_ptr_element(
|
||||
self.Trans.SymTab, nm.id)
|
||||
return 0
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# Handle - 翻译 AnnAssign 语句
|
||||
#
|
||||
# 返回新增的变量数
|
||||
# ============================================================
|
||||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 AnnAssign(target=Name, annotation=..., value=expr)"""
|
||||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa is None:
|
||||
return 0
|
||||
|
||||
target: ast.AST | t.CPtr = aa.target
|
||||
if target is None or target.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||||
if nm.id is None:
|
||||
return 0
|
||||
|
||||
# CDefine 注解: 编译期常量,不生成运行时代码
|
||||
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
|
||||
# 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册
|
||||
if is_cdefine_annotation(aa.annotation) != 0:
|
||||
pool_cd: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
val_cd: int = extract_cdefine_int_value(aa.value)
|
||||
HandlesType.register_cdefine_constant(pool_cd, nm.id, val_cd)
|
||||
return 0
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||||
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||||
|
||||
# 确定类型(从 annotation 推断)
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
annot: ast.AST | t.CPtr = aa.annotation
|
||||
if annot is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
|
||||
if resolved is not None:
|
||||
var_ty = resolved
|
||||
|
||||
# global 变量:写入模块作用域中的全局变量
|
||||
if HT.is_global_name(self.Trans, nm.id) != 0:
|
||||
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||||
self.Trans.SymTab, nm.id)
|
||||
if mod_alloca is not None and aa.value is not None:
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, aa.value,
|
||||
None, 0, self.Trans)
|
||||
if rhs_val is not None:
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if mod_alloca.Ty is not None:
|
||||
target_ty = mod_alloca.Ty.Pointee
|
||||
if target_ty is not None:
|
||||
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty)
|
||||
llvmlite.build_store(builder, rhs_val, mod_alloca)
|
||||
return 0
|
||||
|
||||
# nonlocal 变量:通过闭包 env 写入
|
||||
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
|
||||
if aa.value is not None:
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, aa.value,
|
||||
None, 0, self.Trans)
|
||||
if rhs_val is not None:
|
||||
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
|
||||
self.Trans, nm.id)
|
||||
if nl_ptr is not None:
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
|
||||
builder, rhs_val, i32_ty)
|
||||
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
|
||||
return 0
|
||||
|
||||
# 模块级全局变量(由 handle_module_level_var 注册到模块作用域)
|
||||
# 非函数内 global 声明,但变量已在模块作用域中(如模块级 t.CArray 初始化)
|
||||
mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||||
self.Trans.SymTab, nm.id)
|
||||
if mod_glob is not None:
|
||||
if aa.value is not None:
|
||||
# 列表字面量 → 逐元素 GEP + store 初始化数组
|
||||
if aa.value.kind() == ast.ASTKind.List:
|
||||
_init_global_array_from_list(
|
||||
builder, pool, mod, mod_glob, aa.value, self.Trans)
|
||||
else:
|
||||
rhs_val_mg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, aa.value,
|
||||
None, 0, self.Trans)
|
||||
if rhs_val_mg is not None:
|
||||
target_ty_mg: llvmlite.LLVMType | t.CPtr = None
|
||||
if mod_glob.Ty is not None:
|
||||
target_ty_mg = mod_glob.Ty.Pointee
|
||||
if target_ty_mg is not None:
|
||||
rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg)
|
||||
llvmlite.build_store(builder, rhs_val_mg, mod_glob)
|
||||
return 0
|
||||
|
||||
# 普通局部变量
|
||||
# 创建 alloca
|
||||
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
|
||||
self.Trans.SymTab, pool, builder, nm.id, var_ty)
|
||||
if alloca is None:
|
||||
return 0
|
||||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||||
if annot is not None:
|
||||
cls_nm_hd: str = HandlesType.extract_class_name_from_annotation(
|
||||
annot, self.Trans._imported_modules)
|
||||
if cls_nm_hd is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
self.Trans.SymTab, nm.id, cls_nm_hd)
|
||||
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
|
||||
if _is_ptr_element_annotation(annot) != 0:
|
||||
HandlesVar.set_var_ptr_element(
|
||||
self.Trans.SymTab, nm.id)
|
||||
|
||||
new_vars: int = 0
|
||||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
|
||||
self.Trans.SymTab, nm.id)
|
||||
if existing is None:
|
||||
new_vars = 1
|
||||
|
||||
# 如果有初始值,store
|
||||
if aa.value is not None:
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, aa.value,
|
||||
None, 0, self.Trans)
|
||||
if rhs_val is not None:
|
||||
# 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型
|
||||
# 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if alloca.Ty is not None:
|
||||
target_ty = alloca.Ty.Pointee
|
||||
if target_ty is not None:
|
||||
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty)
|
||||
llvmlite.build_store(builder, rhs_val, alloca)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewAnnAssignHandle - 工厂函数
|
||||
# ============================================================
|
||||
def NewAnnAssignHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> AnnAssignHandle | t.CPtr:
|
||||
h: AnnAssignHandle | t.CPtr = pool.alloc(AnnAssignHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, AnnAssignHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
@@ -1,389 +0,0 @@
|
||||
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.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.StubMerger as StubMerger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesAssign - Assign 语句处理(Mixin 继承模式)
|
||||
#
|
||||
# 对应 TransPyC 的 class AssignHandle(BaseHandle):
|
||||
# @t.NoVTable 继承 Mixin 获得 Trans 字段(展平嵌入,无 vtable)
|
||||
# 通过 self.Trans 访问共享状态(Pool/Module/_cur_builder/SymTab/...)
|
||||
# 通过 self.Trans.ExprH / self.Trans.IfH 等访问其他 Handle
|
||||
# ============================================================
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class AssignHandle(HandlesBase.Mixin):
|
||||
"""Assign 语句处理器:继承 Mixin 获得 Trans 回指针 + 共享方法"""
|
||||
_CurrentClass: str # 模块私有状态
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
self._CurrentClass = None
|
||||
|
||||
# ============================================================
|
||||
# Handle - 处理 Assign 语句,返回新增变量数(0 或 1)
|
||||
#
|
||||
# 对应 TransPyC AssignHandle._HandleAssignLlvm
|
||||
# 共享状态从 self.Trans 获取,无需 11 个参数
|
||||
# ============================================================
|
||||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||||
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||||
if asgn is None:
|
||||
VLogger.error("cast failed", "ASGN")
|
||||
return 0
|
||||
|
||||
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
|
||||
if targets is None:
|
||||
VLogger.error("targets is None", "ASGN")
|
||||
return 0
|
||||
|
||||
# 从 self.Trans 取共享状态(替代 11 个参数)
|
||||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||||
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||||
|
||||
# 翻译 RHS 值
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, asgn.value, None, 0, self.Trans)
|
||||
if rhs_val is None:
|
||||
# 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None and asgn.value is not None:
|
||||
sha1: str = self.Trans.ModuleSha1
|
||||
val_kind: int = asgn.value.kind()
|
||||
val_line: t.CInt = asgn.value.lineno
|
||||
# 通过 sha1 查找文件名(人类可读)
|
||||
rel_path: str = None
|
||||
if sha1 is not None:
|
||||
rel_path = StubMerger.LookupSha1RelPath(sha1)
|
||||
# 根据 AST 节点类型提取详情
|
||||
if val_kind == ast.ASTKind.Attribute:
|
||||
at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value)
|
||||
attr_nm: str = at_nv.attr
|
||||
target_nm: str = "?"
|
||||
if at_nv.value is not None:
|
||||
if at_nv.value.kind() == ast.ASTKind.Name:
|
||||
tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value)
|
||||
target_nm = tn_nm.id
|
||||
if rel_path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: %s:%d '%s.%s' 属性访问失败",
|
||||
rel_path, val_line, target_nm, attr_nm)
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败",
|
||||
sha1, val_line, target_nm, attr_nm)
|
||||
elif val_kind == ast.ASTKind.Name:
|
||||
nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value)
|
||||
if rel_path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: %s:%d 变量 '%s' 未找到",
|
||||
rel_path, val_line, nm_nv.id)
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到",
|
||||
sha1, val_line, nm_nv.id)
|
||||
elif val_kind == ast.ASTKind.Call:
|
||||
cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value)
|
||||
func_nm: str = "?"
|
||||
if cl_nv.func is not None:
|
||||
if cl_nv.func.kind() == ast.ASTKind.Name:
|
||||
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func)
|
||||
func_nm = fn_nm.id
|
||||
if rel_path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None",
|
||||
rel_path, val_line, func_nm)
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None",
|
||||
sha1, val_line, func_nm)
|
||||
else:
|
||||
if rel_path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: %s:%d [kind=%d]",
|
||||
rel_path, val_line, val_kind)
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: sha1=%s:%d [kind=%d]",
|
||||
sha1, val_line, val_kind)
|
||||
VLogger.error(fb, "ASGN")
|
||||
else:
|
||||
VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN")
|
||||
return 0
|
||||
|
||||
new_vars: int = 0
|
||||
tn: t.CSizeT = targets.__len__()
|
||||
for ti in range(tn):
|
||||
target: ast.AST | t.CPtr = targets.get(ti)
|
||||
if target is None:
|
||||
continue
|
||||
|
||||
tk: int = target.kind()
|
||||
|
||||
# Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val
|
||||
if tk == ast.ASTKind.Subscript:
|
||||
# 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct)
|
||||
# list 的 subscript 赋值走 __setitem__ 内联路径
|
||||
list_obj: llvmlite.Value | t.CPtr = HandlesExpr.is_list_subscript(
|
||||
target, self.Trans)
|
||||
if list_obj is not None:
|
||||
# list[T] 类型: 内联生成 __setitem__ 逻辑
|
||||
sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target)
|
||||
if sub_node is not None and sub_node.slice is not None:
|
||||
list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, sub_node.slice, None, 0, self.Trans)
|
||||
if list_idx_val is not None:
|
||||
HandlesExpr.list_setitem_inline(
|
||||
builder, pool, list_obj, list_idx_val, rhs_val)
|
||||
continue
|
||||
# 普通 Subscript 赋值
|
||||
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
|
||||
builder, pool, mod, target, self.Trans)
|
||||
if elem_ptr is not None:
|
||||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||||
if elem_ptr.Ty is not None:
|
||||
elem_ty: llvmlite.LLVMType | t.CPtr = elem_ptr.Ty.Pointee
|
||||
if elem_ty is not None:
|
||||
store_val = HandlesExpr.coerce_to_type(
|
||||
builder, rhs_val, elem_ty)
|
||||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||||
else:
|
||||
# get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载
|
||||
# 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val))
|
||||
sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target)
|
||||
setitem_done: int = 0
|
||||
if sub_asgn is not None and sub_asgn.value is not None:
|
||||
if sub_asgn.value.kind() == ast.ASTKind.Name:
|
||||
sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value)
|
||||
if sub_nm.id is not None:
|
||||
sub_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
self.Trans.SymTab, sub_nm.id)
|
||||
if sub_alloca is not None and sub_alloca.Ty is not None:
|
||||
if HandlesExpr.is_ptr_type(sub_alloca.Ty) != 0:
|
||||
sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee
|
||||
if sub_pointee is not None:
|
||||
cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee)
|
||||
obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, sub_pointee, sub_alloca)
|
||||
# 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct),
|
||||
# 需 load 获取 Ptr(Struct) 再检查 inner struct
|
||||
if cls_nm_set is None and obj_val_set is not None:
|
||||
if HandlesExpr.is_ptr_type(sub_pointee) != 0:
|
||||
inner_ty_set: llvmlite.LLVMType | t.CPtr = sub_pointee.Pointee
|
||||
if inner_ty_set is not None:
|
||||
cls_nm_set = HandlesStruct.get_class_name_by_type(pool, inner_ty_set)
|
||||
if cls_nm_set is not None and obj_val_set is not None:
|
||||
key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||||
if key_val_set is not None:
|
||||
arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16)
|
||||
if arg_vals_set is not None:
|
||||
arg_vals_set[0] = t.CSizeT(key_val_set)
|
||||
arg_vals_set[1] = t.CSizeT(rhs_val)
|
||||
HandlesExprCall._call_method_on_ptr(
|
||||
pool, builder, mod, cls_nm_set, "__setitem__",
|
||||
obj_val_set, arg_vals_set, 2, self.Trans)
|
||||
setitem_done = 1
|
||||
elif sub_asgn.value.kind() == ast.ASTKind.Attribute:
|
||||
# self._ht[key] = val → self._ht.__setitem__(key, val)
|
||||
# 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__
|
||||
field_ptr_set: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||||
builder, pool, mod, sub_asgn.value, self.Trans)
|
||||
if field_ptr_set is not None and field_ptr_set.Ty is not None:
|
||||
if HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0:
|
||||
field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee
|
||||
if field_pointee_set is not None:
|
||||
cls_nm_attr: str = HandlesStruct.get_class_name_by_type(pool, field_pointee_set)
|
||||
obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set
|
||||
# field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段):
|
||||
# load 解引用获取 Ptr(Struct)
|
||||
if cls_nm_attr is None and HandlesExpr.is_ptr_type(field_pointee_set) != 0:
|
||||
inner_struct_attr: llvmlite.LLVMType | t.CPtr = field_pointee_set.Pointee
|
||||
if inner_struct_attr is not None:
|
||||
cls_nm_attr = HandlesStruct.get_class_name_by_type(pool, inner_struct_attr)
|
||||
if cls_nm_attr is not None:
|
||||
obj_val_attr = llvmlite.build_load(
|
||||
builder, field_pointee_set, field_ptr_set)
|
||||
if cls_nm_attr is not None and obj_val_attr is not None:
|
||||
key_val_attr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||||
if key_val_attr is not None:
|
||||
arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16)
|
||||
if arg_vals_attr is not None:
|
||||
arg_vals_attr[0] = t.CSizeT(key_val_attr)
|
||||
arg_vals_attr[1] = t.CSizeT(rhs_val)
|
||||
HandlesExprCall._call_method_on_ptr(
|
||||
pool, builder, mod, cls_nm_attr, "__setitem__",
|
||||
obj_val_attr, arg_vals_attr, 2, self.Trans)
|
||||
setitem_done = 1
|
||||
if setitem_done == 0:
|
||||
# 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store
|
||||
# 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况
|
||||
if sub_asgn is not None and sub_asgn.value is not None:
|
||||
obj_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, sub_asgn.value, None, 0, self.Trans)
|
||||
key_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||||
if obj_val_gen is not None and key_val_gen is not None \
|
||||
and obj_val_gen.Ty is not None:
|
||||
# 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数)
|
||||
cls_nm_gen: str = HandlesStruct.get_class_name_by_type(
|
||||
pool, obj_val_gen.Ty)
|
||||
if cls_nm_gen is None and HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0:
|
||||
inner_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
|
||||
if inner_gen is not None:
|
||||
cls_nm_gen = HandlesStruct.get_class_name_by_type(pool, inner_gen)
|
||||
if cls_nm_gen is not None:
|
||||
# 自定义结构体: 调用 __setitem__
|
||||
arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16)
|
||||
if arg_vals_gen is not None:
|
||||
arg_vals_gen[0] = t.CSizeT(key_val_gen)
|
||||
arg_vals_gen[1] = t.CSizeT(rhs_val)
|
||||
HandlesExprCall._call_method_on_ptr(
|
||||
pool, builder, mod, cls_nm_gen, "__setitem__",
|
||||
obj_val_gen, arg_vals_gen, 2, self.Trans)
|
||||
setitem_done = 1
|
||||
else:
|
||||
# 非自定义结构体: 直接 GEP + store
|
||||
# 处理 get_subscript_ptr 因边界情况返回 None 的指针下标
|
||||
if HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0:
|
||||
elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
|
||||
if elem_gen is not None:
|
||||
store_val_gen: llvmlite.Value | t.CPtr = rhs_val
|
||||
elem_ptr_gen: llvmlite.Value | t.CPtr = None
|
||||
match elem_gen:
|
||||
case llvmlite.LLVMType.Array(arr_elem_gen, _):
|
||||
elem_ptr_gen = llvmlite.build_gep_array(
|
||||
builder, elem_gen, arr_elem_gen,
|
||||
obj_val_gen, key_val_gen)
|
||||
case _:
|
||||
elem_ptr_gen = llvmlite.build_gep(
|
||||
builder, elem_gen, obj_val_gen, key_val_gen)
|
||||
if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None:
|
||||
pt_gen: llvmlite.LLVMType | t.CPtr = elem_ptr_gen.Ty.Pointee
|
||||
if pt_gen is not None:
|
||||
store_val_gen = HandlesExpr.coerce_to_type(
|
||||
builder, rhs_val, pt_gen)
|
||||
llvmlite.build_store(builder, store_val_gen, elem_ptr_gen)
|
||||
setitem_done = 1
|
||||
if setitem_done == 0:
|
||||
sub_vk: int = sub_asgn.value.kind()
|
||||
if setitem_done == 0:
|
||||
HandlesType.fatal_error(target, "subscript ptr is None")
|
||||
continue
|
||||
|
||||
# Attribute 赋值: obj.field = val
|
||||
if tk == ast.ASTKind.Attribute:
|
||||
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||||
builder, pool, mod, target, self.Trans)
|
||||
if field_ptr is not None:
|
||||
# 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64)
|
||||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||||
if field_ptr.Ty is not None:
|
||||
field_ty: llvmlite.LLVMType | t.CPtr = field_ptr.Ty.Pointee
|
||||
if field_ty is not None:
|
||||
store_val = HandlesExpr.coerce_to_type(
|
||||
builder, rhs_val, field_ty)
|
||||
llvmlite.build_store(builder, store_val, field_ptr)
|
||||
else:
|
||||
# 构造详细错误信息
|
||||
attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
|
||||
attr_name: str = "(unknown)"
|
||||
obj_name: str = "(unknown)"
|
||||
if attr_node is not None:
|
||||
attr_name = attr_node.attr
|
||||
if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name:
|
||||
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value)
|
||||
obj_name = obj_nm.id
|
||||
err_buf: t.CChar | t.CPtr = pool.alloc(256)
|
||||
if err_buf is not None:
|
||||
viperlib.snprintf(err_buf, 256,
|
||||
"attribute ptr is None: %s.%s",
|
||||
obj_name, attr_name)
|
||||
HandlesType.fatal_error(target, err_buf)
|
||||
else:
|
||||
HandlesType.fatal_error(target, "attribute ptr is None")
|
||||
continue
|
||||
|
||||
# Name 赋值: var = val
|
||||
if tk == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||||
if nm.id is not None:
|
||||
# global 变量:写入模块作用域中的全局变量
|
||||
if HT.is_global_name(self.Trans, nm.id) != 0:
|
||||
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||||
self.Trans.SymTab, nm.id)
|
||||
if mod_alloca is not None:
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if mod_alloca.Ty is not None:
|
||||
target_ty = mod_alloca.Ty.Pointee
|
||||
if target_ty is not None:
|
||||
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty)
|
||||
llvmlite.build_store(builder, rhs_val, mod_alloca)
|
||||
continue
|
||||
|
||||
# nonlocal 变量:通过闭包 env 写入
|
||||
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
|
||||
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
|
||||
self.Trans, nm.id)
|
||||
if nl_ptr is not None:
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
|
||||
builder, rhs_val, i32_ty)
|
||||
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
|
||||
continue
|
||||
|
||||
# 普通局部变量
|
||||
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
|
||||
self.Trans.SymTab, pool, builder, nm.id, rhs_val.Ty)
|
||||
if alloca is not None:
|
||||
# 按 alloca 类型对值进行转换(如 double → float)
|
||||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||||
if alloca.Ty is not None:
|
||||
alloca_ty: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||||
if alloca_ty is not None:
|
||||
store_val = HandlesExpr.coerce_to_type(
|
||||
builder, rhs_val, alloca_ty)
|
||||
llvmlite.build_store(builder, store_val, alloca)
|
||||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
|
||||
self.Trans.SymTab, nm.id)
|
||||
if existing is None:
|
||||
new_vars += 1
|
||||
else:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "alloca failed for %s", nm.id)
|
||||
VLogger.error(fb, "ASGN")
|
||||
|
||||
return new_vars
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewAssignHandle - 工厂函数:分配并初始化 AssignHandle
|
||||
# ============================================================
|
||||
def NewAssignHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> AssignHandle | t.CPtr:
|
||||
h: AssignHandle | t.CPtr = pool.alloc(AssignHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, AssignHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
@@ -1,315 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import stdio
|
||||
import string
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesAugAssign - 增强赋值语句处理(Mixin 继承模式)
|
||||
#
|
||||
# 处理 += -= *= /= %= &= |= ^= <<= >>=
|
||||
# 流程: load target → apply binop → store result
|
||||
#
|
||||
# 支持 local/global/nonlocal 三种变量作用域
|
||||
# ============================================================
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class AugAssignHandle(HandlesBase.Mixin):
|
||||
"""增强赋值处理器 (+=, -=, *=, etc.):继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# Handle - 处理 AugAssign 语句,返回新增变量数(始终为 0)
|
||||
# ============================================================
|
||||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译增强赋值语句 (x += 1, y -= 2, etc.)"""
|
||||
if node is None:
|
||||
return 0
|
||||
|
||||
aug: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node)
|
||||
if aug is None:
|
||||
return 0
|
||||
|
||||
target: ast.AST | t.CPtr = aug.target
|
||||
if target is None:
|
||||
return 0
|
||||
|
||||
tk: int = target.kind()
|
||||
|
||||
# Attribute 目标: self.field += 1
|
||||
# 流程: get_attribute_ptr → load → binop → store
|
||||
if tk == ast.ASTKind.Attribute:
|
||||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||||
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||||
|
||||
# 1. 获取字段指针
|
||||
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||||
builder, pool, mod, target, self.Trans)
|
||||
if field_ptr is None:
|
||||
VLogger.error("attribute ptr is None", "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 2. 确定字段类型并加载当前值
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if field_ptr.Ty is not None:
|
||||
target_ty = field_ptr.Ty.Pointee
|
||||
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, target_ty, field_ptr)
|
||||
if cur_val is None:
|
||||
VLogger.error("cannot load attribute", "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 3. 翻译 RHS 值
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, aug.value, None, 0, self.Trans)
|
||||
if rhs_val is None:
|
||||
VLogger.error("rhs is None", "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 4. 应用二元运算
|
||||
result: llvmlite.Value | t.CPtr = _apply_aug_op(
|
||||
pool, builder, aug.op, cur_val, rhs_val)
|
||||
if result is None:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "binop failed for attr op=%d", aug.op)
|
||||
VLogger.error(fb, "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 5. 类型对齐并存储
|
||||
result = HandlesExpr.coerce_to_type(builder, result, target_ty)
|
||||
if result is None:
|
||||
return 0
|
||||
llvmlite.build_store(builder, result, field_ptr)
|
||||
return 0
|
||||
|
||||
# Subscript 目标: self.state[i] += x / arr[i] += x
|
||||
# 流程: get_subscript_ptr → load → binop → store
|
||||
if tk == ast.ASTKind.Subscript:
|
||||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||||
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||||
|
||||
# 1. 获取元素指针
|
||||
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
|
||||
builder, pool, mod, target, self.Trans)
|
||||
if elem_ptr is None:
|
||||
VLogger.error("subscript ptr is None", "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 2. 确定元素类型并加载当前值
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||||
target_ty = elem_ptr.Ty.Pointee
|
||||
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, target_ty, elem_ptr)
|
||||
if cur_val is None:
|
||||
VLogger.error("cannot load subscript element", "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 3. 翻译 RHS 值
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, aug.value, None, 0, self.Trans)
|
||||
if rhs_val is None:
|
||||
VLogger.error("rhs is None", "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 4. 应用二元运算
|
||||
result: llvmlite.Value | t.CPtr = _apply_aug_op(
|
||||
pool, builder, aug.op, cur_val, rhs_val)
|
||||
if result is None:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "binop failed for sub op=%d", aug.op)
|
||||
VLogger.error(fb, "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 5. 类型对齐并存储
|
||||
result = HandlesExpr.coerce_to_type(builder, result, target_ty)
|
||||
if result is None:
|
||||
return 0
|
||||
llvmlite.build_store(builder, result, elem_ptr)
|
||||
return 0
|
||||
|
||||
if tk != ast.ASTKind.Name:
|
||||
VLogger.error("only Name/Attribute/Subscript target supported", "AUGASGN")
|
||||
return 0
|
||||
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||||
if nm is None or nm.id is None:
|
||||
return 0
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||||
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
|
||||
# 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal
|
||||
scope_type: int = 0
|
||||
if HT.is_global_name(self.Trans, nm.id) != 0:
|
||||
scope_type = 1
|
||||
elif HT.is_nonlocal_name(self.Trans, nm.id) != 0:
|
||||
scope_type = 2
|
||||
|
||||
# 2. 加载当前值
|
||||
cur_val: llvmlite.Value | t.CPtr = None
|
||||
target_alloca: llvmlite.Value | t.CPtr = None
|
||||
target_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
|
||||
if scope_type == 1:
|
||||
# global 变量
|
||||
target_alloca = HandlesVar.lookup_module_var(
|
||||
self.Trans.SymTab, nm.id)
|
||||
if target_alloca is not None:
|
||||
if target_alloca.Ty is not None:
|
||||
target_ty = target_alloca.Ty.Pointee
|
||||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
|
||||
elif scope_type == 2:
|
||||
# nonlocal 变量(通过闭包 env)
|
||||
cur_val = HandlesNonlocal.load_nonlocal_var(self.Trans, nm.id)
|
||||
if cur_val is not None:
|
||||
target_ty = cur_val.Ty
|
||||
else:
|
||||
# 普通局部变量
|
||||
target_alloca = HandlesVar.lookup_var(self.Trans.SymTab, nm.id)
|
||||
if target_alloca is not None:
|
||||
if target_alloca.Ty is not None:
|
||||
target_ty = target_alloca.Ty.Pointee
|
||||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
|
||||
|
||||
if cur_val is None:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "cannot load target %s", nm.id)
|
||||
VLogger.error(fb, "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 3. 翻译 RHS 值
|
||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, aug.value, None, 0, self.Trans)
|
||||
if rhs_val is None:
|
||||
VLogger.error("rhs is None", "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 4. 类型对齐 + 应用二元运算
|
||||
# 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__)
|
||||
result: llvmlite.Value | t.CPtr = _apply_aug_op(
|
||||
pool, builder, aug.op, cur_val, rhs_val)
|
||||
if result is None:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "binop failed for op=%d", aug.op)
|
||||
VLogger.error(fb, "AUGASGN")
|
||||
return 0
|
||||
|
||||
# 5. 存储结果
|
||||
result = HandlesExpr.coerce_to_type(builder, result, target_ty)
|
||||
if result is None:
|
||||
return 0
|
||||
|
||||
if scope_type == 1:
|
||||
# global 变量
|
||||
if target_alloca is not None:
|
||||
llvmlite.build_store(builder, result, target_alloca)
|
||||
elif scope_type == 2:
|
||||
# nonlocal 变量
|
||||
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
|
||||
self.Trans, nm.id)
|
||||
if nl_ptr is not None:
|
||||
llvmlite.build_store(builder, result, nl_ptr)
|
||||
else:
|
||||
# 普通局部变量
|
||||
if target_alloca is not None:
|
||||
llvmlite.build_store(builder, result, target_alloca)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _apply_aug_op - 应用增强赋值的二元运算
|
||||
#
|
||||
# 支持指针算术: ptr += int / ptr -= int
|
||||
# 整数运算自动类型提升
|
||||
# ============================================================
|
||||
def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
op: int,
|
||||
lhs: llvmlite.Value | t.CPtr,
|
||||
rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""应用增强赋值的二元运算(指针算术 + 整数运算)"""
|
||||
lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
|
||||
rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
|
||||
|
||||
# 指针算术: ptr += int / ptr -= int
|
||||
if lhs_bits == 0 and rhs_bits != 0:
|
||||
if op == ast.OpKind.Add or op == ast.OpKind.Sub:
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
ptr_as_int: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint(builder, lhs, i64_ty)
|
||||
int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty)
|
||||
if ptr_as_int is None or int_val is None:
|
||||
return None
|
||||
if op == ast.OpKind.Add:
|
||||
result: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, ptr_as_int, int_val)
|
||||
else:
|
||||
result = llvmlite.build_sub(builder, ptr_as_int, int_val)
|
||||
if result is None:
|
||||
return None
|
||||
return llvmlite.build_inttoptr(builder, result, lhs.Ty)
|
||||
return None
|
||||
|
||||
# 整数运算:类型提升
|
||||
if lhs_bits > rhs_bits and rhs_bits > 0:
|
||||
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty)
|
||||
elif rhs_bits > lhs_bits and lhs_bits > 0:
|
||||
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty)
|
||||
|
||||
if op == ast.OpKind.Add:
|
||||
return llvmlite.build_add(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Sub:
|
||||
return llvmlite.build_sub(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Mult:
|
||||
return llvmlite.build_mul(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Div:
|
||||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.FloorDiv:
|
||||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Mod:
|
||||
return llvmlite.build_srem(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.BitAnd:
|
||||
return llvmlite.build_and(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.BitOr:
|
||||
return llvmlite.build_or(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.BitXor:
|
||||
return llvmlite.build_xor(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.LShift:
|
||||
return llvmlite.build_shl(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.RShift:
|
||||
return llvmlite.build_ashr(builder, lhs, rhs)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewAugAssignHandle - 工厂函数
|
||||
# ============================================================
|
||||
def NewAugAssignHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> AugAssignHandle | t.CPtr:
|
||||
h: AugAssignHandle | t.CPtr = pool.alloc(AugAssignHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, AugAssignHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
@@ -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: t.CChar | t.CPtr, 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,230 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import viperlib
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesBody - 语句分派(trans 单参模式,全方法调用)
|
||||
#
|
||||
# 所有语句类型通过 trans.XxxH.Handle(node) 分派到对应 Handle。
|
||||
# 对应 TransPyC BodyHandle.HandleBodyLlvm 的 isinstance 分派。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 语句翻译分派
|
||||
# ============================================================
|
||||
def translate_stmt(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译单条语句,返回新增的变量数"""
|
||||
if node is None:
|
||||
return 0
|
||||
k: int = node.kind()
|
||||
|
||||
if k == ast.ASTKind.Expr:
|
||||
return translate_expr_stmt(trans, node)
|
||||
elif k == ast.ASTKind.Assign:
|
||||
return trans.AssignH.Handle(node)
|
||||
elif k == ast.ASTKind.AnnAssign:
|
||||
return trans.AnnAssignH.Handle(node)
|
||||
elif k == ast.ASTKind.FunctionDef:
|
||||
# 嵌套函数定义:提升为顶层函数 + 创建闭包
|
||||
return HandlesFunctions.translate_nested_function_def(trans, node)
|
||||
elif k == ast.ASTKind.Return:
|
||||
return trans.ReturnH.Handle(node)
|
||||
elif k == ast.ASTKind.If:
|
||||
return trans.IfH.Handle(node)
|
||||
elif k == ast.ASTKind.While:
|
||||
return trans.WhileH.Handle(node)
|
||||
elif k == ast.ASTKind.AugAssign:
|
||||
return trans.AugAssignH.Handle(node)
|
||||
elif k == ast.ASTKind.For:
|
||||
return trans.ForH.Handle(node)
|
||||
elif k == ast.ASTKind.ClassDef:
|
||||
return HandlesClassDef.translate_class_def(trans, node)
|
||||
elif k == ast.ASTKind.Import:
|
||||
return trans.ImportsH.HandleImport(node)
|
||||
elif k == ast.ASTKind.ImportFrom:
|
||||
trans.ImportsH.HandleImportFromModule(node)
|
||||
return trans.ImportsH.HandleImportFromNames(node)
|
||||
elif k == ast.ASTKind.Global:
|
||||
return translate_global(trans, node)
|
||||
elif k == ast.ASTKind.Nonlocal:
|
||||
return translate_nonlocal(trans, node)
|
||||
elif k == ast.ASTKind.Pass:
|
||||
return 0
|
||||
elif k == ast.ASTKind.Break:
|
||||
return translate_break(trans)
|
||||
elif k == ast.ASTKind.Continue:
|
||||
return translate_continue(trans)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译 Global 语句: global x, y
|
||||
#
|
||||
# 将 names 中的变量名加入 _global_names 集合
|
||||
# ============================================================
|
||||
def translate_global(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 global 语句:记录 global 变量名"""
|
||||
gn: ast.Global | t.CPtr = (ast.Global | t.CPtr)(node)
|
||||
if gn is None:
|
||||
return 0
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = gn.names
|
||||
if names is None:
|
||||
return 0
|
||||
n: t.CSizeT = names.__len__()
|
||||
for i in range(n):
|
||||
nm_node: ast.AST | t.CPtr = 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)
|
||||
if nm.id is not None:
|
||||
HT.add_global_name(trans, nm.id)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译 Nonlocal 语句: nonlocal x, y
|
||||
#
|
||||
# 将 names 中的变量名加入 _nonlocal_names 集合
|
||||
# ============================================================
|
||||
def translate_nonlocal(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 nonlocal 语句:记录 nonlocal 变量名"""
|
||||
nl: ast.Nonlocal | t.CPtr = (ast.Nonlocal | t.CPtr)(node)
|
||||
if nl is None:
|
||||
return 0
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = nl.names
|
||||
if names is None:
|
||||
return 0
|
||||
n: t.CSizeT = names.__len__()
|
||||
for i in range(n):
|
||||
nm_node: ast.AST | t.CPtr = 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)
|
||||
if nm.id is not None:
|
||||
HT.add_nonlocal_name(trans, nm.id)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译表达式语句 Expr(value=Call(...))
|
||||
# ============================================================
|
||||
def translate_expr_stmt(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译表达式语句(printf 调用等)"""
|
||||
ex: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(node)
|
||||
if ex is None:
|
||||
return 0
|
||||
call_node: ast.AST | t.CPtr = ex.value
|
||||
if call_node is None:
|
||||
return 0
|
||||
ck: int = call_node.kind()
|
||||
if ck != ast.ASTKind.Call:
|
||||
return 0
|
||||
|
||||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(call_node)
|
||||
func_node: ast.AST | t.CPtr = cl.func
|
||||
if func_node is None:
|
||||
return 0
|
||||
|
||||
func_name: str = HandlesExpr.get_func_name(func_node)
|
||||
if func_name is None:
|
||||
return 0
|
||||
|
||||
# printf / print 走特殊路径(print 映射到 printf)
|
||||
if string.strcmp(func_name, "printf") == 0 or string.strcmp(func_name, "print") == 0:
|
||||
trans.ExprCallH.HandlePrintfCall(cl)
|
||||
else:
|
||||
# 通用函数调用(返回值丢弃)
|
||||
trans.ExprCallH.HandleCall(call_node)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 预扫描:为局部变量提前创建 alloca
|
||||
# ============================================================
|
||||
def pre_scan_allocas(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""预扫描语句中的 AnnAssign,提前创建 alloca
|
||||
|
||||
返回新增的变量数
|
||||
"""
|
||||
if node is None:
|
||||
return 0
|
||||
return trans.AnnAssignH.PreScan(node)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译 break 语句
|
||||
# ============================================================
|
||||
def translate_break(trans: HT.Translator | t.CPtr) -> 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
|
||||
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
|
||||
# 发射 br 到 break 目标
|
||||
if trans._break_bb is not None:
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, trans._break_bb)
|
||||
|
||||
# 创建死代码 BB,用于后续语句(break 后面的代码不可达)
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
|
||||
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
llvmlite.position_at_end(builder, dead_bb)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译 continue 语句
|
||||
# ============================================================
|
||||
def translate_continue(trans: HT.Translator | t.CPtr) -> 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
|
||||
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
|
||||
# 发射 br 到 continue 目标
|
||||
if trans._continue_bb is not None:
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, trans._continue_bb)
|
||||
|
||||
# 创建死代码 BB,用于后续语句
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "dead.%d", cnt)
|
||||
dead_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
llvmlite.position_at_end(builder, dead_bb)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 获取语句类型名(调试用)
|
||||
# ============================================================
|
||||
def get_stmt_kind_name(node: ast.AST | t.CPtr) -> str:
|
||||
"""获取语句类型名"""
|
||||
if node is None:
|
||||
return None
|
||||
return node.type_name()
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,238 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import llvmlite
|
||||
import stdio
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesEnum - 枚举类型注册和成员查找
|
||||
#
|
||||
# 管理 t.CEnum 派生类的成员信息:
|
||||
# - 枚举名 → EnumEntry(基准类型 + 成员表)
|
||||
# - 成员名 → EnumMember(值、类型)
|
||||
#
|
||||
# 使用全局数组存储,线性查找(枚举数量通常很少)
|
||||
# ============================================================
|
||||
|
||||
ENUM_MAX: t.CDefine = 64
|
||||
ENUM_MEMBER_MAX: t.CDefine = 64
|
||||
|
||||
|
||||
# ============================================================
|
||||
# EnumMember - 枚举成员条目
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class EnumMember:
|
||||
Name: t.CChar | t.CPtr # 成员名(字符串)
|
||||
Value: t.CInt64T # 成员的整数值
|
||||
Ty: llvmlite.LLVMType | t.CPtr # 成员的 LLVM 类型(用于混用类型场景)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# EnumEntry - 枚举类型条目
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class EnumEntry:
|
||||
Name: t.CChar | t.CPtr # 枚举类名
|
||||
BaseTy: llvmlite.LLVMType | t.CPtr # 基准类型(所有成员类型中最大的)
|
||||
MemberCount: int # 成员数量
|
||||
Members: EnumMember | t.CPtr # 成员数组(ENUM_MEMBER_MAX 个槽位)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局注册表(静态分配)
|
||||
# ============================================================
|
||||
_enum_table: EnumEntry | t.CPtr = None
|
||||
_enum_count: int = 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# init_enum_table — 初始化枚举注册表
|
||||
# ============================================================
|
||||
def init_enum_table(pool: memhub.MemBuddy | t.CPtr) -> int:
|
||||
"""初始化枚举注册表,返回 1 成功"""
|
||||
global _enum_table
|
||||
global _enum_count
|
||||
|
||||
if _enum_table is not None:
|
||||
return 1
|
||||
|
||||
entry_size: t.CSizeT = EnumEntry.__sizeof__()
|
||||
_enum_table = pool.alloc(entry_size * ENUM_MAX)
|
||||
if _enum_table is None:
|
||||
return 0
|
||||
string.memset(_enum_table, 0, entry_size * ENUM_MAX)
|
||||
_enum_count = 0
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _get_enum_entry — 获取第 i 个 EnumEntry 槽位
|
||||
# ============================================================
|
||||
def _get_enum_entry(i: int) -> EnumEntry | t.CPtr:
|
||||
"""获取第 i 个枚举条目"""
|
||||
if _enum_table is None or i < 0 or i >= ENUM_MAX:
|
||||
return None
|
||||
entry_size: t.CSizeT = EnumEntry.__sizeof__()
|
||||
addr: t.CUInt64T = t.CUInt64T(_enum_table) + i * entry_size
|
||||
return (EnumEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _get_enum_member — 获取枚举中第 i 个 EnumMember 槽位
|
||||
# ============================================================
|
||||
def _get_enum_member(enum_entry: EnumEntry | t.CPtr, i: int) -> EnumMember | t.CPtr:
|
||||
"""获取枚举中第 i 个成员条目"""
|
||||
if enum_entry is None or i < 0 or i >= ENUM_MEMBER_MAX:
|
||||
return None
|
||||
member_size: t.CSizeT = EnumMember.__sizeof__()
|
||||
addr: t.CUInt64T = t.CUInt64T(enum_entry.Members) + i * member_size
|
||||
return (EnumMember | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||||
|
||||
|
||||
# ============================================================
|
||||
# register_enum — 注册枚举类型
|
||||
#
|
||||
# 返回 EnumEntry 指针,可用于添加成员
|
||||
# ============================================================
|
||||
def register_enum(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str,
|
||||
base_ty: llvmlite.LLVMType | t.CPtr) -> EnumEntry | t.CPtr:
|
||||
"""注册枚举类型,返回 EnumEntry 指针"""
|
||||
if init_enum_table(pool) == 0:
|
||||
return None
|
||||
|
||||
# 检查是否已注册
|
||||
existing: EnumEntry | t.CPtr = find_enum(name)
|
||||
if existing is not None:
|
||||
return existing
|
||||
|
||||
if _enum_count >= ENUM_MAX:
|
||||
fb_et: t.CChar | t.CPtr = 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")
|
||||
return None
|
||||
|
||||
entry: EnumEntry | t.CPtr = _get_enum_entry(_enum_count)
|
||||
if entry is None:
|
||||
return None
|
||||
|
||||
# 分配成员数组
|
||||
member_size: t.CSizeT = EnumMember.__sizeof__()
|
||||
entry.Members = pool.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: t.CChar | t.CPtr = pool.alloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, name)
|
||||
entry.Name = name_buf
|
||||
|
||||
entry.BaseTy = base_ty
|
||||
entry.MemberCount = 0
|
||||
|
||||
_enum_count += 1
|
||||
return entry
|
||||
|
||||
|
||||
# ============================================================
|
||||
# add_enum_member — 向枚举添加成员
|
||||
# ============================================================
|
||||
def add_enum_member(pool: memhub.MemBuddy | t.CPtr,
|
||||
enum_entry: EnumEntry | t.CPtr,
|
||||
member_name: str,
|
||||
member_val: t.CInt64T,
|
||||
member_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""向枚举添加成员,返回成员索引(-1 失败)"""
|
||||
if enum_entry is None or member_name is None or member_ty is None:
|
||||
return -1
|
||||
|
||||
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
|
||||
fb_em: t.CChar | t.CPtr = 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")
|
||||
return -1
|
||||
|
||||
idx: int = enum_entry.MemberCount
|
||||
me: EnumMember | t.CPtr = _get_enum_member(enum_entry, idx)
|
||||
if me is None:
|
||||
return -1
|
||||
|
||||
# 复制成员名
|
||||
name_len: t.CSizeT = string.strlen(member_name)
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
|
||||
if name_buf is not None:
|
||||
string.strcpy(name_buf, member_name)
|
||||
me.Name = name_buf
|
||||
|
||||
me.Value = member_val
|
||||
me.Ty = member_ty
|
||||
|
||||
enum_entry.MemberCount = idx + 1
|
||||
return idx
|
||||
|
||||
|
||||
# ============================================================
|
||||
# find_enum — 按枚举类名查找
|
||||
# ============================================================
|
||||
def find_enum(name: str) -> EnumEntry | t.CPtr:
|
||||
"""按枚举类名查找,返回 EnumEntry 或 None"""
|
||||
if name is None or _enum_table is None:
|
||||
return None
|
||||
for i in range(_enum_count):
|
||||
entry: EnumEntry | t.CPtr = _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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lookup_enum_member — 按枚举类名和成员名查找
|
||||
# ============================================================
|
||||
def lookup_enum_member(enum_name: str,
|
||||
member_name: str) -> EnumMember | t.CPtr:
|
||||
"""按枚举类名和成员名查找,返回 EnumMember 或 None"""
|
||||
if enum_name is None or member_name is None:
|
||||
return None
|
||||
entry: EnumEntry | t.CPtr = find_enum(enum_name)
|
||||
if entry is None:
|
||||
return None
|
||||
for mi in range(entry.MemberCount):
|
||||
me: EnumMember | t.CPtr = _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
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# is_enum_class — 检查类名是否为已注册枚举
|
||||
# ============================================================
|
||||
def is_enum_class(name: str) -> int:
|
||||
"""检查类名是否为已注册枚举,返回 1=是 / 0=否"""
|
||||
if name is None:
|
||||
return 0
|
||||
if find_enum(name) is not None:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# get_enum_base_type — 按枚举类名获取基准类型
|
||||
# ============================================================
|
||||
def get_enum_base_type(enum_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""按枚举类名获取基准类型"""
|
||||
entry: EnumEntry | t.CPtr = find_enum(enum_name)
|
||||
if entry is not None:
|
||||
return entry.BaseTy
|
||||
return None
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,289 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import viperlib
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesExprOps - 二元运算处理(模块级纯函数)
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 运算符重载支持
|
||||
#
|
||||
# 当二元/比较运算的 lhs 是结构体指针时,检查该类是否定义了
|
||||
# 对应的 dunder 方法(如 __add__、__eq__),若有则生成方法调用
|
||||
# 而非原生算术/比较指令。
|
||||
# ============================================================
|
||||
|
||||
# BinOp 运算符 → dunder 方法名
|
||||
def _binop_to_dunder(op: int) -> str:
|
||||
"""将 BinOp 运算符映射到 dunder 方法名,无映射时返回 None"""
|
||||
if op == ast.OpKind.Add: return "__add__"
|
||||
if op == ast.OpKind.Sub: return "__sub__"
|
||||
if op == ast.OpKind.Mult: return "__mul__"
|
||||
if op == ast.OpKind.Div: return "__div__"
|
||||
if op == ast.OpKind.Mod: return "__mod__"
|
||||
if op == ast.OpKind.BitAnd: return "__and__"
|
||||
if op == ast.OpKind.BitOr: return "__or__"
|
||||
if op == ast.OpKind.BitXor: return "__xor__"
|
||||
if op == ast.OpKind.LShift: return "__lshift__"
|
||||
if op == ast.OpKind.RShift: return "__rshift__"
|
||||
if op == ast.OpKind.FloorDiv: return "__floordiv__"
|
||||
return None
|
||||
|
||||
# Compare 运算符 → dunder 方法名
|
||||
def _cmpop_to_dunder(op: int) -> str:
|
||||
"""将 Compare 运算符映射到 dunder 方法名,无映射时返回 None"""
|
||||
if op == ast.OpKind.Eq: return "__eq__"
|
||||
if op == ast.OpKind.Ne: return "__ne__"
|
||||
if op == ast.OpKind.Lt: return "__lt__"
|
||||
if op == ast.OpKind.Le: return "__le__"
|
||||
if op == ast.OpKind.Gt: return "__gt__"
|
||||
if op == ast.OpKind.Ge: return "__ge__"
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# try_operator_overload - 尝试运算符重载
|
||||
#
|
||||
# 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的
|
||||
# dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回
|
||||
# 调用结果;未找到返回 None,调用方回退到原生运算。
|
||||
#
|
||||
# Args:
|
||||
# pool: 内存池
|
||||
# builder: IRBuilder
|
||||
# mod: LLVM 模块
|
||||
# lhs: 左操作数 Value(已求值)
|
||||
# rhs: 右操作数 Value(已求值)
|
||||
# op: OpKind 运算符
|
||||
# trans: Translator 对象
|
||||
# is_compare: 0=BinOp, 1=Compare(决定 dunder 映射表)
|
||||
#
|
||||
# Returns:
|
||||
# 方法调用的 Value(成功),None(未重载)
|
||||
# ============================================================
|
||||
def try_operator_overload(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
lhs: llvmlite.Value | t.CPtr,
|
||||
rhs: llvmlite.Value | t.CPtr,
|
||||
op: int,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
is_compare: int) -> llvmlite.Value | t.CPtr:
|
||||
"""尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None"""
|
||||
if lhs is None or rhs is None:
|
||||
return None
|
||||
|
||||
# 延迟导入避免循环依赖
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
|
||||
# 映射运算符到 dunder 方法名
|
||||
dunder: str = None
|
||||
if is_compare != 0:
|
||||
dunder = _cmpop_to_dunder(op)
|
||||
else:
|
||||
dunder = _binop_to_dunder(op)
|
||||
if dunder is None:
|
||||
return None
|
||||
|
||||
# 检查 lhs 是否为结构体指针
|
||||
struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lhs)
|
||||
if struct_ty is None:
|
||||
return None
|
||||
|
||||
# 获取类名
|
||||
class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty)
|
||||
if class_name is None:
|
||||
return None
|
||||
|
||||
# 在继承链中查找 dunder 方法
|
||||
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if lookup_name is None:
|
||||
return None
|
||||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
|
||||
found_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, lookup_name)
|
||||
|
||||
search_class: str = class_name
|
||||
if found_func is None:
|
||||
cur_parent: str = HandlesStruct.get_parent_name(class_name)
|
||||
while cur_parent is not None:
|
||||
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if parent_lookup is not None:
|
||||
viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, dunder)
|
||||
parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup)
|
||||
if parent_func is not None:
|
||||
found_func = parent_func
|
||||
search_class = cur_parent
|
||||
break
|
||||
cur_parent = HandlesStruct.get_parent_name(cur_parent)
|
||||
|
||||
# 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入)
|
||||
# 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错)
|
||||
cls_sha1: str = None
|
||||
op_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
|
||||
if op_entry is not None:
|
||||
cls_sha1 = op_entry.ModuleSha1
|
||||
if cls_sha1 is None:
|
||||
cls_sha1 = HandlesStruct.get_struct_sha1(search_class)
|
||||
if cls_sha1 is None:
|
||||
cur_p: str = HandlesStruct.get_parent_name(search_class)
|
||||
while cur_p is not None and cls_sha1 is None:
|
||||
cls_sha1 = HandlesStruct.get_struct_sha1(cur_p)
|
||||
cur_p = HandlesStruct.get_parent_name(cur_p)
|
||||
|
||||
# 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算
|
||||
if found_func is None and cls_sha1 is None:
|
||||
return None
|
||||
|
||||
# 构建 extra_args 数组(仅含 rhs 一个参数)
|
||||
extra_args: t.CSizeT | t.CPtr = pool.alloc(8)
|
||||
if extra_args is None:
|
||||
return None
|
||||
extra_args[0] = t.CSizeT(rhs)
|
||||
|
||||
# 调用方法: lhs.__dunder__(rhs)
|
||||
return HandlesExprCall._call_method_on_ptr(
|
||||
pool, builder, mod, search_class, dunder,
|
||||
lhs, extra_args, 1, trans)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译二元运算(自动类型提升)
|
||||
# ============================================================
|
||||
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:
|
||||
"""翻译二元运算(自动类型提升)"""
|
||||
binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
if binop is None:
|
||||
return None
|
||||
|
||||
lhs_node: ast.AST | t.CPtr = binop.left
|
||||
rhs_node: ast.AST | t.CPtr = binop.right
|
||||
op: int = binop.op
|
||||
|
||||
# 先翻译 rhs(只翻译一次,避免副作用重复)
|
||||
rhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, rhs_node, None, 0, trans)
|
||||
if rhs is None:
|
||||
return None
|
||||
|
||||
# === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 ===
|
||||
# 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值,
|
||||
# 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。
|
||||
if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node)
|
||||
if nm is not None and nm.id is not None:
|
||||
lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
trans.SymTab, nm.id)
|
||||
if lhs_alloca is not None:
|
||||
ovl_result: llvmlite.Value | t.CPtr = try_operator_overload(
|
||||
pool, builder, mod, lhs_alloca, rhs, op, trans, 0)
|
||||
if ovl_result is not None:
|
||||
return ovl_result
|
||||
|
||||
# 正常翻译 lhs
|
||||
lhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, lhs_node, None, 0, trans)
|
||||
if lhs is None:
|
||||
return None
|
||||
|
||||
# === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)===
|
||||
ovl_result2: llvmlite.Value | t.CPtr = try_operator_overload(
|
||||
pool, builder, mod, lhs, rhs, op, trans, 0)
|
||||
if ovl_result2 is not None:
|
||||
return ovl_result2
|
||||
|
||||
# 获取操作数类型信息
|
||||
lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
|
||||
rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
|
||||
lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty)
|
||||
rhs_fbits: int = HandlesExpr.get_llvm_float_bits(rhs.Ty)
|
||||
|
||||
# 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查,
|
||||
# 因为 float 的 int bits 为 0,会被误认为指针)
|
||||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||||
# 确定目标浮点类型(使用较大的位宽)
|
||||
target_fbits: int = lhs_fbits
|
||||
if rhs_fbits > target_fbits:
|
||||
target_fbits = rhs_fbits
|
||||
target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||||
if target_fbits == 32:
|
||||
target_float_ty = llvmlite.Float(pool)
|
||||
# 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc)
|
||||
lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty)
|
||||
rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty)
|
||||
if op == ast.OpKind.Add:
|
||||
return llvmlite.build_fadd(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Sub:
|
||||
return llvmlite.build_fsub(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Mult:
|
||||
return llvmlite.build_fmul(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Div:
|
||||
return llvmlite.build_fdiv(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Mod:
|
||||
return llvmlite.build_frem(builder, lhs, rhs)
|
||||
return None
|
||||
|
||||
# 指针算术: ptr + int 或 ptr - int → ptrtoint + add/sub + inttoptr
|
||||
if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0):
|
||||
if op == ast.OpKind.Add or op == ast.OpKind.Sub:
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
if lhs_bits == 0:
|
||||
# lhs 是指针,rhs 是整数
|
||||
ptr_as_int: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint(builder, lhs, i64_ty)
|
||||
int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty)
|
||||
if op == ast.OpKind.Add:
|
||||
result: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, ptr_as_int, int_val)
|
||||
else:
|
||||
result = llvmlite.build_sub(builder, ptr_as_int, int_val)
|
||||
return llvmlite.build_inttoptr(builder, result, lhs.Ty)
|
||||
else:
|
||||
# rhs 是指针,lhs 是整数(仅 Add 支持交换)
|
||||
ptr_as_int = llvmlite.build_ptrtoint(builder, rhs, i64_ty)
|
||||
int_val = HandlesExpr.coerce_to_type(builder, lhs, i64_ty)
|
||||
if op == ast.OpKind.Add:
|
||||
result = llvmlite.build_add(builder, int_val, ptr_as_int)
|
||||
else:
|
||||
result = llvmlite.build_sub(builder, int_val, ptr_as_int)
|
||||
return llvmlite.build_inttoptr(builder, result, rhs.Ty)
|
||||
|
||||
if lhs_bits > rhs_bits:
|
||||
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty)
|
||||
elif rhs_bits > lhs_bits:
|
||||
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty)
|
||||
|
||||
if op == ast.OpKind.Add:
|
||||
return llvmlite.build_add(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Sub:
|
||||
return llvmlite.build_sub(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Mult:
|
||||
return llvmlite.build_mul(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Div:
|
||||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.FloorDiv:
|
||||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Mod:
|
||||
return llvmlite.build_srem(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.BitAnd:
|
||||
return llvmlite.build_and(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.BitOr:
|
||||
return llvmlite.build_or(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.BitXor:
|
||||
return llvmlite.build_xor(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.LShift:
|
||||
return llvmlite.build_shl(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.RShift:
|
||||
return llvmlite.build_ashr(builder, lhs, rhs)
|
||||
return None
|
||||
@@ -1,398 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import viperlib
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesBody as HandlesBody
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesFor - for 循环语句处理(Mixin 继承模式)
|
||||
#
|
||||
# 支持 for i in range(start, stop, step) 模式:
|
||||
# %i = alloca i32
|
||||
# store i32 start, i32* %i
|
||||
# br label %cond
|
||||
# cond:
|
||||
# %cur = load i32, i32* %i
|
||||
# %cmp = icmp slt i32 %cur, stop
|
||||
# br i1 %cmp, label %body, label %end
|
||||
# body:
|
||||
# ... body ...
|
||||
# br label %incr
|
||||
# incr:
|
||||
# %cur2 = load i32, i32* %i
|
||||
# %next = add i32 %cur2, step
|
||||
# store i32 %next, i32* %i
|
||||
# br label %cond
|
||||
# end:
|
||||
# ============================================================
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class ForHandle(HandlesBase.Mixin):
|
||||
"""for 循环语句处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# Handle - 处理 for 语句,返回新增变量数
|
||||
# ============================================================
|
||||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 for i in range(...) 循环语句"""
|
||||
if node is None:
|
||||
return 0
|
||||
|
||||
trans: HT.Translator | t.CPtr = self.Trans
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
|
||||
for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node)
|
||||
|
||||
# 1. 获取循环变量名(仅支持 for i in range(...))
|
||||
target: ast.AST | t.CPtr = for_node.target
|
||||
if target is None:
|
||||
return 0
|
||||
if target.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||||
var_name: str = target_nm.id
|
||||
if var_name is None:
|
||||
return 0
|
||||
|
||||
# 2. 解析迭代器:支持 range() 和指针迭代
|
||||
iter_node: ast.AST | t.CPtr = for_node.iter
|
||||
if iter_node is None:
|
||||
return 0
|
||||
|
||||
# 检查是否是 range() 调用
|
||||
is_range_iter: int = 0
|
||||
if iter_node.kind() == ast.ASTKind.Call:
|
||||
call_pre: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node)
|
||||
fn_pre: str = HandlesExpr.get_func_name(call_pre.func)
|
||||
if fn_pre is not None:
|
||||
if string.strcmp(fn_pre, "range") == 0:
|
||||
is_range_iter = 1
|
||||
else:
|
||||
err_msg: t.CChar | t.CPtr = pool.alloc(256)
|
||||
if err_msg is not None:
|
||||
viperlib.snprintf(err_msg, 256, "仅支持 range() 或指针迭代,got call '%s'", fn_pre)
|
||||
HandlesType.fatal_error(iter_node, err_msg)
|
||||
HandlesType.fatal_error(iter_node, "仅支持 range() 或指针迭代")
|
||||
|
||||
# 非范围迭代:走指针迭代路径
|
||||
if is_range_iter == 0:
|
||||
return self._handle_ptr_iter(for_node, var_name)
|
||||
|
||||
call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node)
|
||||
|
||||
# 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step)
|
||||
args: list[ast.AST | t.CPtr] | t.CPtr = call.args
|
||||
if args is None:
|
||||
return 0
|
||||
arg_count: t.CSizeT = args.__len__()
|
||||
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
start_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
stop_val: llvmlite.Value | t.CPtr = None
|
||||
step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1)
|
||||
|
||||
if arg_count == 1:
|
||||
stop_val = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, args.get(0),
|
||||
trans._funcs, trans._func_count, trans)
|
||||
elif arg_count >= 2:
|
||||
start_val = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, args.get(0),
|
||||
trans._funcs, trans._func_count, trans)
|
||||
stop_val = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, args.get(1),
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if arg_count >= 3:
|
||||
step_val = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, args.get(2),
|
||||
trans._funcs, trans._func_count, trans)
|
||||
|
||||
if stop_val is None:
|
||||
stop_val = llvmlite.const_int32(pool, 0)
|
||||
if start_val is None:
|
||||
start_val = llvmlite.const_int32(pool, 0)
|
||||
if step_val is None:
|
||||
step_val = llvmlite.const_int32(pool, 1)
|
||||
|
||||
# 4. 创建/查找循环变量 alloca
|
||||
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
trans.SymTab, var_name)
|
||||
new_vars: int = 0
|
||||
if var_alloca is None:
|
||||
var_alloca = HandlesVar._alloca_at_entry(builder, i32_ty)
|
||||
if HandlesVar.define_var(
|
||||
trans.SymTab, var_name, var_alloca) == 0:
|
||||
new_vars = 1
|
||||
|
||||
# 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee)
|
||||
# 当循环变量已声明为 i64(如 t.CSizeT),使用 i64 而非硬编码 i32
|
||||
# 避免 load i32, i64* / store i32, i64* 类型不匹配
|
||||
loop_var_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
if var_alloca is not None and var_alloca.Ty is not None:
|
||||
match var_alloca.Ty:
|
||||
case llvmlite.LLVMType.Ptr(pointee_ty):
|
||||
if pointee_ty is not None:
|
||||
loop_var_ty = pointee_ty
|
||||
loop_var_bits: int = HandlesExpr.get_llvm_type_bits(loop_var_ty)
|
||||
|
||||
# 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty)
|
||||
init_val: llvmlite.Value | t.CPtr = start_val
|
||||
if start_val is not None and start_val.Ty is not None:
|
||||
start_bits: int = HandlesExpr.get_llvm_type_bits(start_val.Ty)
|
||||
if start_bits != 0 and start_bits != loop_var_bits:
|
||||
if start_bits < loop_var_bits:
|
||||
init_val = llvmlite.build_sext(builder, start_val, loop_var_ty)
|
||||
else:
|
||||
init_val = llvmlite.build_trunc(builder, start_val, loop_var_ty)
|
||||
llvmlite.build_store(builder, init_val, var_alloca)
|
||||
|
||||
# 6. 创建基本块: cond / body / incr / end(使用 trans._label_counter,不与 SSA 名共享)
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt)
|
||||
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "for.body.%d", cnt)
|
||||
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt)
|
||||
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "for.end.%d", cnt)
|
||||
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
# 7. 跳转到 cond 块
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# 8. cond 块: load i, icmp slt i, stop, cond_br body/end
|
||||
llvmlite.position_at_end(builder, cond_bb)
|
||||
cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca)
|
||||
# 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型
|
||||
cmp_lhs: llvmlite.Value | t.CPtr = cur_i
|
||||
cmp_rhs: llvmlite.Value | t.CPtr = stop_val
|
||||
if stop_val is not None and stop_val.Ty is not None:
|
||||
stop_bits: int = HandlesExpr.get_llvm_type_bits(stop_val.Ty)
|
||||
cur_bits: int = HandlesExpr.get_llvm_type_bits(cur_i.Ty)
|
||||
if stop_bits != 0 and cur_bits != 0 and stop_bits != cur_bits:
|
||||
if cur_bits < stop_bits:
|
||||
cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty)
|
||||
else:
|
||||
cmp_rhs = llvmlite.build_trunc(builder, stop_val, loop_var_ty)
|
||||
cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_SLT, cmp_lhs, cmp_rhs)
|
||||
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
|
||||
|
||||
# 9. body 块: 翻译循环体,跳到 incr
|
||||
llvmlite.position_at_end(builder, body_bb)
|
||||
|
||||
# 保存旧循环上下文,设置 break/continue 目标
|
||||
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
|
||||
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
|
||||
if body is not None:
|
||||
body_count: t.CSizeT = body.__len__()
|
||||
for bi in range(body_count):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
|
||||
# 恢复旧循环上下文
|
||||
trans._break_bb = old_break
|
||||
trans._continue_bb = old_continue
|
||||
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, incr_bb)
|
||||
|
||||
# 10. incr 块: i = i + step, 跳回 cond
|
||||
llvmlite.position_at_end(builder, incr_bb)
|
||||
cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca)
|
||||
# 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致
|
||||
incr_step: llvmlite.Value | t.CPtr = step_val
|
||||
if step_val is not None and step_val.Ty is not None:
|
||||
step_bits: int = HandlesExpr.get_llvm_type_bits(step_val.Ty)
|
||||
cur2_bits: int = HandlesExpr.get_llvm_type_bits(cur_i2.Ty)
|
||||
if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits:
|
||||
if step_bits > cur2_bits:
|
||||
incr_step = llvmlite.build_trunc(builder, step_val, loop_var_ty)
|
||||
else:
|
||||
incr_step = llvmlite.build_sext(builder, step_val, loop_var_ty)
|
||||
next_i: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step)
|
||||
llvmlite.build_store(builder, next_i, var_alloca)
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# 11. 定位到 end 块
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
return new_vars
|
||||
|
||||
# ============================================================
|
||||
# _handle_ptr_iter - 指针迭代: for x in ptr:
|
||||
# 遍历指针,依赖隐式 index,直到解引用为空(null 终止符)
|
||||
#
|
||||
# 生成 IR 结构:
|
||||
# %idx = alloca i32
|
||||
# store i32 0, i32* %idx
|
||||
# br label %cond
|
||||
# cond:
|
||||
# %i = load i32, i32* %idx
|
||||
# %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i
|
||||
# %ev = load elem_ty, elem_ty* %ep
|
||||
# %null = icmp eq elem_ty %ev, 0
|
||||
# br i1 %null, label %end, label %body
|
||||
# body:
|
||||
# store elem_ty %ev, elem_ty* %var
|
||||
# ... 循环体 ...
|
||||
# br label %incr
|
||||
# incr:
|
||||
# %next = add i32 %i, 1
|
||||
# store i32 %next, i32* %idx
|
||||
# br label %cond
|
||||
# end:
|
||||
# ============================================================
|
||||
def _handle_ptr_iter(self, for_node: ast.For | t.CPtr,
|
||||
var_name: str) -> int:
|
||||
"""指针迭代: for x in ptr: 直到解引用为空"""
|
||||
trans: HT.Translator | t.CPtr = self.Trans
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
|
||||
# 翻译迭代器表达式,获取指针值
|
||||
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, for_node.iter,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if ptr_val is None:
|
||||
HandlesType.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式")
|
||||
|
||||
# 检查是否是指针类型
|
||||
if HandlesExpr.is_ptr_type(ptr_val.Ty) == 0:
|
||||
HandlesType.fatal_error(for_node, "指针迭代: 迭代器不是指针类型")
|
||||
|
||||
# 获取元素类型
|
||||
elem_ty: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||||
if elem_ty is None:
|
||||
HandlesType.fatal_error(for_node, "指针迭代: 无法获取元素类型")
|
||||
|
||||
# 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符)
|
||||
elem_bits: int = HandlesExpr.get_llvm_type_bits(elem_ty)
|
||||
if elem_bits == 0:
|
||||
HandlesType.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符")
|
||||
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
|
||||
# 创建循环变量 alloca(存储元素值)
|
||||
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
trans.SymTab, var_name)
|
||||
new_vars: int = 0
|
||||
if var_alloca is None:
|
||||
var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty)
|
||||
if HandlesVar.define_var(
|
||||
trans.SymTab, var_name, var_alloca) == 0:
|
||||
new_vars = 1
|
||||
|
||||
# 创建隐式 index 变量,初始为 0
|
||||
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty)
|
||||
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
|
||||
|
||||
# 创建基本块: cond / body / incr / end
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt)
|
||||
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt)
|
||||
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt)
|
||||
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt)
|
||||
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
# 跳转到 cond
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# cond 块: load index, GEP, load elem, icmp eq 0
|
||||
llvmlite.position_at_end(builder, cond_bb)
|
||||
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca)
|
||||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||||
builder, elem_ty, ptr_val, cur_idx)
|
||||
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr)
|
||||
null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0)
|
||||
is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_EQ, cur_elem, null_val)
|
||||
llvmlite.build_cond_br(builder, is_null, end_bb, body_bb)
|
||||
|
||||
# body 块: store elem to var, 翻译循环体
|
||||
llvmlite.position_at_end(builder, body_bb)
|
||||
llvmlite.build_store(builder, cur_elem, var_alloca)
|
||||
|
||||
# 保存旧循环上下文,设置 break/continue 目标
|
||||
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
|
||||
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = incr_bb
|
||||
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
|
||||
if body is not None:
|
||||
body_count: t.CSizeT = body.__len__()
|
||||
for bi in range(body_count):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
|
||||
# 恢复旧循环上下文
|
||||
trans._break_bb = old_break
|
||||
trans._continue_bb = old_continue
|
||||
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, incr_bb)
|
||||
|
||||
# incr 块: index++, br cond
|
||||
llvmlite.position_at_end(builder, incr_bb)
|
||||
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1)
|
||||
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
|
||||
llvmlite.build_store(builder, next_idx, idx_alloca)
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# 定位到 end 块
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
return new_vars
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewForHandle - 工厂函数
|
||||
# ============================================================
|
||||
def NewForHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> ForHandle | t.CPtr:
|
||||
h: ForHandle | t.CPtr = pool.alloc(ForHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, ForHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
@@ -1,995 +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.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesBody as HandlesBody
|
||||
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
|
||||
|
||||
# 作用域类型常量(本地副本,避免旧编译器跨模块 CDefine 查找 bug)
|
||||
SCOPE_FUNCTION: t.CDefine = 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 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(pool: memhub.MemBuddy | t.CPtr,
|
||||
decorator_list: list[ast.AST | t.CPtr] | t.CPtr,
|
||||
imported_modules: str) -> t.CChar | t.CPtr:
|
||||
"""从 decorator_list 提取 c.Attribute 属性,返回 LLVM IR 属性字符串"""
|
||||
if decorator_list is None:
|
||||
return None
|
||||
dn: t.CSizeT = decorator_list.__len__()
|
||||
if dn == 0:
|
||||
return None
|
||||
|
||||
attrs_buf: t.CChar | t.CPtr = 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 | t.CPtr = decorator_list.get(di)
|
||||
if deco is None or deco.kind() != ast.ASTKind.Call:
|
||||
continue
|
||||
call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco)
|
||||
if call_node.func is None or call_node.func.kind() != 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 or string.strcmp(func_attr.attr, "Attribute") != 0:
|
||||
continue
|
||||
if func_attr.value is None or func_attr.value.kind() != ast.ASTKind.Name:
|
||||
continue
|
||||
c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value)
|
||||
if c_name.id is None or string.strcmp(c_name.id, "c") != 0:
|
||||
continue
|
||||
if HandlesImports.is_module_imported(imported_modules, "c") == 0:
|
||||
continue
|
||||
|
||||
# 遍历参数提取属性
|
||||
if call_node.args is None:
|
||||
continue
|
||||
args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args
|
||||
an: t.CSizeT = args_list.__len__()
|
||||
for ai in range(an):
|
||||
arg_node: ast.AST | t.CPtr = args_list.get(ai)
|
||||
if arg_node is None:
|
||||
continue
|
||||
|
||||
# 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx)
|
||||
attr_name: str = _get_attr_name_from_node(arg_node)
|
||||
if attr_name is None:
|
||||
continue
|
||||
|
||||
# 映射到 LLVM 属性名并追加
|
||||
if _append_llvm_attr(attrs_buf, attr_name) != 0:
|
||||
found_any = 1
|
||||
# 追加成功后,如果不是最后一个属性,添加空格分隔
|
||||
# 在下一次追加前由 _append_str 处理
|
||||
|
||||
if found_any == 0:
|
||||
return None
|
||||
return attrs_buf
|
||||
|
||||
|
||||
def _get_attr_name_from_node(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(attrs_buf: t.CChar | t.CPtr, 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, "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':
|
||||
_append_str(attrs_buf, " ")
|
||||
_append_str(attrs_buf, llvm_name)
|
||||
return 1
|
||||
|
||||
|
||||
def _append_str(buf: t.CChar | t.CPtr, s: str) -> None:
|
||||
"""将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)"""
|
||||
if buf is None or s is None:
|
||||
return
|
||||
cur_len: t.CSizeT = string.strlen(buf)
|
||||
string.strcpy(buf + cur_len, s)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesFunctions - 函数定义处理(trans 单参模式)
|
||||
#
|
||||
# 参考 Python 版 TransPyC FunctionHandle
|
||||
#
|
||||
# 函数有自己的局部作用域,通过 HandlesVar.enter_scope/exit_scope
|
||||
# 管理嵌套作用域链,翻译函数体前进入函数作用域,翻译完退出。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _mangle_name - 为名称添加 SHA1 前缀
|
||||
#
|
||||
# 返回 "sha1.name" 格式的混淆名。若 ModuleSha1 为 None 或名称已带
|
||||
# SHA1 前缀(16 hex + '.'),则原样返回。
|
||||
# ============================================================
|
||||
def _mangle_name(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(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(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 _mangle_name(trans, name)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# forward_declare_functions - 预扫描所有顶层 FunctionDef,创建前向声明
|
||||
#
|
||||
# 解决同模块内前向引用问题:如 viperlib.py 中 sprintf(行15) 调用
|
||||
# vsnprintf(行41),但 vsnprintf 定义在后面。
|
||||
#
|
||||
# 对每个顶层 FunctionDef:
|
||||
# 1. 推断返回类型和参数类型
|
||||
# 2. 计算 mangled name(含 SHA1 前缀)
|
||||
# 3. 创建 declare(IsDeclared=1)
|
||||
# 4. 添加参数
|
||||
# 5. 注册到函数表
|
||||
#
|
||||
# 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare,
|
||||
# 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。
|
||||
# ============================================================
|
||||
def forward_declare_functions(trans: HT.Translator | t.CPtr,
|
||||
tree: ast.AST | t.CPtr) -> int:
|
||||
"""预扫描所有顶层 FunctionDef,创建前向声明"""
|
||||
if trans is None or tree is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
if pool is None or mod is None:
|
||||
return 0
|
||||
|
||||
imported_modules: str = trans._imported_modules
|
||||
from_imports: str = trans._from_imports
|
||||
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
|
||||
|
||||
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)
|
||||
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is None:
|
||||
return 0
|
||||
cn_count: t.CSizeT = ch.__len__()
|
||||
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
if child.kind() != ast.ASTKind.FunctionDef:
|
||||
continue
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||||
if fd is None or fd.name is None:
|
||||
continue
|
||||
|
||||
# 推断返回类型
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if fd.returns is not None:
|
||||
ret_ty = HandlesType.resolve_annotation_type(
|
||||
pool, fd.returns, imported_modules, from_imports, trans)
|
||||
if ret_ty is None and fd.returns is not None:
|
||||
if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
|
||||
ret_ty = llvmlite.Void(pool)
|
||||
if ret_ty is None:
|
||||
ret_ty = i32_ty
|
||||
|
||||
# 检测 CExtern/State/CExport
|
||||
has_extern: int = 0
|
||||
has_state: int = 0
|
||||
has_export: int = 0
|
||||
if fd.returns is not None:
|
||||
has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern")
|
||||
has_state = HandlesType.has_decorator_marker(fd.returns, "State")
|
||||
has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
|
||||
is_extern_decl: int = 0
|
||||
if has_extern != 0 or has_state != 0:
|
||||
is_extern_decl = 1
|
||||
|
||||
# 计算 mangled name
|
||||
if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main":
|
||||
mangled_name: str = fd.name
|
||||
else:
|
||||
mangled_name = _mangle_func_name(trans, fd.name, 0)
|
||||
|
||||
# 如果函数已存在(如重复定义),跳过
|
||||
existing: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
|
||||
if existing is not None:
|
||||
continue
|
||||
|
||||
# 创建 declare
|
||||
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, mangled_name, ret_ty)
|
||||
if func is None:
|
||||
continue
|
||||
|
||||
# 提取默认参数信息
|
||||
# 注意: 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
|
||||
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
|
||||
fd_args_node: ast.Arguments | t.CPtr = fd.args
|
||||
fd_defaults: t.CVoid | t.CPtr = None
|
||||
fd_default_count: int = 0
|
||||
fd_param_count: int = 0
|
||||
if fd_args_node is not None:
|
||||
fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node)
|
||||
if fd_ags.args is not None:
|
||||
fd_alist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.args
|
||||
fd_param_count = fd_alist.__len__()
|
||||
if fd_ags.defaults is not None:
|
||||
fd_dlist: list[ast.AST | t.CPtr] | t.CPtr = fd_ags.defaults
|
||||
fd_defaults = fd_dlist
|
||||
fd_default_count = fd_dlist.__len__()
|
||||
|
||||
# 注册到函数表(用裸名 fd.name,不是 mangled_name)
|
||||
max_funcs: int = 256
|
||||
cur_count: int = trans._func_count
|
||||
if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs,
|
||||
fd_defaults, fd_default_count, fd_param_count) == 0:
|
||||
trans._func_count = cur_count + 1
|
||||
|
||||
# 注册 CExport 函数到全局表
|
||||
if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None:
|
||||
HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)
|
||||
|
||||
# 添加参数
|
||||
args_node: ast.Arguments | t.CPtr = fd.args
|
||||
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 = alist.__len__()
|
||||
for ai in range(an):
|
||||
arg: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist.get(ai))
|
||||
if arg is None or arg.arg is None:
|
||||
continue
|
||||
# t.CVoid 表示空参:跳过
|
||||
if arg.annotation is not None:
|
||||
if HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0:
|
||||
continue
|
||||
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
if arg.annotation is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, arg.annotation, imported_modules, from_imports, trans)
|
||||
if resolved is not None:
|
||||
param_ty = resolved
|
||||
pname: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if pname is not None:
|
||||
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
|
||||
llvmlite.add_param(pool, func, param_ty, pname)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译函数定义 FunctionDef(name, args, body, ...)
|
||||
#
|
||||
# trans 单参模式:所有共享状态从 trans 获取
|
||||
# 函数局部作用域通过 enter_scope/exit_scope 管理
|
||||
# ============================================================
|
||||
def translate_function_def(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译函数定义,返回新增的变量数(通常为 0,函数定义不增加当前作用域变量)"""
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
|
||||
if fd is None or fd.name is None:
|
||||
return 0
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
imported_modules: str = trans._imported_modules
|
||||
from_imports: str = trans._from_imports
|
||||
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
|
||||
func_count: int = trans._func_count
|
||||
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
|
||||
# 推断返回类型:优先使用返回类型注解
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if fd.returns is not None:
|
||||
ret_ty = HandlesType.resolve_annotation_type(
|
||||
pool, fd.returns, imported_modules, from_imports, trans)
|
||||
|
||||
# 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void
|
||||
# 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32
|
||||
if ret_ty is None and fd.returns is not None:
|
||||
if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
|
||||
ret_ty = llvmlite.Void(pool)
|
||||
|
||||
# 如果仍然为 None,扫描 return 语句推断(至少返回 i32)
|
||||
if ret_ty is None:
|
||||
param_types_str: str = HandlesType.build_param_types_str(pool, fd.args)
|
||||
ret_ty = HandlesType.infer_return_type(
|
||||
pool, fd.children, param_types_str)
|
||||
# 检测是否为外部声明函数(t.CExtern 或 t.State)
|
||||
# 语义:t.CExtern 忽略 body 体,仅生成 declare(由链接器解析符号)
|
||||
# t.State = t.CExtern + t.CExport(既是声明又是导出)
|
||||
# t.CExport 导出函数不加 SHA1 前缀
|
||||
# t.CExtern/t.State/t.CExport 都不加 SHA1 前缀,直接映射到 C 标准库函数名
|
||||
is_extern_decl: int = 0
|
||||
has_export: int = 0
|
||||
has_extern: int = 0
|
||||
has_state: int = 0
|
||||
if fd.returns is not None:
|
||||
has_extern = HandlesType.has_decorator_marker(fd.returns, "CExtern")
|
||||
has_state = HandlesType.has_decorator_marker(fd.returns, "State")
|
||||
has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
|
||||
# t.CExtern/t.State 忽略 body 体,仅声明(无论 body 是否为 pass)
|
||||
if has_extern != 0 or has_state != 0:
|
||||
is_extern_decl = 1
|
||||
|
||||
# SHA1 命名空间:t.CExtern/t.State/t.CExport 不加前缀,直接用裸名
|
||||
# (裸名映射到 C 标准库符号,带 sha1 前缀会导致 undefined reference)
|
||||
# main 函数也不加前缀(程序入口点)
|
||||
if has_extern != 0 or has_state != 0 or has_export != 0 or fd.name == "main":
|
||||
mangled_name: str = fd.name
|
||||
else:
|
||||
mangled_name: str = _mangle_func_name(trans, fd.name, 0)
|
||||
|
||||
# 注册 CExport 函数到全局表(供跨模块调用查表)
|
||||
# t.CExport 函数定义用裸名(@strlen),跨模块调用需查表确认用裸名而非 @{sha1}.func
|
||||
if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None:
|
||||
HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)
|
||||
|
||||
if is_extern_decl != 0:
|
||||
# 外部声明函数:生成 declare(仅声明,不定义)
|
||||
# 先检查是否已由 forward_declare_functions 创建,避免重复 declare
|
||||
existing_extern: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
|
||||
if existing_extern is not None:
|
||||
# 已存在前向声明,复用之,不再重复创建
|
||||
return 0
|
||||
|
||||
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||
pool, mod, mangled_name, ret_ty)
|
||||
if func is None:
|
||||
return 0
|
||||
|
||||
# 注册到函数表
|
||||
max_funcs_extern: int = 256
|
||||
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs_extern) == 0:
|
||||
trans._func_count = func_count + 1
|
||||
|
||||
# 添加参数(支持类型注解)
|
||||
args_node_extern: ast.Arguments | t.CPtr = fd.args
|
||||
if args_node_extern is not None:
|
||||
ags_e: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node_extern)
|
||||
if ags_e.args is not None:
|
||||
alist_e: list[ast.AST | t.CPtr] | t.CPtr = ags_e.args
|
||||
an_e: t.CSizeT = alist_e.__len__()
|
||||
for ai_e in range(an_e):
|
||||
arg_e: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist_e.get(ai_e))
|
||||
if arg_e is not None and arg_e.arg is not None:
|
||||
# t.CVoid 表示空参:跳过,不添加到函数签名
|
||||
if arg_e.annotation is not None:
|
||||
if HandlesType._is_t_attr(arg_e.annotation, "CVoid", imported_modules) != 0:
|
||||
continue
|
||||
param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
if arg_e.annotation is not None:
|
||||
resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, arg_e.annotation, imported_modules, from_imports, trans)
|
||||
if resolved_e is not None:
|
||||
param_ty_e = resolved_e
|
||||
pname_e: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if pname_e is not None:
|
||||
viperlib.snprintf(pname_e, 32, "%%%s", arg_e.arg)
|
||||
llvmlite.add_param(pool, func, param_ty_e, pname_e)
|
||||
|
||||
# 提取 @c.Attribute 装饰器属性并设置到函数
|
||||
func_attrs_e: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
|
||||
if func_attrs_e is not None:
|
||||
llvmlite.function_set_attrs(func, func_attrs_e)
|
||||
|
||||
return 0
|
||||
|
||||
# args_node 用于后续 alloca 创建,提前赋值
|
||||
args_node: ast.Arguments | t.CPtr = fd.args
|
||||
|
||||
# 检查是否已有前向声明(由 forward_declare_functions 创建)
|
||||
func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
|
||||
if func is not None and llvmlite.function_is_declared(func) != 0:
|
||||
# 复用前向声明:清除 IsDeclared 标记,转为 define
|
||||
func.IsDeclared = 0
|
||||
# 装饰器属性设置(前向声明时未设置)
|
||||
func_attrs_reuse: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
|
||||
if func_attrs_reuse is not None:
|
||||
llvmlite.function_set_attrs(func, func_attrs_reuse)
|
||||
else:
|
||||
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
|
||||
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
|
||||
if func is None:
|
||||
fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_cf is not None:
|
||||
viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name)
|
||||
VLogger.error(fb_cf, "FUNC")
|
||||
return 0
|
||||
|
||||
# 提取 @c.Attribute 装饰器属性并设置到函数
|
||||
func_attrs: t.CChar | t.CPtr = extract_func_attrs(pool, fd.decorator_list, imported_modules)
|
||||
if func_attrs is not None:
|
||||
llvmlite.function_set_attrs(func, func_attrs)
|
||||
|
||||
# 提取默认参数信息
|
||||
tfd_defaults: t.CVoid | t.CPtr = None
|
||||
tfd_default_count: int = 0
|
||||
tfd_param_count: int = 0
|
||||
if args_node is not None:
|
||||
tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
|
||||
if tfd_ags.args is not None:
|
||||
tfd_alist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.args
|
||||
tfd_param_count = tfd_alist.__len__()
|
||||
if tfd_ags.defaults is not None:
|
||||
tfd_dlist: list[ast.AST | t.CPtr] | t.CPtr = tfd_ags.defaults
|
||||
tfd_defaults = tfd_dlist
|
||||
tfd_default_count = tfd_dlist.__len__()
|
||||
|
||||
# 注册到函数表
|
||||
max_funcs: int = 256
|
||||
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs,
|
||||
tfd_defaults, tfd_default_count, tfd_param_count) == 0:
|
||||
trans._func_count = func_count + 1
|
||||
|
||||
# 添加参数(支持类型注解)
|
||||
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 = alist.__len__()
|
||||
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 HandlesType._is_t_attr(arg.annotation, "CVoid", imported_modules) != 0:
|
||||
continue
|
||||
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
if arg.annotation is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, arg.annotation, imported_modules, from_imports, trans)
|
||||
if resolved is not None:
|
||||
param_ty = resolved
|
||||
pname: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if pname is not None:
|
||||
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
|
||||
llvmlite.add_param(pool, func, param_ty, pname)
|
||||
# 创建 entry 块
|
||||
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
|
||||
if entry_blk is None:
|
||||
return 0
|
||||
|
||||
# 创建函数专属 builder
|
||||
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
|
||||
if func_builder is None:
|
||||
return 0
|
||||
llvmlite.position_at_end(func_builder, entry_blk)
|
||||
|
||||
# 进入函数作用域(嵌套符号表)
|
||||
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
|
||||
|
||||
# 为参数创建 alloca
|
||||
if args_node is not None:
|
||||
ags2: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
|
||||
if ags2.args is not None:
|
||||
alist2: list[ast.AST | t.CPtr] | t.CPtr = ags2.args
|
||||
an2: t.CSizeT = alist2.__len__()
|
||||
for ai2 in range(an2):
|
||||
arg2: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(alist2.get(ai2))
|
||||
if arg2 is not None and arg2.arg is not None:
|
||||
# t.CVoid 表示空参:跳过,不创建 alloca
|
||||
if arg2.annotation is not None:
|
||||
if HandlesType._is_t_attr(arg2.annotation, "CVoid", imported_modules) != 0:
|
||||
continue
|
||||
param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||
if arg2.annotation is not None:
|
||||
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, arg2.annotation, imported_modules, from_imports, trans)
|
||||
if resolved2 is not None:
|
||||
param_ty2 = resolved2
|
||||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
|
||||
if alloca is not None:
|
||||
HandlesVar.define_var(trans.SymTab, arg2.arg, alloca)
|
||||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||||
if arg2.annotation is not None:
|
||||
cls_nm: str = HandlesType.extract_class_name_from_annotation(
|
||||
arg2.annotation, imported_modules)
|
||||
if cls_nm is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
trans.SymTab, arg2.arg, cls_nm)
|
||||
pname2: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if pname2 is not None:
|
||||
viperlib.snprintf(pname2, 32, "%%%s", arg2.arg)
|
||||
param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
|
||||
pool, param_ty2, pname2)
|
||||
llvmlite.build_store(func_builder, param_val, alloca)
|
||||
# 保存模块级作用域状态(仅非变量表相关)
|
||||
old_func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
old_global_count: int = trans._global_name_count
|
||||
old_nonlocal_count: int = trans._nonlocal_name_count
|
||||
old_env_count: int = trans._closure_env_count
|
||||
|
||||
trans._cur_func = func
|
||||
trans._cur_builder = func_builder
|
||||
# 清空 global/nonlocal 名称集合(新函数作用域)
|
||||
HT.clear_scope_names(trans)
|
||||
|
||||
# 预扫描函数体:为局部变量提前创建 alloca
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
|
||||
if body is not None:
|
||||
bn: t.CSizeT = body.__len__()
|
||||
for bi in range(bn):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.pre_scan_allocas(trans, stmt)
|
||||
|
||||
# 翻译函数体
|
||||
if body is not None:
|
||||
bn2: t.CSizeT = body.__len__()
|
||||
for bi2 in range(bn2):
|
||||
stmt2: ast.AST | t.CPtr = body.get(bi2)
|
||||
if stmt2 is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt2)
|
||||
|
||||
# 如果函数体最后一条语句不是 Return,添加隐式 ret
|
||||
last_is_return: int = 0
|
||||
if body is not None:
|
||||
bn3: t.CSizeT = body.__len__()
|
||||
if bn3 > 0:
|
||||
last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1)
|
||||
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
|
||||
last_is_return = 1
|
||||
if last_is_return == 0:
|
||||
if llvmlite.builder_cur_block_is_terminated(func_builder) == 0:
|
||||
# 根据返回类型生成正确的零值返回
|
||||
_is_void: int = 0
|
||||
_is_ptr: int = 0
|
||||
if ret_ty is not None:
|
||||
match ret_ty:
|
||||
case llvmlite.LLVMType.Void():
|
||||
_is_void = 1
|
||||
case llvmlite.LLVMType.Ptr(_pe):
|
||||
_is_ptr = 1
|
||||
if _is_void != 0:
|
||||
llvmlite.build_ret_void(func_builder)
|
||||
elif _is_ptr != 0:
|
||||
_null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
|
||||
llvmlite.build_ret(func_builder, _null_val)
|
||||
else:
|
||||
_zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
llvmlite.build_ret(func_builder, _zero_val)
|
||||
|
||||
# 恢复模块级作用域(退出函数作用域)
|
||||
HandlesVar.exit_scope(trans.SymTab)
|
||||
trans._cur_func = old_func
|
||||
trans._cur_builder = old_builder
|
||||
trans._global_name_count = old_global_count
|
||||
trans._nonlocal_name_count = old_nonlocal_count
|
||||
trans._closure_env_count = old_env_count
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# translate_nested_function_def - 嵌套函数提升 + 闭包创建
|
||||
#
|
||||
# 将嵌套函数提升为顶层函数 @__closure_{name}(i8* %env) -> i32,
|
||||
# 在父函数中创建闭包对象 {i8* fn_ptr, i8* env_ptr} 并存储到
|
||||
# 以函数名命名的局部变量中。
|
||||
#
|
||||
# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节, malloc 分配)
|
||||
# Env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量 8 字节)
|
||||
# ============================================================
|
||||
def translate_nested_function_def(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译嵌套函数定义:提升为顶层函数 + 创建闭包"""
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
|
||||
if fd is None or fd.name is None:
|
||||
return 0
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
func_name: str = fd.name
|
||||
|
||||
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)
|
||||
|
||||
# 1. 构建提升后的函数名: __closure_{name}(加 SHA1 前缀避免跨模块冲突)
|
||||
promoted_name: t.CChar | t.CPtr = pool.alloc(64)
|
||||
if promoted_name is not None:
|
||||
viperlib.snprintf(promoted_name, 64, "__closure_%s", func_name)
|
||||
mangled_promoted: str = _mangle_name(trans, promoted_name)
|
||||
|
||||
# 2. 创建提升后的函数: define i32 @__closure_{name}(i8* %env)
|
||||
func: llvmlite.Function | t.CPtr = llvmlite.create_function(
|
||||
pool, mod, mangled_promoted, i32_ty)
|
||||
if func is None:
|
||||
return 0
|
||||
llvmlite.add_param(pool, func, i8_ptr_ty, "%env")
|
||||
|
||||
# 3. 创建 entry 块 + builder
|
||||
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
|
||||
if entry_blk is None:
|
||||
return 0
|
||||
func_builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, func)
|
||||
if func_builder is None:
|
||||
return 0
|
||||
llvmlite.position_at_end(func_builder, entry_blk)
|
||||
|
||||
# 4. 进入嵌套函数作用域(嵌套符号表)
|
||||
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
|
||||
|
||||
# 5. 创建 _env_ptr alloca 并存储 %env 参数
|
||||
env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty)
|
||||
if env_alloca is not None:
|
||||
HandlesVar.define_var(trans.SymTab, "_env_ptr", env_alloca)
|
||||
env_param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "%env")
|
||||
llvmlite.build_store(func_builder, env_param_val, env_alloca)
|
||||
|
||||
# 6. 保存父函数作用域状态(仅非变量表相关)
|
||||
old_func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
old_func_name: str = trans._cur_func_name
|
||||
old_global_count: int = trans._global_name_count
|
||||
old_nonlocal_count: int = trans._nonlocal_name_count
|
||||
old_env_count: int = trans._closure_env_count
|
||||
|
||||
# 7. 切换到嵌套函数作用域 + 清空 scope names
|
||||
trans._cur_func = func
|
||||
trans._cur_builder = func_builder
|
||||
trans._cur_func_name = func_name
|
||||
HT.clear_scope_names(trans)
|
||||
|
||||
# 8. 预扫描函数体:为局部变量提前创建 alloca
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = fd.children
|
||||
if body is not None:
|
||||
bn: t.CSizeT = body.__len__()
|
||||
for bi in range(bn):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.pre_scan_allocas(trans, stmt)
|
||||
|
||||
# 9. 翻译函数体(Nonlocal 语句会填充 _nonlocal_names)
|
||||
if body is not None:
|
||||
bn2: t.CSizeT = body.__len__()
|
||||
for bi2 in range(bn2):
|
||||
stmt2: ast.AST | t.CPtr = body.get(bi2)
|
||||
if stmt2 is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt2)
|
||||
|
||||
# 10. 隐式 ret
|
||||
last_is_return: int = 0
|
||||
if body is not None:
|
||||
bn3: t.CSizeT = body.__len__()
|
||||
if bn3 > 0:
|
||||
last_stmt: ast.AST | t.CPtr = body.get(bn3 - 1)
|
||||
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
|
||||
last_is_return = 1
|
||||
if last_is_return == 0:
|
||||
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
llvmlite.build_ret(func_builder, zero_val)
|
||||
|
||||
# 11. 保存嵌套函数的 nonlocal 信息
|
||||
nested_nonlocal_count: int = trans._nonlocal_name_count
|
||||
|
||||
# 12. 退出嵌套函数作用域,回到父函数作用域(保留 _nonlocal_names 用于 env 创建)
|
||||
HandlesVar.exit_scope(trans.SymTab)
|
||||
trans._cur_func = old_func
|
||||
trans._cur_builder = old_builder
|
||||
# NOTE: _nonlocal_names 和 _nonlocal_name_count 仍为嵌套函数的值
|
||||
|
||||
# 13. 在父函数中创建闭包对象
|
||||
parent_builder: llvmlite.IRBuilder | t.CPtr = old_builder
|
||||
if parent_builder is None:
|
||||
# 无 builder(模块级嵌套函数?)→ 无法创建闭包,仅恢复状态
|
||||
trans._cur_func_name = old_func_name
|
||||
trans._global_name_count = old_global_count
|
||||
trans._nonlocal_name_count = old_nonlocal_count
|
||||
trans._closure_env_count = old_env_count
|
||||
return 0
|
||||
|
||||
# 13a. 创建 env: malloc(4 * nested_nonlocal_count) — env 直接存储 i32 值
|
||||
env_ptr: llvmlite.Value | t.CPtr = None
|
||||
if nested_nonlocal_count > 0:
|
||||
env_size: t.CInt64T = nested_nonlocal_count * 4
|
||||
env_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, env_size)
|
||||
if env_size_val is not None:
|
||||
env_size_val.Next = None
|
||||
env_ptr = llvmlite.build_call(
|
||||
parent_builder, "malloc", env_size_val, 1, i8_ptr_ty, 0)
|
||||
|
||||
# 为每个 nonlocal 变量存储值到 env
|
||||
if env_ptr is not None:
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty)
|
||||
for ni in range(nested_nonlocal_count):
|
||||
# 从 _nonlocal_names 缓冲区读取名称
|
||||
name_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + ni * 8
|
||||
nl_slot: str | t.CPtr = (t.CVoid | t.CPtr)(name_addr)
|
||||
nl_name: str = nl_slot[0]
|
||||
if nl_name is not None:
|
||||
# 在父函数作用域中查找(Current 已回到父作用域)
|
||||
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
trans.SymTab, nl_name)
|
||||
if var_alloca is not None:
|
||||
# 加载变量值
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if var_alloca.Ty is not None:
|
||||
var_ty = var_alloca.Ty.Pointee
|
||||
if var_ty is None:
|
||||
var_ty = i32_ty
|
||||
var_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
parent_builder, var_ty, var_alloca)
|
||||
if var_val is not None:
|
||||
# GEP to env[ni*4]
|
||||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, ni * 4)
|
||||
slot: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||||
parent_builder, i8_ty, env_ptr, offset_val)
|
||||
if slot is not None:
|
||||
# bitcast to i32* and store value
|
||||
slot_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
parent_builder, slot, i32_ptr_ty)
|
||||
if slot_typed is not None:
|
||||
# 类型转换(确保 var_val 是 i32)
|
||||
coerced_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
|
||||
parent_builder, var_val, i32_ty)
|
||||
if coerced_val is not None:
|
||||
llvmlite.build_store(parent_builder, coerced_val, slot_typed)
|
||||
|
||||
# 13b. 创建闭包结构: malloc(16)
|
||||
closure_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 16)
|
||||
if closure_size_val is not None:
|
||||
closure_size_val.Next = None
|
||||
closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||||
parent_builder, "malloc", closure_size_val, 1, i8_ptr_ty, 0)
|
||||
if closure_ptr is None:
|
||||
# malloc 失败,恢复状态
|
||||
trans._cur_func_name = old_func_name
|
||||
trans._global_name_count = old_global_count
|
||||
trans._nonlocal_name_count = old_nonlocal_count
|
||||
trans._closure_env_count = old_env_count
|
||||
return 0
|
||||
|
||||
# 13c. 存储 fn_ptr 到 offset 0
|
||||
# 创建函数指针类型 i32(i8*)*
|
||||
fn_param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
|
||||
fn_func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, fn_param_node, 1)
|
||||
fn_func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, fn_func_ty)
|
||||
|
||||
# 创建函数引用 Value(类型为 i32(i8*)*,使用 SHA1 混淆名)
|
||||
fn_ptr_name: t.CChar | t.CPtr = pool.alloc(64)
|
||||
if fn_ptr_name is not None:
|
||||
# SHA1 前缀名含 '.' 需要加引号(如 @"sha1.__closure_func")
|
||||
if string.strchr(mangled_promoted, '.') is not None:
|
||||
viperlib.snprintf(fn_ptr_name, 64, "@\"%s\"", mangled_promoted)
|
||||
else:
|
||||
viperlib.snprintf(fn_ptr_name, 64, "@%s", mangled_promoted)
|
||||
fn_ptr_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, fn_func_ptr_ty, fn_ptr_name)
|
||||
|
||||
# bitcast 函数指针到 i8*(闭包存储 i8* 类型)
|
||||
fn_as_i8ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
parent_builder, fn_ptr_val, i8_ptr_ty)
|
||||
fn_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
parent_builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty))
|
||||
if fn_slot is not None and fn_as_i8ptr is not None:
|
||||
llvmlite.build_store(parent_builder, fn_as_i8ptr, fn_slot)
|
||||
|
||||
# 13d. 存储 env_ptr 到 offset 8
|
||||
eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8)
|
||||
env_slot_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||||
parent_builder, i8_ty, closure_ptr, eight_val)
|
||||
if env_slot_addr is not None:
|
||||
env_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||||
parent_builder, env_slot_addr, llvmlite.Ptr(pool, i8_ptr_ty))
|
||||
if env_slot is not None:
|
||||
if env_ptr is not None:
|
||||
llvmlite.build_store(parent_builder, env_ptr, env_slot)
|
||||
else:
|
||||
# 无 nonlocal 变量,存储 null
|
||||
null_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ty, "null")
|
||||
llvmlite.build_store(parent_builder, null_val, env_slot)
|
||||
|
||||
# 13e. 将闭包指针存储到父函数的局部变量 {func_name}
|
||||
closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty)
|
||||
if closure_alloca is not None:
|
||||
llvmlite.build_store(parent_builder, closure_ptr, closure_alloca)
|
||||
HandlesVar.define_var(trans.SymTab, func_name, closure_alloca)
|
||||
|
||||
# 14. 恢复 scope names
|
||||
trans._cur_func_name = old_func_name
|
||||
trans._global_name_count = old_global_count
|
||||
trans._nonlocal_name_count = old_nonlocal_count
|
||||
trans._closure_env_count = old_env_count
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 创建 LLVM 函数(简单版本,仅声明)
|
||||
# ============================================================
|
||||
def create_function(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 = alist.__len__()
|
||||
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 = HandlesType.resolve_annotation_type(
|
||||
pool, arg.annotation, None, None, None)
|
||||
if resolved is not None:
|
||||
param_ty = resolved
|
||||
pname: t.CChar | t.CPtr = 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
|
||||
@@ -1,141 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import viperlib
|
||||
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.HandlesBody as HandlesBody
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesIf - if/elif/else 语句处理(Mixin 继承模式)
|
||||
#
|
||||
# 翻译 if 语句为 LLVM IR 控制流:
|
||||
# br i1 %cond, label %then, label %else
|
||||
# then:
|
||||
# ... body ...
|
||||
# br label %end
|
||||
# else:
|
||||
# ... orelse ...
|
||||
# br label %end
|
||||
# end:
|
||||
# ============================================================
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class IfHandle(HandlesBase.Mixin):
|
||||
"""if/elif/else 语句处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# Handle - 处理 if 语句,返回新增变量数
|
||||
# ============================================================
|
||||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 if/elif/else 语句"""
|
||||
if node is None:
|
||||
return 0
|
||||
|
||||
trans: HT.Translator | t.CPtr = self.Trans
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
|
||||
if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(node)
|
||||
|
||||
# 1. 求值条件表达式
|
||||
cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, if_node.test,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
|
||||
# 2. 转换为 i1 条件
|
||||
# Compare/Not 表达式已返回 i1,直接使用;其他类型与 0 比较
|
||||
if cond_val is None:
|
||||
cond_val = llvmlite.const_int32(pool, 0)
|
||||
cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty)
|
||||
if cond_bits == 1:
|
||||
cond_i1: llvmlite.Value | t.CPtr = cond_val
|
||||
else:
|
||||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
cond_i1 = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_NE, cond_val, zero)
|
||||
|
||||
# 3. 创建基本块(使用 trans._label_counter 生成唯一标签名,不与 SSA 名共享)
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "if.then.%d", cnt)
|
||||
then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "if.end.%d", cnt)
|
||||
merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
# 检查是否有 else 分支
|
||||
has_else: int = 0
|
||||
orelse_list: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse
|
||||
if orelse_list is not None:
|
||||
if orelse_list.__len__() > 0:
|
||||
has_else = 1
|
||||
|
||||
else_bb: llvmlite.BasicBlock | t.CPtr = None
|
||||
if has_else == 1:
|
||||
viperlib.snprintf(name_buf, 32, "if.else.%d", cnt)
|
||||
else_bb = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
# 4. 发射条件分支
|
||||
if has_else == 1:
|
||||
llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb)
|
||||
else:
|
||||
llvmlite.build_cond_br(builder, cond_i1, then_bb, merge_bb)
|
||||
|
||||
# 5. 翻译 then body
|
||||
llvmlite.position_at_end(builder, then_bb)
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = if_node.children
|
||||
if body is not None:
|
||||
body_count: t.CSizeT = body.__len__()
|
||||
for bi in range(body_count):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
|
||||
# then 块未终止则跳到 merge
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, merge_bb)
|
||||
|
||||
# 6. 翻译 else body(若有)
|
||||
if has_else == 1:
|
||||
llvmlite.position_at_end(builder, else_bb)
|
||||
else_count: t.CSizeT = orelse_list.__len__()
|
||||
for ei in range(else_count):
|
||||
stmt: ast.AST | t.CPtr = orelse_list.get(ei)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, merge_bb)
|
||||
|
||||
# 7. 定位到 merge 块继续后续代码
|
||||
llvmlite.position_at_end(builder, merge_bb)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewIfHandle - 工厂函数
|
||||
# ============================================================
|
||||
def NewIfHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> IfHandle | t.CPtr:
|
||||
h: IfHandle | t.CPtr = pool.alloc(IfHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, IfHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
@@ -1,596 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import viperlib
|
||||
import stdio
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesImports - 导入语句处理(Mixin 继承模式)
|
||||
#
|
||||
# 管理 _imported_modules 和 _from_imports 字符串
|
||||
# 注意:str = bytes = t.CChar | t.CPtr = i8*
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块级工具函数(保留供外部调用)
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 添加已导入模块名
|
||||
# ============================================================
|
||||
def add_imported_module(pool: memhub.MemBuddy | t.CPtr,
|
||||
imported_modules: str,
|
||||
name: str) -> str:
|
||||
"""记录已导入的模块名,返回新的 imported_modules 字符串指针"""
|
||||
if name is None:
|
||||
return imported_modules
|
||||
if imported_modules is None:
|
||||
nlen: t.CSizeT = string.strlen(name)
|
||||
buf: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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
|
||||
return imported_modules
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 检查模块是否已导入
|
||||
# ============================================================
|
||||
def is_module_imported(imported_modules: str, name: str) -> int:
|
||||
"""检查模块是否已导入(词边界精确匹配,避免子串误匹配)"""
|
||||
if name is None or imported_modules is None:
|
||||
return 0
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
cur: t.CChar | t.CPtr = imported_modules
|
||||
total_len: t.CSizeT = string.strlen(imported_modules)
|
||||
ci: t.CSizeT = 0
|
||||
while ci < total_len:
|
||||
while ci < total_len and cur[ci] == ' ':
|
||||
ci += 1
|
||||
if ci >= total_len:
|
||||
break
|
||||
word_start: t.CSizeT = ci
|
||||
while ci < total_len and cur[ci] != ' ':
|
||||
ci += 1
|
||||
word_len: t.CSizeT = ci - word_start
|
||||
if word_len == name_len:
|
||||
match: int = 1
|
||||
for ei in range(name_len):
|
||||
if cur[word_start + ei] != name[ei]:
|
||||
match = 0
|
||||
break
|
||||
if match == 1:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 添加 from-import 名称映射
|
||||
# ============================================================
|
||||
def add_from_import(pool: memhub.MemBuddy | t.CPtr,
|
||||
from_imports: str,
|
||||
local_name: str,
|
||||
module_name: str,
|
||||
original_name: str = None) -> str:
|
||||
"""添加 from-import 映射,返回新的 from_imports 字符串
|
||||
|
||||
格式:
|
||||
无别名: "local_name:module_name"
|
||||
有别名: "local_name:module_name:original_name"
|
||||
(original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰)
|
||||
"""
|
||||
if local_name is None or module_name is None:
|
||||
return from_imports
|
||||
entry: t.CChar | t.CPtr = pool.alloc(256)
|
||||
if entry is None:
|
||||
return from_imports
|
||||
if original_name is not None and original_name != local_name:
|
||||
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: t.CChar | t.CPtr = 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
|
||||
return from_imports
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 查找 from-import 名称 → 返回原始函数名(别名场景)
|
||||
#
|
||||
# 对于 from X import Y as Z,返回 Y(源模块中的真实函数名)。
|
||||
# 无别名时返回 None(local_name 即为原始名)。
|
||||
# ============================================================
|
||||
def lookup_from_import_original(from_imports: str,
|
||||
local_name: str) -> str:
|
||||
"""查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到"""
|
||||
if local_name is None or from_imports is None:
|
||||
return None
|
||||
name_len: t.CSizeT = string.strlen(local_name)
|
||||
cur: t.CChar | t.CPtr = from_imports
|
||||
ci: t.CSizeT = 0
|
||||
total_len: t.CSizeT = string.strlen(from_imports)
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
while ci < total_len and cur[ci] == ' ':
|
||||
ci += 1
|
||||
if ci >= total_len:
|
||||
break
|
||||
# 找到第一个 ':' 的位置
|
||||
colon1: t.CSizeT = 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
|
||||
# 跳过 star import
|
||||
if entry_name_len == 1 and cur[ci] == '*':
|
||||
ci = colon1
|
||||
while ci < total_len and cur[ci] != ' ':
|
||||
ci += 1
|
||||
continue
|
||||
# 比较名称
|
||||
if entry_name_len == name_len:
|
||||
match: int = 1
|
||||
ei: t.CSizeT = 0
|
||||
while ei < name_len:
|
||||
if cur[ci + ei] != local_name[ei]:
|
||||
match = 0
|
||||
break
|
||||
ei += 1
|
||||
if match == 1:
|
||||
# 找到匹配,检查是否有第三个字段(原始名)
|
||||
pos: t.CSizeT = 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
|
||||
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
|
||||
if orig_len > 0:
|
||||
orig_buf: str = cur + orig_start
|
||||
# 返回指向内部的指针(调用方需在使用期内保持 from_imports 有效)
|
||||
return orig_buf
|
||||
return None
|
||||
return None
|
||||
# 跳到下一个条目
|
||||
ci = colon1
|
||||
while ci < total_len and cur[ci] != ' ':
|
||||
ci += 1
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 查找 from-import 名称 → 返回模块名或 None
|
||||
#
|
||||
# allow_star_fallback: 是否允许 star import 回退(默认 1=允许)。
|
||||
# 当查询明确模块名(如 "BuildPipeline")时,应传 0 禁用回退,
|
||||
# 避免被 star import 模块名误导(如 from stdint import * 后
|
||||
# 查询 "BuildPipeline" 错误回退到 "stdint")。
|
||||
# ============================================================
|
||||
def lookup_from_import(from_imports: str, name: str,
|
||||
allow_star_fallback: int = 1) -> str:
|
||||
"""查找 from-import 名称,返回模块名或 None
|
||||
|
||||
支持 star import: 如果 from_imports 中有 "*:module" 条目,
|
||||
且未找到精确名称匹配,且 allow_star_fallback != 0,则返回 star import 的模块名。
|
||||
"""
|
||||
if name is None or from_imports is None:
|
||||
return None
|
||||
name_len: t.CSizeT = string.strlen(name)
|
||||
cur: t.CChar | t.CPtr = from_imports
|
||||
ci: t.CSizeT = 0
|
||||
total_len: t.CSizeT = string.strlen(from_imports)
|
||||
star_mod: str = None
|
||||
while ci < total_len:
|
||||
# 跳过前导空格
|
||||
while ci < total_len and cur[ci] == ' ':
|
||||
ci += 1
|
||||
if ci >= total_len:
|
||||
break
|
||||
# 找到 ':' 的位置
|
||||
colon_pos: t.CSizeT = 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
|
||||
# 检测 star import ("*:module")
|
||||
if entry_name_len == 1 and cur[ci] == '*':
|
||||
mod_start: t.CSizeT = colon_pos + 1
|
||||
mod_end: t.CSizeT = 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
|
||||
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
|
||||
# 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符)
|
||||
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':':
|
||||
mod_end2 += 1
|
||||
return cur + mod_start2
|
||||
# 跳到下一个条目
|
||||
ci = colon_pos
|
||||
while ci < total_len and cur[ci] != ' ':
|
||||
ci += 1
|
||||
# 未找到精确匹配,仅在允许时回退到 star import
|
||||
if allow_star_fallback == 0:
|
||||
return None
|
||||
return star_mod
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局 re-export 映射表(module_sha1 + func_name → source_module)
|
||||
#
|
||||
# 当 ast/__init__.py 中有 from .lexer import _lexer_init 时,
|
||||
# _lexer_init 被 re-export 为 ast._lexer_init。
|
||||
# 跨模块调用 ast._lexer_init(...) 需使用 ast.lexer 的 SHA1 混淆,
|
||||
# 而非 ast 的 SHA1。
|
||||
#
|
||||
# 数据布局:
|
||||
# _g_reexport_sha1s: 每条 17 字节(SHA1 16字符 + null)
|
||||
# _g_reexport_funcs: 每条 64 字节(函数名 + null)
|
||||
# _g_reexport_srcs: 每条 64 字节(源模块名 + null)
|
||||
# ============================================================
|
||||
MAX_REEXPORT: t.CDefine = 512
|
||||
|
||||
_g_reexport_sha1s: bytes = None
|
||||
_g_reexport_funcs: bytes = None
|
||||
_g_reexport_srcs: bytes = None
|
||||
_g_reexport_count: int = 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# register_reexport - 注册 re-export 映射
|
||||
#
|
||||
# 在 HandleImportFromNames 中调用:当处理 from .X import Y 时,
|
||||
# 记录当前模块(通过 ModuleSha1)re-export 了函数 Y,源模块为 X。
|
||||
#
|
||||
# 幂等:重复注册相同映射不会增加条目。
|
||||
# 内存用 stdlib.malloc 分配(全局存储器,跨 Phase 持久化)。
|
||||
# ============================================================
|
||||
def register_reexport(mod_sha1: str, func_name: str, source_module: str) -> int:
|
||||
"""注册 re-export 映射(幂等),返回 0 成功,-1 失败"""
|
||||
global _g_reexport_sha1s, _g_reexport_funcs, _g_reexport_srcs, _g_reexport_count
|
||||
if mod_sha1 is None or func_name is None or source_module is None:
|
||||
return -1
|
||||
# 懒初始化
|
||||
if _g_reexport_sha1s is None:
|
||||
_g_reexport_sha1s = stdlib.malloc(MAX_REEXPORT * 17)
|
||||
_g_reexport_funcs = stdlib.malloc(MAX_REEXPORT * 64)
|
||||
_g_reexport_srcs = stdlib.malloc(MAX_REEXPORT * 64)
|
||||
if _g_reexport_sha1s is None or _g_reexport_funcs is None or _g_reexport_srcs is None:
|
||||
return -1
|
||||
string.memset(_g_reexport_sha1s, 0, MAX_REEXPORT * 17)
|
||||
string.memset(_g_reexport_funcs, 0, MAX_REEXPORT * 64)
|
||||
string.memset(_g_reexport_srcs, 0, MAX_REEXPORT * 64)
|
||||
if _g_reexport_count >= MAX_REEXPORT:
|
||||
return -1
|
||||
# 幂等检查:查找是否已存在相同映射
|
||||
for i in range(_g_reexport_count):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
fidx: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
|
||||
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
|
||||
# 已存在,更新 source_module(以防变化)
|
||||
string.strcpy(_g_reexport_srcs + fidx, source_module)
|
||||
return 0
|
||||
# 添加新条目
|
||||
idx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 17
|
||||
fidx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 64
|
||||
string.strcpy(_g_reexport_sha1s + idx2, mod_sha1)
|
||||
string.strcpy(_g_reexport_funcs + fidx2, func_name)
|
||||
string.strcpy(_g_reexport_srcs + fidx2, source_module)
|
||||
_g_reexport_count += 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lookup_reexport - 查找 re-export 映射
|
||||
#
|
||||
# 给定模块 SHA1 和函数名,返回源模块名(如 "ast.lexer")或 None。
|
||||
# 调用方通过 _lookup_module_sha1(source_module) 获取源模块的 SHA1。
|
||||
# ============================================================
|
||||
def lookup_reexport(mod_sha1: str, func_name: str) -> str:
|
||||
"""查找 re-export 映射,返回源模块名或 None"""
|
||||
if mod_sha1 is None or func_name is None:
|
||||
return None
|
||||
if _g_reexport_sha1s is None or _g_reexport_count <= 0:
|
||||
return None
|
||||
for i in range(_g_reexport_count):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
fidx: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
|
||||
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
|
||||
return _g_reexport_srcs + fidx
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _resolve_relative_module - 解析相对导入为完整模块名
|
||||
#
|
||||
# 对于 from .X import Y(level=1, module="X")在包 pkg 中:
|
||||
# 解析为 "pkg.X"
|
||||
# 对于 from . import Y(level=1, module=None)在包 pkg 中:
|
||||
# 解析为 "pkg"
|
||||
# 对于 from ..X import Y(level=2, module="X")在包 pkg.sub 中:
|
||||
# 解析为 "pkg.X"(先从 pkg.sub 上溯一级到 pkg,再追加 .X)
|
||||
#
|
||||
# Args:
|
||||
# pool: 内存池
|
||||
# current_package: 当前文件所属包名(如 "llvmlite"),None 表示无包
|
||||
# level: 相对导入级别(0=绝对,1=., 2=..)
|
||||
# module: ImportFrom 的 module 字段(可能为 None)
|
||||
#
|
||||
# Returns:
|
||||
# 解析后的完整模块名;绝对导入(level<=0)直接返回 module;
|
||||
# 无法解析时返回 module(回退到原始值)
|
||||
# ============================================================
|
||||
def _resolve_relative_module(pool: memhub.MemBuddy | t.CPtr,
|
||||
current_package: str,
|
||||
level: t.CInt,
|
||||
module: str) -> str:
|
||||
"""解析相对导入为完整模块名"""
|
||||
if level <= 0:
|
||||
return module
|
||||
if current_package is None:
|
||||
return module
|
||||
|
||||
# 从 current_package 开始,上溯 (level-1) 级
|
||||
pkg: str = current_package
|
||||
up: t.CInt = level - 1
|
||||
while up > 0:
|
||||
pkg_len: t.CSizeT = string.strlen(pkg)
|
||||
last_dot: t.CSizeT = 0
|
||||
found: int = 0
|
||||
i: t.CSizeT = 0
|
||||
while i < pkg_len:
|
||||
if pkg[i] == '.':
|
||||
last_dot = i
|
||||
found = 1
|
||||
i += 1
|
||||
if found == 0:
|
||||
# 无更多父级,包变为空
|
||||
pkg = None
|
||||
break
|
||||
# 截断到最后一个 '.' 处
|
||||
new_pkg: str = pool.alloc(last_dot + 1)
|
||||
if new_pkg is None:
|
||||
return module
|
||||
string.strncpy(new_pkg, pkg, last_dot)
|
||||
new_pkg[last_dot] = '\0'
|
||||
pkg = new_pkg
|
||||
up -= 1
|
||||
|
||||
if module is None:
|
||||
# from . import Y → 模块就是包本身
|
||||
return pkg
|
||||
if pkg is None:
|
||||
# 包已上溯到空,直接用 module
|
||||
return module
|
||||
# 拼接 pkg + "." + module
|
||||
pkg_len2: t.CSizeT = string.strlen(pkg)
|
||||
mod_len: t.CSizeT = string.strlen(module)
|
||||
buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1)
|
||||
if buf is None:
|
||||
return module
|
||||
string.strcpy(buf, pkg)
|
||||
buf[pkg_len2] = '.'
|
||||
string.strcpy(buf + pkg_len2 + 1, module)
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# compute_package_from_relpath - 从相对路径计算包名
|
||||
#
|
||||
# 包名 = 文件所在目录路径,将 / 和 \ 替换为 .
|
||||
# 对于顶级文件(无目录分隔符),返回 None
|
||||
#
|
||||
# 示例:
|
||||
# "llvmlite/__init__.py" → "llvmlite"
|
||||
# "llvmlite/__types.py" → "llvmlite"
|
||||
# "ast/parser.py" → "ast"
|
||||
# "ast.py" → None(顶级文件)
|
||||
# ============================================================
|
||||
def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr,
|
||||
rel_path: str) -> str:
|
||||
"""从相对路径计算包名(目录部分,分隔符替换为 .)"""
|
||||
if rel_path is None:
|
||||
return None
|
||||
rlen: t.CSizeT = string.strlen(rel_path)
|
||||
# 找最后一个 / 或 \
|
||||
last_sep: t.CSizeT = 0
|
||||
found: int = 0
|
||||
i: t.CSizeT = 0
|
||||
while i < rlen:
|
||||
ch: t.CChar = rel_path[i]
|
||||
if ch == '/' or ch == '\\':
|
||||
last_sep = i
|
||||
found = 1
|
||||
i += 1
|
||||
if found == 0:
|
||||
# 无目录分隔符 → 顶级文件,无包
|
||||
return None
|
||||
# 复制目录部分,将 / 和 \ 替换为 .
|
||||
dir_len: t.CSizeT = last_sep
|
||||
buf: str = pool.alloc(dir_len + 1)
|
||||
if buf is None:
|
||||
return None
|
||||
j: t.CSizeT = 0
|
||||
while j < dir_len:
|
||||
ch2: t.CChar = rel_path[j]
|
||||
if ch2 == '/' or ch2 == '\\':
|
||||
buf[j] = '.'
|
||||
else:
|
||||
buf[j] = ch2
|
||||
j += 1
|
||||
buf[dir_len] = '\0'
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ImportsHandle - 导入语句处理器(Mixin 继承模式)
|
||||
#
|
||||
# 方法版本:直接更新 trans._imported_modules / trans._from_imports
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ImportsHandle(HandlesBase.Mixin):
|
||||
"""导入语句处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# HandleImport - 处理 import 语句,更新 trans._imported_modules
|
||||
# ============================================================
|
||||
def HandleImport(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""处理 import 语句,返回 0"""
|
||||
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node)
|
||||
if imp is None:
|
||||
return 0
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
|
||||
if names is None:
|
||||
return 0
|
||||
nn: t.CSizeT = names.__len__()
|
||||
for ni in range(nn):
|
||||
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
|
||||
if alias is not None and alias.name is not None:
|
||||
pool_val: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
im_val: str = self.Trans._imported_modules
|
||||
self.Trans._imported_modules = add_imported_module(
|
||||
pool_val, im_val, alias.name)
|
||||
# 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class())
|
||||
if alias.asname is not None:
|
||||
self.Trans._imported_modules = add_imported_module(
|
||||
pool_val, self.Trans._imported_modules, alias.asname)
|
||||
# 别名也加入 from_imports(asname:fullname),
|
||||
# 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1
|
||||
# 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator)
|
||||
self.Trans._from_imports = add_from_import(
|
||||
pool_val, self.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'
|
||||
self.Trans._imported_modules = add_imported_module(
|
||||
pool_val, self.Trans._imported_modules, pkg_buf)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# HandleImportFromModule - 处理 from X import Y 的模块部分
|
||||
#
|
||||
# 对相对导入(level > 0),使用 trans.CurrentPackage 解析为
|
||||
# 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt
|
||||
# 记录的模块名与 SHA1 映射表一致。
|
||||
# ============================================================
|
||||
def HandleImportFromModule(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""处理 from X import Y 的模块部分,更新 trans._imported_modules"""
|
||||
impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
|
||||
if impf is None:
|
||||
return 0
|
||||
# 解析模块名:相对导入需补充包前缀
|
||||
resolved: str = _resolve_relative_module(
|
||||
self.Trans.Pool, self.Trans.CurrentPackage,
|
||||
impf.level, impf.module)
|
||||
if resolved is not None:
|
||||
self.Trans._imported_modules = add_imported_module(
|
||||
self.Trans.Pool, self.Trans._imported_modules, resolved)
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# HandleImportFromNames - 处理 from X import Y 的名称部分
|
||||
#
|
||||
# 同样使用解析后的完整模块名,确保 from-import 映射
|
||||
# (如 LLVMType:llvmlite.__types)能正确查到 SHA1。
|
||||
# ============================================================
|
||||
def HandleImportFromNames(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""处理 from X import Y 的名称部分,更新 trans._from_imports"""
|
||||
impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
|
||||
if impf is None:
|
||||
return 0
|
||||
# 解析模块名:相对导入需补充包前缀
|
||||
resolved: str = _resolve_relative_module(
|
||||
self.Trans.Pool, self.Trans.CurrentPackage,
|
||||
impf.level, impf.module)
|
||||
if resolved is not None:
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = impf.names
|
||||
if names is not None:
|
||||
nn: t.CSizeT = names.__len__()
|
||||
for ni in range(nn):
|
||||
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
|
||||
if alias is not None and alias.name is not None:
|
||||
local_name: str = alias.name
|
||||
orig_name: str = None
|
||||
if alias.asname is not None:
|
||||
local_name = alias.asname
|
||||
orig_name = alias.name
|
||||
self.Trans._from_imports = add_from_import(
|
||||
self.Trans.Pool, self.Trans._from_imports,
|
||||
local_name, resolved, orig_name)
|
||||
# 命名空间隔离:from-import 的名称标记为可见结构体
|
||||
HandlesStruct.add_visible_struct(self.Trans.Pool, local_name)
|
||||
# 注册 re-export 映射:当前模块 re-export 了 local_name,源模块为 resolved
|
||||
# 使跨模块调用 module.func() 能解析到正确的源模块 SHA1
|
||||
if self.Trans.ModuleSha1 is not None:
|
||||
register_reexport(self.Trans.ModuleSha1, local_name, resolved)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewImportsHandle - 工厂函数
|
||||
# ============================================================
|
||||
def NewImportsHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> ImportsHandle | t.CPtr:
|
||||
h: ImportsHandle | t.CPtr = pool.alloc(ImportsHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, ImportsHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
@@ -1,492 +0,0 @@
|
||||
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.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.Handles.HandlesBody as HandlesBody
|
||||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesMain - 模块级翻译入口 + wrapper main 创建
|
||||
#
|
||||
# 从 translator.py 拆分出来,负责:
|
||||
# 1. create_wrapper_main() - 无用户 main 时创建包装 main
|
||||
# 2. translate_children() - 遍历 AST 子节点并分派翻译
|
||||
#
|
||||
# trans 单参模式:所有共享状态从 trans 获取,无需 11 个参数
|
||||
# 注意: str = bytes = t.CChar | t.CPtr = i8*
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数
|
||||
#
|
||||
# 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的
|
||||
# CExport 函数无法被先翻译的模块正确识别为裸名调用。
|
||||
# Phase 1a 预注册所有 CExport/State 函数名到全局表。
|
||||
# ============================================================
|
||||
def _register_cexport_from_funcdef(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""预注册 CExport/State 函数到全局表(仅注册,不生成 IR)"""
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
|
||||
if fd is None or fd.name is None:
|
||||
return 0
|
||||
if trans is None or trans.ModuleSha1 is None:
|
||||
return 0
|
||||
|
||||
# 检查返回类型是否有 CExport 或 State 标记
|
||||
has_export: int = 0
|
||||
has_state: int = 0
|
||||
if fd.returns is not None:
|
||||
has_export = HandlesType.has_decorator_marker(fd.returns, "CExport")
|
||||
has_state = HandlesType.has_decorator_marker(fd.returns, "State")
|
||||
|
||||
if has_export != 0 or has_state != 0:
|
||||
HandlesExprCall.register_cexport_func(trans.ModuleSha1, fd.name)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# translate_children - 遍历 AST 子节点并分派翻译
|
||||
#
|
||||
# 对应 TransPyC translator._translate_children()
|
||||
# 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans
|
||||
# ============================================================
|
||||
def translate_children(trans: HT.Translator | t.CPtr,
|
||||
tree: ast.AST | t.CPtr) -> int:
|
||||
"""遍历 tree.children 并翻译每个子节点
|
||||
|
||||
Args:
|
||||
trans: 翻译器(含所有共享状态)
|
||||
tree: AST 模块节点
|
||||
|
||||
Returns:
|
||||
t.CInt: 新增的变量数
|
||||
"""
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is None:
|
||||
return 0
|
||||
|
||||
cn_count: t.CSizeT = ch.__len__()
|
||||
added_total: int = 0
|
||||
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None: continue
|
||||
kd: int = child.kind()
|
||||
|
||||
# _declare_only == 0 时,_translate_module_level 已预处理导入语句,
|
||||
# 此处跳过避免重复处理(from_imports 条目重复)
|
||||
if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom):
|
||||
continue
|
||||
if kd == ast.ASTKind.Import:
|
||||
trans.ImportsH.HandleImport(child)
|
||||
elif kd == ast.ASTKind.ImportFrom:
|
||||
trans.ImportsH.HandleImportFromModule(child)
|
||||
trans.ImportsH.HandleImportFromNames(child)
|
||||
elif kd == ast.ASTKind.FunctionDef:
|
||||
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
|
||||
# Phase 1b 全量翻译:正常翻译函数体
|
||||
if trans._declare_only == 0:
|
||||
added: int = HandlesFunctions.translate_function_def(trans, child)
|
||||
added_total += added
|
||||
elif trans._declare_only == 1:
|
||||
_register_cexport_from_funcdef(trans, child)
|
||||
elif kd == ast.ASTKind.ClassDef:
|
||||
# ClassDef 在模块级直接处理(不需要 builder)
|
||||
# _declare_only=2(import扫描模式)时跳过,只处理 import 依赖
|
||||
if trans._declare_only != 2:
|
||||
HandlesClassDef.translate_class_def(trans, child)
|
||||
elif trans._declare_only == 0 and trans._cur_builder is not None:
|
||||
# 有 builder → 委托 HandlesBody 分派
|
||||
added = HandlesBody.translate_stmt(trans, child)
|
||||
added_total += added
|
||||
elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2:
|
||||
# 模块级 AnnAssign
|
||||
# _declare_only=2(import扫描模式)时跳过
|
||||
# _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断)
|
||||
# _declare_only=0(全量翻译)时处理所有模块级 AnnAssign
|
||||
added = handle_module_level_var(trans, child)
|
||||
added_total += added
|
||||
elif trans._declare_only == 0 and kd == ast.ASTKind.Assign:
|
||||
# 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式)
|
||||
added = handle_module_level_var(trans, child)
|
||||
added_total += added
|
||||
|
||||
return added_total
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器
|
||||
#
|
||||
# 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...]
|
||||
# 用于模块级 t.CArray 列表字面量初始化(不依赖 builder,直接生成常量初始化器)
|
||||
# ============================================================
|
||||
def _build_array_initializer_text(pool: memhub.MemBuddy | t.CPtr,
|
||||
var_ty: llvmlite.LLVMType | t.CPtr,
|
||||
list_node: ast.List | t.CPtr) -> str:
|
||||
"""从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败"""
|
||||
if var_ty is None or list_node is None:
|
||||
return None
|
||||
|
||||
# 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型
|
||||
# (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr)
|
||||
ln: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
|
||||
if ln is None:
|
||||
return None
|
||||
|
||||
# 从 var_ty 提取数组元素类型和数量
|
||||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
arr_count: t.CInt = 0
|
||||
match var_ty:
|
||||
case llvmlite.LLVMType.Array(et, cnt):
|
||||
elem_ty = et
|
||||
arr_count = cnt
|
||||
|
||||
if elem_ty is None or arr_count <= 0:
|
||||
return None
|
||||
|
||||
# 确定元素类型的 IR 表示
|
||||
elem_ir_ty: str = "i8"
|
||||
match elem_ty:
|
||||
case llvmlite.LLVMType.Int(bits):
|
||||
if bits == 8:
|
||||
elem_ir_ty = "i8"
|
||||
elif bits == 16:
|
||||
elem_ir_ty = "i16"
|
||||
elif bits == 32:
|
||||
elem_ir_ty = "i32"
|
||||
elif bits == 64:
|
||||
elem_ir_ty = "i64"
|
||||
|
||||
# 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别)
|
||||
elts: list[ast.AST | t.CPtr] | t.CPtr = ln.elts
|
||||
if elts is None:
|
||||
return None
|
||||
elts_count: t.CSizeT = elts.__len__()
|
||||
|
||||
# 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符
|
||||
buf_size: t.CSizeT = 64 + elts_count * 32
|
||||
buf: t.CChar | t.CPtr = pool.alloc(buf_size)
|
||||
if buf is None:
|
||||
return None
|
||||
|
||||
# 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表)
|
||||
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
|
||||
pos: t.CSizeT = t.CSizeT(written)
|
||||
|
||||
# 逐个元素写入
|
||||
i: t.CSizeT = 0
|
||||
while i < elts_count:
|
||||
elem_node: ast.AST | t.CPtr = elts.get(i)
|
||||
# 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断)
|
||||
elem_val: t.CInt64T = 0
|
||||
if elem_node is not None:
|
||||
ek: int = elem_node.kind()
|
||||
if ek == ast.ASTKind.Constant:
|
||||
ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node)
|
||||
if ec is not None and ec.const_kind == ast.CONST_INT:
|
||||
elem_val = ec.int_val
|
||||
elif ek == ast.ASTKind.UnaryOp:
|
||||
# 负数: UnaryOp(USub, Constant)
|
||||
elem_val = HandlesAnnAssign.extract_cdefine_int_value(elem_node)
|
||||
if i > 0:
|
||||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||||
pos += t.CSizeT(written)
|
||||
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val)
|
||||
pos += t.CSizeT(written)
|
||||
i += 1
|
||||
|
||||
# 写入后缀 "]"
|
||||
viperlib.snprintf(buf + pos, buf_size - pos, "]")
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量
|
||||
#
|
||||
# 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00"
|
||||
# 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0)
|
||||
# 用于 b64_tab: t.CArray[t.CChar, None] = "ABC..." 等字符串初始化指针类型
|
||||
# ============================================================
|
||||
def _build_string_ptr_initializer(pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
var_name: str,
|
||||
str_val: str) -> str:
|
||||
"""为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败"""
|
||||
if str_val is None or var_name is None:
|
||||
return None
|
||||
|
||||
# 构造内部字符串常量名称: .str.{var_name}
|
||||
str_name_buf: t.CChar | t.CPtr = pool.alloc(64)
|
||||
if str_name_buf is None:
|
||||
return None
|
||||
viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name)
|
||||
|
||||
# 调用 llvmlite.create_global_string 创建字符串常量全局
|
||||
str_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_string(
|
||||
pool, mod, str_name_buf, str_val)
|
||||
if str_gv is None:
|
||||
return None
|
||||
|
||||
# 生成 GEP 初始化器文本
|
||||
str_len: t.CSizeT = string.strlen(str_val)
|
||||
init_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||||
if init_buf is None:
|
||||
return None
|
||||
viperlib.snprintf(init_buf, 128,
|
||||
"getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)",
|
||||
str_len + 1, str_len + 1, str_name_buf)
|
||||
return init_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
|
||||
#
|
||||
# 当用户已定义 main(无 wrapper main builder)时,模块级
|
||||
# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域
|
||||
# 支持整数、列表字面量、字符串字面量初始值
|
||||
# ============================================================
|
||||
def handle_module_level_var(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""处理模块级变量声明,创建全局变量"""
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
|
||||
# CDefine 注解: 编译期常量,不创建全局变量
|
||||
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa_cd is not None and aa_cd.target is not None:
|
||||
if aa_cd.target.kind() == ast.ASTKind.Name:
|
||||
nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target)
|
||||
if nm_cd.id is not None:
|
||||
if HandlesAnnAssign.is_cdefine_annotation(aa_cd.annotation) != 0:
|
||||
val_cd: int = HandlesAnnAssign.extract_cdefine_int_value(aa_cd.value)
|
||||
HandlesType.register_cdefine_constant(pool, nm_cd.id, val_cd)
|
||||
return 0
|
||||
|
||||
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
|
||||
# CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过
|
||||
if trans._declare_only == 1:
|
||||
return 0
|
||||
|
||||
var_name: str = None
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
init_val: t.CInt64T = 0
|
||||
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str
|
||||
init_str_val: str = None
|
||||
init_list_node: ast.List | t.CPtr = None
|
||||
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa is None or aa.target is None:
|
||||
return 0
|
||||
if aa.target.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
|
||||
var_name = nm.id
|
||||
# 解析类型
|
||||
if aa.annotation is not None:
|
||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
|
||||
if resolved is not None:
|
||||
var_ty = resolved
|
||||
# 解析初始值(支持整数、列表字面量、字符串字面量)
|
||||
if aa.value is not None:
|
||||
val_kind: int = aa.value.kind()
|
||||
if val_kind == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
|
||||
if cn.const_kind == ast.CONST_INT:
|
||||
init_val = cn.int_val
|
||||
init_kind = 1
|
||||
elif cn.const_kind == ast.CONST_STR:
|
||||
init_str_val = cn.str_val
|
||||
init_kind = 3
|
||||
elif val_kind == ast.ASTKind.List:
|
||||
init_list_node = (ast.List | t.CPtr)(aa.value)
|
||||
init_kind = 2
|
||||
elif k == ast.ASTKind.Assign:
|
||||
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||||
if asgn is None or asgn.targets is None:
|
||||
return 0
|
||||
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
|
||||
if targets.__len__() < 1:
|
||||
return 0
|
||||
t0: ast.AST | t.CPtr = targets.get(0)
|
||||
if t0 is None or t0.kind() != ast.ASTKind.Name:
|
||||
return 0
|
||||
nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0)
|
||||
var_name = nm2.id
|
||||
if asgn.value is not None:
|
||||
val_kind2: int = asgn.value.kind()
|
||||
if val_kind2 == ast.ASTKind.Constant:
|
||||
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value)
|
||||
if cn2.const_kind == ast.CONST_INT:
|
||||
init_val = cn2.int_val
|
||||
init_kind = 1
|
||||
elif cn2.const_kind == ast.CONST_STR:
|
||||
init_str_val = cn2.str_val
|
||||
init_kind = 3
|
||||
elif val_kind2 == ast.ASTKind.List:
|
||||
init_list_node = (ast.List | t.CPtr)(asgn.value)
|
||||
init_kind = 2
|
||||
|
||||
if var_name is None:
|
||||
return 0
|
||||
|
||||
# 检查是否已注册
|
||||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||||
trans.SymTab, var_name)
|
||||
if existing is not None:
|
||||
return 0
|
||||
|
||||
# 创建全局变量 @var_name
|
||||
# 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明
|
||||
# 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报
|
||||
# "use of undefined type named 'sha1.ClassName'" 错误
|
||||
# (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager")))
|
||||
llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty)
|
||||
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, var_name, var_ty)
|
||||
if gv is None:
|
||||
return 0
|
||||
llvmlite.module_add_global(mod, gv)
|
||||
|
||||
# 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值)
|
||||
gv.Linkage = None
|
||||
if init_kind == 1:
|
||||
# 整数初始值
|
||||
init_buf: t.CChar | t.CPtr = pool.alloc(48)
|
||||
if init_buf is not None:
|
||||
viperlib.snprintf(init_buf, 48, "%lld", init_val)
|
||||
gv.Initializer = init_buf
|
||||
elif init_kind == 2:
|
||||
# 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...]
|
||||
arr_init: str = _build_array_initializer_text(pool, var_ty, init_list_node)
|
||||
if arr_init is not None:
|
||||
gv.Initializer = arr_init
|
||||
else:
|
||||
gv.Initializer = "zeroinitializer"
|
||||
elif init_kind == 3:
|
||||
# 字符串字面量 → 创建字符串常量全局 + GEP 引用
|
||||
str_init: str = _build_string_ptr_initializer(pool, mod, var_name, init_str_val)
|
||||
if str_init is not None:
|
||||
gv.Initializer = str_init
|
||||
else:
|
||||
gv.Initializer = "zeroinitializer"
|
||||
else:
|
||||
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
|
||||
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
|
||||
gv.Initializer = "zeroinitializer"
|
||||
|
||||
# 创建 Value 引用(@var_name, 类型为 var_ty*)
|
||||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||||
ref_name: t.CChar | t.CPtr = pool.alloc(64)
|
||||
if ref_name is not None:
|
||||
viperlib.snprintf(ref_name, 64, "@%s", var_name)
|
||||
gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name)
|
||||
|
||||
# 注册到模块作用域
|
||||
if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
|
||||
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
|
||||
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa_ml is not None and aa_ml.annotation is not None:
|
||||
cls_nm_ml: str = HandlesType.extract_class_name_from_annotation(
|
||||
aa_ml.annotation, trans._imported_modules)
|
||||
if cls_nm_ml is not None:
|
||||
HandlesVar.set_var_annot_class_name(
|
||||
trans.SymTab, var_name, cls_nm_ml)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# create_wrapper_main - 创建包装 main 函数
|
||||
#
|
||||
# 当用户未定义 main 函数时调用。
|
||||
# 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder →
|
||||
# 预扫描 alloca → 翻译子节点 → ret 0
|
||||
# ============================================================
|
||||
def create_wrapper_main(trans: HT.Translator | t.CPtr,
|
||||
tree: ast.AST | t.CPtr,
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
"""创建包装 main 函数并翻译所有顶层语句
|
||||
|
||||
Args:
|
||||
trans: 翻译器(含所有共享状态)
|
||||
tree: AST 模块节点
|
||||
i32_ty: i32 LLVMType
|
||||
|
||||
Returns:
|
||||
t.CInt: 新增的变量数
|
||||
"""
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
|
||||
main_func: llvmlite.Function | t.CPtr = llvmlite.create_function(
|
||||
pool, mod, "main", i32_ty)
|
||||
if main_func is None:
|
||||
VLogger.error("CreateFunction main returned NULL", "TR")
|
||||
return 0
|
||||
|
||||
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||
pool, main_func, "entry")
|
||||
if entry_blk is None:
|
||||
VLogger.error("CreateBlock returned NULL", "TR")
|
||||
return 0
|
||||
|
||||
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
|
||||
if builder is None:
|
||||
VLogger.error("NewBuilder returned NULL", "TR")
|
||||
return 0
|
||||
llvmlite.position_at_end(builder, entry_blk)
|
||||
|
||||
# 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问)
|
||||
trans._cur_func = main_func
|
||||
trans._cur_builder = builder
|
||||
|
||||
# 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量
|
||||
# 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca,
|
||||
# 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR)
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is not None:
|
||||
cn_count: t.CSizeT = ch.__len__()
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is not None:
|
||||
kd: int = child.kind()
|
||||
if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign:
|
||||
handle_module_level_var(trans, child)
|
||||
|
||||
# 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca
|
||||
# (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们)
|
||||
if ch is not None:
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is not None:
|
||||
HandlesBody.pre_scan_allocas(trans, child)
|
||||
|
||||
# 翻译子节点
|
||||
added_total: int = translate_children(trans, tree)
|
||||
|
||||
# 返回 0
|
||||
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
llvmlite.build_ret(builder, zero_val)
|
||||
|
||||
return added_total
|
||||
@@ -1,127 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesNonlocal - nonlocal 变量访问(通过闭包 env)
|
||||
#
|
||||
# 闭包 env 结构: {i8* ptr0, i8* ptr1, ...} (每个 nonlocal 变量一个 i8* 指针)
|
||||
# 指针指向原始变量(可能是 alloca 或全局变量)
|
||||
#
|
||||
# 在提升的嵌套函数中:
|
||||
# 1. 函数签名: define i32 @__closure_{name}(i8* %env)
|
||||
# 2. 入口处: %env_alloca = alloca i8*; store i8* %env, i8** %env_alloca
|
||||
# 3. 访问 nonlocal var:
|
||||
# a. %env_ptr = load i8*, i8** %env_alloca
|
||||
# b. %addr = gep i8, i8* %env_ptr, i32 (index * 8)
|
||||
# c. %ptr_addr = bitcast i8* %addr to i8**
|
||||
# d. %var_ptr_raw = load i8*, i8** %ptr_addr
|
||||
# e. %var_ptr = bitcast i8* %var_ptr_raw to i32*
|
||||
# f. read: %val = load i32, i32* %var_ptr
|
||||
# write: store i32 %new, i32* %var_ptr
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 获取或创建 _env_ptr 变量(存储 env 参数的 alloca)
|
||||
# ============================================================
|
||||
def get_env_ptr_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""获取或创建 _env_ptr 变量(存储闭包 env 指针)"""
|
||||
env_var: llvmlite.Value | t.CPtr = HandlesVar.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)
|
||||
if alloca is None:
|
||||
return None
|
||||
HandlesVar.define_var(trans.SymTab, "_env_ptr", alloca)
|
||||
return alloca
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 加载 nonlocal 变量值 → 返回 i32 Value
|
||||
#
|
||||
# env 直接存储 i32 值(不是指针),每个 nonlocal 变量占 4 字节
|
||||
# ============================================================
|
||||
def load_nonlocal_var(trans: HT.Translator | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
"""从闭包 env 加载 nonlocal 变量值(env 直接存储 i32 值)"""
|
||||
idx: int = HT.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)
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty)
|
||||
|
||||
# 1. 加载 env_ptr
|
||||
env_alloca: llvmlite.Value | t.CPtr = 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)
|
||||
if env_ptr is None:
|
||||
return None
|
||||
|
||||
# 2. GEP to offset (idx * 4) — env 直接存储 i32 值
|
||||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4)
|
||||
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||||
if addr is None:
|
||||
return None
|
||||
|
||||
# 3. Bitcast to i32* and load
|
||||
var_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, addr, i32_ptr_ty)
|
||||
if var_ptr is None:
|
||||
return None
|
||||
return llvmlite.build_load(builder, i32_ty, var_ptr)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 获取 nonlocal 变量指针(用于 store)
|
||||
#
|
||||
# 返回 env 中 i32 槽位的地址(i32*),用于直接 store
|
||||
# ============================================================
|
||||
def get_nonlocal_var_ptr(trans: HT.Translator | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
"""获取 nonlocal 变量在 env 中的地址(i32*),用于 store 操作"""
|
||||
idx: int = HT.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)
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty)
|
||||
|
||||
# 1. 加载 env_ptr
|
||||
env_alloca: llvmlite.Value | t.CPtr = 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)
|
||||
if env_ptr is None:
|
||||
return None
|
||||
|
||||
# 2. GEP to offset (idx * 4) — env 直接存储 i32 值
|
||||
offset_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, idx * 4)
|
||||
addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, env_ptr, offset_val)
|
||||
if addr is None:
|
||||
return None
|
||||
|
||||
# 3. Bitcast to i32* and return (直接指向 env 中的 i32 槽位)
|
||||
return llvmlite.build_bitcast(builder, addr, i32_ptr_ty)
|
||||
@@ -1,117 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
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.HandlesVar as HandlesVar
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesReturn - Return 语句处理(Mixin 继承模式)
|
||||
# ============================================================
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class ReturnHandle(HandlesBase.Mixin):
|
||||
"""Return 语句处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# Handle - 处理 Return 语句,返回 0
|
||||
#
|
||||
# 翻译返回值(若有)并生成 ret 指令
|
||||
# ============================================================
|
||||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 Return 语句"""
|
||||
rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node)
|
||||
if rt is None:
|
||||
return 0
|
||||
|
||||
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||||
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||||
|
||||
val: llvmlite.Value | t.CPtr = None
|
||||
if rt.value is not None:
|
||||
# return self: 直接返回指针(self 是 SSA 参数 Ptr(struct_ty))
|
||||
# translate_value 会 load 得到结构体值,但 return self 需要指针本身
|
||||
if rt.value.kind() == ast.ASTKind.Name:
|
||||
ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rt.value)
|
||||
if ret_nm is not None and ret_nm.id is not None:
|
||||
if string.strcmp(ret_nm.id, "self") == 0:
|
||||
self_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
self.Trans.SymTab, "self")
|
||||
if self_ptr is not None:
|
||||
val = self_ptr
|
||||
if val is None:
|
||||
val = HandlesExpr.translate_value(
|
||||
builder, pool, mod, rt.value,
|
||||
self.Trans._funcs, self.Trans._func_count, self.Trans)
|
||||
|
||||
# val 为 None 时(裸 return):检查当前函数返回类型
|
||||
# void 函数(如 __init__/__before_init__)生成 ret void,
|
||||
# ptr 函数生成 ret ptr null,否则 ret i32 0
|
||||
if val is None:
|
||||
cur_func: llvmlite.Function | t.CPtr = self.Trans._cur_func
|
||||
is_void_ret: int = 0
|
||||
is_ptr_ret: int = 0
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if cur_func is not None:
|
||||
ret_ty = llvmlite.function_get_ret_ty(cur_func)
|
||||
if ret_ty is not None:
|
||||
match ret_ty:
|
||||
case llvmlite.LLVMType.Void():
|
||||
is_void_ret = 1
|
||||
case llvmlite.LLVMType.Ptr(_pe):
|
||||
is_ptr_ret = 1
|
||||
if is_void_ret != 0:
|
||||
llvmlite.build_ret_void(builder)
|
||||
return 0
|
||||
if is_ptr_ret != 0:
|
||||
null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
|
||||
llvmlite.build_ret(builder, null_val)
|
||||
return 0
|
||||
val = llvmlite.const_int32(pool, 0)
|
||||
|
||||
# 类型转换:确保 val 类型与函数返回类型匹配
|
||||
# 处理 i1(bool 比较结果)→ i8(t.CBool)等情况
|
||||
# i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF)
|
||||
# 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr),
|
||||
# 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type"
|
||||
cur_func_rt: llvmlite.Function | t.CPtr = self.Trans._cur_func
|
||||
if cur_func_rt is not None and val is not None and val.Ty is not None:
|
||||
ret_ty_rt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func_rt)
|
||||
if ret_ty_rt is not None:
|
||||
val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
|
||||
ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt)
|
||||
val_is_ptr: int = HandlesExpr.is_ptr_type(val.Ty)
|
||||
ret_is_ptr: int = HandlesExpr.is_ptr_type(ret_ty_rt)
|
||||
# ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换
|
||||
if val_is_ptr != ret_is_ptr:
|
||||
val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt)
|
||||
elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits:
|
||||
if val_bits == 1 and val_bits < ret_bits:
|
||||
val = llvmlite.build_zext(builder, val, ret_ty_rt)
|
||||
else:
|
||||
val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt)
|
||||
llvmlite.build_ret(builder, val)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewReturnHandle - 工厂函数
|
||||
# ============================================================
|
||||
def NewReturnHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> ReturnHandle | t.CPtr:
|
||||
h: ReturnHandle | t.CPtr = pool.alloc(ReturnHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, ReturnHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,434 +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.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesMain as HandlesMain
|
||||
import lib.core.Handles.HandlesAssign as HandlesAssign
|
||||
import lib.core.Handles.HandlesReturn as HandlesReturn
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
import lib.core.Handles.HandlesAugAssign as HandlesAugAssign
|
||||
import lib.core.Handles.HandlesIf as HandlesIf
|
||||
import lib.core.Handles.HandlesWhile as HandlesWhile
|
||||
import lib.core.Handles.HandlesFor as HandlesFor
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
# ============================================================
|
||||
# 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*
|
||||
# ============================================================
|
||||
|
||||
# 常量
|
||||
MAX_VARS: t.CDefine = 256
|
||||
MAX_FUNCS: t.CDefine = 256
|
||||
MAX_GLOBAL_NAMES: t.CDefine = 32
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class Translator:
|
||||
"""翻译器:管理编译状态,委托 Handles 模块执行翻译"""
|
||||
|
||||
# LLVM 上下文(共享状态)
|
||||
Module: llvmlite.LLVMModule | t.CPtr
|
||||
Pool: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# 函数表
|
||||
_funcs: HandlesExprCall.FuncEntry | t.CPtr
|
||||
_func_count: t.CInt
|
||||
|
||||
# 导入模块跟踪
|
||||
_imported_modules: str
|
||||
_from_imports: str
|
||||
|
||||
# 当前翻译上下文
|
||||
_cur_func: llvmlite.Function | t.CPtr
|
||||
_cur_builder: llvmlite.IRBuilder | t.CPtr
|
||||
|
||||
# 循环控制流目标(break/continue)
|
||||
_break_bb: llvmlite.BasicBlock | t.CPtr
|
||||
_continue_bb: llvmlite.BasicBlock | t.CPtr
|
||||
|
||||
# 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调)
|
||||
_label_counter: t.CInt
|
||||
|
||||
# global 声明的变量名集合(当前函数内)
|
||||
_global_names: str
|
||||
_global_name_count: t.CInt
|
||||
|
||||
# nonlocal 声明的变量名集合(当前函数内)
|
||||
_nonlocal_names: str
|
||||
_nonlocal_name_count: t.CInt
|
||||
|
||||
# 闭包相关:当前函数名(用于嵌套函数提升命名)
|
||||
_cur_func_name: str
|
||||
|
||||
# 模块 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
|
||||
|
||||
# 泛型特化上下文:当前正在特化的类型参数名/实参名列表
|
||||
# 由 _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
|
||||
|
||||
# 子 Handle 指针(每个 Handle 一个槽,通过 Mixin 回指针访问本结构体)
|
||||
AssignH: HandlesAssign.AssignHandle | t.CPtr
|
||||
ReturnH: HandlesReturn.ReturnHandle | t.CPtr
|
||||
ImportsH: HandlesImports.ImportsHandle | t.CPtr
|
||||
AnnAssignH: HandlesAnnAssign.AnnAssignHandle | t.CPtr
|
||||
AugAssignH: HandlesAugAssign.AugAssignHandle | t.CPtr
|
||||
IfH: HandlesIf.IfHandle | t.CPtr
|
||||
WhileH: HandlesWhile.WhileHandle | t.CPtr
|
||||
ForH: HandlesFor.ForHandle | t.CPtr
|
||||
ExprH: HandlesExpr.ExprHandle | t.CPtr
|
||||
ExprCallH: HandlesExprCall.ExprCallHandle | t.CPtr
|
||||
|
||||
# 嵌套作用域符号表
|
||||
SymTab: HandlesVar.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._cur_func_name = None
|
||||
self.ModuleSha1 = None
|
||||
self.CurrentPackage = None
|
||||
self._closure_env_offsets = 0
|
||||
self._closure_env_count = 0
|
||||
self.GenericTypeParamNames = None
|
||||
self.GenericTypeArgs = None
|
||||
self._declare_only = 0
|
||||
self.AssignH = None
|
||||
self.ReturnH = None
|
||||
self.ImportsH = None
|
||||
self.AnnAssignH = None
|
||||
self.AugAssignH = None
|
||||
self.IfH = None
|
||||
self.WhileH = None
|
||||
self.ForH = None
|
||||
self.ExprH = None
|
||||
self.ExprCallH = None
|
||||
self.SymTab = None
|
||||
|
||||
# ============================================================
|
||||
# 状态初始化
|
||||
# ============================================================
|
||||
def _init_state(self, pool: memhub.MemBuddy | t.CPtr):
|
||||
"""初始化变量表、函数表和子 Handle"""
|
||||
self.Pool = pool
|
||||
if self._funcs is None:
|
||||
self._funcs = HandlesExprCall.init_func_table(pool, MAX_FUNCS)
|
||||
# 嵌套作用域符号表(新版)
|
||||
if self.SymTab is None:
|
||||
self.SymTab = HandlesVar.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
|
||||
# 创建子 Handle(传入 self 作为 Mixin 回指针)
|
||||
if self.AssignH is None:
|
||||
self.AssignH = HandlesAssign.NewAssignHandle(pool, self)
|
||||
if self.ReturnH is None:
|
||||
self.ReturnH = HandlesReturn.NewReturnHandle(pool, self)
|
||||
if self.ImportsH is None:
|
||||
self.ImportsH = HandlesImports.NewImportsHandle(pool, self)
|
||||
if self.AnnAssignH is None:
|
||||
self.AnnAssignH = HandlesAnnAssign.NewAnnAssignHandle(pool, self)
|
||||
if self.AugAssignH is None:
|
||||
self.AugAssignH = HandlesAugAssign.NewAugAssignHandle(pool, self)
|
||||
if self.IfH is None:
|
||||
self.IfH = HandlesIf.NewIfHandle(pool, self)
|
||||
if self.WhileH is None:
|
||||
self.WhileH = HandlesWhile.NewWhileHandle(pool, self)
|
||||
if self.ForH is None:
|
||||
self.ForH = HandlesFor.NewForHandle(pool, self)
|
||||
if self.ExprH is None:
|
||||
self.ExprH = HandlesExpr.NewExprHandle(pool, self)
|
||||
if self.ExprCallH is None:
|
||||
self.ExprCallH = HandlesExprCall.NewExprCallHandle(pool, self)
|
||||
|
||||
# ============================================================
|
||||
# 主翻译入口
|
||||
# ============================================================
|
||||
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
|
||||
|
||||
# 声明 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 = ch.__len__()
|
||||
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):
|
||||
"""委托 HandlesMain.create_wrapper_main() 创建包装 main(trans 单参)"""
|
||||
added: int = HandlesMain.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):
|
||||
"""委托 HandlesMain.translate_children() 翻译模块级语句(trans 单参)"""
|
||||
# 全量翻译模式下,先处理导入语句,再创建前向声明,解决前向引用问题
|
||||
if self._declare_only == 0:
|
||||
# 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充
|
||||
# (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入)
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is not None:
|
||||
cn_count: t.CSizeT = ch.__len__()
|
||||
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:
|
||||
self.ImportsH.HandleImport(child)
|
||||
elif kd == ast.ASTKind.ImportFrom:
|
||||
self.ImportsH.HandleImportFromModule(child)
|
||||
self.ImportsH.HandleImportFromNames(child)
|
||||
# 预注册模块级变量(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:
|
||||
HandlesMain.handle_module_level_var(self, child)
|
||||
# 创建前向声明
|
||||
HandlesFunctions.forward_declare_functions(self, tree)
|
||||
added: int = HandlesMain.translate_children(self, tree)
|
||||
|
||||
# ============================================================
|
||||
# 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 名称管理(模块级辅助函数)
|
||||
# ============================================================
|
||||
def add_global_name(trans: HT.Translator | t.CPtr, name: str):
|
||||
"""添加一个 global 变量名"""
|
||||
if trans is None or name is None:
|
||||
return
|
||||
if trans._global_name_count >= MAX_GLOBAL_NAMES:
|
||||
return
|
||||
if trans._global_names is None:
|
||||
return
|
||||
# 检查是否已存在
|
||||
if is_global_name(trans, name) != 0:
|
||||
return
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8
|
||||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||||
slot_ptr[0] = name
|
||||
trans._global_name_count += 1
|
||||
|
||||
|
||||
def is_global_name(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""检查 name 是否在当前函数的 global 集合中"""
|
||||
if trans is None or name is None or trans._global_names is None:
|
||||
return 0
|
||||
for i in range(trans._global_name_count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + i * 8
|
||||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||||
entry: str = slot_ptr[0]
|
||||
if entry is not None:
|
||||
if string.strcmp(entry, name) == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def add_nonlocal_name(trans: HT.Translator | t.CPtr, name: str):
|
||||
"""添加一个 nonlocal 变量名"""
|
||||
if trans is None or name is None:
|
||||
return
|
||||
if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES:
|
||||
return
|
||||
if trans._nonlocal_names is None:
|
||||
return
|
||||
if is_nonlocal_name(trans, name) != 0:
|
||||
return
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8
|
||||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||||
slot_ptr[0] = name
|
||||
trans._nonlocal_name_count += 1
|
||||
trans._closure_env_count += 1
|
||||
|
||||
|
||||
def is_nonlocal_name(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""检查 name 是否在当前函数的 nonlocal 集合中"""
|
||||
if trans is None or name is None or trans._nonlocal_names is None:
|
||||
return 0
|
||||
for i in range(trans._nonlocal_name_count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
|
||||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||||
entry: str = slot_ptr[0]
|
||||
if entry is not None:
|
||||
if string.strcmp(entry, name) == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def get_nonlocal_index(trans: HT.Translator | t.CPtr, name: str) -> int:
|
||||
"""获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1"""
|
||||
if trans is None or name is None or trans._nonlocal_names is None:
|
||||
return -1
|
||||
for i in range(trans._nonlocal_name_count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
|
||||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||||
entry: str = slot_ptr[0]
|
||||
if entry is not None:
|
||||
if string.strcmp(entry, name) == 0:
|
||||
return i
|
||||
return -1
|
||||
|
||||
|
||||
def clear_scope_names(trans: HT.Translator | t.CPtr):
|
||||
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)"""
|
||||
if trans is None:
|
||||
return
|
||||
trans._global_name_count = 0
|
||||
trans._nonlocal_name_count = 0
|
||||
trans._closure_env_count = 0
|
||||
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,406 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesVar - 嵌套作用域符号表 + 变量管理
|
||||
#
|
||||
# 使用 Scope 链(Parent 指针)管理嵌套作用域,
|
||||
# 每个作用域包含一个 VarEntry 数组(扁平化,已验证可工作)。
|
||||
#
|
||||
# 作用域类型:
|
||||
# SCOPE_MODULE — 模块级(根作用域)
|
||||
# SCOPE_FUNCTION — 函数级
|
||||
# SCOPE_BLOCK — 块级(if/for/while,当前未使用块作用域)
|
||||
# ============================================================
|
||||
|
||||
# 作用域类型常量
|
||||
SCOPE_MODULE: t.CDefine = 0
|
||||
SCOPE_FUNCTION: t.CDefine = 1
|
||||
SCOPE_BLOCK: t.CDefine = 2
|
||||
|
||||
# 每个作用域最大变量数
|
||||
MAX_VARS: t.CDefine = 256
|
||||
|
||||
|
||||
# ============================================================
|
||||
# VarEntry - 变量表条目
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class VarEntry:
|
||||
"""变量表条目"""
|
||||
Name: t.CChar | t.CPtr
|
||||
Alloca: llvmlite.Value | t.CPtr
|
||||
Used: t.CInt
|
||||
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
|
||||
IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Scope - 作用域节点
|
||||
#
|
||||
# Parent 指向父作用域(None 表示根),
|
||||
# Vars 是 VarEntry 数组,VarCount 是当前变量数。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class Scope:
|
||||
"""作用域节点"""
|
||||
Parent: Scope | t.CPtr
|
||||
Vars: VarEntry | t.CPtr
|
||||
VarCount: t.CInt
|
||||
Kind: t.CInt
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SymbolTable - 嵌套作用域符号表
|
||||
#
|
||||
# Root 是模块级根作用域,Current 是当前作用域。
|
||||
# enter_scope/exit_scope 管理作用域栈。
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class SymbolTable:
|
||||
"""嵌套作用域符号表"""
|
||||
Pool: memhub.MemBuddy | t.CPtr
|
||||
Root: Scope | t.CPtr
|
||||
Current: Scope | t.CPtr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# init_vars — 分配并清零 VarEntry 数组
|
||||
# ============================================================
|
||||
def init_vars(pool: memhub.MemBuddy | t.CPtr) -> VarEntry | t.CPtr:
|
||||
"""分配并清零变量表数组"""
|
||||
size: t.CSizeT = MAX_VARS * VarEntry.__sizeof__()
|
||||
vars_ptr: VarEntry | t.CPtr = pool.alloc(size)
|
||||
if vars_ptr is not None:
|
||||
string.memset(vars_ptr, 0, size)
|
||||
return vars_ptr
|
||||
|
||||
|
||||
# ============================================================
|
||||
# find_var — 在变量表中按名称查找
|
||||
# ============================================================
|
||||
def find_var(vars_ptr: VarEntry | t.CPtr,
|
||||
var_count: int,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
"""在变量表中按名称查找"""
|
||||
if name is None or vars_ptr is None:
|
||||
return None
|
||||
entry_size: t.CSizeT = VarEntry.__sizeof__()
|
||||
for i in range(var_count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
|
||||
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry.Name is not None and entry.Used != 0:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
return entry.Alloca
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# find_var_entry — 在变量表中按名称查找,返回 VarEntry(含 AnnotTy)
|
||||
# ============================================================
|
||||
def find_var_entry(vars_ptr: VarEntry | t.CPtr,
|
||||
var_count: int,
|
||||
name: str) -> VarEntry | t.CPtr:
|
||||
"""在变量表中按名称查找,返回 VarEntry 或 None"""
|
||||
if name is None or vars_ptr is None:
|
||||
return None
|
||||
entry_size: t.CSizeT = VarEntry.__sizeof__()
|
||||
for i in range(var_count):
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + i * entry_size
|
||||
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry.Name is not None and entry.Used != 0:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
return entry
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lookup_var_entry — 从当前作用域逐级向上查找变量,返回 VarEntry
|
||||
# ============================================================
|
||||
def lookup_var_entry(symtab: SymbolTable | t.CPtr,
|
||||
name: str) -> VarEntry | t.CPtr:
|
||||
"""从当前作用域逐级向上查找变量,返回 VarEntry 或 None"""
|
||||
if symtab is None or name is None:
|
||||
return None
|
||||
scope: Scope | t.CPtr = symtab.Current
|
||||
while scope is not None:
|
||||
result: VarEntry | t.CPtr = find_var_entry(scope.Vars, scope.VarCount, name)
|
||||
if result is not None:
|
||||
return result
|
||||
scope = scope.Parent
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# set_var_annot_class_name — 设置变量的原始类型注解类名
|
||||
#
|
||||
# 在函数参数定义后调用,存储原始类型注解的类名。
|
||||
# 方法调用检测时,当 alloca 类型是 Ptr(i8)(联合类型简化),
|
||||
# 通过 AnnotClassName 查找实际结构体类型。
|
||||
# ============================================================
|
||||
def set_var_annot_class_name(symtab: SymbolTable | t.CPtr,
|
||||
name: str,
|
||||
class_name: str) -> int:
|
||||
"""设置变量的原始类型注解类名,返回 0=成功 / 1=失败"""
|
||||
if symtab is None or name is None:
|
||||
return 1
|
||||
entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name)
|
||||
if entry is None:
|
||||
return 1
|
||||
entry.AnnotClassName = class_name
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# set_var_ptr_element — 标记变量为"指针到 str/bytes"类型
|
||||
#
|
||||
# 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*,
|
||||
# 但下标访问应按 8 字节步长(i8** 语义),而非 1 字节步长(i8* 语义)。
|
||||
# 此标志在 HandlesAnnAssign 中根据注解形式设置。
|
||||
# ============================================================
|
||||
def set_var_ptr_element(symtab: SymbolTable | t.CPtr,
|
||||
name: str) -> int:
|
||||
"""标记变量为 ptr_element 类型,返回 0=成功 / 1=失败"""
|
||||
if symtab is None or name is None:
|
||||
return 1
|
||||
entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name)
|
||||
if entry is None:
|
||||
return 1
|
||||
entry.IsPtrElement = 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# add_var — 添加变量到变量表
|
||||
# ============================================================
|
||||
def add_var(vars_ptr: VarEntry | t.CPtr,
|
||||
var_count: int,
|
||||
name: str,
|
||||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||||
"""添加变量到变量表"""
|
||||
if name is None or alloca is None or vars_ptr is None:
|
||||
return 1
|
||||
if var_count >= MAX_VARS:
|
||||
return 1
|
||||
entry_size: t.CSizeT = VarEntry.__sizeof__()
|
||||
entry_addr: t.CUInt64T = t.CUInt64T(vars_ptr) + var_count * entry_size
|
||||
entry: VarEntry | t.CPtr = (VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
entry.Name = name
|
||||
entry.Alloca = alloca
|
||||
entry.Used = 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _alloca_at_entry - 在函数入口块生成 alloca(确保支配性)
|
||||
#
|
||||
# LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成,
|
||||
# 但在其他分支使用,会违反支配性(Instruction does not dominate all uses)。
|
||||
# 标准做法:所有 alloca 在函数入口块生成。
|
||||
#
|
||||
# 临时切换 builder.CurBlock 到入口块,生成 alloca,然后恢复。
|
||||
# ============================================================
|
||||
def _alloca_at_entry(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""在函数入口块生成 alloca,返回 alloca 值
|
||||
|
||||
使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca,
|
||||
确保所有 alloca 在入口块,避免支配性违规。
|
||||
"""
|
||||
if builder is None or ty is None:
|
||||
return None
|
||||
return llvmlite.build_alloca_at_entry(builder, ty)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# get_or_create_var — 查找或创建变量 alloca(旧版兼容)
|
||||
# ============================================================
|
||||
def get_or_create_var(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
vars_ptr: VarEntry | t.CPtr,
|
||||
var_count: int,
|
||||
name: str,
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""查找或创建变量 alloca"""
|
||||
existing: llvmlite.Value | t.CPtr = find_var(vars_ptr, var_count, name)
|
||||
if existing is not None:
|
||||
return existing
|
||||
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
|
||||
if alloca is None:
|
||||
return None
|
||||
if add_var(vars_ptr, var_count, name, alloca) != 0:
|
||||
return None
|
||||
return alloca
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _create_scope — 创建新作用域节点(内部辅助函数)
|
||||
# ============================================================
|
||||
def _create_scope(pool: memhub.MemBuddy | t.CPtr,
|
||||
parent: Scope | t.CPtr,
|
||||
kind: int) -> Scope | t.CPtr:
|
||||
"""创建并初始化作用域节点"""
|
||||
scope: Scope | t.CPtr = pool.alloc(Scope.__sizeof__())
|
||||
if scope is None:
|
||||
return None
|
||||
string.memset(scope, 0, Scope.__sizeof__())
|
||||
scope.Parent = parent
|
||||
scope.Vars = init_vars(pool)
|
||||
scope.VarCount = 0
|
||||
scope.Kind = kind
|
||||
if scope.Vars is None:
|
||||
return None
|
||||
return scope
|
||||
|
||||
|
||||
# ============================================================
|
||||
# init_symbol_table — 创建符号表(含模块级根作用域)
|
||||
# ============================================================
|
||||
def init_symbol_table(pool: memhub.MemBuddy | t.CPtr) -> SymbolTable | t.CPtr:
|
||||
"""创建并初始化符号表,包含模块级根作用域"""
|
||||
if pool is None:
|
||||
return None
|
||||
symtab: SymbolTable | t.CPtr = pool.alloc(SymbolTable.__sizeof__())
|
||||
if symtab is None:
|
||||
return None
|
||||
string.memset(symtab, 0, SymbolTable.__sizeof__())
|
||||
symtab.Pool = pool
|
||||
|
||||
# 创建根作用域(模块级)
|
||||
root: Scope | t.CPtr = _create_scope(pool, None, SCOPE_MODULE)
|
||||
if root is None:
|
||||
return None
|
||||
|
||||
symtab.Root = root
|
||||
symtab.Current = root
|
||||
return symtab
|
||||
|
||||
|
||||
# ============================================================
|
||||
# enter_scope — 进入新作用域
|
||||
# ============================================================
|
||||
def enter_scope(symtab: SymbolTable | t.CPtr,
|
||||
kind: int) -> Scope | t.CPtr:
|
||||
"""进入新作用域,返回新创建的作用域"""
|
||||
if symtab is None:
|
||||
return None
|
||||
pool: memhub.MemBuddy | t.CPtr = symtab.Pool
|
||||
scope: Scope | t.CPtr = _create_scope(pool, symtab.Current, kind)
|
||||
if scope is None:
|
||||
return None
|
||||
symtab.Current = scope
|
||||
return scope
|
||||
|
||||
|
||||
# ============================================================
|
||||
# exit_scope — 退出当前作用域
|
||||
# ============================================================
|
||||
def exit_scope(symtab: SymbolTable | t.CPtr):
|
||||
"""退出当前作用域,恢复到父作用域"""
|
||||
if symtab is not None and symtab.Current is not None:
|
||||
symtab.Current = symtab.Current.Parent
|
||||
|
||||
|
||||
# ============================================================
|
||||
# define_var — 在当前作用域定义变量
|
||||
# ============================================================
|
||||
def define_var(symtab: SymbolTable | t.CPtr,
|
||||
name: str,
|
||||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||||
"""在当前作用域定义变量,返回 0 成功"""
|
||||
if symtab is None or name is None or alloca is None:
|
||||
return 1
|
||||
scope: Scope | t.CPtr = symtab.Current
|
||||
if scope is None:
|
||||
return 1
|
||||
ret: int = add_var(scope.Vars, scope.VarCount, name, alloca)
|
||||
if ret == 0:
|
||||
scope.VarCount = scope.VarCount + 1
|
||||
return ret
|
||||
|
||||
|
||||
# ============================================================
|
||||
# define_module_var — 在模块作用域定义变量
|
||||
# ============================================================
|
||||
def define_module_var(symtab: SymbolTable | t.CPtr,
|
||||
name: str,
|
||||
alloca: llvmlite.Value | t.CPtr) -> int:
|
||||
"""在模块作用域定义变量,返回 0 成功"""
|
||||
if symtab is None or name is None or alloca is None:
|
||||
return 1
|
||||
scope: Scope | t.CPtr = symtab.Root
|
||||
if scope is None:
|
||||
return 1
|
||||
ret: int = add_var(scope.Vars, scope.VarCount, name, alloca)
|
||||
if ret == 0:
|
||||
scope.VarCount = scope.VarCount + 1
|
||||
return ret
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lookup_var — 从当前作用域逐级向上查找变量
|
||||
# ============================================================
|
||||
def lookup_var(symtab: SymbolTable | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
"""从当前作用域逐级向上查找变量,返回 alloca 或 None"""
|
||||
if symtab is None or name is None:
|
||||
return None
|
||||
scope: Scope | t.CPtr = symtab.Current
|
||||
while scope is not None:
|
||||
result: llvmlite.Value | t.CPtr = find_var(
|
||||
scope.Vars, scope.VarCount, name)
|
||||
if result is not None:
|
||||
return result
|
||||
scope = scope.Parent
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lookup_current — 仅在当前作用域查找变量
|
||||
# ============================================================
|
||||
def lookup_current(symtab: SymbolTable | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
"""仅在当前作用域查找变量"""
|
||||
if symtab is None or name is None:
|
||||
return None
|
||||
scope: Scope | t.CPtr = symtab.Current
|
||||
if scope is None:
|
||||
return None
|
||||
return find_var(scope.Vars, scope.VarCount, name)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# lookup_module_var — 在模块作用域查找变量
|
||||
# ============================================================
|
||||
def lookup_module_var(symtab: SymbolTable | t.CPtr,
|
||||
name: str) -> llvmlite.Value | t.CPtr:
|
||||
"""在模块作用域查找变量"""
|
||||
if symtab is None or name is None:
|
||||
return None
|
||||
scope: Scope | t.CPtr = symtab.Root
|
||||
if scope is None:
|
||||
return None
|
||||
return find_var(scope.Vars, scope.VarCount, name)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# get_or_create_sym — 查找或创建变量(在当前作用域)
|
||||
# ============================================================
|
||||
def get_or_create_sym(symtab: SymbolTable | t.CPtr,
|
||||
pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
name: str,
|
||||
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""查找或创建变量 alloca(在当前作用域)"""
|
||||
existing: llvmlite.Value | t.CPtr = lookup_current(symtab, name)
|
||||
if existing is not None:
|
||||
return existing
|
||||
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
|
||||
if alloca is None:
|
||||
return None
|
||||
define_var(symtab, name, alloca)
|
||||
return alloca
|
||||
@@ -1,130 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import ast
|
||||
import llvmlite
|
||||
import memhub
|
||||
import string
|
||||
import stdio
|
||||
import viperlib
|
||||
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.HandlesBody as HandlesBody
|
||||
|
||||
|
||||
# ============================================================
|
||||
# HandlesWhile - while 循环语句处理(Mixin 继承模式)
|
||||
#
|
||||
# 翻译 while 语句为 LLVM IR 控制流:
|
||||
# br label %cond
|
||||
# cond:
|
||||
# %t = <test>
|
||||
# %c = icmp ne i32 %t, 0
|
||||
# br i1 %c, label %body, label %end
|
||||
# body:
|
||||
# ... body ...
|
||||
# br label %cond
|
||||
# end:
|
||||
# ============================================================
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class WhileHandle(HandlesBase.Mixin):
|
||||
"""while 循环语句处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# Handle - 处理 while 语句,返回新增变量数
|
||||
# ============================================================
|
||||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 while 循环语句"""
|
||||
if node is None:
|
||||
return 0
|
||||
|
||||
trans: HT.Translator | t.CPtr = self.Trans
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||||
func: llvmlite.Function | t.CPtr = trans._cur_func
|
||||
|
||||
if builder is None or func is None:
|
||||
return 0
|
||||
|
||||
while_node: ast.While | t.CPtr = (ast.While | t.CPtr)(node)
|
||||
|
||||
# 1. 创建基本块: cond / body / end(使用 trans._label_counter,不与 SSA 名共享)
|
||||
cnt: int = trans._label_counter
|
||||
trans._label_counter = cnt + 1
|
||||
|
||||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt)
|
||||
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "while.body.%d", cnt)
|
||||
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
viperlib.snprintf(name_buf, 32, "while.end.%d", cnt)
|
||||
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||||
|
||||
# 2. 跳转到 cond 块
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# 3. cond 块: 求值条件,条件分支
|
||||
llvmlite.position_at_end(builder, cond_bb)
|
||||
cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, trans.Module, while_node.test,
|
||||
trans._funcs, trans._func_count, trans)
|
||||
if cond_val is None:
|
||||
cond_val = llvmlite.const_int32(pool, 0)
|
||||
|
||||
# Compare/Not 表达式已返回 i1,直接使用;其他类型与 0 比较
|
||||
cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty)
|
||||
if cond_bits == 1:
|
||||
cond_i1: llvmlite.Value | t.CPtr = cond_val
|
||||
else:
|
||||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
cond_i1 = llvmlite.build_icmp(
|
||||
builder, llvmlite.ICMP_NE, cond_val, zero)
|
||||
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
|
||||
|
||||
# 4. body 块: 翻译循环体,跳回 cond
|
||||
llvmlite.position_at_end(builder, body_bb)
|
||||
|
||||
# 保存旧循环上下文,设置 break/continue 目标
|
||||
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
|
||||
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
|
||||
trans._break_bb = end_bb
|
||||
trans._continue_bb = cond_bb
|
||||
|
||||
body: list[ast.AST | t.CPtr] | t.CPtr = while_node.children
|
||||
if body is not None:
|
||||
body_count: t.CSizeT = body.__len__()
|
||||
for bi in range(body_count):
|
||||
stmt: ast.AST | t.CPtr = body.get(bi)
|
||||
if stmt is not None:
|
||||
HandlesBody.translate_stmt(trans, stmt)
|
||||
|
||||
# 恢复旧循环上下文
|
||||
trans._break_bb = old_break
|
||||
trans._continue_bb = old_continue
|
||||
|
||||
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
|
||||
llvmlite.build_br(builder, cond_bb)
|
||||
|
||||
# 5. 定位到 end 块
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# NewWhileHandle - 工厂函数
|
||||
# ============================================================
|
||||
def NewWhileHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> WhileHandle | t.CPtr:
|
||||
h: WhileHandle | t.CPtr = pool.alloc(WhileHandle.__sizeof__())
|
||||
if h is None:
|
||||
return None
|
||||
string.memset(h, 0, WhileHandle.__sizeof__())
|
||||
h.Trans = trans
|
||||
return h
|
||||
@@ -1,23 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
# Handles 模块(绝对导入,Viper 兼容)
|
||||
# 参考 Python 版 TransPyC lib/core/Handles 的细粒度拆分
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesExprOps as HandlesExprOps
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesAssign as HandlesAssign
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
import lib.core.Handles.HandlesReturn as HandlesReturn
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.Handles.HandlesBody as HandlesBody
|
||||
import lib.core.Handles.HandlesIf as HandlesIf
|
||||
import lib.core.Handles.HandlesWhile as HandlesWhile
|
||||
import lib.core.Handles.HandlesFor as HandlesFor
|
||||
import lib.core.Handles.HandlesAugAssign as HandlesAugAssign
|
||||
import lib.core.Handles.HandlesMain as HandlesMain
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
@@ -1,365 +0,0 @@
|
||||
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 w32.fileio as fileio
|
||||
import hashlib
|
||||
import viperlib
|
||||
import lib.core.VLogger as VLogger
|
||||
|
||||
|
||||
# ============================================================
|
||||
# IncludesScanner - includes 目录递归扫描
|
||||
#
|
||||
# 递归扫描 includes 目录,收集所有 .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 = 256
|
||||
|
||||
|
||||
# ============================================================
|
||||
# FileEntry - 文件条目(路径 + SHA1)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class FileEntry:
|
||||
"""扫描到的文件条目"""
|
||||
Path: str # 文件绝对路径
|
||||
Sha1: str # SHA1 前16字符(16字节+null)
|
||||
RelPath: str # 相对于 includes 根目录的路径
|
||||
ModuleName: str # 模块名(如 "ast.parser")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 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) -> int:
|
||||
"""添加文件条目到扫描结果,返回 0 成功"""
|
||||
if result is None or pool is None:
|
||||
return 1
|
||||
if result.Count >= result.Capacity:
|
||||
return 1
|
||||
|
||||
# 计算模块名:rel_path 中的 / 替换为 .,去掉 .py 扩展名
|
||||
rel_len: t.CSizeT = string.strlen(rel_path)
|
||||
mod_buf: str = stdlib.malloc(rel_len + 1)
|
||||
if mod_buf is None:
|
||||
return 1
|
||||
string.strcpy(mod_buf, rel_path)
|
||||
# 替换 / 为 .
|
||||
for i in range(rel_len):
|
||||
ch: t.CChar = mod_buf[i]
|
||||
if ch == '/' or ch == '\\':
|
||||
mod_buf[i] = '.'
|
||||
# 去掉 .py 扩展名
|
||||
if rel_len >= 3:
|
||||
if mod_buf[rel_len - 3] == '.' and mod_buf[rel_len - 2] == 'p' and mod_buf[rel_len - 1] == 'y':
|
||||
mod_buf[rel_len - 3] = '\0'
|
||||
|
||||
# 获取条目地址
|
||||
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(rel_len + 1)
|
||||
if rel_buf is None:
|
||||
return 1
|
||||
string.strcpy(rel_buf, rel_path)
|
||||
entry.RelPath = rel_buf
|
||||
|
||||
# 复制模块名
|
||||
entry.ModuleName = mod_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
|
||||
|
||||
# 打开文件
|
||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
return None
|
||||
|
||||
# 分配读取缓冲区(128KB,足够大多数 .py 文件)
|
||||
# 使用 stdlib.malloc 避免 mbuddy 池耗尽(每文件 128KB,60+ 文件会耗尽 16MB 池)
|
||||
BUF_SIZE: t.CSizeT = 131072
|
||||
buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
if buf is None:
|
||||
f.close()
|
||||
return None
|
||||
|
||||
# 读取文件内容
|
||||
bytes_read: t.CInt64T = f.read_all(buf, BUF_SIZE)
|
||||
f.close()
|
||||
if bytes_read <= 0:
|
||||
return None
|
||||
|
||||
# 原地去除 \r(CRLF → LF),与 Projectrans.py 文本模式读取一致
|
||||
write_pos: t.CSizeT = 0
|
||||
read_pos: t.CSizeT = 0
|
||||
while read_pos < bytes_read:
|
||||
ch: t.CChar = buf[read_pos]
|
||||
if ch != '\r':
|
||||
buf[write_pos] = ch
|
||||
write_pos += 1
|
||||
read_pos += 1
|
||||
|
||||
# 添加 null 终止符
|
||||
buf[write_pos] = 0
|
||||
|
||||
# 计算 SHA1
|
||||
ctx: hashlib.sha1 | t.CPtr = hashlib.sha1()
|
||||
if ctx is None:
|
||||
return None
|
||||
ctx.update(buf)
|
||||
|
||||
digest: bytes = stdlib.malloc(hashlib.SHA1_DIGEST_LEN)
|
||||
if digest is None:
|
||||
return None
|
||||
ctx.final(digest)
|
||||
|
||||
# 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符)
|
||||
hex_buf: str = stdlib.malloc(17)
|
||||
if hex_buf is None:
|
||||
return None
|
||||
for i in range(8):
|
||||
hi: int = (digest[i] >> 4) & 0xF
|
||||
lo: int = digest[i] & 0xF
|
||||
if hi < 10:
|
||||
hex_buf[i * 2] = '0' + hi
|
||||
else:
|
||||
hex_buf[i * 2] = 'a' + (hi - 10)
|
||||
if lo < 10:
|
||||
hex_buf[i * 2 + 1] = '0' + lo
|
||||
else:
|
||||
hex_buf[i * 2 + 1] = 'a' + (lo - 10)
|
||||
hex_buf[16] = '\0'
|
||||
return hex_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# scan_directory_recursive - 递归扫描目录
|
||||
#
|
||||
# 使用 FindFirstFileA/FindNextFileA 遍历目录树,
|
||||
# 对每个 .py 文件计算 SHA1 并添加到结果中。
|
||||
# ============================================================
|
||||
def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
root_dir: str,
|
||||
rel_prefix: str,
|
||||
result: ScanResult | t.CPtr) -> int:
|
||||
"""递归扫描目录,收集 .py 文件"""
|
||||
if pool is None or root_dir is None or result is None:
|
||||
return 1
|
||||
|
||||
# 构造搜索模式: 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 = stdlib.malloc(root_len + fname_len + 2)
|
||||
if full_path is None:
|
||||
break
|
||||
viperlib.snprintf(full_path, root_len + fname_len + 2, "%s/%s", root_dir, fname)
|
||||
|
||||
# 构造相对路径
|
||||
prefix_len: t.CSizeT = 0
|
||||
if rel_prefix is not None:
|
||||
prefix_len = string.strlen(rel_prefix)
|
||||
rel_path: bytes = stdlib.malloc(prefix_len + fname_len + 2)
|
||||
if rel_path is None:
|
||||
break
|
||||
if rel_prefix is not None and prefix_len > 0:
|
||||
viperlib.snprintf(rel_path, prefix_len + fname_len + 2, "%s/%s", rel_prefix, fname)
|
||||
else:
|
||||
string.strcpy(rel_path, fname)
|
||||
|
||||
if is_dir != 0:
|
||||
# 递归扫描子目录
|
||||
scan_directory_recursive(pool, full_path, rel_path, result)
|
||||
else:
|
||||
# 检查是否为 .py 文件
|
||||
is_py: int = 0
|
||||
if fname_len >= 3:
|
||||
if fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y':
|
||||
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)
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "扫描: %s -> %s", rel_path, sha1)
|
||||
VLogger.debug(fb, "scan")
|
||||
|
||||
# 继续搜索下一个文件
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
|
||||
win32file.FindClose(handle)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# scan_includes - 扫描 includes 目录入口
|
||||
#
|
||||
# 扫描指定的 includes 目录,返回所有 .py 文件的路径和 SHA1。
|
||||
# ============================================================
|
||||
def scan_includes(pool: memhub.MemBuddy | t.CPtr,
|
||||
includes_dir: str) -> ScanResult | t.CPtr:
|
||||
"""扫描 includes 目录,返回所有 .py 文件的扫描结果"""
|
||||
if pool is None or includes_dir is None:
|
||||
return None
|
||||
|
||||
result: ScanResult | t.CPtr = create_scan_result(pool)
|
||||
if result is None:
|
||||
return None
|
||||
|
||||
scan_directory_recursive(pool, includes_dir, None, result)
|
||||
|
||||
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 entry.ModuleName == module_name:
|
||||
return entry
|
||||
return None
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,953 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import sys
|
||||
import ast
|
||||
import llvmlite
|
||||
import subprocess
|
||||
import argparse
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.BuildPipeline as BuildPipeline
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
|
||||
# 源代码缓冲区大小(1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
|
||||
# 最大源文件数(递归扫描子目录后文件数增多,增大到 64)
|
||||
MAX_SRC_FILES: t.CDefine = 64
|
||||
|
||||
# 全局栈金丝雀(避免局部变量改变栈布局)
|
||||
_g_canary: t.CUInt32T
|
||||
|
||||
|
||||
@t.NoVTable
|
||||
class SrcFileEntry:
|
||||
"""源文件条目"""
|
||||
Path: str # 完整路径
|
||||
Sha1: str # SHA1 前16字符
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _ScanDirForPyFiles - 递归扫描目录,收集 .py 文件到 entries
|
||||
#
|
||||
# 替代旧的非递归 FindFirstFileA(dir/*.py) 扫描,支持子目录
|
||||
# (如 App/lib/core/Handles/)。遇到目录递归扫描,遇到 .py
|
||||
# 文件读取内容、计算 SHA1、加入 entries。
|
||||
#
|
||||
# Args:
|
||||
# mb: 内存池
|
||||
# dir_path: 当前扫描目录
|
||||
# entries: SrcFileEntry 数组
|
||||
# entry_size: 单个条目大小(SrcFileEntry.__sizeof__())
|
||||
# file_count: 当前已收集的文件数
|
||||
# max_files: 最大文件数
|
||||
#
|
||||
# Returns:
|
||||
# 新的 file_count
|
||||
# ============================================================
|
||||
def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
dir_path: str,
|
||||
entries: SrcFileEntry | t.CPtr,
|
||||
entry_size: t.CSizeT,
|
||||
file_count: int, max_files: int) -> int:
|
||||
"""递归扫描目录,收集 .py 文件到 entries,返回新的 file_count"""
|
||||
if dir_path is None or entries is None:
|
||||
return file_count
|
||||
if file_count >= max_files:
|
||||
return file_count
|
||||
|
||||
dir_len: t.CSizeT = string.strlen(dir_path)
|
||||
pattern: bytes = stdlib.malloc(dir_len + 16)
|
||||
if pattern is None:
|
||||
return file_count
|
||||
viperlib.snprintf(pattern, dir_len + 16, "%s/*", dir_path)
|
||||
|
||||
find_data_size: t.CSizeT = w32.win32file.WIN32_FIND_DATAA.__sizeof__()
|
||||
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(find_data_size + 16)
|
||||
if find_data is None:
|
||||
stdlib.free(pattern)
|
||||
return file_count
|
||||
string.memset(find_data, 0, find_data_size + 16)
|
||||
|
||||
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 file_count
|
||||
|
||||
while True:
|
||||
fname: str = find_data.cFileName
|
||||
if fname is not None:
|
||||
fname_len: t.CSizeT = string.strlen(fname)
|
||||
if fname_len > 0:
|
||||
# 跳过 . 和 ..
|
||||
is_dot: int = 0
|
||||
if fname_len == 1 and fname[0] == '.':
|
||||
is_dot = 1
|
||||
elif fname_len == 2 and fname[0] == '.' and fname[1] == '.':
|
||||
is_dot = 1
|
||||
if is_dot == 0:
|
||||
# 检查是否是目录
|
||||
attrs: ULONG = find_data.dwFileAttributes
|
||||
is_dir: int = 0
|
||||
if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
|
||||
is_dir = 1
|
||||
if is_dir != 0:
|
||||
# 递归扫描子目录
|
||||
sub_dir: bytes = stdlib.malloc(dir_len + fname_len + 2)
|
||||
if sub_dir is not None:
|
||||
viperlib.snprintf(sub_dir, dir_len + fname_len + 2, "%s/%s", dir_path, fname)
|
||||
file_count = _ScanDirForPyFiles(mb, sub_dir, entries, entry_size, file_count, max_files)
|
||||
stdlib.free(sub_dir)
|
||||
else:
|
||||
# 检查是否是 .py 文件
|
||||
if fname_len > 3:
|
||||
if fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y':
|
||||
if file_count < max_files:
|
||||
full_path: bytes = stdlib.malloc(dir_len + fname_len + 2)
|
||||
if full_path is not None:
|
||||
viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", dir_path, fname)
|
||||
sf: fileio.File | t.CPtr = fileio.File(full_path, fileio.MODE.R)
|
||||
if not sf.closed:
|
||||
sbuf: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
if sbuf is not None:
|
||||
br: LONG = sf.read_all(sbuf, SRC_BUF_SIZE)
|
||||
sf.close()
|
||||
if br > 0:
|
||||
if br < SRC_BUF_SIZE:
|
||||
sbuf[br] = 0
|
||||
else:
|
||||
sbuf[SRC_BUF_SIZE - 1] = 0
|
||||
sha1_val: str = Utils.compute_sha1(mb, sbuf)
|
||||
if sha1_val is not None:
|
||||
ea: t.CUInt64T = t.CUInt64T(entries) + file_count * entry_size
|
||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||
if ent is not None:
|
||||
ent.Path = full_path
|
||||
ent.Sha1 = sha1_val
|
||||
file_count += 1
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "%s (sha1=%s)", fname, sha1_val)
|
||||
VLogger.info(fb, "project")
|
||||
stdlib.free(sbuf)
|
||||
# full_path 不释放:ent.Path 引用它
|
||||
|
||||
if w32.win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
|
||||
w32.win32file.FindClose(handle)
|
||||
stdlib.free(pattern)
|
||||
stdlib.free(find_data)
|
||||
return file_count
|
||||
|
||||
|
||||
def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
source_dir: str, temp_dir: str, output_dir: str,
|
||||
cc_cmd: str, cc_flags: str,
|
||||
linker_cmd: str, linker_flags: str, linker_output: str,
|
||||
includes_binary_dir: str,
|
||||
includes_dir: str,
|
||||
do_phase1: int, do_phase2: int,
|
||||
log: VLogger.Logger | t.CPtr,
|
||||
args: argparse.ParsedArgs | t.CPtr) -> int:
|
||||
"""多文件项目编译
|
||||
|
||||
Returns: 0 成功,非 0 失败
|
||||
"""
|
||||
if source_dir is None:
|
||||
VLogger.error("source_dir 为空", "project")
|
||||
return 1
|
||||
|
||||
# === 栈金丝雀检查(全局变量,不影响栈布局)===
|
||||
_g_canary = 305419896
|
||||
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir)
|
||||
VLogger.info(fb, "project")
|
||||
|
||||
# === 1. 递归扫描 source_dir 下的 .py 文件(包括子目录)===
|
||||
entry_size: t.CSizeT = SrcFileEntry.__sizeof__()
|
||||
entries: SrcFileEntry | t.CPtr = stdlib.malloc(MAX_SRC_FILES * entry_size)
|
||||
if entries is None:
|
||||
return 1
|
||||
string.memset(entries, 0, MAX_SRC_FILES * entry_size)
|
||||
|
||||
file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES)
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "共 %d 个源文件", file_count)
|
||||
VLogger.info(fb, "project")
|
||||
|
||||
if file_count == 0:
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
|
||||
# 初始化 AST 表
|
||||
ast._init_tables(mb)
|
||||
|
||||
# 确保 temp/output 目录存在
|
||||
BuildPipeline.ensure_dir(temp_dir)
|
||||
BuildPipeline.ensure_dir(output_dir)
|
||||
|
||||
# === 0.5 扫描 includes 目录填充 Sha1Store(消除 Phase1 依赖)===
|
||||
# Phase2 不依赖 Phase1 的副作用:如果 Sha1Store 为空(Phase1 未运行或提前返回),
|
||||
# 自行扫描 includes 目录并填充 Sha1Store,确保后续"编译缺失 includes"逻辑能正常工作
|
||||
if includes_dir is not None:
|
||||
if StubMerger.GetSha1StoreCount() == 0:
|
||||
inc_scan_result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
|
||||
if inc_scan_result is not None:
|
||||
inc_filled: int = StubMerger.PopulateSha1MapStore(inc_scan_result)
|
||||
fb_inc: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_inc is not None:
|
||||
viperlib.snprintf(fb_inc, 1024, "Phase2 自主填充 includes Sha1Store: %d 个", inc_filled)
|
||||
VLogger.info(fb_inc, "project")
|
||||
|
||||
# 追加 App 源文件 SHA1 到 _sha1_map.txt(人类可读输出,程序内部不读取此文件)
|
||||
# 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.py)
|
||||
# 同步追加到内存存储器(AppendToSha1MapStore,供跨模块 CDefine 查找)
|
||||
td_len_am: t.CSizeT = string.strlen(temp_dir)
|
||||
src_dir_len_am: t.CSizeT = string.strlen(source_dir)
|
||||
map_path_am: bytes = stdlib.malloc(td_len_am + 32)
|
||||
if map_path_am is not None:
|
||||
viperlib.snprintf(map_path_am, td_len_am + 32, "%s/_sha1_map.txt", temp_dir)
|
||||
mf: fileio.File | t.CPtr = fileio.File(map_path_am, fileio.MODE.A)
|
||||
line_am: bytes = stdlib.malloc(512)
|
||||
# 先遍历一次填充内存存储器(不依赖文件 I/O),再写入 _sha1_map.txt
|
||||
app_filled: int = 0
|
||||
for i in range(file_count):
|
||||
ea_am: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent_am: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_am, t.CPtr))
|
||||
if ent_am is None or ent_am.Path is None or ent_am.Sha1 is None:
|
||||
continue
|
||||
# 计算相对路径(去除 source_dir 前缀,保留目录结构)
|
||||
p_str: str = ent_am.Path
|
||||
p_len: t.CSizeT = string.strlen(p_str)
|
||||
rel_path_am: str = p_str
|
||||
if p_len > src_dir_len_am + 1:
|
||||
if string.strncmp(p_str, source_dir, src_dir_len_am) == 0:
|
||||
rel_path_am = p_str + src_dir_len_am + 1
|
||||
# 同步追加到内存存储器(供跨模块 CDefine 查找)
|
||||
# rel_path_am 格式如 "lib/core/StubMerger.py",与 _sha1_map.txt 一致
|
||||
if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) == 0:
|
||||
app_filled += 1
|
||||
# 写入 _sha1_map.txt(人类可读输出)
|
||||
if not mf.closed and line_am is not None:
|
||||
viperlib.snprintf(line_am, 512, "%s:%s\n", ent_am.Sha1, rel_path_am)
|
||||
ll_am: t.CSizeT = string.strlen(line_am)
|
||||
mf.write(line_am, ll_am)
|
||||
if line_am is not None:
|
||||
stdlib.free(line_am)
|
||||
if not mf.closed:
|
||||
mf.close()
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "已追加 %d 个 App 文件到 _sha1_map.txt 和内存存储器", app_filled)
|
||||
VLogger.info(fb, "project")
|
||||
stdlib.free(map_path_am)
|
||||
|
||||
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
|
||||
td_len_pb: t.CSizeT = string.strlen(temp_dir)
|
||||
pb_sha1_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||||
pb_mod_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||||
pb_inc_count: int = 0
|
||||
if pb_sha1_arr is not None and pb_mod_arr is not None:
|
||||
pb_inc_count = StubMerger._BuildIncludesSha1Map(temp_dir, td_len_pb, pb_sha1_arr, pb_mod_arr)
|
||||
# 追加用户源文件的 (模块名, SHA1) 到全局映射
|
||||
# 使跨模块方法调用能通过 from_imports + _lookup_module_sha1 找到正确的 SHA1
|
||||
if pb_sha1_arr is not None and pb_mod_arr is not None:
|
||||
src_dir_len_us: t.CSizeT = string.strlen(source_dir)
|
||||
for i in range(file_count):
|
||||
ea_us: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent_us: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_us, t.CPtr))
|
||||
if ent_us is None or ent_us.Path is None or ent_us.Sha1 is None:
|
||||
continue
|
||||
if pb_inc_count >= StubMerger.MAX_INCLUDES:
|
||||
break
|
||||
# 计算相对路径并转换为点分模块名(保留完整包路径)
|
||||
path_str: str = ent_us.Path
|
||||
path_len_us: t.CSizeT = string.strlen(path_str)
|
||||
rel_path_us: str = path_str
|
||||
if path_len_us > src_dir_len_us + 1:
|
||||
if string.strncmp(path_str, source_dir, src_dir_len_us) == 0:
|
||||
rel_path_us = path_str + src_dir_len_us + 1
|
||||
# 使用 _PathToModuleName 转换为点分模块名(处理 __init__.py → 包名)
|
||||
mod_name_us: str = StubMerger._PathToModuleName(rel_path_us)
|
||||
if mod_name_us is None:
|
||||
continue
|
||||
# 写入模块名
|
||||
mod_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 64
|
||||
mn_len_us: t.CSizeT = string.strlen(mod_name_us)
|
||||
if mn_len_us >= 64:
|
||||
string.strncpy(pb_mod_arr + mod_idx, mod_name_us, 63)
|
||||
pb_mod_arr[mod_idx + 63] = '\0'
|
||||
else:
|
||||
string.strcpy(pb_mod_arr + mod_idx, mod_name_us)
|
||||
stdlib.free(mod_name_us)
|
||||
# 写入 SHA1
|
||||
sha1_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 17
|
||||
string.strcpy(pb_sha1_arr + sha1_idx, ent_us.Sha1)
|
||||
pb_inc_count += 1
|
||||
HandlesExprCall.set_module_sha1_map(pb_sha1_arr, pb_mod_arr, pb_inc_count)
|
||||
|
||||
|
||||
# === 2. Phase A: 为每个文件生成 stub + text ===
|
||||
# app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔)
|
||||
# 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist,实现按需编译
|
||||
# 声明在 if 块外,确保 Phase B+ 和清理代码能访问
|
||||
APP_DEPS_BUF_SIZE: t.CSizeT = 8192
|
||||
app_deps_buf: bytes = None
|
||||
app_deps_len: t.CSizeT = 0
|
||||
if do_phase1 != 0:
|
||||
if log is not None:
|
||||
log.banner("Phase A: 生成 stub + text")
|
||||
|
||||
# === Phase A-pre-inc: includes 预注册 struct + 依赖填充 ===
|
||||
# 必须在 App 源文件预注册之前执行:App 源文件(strict_mode=1)可能继承
|
||||
# 或引用 includes 中的 struct(如 ast.AST)。若 includes struct 未注册,
|
||||
# App 源文件翻译会失败 → .obj 缺失 → undefined reference。
|
||||
# 同时填充 PopulateIncludesDeps,供 Phase B+ 的 _BuildReachableSha1Set 使用。
|
||||
# 多遍扫描:解决跨文件继承问题(如 Constant(AST) 在 AST 未注册时被跳过)。
|
||||
if includes_dir is not None and includes_binary_dir is not None:
|
||||
store_count_inc_pre: int = StubMerger.GetSha1StoreCount()
|
||||
if store_count_inc_pre > 0:
|
||||
store_sha1_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
|
||||
store_rel_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||||
inc_dir_len_pre: t.CSizeT = string.strlen(includes_dir)
|
||||
deps_filled_pre: int = 0
|
||||
PHASE_A_INC_MAX_PASSES: t.CInt = 3
|
||||
for pass_inc_i in range(PHASE_A_INC_MAX_PASSES):
|
||||
struct_count_before_inc: int = HandlesStruct.get_struct_count()
|
||||
for si_inc in range(store_count_inc_pre):
|
||||
inc_sha1_pre: str = store_sha1_inc_pre + t.CSizeT(si_inc) * 17
|
||||
inc_rel_pre: str = store_rel_inc_pre + t.CSizeT(si_inc) * StubMerger.MAX_REL_PATH_LEN
|
||||
if inc_rel_pre is None or inc_rel_pre[0] == '\0':
|
||||
continue
|
||||
rel_len_pre: t.CSizeT = string.strlen(inc_rel_pre)
|
||||
full_path_pre: bytes = stdlib.malloc(inc_dir_len_pre + rel_len_pre + 2)
|
||||
if full_path_pre is None:
|
||||
continue
|
||||
viperlib.snprintf(full_path_pre, inc_dir_len_pre + rel_len_pre + 2,
|
||||
"%s/%s", includes_dir, inc_rel_pre)
|
||||
pkg_inc_pre: str = HandlesImports.compute_package_from_relpath(mb, inc_rel_pre)
|
||||
tr_inc_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(
|
||||
mb, full_path_pre, inc_sha1_pre, pkg_inc_pre, 1)
|
||||
stdlib.free(full_path_pre)
|
||||
if tr_inc_pre is not None:
|
||||
# 依赖填充只在第一遍执行(PopulateIncludesDeps 内部有去重)
|
||||
if pass_inc_i == 0:
|
||||
if tr_inc_pre._imported_modules is not None:
|
||||
if StubMerger.PopulateIncludesDeps(inc_sha1_pre, tr_inc_pre._imported_modules) == 0:
|
||||
deps_filled_pre = deps_filled_pre + 1
|
||||
struct_count_after_inc: int = HandlesStruct.get_struct_count()
|
||||
# 收敛检查:本遍没有新结构体注册 → 所有类已注册
|
||||
if struct_count_after_inc == struct_count_before_inc:
|
||||
break
|
||||
fb_inc_pre: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_inc_pre is not None:
|
||||
viperlib.snprintf(fb_inc_pre, 1024, "includes 预注册 + 依赖填充: %d/%d", deps_filled_pre, store_count_inc_pre)
|
||||
VLogger.info(fb_inc_pre, "prePhaseA")
|
||||
|
||||
# === Phase A-pre: 预注册所有源文件的 struct/enum/union ===
|
||||
# 解决循环引用问题:circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义
|
||||
# 仅注册 struct/enum/union(declare_only=1),不翻译方法体
|
||||
# 多遍扫描:解决跨文件继承的字母序问题(如 HandlesAnnAssign.py 在 HandlesBase.py 之前,
|
||||
# AnnAssignHandle 继承 Mixin 时 Mixin 未注册)。每遍注册新类后,下一遍子类可继承。
|
||||
VLogger.info("预注册 struct/enum/union...", "PhaseA")
|
||||
src_dir_len_pre: t.CSizeT = string.strlen(source_dir)
|
||||
PHASE_A_PRE_MAX_PASSES: t.CInt = 3
|
||||
for pass_i in range(PHASE_A_PRE_MAX_PASSES):
|
||||
struct_count_before: int = HandlesStruct.get_struct_count()
|
||||
for i in range(file_count):
|
||||
ea_pre: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent_pre: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pre, t.CPtr))
|
||||
if ent_pre is None or ent_pre.Path is None:
|
||||
continue
|
||||
pkg_pre: str = None
|
||||
if string.strlen(ent_pre.Path) > src_dir_len_pre + 1:
|
||||
rel_path_pre: str = ent_pre.Path + src_dir_len_pre + 1
|
||||
pkg_pre = HandlesImports.compute_package_from_relpath(mb, rel_path_pre)
|
||||
tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1)
|
||||
if tr_pre is None:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path)
|
||||
VLogger.warning(fb, "PhaseA")
|
||||
struct_count_after: int = HandlesStruct.get_struct_count()
|
||||
# 收敛检查:本遍没有新结构体注册 → 所有类已注册
|
||||
if struct_count_after == struct_count_before:
|
||||
break
|
||||
VLogger.info("预注册完成", "PhaseA")
|
||||
|
||||
PHASE_A_IR_SIZE: t.CSizeT = 1048576
|
||||
td_len_pa: t.CSizeT = string.strlen(temp_dir)
|
||||
|
||||
# app_deps_buf: 收集所有 App 源文件的直接依赖模块名(空格分隔)
|
||||
# 供 Phase B+ 的 _BuildReachableSha1Set 作为初始 worklist 使用
|
||||
# 声明已在 if 块外,此处仅赋值
|
||||
app_deps_buf = stdlib.malloc(APP_DEPS_BUF_SIZE)
|
||||
app_deps_len = 0
|
||||
if app_deps_buf is not None:
|
||||
app_deps_buf[0] = '\0'
|
||||
|
||||
for i in range(file_count):
|
||||
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||
if ent is None or ent.Path is None:
|
||||
continue
|
||||
# 计算源文件的包名(相对 source_dir 的目录部分)
|
||||
src_dir_len_pa: t.CSizeT = string.strlen(source_dir)
|
||||
pkg_pa: str = None
|
||||
if string.strlen(ent.Path) > src_dir_len_pa + 1:
|
||||
rel_path_pa: str = ent.Path + src_dir_len_pa + 1
|
||||
pkg_pa = HandlesImports.compute_package_from_relpath(mb, rel_path_pa)
|
||||
tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa)
|
||||
if tr_a is None:
|
||||
continue
|
||||
|
||||
# dump stub IR (declarations only)
|
||||
stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||
if stub_buf_a is None:
|
||||
continue
|
||||
tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB)
|
||||
stub_len_a: t.CSizeT = string.strlen(stub_buf_a)
|
||||
|
||||
# save stub.ll (切片路径: temp_dir/{sha1前缀}/{sha1}.stub.ll)
|
||||
stub_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "stub.ll")
|
||||
if stub_path_a is not None:
|
||||
sf_a: fileio.File | t.CPtr = fileio.File(stub_path_a, fileio.MODE.W)
|
||||
if not sf_a.closed:
|
||||
sf_a.write(stub_buf_a, stub_len_a)
|
||||
sf_a.close()
|
||||
stdlib.free(stub_path_a)
|
||||
stdlib.free(stub_buf_a)
|
||||
|
||||
# dump text IR (definitions only)
|
||||
text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||
if text_buf_a is None:
|
||||
continue
|
||||
tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
||||
text_len_a: t.CSizeT = string.strlen(text_buf_a)
|
||||
|
||||
# save text.ll (切片路径)
|
||||
text_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "text.ll")
|
||||
if text_path_a is not None:
|
||||
tf_a: fileio.File | t.CPtr = fileio.File(text_path_a, fileio.MODE.W)
|
||||
if not tf_a.closed:
|
||||
tf_a.write(text_buf_a, text_len_a)
|
||||
tf_a.close()
|
||||
stdlib.free(text_path_a)
|
||||
stdlib.free(text_buf_a)
|
||||
|
||||
# save dependencies (_imported_modules) for Phase B (切片路径)
|
||||
deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "deps.txt")
|
||||
if deps_path_a is not None:
|
||||
df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W)
|
||||
if not df_a.closed:
|
||||
if tr_a._imported_modules is not None:
|
||||
dl_a: t.CSizeT = string.strlen(tr_a._imported_modules)
|
||||
df_a.write(tr_a._imported_modules, dl_a)
|
||||
df_a.close()
|
||||
stdlib.free(deps_path_a)
|
||||
|
||||
# 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)
|
||||
if tr_a._imported_modules is not None and app_deps_buf is not None:
|
||||
im_len_a: t.CSizeT = string.strlen(tr_a._imported_modules)
|
||||
if im_len_a > 0 and app_deps_len + im_len_a + 1 < APP_DEPS_BUF_SIZE:
|
||||
if app_deps_len > 0:
|
||||
app_deps_buf[app_deps_len] = ' '
|
||||
app_deps_len = app_deps_len + 1
|
||||
string.strcpy(app_deps_buf + app_deps_len, tr_a._imported_modules)
|
||||
app_deps_len = app_deps_len + im_len_a
|
||||
app_deps_buf[app_deps_len] = '\0'
|
||||
|
||||
if do_phase2 == 0:
|
||||
VLogger.info("Phase A 完成(仅 stub 生成)", "project")
|
||||
if app_deps_buf is not None:
|
||||
stdlib.free(app_deps_buf)
|
||||
stdlib.free(entries)
|
||||
return 0
|
||||
|
||||
# === 3. Phase B: 编译每个文件为 .obj ===
|
||||
if do_phase2 != 0:
|
||||
if log is not None:
|
||||
log.banner("Phase B: 编译 .obj")
|
||||
|
||||
# 收集 .obj 路径(增大到 64KB,避免 includes .obj 路径溢出导致链接丢失符号)
|
||||
# reachable_set/reachable_count: Phase B+ 填充,Phase C 用于按需链接
|
||||
reachable_set: bytes = None
|
||||
reachable_count: int = 0
|
||||
OBJ_PATHS_SIZE: t.CSizeT = 65536
|
||||
obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE)
|
||||
if obj_paths is None:
|
||||
return 1
|
||||
obj_paths[0] = '\0'
|
||||
obj_pos: t.CSizeT = 0
|
||||
# main_obj_path: 存放定义了用户 main 的 .obj 路径(链接时放在最前面,
|
||||
# 避免 --allow-multiple-definition 选择了其他模块的 wrapper main)
|
||||
main_obj_path: bytes = stdlib.malloc(512)
|
||||
if main_obj_path is None:
|
||||
return 1
|
||||
main_obj_path[0] = '\0'
|
||||
compiled_count: int = 0
|
||||
|
||||
# 组合 IR 缓冲区大小(4MB,足够容纳本地 stub + 所有依赖 stub + 本地 text)
|
||||
COMBINED_IR_SIZE: t.CSizeT = 4194304
|
||||
|
||||
for i in range(file_count):
|
||||
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||
if ent is None or ent.Path is None or ent.Sha1 is None:
|
||||
continue
|
||||
# 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR
|
||||
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
||||
if combined_ir is None:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
continue
|
||||
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
|
||||
if combined_len == 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", ent.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
stdlib.free(combined_ir)
|
||||
continue
|
||||
|
||||
# 编译为 .obj
|
||||
cret: int = BuildPipeline.compile_module_to_obj(
|
||||
combined_ir, combined_len, temp_dir, output_dir, ent.Sha1,
|
||||
cc_cmd, cc_flags)
|
||||
stdlib.free(combined_ir)
|
||||
if cret != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", ent.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
sys.exit(1)
|
||||
|
||||
compiled_count += 1
|
||||
# 显示编译完成的文件
|
||||
fb_comp: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_comp is not None:
|
||||
viperlib.snprintf(fb_comp, 1024, "[%d/%d] 编译完成: %s", i + 1, file_count, ent.Path)
|
||||
VLogger.info(fb_comp, "PhaseB")
|
||||
# 构造 .obj 路径,检测是否是 main 模块(test_main.py 或 main.py)
|
||||
od_len: t.CSizeT = string.strlen(output_dir)
|
||||
is_main_mod: int = 0
|
||||
if string.strstr(ent.Path, "test_main.py") is not None:
|
||||
is_main_mod = 1
|
||||
elif string.strstr(ent.Path, "main.py") is not None:
|
||||
is_main_mod = 1
|
||||
|
||||
# 切片路径: output_dir/{sha1前缀}/{sha1}.obj
|
||||
obj_path_sliced: str = StubMerger._sliced_path(output_dir, od_len, ent.Sha1, "obj")
|
||||
if obj_path_sliced is not None:
|
||||
op_sliced_len: t.CSizeT = string.strlen(obj_path_sliced)
|
||||
if is_main_mod != 0:
|
||||
# main 模块: 复制到 main_obj_path(确保链接时 main 在最前)
|
||||
if op_sliced_len < 512:
|
||||
string.strcpy(main_obj_path, obj_path_sliced)
|
||||
else:
|
||||
VLogger.warning("main_obj_path 缓冲区不足", "PhaseB")
|
||||
else:
|
||||
# 其他模块: 追加到 obj_paths
|
||||
if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE:
|
||||
if obj_pos > 0:
|
||||
obj_paths[obj_pos] = ' '
|
||||
obj_pos += 1
|
||||
string.strcpy(obj_paths + obj_pos, obj_path_sliced)
|
||||
obj_pos += op_sliced_len
|
||||
obj_paths[obj_pos] = '\0'
|
||||
else:
|
||||
VLogger.warning(".obj 路径缓冲区不足", "PhaseB")
|
||||
stdlib.free(obj_path_sliced)
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "编译完成: %d/%d", compiled_count, file_count)
|
||||
VLogger.success(fb, "PhaseB")
|
||||
|
||||
if compiled_count == 0:
|
||||
VLogger.error("无成功编译的文件", "PhaseB")
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
|
||||
# === 3.5 编译缺失的 includes 文件(按依赖图按需编译)===
|
||||
# 只编译被 App 源文件直接/间接引用的 includes 文件(可达集合),
|
||||
# 而非遍历整个 includes 目录。通过 _BuildReachableSha1Set 构建依赖图。
|
||||
if includes_dir is not None and includes_binary_dir is not None:
|
||||
inc_compiled: int = 0
|
||||
td_len_mi: t.CSizeT = string.strlen(temp_dir)
|
||||
|
||||
# 诊断日志:确认 Phase B+ 入口和 Sha1Store 状态
|
||||
fb_pbp_enter: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_pbp_enter is not None:
|
||||
viperlib.snprintf(fb_pbp_enter, 1024,
|
||||
"PhaseB+ 入口: store_count=%d includes_binary_dir=%s",
|
||||
StubMerger.GetSha1StoreCount(), includes_binary_dir)
|
||||
VLogger.info(fb_pbp_enter, "PhaseB+")
|
||||
|
||||
# 创建 includes_binary_dir 目录(确保 .obj 能写入和 collect_obj_files 能扫描)
|
||||
BuildPipeline.ensure_dir(includes_binary_dir)
|
||||
|
||||
# declare_only 预处理已移至 Phase A 之前(Phase A-pre-inc),
|
||||
# 确保 Phase A 翻译 App 源文件时 includes struct 已注册。
|
||||
# PopulateIncludesDeps 已在 Phase A-pre-inc 中填充。
|
||||
|
||||
# 构建可达 SHA1 集合(依赖图遍历)
|
||||
# app_deps_buf 为 None 时回退到扫描 source_dir(非递归)
|
||||
REACHABLE_SET_SIZE: t.CSizeT = t.CSizeT(StubMerger.MAX_INCLUDES_SHA1) * 17
|
||||
reachable_set: bytes = stdlib.malloc(REACHABLE_SET_SIZE)
|
||||
reachable_count: int = 0
|
||||
if reachable_set is not None:
|
||||
string.memset(reachable_set, 0, REACHABLE_SET_SIZE)
|
||||
reachable_count = StubMerger._BuildReachableSha1Set(
|
||||
mb, source_dir, temp_dir, reachable_set, app_deps_buf)
|
||||
fb_reach: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_reach is not None:
|
||||
viperlib.snprintf(fb_reach, 1024, "可达 includes SHA1: %d 个", reachable_count)
|
||||
VLogger.info(fb_reach, "PhaseB+")
|
||||
# fast-fail: 可达集合构建失败(依赖未找到),永不回退,直接终止
|
||||
if reachable_count < 0:
|
||||
VLogger.error("可达集合构建失败(fast-fail),终止编译", "PhaseB+")
|
||||
return 1
|
||||
else:
|
||||
VLogger.error("reachable_set 分配失败,终止编译", "PhaseB+")
|
||||
return 1
|
||||
|
||||
# 释放 app_deps_buf(已构建完 reachable_set,不再需要)
|
||||
if app_deps_buf is not None:
|
||||
stdlib.free(app_deps_buf)
|
||||
app_deps_buf = None
|
||||
|
||||
# 从全局存储器获取 SHA1/模块名/rel_path 数组(直接访问器,避免 box 解引用问题)
|
||||
store_count_mi: int = StubMerger.GetSha1StoreCount()
|
||||
if store_count_mi > 0:
|
||||
store_sha1_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
|
||||
store_mod_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreModArrPtr()
|
||||
store_rel_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||||
|
||||
for si_mi in range(store_count_mi):
|
||||
# 获取当前条目的 SHA1 和 rel_path
|
||||
inc_sha1_mi: str = store_sha1_arr_mi + t.CSizeT(si_mi) * 17
|
||||
inc_rel_mi: str = store_rel_arr_mi + t.CSizeT(si_mi) * StubMerger.MAX_REL_PATH_LEN
|
||||
# 按需编译过滤:只处理 reachable_set 中的 includes
|
||||
# 永不回退:reachable_count > 0 时严格按可达集合过滤
|
||||
if reachable_count > 0:
|
||||
if StubMerger._is_in_sha1_set(inc_sha1_mi, reachable_set, reachable_count) == 0:
|
||||
continue
|
||||
# 检查 .obj 是否已存在于 includes.binary(切片子目录)
|
||||
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
|
||||
check_pat_mi: str = StubMerger._sliced_path(includes_binary_dir, ibd_len_mi, inc_sha1_mi, "obj")
|
||||
check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
obj_exists_mi: int = 0
|
||||
if check_pat_mi is not None and check_fd_mi is not None:
|
||||
string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
check_h_mi: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(check_pat_mi, check_fd_mi)
|
||||
if check_h_mi != w32.win32base.INVALID_HANDLE_VALUE:
|
||||
w32.win32file.FindClose(check_h_mi)
|
||||
obj_exists_mi = 1
|
||||
if obj_exists_mi != 0:
|
||||
if check_pat_mi is not None:
|
||||
stdlib.free(check_pat_mi)
|
||||
stdlib.free(check_fd_mi)
|
||||
continue
|
||||
|
||||
# .obj 不存在,需要编译
|
||||
# 构造源文件路径: {includes_dir}/{rel_path}
|
||||
rel_path_len_mi: t.CSizeT = string.strlen(inc_rel_mi)
|
||||
inc_dir_len_mi: t.CSizeT = string.strlen(includes_dir)
|
||||
src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1)
|
||||
if src_fp_mi is None:
|
||||
stdlib.free(check_pat_mi)
|
||||
if check_fd_mi is not None:
|
||||
stdlib.free(check_fd_mi)
|
||||
continue
|
||||
viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1,
|
||||
"%s/%s", includes_dir, inc_rel_mi)
|
||||
|
||||
# 检查是否为声明文件(只有 declare 没有实质 define)
|
||||
# 判断方法: text.ll 中若有混淆函数 define(含 @")则为实现文件
|
||||
is_decl_mi: int = -1
|
||||
tpath_mi: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
if tpath_mi is not None:
|
||||
tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R)
|
||||
if not tf_mi.closed:
|
||||
is_decl_mi = 1
|
||||
tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
|
||||
if tbuf_mi is not None:
|
||||
tbr_mi: t.CInt64T = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE)
|
||||
if tbr_mi > 0:
|
||||
if tbr_mi < StubMerger.STUB_READ_BUF_SIZE:
|
||||
tbuf_mi[tbr_mi] = '\0'
|
||||
else:
|
||||
tbuf_mi[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0'
|
||||
# 逐行扫描: 找 define 行中含 @" 的(混淆函数名)
|
||||
tpos_mi: t.CSizeT = 0
|
||||
while tpos_mi < tbr_mi:
|
||||
tls_mi: t.CSizeT = tpos_mi
|
||||
while tpos_mi < tbr_mi:
|
||||
if tbuf_mi[tpos_mi] == '\n':
|
||||
break
|
||||
tpos_mi += 1
|
||||
tll_mi: t.CSizeT = tpos_mi - tls_mi
|
||||
if tpos_mi < tbr_mi:
|
||||
tpos_mi += 1
|
||||
if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0:
|
||||
# 临时在行尾加 \0 供 strstr 使用
|
||||
# 仅当行尾不在缓冲区末尾时才需保存/恢复
|
||||
# (缓冲区末尾已在上方 read_all 后截断为 '\0',直接用即可)
|
||||
# 避免 tls_mi + tll_mi == tbr_mi 时越界写
|
||||
end_pos_mi: t.CSizeT = tls_mi + tll_mi
|
||||
saved_mi: t.CChar = '\0'
|
||||
need_restore_mi: int = 0
|
||||
if end_pos_mi < tbr_mi:
|
||||
saved_mi = tbuf_mi[end_pos_mi]
|
||||
tbuf_mi[end_pos_mi] = '\0'
|
||||
need_restore_mi = 1
|
||||
if string.strstr(tbuf_mi + tls_mi, "@\"") is not None:
|
||||
if need_restore_mi != 0:
|
||||
tbuf_mi[end_pos_mi] = saved_mi
|
||||
is_decl_mi = 0
|
||||
break
|
||||
if need_restore_mi != 0:
|
||||
tbuf_mi[end_pos_mi] = saved_mi
|
||||
stdlib.free(tbuf_mi)
|
||||
tf_mi.close()
|
||||
stdlib.free(tpath_mi)
|
||||
# is_decl_mi == -1: text.ll 不存在(Phase1 未翻译此文件)
|
||||
# is_decl_mi == 1: 声明文件(仅 declare 无 define)
|
||||
# is_decl_mi == 0: 实现文件(有 define)
|
||||
# 只跳过声明文件(is_decl_mi == 1);text.ll 不存在时继续,让后续翻译逻辑处理
|
||||
if is_decl_mi == 1:
|
||||
stdlib.free(check_pat_mi)
|
||||
if check_fd_mi is not None:
|
||||
stdlib.free(check_fd_mi)
|
||||
stdlib.free(src_fp_mi)
|
||||
continue
|
||||
|
||||
# 尝试 BuildCombinedIR(stub/text 应已由 Phase1 生成)
|
||||
inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
||||
inc_combined_len_mi: t.CSizeT = 0
|
||||
if inc_combined_mi is not None:
|
||||
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||
|
||||
# 如果 stub/text 不存在,翻译源文件并保存 stub + text,然后重试
|
||||
if inc_combined_len_mi == 0 and inc_combined_mi is not None:
|
||||
# 计算 includes 文件的包名(相对 includes_dir 的目录部分)
|
||||
inc_pkg_mi: str = None
|
||||
if string.strlen(src_fp_mi) > inc_dir_len_mi + 1:
|
||||
inc_rel_mi2: str = src_fp_mi + inc_dir_len_mi + 1
|
||||
inc_pkg_mi = HandlesImports.compute_package_from_relpath(mb, inc_rel_mi2)
|
||||
tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi)
|
||||
if tr_mi is not None:
|
||||
PBP_IR_SIZE: t.CSizeT = 1048576
|
||||
# 保存 stub.ll (切片路径)
|
||||
inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
|
||||
if inc_stub_buf is not None:
|
||||
tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB)
|
||||
inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf)
|
||||
inc_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
|
||||
if inc_stub_path is not None:
|
||||
isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W)
|
||||
if not isf.closed:
|
||||
isf.write(inc_stub_buf, inc_stub_len)
|
||||
isf.close()
|
||||
stdlib.free(inc_stub_path)
|
||||
stdlib.free(inc_stub_buf)
|
||||
# 保存 text.ll (切片路径)
|
||||
inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
|
||||
if inc_text_buf is not None:
|
||||
tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
||||
inc_text_len: t.CSizeT = string.strlen(inc_text_buf)
|
||||
inc_text_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
if inc_text_path is not None:
|
||||
itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W)
|
||||
if not itf.closed:
|
||||
itf.write(inc_text_buf, inc_text_len)
|
||||
itf.close()
|
||||
stdlib.free(inc_text_path)
|
||||
stdlib.free(inc_text_buf)
|
||||
# 重试 BuildCombinedIR
|
||||
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||
|
||||
if inc_combined_len_mi == 0:
|
||||
# 诊断:检查 stub.ll/text.ll 是否存在
|
||||
diag_stub: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
|
||||
diag_text: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
diag_stub_ex: int = 0
|
||||
diag_text_ex: int = 0
|
||||
if diag_stub is not None:
|
||||
df_diag_s: fileio.File | t.CPtr = fileio.File(diag_stub, fileio.MODE.R)
|
||||
if not df_diag_s.closed:
|
||||
diag_stub_ex = 1
|
||||
df_diag_s.close()
|
||||
stdlib.free(diag_stub)
|
||||
if diag_text is not None:
|
||||
df_diag_t: fileio.File | t.CPtr = fileio.File(diag_text, fileio.MODE.R)
|
||||
if not df_diag_t.closed:
|
||||
diag_text_ex = 1
|
||||
df_diag_t.close()
|
||||
stdlib.free(diag_text)
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"BuildCombinedIR 失败: %s (stub=%d text=%d is_decl=%d)",
|
||||
src_fp_mi, diag_stub_ex, diag_text_ex, is_decl_mi)
|
||||
VLogger.error(fb, "PhaseB+")
|
||||
if inc_combined_mi is not None:
|
||||
stdlib.free(inc_combined_mi)
|
||||
stdlib.free(check_pat_mi)
|
||||
if check_fd_mi is not None:
|
||||
stdlib.free(check_fd_mi)
|
||||
stdlib.free(src_fp_mi)
|
||||
continue
|
||||
|
||||
# 编译为 .obj(输出到 includes_binary_dir,与存在性检查和链接收集一致)
|
||||
inc_cret_mi: int = BuildPipeline.compile_module_to_obj(
|
||||
inc_combined_mi, inc_combined_len_mi, temp_dir, includes_binary_dir, inc_sha1_mi,
|
||||
cc_cmd, cc_flags)
|
||||
stdlib.free(inc_combined_mi)
|
||||
|
||||
if inc_cret_mi != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", src_fp_mi)
|
||||
VLogger.error(fb, "PhaseB+")
|
||||
sys.exit(1)
|
||||
|
||||
inc_compiled += 1
|
||||
# 显示编译完成的 includes 文件
|
||||
fb_inc_comp: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_inc_comp is not None:
|
||||
viperlib.snprintf(fb_inc_comp, 1024, "[includes %d] 编译完成: %s", inc_compiled, src_fp_mi)
|
||||
VLogger.info(fb_inc_comp, "PhaseB+")
|
||||
|
||||
# 添加到 obj_paths (切片路径,从 includes_binary_dir 取)
|
||||
ibd_len_mi2: t.CSizeT = string.strlen(includes_binary_dir)
|
||||
inc_obj_sliced: str = StubMerger._sliced_path(includes_binary_dir, ibd_len_mi2, inc_sha1_mi, "obj")
|
||||
|
||||
if inc_obj_sliced is not None:
|
||||
inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced)
|
||||
if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE:
|
||||
if obj_pos > 0:
|
||||
obj_paths[obj_pos] = ' '
|
||||
obj_pos += 1
|
||||
string.strcpy(obj_paths + obj_pos, inc_obj_sliced)
|
||||
obj_pos += inc_obj_len
|
||||
obj_paths[obj_pos] = '\0'
|
||||
stdlib.free(inc_obj_sliced)
|
||||
|
||||
# 释放本次迭代的临时内存
|
||||
if check_pat_mi is not None:
|
||||
stdlib.free(check_pat_mi)
|
||||
|
||||
if check_fd_mi is not None:
|
||||
stdlib.free(check_fd_mi)
|
||||
|
||||
stdlib.free(src_fp_mi)
|
||||
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "编译缺失 includes: %d 个", inc_compiled)
|
||||
VLogger.info(fb, "PhaseB+")
|
||||
|
||||
# 释放 app_deps_buf(Phase B+ 块未执行时此处兜底释放)
|
||||
if app_deps_buf is not None:
|
||||
stdlib.free(app_deps_buf)
|
||||
app_deps_buf = None
|
||||
|
||||
# === 4. Phase C: 链接所有 .obj → .exe ===
|
||||
if log is not None:
|
||||
log.banner("Phase C: 链接")
|
||||
|
||||
od_len2: t.CSizeT = string.strlen(output_dir)
|
||||
lo_len: t.CSizeT = string.strlen(linker_output)
|
||||
exe_path: bytes = stdlib.malloc(od_len2 + lo_len + 2)
|
||||
if exe_path is not None:
|
||||
viperlib.snprintf(exe_path, od_len2 + lo_len + 2, "%s/%s", output_dir, linker_output)
|
||||
else:
|
||||
exe_path = linker_output
|
||||
|
||||
# 构造最终 .obj 路径列表:main_obj_path 在前,其他 .obj 在后
|
||||
final_obj_paths: bytes = stdlib.malloc(OBJ_PATHS_SIZE + 512)
|
||||
if final_obj_paths is None:
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
final_obj_paths[0] = '\0'
|
||||
fop_pos: t.CSizeT = 0
|
||||
# main_obj_path 放在最前面(确保 --allow-multiple-definition 选择用户 main)
|
||||
if main_obj_path[0] != '\0':
|
||||
mlen: t.CSizeT = string.strlen(main_obj_path)
|
||||
string.strcpy(final_obj_paths, main_obj_path)
|
||||
fop_pos = mlen
|
||||
if obj_paths[0] != '\0':
|
||||
final_obj_paths[fop_pos] = ' '
|
||||
fop_pos += 1
|
||||
# 追加其他 .obj
|
||||
if obj_paths[0] != '\0':
|
||||
string.strcpy(final_obj_paths + fop_pos, obj_paths)
|
||||
fop_pos += string.strlen(obj_paths)
|
||||
final_obj_paths[fop_pos] = '\0'
|
||||
|
||||
obj_paths_len: t.CSizeT = fop_pos
|
||||
|
||||
# 暂时禁用按图链接:始终全量链接 includes.binary 中的 .obj
|
||||
# 按图链接在 --clean 后 deps.txt 缺失时无法正确工作(跨包传递依赖丢失)
|
||||
# 按图编译(Phase B+)仍保留:只编译 reachable_set 中的缺失 includes
|
||||
# TODO: 待 deps.txt 生成机制完善后(如 Phase A 翻译所有 includes 的 imports),重新启用按图链接
|
||||
|
||||
# 释放 reachable_set(Phase B+ 已使用完毕)
|
||||
if reachable_set is not None:
|
||||
stdlib.free(reachable_set)
|
||||
reachable_set = None
|
||||
|
||||
# 始终传 includes_binary_dir 给 link_objs_to_exe,由其全量收集 .obj
|
||||
lret: int = BuildPipeline.link_objs_to_exe(
|
||||
final_obj_paths, obj_paths_len,
|
||||
linker_cmd, linker_flags, exe_path,
|
||||
includes_binary_dir)
|
||||
|
||||
if lret == 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "输出: %s", exe_path)
|
||||
VLogger.success(fb, "PhaseC")
|
||||
if args.get_bool("run"):
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "执行: %s", exe_path)
|
||||
VLogger.info(fb, "run")
|
||||
rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
||||
if rp is not None:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "退出码: %d", rp.returncode)
|
||||
VLogger.info(fb, "run")
|
||||
else:
|
||||
VLogger.error("链接失败", "PhaseC")
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
|
||||
stdlib.free(entries)
|
||||
return 0
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,291 +0,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 控制台彩色输出)
|
||||
#
|
||||
# 输出格式与 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: t.CChar | t.CPtr
|
||||
|
||||
|
||||
def fmt_buf() -> t.CChar | t.CPtr:
|
||||
"""获取全局格式化缓冲区(1024 字节)。
|
||||
|
||||
用法:
|
||||
buf: t.CChar | t.CPtr = 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
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 模块级便捷函数(与 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
|
||||
@@ -1,9 +0,0 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
# ============================================================
|
||||
# core 包入口
|
||||
#
|
||||
# 子模块通过绝对导入使用(import lib.core.X as X),
|
||||
# 此 __init__.py 不做 re-export,避免引入未使用的依赖。
|
||||
# ============================================================
|
||||
Reference in new issue
Block a user