snapshot before regression test

This commit is contained in:
t
2026-07-18 19:25:40 +08:00
commit 796222a300
2295 changed files with 206453 additions and 0 deletions

View File

@@ -0,0 +1,299 @@
import t, c
from stdint import *
import memhub
import string
import stdio
import viperlib
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
TempDir: str
OutputDir: str
ProjectName: str
ProjectVersion: str
CompilerCmd: str
CompilerFlags: str # 编译器参数(空格分隔,从 compiler.flags 数组拼接)
LinkerCmd: str
LinkerFlags: str # 链接器参数(空格分隔,从 linker.flags 数组拼接)
LinkerOutput: str
TargetTriple: str
TargetDataLayout: str
SliceLevel: t.CInt
StrictMode: t.CInt
IncludesDir: str # includes 目录路径(从 includes 数组首元素)
def Load_project_config(path: str) -> int:
"""加载工程配置文件project.vpj
Args:
path: 配置文件路径
Returns:
0 表示成功,非 0 表示失败
"""
global SourceDir, TempDir, OutputDir, ProjectName, ProjectVersion
global CompilerCmd, CompilerFlags, LinkerCmd, LinkerFlags, LinkerOutput
global TargetTriple, TargetDataLayout, SliceLevel, 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.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
# 读取顶层字段
SourceDir = root["source_dir"].as_string() if root["source_dir"] is not None else None
TempDir = root["temp_dir"].as_string() if root["temp_dir"] is not None else None
OutputDir = root["output_dir"].as_string() if root["output_dir"] is not None else None
ProjectName = root["name"].as_string() if root["name"] is not None else None
ProjectVersion = root["version"].as_string() if root["version"] is not None else None
# 读取 compiler 子对象
compiler: JsonValue | t.CPtr = root["compiler"]
if compiler is not None and compiler.is_object():
CompilerCmd = compiler["cmd"].as_string() if compiler["cmd"] is not None else None
# 读取 compiler.flags 数组,拼接成空格分隔的字符串
cc_flags_val: JsonValue | t.CPtr = compiler["flags"]
CompilerFlags = _join_flags_array(cc_flags_val)
# 读取 linker 子对象
linker: JsonValue | t.CPtr = root["linker"]
if linker is not None and linker.is_object():
LinkerCmd = linker["cmd"].as_string() if linker["cmd"] is not None else None
LinkerOutput = linker["output"].as_string() if linker["output"] is not None else None
# 读取 linker.flags 数组,拼接成空格分隔的字符串
ld_flags_val: JsonValue | t.CPtr = linker["flags"]
LinkerFlags = _join_flags_array(ld_flags_val)
# 读取 target 子对象
target: JsonValue | t.CPtr = root["target"]
if target is not None and target.is_object():
TargetTriple = target["triple"].as_string() if target["triple"] is not None else None
TargetDataLayout = target["datalayout"].as_string() if target["datalayout"] is not None else None
# 读取 options 子对象
options: JsonValue | t.CPtr = root["options"]
if options is not None and options.is_object():
sl: JsonValue | t.CPtr = options["slice_level"]
if sl is not None and sl.is_int():
SliceLevel = sl.as_int()
sm: JsonValue | t.CPtr = options["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["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/../includesOS 解析为 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/temp/output/includes
将 project.vpj 中的相对路径(以 ./ 开头)转换为基于 project_dir 的路径。
Args:
project_dir: 工程根目录project.vpj 所在目录)
Returns:
0 表示成功,非 0 表示失败
"""
global SourceDir, TempDir, OutputDir, IncludesDir
if project_dir is None:
return 1
if _mbuddy is None:
return 1
SourceDir = _join_path(SourceDir, project_dir)
TempDir = _join_path(TempDir, project_dir)
OutputDir = _join_path(OutputDir, project_dir)
# 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():
"""打印当前配置(调试用)"""
if ProjectName is not None:
stdio.printf(" project: %s v%s\n", ProjectName, ProjectVersion if ProjectVersion is not None else "?")
if SourceDir is not None:
stdio.printf(" source_dir: %s\n", SourceDir)
if TempDir is not None:
stdio.printf(" temp_dir: %s\n", TempDir)
if OutputDir is not None:
stdio.printf(" output_dir: %s\n", OutputDir)
if CompilerCmd is not None:
stdio.printf(" compiler: %s\n", CompilerCmd)
if LinkerCmd is not None:
stdio.printf(" linker: %s -> %s\n", LinkerCmd, LinkerOutput if LinkerOutput is not None else "?")
if IncludesDir is not None:
stdio.printf(" includes: %s\n", IncludesDir)

View File

@@ -0,0 +1,117 @@
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.MemManager | t.CPtr
# ============================================================
# compute_sha1 - 计算字符串的 SHA1返回前 16 个十六进制字符
#
# 使用 includes/hashlib 库的 sha1 类计算摘要,转为十六进制字符串。
# 参考 Projectrans.py 的 compute_sha1hashlib.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 - 删除目录中所有文件(非递归,保留目录本身)
#
# 用于 --clean 选项:清理 temp_dir 和 output_dir 中的旧文件。
# ============================================================
def CleanDir(dir_path: str) -> int:
"""删除目录中所有文件(非递归),返回删除的文件数,-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)
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

View File

@@ -0,0 +1,12 @@
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',
]

View File

@@ -0,0 +1,27 @@
import t, c
from stdint import *
import memhub
import lib.core.VLogger as VLogger
# ============================================================
# lib 包入口 - 声明全局 _mbuddy 内存池指针
# ============================================================
# 全局 mbuddy 内存池指针(由 App/main.py 初始化后注入)
_mbuddy: memhub.MemManager | t.CPtr
def InitLib(mb: memhub.MemManager | t.CPtr) -> int:
"""初始化 lib 包的全局 _mbuddy 指针,并级联注入到所有子模块。
Args:
mb: memhub.MemManager 实例指针MemBuddy 等子类通过多态传入)
Returns:
0 表示成功,非 0 表示失败
"""
if mb is None:
return 1
VLogger._mbuddy = mb
return 0

View File

@@ -0,0 +1,502 @@
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.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
# ============================================================
# BuildPipeline - 编译管线
#
# 负责将 LLVM IR 编译为可执行文件:
# 1. 写 .ll 文件到 temp 目录
# 2. 调用 llc 编译 .ll → .obj
# 3. 调用 clang++ 链接 .obj → .exe
# ============================================================
# 全局 mbuddy 指针
_mbuddy: memhub.MemManager | 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) -> HandlesTranslator.Translator | t.CPtr:
"""翻译文件,返回 Translator 对象(调用者负责 dump_irNone 失败
current_package: 当前文件所属包名用于解析相对导入None 表示顶级模块
"""
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:
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)
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
# 设置当前文件名(供报错使用)
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失败忽略即可
for i in range(path_len):
ch: int = c.Deref(buf + i)
if ch == ord('/') or ch == ord('\\'):
saved: int = ch
buf[i] = '\0'
w32.win32file.CreateDirectoryA(buf, None)
buf[i] = saved
# 创建最终目录
w32.win32file.CreateDirectoryA(buf, None)
return 0
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: 模块名(如 "main"
Returns:
0 成功,非 0 失败
"""
if ir_buf is None or output_dir is None:
return 1
# 构造文件路径: output_dir/module_name.ll
dir_len: t.CSizeT = string.strlen(output_dir)
name_len: t.CSizeT = string.strlen(module_name)
path_len: t.CSizeT = dir_len + 1 + name_len + 4 # dir/module.ll\0
path: bytes = _mbuddy.alloc(path_len)
if path is None:
return 1
viperlib.snprintf(path, path_len, "%s/%s.ll", output_dir, module_name)
# 打开文件写入
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: 模块名(用于生成 .obj 文件名)
cc_cmd: 编译器命令(如 "llc"
cc_flags: 编译器参数(如 "-filetype=obj -relocation-model=pic"
Returns:
0 成功,非 0 失败
"""
if ir_path is None or cc_cmd is None:
return 1
# 构造命令: llc -filetype=obj -o output_dir/module_name.obj ir_path
cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(output_dir) + string.strlen(module_name) + 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.obj %s", cc_cmd, cc_flags, output_dir, module_name, ir_path)
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
if result is None:
stdio.printf("[FATAL][LLC] subprocess.run 返回 None: %s\n", module_name)
return 1
if result.returncode != 0:
stdio.printf("[FATAL][LLC] 编译失败 (module=%s, cmd=%s)\n", module_name, cmd)
if result.stdout is not None:
stdio.printf("[LLC] 输出:\n%s\n", result.stdout)
return 1
return 0
def collect_obj_files(includes_binary_dir: str, out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT:
"""扫描 includes_binary_dir 目录,收集所有 .obj 文件路径到 out_buf
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'
out_pos: t.CSizeT = 0
# 构造搜索模式: dir/*.obj
dir_len: t.CSizeT = string.strlen(includes_binary_dir)
pattern: bytes = _mbuddy.alloc(dir_len + 8)
if pattern is None:
return 0
viperlib.snprintf(pattern, dir_len + 8, "%s/*.obj", includes_binary_dir)
# FindFirstFileA
find_data: w32.win32file.WIN32_FIND_DATAA | t.CPtr = _mbuddy.alloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
if find_data is None:
return 0
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:
return 0
# 需要 win32base 的 INVALID_HANDLE_VALUE
while True:
fname: str = find_data.cFileName
if fname is not None:
fname_len: t.CSizeT = string.strlen(fname)
# 构造完整路径并追加到 out_buf
# 路径格式: "dir/fname "
need: t.CSizeT = dir_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", includes_binary_dir, fname)
out_pos += dir_len + 1 + fname_len
else:
# 缓冲区不足,停止
break
if w32.win32file.FindNextFileA(handle, find_data) == 0:
break
w32.win32file.FindClose(handle)
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: 模块名
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:
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:
stdio.printf("[link] 附加 %d 字节的 includes.binary .obj 文件\n", extra_len)
else:
stdio.printf("[link] 警告: includes.binary 无 .obj 文件: %s\n", includes_binary_dir)
# 构造命令: clang++ main.obj extra_objs -o output linker_flags
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(output_dir) + string.strlen(module_name) + 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.obj %s -o %s/%s %s",
linker_cmd, output_dir, module_name, extra_objs,
output_dir, linker_output, linker_flags)
else:
viperlib.snprintf(cmd, cmd_len, "%s %s/%s.obj -o %s/%s %s",
linker_cmd, output_dir, module_name, output_dir, linker_output,
linker_flags)
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
if result is None:
stdio.printf("[link] subprocess.run 返回 None\n")
return 1
if result.returncode != 0:
stdio.printf("[link] 链接失败,返回码: %d\n", result.returncode)
stdio.printf("[link] 命令: %s\n", cmd)
# 显示链接器错误输出subprocess 将 stderr 合并到 stdout
if result.stdout is not None:
stdio.printf("[link] 链接器输出:\n%s\n", result.stdout)
else:
stdio.printf("[link] 无输出捕获\n")
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:
return 1
# Step 1: 写 .ll 文件
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
if ret != 0:
stdio.printf("[compile] 写 .ll 失败: %s\n", module_name)
return 1
# Step 2: 构造 .ll 路径并编译 → .obj
name_len: t.CSizeT = string.strlen(module_name)
dir_len: t.CSizeT = string.strlen(temp_dir)
ir_path: bytes = _mbuddy.alloc(dir_len + name_len + 5)
if ir_path is None:
return 1
viperlib.snprintf(ir_path, dir_len + name_len + 5, "%s/%s.ll", temp_dir, module_name)
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
if ret != 0:
stdio.printf("[compile] llc 编译失败: %s\n", module_name)
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)
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
if result is None:
stdio.printf("[link] subprocess.run 返回 None\n")
return 1
if result.returncode != 0:
stdio.printf("[link] 链接失败,返回码: %d\n", result.returncode)
stdio.printf("[link] 命令: %s\n", cmd)
if result.stdout is not None:
stdio.printf("[link] 链接器输出:\n%s\n", result.stdout)
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 文件路径
name_len: t.CSizeT = string.strlen(module_name)
dir_len: t.CSizeT = string.strlen(temp_dir)
ir_path: bytes = _mbuddy.alloc(dir_len + name_len + 5)
if ir_path is None:
result.Success = 0
result.ErrorMsg = "内存分配失败"
return result
viperlib.snprintf(ir_path, dir_len + name_len + 5, "%s/%s.ll", temp_dir, module_name)
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

View File

@@ -0,0 +1,281 @@
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.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
# ============================================================
# 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 提取整数常量(模块级函数)
#
# 仅支持 ast.Constant(INT),其他形式返回 0
# ============================================================
def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
"""从值节点提取整数常量(仅支持 Constant INT"""
if val_node is None:
return 0
if val_node.kind() != ast.ASTKind.Constant:
return 0
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
if cn.const_kind != ast.CONST_INT:
return 0
return cn.int_val
@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
# 检查是否已存在
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)
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)
if resolved is not None:
var_ty = resolved
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(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)
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)
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
# 普通局部变量
# 创建 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)
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

View File

@@ -0,0 +1,231 @@
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.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesStruct as HandlesStruct
# ============================================================
# 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:
stdio.printf("[ASGN] cast failed\n")
return 0
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
if targets is None:
stdio.printf("[ASGN] targets is None\n")
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:
stdio.printf("[ASGN] rhs_val is None\n")
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)
if cls_nm_set is not None:
obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, sub_pointee, sub_alloca)
if 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
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:
stdio.printf("[ASGN] alloca failed for %s\n", nm.id)
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

View File

@@ -0,0 +1,254 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import stdio
import string
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:
stdio.printf("[AUGASGN] attribute ptr is None\n")
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:
stdio.printf("[AUGASGN] cannot load attribute\n")
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:
stdio.printf("[AUGASGN] rhs is None\n")
return 0
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val)
if result is None:
stdio.printf("[AUGASGN] binop failed for attr op=%d\n", aug.op)
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
if tk != ast.ASTKind.Name:
stdio.printf("[AUGASGN] only Name/Attribute target supported\n")
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:
stdio.printf("[AUGASGN] cannot load target %s\n", nm.id)
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:
stdio.printf("[AUGASGN] rhs is None\n")
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:
stdio.printf("[AUGASGN] binop failed for op=%d\n", aug.op)
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.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

View File

@@ -0,0 +1,262 @@
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.MemManager | 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.MemManager | 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.MemManager | 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

View File

@@ -0,0 +1,230 @@
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

View File

@@ -0,0 +1,230 @@
import t, c
from stdint import *
import memhub
import string
import llvmlite
import stdio
# ============================================================
# 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:
stdio.printf("[ENUM] table full, cannot register %s\n", name)
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:
stdio.printf("[ENUM] member table full for %s\n", enum_entry.Name)
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

View File

@@ -0,0 +1,287 @@
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)
# 方法不在当前模块中时,检查类(含父类)是否有 SHA1stub 可能未注入)
# 优先用类型指针定位 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: Countertranslate_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.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

View File

@@ -0,0 +1,384 @@
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 = llvmlite.build_alloca(builder, i32_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 5. 存储初始值 (类型对齐: start_val 可能是 i64需截断到 i32)
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 != 32:
init_val = llvmlite.build_trunc(builder, start_val, i32_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, i32_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, i32_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, i32_ty, var_alloca)
# 类型对齐: step_val 可能是 i64需截断到 i32 与 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, i32_ty)
else:
incr_step = llvmlite.build_sext(builder, step_val, i32_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 = llvmlite.build_alloca(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 = llvmlite.build_alloca(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

View File

@@ -0,0 +1,936 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import viperlib
import stdio
import stdlib
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
# ============================================================
# 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. 创建 declareIsDeclared=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)
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
# 注册到函数表(用裸名 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) == 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)
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)
# 如果返回类型注解纯装饰器标记(如 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仅声明不定义
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, mangled_name, ret_ty)
if func is None:
stdio.printf("[FUNC] create_declare %s failed\n", fd.name)
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)
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:
stdio.printf("[FUNC] create_function %s failed\n", fd.name)
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)
# 注册到函数表
max_funcs: int = 256
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs) == 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)
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, HandlesVar.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)
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:
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, HandlesVar.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)
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

View File

@@ -0,0 +1,141 @@
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

View File

@@ -0,0 +1,404 @@
import t, c
from stdint import *
import ast
import memhub
import string
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) -> str:
"""添加 from-import 映射 "name:module",返回新的 from_imports 字符串"""
if local_name is None or module_name is None:
return from_imports
entry: t.CChar | t.CPtr = pool.alloc(128)
if entry is None:
return from_imports
viperlib.snprintf(entry, 128, "%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 名称 → 返回模块名或 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':
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
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0':
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
# ============================================================
# _resolve_relative_module - 解析相对导入为完整模块名
#
# 对于 from .X import Ylevel=1, module="X")在包 pkg 中:
# 解析为 "pkg.X"
# 对于 from . import Ylevel=1, module=None在包 pkg 中:
# 解析为 "pkg"
# 对于 from ..X import Ylevel=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)
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
if alias.asname is not None:
local_name = alias.asname
self.Trans._from_imports = add_from_import(
self.Trans.Pool, self.Trans._from_imports,
local_name, resolved)
# 命名空间隔离from-import 的名称标记为可见结构体
HandlesStruct.add_visible_struct(self.Trans.Pool, local_name)
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

View File

@@ -0,0 +1,314 @@
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.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()
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=2import扫描模式时跳过只处理 import 依赖
if trans._declare_only != 2:
cd_node: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
cd_name: str = "?" if cd_node is None or cd_node.name is None else cd_node.name
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=2import扫描模式时跳过
# _declare_only=1struct注册模式时只处理 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
# ============================================================
# 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=1struct注册模式时只处理 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
has_init: int = 0
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)
if resolved is not None:
var_ty = resolved
# 解析初始值
if aa.value is not None and aa.value.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
has_init = 1
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 and asgn.value.kind() == 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
has_init = 1
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
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 has_init != 0:
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
else:
gv.Initializer = "0"
# 创建 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:
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:
stdio.printf("[TR] CreateFunction main returned NULL\n")
return 0
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
pool, main_func, "entry")
if entry_blk is None:
stdio.printf("[TR] CreateBlock returned NULL\n")
return 0
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
if builder is None:
stdio.printf("[TR] NewBuilder returned NULL\n")
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

View File

@@ -0,0 +1,127 @@
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)

View File

@@ -0,0 +1,101 @@
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否则 ret i32 0
if val is None:
cur_func: llvmlite.Function | t.CPtr = self.Trans._cur_func
is_void_ret: int = 0
if cur_func is not None:
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func)
if ret_ty is not None:
match ret_ty:
case llvmlite.LLVMType.Void():
is_void_ret = 1
if is_void_ret != 0:
llvmlite.build_ret_void(builder)
return 0
val = llvmlite.const_int32(pool, 0)
# 类型转换:确保 val 类型与函数返回类型匹配
# 处理 i1bool 比较结果)→ i8t.CBool等情况
# i1 → 更宽整数用 zextbool 语义1 保持 1而非 sext 的 0xFF
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)
if 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

View File

@@ -0,0 +1,975 @@
import t, c
from stdint import *
import memhub
import string
import llvmlite
import stdio
import ast
import hashtable
# ============================================================
# HandlesStruct - 结构体类型注册和字段查找
#
# 管理 class 定义的结构体类型信息:
# - 类名 → LLVM StructType
# - 字段名 → 字段索引和类型
#
# 使用全局数组存储,线性查找(结构体数量通常很少)
# ============================================================
STRUCT_MAX: t.CDefine = 512
FIELD_MAX: t.CDefine = 32
FIELD_NAME_MAX: t.CDefine = 64
# ============================================================
# FieldEntry - 字段信息条目
# ============================================================
@t.NoVTable
class FieldEntry:
Name: t.CChar | t.CPtr # 字段名(字符串)
Index: int # 字段在结构体中的索引
Ty: llvmlite.LLVMType | t.CPtr # 字段的 LLVM 类型
DefaultVal: ast.AST | t.CPtr # 默认值 AST 节点None=无默认值)
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名str 别名在结构体字段中触发编译器 bug改用显式联合类型
# ============================================================
# StructEntry - 结构体注册条目
# ============================================================
@t.NoVTable
class StructEntry:
Name: t.CChar | t.CPtr # 类名
Ty: llvmlite.LLVMType | t.CPtr # LLVM StructType
FieldCount: int # 字段数量
Fields: FieldEntry | t.CPtr # 字段数组FIELD_MAX 个槽位)
IsUnion: int # 1=联合体 / 0=普通结构体
IsOOP: int # 1=OOP结构体有方法 / 0=纯内存结构体
HasInit: int # 1=有__init__方法 / 0=无
HasNew: int # 1=有__new__方法 / 0=无
HasVTable: int # 1=有虚表 / 0=无虚表
IsNoVTable: int # 1=明确标记 @t.NoVTable / 0=未标记
ParentName: t.CChar | t.CPtr # 父类名None=无父类)
VTableMethodCount: int # 虚表中的方法数量
VTableMethods: t.CChar | t.CPtr # 虚表方法名数组(每个方法名 strVTableMethodCount 个)
ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1None=无 SHA1
# ============================================================
# 全局注册表(静态分配)
# ============================================================
_struct_table: StructEntry | t.CPtr = None
_struct_count: int = 0
# ============================================================
# 跨模块命名空间隔离per-file 结构体可见性
#
# _visible_structs: 当前文件可见的结构体名HashTableO(1) 查找)
# _strict_visibility: 1=严格模式(仅本地+import可见/ 0=宽松模式(全部可见)
#
# 每个文件翻译前调用 reset_visible_structs 重置
# ============================================================
_visible_structs: hashtable.HashTable | t.CPtr = None
_strict_visibility: int = 0
# ============================================================
# reset_visible_structs — 重置可见性状态(每个文件翻译前调用)
# ============================================================
def reset_visible_structs(pool: memhub.MemBuddy | t.CPtr, strict: int):
"""重置可见性状态(每个文件翻译前调用)
pool: 内存分配器(严格模式下创建 HashTable
strict: 1=严格模式用户文件0=宽松模式includes 文件)
"""
global _visible_structs
global _strict_visibility
_strict_visibility = strict
if strict != 0:
# 严格模式:创建新的 HashTable 记录可见结构体
_visible_structs = hashtable.HashTable(pool)
else:
# 宽松模式:全部可见,不需要 HashTable
_visible_structs = None
# ============================================================
# add_visible_struct — 添加可见结构体名
# ============================================================
def add_visible_struct(pool: memhub.MemBuddy | t.CPtr, name: str):
"""添加可见结构体名(类定义时和 from-import 时调用)"""
global _visible_structs
if name is None:
return
# 宽松模式:全部可见,无需记录
if _strict_visibility == 0:
return
if _visible_structs is None:
return
# 已存在则跳过HashTable.__setitem__ 会覆盖,此处提前检查避免重复分配)
if _visible_structs.__contains__(name) != 0:
return
_visible_structs.set_int(name, 1)
# ============================================================
# is_struct_visible — 检查结构体是否在当前文件可见
# ============================================================
def is_struct_visible(name: str) -> int:
"""检查结构体是否可见,返回 1=可见 / 0=不可见"""
if _strict_visibility == 0:
return 1
if name is None or _visible_structs is None:
return 0
return _visible_structs.__contains__(name)
# ============================================================
# 初始化结构体注册表
# ============================================================
def init_struct_table(pool: memhub.MemBuddy | t.CPtr) -> int:
"""初始化结构体注册表,返回 1 成功"""
global _struct_table
global _struct_count
if _struct_table is not None:
return 1
entry_size: t.CSizeT = StructEntry.__sizeof__()
_struct_table = pool.alloc(entry_size * STRUCT_MAX)
if _struct_table is None:
return 0
string.memset(_struct_table, 0, entry_size * STRUCT_MAX)
_struct_count = 0
return 1
# ============================================================
# _get_struct_entry — 获取第 i 个 StructEntry 槽位
# ============================================================
def _get_struct_entry(i: int) -> StructEntry | t.CPtr:
"""获取第 i 个结构体条目"""
if _struct_table is None or i < 0 or i >= STRUCT_MAX:
return None
entry_size: t.CSizeT = StructEntry.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(_struct_table) + i * entry_size
return (StructEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
# ============================================================
# _get_field_entry — 获取结构体中第 i 个 FieldEntry 槽位
# ============================================================
def _get_field_entry(struct_entry: StructEntry | t.CPtr, i: int) -> FieldEntry | t.CPtr:
"""获取结构体中第 i 个字段条目"""
if struct_entry is None or i < 0 or i >= FIELD_MAX:
return None
field_size: t.CSizeT = FieldEntry.__sizeof__()
addr: t.CUInt64T = t.CUInt64T(struct_entry.Fields) + i * field_size
return (FieldEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
# ============================================================
# register_struct — 注册结构体类型
#
# 返回 StructEntry 指针,可用于添加字段
# ============================================================
def register_struct(pool: memhub.MemBuddy | t.CPtr,
name: str,
struct_ty: llvmlite.LLVMType | t.CPtr,
sha1: str = None) -> StructEntry | t.CPtr:
"""注册结构体类型,返回 StructEntry 指针
用类型指针去重is 比较),不用类名去重。
这样跨模块同名类可以共存,各自有独立的字段定义。
sha1 参数在注册时直接设置 ModuleSha1避免 set_struct_sha1 找错 entry
"""
if init_struct_table(pool) == 0:
return None
# 用类型指针去重(同一类型不重复注册,支持跨模块同名类)
for i in range(_struct_count):
existing: StructEntry | t.CPtr = _get_struct_entry(i)
if existing is not None and existing.Ty is not None:
if existing.Ty is struct_ty:
return existing
if _struct_count >= STRUCT_MAX:
stdio.printf("[STRUCT] table full, cannot register %s\n", name)
return None
entry: StructEntry | t.CPtr = _get_struct_entry(_struct_count)
if entry is None:
return None
# 分配字段数组
field_size: t.CSizeT = FieldEntry.__sizeof__()
entry.Fields = pool.alloc(field_size * FIELD_MAX)
if entry.Fields is None:
return None
string.memset(entry.Fields, 0, field_size * FIELD_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.Ty = struct_ty
entry.FieldCount = 0
# 注册时直接设置 SHA1避免 set_struct_sha1 跨模块同名时找错 entry
if sha1 is not None:
sha1_len: t.CSizeT = string.strlen(sha1)
sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1)
if sha1_buf is not None:
string.strcpy(sha1_buf, sha1)
entry.ModuleSha1 = sha1_buf
_struct_count += 1
return entry
# ============================================================
# set_struct_sha1 — 设置结构体所属模块的 SHA1
#
# 在翻译类定义时调用,记录类所属模块的 SHA1。
# 跨模块方法调用时(如 __before_init__/__init__通过 SHA1
# 构造正确的函数名("{sha1}.{ClassName}.{method}")。
# ============================================================
def set_struct_sha1(pool: memhub.MemBuddy | t.CPtr,
class_name: str, sha1: str) -> int:
"""设置结构体所属模块的 SHA1返回 1=成功 / 0=失败"""
if class_name is None or sha1 is None:
return 0
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is None:
return 0
# 复制 SHA1 字符串(避免悬空指针)
sha1_len: t.CSizeT = string.strlen(sha1)
sha1_buf: t.CChar | t.CPtr = pool.alloc(sha1_len + 1)
if sha1_buf is None:
return 0
string.strcpy(sha1_buf, sha1)
entry.ModuleSha1 = sha1_buf
return 1
# ============================================================
# get_struct_sha1 — 获取结构体所属模块的 SHA1
#
# 跨模块方法调用时使用,返回 None=无 SHA1本模块定义或无 SHA1
# ============================================================
def get_struct_sha1(class_name: str) -> str:
"""获取结构体所属模块的 SHA1返回 None=无 SHA1"""
if class_name is None or _struct_table is None:
return None
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is None:
return None
return entry.ModuleSha1
# ============================================================
# add_field — 向结构体添加字段信息
# ============================================================
def add_field(pool: memhub.MemBuddy | t.CPtr,
struct_entry: StructEntry | t.CPtr,
field_name: str,
field_ty: llvmlite.LLVMType | t.CPtr,
default_val: ast.AST | t.CPtr = None,
annot_class_name: t.CChar | t.CPtr = None) -> int:
"""向结构体添加字段,返回字段索引(-1 失败)
default_val: 字段默认值 AST 节点可选None=无默认值)
annot_class_name: 原始类型注解的类名(可选,用于联合类型字段的方法调用解析)
"""
if struct_entry is None or field_name is None or field_ty is None:
return -1
if struct_entry.FieldCount >= FIELD_MAX:
stdio.printf("[STRUCT] field table full for %s\n", struct_entry.Name)
return -1
idx: int = struct_entry.FieldCount
fe: FieldEntry | t.CPtr = _get_field_entry(struct_entry, idx)
if fe is None:
return -1
# 复制字段名
name_len: t.CSizeT = string.strlen(field_name)
name_buf: t.CChar | t.CPtr = pool.alloc(name_len + 1)
if name_buf is not None:
string.strcpy(name_buf, field_name)
fe.Name = name_buf
fe.Index = idx
fe.Ty = field_ty
fe.DefaultVal = default_val
fe.AnnotClassName = annot_class_name
struct_entry.FieldCount = idx + 1
return idx
# ============================================================
# find_struct — 按类名查找结构体
# ============================================================
def find_struct(name: str) -> StructEntry | t.CPtr:
"""按类名查找结构体,返回 StructEntry 或 None"""
if name is None or _struct_table is None:
return None
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
return None
# ============================================================
# find_struct_by_module — 按类名 + SHA1 查找结构体
#
# 跨模块同名类区分Phase B 重新翻译时,必须找到当前模块
# 注册的结构体(而非第一个同名条目),否则 struct type、
# 字段布局、GEP 索引全部错误。
# ============================================================
def find_struct_by_module(name: str, sha1: str) -> StructEntry | t.CPtr:
"""按类名 + SHA1 查找结构体,返回 StructEntry 或 None
SHA1 非 None 时:精确匹配 name+sha1未找到返回 None不回退避免跨模块同名找错
SHA1 为 None 时:回退到 find_struct(name) 按类名查找第一个
"""
if name is None or _struct_table is None:
return None
if sha1 is not None:
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
if entry.ModuleSha1 is not None:
if string.strcmp(entry.ModuleSha1, sha1) == 0:
return entry
# SHA1 查找失败:不回退到 find_struct会返回跨模块同名错误 entry
# 返回 None 让调用方创建新类型,避免 Phase B 用错误类型短路
return None
# 无 SHA1按类名查找第一个
return find_struct(name)
# ============================================================
# find_struct_by_type — 按类型指针查找结构体is 身份比较)
#
# 用于 _translate_oop_methods 等已有 struct_ty 的场景,
# 直接用指针身份定位 entry规避跨模块同名类 find_struct 找错的问题。
# ============================================================
def find_struct_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> StructEntry | t.CPtr:
"""按类型指针查找结构体is 比较),返回 StructEntry 或 None"""
if struct_ty is None or _struct_table is None:
return None
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if entry.Ty is struct_ty:
return entry
return None
# ============================================================
# lookup_field — 按结构体类型和字段名查找字段信息
# ============================================================
def lookup_field(struct_ty: llvmlite.LLVMType | t.CPtr,
field_name: str) -> FieldEntry | t.CPtr:
"""按结构体类型和字段名查找字段信息
两遍查找策略(跨模块同名类冲突的根本修复):
第一遍: 类型指针 is 身份比较(最高优先级,类型唯一确定 entry
第二遍: 名称回退is 未匹配时,按类名/strstr 匹配,字段未找到时 continue
"""
if struct_ty is None or field_name is None or _struct_table is None:
return None
# ============================================================
# 两遍查找策略(跨模块同名类冲突的根本修复):
#
# 第一遍: 用类型指针 is 身份比较(最高优先级)
# - is 匹配唯一确定 entry字段未找到直接返回 None
# - 规避联合类型 == BUG且不受遍历顺序影响
#
# 第二遍: 名称回退is 未匹配到任何 entry 时才执行)
# - 用于未注册类型或 is 不可靠的场景
# - 名称匹配但字段未找到时 continue继续检查其他同名 entry
# ============================================================
# 第一遍: is 身份比较
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if entry.Ty is struct_ty:
# is 匹配,查找字段
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
# is 匹配但字段未找到(类型唯一确定,无需继续)
return None
# 第二遍: 名称回退is 未匹配到)
ty_name: str = _extract_struct_name(struct_ty)
if ty_name is not None:
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
matched: int = 0
if string.strcmp(entry.Name, ty_name) == 0:
matched = 1
elif string.strstr(ty_name, entry.Name) is not None:
matched = 1
if matched != 0:
# 查找字段
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
# 名称匹配但字段未找到,继续检查其他同名 entry跨模块同名
continue
# 所有条目都未匹配
return None
# ============================================================
# lookup_field_by_class — 按类名和字段名查找字段信息
# ============================================================
def lookup_field_by_class(class_name: str,
field_name: str,
sha1: str = None) -> FieldEntry | t.CPtr:
"""按类名和字段名查找字段信息
优先用 SHA1 匹配(跨模块同名类区分),无 SHA1 时按类名查找第一个
"""
if class_name is None or field_name is None:
return None
# 优先用 SHA1 匹配(跨模块同名类区分)
if sha1 is not None:
sha1_matched: int = 0
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Name is not None:
if string.strcmp(entry.Name, class_name) == 0:
if entry.ModuleSha1 is not None:
if string.strcmp(entry.ModuleSha1, sha1) == 0:
sha1_matched = 1
# SHA1 + 类名匹配,查找字段
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
return None
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
entry = find_struct(class_name)
if entry is None:
return None
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.Name is not None:
if string.strcmp(fe.Name, field_name) == 0:
return fe
return None
# ============================================================
# get_struct_type — 按类名获取结构体的 LLVM 类型
# ============================================================
def get_struct_type(class_name: str) -> llvmlite.LLVMType | t.CPtr:
"""按类名获取结构体的 LLVM 类型"""
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is not None:
return entry.Ty
return None
# ============================================================
# get_field_by_index — 按类名和字段索引获取字段信息
#
# 用于构造函数 Point(10, 20) 按顺序访问字段
# ============================================================
def get_field_by_index(class_name: str,
idx: int) -> FieldEntry | t.CPtr:
"""按类名和字段索引获取字段信息"""
if class_name is None:
return None
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is None:
return None
if idx < 0 or idx >= entry.FieldCount:
return None
return _get_field_entry(entry, idx)
# ============================================================
# struct_has_defaults — 检查结构体是否有任何带默认值的字段
# ============================================================
def struct_has_defaults(class_name: str) -> int:
"""检查结构体是否有任何带默认值的字段,返回 1=有 / 0=无"""
if class_name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(class_name)
if entry is None:
return 0
for fi in range(entry.FieldCount):
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
if fe is not None and fe.DefaultVal is not None:
return 1
return 0
# ============================================================
# get_struct_type_from_value — 从 LLVM Value 的类型推断结构体类型
#
# 如果 value 是 Ptr(Struct(...)),返回 Struct 类型
# ============================================================
def _is_struct_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
"""检查 ty 是否是 Struct 类型(独立函数,规避嵌套 match 编译器 BUG"""
if ty is None:
return 0
match ty:
case llvmlite.LLVMType.Struct(fields, fcount, name):
return 1
case _:
return 0
def get_struct_type_from_value(val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""从 Value 的类型推断结构体类型"""
if val is None or val.Ty is None:
return None
match val.Ty:
case llvmlite.LLVMType.Ptr(pointee):
if _is_struct_type(pointee) != 0:
return pointee
return None
case _:
return None
# ============================================================
# 联合体支持函数
# ============================================================
# ============================================================
# mark_as_union — 标记已注册的结构体为联合体
#
# 联合体用 Struct([Array(Int8, max_size)]) 表示,
# 注册时用 register_struct 注册类型,再用此函数标记 IsUnion=1
# ============================================================
def mark_as_union(name: str) -> int:
"""标记已注册的结构体为联合体,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.IsUnion = 1
return 1
# ============================================================
# is_union_by_name — 按类名检查是否为联合体
# ============================================================
def is_union_by_name(name: str) -> int:
"""按类名检查是否为联合体,返回 1=是 / 0=否"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.IsUnion
# ============================================================
# is_union_by_type — 按类型指针检查是否为联合体
# ============================================================
def is_union_by_type(struct_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""按类型指针检查是否为联合体,返回 1=是 / 0=否
先尝试类型指针 == 比较,失败时回退到名称匹配
"""
if struct_ty is None or _struct_table is None:
return 0
ty_name: str = _extract_struct_name(struct_ty)
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Ty is not None:
matched: int = 0
if entry.Ty is struct_ty:
matched = 1
elif ty_name is not None and entry.Name is not None:
if string.strcmp(entry.Name, ty_name) == 0:
matched = 1
elif string.strstr(ty_name, entry.Name) is not None:
matched = 1
if matched != 0:
return entry.IsUnion
return 0
# ============================================================
# OOP 支持函数
# ============================================================
# ============================================================
# mark_as_oop — 标记已注册的结构体为 OOP有方法
# ============================================================
def mark_as_oop(name: str) -> int:
"""标记已注册的结构体为 OOP返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.IsOOP = 1
return 1
# ============================================================
# is_oop_by_name — 按类名检查是否为 OOP 结构体
# ============================================================
def is_oop_by_name(name: str) -> int:
"""按类名检查是否为 OOP 结构体,返回 1=是 / 0=否"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.IsOOP
# ============================================================
# mark_has_init — 标记结构体拥有 __init__ 方法
# ============================================================
def mark_has_init(name: str) -> int:
"""标记结构体拥有 __init__ 方法,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.HasInit = 1
return 1
# ============================================================
# has_init_by_name — 按类名检查是否有 __init__ 方法
# ============================================================
def has_init_by_name(name: str) -> int:
"""按类名检查是否有 __init__ 方法,返回 1=有 / 0=无"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.HasInit
# ============================================================
# mark_has_new — 标记结构体拥有 __new__ 方法
# ============================================================
def mark_has_new(name: str) -> int:
"""标记结构体拥有 __new__ 方法,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.HasNew = 1
return 1
# ============================================================
# has_new_by_name — 按类名检查是否有 __new__ 方法
# ============================================================
def has_new_by_name(name: str) -> int:
"""按类名检查是否有 __new__ 方法,返回 1=有 / 0=无"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.HasNew
# ============================================================
# get_class_name_by_type — 按 LLVM 类型指针查找类名
#
# 用于方法调用:从变量类型 Ptr(Struct(...)) 反查类名,
# 以构造 ClassName.method_name 进行方法查找
# ============================================================
def get_class_name_by_type(pool: memhub.MemBuddy | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr) -> str:
"""按类型指针查找类名,返回类名字符串或 None"""
if struct_ty is None or _struct_table is None:
return None
for i in range(_struct_count):
entry: StructEntry | t.CPtr = _get_struct_entry(i)
if entry is not None and entry.Ty is not None:
if entry.Ty is struct_ty:
return entry.Name
# 回退: 类型指针比较失败时,遍历所有注册的结构体按名称匹配
# 提取 struct_ty 的 Name 字段(可能是 "SHA1.ClassName" 格式)
ty_name: str = _extract_struct_name(struct_ty)
if ty_name is not None:
for j in range(_struct_count):
entry2: StructEntry | t.CPtr = _get_struct_entry(j)
if entry2 is not None and entry2.Name is not None:
# 构造 "SHA1.ClassName" 格式进行比较
entry2_sha1: str = entry2.ModuleSha1
if entry2_sha1 is not None:
full_nm: t.CChar | t.CPtr = pool.alloc(128)
if full_nm is not None:
viperlib.snprintf(full_nm, 128, "%s.%s", entry2_sha1, entry2.Name)
if string.strcmp(full_nm, ty_name) == 0:
return entry2.Name
# 也直接比较类名struct_ty 的 Name 可能无 SHA1 前缀)
if string.strcmp(entry2.Name, ty_name) == 0:
return entry2.Name
# 最后回退: strstr 检查包含关系
# ty_name 可能是 "SHA1.Counter"entry2.Name 是 "Counter"
if string.strstr(ty_name, entry2.Name) is not None:
return entry2.Name
return None
# ============================================================
# _extract_struct_name — 从 LLVMType 提取 Struct 变体的 Name 字段
# ============================================================
def _extract_struct_name(ty: llvmlite.LLVMType | t.CPtr) -> str:
"""从 LLVMType 提取 Struct 变体的 Name 字段,返回 None 非 Struct"""
if ty is None:
return None
match ty:
case llvmlite.LLVMType.Struct(fields, fcount, name):
return name
case _:
return None
# ============================================================
# VTable 支持函数
# ============================================================
# ============================================================
# mark_has_vtable — 标记结构体拥有虚表
# ============================================================
def mark_has_vtable(name: str) -> int:
"""标记结构体拥有虚表,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.HasVTable = 1
return 1
# ============================================================
# has_vtable_by_name — 按类名检查是否有虚表
# ============================================================
def has_vtable_by_name(name: str) -> int:
"""按类名检查是否有虚表,返回 1=有 / 0=无"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.HasVTable
# ============================================================
# mark_novtable — 标记结构体为 @t.NoVTable
# ============================================================
def mark_novtable(name: str) -> int:
"""标记结构体为 NoVTable返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.IsNoVTable = 1
return 1
# ============================================================
# is_novtable_by_name — 按类名检查是否为 NoVTable
# ============================================================
def is_novtable_by_name(name: str) -> int:
"""按类名检查是否为 NoVTable返回 1=是 / 0=否"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.IsNoVTable
# ============================================================
# set_parent_name — 设置父类名
# ============================================================
def set_parent_name(name: str, parent_name: str) -> int:
"""设置结构体的父类名,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.ParentName = parent_name
return 1
# ============================================================
# get_parent_name — 获取父类名
# ============================================================
def get_parent_name(name: str) -> str:
"""获取结构体的父类名,返回 None=无父类"""
if name is None:
return None
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return None
return entry.ParentName
# ============================================================
# set_vtable_methods — 设置虚表方法名数组
#
# methods 是一个 str 数组(每个元素是方法名字符串指针),
# count 是方法数量。数组直接引用,不复制。
# ============================================================
def set_vtable_methods(name: str, methods: t.CChar | t.CPtr, count: int) -> int:
"""设置虚表方法名数组,返回 1=成功 / 0=失败"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
entry.VTableMethods = methods
entry.VTableMethodCount = count
return 1
# ============================================================
# get_vtable_method_index — 获取方法在虚表中的索引
#
# 在 VTableMethods 数组中查找方法名,返回索引(-1=未找到)
# ============================================================
def get_vtable_method_index(name: str, method_name: str) -> int:
"""获取方法在虚表中的索引,返回 -1=未找到"""
if name is None or method_name is None:
return -1
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None or entry.VTableMethods is None:
return -1
# VTableMethods 字段声明为 t.CChar*,但实际存储的是 t.CSizeT 数组
# 必须转换为 t.CSizeT* 才能正确读取 8 字节指针值
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr))
for i in range(entry.VTableMethodCount):
mname_addr: t.CSizeT = methods_arr[i]
if mname_addr == 0:
continue
mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr))
if mname is not None and string.strcmp(mname, method_name) == 0:
return i
return -1
# ============================================================
# get_vtable_method_count — 获取虚表方法数量
# ============================================================
def get_vtable_method_count(name: str) -> int:
"""获取虚表方法数量"""
if name is None:
return 0
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return 0
return entry.VTableMethodCount
# ============================================================
# get_vtable_method_name — 获取虚表中第 idx 个方法名
#
# 返回方法名字符串指针None=越界或未设置
# ============================================================
def get_vtable_method_name(name: str, idx: int) -> str:
"""获取虚表中第 idx 个方法名,返回 None=越界"""
if name is None or idx < 0:
return None
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None or entry.VTableMethods is None:
return None
if idx >= entry.VTableMethodCount:
return None
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr))
mname_addr: t.CSizeT = methods_arr[idx]
if mname_addr == 0:
return None
return (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr))
# ============================================================
# get_field_count — 获取结构体字段数量(访问器,绕过 stub 类型限制)
# ============================================================
def get_field_count(name: str) -> int:
"""获取结构体字段数量,返回 -1=未找到"""
if name is None:
return -1
entry: StructEntry | t.CPtr = find_struct(name)
if entry is None:
return -1
return entry.FieldCount
# ============================================================
# get_field_name_ptr — 获取 FieldEntry 的字段名指针(访问器)
# ============================================================
def get_field_name_ptr(fe: FieldEntry | t.CPtr) -> str:
"""获取 FieldEntry 的字段名,返回 None=未设置"""
if fe is None:
return None
return fe.Name
# ============================================================
# get_field_type_ptr — 获取 FieldEntry 的字段类型指针(访问器)
# ============================================================
def get_field_type_ptr(fe: FieldEntry | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""获取 FieldEntry 的字段类型,返回 None=未设置"""
if fe is None:
return None
return fe.Ty
# ============================================================
# get_field_default_ptr — 获取 FieldEntry 的默认值 AST 指针(访问器)
# ============================================================
def get_field_default_ptr(fe: FieldEntry | t.CPtr) -> ast.AST | t.CPtr:
"""获取 FieldEntry 的默认值 AST 节点,返回 None=无默认值"""
if fe is None:
return None
return fe.DefaultVal
# ============================================================
# get_field_annot_class_name — 获取 FieldEntry 的注解类名(访问器)
# ============================================================
def get_field_annot_class_name(fe: FieldEntry | t.CPtr) -> str:
"""获取 FieldEntry 的原始类型注解类名,返回 None=未设置"""
if fe is None:
return None
return fe.AnnotClassName

View File

@@ -0,0 +1,417 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
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:
stdio.printf("[TR] NewModule returned NULL\n")
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:
stdio.printf("[TR] CreateDeclare printf returned NULL\n")
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() 创建包装 maintrans 单参)"""
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)
# 创建前向声明
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

View File

@@ -0,0 +1,365 @@
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改用显式联合类型
# ============================================================
# 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
# ============================================================
# 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
# ============================================================
# 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 = llvmlite.build_alloca(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 = llvmlite.build_alloca(builder, ty)
if alloca is None:
return None
define_var(symtab, name, alloca)
return alloca

View File

@@ -0,0 +1,130 @@
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

View File

@@ -0,0 +1,23 @@
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

View File

@@ -0,0 +1,364 @@
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
# ============================================================
# IncludesScanner - includes 目录递归扫描
#
# 递归扫描 includes 目录,收集所有 .py 文件路径和 SHA1
# 为 Phase1 stub 生成和 Phase2 stub 合并提供基础数据。
#
# 使用 Win32 FindFirstFileA/FindNextFileA 实现目录遍历。
# ============================================================
# 全局 mbuddy 指针
_mbuddy: memhub.MemManager | 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 池耗尽(每文件 128KB60+ 文件会耗尽 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
# 原地去除 \rCRLF → 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)
stdio.printf(" [scan] %s -> %s\n", rel_path, sha1)
# 继续搜索下一个文件
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
stdio.printf("[Phase1] 扫描 includes 目录: %s\n", includes_dir)
result: ScanResult | t.CPtr = create_scan_result(pool)
if result is None:
return None
scan_directory_recursive(pool, includes_dir, None, result)
stdio.printf("[Phase1] 扫描完成: %d 个 .py 文件\n", result.Count)
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

View File

@@ -0,0 +1,540 @@
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 ast
import llvmlite
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.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.IncludesScanner as IncludesScanner
import lib.core.StubMerger as StubMerger
import lib.Projectrans.Config as Config
# 全局 mbuddy 指针
_mbuddy: memhub.MemManager | t.CPtr
# 源代码缓冲区大小1MB
SRC_BUF_SIZE: t.CDefine = 1048576
# ============================================================
# RunPhase1 - Phase1: 扫描 includes 目录,按需翻译并生成 stub
#
# 对每个 .py 文件检查 stub 是否已存在,若不存在则翻译并分离 stub。
# "按需翻译":仅对 stub 不存在的文件执行翻译,避免重复工作。
#
# Args:
# mb: 内存池
# includes_dir: includes 目录路径
# temp_dir: 临时目录(保存 stub
# log: 日志器
#
# Returns:
# 0 成功,非 0 失败
# ============================================================
def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
log: VLogger.Logger | t.CPtr) -> int:
"""Phase1: 扫描 includes 目录,按需翻译并生成 stub"""
if includes_dir is None or temp_dir is None:
stdio.printf("[Phase1] includes_dir 或 temp_dir 为空,跳过\n")
return 1
if log is not None:
log.banner("Phase1: 扫描 includes按需翻译")
# 扫描 includes 目录
result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
if result is None:
stdio.printf("[Phase1] 扫描失败\n")
return 1
stdio.printf("[Phase1] 共 %d 个文件\n", result.Count)
# 读取 _sha1_map.txt 获取需要的 includes SHA1 集合
# 优先使用 Projectrans.py 生成的 _sha1_map.txt含依赖分析只包含需要的 includes
# 若不存在,则从扫描结果生成(包含所有 includes可能导致结构体表溢出
sha1_set: str = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17)
if sha1_set is None:
stdio.printf("[Phase1] sha1_set 分配失败\n")
return 1
string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
set_count: int = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set)
if set_count <= 0:
stdio.printf("[Phase1] _sha1_map.txt 不存在或为空,从扫描结果生成\n")
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, None, 0)
set_count = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set)
if set_count < 0:
stdio.printf("[Phase1] 无法加载 _sha1_map.txt跳过 Phase1\n")
return 1
stdio.printf("[Phase1] includes SHA1 集合: %d\n", set_count)
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
td_len_p1map: t.CSizeT = string.strlen(temp_dir)
p1_sha1_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
p1_mod_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
p1_inc_count: int = 0
if p1_sha1_arr is not None and p1_mod_arr is not None:
p1_inc_count = StubMerger._BuildIncludesSha1Map(temp_dir, td_len_p1map, p1_sha1_arr, p1_mod_arr)
HandlesExprCall.set_module_sha1_map(p1_sha1_arr, p1_mod_arr, p1_inc_count)
# 初始化 AST 表(只需一次)
ast._init_tables(mb)
# FileEntry 结构体大小Phase 1a 和 1b 共用)
entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
# ============================================================
# Phase 1a-pre: 扫描所有 includes 文件的 import 依赖
#
# 只处理 Import/ImportFrom 语句,跳过 ClassDef/FunctionDef 等,
# 不调用 resolve_annotation_type避免 list[...] 等不支持的语法触发 crash。
# 生成 .deps.txt 供依赖图按需翻译使用。
# ============================================================
stdio.printf("[Phase1a-pre] 扫描 import 依赖\n")
p1a_registered: int = 0
p1a_skipped: int = 0
p1a_failed: int = 0
for i in range(result.Count):
entry_addr_a: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
entry_a: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_a, t.CPtr))
if entry_a is None:
p1a_failed += 1
continue
sha1_a: str = entry_a.Sha1
if sha1_a is None:
p1a_failed += 1
continue
if StubMerger._is_in_sha1_set(sha1_a, sha1_set, set_count) == 0:
p1a_skipped += 1
continue
# 读取文件内容
file_path_a: str = entry_a.Path
f_a: fileio.File | t.CPtr = fileio.File(file_path_a, fileio.MODE.R)
if f_a.closed:
p1a_failed += 1
continue
src_buf_a: bytes = stdlib.malloc(SRC_BUF_SIZE)
if src_buf_a is None:
f_a.close()
p1a_failed += 1
continue
bytes_read_a: LONG = f_a.read_all(src_buf_a, SRC_BUF_SIZE)
f_a.close()
if bytes_read_a <= 0:
stdlib.free(src_buf_a)
p1a_failed += 1
continue
if bytes_read_a < SRC_BUF_SIZE:
src_buf_a[bytes_read_a] = 0
else:
src_buf_a[SRC_BUF_SIZE - 1] = 0
# 解析 AST
lx_a: ast.Lexer | t.CPtr = ast.new_lexer(mb)
if lx_a is None:
stdlib.free(src_buf_a)
p1a_failed += 1
continue
ast._lexer_init(lx_a, src_buf_a, mb)
tokens_a: ast.Token | t.CPtr = ast.tokenize(lx_a)
tree_a: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_a)
if tree_a is None:
stdlib.free(src_buf_a)
p1a_failed += 1
continue
# 创建 Translator设置 _declare_only=2只扫描 import跳过 ClassDef
tr_a: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
if tr_a is None:
stdlib.free(src_buf_a)
p1a_failed += 1
continue
tr_a.ModuleSha1 = sha1_a
tr_a._declare_only = 2
tr_a.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_a.RelPath)
HandlesType.set_current_file(file_path_a)
HandlesType.clear_cdefine_constants()
HandlesStruct.reset_visible_structs(mb, 0)
ret_a: int = tr_a.translate(tree_a)
if ret_a != 0:
p1a_failed += 1
else:
p1a_registered += 1
# 生成 .deps.txt记录依赖模块名供依赖图按需翻译使用
td_len_a: t.CSizeT = string.strlen(temp_dir)
deps_path_a: bytes = stdlib.malloc(td_len_a + 32)
if deps_path_a is not None:
viperlib.snprintf(deps_path_a, td_len_a + 32, "%s/%s.deps.txt", temp_dir, sha1_a)
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)
# 释放 Translator 的 C malloc 资源
if tr_a._global_names is not None:
stdlib.free(tr_a._global_names)
if tr_a._nonlocal_names is not None:
stdlib.free(tr_a._nonlocal_names)
stdlib.free(src_buf_a)
stdio.printf("[Phase1a-pre] 完成: 扫描=%d 跳过=%d 失败=%d\n", p1a_registered, p1a_skipped, p1a_failed)
# ============================================================
# 依赖图按需翻译:构建可达 SHA1 集合
#
# 从 Config.SourceDir 的源文件开始,解析 import 语句,递归收集
# 可达的 includes 文件 SHA1。Phase 1b 只翻译可达集合中的文件,
# 避免翻译不需要的 includes如 Test 不依赖 llvmlite则不翻译
# 如果 Config.SourceDir 不可用(仅运行 Phase1回退到 sha1_set。
# ============================================================
reachable_set: str = None
reachable_count: int = 0
use_reachable: int = 0
if Config.SourceDir is not None:
reachable_set = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17)
if reachable_set is not None:
string.memset(reachable_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
reachable_count = StubMerger._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set)
if reachable_count > 0:
use_reachable = 1
stdio.printf("[Phase1b] 使用可达 SHA1 集合过滤: %d\n", reachable_count)
# 用可达集合重新生成 _sha1_map.txt按图求索的最终产物
# Phase B+ 只遍历这些条目,避免编译不需要的 includes如 asm.py
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, reachable_set, reachable_count)
# 重新加载 sha1_set使后续 Phase 1a-pre/1a/1b 的过滤也使用可达集合
string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
set_count = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set)
stdio.printf("[Phase1b] _sha1_map.txt 已重写为可达集合: %d\n", set_count)
else:
stdio.printf("[Phase1b] 可达 SHA1 集合构建失败,回退到全量集合\n")
stdlib.free(reachable_set)
reachable_set = None
# ============================================================
# Phase 1a: 注册可达 includes 文件的 struct/enum/union
#
# 解决字母序依赖问题:按字母顺序翻译时,后面的 struct 未注册
# 前面就需要用。Phase 1a 先注册所有 struct/enum/union 到全局表,
# Phase 1b 全量翻译时 struct 已注册,走 existing 路径只翻译方法体。
# 只处理可达文件,避免翻译不需要的 includes如 Test 不依赖 ast 模块)。
# ============================================================
stdio.printf("[Phase1a] 注册可达文件 struct/enum/union\n")
stdio.fflush(0)
p1a_reg: int = 0
p1a_skp: int = 0
p1a_fl: int = 0
for i in range(result.Count):
entry_addr_r: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
entry_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_r, t.CPtr))
if entry_r is None:
p1a_fl += 1
continue
sha1_r: str = entry_r.Sha1
if sha1_r is None:
p1a_fl += 1
continue
# 按需翻译过滤:只处理可达文件
if use_reachable != 0:
if StubMerger._is_in_sha1_set(sha1_r, reachable_set, reachable_count) == 0:
p1a_skp += 1
continue
else:
if StubMerger._is_in_sha1_set(sha1_r, sha1_set, set_count) == 0:
p1a_skp += 1
continue
# 读取文件内容
file_path_r: str = entry_r.Path
f_r: fileio.File | t.CPtr = fileio.File(file_path_r, fileio.MODE.R)
if f_r.closed:
p1a_fl += 1
continue
src_buf_r: bytes = stdlib.malloc(SRC_BUF_SIZE)
if src_buf_r is None:
f_r.close()
p1a_fl += 1
continue
bytes_read_r: LONG = f_r.read_all(src_buf_r, SRC_BUF_SIZE)
f_r.close()
if bytes_read_r <= 0:
stdlib.free(src_buf_r)
p1a_fl += 1
continue
if bytes_read_r < SRC_BUF_SIZE:
src_buf_r[bytes_read_r] = 0
else:
src_buf_r[SRC_BUF_SIZE - 1] = 0
# 解析 AST
lx_r: ast.Lexer | t.CPtr = ast.new_lexer(mb)
if lx_r is None:
stdlib.free(src_buf_r)
p1a_fl += 1
continue
ast._lexer_init(lx_r, src_buf_r, mb)
tokens_r: ast.Token | t.CPtr = ast.tokenize(lx_r)
tree_r: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens_r)
if tree_r is None:
stdlib.free(src_buf_r)
p1a_fl += 1
continue
# 创建 Translator设置 _declare_only=1注册 struct/enum/union
tr_r: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
if tr_r is None:
stdlib.free(src_buf_r)
p1a_fl += 1
continue
tr_r.ModuleSha1 = sha1_r
tr_r._declare_only = 1
tr_r.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_r.RelPath)
HandlesType.set_current_file(file_path_r)
HandlesType.clear_cdefine_constants()
HandlesStruct.reset_visible_structs(mb, 0)
ret_r: int = tr_r.translate(tree_r)
if ret_r != 0:
p1a_fl += 1
else:
p1a_reg += 1
# 释放 Translator 的 C malloc 资源
if tr_r._global_names is not None:
stdlib.free(tr_r._global_names)
if tr_r._nonlocal_names is not None:
stdlib.free(tr_r._nonlocal_names)
stdlib.free(src_buf_r)
stdio.printf("[Phase1a] 完成: 注册=%d 跳过=%d 失败=%d\n", p1a_reg, p1a_skp, p1a_fl)
# ============================================================
# Phase 1b: 全量翻译struct 已注册,走 existing 路径翻译方法体)
# ============================================================
# 遍历每个文件
translated: int = 0
skipped: int = 0
failed: int = 0
for i in range(result.Count):
# 获取 entry
entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry is None:
failed += 1
continue
sha1: str = entry.Sha1
if sha1 is None:
failed += 1
continue
# 检查 SHA1 是否在翻译集合中(按需翻译:只翻译可达的文件)
if use_reachable != 0:
if StubMerger._is_in_sha1_set(sha1, reachable_set, reachable_count) == 0:
skipped += 1
continue
else:
if StubMerger._is_in_sha1_set(sha1, sha1_set, set_count) == 0:
skipped += 1
continue
# 构造 stub 路径: {temp_dir}/{sha1}.stub.ll
dir_len: t.CSizeT = string.strlen(temp_dir)
sha1_len: t.CSizeT = string.strlen(sha1)
stub_path: bytes = stdlib.malloc(dir_len + sha1_len + 16)
if stub_path is None:
failed += 1
continue
viperlib.snprintf(stub_path, dir_len + sha1_len + 16, "%s/%s.stub.ll", temp_dir, sha1)
# 检查 stub 是否已存在(按需翻译:跳过已存在的)
sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R)
if not sf.closed:
sf.close()
# 检查 text.ll 是否也存在(虚表扫描需要 text.ll
text_path: bytes = stdlib.malloc(dir_len + sha1_len + 16)
if text_path is not None:
viperlib.snprintf(text_path, dir_len + sha1_len + 16, "%s/%s.text.ll", temp_dir, sha1)
tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
if not tf.closed:
tf.close()
stdlib.free(text_path)
stdlib.free(stub_path)
continue
stdlib.free(text_path)
# text.ll 不存在,需要重新翻译
stdio.printf("[Phase1] text.ll 不存在,重新翻译: %s (sha1=%s)\n", entry.RelPath, sha1)
else:
# stub 不存在,需要翻译
stdio.printf("[Phase1] 翻译: %s (sha1=%s)\n", entry.RelPath, sha1)
stdlib.free(stub_path)
# 读取文件内容
file_path: str = entry.Path
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
if f.closed:
stdio.printf("[Phase1] 无法打开: %s\n", file_path)
failed += 1
continue
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
if src_buf is None:
f.close()
failed += 1
continue
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
f.close()
if bytes_read <= 0:
stdio.printf("[Phase1] 读取失败: %s\n", file_path)
stdlib.free(src_buf)
failed += 1
continue
if bytes_read < SRC_BUF_SIZE:
src_buf[bytes_read] = 0
else:
src_buf[SRC_BUF_SIZE - 1] = 0
# 解析 AST
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
if lx is None:
stdlib.free(src_buf)
failed += 1
continue
ast._lexer_init(lx, src_buf, mb)
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
if tree is None:
stdio.printf("[Phase1] AST 解析失败: %s\n", file_path)
stdlib.free(src_buf)
failed += 1
continue
# 翻译 AST → LLVM IR
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
if tr is None:
stdlib.free(src_buf)
failed += 1
continue
tr.ModuleSha1 = sha1
tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry.RelPath)
HandlesType.set_current_file(file_path)
HandlesType.clear_cdefine_constants()
HandlesStruct.reset_visible_structs(mb, 0)
ret: int = tr.translate(tree)
if ret != 0:
stdio.printf("[Phase1] 翻译失败: %s\n", file_path)
stdlib.free(src_buf)
if tr._global_names is not None:
stdlib.free(tr._global_names)
if tr._nonlocal_names is not None:
stdlib.free(tr._nonlocal_names)
failed += 1
continue
# dump stub IR (declarations only)
PHASE1_IR_SIZE: t.CSizeT = 262144
stub_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE)
if stub_buf is None:
stdlib.free(src_buf)
if tr._global_names is not None:
stdlib.free(tr._global_names)
if tr._nonlocal_names is not None:
stdlib.free(tr._nonlocal_names)
failed += 1
continue
tr.dump_ir(stub_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_STUB)
stub_len: t.CSizeT = string.strlen(stub_buf)
# save stub.ll
dir_len_p1: t.CSizeT = string.strlen(temp_dir)
stub_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32)
if stub_path_p1 is not None:
viperlib.snprintf(stub_path_p1, dir_len_p1 + 32, "%s/%s.stub.ll", temp_dir, sha1)
sf_p1: fileio.File | t.CPtr = fileio.File(stub_path_p1, fileio.MODE.W)
if not sf_p1.closed:
sf_p1.write(stub_buf, stub_len)
sf_p1.close()
stdlib.free(stub_path_p1)
stdlib.free(stub_buf)
# dump text IR (definitions only)
text_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE)
if text_buf is None:
stdlib.free(src_buf)
if tr._global_names is not None:
stdlib.free(tr._global_names)
if tr._nonlocal_names is not None:
stdlib.free(tr._nonlocal_names)
failed += 1
continue
tr.dump_ir(text_buf, PHASE1_IR_SIZE, llvmlite.OUTPUT_TEXT)
text_len: t.CSizeT = string.strlen(text_buf)
# save text.ll
text_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32)
if text_path_p1 is not None:
viperlib.snprintf(text_path_p1, dir_len_p1 + 32, "%s/%s.text.ll", temp_dir, sha1)
tf_p1: fileio.File | t.CPtr = fileio.File(text_path_p1, fileio.MODE.W)
if not tf_p1.closed:
tf_p1.write(text_buf, text_len)
tf_p1.close()
stdlib.free(text_path_p1)
stdlib.free(text_buf)
# save dependencies (_imported_modules) for Phase B
deps_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32)
if deps_path_p1 is not None:
viperlib.snprintf(deps_path_p1, dir_len_p1 + 32, "%s/%s.deps.txt", temp_dir, sha1)
df_p1: fileio.File | t.CPtr = fileio.File(deps_path_p1, fileio.MODE.W)
if not df_p1.closed:
if tr._imported_modules is not None:
dl: t.CSizeT = string.strlen(tr._imported_modules)
df_p1.write(tr._imported_modules, dl)
df_p1.close()
stdlib.free(deps_path_p1)
# 释放 Translator 的 C malloc 资源
if tr._global_names is not None:
stdlib.free(tr._global_names)
if tr._nonlocal_names is not None:
stdlib.free(tr._nonlocal_names)
# 所有 dump_ir 完成src_buf 不再需要
stdlib.free(src_buf)
translated += 1
stdio.printf("[Phase1] 完成: 翻译=%d 跳过=%d 失败=%d\n", translated, skipped, failed)
# 释放可达 SHA1 集合(如果分配了)
if reachable_set is not None:
stdlib.free(reachable_set)
return 0

View File

@@ -0,0 +1,680 @@
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.BuildPipeline as BuildPipeline
import lib.core.StubMerger as StubMerger
import lib.Projectrans.Utils as Utils
import lib.Projectrans.Config as Config
# 全局 mbuddy 指针
_mbuddy: memhub.MemManager | t.CPtr
# 源代码缓冲区大小1MB
SRC_BUF_SIZE: t.CDefine = 1048576
# 最大源文件数(递归扫描子目录后文件数增多,增大到 64
MAX_SRC_FILES: t.CDefine = 64
@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
stdio.printf("[project] %s (sha1=%s)\n", fname, sha1_val)
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:
stdio.printf("[project] source_dir 为空\n")
return 1
stdio.printf("[project] 多文件项目编译: %s\n", source_dir)
# === 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)
stdio.printf("[project] 共 %d 个源文件\n", file_count)
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)
# 追加 App 源文件 SHA1 到 _sha1_map.txt供日志转存和符号查找使用
# 格式: {sha1}:App/{filename}\n (与 includes 条目格式对应)
td_len_am: t.CSizeT = string.strlen(temp_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)
if not mf.closed:
line_am: bytes = stdlib.malloc(512)
if line_am is not None:
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
# 从路径提取文件名(最后一个 / 或 \\ 之后的部分)
p_str: str = ent_am.Path
p_len: t.CSizeT = string.strlen(p_str)
f_start: t.CSizeT = 0
for j in range(p_len):
if p_str[j] == '/' or p_str[j] == '\\':
f_start = j + 1
viperlib.snprintf(line_am, 512, "%s:App/%s\n", ent_am.Sha1, p_str + f_start)
ll_am: t.CSizeT = string.strlen(line_am)
mf.write(line_am, ll_am)
stdlib.free(line_am)
mf.close()
stdio.printf("[project] 已追加 %d 个 App 文件到 _sha1_map.txt\n", file_count)
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:
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
# 从路径提取模块名(文件名去掉 .py 后缀)
path_str: str = ent_us.Path
path_len: t.CSizeT = string.strlen(path_str)
fname_start: t.CSizeT = 0
for j in range(path_len):
if path_str[j] == '/' or path_str[j] == '\\':
fname_start = j + 1
mod_len: t.CSizeT = path_len - fname_start
if mod_len < 4:
continue
mod_len -= 3
if mod_len >= 64:
mod_len = 63
# 写入模块名
mod_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 64
for k in range(mod_len):
pb_mod_arr[mod_idx + k] = path_str[fname_start + k]
pb_mod_arr[mod_idx + mod_len] = '\0'
# 写入 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 ===
if do_phase1 != 0:
if log is not None:
log.banner("Phase A: 生成 stub + text")
PHASE_A_IR_SIZE: t.CSizeT = 262144
td_len_pa: t.CSizeT = string.strlen(temp_dir)
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
stub_path_a: bytes = stdlib.malloc(td_len_pa + 32)
if stub_path_a is not None:
viperlib.snprintf(stub_path_a, td_len_pa + 32, "%s/%s.stub.ll", temp_dir, ent.Sha1)
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: bytes = stdlib.malloc(td_len_pa + 32)
if text_path_a is not None:
viperlib.snprintf(text_path_a, td_len_pa + 32, "%s/%s.text.ll", temp_dir, ent.Sha1)
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: bytes = stdlib.malloc(td_len_pa + 32)
if deps_path_a is not None:
viperlib.snprintf(deps_path_a, td_len_pa + 32, "%s/%s.deps.txt", temp_dir, ent.Sha1)
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)
if do_phase2 == 0:
stdio.printf("[project] Phase A 完成(仅 stub 生成)\n")
stdlib.free(entries)
return 0
# === 3. Phase B: 编译每个文件为 .obj ===
if do_phase2 != 0:
if log is not None:
log.banner("Phase B: 编译 .obj")
# 收集 .obj 路径
OBJ_PATHS_SIZE: t.CSizeT = 8192
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
stdio.printf("[Phase B] %s\n", ent.Path)
# 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR
stdio.printf("[Phase B] malloc %d bytes...\n", COMBINED_IR_SIZE)
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
if combined_ir is None:
stdio.printf("[Phase B] combined_ir 分配失败: %s\n", ent.Path)
continue
stdio.printf("[Phase B] malloc OK, calling BuildCombinedIR...\n")
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
if combined_len == 0:
stdio.printf("[Phase B] BuildCombinedIR 失败: %s\n", ent.Path)
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:
stdio.printf("[FATAL][Phase B] llc 编译失败,终止编译: %s\n", ent.Path)
sys.exit(1)
compiled_count += 1
# 构造 .obj 路径,检测是否是 main 模块test_main.py 或 main.py
od_len: t.CSizeT = string.strlen(output_dir)
sha1_len: t.CSizeT = string.strlen(ent.Sha1)
need: t.CSizeT = od_len + 1 + sha1_len + 6
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
if is_main_mod != 0:
viperlib.snprintf(main_obj_path, 512, "%s/%s.obj", output_dir, ent.Sha1)
else:
if obj_pos + need < OBJ_PATHS_SIZE:
if obj_pos > 0:
obj_paths[obj_pos] = ' '
obj_pos += 1
viperlib.snprintf(obj_paths + obj_pos, need, "%s/%s.obj", output_dir, ent.Sha1)
obj_pos += od_len + 1 + sha1_len + 4
obj_paths[obj_pos] = '\0'
else:
stdio.printf("[Phase B] 警告: .obj 路径缓冲区不足\n")
stdio.printf("[Phase B] 编译完成: %d/%d\n", compiled_count, file_count)
if compiled_count == 0:
stdio.printf("[Phase B] 无成功编译的文件\n")
stdlib.free(entries)
return 1
# === 3.5 编译缺失的 includes 文件 ===
# includes.binary 可能缺少某些 includes .obj如 testcheck.py
# 这些文件被用户项目导入但未被 TransPyV 自身依赖Projectrans.py 未编译它们。
# 检测并编译缺失的 includes 文件到 output_dir加入链接命令。
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)
map_path_mi: bytes = stdlib.malloc(td_len_mi + 32)
if map_path_mi is not None:
viperlib.snprintf(map_path_mi, td_len_mi + 32, "%s/_sha1_map.txt", temp_dir)
mapf_mi: fileio.File | t.CPtr = fileio.File(map_path_mi, fileio.MODE.R)
if not mapf_mi.closed:
map_buf_mi: bytes = stdlib.malloc(65536)
if map_buf_mi is not None:
map_br_mi: t.CInt64T = mapf_mi.read_all(map_buf_mi, 65536)
mapf_mi.close()
if map_br_mi > 0:
if map_br_mi < 65536:
map_buf_mi[map_br_mi] = '\0'
else:
map_buf_mi[65535] = '\0'
map_len_mi: t.CSizeT = map_br_mi
mpos_mi: t.CSizeT = 0
while mpos_mi < map_len_mi:
ml_start_mi: t.CSizeT = mpos_mi
while mpos_mi < map_len_mi:
if map_buf_mi[mpos_mi] == '\n':
break
mpos_mi += 1
ml_len_mi: t.CSizeT = mpos_mi - ml_start_mi
mpos_mi += 1
# 最小长度: 16(sha1)+1(:)+9(includes/)+1+1+1 = 29
if ml_len_mi < 26:
continue
if map_buf_mi[ml_start_mi + 16] != ':':
continue
rp_start_mi: t.CSizeT = ml_start_mi + 17
if string.strncmp(map_buf_mi + rp_start_mi, "includes/", 9) != 0:
continue
# 提取 SHA1
inc_sha1_mi: str = stdlib.malloc(17)
if inc_sha1_mi is None:
continue
string.strncpy(inc_sha1_mi, map_buf_mi + ml_start_mi, 16)
inc_sha1_mi[16] = '\0'
# 检查 .obj 是否已存在于 includes.binary
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
check_pat_mi: bytes = stdlib.malloc(ibd_len_mi + 35)
if check_pat_mi is None:
continue
viperlib.snprintf(check_pat_mi, ibd_len_mi + 35, "%s/%s*.obj", includes_binary_dir, inc_sha1_mi)
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_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:
continue
# .obj 不存在,需要编译
# 构造源文件路径: {includes_dir}/{rel_path_without_includes_prefix}
rel_path_len_mi: t.CSizeT = ml_len_mi - 26
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:
continue
viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1,
"%s/%s", includes_dir, map_buf_mi + rp_start_mi + 9)
# 检查是否为声明文件(只有 declare 没有实质 define
# 判断方法: text.ll 中若有混淆函数 define含 @\")则为实现文件
is_decl_mi: int = -1
tpath_mi: bytes = stdlib.malloc(td_len_mi + 32)
if tpath_mi is not None:
viperlib.snprintf(tpath_mi, td_len_mi + 32, "%s/%s.text.ll", temp_dir, inc_sha1_mi)
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 使用
saved_mi: t.CChar = tbuf_mi[tls_mi + tll_mi]
tbuf_mi[tls_mi + tll_mi] = '\0'
if string.strstr(tbuf_mi + tls_mi, "@\"") is not None:
tbuf_mi[tls_mi + tll_mi] = saved_mi
is_decl_mi = 0
break
tbuf_mi[tls_mi + tll_mi] = saved_mi
stdlib.free(tbuf_mi)
tf_mi.close()
stdlib.free(tpath_mi)
if is_decl_mi == 1:
stdio.printf("[Phase B+] 跳过(声明文件): %s (sha1=%s)\n", src_fp_mi, inc_sha1_mi)
continue
stdio.printf("[Phase B+] 编译缺失 includes: %s (sha1=%s)\n", src_fp_mi, inc_sha1_mi)
# 尝试 BuildCombinedIRstub/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:
stdio.printf("[Phase B+] stub/text 不存在,翻译: %s\n", src_fp_mi)
# 计算 includes 文件的包名(相对 includes_dir 的目录部分)
inc_pkg_mi: str = None
if string.strlen(src_fp_mi) > inc_dir_len_mi + 1:
inc_rel_mi: str = src_fp_mi + inc_dir_len_mi + 1
inc_pkg_mi = HandlesImports.compute_package_from_relpath(mb, inc_rel_mi)
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 = 262144
# 保存 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: bytes = stdlib.malloc(td_len_mi + 32)
if inc_stub_path is not None:
viperlib.snprintf(inc_stub_path, td_len_mi + 32, "%s/%s.stub.ll", temp_dir, inc_sha1_mi)
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: bytes = stdlib.malloc(td_len_mi + 32)
if inc_text_path is not None:
viperlib.snprintf(inc_text_path, td_len_mi + 32, "%s/%s.text.ll", temp_dir, inc_sha1_mi)
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:
stdio.printf("[Phase B+] BuildCombinedIR 失败: %s\n", src_fp_mi)
if inc_combined_mi is not None:
stdlib.free(inc_combined_mi)
continue
# 编译为 .obj
inc_cret_mi: int = BuildPipeline.compile_module_to_obj(
inc_combined_mi, inc_combined_len_mi, temp_dir, output_dir, inc_sha1_mi,
cc_cmd, cc_flags)
stdlib.free(inc_combined_mi)
if inc_cret_mi != 0:
stdio.printf("[FATAL][Phase B+] llc 编译失败,终止编译: %s\n", src_fp_mi)
sys.exit(1)
inc_compiled += 1
# 添加到 obj_paths
od_len_mi: t.CSizeT = string.strlen(output_dir)
sha1_len_mi: t.CSizeT = 16
need_mi: t.CSizeT = od_len_mi + 1 + sha1_len_mi + 6
if obj_pos + need_mi < OBJ_PATHS_SIZE:
if obj_pos > 0:
obj_paths[obj_pos] = ' '
obj_pos += 1
viperlib.snprintf(obj_paths + obj_pos, need_mi, "%s/%s.obj", output_dir, inc_sha1_mi)
obj_pos += od_len_mi + 1 + sha1_len_mi + 4
obj_paths[obj_pos] = '\0'
stdio.printf("[Phase B+] 编译缺失 includes: %d\n", inc_compiled)
# === 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
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:
stdio.printf("输出: %s\n", exe_path)
if args.get_bool("run"):
stdio.printf("[run] 执行: %s\n", exe_path)
rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
if rp is not None:
stdio.printf("[run] 退出码: %d\n", rp.returncode)
else:
stdio.printf("[Phase C] 链接失败\n")
stdlib.free(entries)
return 1
stdlib.free(entries)
return 0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
import t, c
from stdint import *
import stdio
import memhub
import w32.win32console as w32cmd
import w32.win32file as w32file
import w32.win32base as w32base
# ============================================================
# VLogger - 原生日志系统Windows 控制台彩色输出)
# ============================================================
# 日志级别
class LogLevel(t.CEnum):
DEBUG = 0
INFO = 1
WARNING = 2
ERROR = 3
SUCCESS = 4
# 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
class Logger:
_level: int
_console_handle: w32base.HANDLE
_use_color: int
__mbuddy__: memhub.MemManager | 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:
if self._use_color:
return w32cmd.SetConsoleTextAttribute(self._console_handle, attr)
return 0
def _reset_color(self) -> int:
if self._use_color:
return w32cmd.SetConsoleTextAttribute(self._console_handle, FOREGROUND_WHITE)
return 0
def _log(self, level: int, prefix: str, msg: str, color: WORD,
category: str = "") -> int:
if level < self._level:
return 0
self._set_color(color)
if category is not None:
if category[0] != 0:
stdio.printf("%s[%s] %s\n", prefix, category, msg)
else:
stdio.printf("%s %s\n", prefix, msg)
else:
stdio.printf("%s %s\n", prefix, msg)
self._reset_color()
return 0
def debug(self, msg: str, category: str = "") -> int:
return self._log(LogLevel.DEBUG, "[DEBUG]", msg,
FOREGROUND_INTENSITY, category)
def info(self, msg: str, category: str = "") -> int:
return self._log(LogLevel.INFO, "[INFO]", msg,
FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
def warning(self, msg: str, category: str = "") -> int:
return self._log(LogLevel.WARNING, "[WARN]", msg,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
category)
def error(self, msg: str, category: str = "") -> int:
return self._log(LogLevel.ERROR, "[ERROR]", msg,
FOREGROUND_RED | FOREGROUND_INTENSITY, category)
def success(self, msg: str, category: str = "") -> int:
return self._log(LogLevel.SUCCESS, "[SUCCESS]", msg,
FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
def set_level(self, level: int) -> int:
self._level = level
return 0
# ============================================================
# 高级日志方法
# ============================================================
def banner(self, msg: str) -> int:
"""输出分节标题(青色高亮)。"""
self._set_color(FOREGROUND_CYAN | 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.MemManager | t.CPtr
# 全局 logger 指针
_g_logger: Logger | t.CPtr
def get_logger() -> Logger | t.CPtr:
"""获取全局 logger 实例。若不存在则通过 _mbuddy 分配并初始化。"""
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._level = LogLevel.INFO
_g_logger._console_handle = w32file.GetStdHandle(w32file.STD_OUTPUT_HANDLE)
_g_logger._use_color = 1
_g_logger.__mbuddy__ = _mbuddy
return _g_logger
def set_logger(logger: Logger | t.CPtr) -> int:
"""设置全局 logger 实例。"""
_g_logger = logger
return 0

View File

@@ -0,0 +1,9 @@
import t, c
from stdint import *
# ============================================================
# core 包入口
#
# 子模块通过绝对导入使用import lib.core.X as X
# 此 __init__.py 不做 re-export避免引入未使用的依赖。
# ============================================================

510
TransPyV/App/main.py Normal file
View File

@@ -0,0 +1,510 @@
import t, c
from stdint import *
import stdio
import string
import stdlib
import memhub
import argparse
import w32.win32console as w32cmd
import w32.fileio as fileio
import w32.win32file
import w32.win32base
import sys
import ast
import lib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HandlesTranslator
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.BuildPipeline as BuildPipeline
import lib.core.IncludesScanner as IncludesScanner
import lib.core.StubMerger as StubMerger
import lib.core.Phase1 as Phase1
import lib.core.Phase2 as Phase2
import lib.Projectrans.Config as Config
import lib.Projectrans.Utils as Utils
import llvmlite
import subprocess
import viperlib
import hashlib
# 内存大小: fl_bytes=264 (33*8), POOL_SIZE-fl_bytes 必须是 2 的幂以避免浪费
# 1073742088 - 264 = 1073741824 (1024MB usable = 2^30)
# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件512MB 不足导致 Phase2 崩溃
POOL_SIZE: t.CDefine = 1073741824
# 语言编码页
CODE_PAGE: t.CDefine = 65001
# 源代码缓冲区大小1MB
SRC_BUF_SIZE: t.CDefine = 1048576
# ============================================================
# main: 命令行入口
#
# 解析参数 → 加载配置 → AST 解析 → LLVM IR 翻译 → 编译管线 → 可选执行
# ============================================================
def main() -> int:
w32cmd.SetConsoleOutputCP(CODE_PAGE)
w32cmd.SetConsoleCP(CODE_PAGE)
# 初始化 mbuddy 内存池
arena: bytes = stdlib.malloc(POOL_SIZE)
if arena is None:
stdio.printf("FAIL: malloc for arena failed\n")
return 1
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE)
if mb is None:
stdio.printf("FAIL: MemBuddy init failed\n")
return 1
# 设置全局 mbuddy 指针sys 和 argparse 都需要)
sys._mbuddy = mb
argparse._mbuddy = mb
ast._mbuddy = mb
lib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
Config._mbuddy = (memhub.MemManager | t.CPtr)(mb)
Utils._mbuddy = (memhub.MemManager | t.CPtr)(mb)
HandlesTranslator._mbuddy = mb
BuildPipeline._mbuddy = (memhub.MemManager | t.CPtr)(mb)
IncludesScanner._mbuddy = (memhub.MemManager | t.CPtr)(mb)
StubMerger._mbuddy = (memhub.MemManager | t.CPtr)(mb)
Phase1._mbuddy = (memhub.MemManager | t.CPtr)(mb)
Phase2._mbuddy = (memhub.MemManager | t.CPtr)(mb)
subprocess._mbuddy = mb
hashlib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
lib.InitLib((memhub.MemManager | t.CPtr)(mb))
# 初始化 VLogger 并打印启动日志
log: VLogger.Logger | t.CPtr = VLogger.get_logger()
if log is not None:
log.info("TransPyV 启动")
# 初始化命令行参数Windows: GetCommandLineA, POSIX: /proc/self/cmdline
sys._init_argv()
# 创建参数解析器
parser: argparse.ArgumentParser | t.CPtr = argparse.ArgumentParser(
"TransPyV", "TransPyV 命令行参数解析", pool=mb)
# 注册参数(与 Projectrans.py main() 一致)
parser.add_argument("--project", None, argparse.STRING, 0, None, False,
argparse.STORE, "project.json 路径(默认查找当前目录)")
parser.add_argument("--src", None, argparse.STRING, 0, None, False,
argparse.STORE, "源文件目录(覆盖 project.json")
parser.add_argument("--temp", None, argparse.STRING, 0, None, False,
argparse.STORE, "声明接口临时目录(覆盖 project.json")
parser.add_argument("--output", None, argparse.STRING, 0, None, False,
argparse.STORE, "输出目录(覆盖 project.json")
parser.add_argument("--phase", None, argparse.STRING, 0, None, False,
argparse.STORE, "阶段: 1=生成声明, 2=翻译+编译, all=全部")
parser.add_argument("--cc", None, argparse.STRING, 0, None, False,
argparse.STORE, "LLVM 编译器命令(覆盖 project.json")
parser.add_argument("--clean", None, argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "清理 output 和 temp 目录")
parser.add_argument("--run", None, argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "编译成功后立即执行生成的可执行文件")
parser.add_argument("--rebuild-includes", None, argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "删除 includes.binary 预编译缓存并重新编译所有 includes")
parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False,
argparse.STORE_TRUE, "清除 .transpyc_cache 全局缓存")
# 解析命令行参数
args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv)
if args is None:
if log is not None:
log.error("参数解析失败", "argparse")
return 1
# 打印解析结果
if log is not None:
log.banner("TransPyV 参数解析结果")
# 字符串参数
project: str = args.get_str("project")
if project is not None:
stdio.printf(" --project: %s\n", project)
else:
stdio.printf(" --project: (未指定)\n")
src: str = args.get_str("src")
if src is not None:
stdio.printf(" --src: %s\n", src)
else:
stdio.printf(" --src: (未指定)\n")
temp: str = args.get_str("temp")
if temp is not None:
stdio.printf(" --temp: %s\n", temp)
else:
stdio.printf(" --temp: (未指定)\n")
output: str = args.get_str("output")
if output is not None:
stdio.printf(" --output: %s\n", output)
else:
stdio.printf(" --output: (未指定)\n")
phase: str = args.get_str("phase")
if phase is not None:
stdio.printf(" --phase: %s\n", phase)
else:
stdio.printf(" --phase: (未指定,默认 all)\n")
cc: str = args.get_str("cc")
if cc is not None:
stdio.printf(" --cc: %s\n", cc)
else:
stdio.printf(" --cc: (未指定)\n")
# 布尔参数
_gb_clean: INT = args.get_bool("clean")
if _gb_clean:
stdio.printf(" --clean: True\n")
else:
stdio.printf(" --clean: False\n")
if args.get_bool("run"):
stdio.printf(" --run: True\n")
else:
stdio.printf(" --run: False\n")
if args.get_bool("rebuild-includes"):
stdio.printf(" --rebuild-includes: True\n")
else:
stdio.printf(" --rebuild-includes: False\n")
if args.get_bool("clear-cache"):
stdio.printf(" --clear-cache: True\n")
else:
stdio.printf(" --clear-cache: False\n")
stdio.printf("\n参数解析完成。\n")
# 加载 project.vpj 配置
proj_loaded: int = 0
proj_path: str = project
if proj_path is not None:
if log is not None:
log.banner("工程配置")
if Config.Load_project_config(proj_path) == 0:
proj_loaded = 1
else:
stdio.printf(" 警告: 无法加载 project.vpj: %s\n", proj_path)
else:
# 尝试默认路径 project.vpj当前目录和上级目录
proj_path = "project.vpj"
if Config.Load_project_config(proj_path) == 0:
proj_loaded = 1
else:
proj_path = "../project.vpj"
if Config.Load_project_config(proj_path) == 0:
proj_loaded = 1
if proj_loaded == 1:
# 提取 project.vpj 所在目录,将相对路径解析为基于该目录的路径
proj_len: t.CSizeT = string.strlen(proj_path)
slash_pos: t.CSizeT = proj_len
for i in range(proj_len):
idx: t.CSizeT = proj_len - 1 - i
ch: t.CChar = proj_path[idx]
if ch == '/' or ch == '\\':
slash_pos = idx
break
proj_dir: str = ""
if slash_pos > 0 and slash_pos < proj_len:
proj_dir = stdlib.malloc(slash_pos + 1)
if proj_dir is not None:
string.memcpy(proj_dir, proj_path, slash_pos)
proj_dir[slash_pos] = '\0'
Config.resolve_paths(proj_dir)
Config.print_config()
# === --clean: 清理 temp 和 output 目录 ===
if _gb_clean:
stdio.printf("\n[clean] 清理临时目录...\n")
if Config.TempDir is not None:
n: int = Utils.CleanDir(Config.TempDir)
stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.TempDir, n)
if Config.OutputDir is not None:
n2: int = Utils.CleanDir(Config.OutputDir)
stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.OutputDir, n2)
# === --phase 参数控制 ===
# phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll不编译
# phase=2: 仅 stub 合并 + 编译(跳过 stub 分离)
# phase=all: 两者都执行(默认)
phase_mode: str = phase
if phase_mode is None:
phase_mode = "all"
do_phase1: int = 0
do_phase2: int = 0
if phase_mode == "1" or phase_mode == "all":
do_phase1 = 1
if phase_mode == "2" or phase_mode == "all":
do_phase2 = 1
stdio.printf("[phase] 模式: %s (phase1=%d phase2=%d)\n", phase_mode, do_phase1, do_phase2)
# === Phase1: 扫描 includes按需翻译===
# 对 includes 目录中每个 .py 文件,若 stub 不存在则翻译并分离 stub
if do_phase1 != 0 and Config.IncludesDir is not None:
ph1_temp: str = Config.TempDir
if ph1_temp is None:
ph1_temp = "."
Phase1.RunPhase1(mb, Config.IncludesDir, ph1_temp, log)
# 如果仅 Phase1不执行 Phase2直接退出
if do_phase2 == 0:
stdio.printf("[phase] Phase1 完成,退出\n")
return 0
# AST 解析:如果指定了 --src 或 --project读取文件并解析为 AST 树
src_path: str = args.get_str("src")
# === 多文件项目模式 ===
# 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .py 文件编译
if src_path is None and project is not None and Config.SourceDir is not None:
mf_temp: str = Config.TempDir if Config.TempDir is not None else "."
mf_output: str = Config.OutputDir if Config.OutputDir is not None else "."
mf_cc: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
mf_cc_flags: str = Config.CompilerFlags if Config.CompilerFlags is not None else "-filetype=obj -relocation-model=pic"
mf_linker: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
mf_linker_flags: str = Config.LinkerFlags if Config.LinkerFlags is not None else "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition"
mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe"
mf_includes_bin: str = Config.get_includes_binary_dir()
mf_ret: int = Phase2.RunMultiFileProject(
mb, Config.SourceDir, mf_temp, mf_output,
mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out,
mf_includes_bin, Config.IncludesDir, do_phase1, do_phase2, log, args)
argparse.release(args)
if log is not None:
log.success("TransPyV 完成")
return mf_ret
# === 单文件模式:--src 指定时使用指定文件;--project 但无 SourceDir 时回退 ===
if src_path is None and project is not None:
if Config.SourceDir is not None:
# 构造入口路径: SourceDir/main.py
sd_len: t.CSizeT = string.strlen(Config.SourceDir)
path_buf: bytes = stdlib.malloc(sd_len + 16)
if path_buf is not None:
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir)
src_path = path_buf
stdio.printf("[project] 入口文件: %s\n", src_path)
if src_path is not None:
if log is not None:
log.banner("AST 解析")
# 打开文件
f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R)
if f.closed:
if log is not None:
log.error("无法打开文件", "fileio")
stdio.printf(" 路径: %s\n", src_path)
argparse.release(args)
return 1
# 分配源代码缓冲区
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
if src_buf is None:
if log is not None:
log.error("malloc for src_buf failed", "memhub")
f.close()
argparse.release(args)
return 1
# 读取文件内容
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
f.close()
if bytes_read < 0:
if log is not None:
log.error("读取文件失败", "fileio")
stdio.printf(" 错误码: %d\n", bytes_read)
argparse.release(args)
return 1
# 添加 null 终止符,确保 strlen 和 SHA1 计算正确
if bytes_read < SRC_BUF_SIZE:
src_buf[bytes_read] = 0
else:
src_buf[SRC_BUF_SIZE - 1] = 0
if log is not None:
log.info("文件读取完成", "fileio")
stdio.printf("读取 %d 字节\n", bytes_read)
# 解析 AST拆分为词法+语法两阶段,便于调试)
ast._init_tables(mb)
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)
if tree is None:
if log is not None:
log.error("AST 解析失败", "ast")
argparse.release(args)
return 1
# === 翻译 AST → LLVM IR ===
if log is not None:
log.banner("LLVM IR 翻译")
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
result: int = tr.translate(tree)
if result == 0:
IR_BUF_SIZE: t.CSizeT = 262144
ir_buf: bytes = stdlib.malloc(IR_BUF_SIZE)
if ir_buf is not None:
tr.dump_ir(ir_buf, IR_BUF_SIZE, llvmlite.OUTPUT_FULL)
# === 编译管线: .ll → .obj → .exe ===
if log is not None:
log.banner("编译管线")
# module_name 用源代码内容的 SHA1前 16 字符),与 Projectrans.py 一致
# output_name 从文件名推导(如 test.py -> test.exe保持可读性
module_name: str = Utils.compute_sha1(mb, src_buf)
if module_name is None:
module_name = "main"
output_name: str = "test_prog.exe"
# 从文件名提取 output_name去掉路径和 .py 扩展名)
src_len: t.CSizeT = string.strlen(src_path)
if src_len > 0:
# 找到最后一个 / 或 \ 之后的部分
base_start: t.CSizeT = src_len
i: t.CSizeT = src_len
while i > 0:
i -= 1
ch: t.CChar = src_path[i]
if ch == '/' or ch == '\\':
base_start = i + 1
break
if i == 0:
base_start = 0
# 找到 .py 扩展名
base_end: t.CSizeT = src_len
j: t.CSizeT = base_start
while j < src_len:
if src_path[j] == '.':
base_end = j
break
j += 1
# 输出名 = 文件名 + ".exe"
name_len: t.CSizeT = base_end - base_start
if name_len > 0:
out_len: t.CSizeT = name_len + 5
output_name = stdlib.malloc(out_len)
if output_name is not None:
# 手动复制文件名并追加 .exeviperlib.snprintf 不支持 %.*sstring 无 strcat
string.strncpy(output_name, src_path + base_start, name_len)
output_name[name_len] = '.'
output_name[name_len + 1] = 'e'
output_name[name_len + 2] = 'x'
output_name[name_len + 3] = 'e'
output_name[name_len + 4] = '\0'
# 使用 project.vpj 中的配置
temp_dir: str = Config.TempDir if Config.TempDir is not None else "."
output_dir: str = Config.OutputDir if Config.OutputDir is not None else "."
cc_cmd: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
cc_flags: str = "-filetype=obj -relocation-model=pic"
linker_cmd: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
linker_flags: str = "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition"
# --project 模式且未显式指定 --src 时:使用 config 中的 linker_output如 TransPyV.exe
# 显式指定 --src 时:使用从文件名推导的 output_name如 test.exe避免覆盖正在运行的 exe
if project is not None and Config.LinkerOutput is not None and args.get_str("src") is None:
linker_output: str = Config.LinkerOutput
else:
linker_output: str = output_name
# 计算 includes.binary 目录路径(链接时附加预编译 .obj
includes_binary_dir: str = Config.get_includes_binary_dir()
ir_len: t.CSizeT = string.strlen(ir_buf)
# (--phase 参数已在配置加载后处理,此处直接使用 do_phase1/do_phase2)
# === Phase1 stub 分离:使用 OUTPUT_STUB/TEXT 模式分别生成 stub.ll 和 text.ll ===
if do_phase1 != 0 and temp_dir is not None and module_name is not None:
if log is not None:
log.banner("stub 分离")
SF_IR_SIZE: t.CSizeT = 262144
td_len_sf: t.CSizeT = string.strlen(temp_dir)
# 保存 stub.ll
sf_stub_buf: bytes = stdlib.malloc(SF_IR_SIZE)
if sf_stub_buf is not None:
tr.dump_ir(sf_stub_buf, SF_IR_SIZE, llvmlite.OUTPUT_STUB)
sf_stub_len: t.CSizeT = string.strlen(sf_stub_buf)
sf_stub_path: bytes = stdlib.malloc(td_len_sf + 32)
if sf_stub_path is not None:
viperlib.snprintf(sf_stub_path, td_len_sf + 32, "%s/%s.stub.ll", temp_dir, module_name)
sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W)
if not sf_f.closed:
sf_f.write(sf_stub_buf, sf_stub_len)
sf_f.close()
stdlib.free(sf_stub_path)
stdlib.free(sf_stub_buf)
# 保存 text.ll
sf_text_buf: bytes = stdlib.malloc(SF_IR_SIZE)
if sf_text_buf is not None:
tr.dump_ir(sf_text_buf, SF_IR_SIZE, llvmlite.OUTPUT_TEXT)
sf_text_len: t.CSizeT = string.strlen(sf_text_buf)
sf_text_path: bytes = stdlib.malloc(td_len_sf + 32)
if sf_text_path is not None:
viperlib.snprintf(sf_text_path, td_len_sf + 32, "%s/%s.text.ll", temp_dir, module_name)
sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W)
if not sf_tf.closed:
sf_tf.write(sf_text_buf, sf_text_len)
sf_tf.close()
stdlib.free(sf_text_path)
stdlib.free(sf_text_buf)
# phase=1 模式:仅生成 stub不执行编译
if do_phase2 == 0:
if log is not None:
log.success("Phase1 完成(仅 stub 分离,跳过编译)")
argparse.release(args)
return 0
# === Phase2: 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR ===
final_ir: bytes = ir_buf
final_ir_len: t.CSizeT = ir_len
if temp_dir is not None and module_name is not None:
if log is not None:
log.banner("IR 组合")
SF_COMBINED_SIZE: t.CSizeT = 4194304 # 4MB
combined_buf: bytes = stdlib.malloc(SF_COMBINED_SIZE)
if combined_buf is not None:
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, module_name, combined_buf, SF_COMBINED_SIZE)
if combined_len > 0:
final_ir = combined_buf
final_ir_len = combined_len
else:
stdio.printf("[stub] BuildCombinedIR 失败,使用原始 IR\n")
stdlib.free(combined_buf)
br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline(
final_ir, final_ir_len, temp_dir, output_dir, module_name,
cc_cmd, cc_flags, linker_cmd, linker_flags, linker_output,
includes_binary_dir
)
if br is not None and br.Success == 1:
if log is not None:
log.success("编译管线完成")
stdio.printf("输出: %s/%s\n", output_dir, linker_output)
# --run 模式:执行生成的可执行文件
if args.get_bool("run"):
exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2)
if exe_path is not None:
viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output)
stdio.printf("[run] 执行: %s\n", exe_path)
r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
if r is not None:
stdio.printf("[run] 退出码: %d\n", r.returncode)
else:
if log is not None:
log.error("编译管线失败", "pipeline")
if br is not None and br.ErrorMsg is not None:
stdio.printf("[FATAL] 编译管线失败: %s\n", br.ErrorMsg)
sys.exit(1)
else:
if log is not None:
log.error("malloc for IR buffer failed", "memhub")
else:
if log is not None:
log.error("翻译失败", "translator")
argparse.release(args)
if log is not None:
log.success("TransPyV 完成")
return 0