Initial import of TransPyV
This commit is contained in:
299
App/lib/Projectrans/Config.py
Normal file
299
App/lib/Projectrans/Config.py
Normal 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/../includes(OS 解析为 includes)
|
||||
- 绝对路径保持不变
|
||||
- None 返回 None
|
||||
"""
|
||||
if rel is None:
|
||||
return None
|
||||
# 绝对路径(以 / 或 \ 开头)保持不变
|
||||
if rel[0] == '/' or rel[0] == '\\':
|
||||
return rel
|
||||
|
||||
rel_len: t.CSizeT = string.strlen(rel)
|
||||
dir_len: t.CSizeT = string.strlen(project_dir)
|
||||
|
||||
# 处理 ../ 或 ..\\ 前缀:拼接 project_dir/../...
|
||||
if rel_len >= 3 and rel[0] == '.' and rel[1] == '.':
|
||||
if rel[2] == '/' or rel[2] == '\\':
|
||||
if dir_len == 0:
|
||||
return rel
|
||||
total_len: t.CSizeT = dir_len + 1 + rel_len + 1
|
||||
buf: str = _mbuddy.alloc(total_len)
|
||||
if buf is None:
|
||||
return rel
|
||||
viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel)
|
||||
return buf
|
||||
|
||||
# 处理 ./ 或 .\\ 前缀:拼接 project_dir + rel[2:]
|
||||
rel_off: t.CSizeT = 0
|
||||
if rel_len >= 2 and rel[0] == '.':
|
||||
if rel[1] == '/' or rel[1] == '\\':
|
||||
rel_off = 2
|
||||
else:
|
||||
return rel # 不是 ./ 开头,保持不变
|
||||
else:
|
||||
return rel # 不是 . 开头,保持不变
|
||||
|
||||
if dir_len == 0:
|
||||
# project_dir 为空(当前目录),去掉 ./ 前缀即可
|
||||
return rel + rel_off
|
||||
# 拼接: project_dir + "/" + rel[rel_off:]
|
||||
total_len = dir_len + 1 + (rel_len - rel_off) + 1
|
||||
buf = _mbuddy.alloc(total_len)
|
||||
if buf is None:
|
||||
return rel # 分配失败,返回原路径
|
||||
viperlib.snprintf(buf, total_len, "%s/%s", project_dir, rel + rel_off)
|
||||
return buf
|
||||
|
||||
|
||||
def resolve_paths(project_dir: str) -> int:
|
||||
"""解析并规范化工程路径(src/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)
|
||||
117
App/lib/Projectrans/Utils.py
Normal file
117
App/lib/Projectrans/Utils.py
Normal 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_sha1(hashlib.sha1().hexdigest()[:16])。
|
||||
# ============================================================
|
||||
def compute_sha1(pool: memhub.MemBuddy | t.CPtr, content: str) -> str:
|
||||
"""计算字符串的 SHA1,返回前 16 个十六进制字符(用于文件命名)"""
|
||||
if content is None or pool is None:
|
||||
return None
|
||||
|
||||
# 构造 sha1 对象(__init__ 会初始化 state/count/buf)
|
||||
# ctx 在栈上分配(alloca),函数内使用完即丢弃,无需堆分配
|
||||
ctx: hashlib.sha1 | t.CPtr = hashlib.sha1()
|
||||
if ctx is None:
|
||||
return None
|
||||
|
||||
# 计算摘要
|
||||
ctx.update(content)
|
||||
digest: bytes = pool.alloc(hashlib.SHA1_DIGEST_LEN)
|
||||
if digest is None:
|
||||
return None
|
||||
ctx.final(digest)
|
||||
|
||||
# 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符)
|
||||
hex_buf: str = pool.alloc(17)
|
||||
if hex_buf is None:
|
||||
return None
|
||||
for i in range(8):
|
||||
hi: int = (digest[i] >> 4) & 0xF
|
||||
lo: int = digest[i] & 0xF
|
||||
if hi < 10:
|
||||
hex_buf[i * 2] = '0' + hi
|
||||
else:
|
||||
hex_buf[i * 2] = 'a' + (hi - 10)
|
||||
if lo < 10:
|
||||
hex_buf[i * 2 + 1] = '0' + lo
|
||||
else:
|
||||
hex_buf[i * 2 + 1] = 'a' + (lo - 10)
|
||||
hex_buf[16] = '\0'
|
||||
return hex_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CleanDir - 删除目录中所有文件(非递归,保留目录本身)
|
||||
#
|
||||
# 用于 --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
|
||||
12
App/lib/Projectrans/__init__.py
Normal file
12
App/lib/Projectrans/__init__.py
Normal 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',
|
||||
]
|
||||
27
App/lib/__init__.py
Normal file
27
App/lib/__init__.py
Normal 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
|
||||
502
App/lib/core/BuildPipeline.py
Normal file
502
App/lib/core/BuildPipeline.py
Normal 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_ir),None 失败
|
||||
|
||||
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
|
||||
281
App/lib/core/Handles/HandlesAnnAssign.py
Normal file
281
App/lib/core/Handles/HandlesAnnAssign.py
Normal 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
|
||||
231
App/lib/core/Handles/HandlesAssign.py
Normal file
231
App/lib/core/Handles/HandlesAssign.py
Normal 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
|
||||
254
App/lib/core/Handles/HandlesAugAssign.py
Normal file
254
App/lib/core/Handles/HandlesAugAssign.py
Normal 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
|
||||
262
App/lib/core/Handles/HandlesBase.py
Normal file
262
App/lib/core/Handles/HandlesBase.py
Normal 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
|
||||
230
App/lib/core/Handles/HandlesBody.py
Normal file
230
App/lib/core/Handles/HandlesBody.py
Normal 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()
|
||||
2327
App/lib/core/Handles/HandlesClassDef.py
Normal file
2327
App/lib/core/Handles/HandlesClassDef.py
Normal file
File diff suppressed because it is too large
Load Diff
230
App/lib/core/Handles/HandlesEnum.py
Normal file
230
App/lib/core/Handles/HandlesEnum.py
Normal 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
|
||||
1525
App/lib/core/Handles/HandlesExpr.py
Normal file
1525
App/lib/core/Handles/HandlesExpr.py
Normal file
File diff suppressed because it is too large
Load Diff
3972
App/lib/core/Handles/HandlesExprCall.py
Normal file
3972
App/lib/core/Handles/HandlesExprCall.py
Normal file
File diff suppressed because it is too large
Load Diff
287
App/lib/core/Handles/HandlesExprOps.py
Normal file
287
App/lib/core/Handles/HandlesExprOps.py
Normal 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)
|
||||
|
||||
# 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入)
|
||||
# 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错)
|
||||
cls_sha1: str = None
|
||||
op_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
|
||||
if op_entry is not None:
|
||||
cls_sha1 = op_entry.ModuleSha1
|
||||
if cls_sha1 is None:
|
||||
cls_sha1 = HandlesStruct.get_struct_sha1(search_class)
|
||||
if cls_sha1 is None:
|
||||
cur_p: str = HandlesStruct.get_parent_name(search_class)
|
||||
while cur_p is not None and cls_sha1 is None:
|
||||
cls_sha1 = HandlesStruct.get_struct_sha1(cur_p)
|
||||
cur_p = HandlesStruct.get_parent_name(cur_p)
|
||||
|
||||
# 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算
|
||||
if found_func is None and cls_sha1 is None:
|
||||
return None
|
||||
|
||||
# 构建 extra_args 数组(仅含 rhs 一个参数)
|
||||
extra_args: t.CSizeT | t.CPtr = pool.alloc(8)
|
||||
if extra_args is None:
|
||||
return None
|
||||
extra_args[0] = t.CSizeT(rhs)
|
||||
|
||||
# 调用方法: lhs.__dunder__(rhs)
|
||||
return HandlesExprCall._call_method_on_ptr(
|
||||
pool, builder, mod, search_class, dunder,
|
||||
lhs, extra_args, 1, trans)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 翻译二元运算(自动类型提升)
|
||||
# ============================================================
|
||||
def translate_binop(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""翻译二元运算(自动类型提升)"""
|
||||
binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
if binop is None:
|
||||
return None
|
||||
|
||||
lhs_node: ast.AST | t.CPtr = binop.left
|
||||
rhs_node: ast.AST | t.CPtr = binop.right
|
||||
op: int = binop.op
|
||||
|
||||
# 先翻译 rhs(只翻译一次,避免副作用重复)
|
||||
rhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, rhs_node, None, 0, trans)
|
||||
if rhs is None:
|
||||
return None
|
||||
|
||||
# === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 ===
|
||||
# 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值,
|
||||
# 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。
|
||||
if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node)
|
||||
if nm is not None and nm.id is not None:
|
||||
lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
trans.SymTab, nm.id)
|
||||
if lhs_alloca is not None:
|
||||
ovl_result: llvmlite.Value | t.CPtr = try_operator_overload(
|
||||
pool, builder, mod, lhs_alloca, rhs, op, trans, 0)
|
||||
if ovl_result is not None:
|
||||
return ovl_result
|
||||
|
||||
# 正常翻译 lhs
|
||||
lhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, lhs_node, None, 0, trans)
|
||||
if lhs is None:
|
||||
return None
|
||||
|
||||
# === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)===
|
||||
ovl_result2: llvmlite.Value | t.CPtr = try_operator_overload(
|
||||
pool, builder, mod, lhs, rhs, op, trans, 0)
|
||||
if ovl_result2 is not None:
|
||||
return ovl_result2
|
||||
|
||||
# 获取操作数类型信息
|
||||
lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
|
||||
rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
|
||||
lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty)
|
||||
rhs_fbits: int = HandlesExpr.get_llvm_float_bits(rhs.Ty)
|
||||
|
||||
# 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查,
|
||||
# 因为 float 的 int bits 为 0,会被误认为指针)
|
||||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||||
# 确定目标浮点类型(使用较大的位宽)
|
||||
target_fbits: int = lhs_fbits
|
||||
if rhs_fbits > target_fbits:
|
||||
target_fbits = rhs_fbits
|
||||
target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||||
if target_fbits == 32:
|
||||
target_float_ty = llvmlite.Float(pool)
|
||||
# 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc)
|
||||
lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty)
|
||||
rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty)
|
||||
if op == ast.OpKind.Add:
|
||||
return llvmlite.build_fadd(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Sub:
|
||||
return llvmlite.build_fsub(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Mult:
|
||||
return llvmlite.build_fmul(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Div:
|
||||
return llvmlite.build_fdiv(builder, lhs, rhs)
|
||||
if op == ast.OpKind.Mod:
|
||||
return llvmlite.build_frem(builder, lhs, rhs)
|
||||
return None
|
||||
|
||||
# 指针算术: ptr + int 或 ptr - int → ptrtoint + add/sub + inttoptr
|
||||
if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0):
|
||||
if op == ast.OpKind.Add or op == ast.OpKind.Sub:
|
||||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
if lhs_bits == 0:
|
||||
# lhs 是指针,rhs 是整数
|
||||
ptr_as_int: llvmlite.Value | t.CPtr = llvmlite.build_ptrtoint(builder, lhs, i64_ty)
|
||||
int_val: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, rhs, i64_ty)
|
||||
if op == ast.OpKind.Add:
|
||||
result: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, ptr_as_int, int_val)
|
||||
else:
|
||||
result = llvmlite.build_sub(builder, ptr_as_int, int_val)
|
||||
return llvmlite.build_inttoptr(builder, result, lhs.Ty)
|
||||
else:
|
||||
# rhs 是指针,lhs 是整数(仅 Add 支持交换)
|
||||
ptr_as_int = llvmlite.build_ptrtoint(builder, rhs, i64_ty)
|
||||
int_val = HandlesExpr.coerce_to_type(builder, lhs, i64_ty)
|
||||
if op == ast.OpKind.Add:
|
||||
result = llvmlite.build_add(builder, int_val, ptr_as_int)
|
||||
else:
|
||||
result = llvmlite.build_sub(builder, int_val, ptr_as_int)
|
||||
return llvmlite.build_inttoptr(builder, result, rhs.Ty)
|
||||
|
||||
if lhs_bits > rhs_bits:
|
||||
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty)
|
||||
elif rhs_bits > lhs_bits:
|
||||
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty)
|
||||
|
||||
if op == ast.OpKind.Add:
|
||||
return llvmlite.build_add(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Sub:
|
||||
return llvmlite.build_sub(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Mult:
|
||||
return llvmlite.build_mul(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.Div:
|
||||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||
elif op == ast.OpKind.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
|
||||
384
App/lib/core/Handles/HandlesFor.py
Normal file
384
App/lib/core/Handles/HandlesFor.py
Normal 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
|
||||
936
App/lib/core/Handles/HandlesFunctions.py
Normal file
936
App/lib/core/Handles/HandlesFunctions.py
Normal 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. 创建 declare(IsDeclared=1)
|
||||
# 4. 添加参数
|
||||
# 5. 注册到函数表
|
||||
#
|
||||
# 后续 translate_function_def 会通过 find_func_in_module 找到已有的 declare,
|
||||
# 复用之(清除 IsDeclared,跳过参数创建,直接添加函数体)。
|
||||
# ============================================================
|
||||
def forward_declare_functions(trans: HT.Translator | t.CPtr,
|
||||
tree: ast.AST | t.CPtr) -> int:
|
||||
"""预扫描所有顶层 FunctionDef,创建前向声明"""
|
||||
if trans is None or tree is None:
|
||||
return 0
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
if pool is None or mod is None:
|
||||
return 0
|
||||
|
||||
imported_modules: str = trans._imported_modules
|
||||
from_imports: str = trans._from_imports
|
||||
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = trans._funcs
|
||||
|
||||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||||
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is None:
|
||||
return 0
|
||||
cn_count: t.CSizeT = ch.__len__()
|
||||
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
if child.kind() != ast.ASTKind.FunctionDef:
|
||||
continue
|
||||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||||
if fd is None or fd.name is None:
|
||||
continue
|
||||
|
||||
# 推断返回类型
|
||||
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
if fd.returns is not None:
|
||||
ret_ty = HandlesType.resolve_annotation_type(
|
||||
pool, fd.returns, imported_modules, from_imports)
|
||||
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
|
||||
141
App/lib/core/Handles/HandlesIf.py
Normal file
141
App/lib/core/Handles/HandlesIf.py
Normal 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
|
||||
404
App/lib/core/Handles/HandlesImports.py
Normal file
404
App/lib/core/Handles/HandlesImports.py
Normal 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 Y(level=1, module="X")在包 pkg 中:
|
||||
# 解析为 "pkg.X"
|
||||
# 对于 from . import Y(level=1, module=None)在包 pkg 中:
|
||||
# 解析为 "pkg"
|
||||
# 对于 from ..X import Y(level=2, module="X")在包 pkg.sub 中:
|
||||
# 解析为 "pkg.X"(先从 pkg.sub 上溯一级到 pkg,再追加 .X)
|
||||
#
|
||||
# Args:
|
||||
# pool: 内存池
|
||||
# current_package: 当前文件所属包名(如 "llvmlite"),None 表示无包
|
||||
# level: 相对导入级别(0=绝对,1=., 2=..)
|
||||
# module: ImportFrom 的 module 字段(可能为 None)
|
||||
#
|
||||
# Returns:
|
||||
# 解析后的完整模块名;绝对导入(level<=0)直接返回 module;
|
||||
# 无法解析时返回 module(回退到原始值)
|
||||
# ============================================================
|
||||
def _resolve_relative_module(pool: memhub.MemBuddy | t.CPtr,
|
||||
current_package: str,
|
||||
level: t.CInt,
|
||||
module: str) -> str:
|
||||
"""解析相对导入为完整模块名"""
|
||||
if level <= 0:
|
||||
return module
|
||||
if current_package is None:
|
||||
return module
|
||||
|
||||
# 从 current_package 开始,上溯 (level-1) 级
|
||||
pkg: str = current_package
|
||||
up: t.CInt = level - 1
|
||||
while up > 0:
|
||||
pkg_len: t.CSizeT = string.strlen(pkg)
|
||||
last_dot: t.CSizeT = 0
|
||||
found: int = 0
|
||||
i: t.CSizeT = 0
|
||||
while i < pkg_len:
|
||||
if pkg[i] == '.':
|
||||
last_dot = i
|
||||
found = 1
|
||||
i += 1
|
||||
if found == 0:
|
||||
# 无更多父级,包变为空
|
||||
pkg = None
|
||||
break
|
||||
# 截断到最后一个 '.' 处
|
||||
new_pkg: str = pool.alloc(last_dot + 1)
|
||||
if new_pkg is None:
|
||||
return module
|
||||
string.strncpy(new_pkg, pkg, last_dot)
|
||||
new_pkg[last_dot] = '\0'
|
||||
pkg = new_pkg
|
||||
up -= 1
|
||||
|
||||
if module is None:
|
||||
# from . import Y → 模块就是包本身
|
||||
return pkg
|
||||
if pkg is None:
|
||||
# 包已上溯到空,直接用 module
|
||||
return module
|
||||
# 拼接 pkg + "." + module
|
||||
pkg_len2: t.CSizeT = string.strlen(pkg)
|
||||
mod_len: t.CSizeT = string.strlen(module)
|
||||
buf: str = pool.alloc(pkg_len2 + 1 + mod_len + 1)
|
||||
if buf is None:
|
||||
return module
|
||||
string.strcpy(buf, pkg)
|
||||
buf[pkg_len2] = '.'
|
||||
string.strcpy(buf + pkg_len2 + 1, module)
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# compute_package_from_relpath - 从相对路径计算包名
|
||||
#
|
||||
# 包名 = 文件所在目录路径,将 / 和 \ 替换为 .
|
||||
# 对于顶级文件(无目录分隔符),返回 None
|
||||
#
|
||||
# 示例:
|
||||
# "llvmlite/__init__.py" → "llvmlite"
|
||||
# "llvmlite/__types.py" → "llvmlite"
|
||||
# "ast/parser.py" → "ast"
|
||||
# "ast.py" → None(顶级文件)
|
||||
# ============================================================
|
||||
def compute_package_from_relpath(pool: memhub.MemBuddy | t.CPtr,
|
||||
rel_path: str) -> str:
|
||||
"""从相对路径计算包名(目录部分,分隔符替换为 .)"""
|
||||
if rel_path is None:
|
||||
return None
|
||||
rlen: t.CSizeT = string.strlen(rel_path)
|
||||
# 找最后一个 / 或 \
|
||||
last_sep: t.CSizeT = 0
|
||||
found: int = 0
|
||||
i: t.CSizeT = 0
|
||||
while i < rlen:
|
||||
ch: t.CChar = rel_path[i]
|
||||
if ch == '/' or ch == '\\':
|
||||
last_sep = i
|
||||
found = 1
|
||||
i += 1
|
||||
if found == 0:
|
||||
# 无目录分隔符 → 顶级文件,无包
|
||||
return None
|
||||
# 复制目录部分,将 / 和 \ 替换为 .
|
||||
dir_len: t.CSizeT = last_sep
|
||||
buf: str = pool.alloc(dir_len + 1)
|
||||
if buf is None:
|
||||
return None
|
||||
j: t.CSizeT = 0
|
||||
while j < dir_len:
|
||||
ch2: t.CChar = rel_path[j]
|
||||
if ch2 == '/' or ch2 == '\\':
|
||||
buf[j] = '.'
|
||||
else:
|
||||
buf[j] = ch2
|
||||
j += 1
|
||||
buf[dir_len] = '\0'
|
||||
return buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# ImportsHandle - 导入语句处理器(Mixin 继承模式)
|
||||
#
|
||||
# 方法版本:直接更新 trans._imported_modules / trans._from_imports
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class ImportsHandle(HandlesBase.Mixin):
|
||||
"""导入语句处理器:继承 Mixin 获得 Trans 回指针"""
|
||||
|
||||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||||
self.Trans = trans
|
||||
|
||||
# ============================================================
|
||||
# HandleImport - 处理 import 语句,更新 trans._imported_modules
|
||||
# ============================================================
|
||||
def HandleImport(self, node: ast.AST | t.CPtr) -> int:
|
||||
"""处理 import 语句,返回 0"""
|
||||
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node)
|
||||
if imp is None:
|
||||
return 0
|
||||
names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
|
||||
if names is None:
|
||||
return 0
|
||||
nn: t.CSizeT = names.__len__()
|
||||
for ni in range(nn):
|
||||
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
|
||||
if alias is not None and alias.name is not None:
|
||||
pool_val: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||
im_val: str = self.Trans._imported_modules
|
||||
self.Trans._imported_modules = add_imported_module(
|
||||
pool_val, im_val, alias.name)
|
||||
# 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class())
|
||||
if alias.asname is not None:
|
||||
self.Trans._imported_modules = add_imported_module(
|
||||
pool_val, self.Trans._imported_modules, alias.asname)
|
||||
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
|
||||
314
App/lib/core/Handles/HandlesMain.py
Normal file
314
App/lib/core/Handles/HandlesMain.py
Normal 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=2(import扫描模式)时跳过,只处理 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=2(import扫描模式)时跳过
|
||||
# _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断)
|
||||
# _declare_only=0(全量翻译)时处理所有模块级 AnnAssign
|
||||
added = handle_module_level_var(trans, child)
|
||||
added_total += added
|
||||
elif trans._declare_only == 0 and kd == ast.ASTKind.Assign:
|
||||
# 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式)
|
||||
added = handle_module_level_var(trans, child)
|
||||
added_total += added
|
||||
|
||||
return added_total
|
||||
|
||||
|
||||
# ============================================================
|
||||
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
|
||||
#
|
||||
# 当用户已定义 main(无 wrapper main builder)时,模块级
|
||||
# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域
|
||||
# ============================================================
|
||||
def handle_module_level_var(trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""处理模块级变量声明,创建全局变量"""
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||||
|
||||
# CDefine 注解: 编译期常量,不创建全局变量
|
||||
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
|
||||
k: int = node.kind()
|
||||
if k == ast.ASTKind.AnnAssign:
|
||||
aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||
if aa_cd is not None and aa_cd.target is not None:
|
||||
if aa_cd.target.kind() == ast.ASTKind.Name:
|
||||
nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target)
|
||||
if nm_cd.id is not None:
|
||||
if HandlesAnnAssign.is_cdefine_annotation(aa_cd.annotation) != 0:
|
||||
val_cd: int = HandlesAnnAssign.extract_cdefine_int_value(aa_cd.value)
|
||||
HandlesType.register_cdefine_constant(pool, nm_cd.id, val_cd)
|
||||
return 0
|
||||
|
||||
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
|
||||
# CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过
|
||||
if trans._declare_only == 1:
|
||||
return 0
|
||||
|
||||
var_name: str = None
|
||||
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
init_val: t.CInt64T = 0
|
||||
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
|
||||
127
App/lib/core/Handles/HandlesNonlocal.py
Normal file
127
App/lib/core/Handles/HandlesNonlocal.py
Normal 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)
|
||||
101
App/lib/core/Handles/HandlesReturn.py
Normal file
101
App/lib/core/Handles/HandlesReturn.py
Normal 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 类型与函数返回类型匹配
|
||||
# 处理 i1(bool 比较结果)→ i8(t.CBool)等情况
|
||||
# i1 → 更宽整数用 zext(bool 语义: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
|
||||
975
App/lib/core/Handles/HandlesStruct.py
Normal file
975
App/lib/core/Handles/HandlesStruct.py
Normal 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 # 虚表方法名数组(每个方法名 str,VTableMethodCount 个)
|
||||
ModuleSha1: t.CChar | t.CPtr # 定义该类的模块 SHA1(None=无 SHA1)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 全局注册表(静态分配)
|
||||
# ============================================================
|
||||
_struct_table: StructEntry | t.CPtr = None
|
||||
_struct_count: int = 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 跨模块命名空间隔离:per-file 结构体可见性
|
||||
#
|
||||
# _visible_structs: 当前文件可见的结构体名(HashTable,O(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
|
||||
417
App/lib/core/Handles/HandlesTranslator.py
Normal file
417
App/lib/core/Handles/HandlesTranslator.py
Normal 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() 创建包装 main(trans 单参)"""
|
||||
added: int = HandlesMain.create_wrapper_main(self, tree, i32_ty)
|
||||
|
||||
# ============================================================
|
||||
# 模块级翻译(用户已定义 main)→ 委托 HandlesMain
|
||||
# ============================================================
|
||||
def _translate_module_level(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
tree: ast.AST | t.CPtr):
|
||||
"""委托 HandlesMain.translate_children() 翻译模块级语句(trans 单参)"""
|
||||
# 全量翻译模式下,先处理导入语句,再创建前向声明,解决前向引用问题
|
||||
if self._declare_only == 0:
|
||||
# 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充
|
||||
# (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入)
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch is not None:
|
||||
cn_count: t.CSizeT = ch.__len__()
|
||||
for ci in range(cn_count):
|
||||
child: ast.AST | t.CPtr = ch.get(ci)
|
||||
if child is None:
|
||||
continue
|
||||
kd: int = child.kind()
|
||||
if kd == ast.ASTKind.Import:
|
||||
self.ImportsH.HandleImport(child)
|
||||
elif kd == ast.ASTKind.ImportFrom:
|
||||
self.ImportsH.HandleImportFromModule(child)
|
||||
self.ImportsH.HandleImportFromNames(child)
|
||||
# 创建前向声明
|
||||
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
|
||||
1185
App/lib/core/Handles/HandlesType.py
Normal file
1185
App/lib/core/Handles/HandlesType.py
Normal file
File diff suppressed because it is too large
Load Diff
365
App/lib/core/Handles/HandlesVar.py
Normal file
365
App/lib/core/Handles/HandlesVar.py
Normal 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
|
||||
130
App/lib/core/Handles/HandlesWhile.py
Normal file
130
App/lib/core/Handles/HandlesWhile.py
Normal 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
|
||||
23
App/lib/core/Handles/__init__.py
Normal file
23
App/lib/core/Handles/__init__.py
Normal 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
|
||||
364
App/lib/core/IncludesScanner.py
Normal file
364
App/lib/core/IncludesScanner.py
Normal 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 池耗尽(每文件 128KB,60+ 文件会耗尽 16MB 池)
|
||||
BUF_SIZE: t.CSizeT = 131072
|
||||
buf: bytes = stdlib.malloc(BUF_SIZE)
|
||||
if buf is None:
|
||||
f.close()
|
||||
return None
|
||||
|
||||
# 读取文件内容
|
||||
bytes_read: t.CInt64T = f.read_all(buf, BUF_SIZE)
|
||||
f.close()
|
||||
if bytes_read <= 0:
|
||||
return None
|
||||
|
||||
# 原地去除 \r(CRLF → LF),与 Projectrans.py 文本模式读取一致
|
||||
write_pos: t.CSizeT = 0
|
||||
read_pos: t.CSizeT = 0
|
||||
while read_pos < bytes_read:
|
||||
ch: t.CChar = buf[read_pos]
|
||||
if ch != '\r':
|
||||
buf[write_pos] = ch
|
||||
write_pos += 1
|
||||
read_pos += 1
|
||||
|
||||
# 添加 null 终止符
|
||||
buf[write_pos] = 0
|
||||
|
||||
# 计算 SHA1
|
||||
ctx: hashlib.sha1 | t.CPtr = hashlib.sha1()
|
||||
if ctx is None:
|
||||
return None
|
||||
ctx.update(buf)
|
||||
|
||||
digest: bytes = stdlib.malloc(hashlib.SHA1_DIGEST_LEN)
|
||||
if digest is None:
|
||||
return None
|
||||
ctx.final(digest)
|
||||
|
||||
# 转为十六进制字符串(取前 8 字节 = 16 个十六进制字符)
|
||||
hex_buf: str = stdlib.malloc(17)
|
||||
if hex_buf is None:
|
||||
return None
|
||||
for i in range(8):
|
||||
hi: int = (digest[i] >> 4) & 0xF
|
||||
lo: int = digest[i] & 0xF
|
||||
if hi < 10:
|
||||
hex_buf[i * 2] = '0' + hi
|
||||
else:
|
||||
hex_buf[i * 2] = 'a' + (hi - 10)
|
||||
if lo < 10:
|
||||
hex_buf[i * 2 + 1] = '0' + lo
|
||||
else:
|
||||
hex_buf[i * 2 + 1] = 'a' + (lo - 10)
|
||||
hex_buf[16] = '\0'
|
||||
return hex_buf
|
||||
|
||||
|
||||
# ============================================================
|
||||
# scan_directory_recursive - 递归扫描目录
|
||||
#
|
||||
# 使用 FindFirstFileA/FindNextFileA 遍历目录树,
|
||||
# 对每个 .py 文件计算 SHA1 并添加到结果中。
|
||||
# ============================================================
|
||||
def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
root_dir: str,
|
||||
rel_prefix: str,
|
||||
result: ScanResult | t.CPtr) -> int:
|
||||
"""递归扫描目录,收集 .py 文件"""
|
||||
if pool is None or root_dir is None or result is None:
|
||||
return 1
|
||||
|
||||
# 构造搜索模式: root_dir/*
|
||||
root_len: t.CSizeT = string.strlen(root_dir)
|
||||
pattern: bytes = stdlib.malloc(root_len + 4)
|
||||
if pattern is None:
|
||||
return 1
|
||||
viperlib.snprintf(pattern, root_len + 4, "%s/*", root_dir)
|
||||
|
||||
# 使用 FindFirstFileA 开始搜索
|
||||
find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
if find_data is None:
|
||||
return 1
|
||||
string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
|
||||
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
|
||||
if handle == win32base.INVALID_HANDLE_VALUE:
|
||||
return 1
|
||||
|
||||
# 遍历所有文件和子目录
|
||||
while True:
|
||||
# 跳过 . 和 ..
|
||||
fname: str = find_data.cFileName
|
||||
if fname is not None:
|
||||
fname0: t.CChar = fname[0]
|
||||
if fname0 == '.':
|
||||
fname1: t.CChar = fname[1]
|
||||
if fname1 == '\0':
|
||||
# "."
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
elif fname1 == '.':
|
||||
fname2: t.CChar = fname[2]
|
||||
if fname2 == '\0':
|
||||
# ".."
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
break
|
||||
continue
|
||||
|
||||
# 检查是否为目录
|
||||
is_dir: int = find_data.dwFileAttributes & win32file.FILE_ATTRIBUTE_DIRECTORY
|
||||
|
||||
# 构造完整路径
|
||||
fname_len: t.CSizeT = string.strlen(fname)
|
||||
full_path: bytes = stdlib.malloc(root_len + fname_len + 2)
|
||||
if full_path is None:
|
||||
break
|
||||
viperlib.snprintf(full_path, root_len + fname_len + 2, "%s/%s", root_dir, fname)
|
||||
|
||||
# 构造相对路径
|
||||
prefix_len: t.CSizeT = 0
|
||||
if rel_prefix is not None:
|
||||
prefix_len = string.strlen(rel_prefix)
|
||||
rel_path: bytes = stdlib.malloc(prefix_len + fname_len + 2)
|
||||
if rel_path is None:
|
||||
break
|
||||
if rel_prefix is not None and prefix_len > 0:
|
||||
viperlib.snprintf(rel_path, prefix_len + fname_len + 2, "%s/%s", rel_prefix, fname)
|
||||
else:
|
||||
string.strcpy(rel_path, fname)
|
||||
|
||||
if is_dir != 0:
|
||||
# 递归扫描子目录
|
||||
scan_directory_recursive(pool, full_path, rel_path, result)
|
||||
else:
|
||||
# 检查是否为 .py 文件
|
||||
is_py: int = 0
|
||||
if fname_len >= 3:
|
||||
if fname[fname_len - 3] == '.' and fname[fname_len - 2] == 'p' and fname[fname_len - 1] == 'y':
|
||||
is_py = 1
|
||||
|
||||
if is_py != 0:
|
||||
# 跳过 __pycache__ 目录下的文件
|
||||
is_pycache: int = 0
|
||||
if rel_prefix is not None:
|
||||
if string.strcmp(rel_prefix, "__pycache__") == 0:
|
||||
is_pycache = 1
|
||||
|
||||
if is_pycache == 0:
|
||||
# 计算 SHA1
|
||||
sha1: str = compute_file_sha1(pool, full_path)
|
||||
if sha1 is not None:
|
||||
add_file_entry(result, pool, full_path, rel_path, sha1)
|
||||
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
|
||||
540
App/lib/core/Phase1.py
Normal file
540
App/lib/core/Phase1.py
Normal 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
|
||||
680
App/lib/core/Phase2.py
Normal file
680
App/lib/core/Phase2.py
Normal 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)
|
||||
|
||||
# 尝试 BuildCombinedIR(stub/text 应已由 Phase1 生成)
|
||||
inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
||||
inc_combined_len_mi: t.CSizeT = 0
|
||||
if inc_combined_mi is not None:
|
||||
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||
|
||||
# 如果 stub/text 不存在,翻译源文件并保存 stub + text,然后重试
|
||||
if inc_combined_len_mi == 0 and inc_combined_mi is not None:
|
||||
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
|
||||
1477
App/lib/core/StubMerger.py
Normal file
1477
App/lib/core/StubMerger.py
Normal file
File diff suppressed because it is too large
Load Diff
171
App/lib/core/VLogger.py
Normal file
171
App/lib/core/VLogger.py
Normal 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
|
||||
9
App/lib/core/__init__.py
Normal file
9
App/lib/core/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
|
||||
# ============================================================
|
||||
# core 包入口
|
||||
#
|
||||
# 子模块通过绝对导入使用(import lib.core.X as X),
|
||||
# 此 __init__.py 不做 re-export,避免引入未使用的依赖。
|
||||
# ============================================================
|
||||
Reference in New Issue
Block a user