Initial import of TransPyV
This commit is contained in:
25
.gitignore
vendored
Normal file
25
.gitignore
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
|
||||
# 备份
|
||||
*.bak
|
||||
|
||||
# 构建产物(防御性)
|
||||
**/output/
|
||||
**/temp/
|
||||
**/*.deps.json
|
||||
**/*.doc.json
|
||||
**/*.pyi
|
||||
**/*.elf
|
||||
**/*.o
|
||||
**/*.obj
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
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,避免引入未使用的依赖。
|
||||
# ============================================================
|
||||
510
App/main.py
Normal file
510
App/main.py
Normal file
@@ -0,0 +1,510 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import string
|
||||
import stdlib
|
||||
import memhub
|
||||
import argparse
|
||||
import w32.win32console as w32cmd
|
||||
import w32.fileio as fileio
|
||||
import w32.win32file
|
||||
import w32.win32base
|
||||
import sys
|
||||
import ast
|
||||
import lib
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.BuildPipeline as BuildPipeline
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.Phase1 as Phase1
|
||||
import lib.core.Phase2 as Phase2
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import llvmlite
|
||||
import subprocess
|
||||
import viperlib
|
||||
import hashlib
|
||||
|
||||
|
||||
# 内存大小: fl_bytes=264 (33*8), POOL_SIZE-fl_bytes 必须是 2 的幂以避免浪费
|
||||
# 1073742088 - 264 = 1073741824 (1024MB usable = 2^30)
|
||||
# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件,512MB 不足导致 Phase2 崩溃
|
||||
POOL_SIZE: t.CDefine = 1073741824
|
||||
# 语言编码页
|
||||
CODE_PAGE: t.CDefine = 65001
|
||||
# 源代码缓冲区大小(1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
|
||||
|
||||
# ============================================================
|
||||
# main: 命令行入口
|
||||
#
|
||||
# 解析参数 → 加载配置 → AST 解析 → LLVM IR 翻译 → 编译管线 → 可选执行
|
||||
# ============================================================
|
||||
def main() -> int:
|
||||
w32cmd.SetConsoleOutputCP(CODE_PAGE)
|
||||
w32cmd.SetConsoleCP(CODE_PAGE)
|
||||
# 初始化 mbuddy 内存池
|
||||
arena: bytes = stdlib.malloc(POOL_SIZE)
|
||||
if arena is None:
|
||||
stdio.printf("FAIL: malloc for arena failed\n")
|
||||
return 1
|
||||
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE)
|
||||
if mb is None:
|
||||
stdio.printf("FAIL: MemBuddy init failed\n")
|
||||
return 1
|
||||
|
||||
# 设置全局 mbuddy 指针(sys 和 argparse 都需要)
|
||||
sys._mbuddy = mb
|
||||
argparse._mbuddy = mb
|
||||
ast._mbuddy = mb
|
||||
lib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
Config._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
Utils._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
HandlesTranslator._mbuddy = mb
|
||||
BuildPipeline._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
IncludesScanner._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
StubMerger._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
Phase1._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
Phase2._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
subprocess._mbuddy = mb
|
||||
hashlib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
lib.InitLib((memhub.MemManager | t.CPtr)(mb))
|
||||
|
||||
# 初始化 VLogger 并打印启动日志
|
||||
log: VLogger.Logger | t.CPtr = VLogger.get_logger()
|
||||
if log is not None:
|
||||
log.info("TransPyV 启动")
|
||||
|
||||
# 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline)
|
||||
sys._init_argv()
|
||||
|
||||
# 创建参数解析器
|
||||
parser: argparse.ArgumentParser | t.CPtr = argparse.ArgumentParser(
|
||||
"TransPyV", "TransPyV 命令行参数解析", pool=mb)
|
||||
|
||||
# 注册参数(与 Projectrans.py main() 一致)
|
||||
parser.add_argument("--project", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "project.json 路径(默认查找当前目录)")
|
||||
parser.add_argument("--src", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "源文件目录(覆盖 project.json)")
|
||||
parser.add_argument("--temp", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "声明接口临时目录(覆盖 project.json)")
|
||||
parser.add_argument("--output", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "输出目录(覆盖 project.json)")
|
||||
parser.add_argument("--phase", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "阶段: 1=生成声明, 2=翻译+编译, all=全部")
|
||||
parser.add_argument("--cc", None, argparse.STRING, 0, None, False,
|
||||
argparse.STORE, "LLVM 编译器命令(覆盖 project.json)")
|
||||
parser.add_argument("--clean", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "清理 output 和 temp 目录")
|
||||
parser.add_argument("--run", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "编译成功后立即执行生成的可执行文件")
|
||||
parser.add_argument("--rebuild-includes", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "删除 includes.binary 预编译缓存并重新编译所有 includes")
|
||||
parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False,
|
||||
argparse.STORE_TRUE, "清除 .transpyc_cache 全局缓存")
|
||||
|
||||
# 解析命令行参数
|
||||
args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv)
|
||||
if args is None:
|
||||
if log is not None:
|
||||
log.error("参数解析失败", "argparse")
|
||||
return 1
|
||||
|
||||
# 打印解析结果
|
||||
if log is not None:
|
||||
log.banner("TransPyV 参数解析结果")
|
||||
|
||||
# 字符串参数
|
||||
project: str = args.get_str("project")
|
||||
if project is not None:
|
||||
stdio.printf(" --project: %s\n", project)
|
||||
else:
|
||||
stdio.printf(" --project: (未指定)\n")
|
||||
|
||||
src: str = args.get_str("src")
|
||||
if src is not None:
|
||||
stdio.printf(" --src: %s\n", src)
|
||||
else:
|
||||
stdio.printf(" --src: (未指定)\n")
|
||||
|
||||
temp: str = args.get_str("temp")
|
||||
if temp is not None:
|
||||
stdio.printf(" --temp: %s\n", temp)
|
||||
else:
|
||||
stdio.printf(" --temp: (未指定)\n")
|
||||
|
||||
output: str = args.get_str("output")
|
||||
if output is not None:
|
||||
stdio.printf(" --output: %s\n", output)
|
||||
else:
|
||||
stdio.printf(" --output: (未指定)\n")
|
||||
|
||||
phase: str = args.get_str("phase")
|
||||
if phase is not None:
|
||||
stdio.printf(" --phase: %s\n", phase)
|
||||
else:
|
||||
stdio.printf(" --phase: (未指定,默认 all)\n")
|
||||
|
||||
cc: str = args.get_str("cc")
|
||||
if cc is not None:
|
||||
stdio.printf(" --cc: %s\n", cc)
|
||||
else:
|
||||
stdio.printf(" --cc: (未指定)\n")
|
||||
|
||||
# 布尔参数
|
||||
_gb_clean: INT = args.get_bool("clean")
|
||||
if _gb_clean:
|
||||
stdio.printf(" --clean: True\n")
|
||||
else:
|
||||
stdio.printf(" --clean: False\n")
|
||||
|
||||
if args.get_bool("run"):
|
||||
stdio.printf(" --run: True\n")
|
||||
else:
|
||||
stdio.printf(" --run: False\n")
|
||||
|
||||
if args.get_bool("rebuild-includes"):
|
||||
stdio.printf(" --rebuild-includes: True\n")
|
||||
else:
|
||||
stdio.printf(" --rebuild-includes: False\n")
|
||||
|
||||
if args.get_bool("clear-cache"):
|
||||
stdio.printf(" --clear-cache: True\n")
|
||||
else:
|
||||
stdio.printf(" --clear-cache: False\n")
|
||||
|
||||
stdio.printf("\n参数解析完成。\n")
|
||||
|
||||
# 加载 project.vpj 配置
|
||||
proj_loaded: int = 0
|
||||
proj_path: str = project
|
||||
if proj_path is not None:
|
||||
if log is not None:
|
||||
log.banner("工程配置")
|
||||
if Config.Load_project_config(proj_path) == 0:
|
||||
proj_loaded = 1
|
||||
else:
|
||||
stdio.printf(" 警告: 无法加载 project.vpj: %s\n", proj_path)
|
||||
else:
|
||||
# 尝试默认路径 project.vpj(当前目录和上级目录)
|
||||
proj_path = "project.vpj"
|
||||
if Config.Load_project_config(proj_path) == 0:
|
||||
proj_loaded = 1
|
||||
else:
|
||||
proj_path = "../project.vpj"
|
||||
if Config.Load_project_config(proj_path) == 0:
|
||||
proj_loaded = 1
|
||||
if proj_loaded == 1:
|
||||
# 提取 project.vpj 所在目录,将相对路径解析为基于该目录的路径
|
||||
proj_len: t.CSizeT = string.strlen(proj_path)
|
||||
slash_pos: t.CSizeT = proj_len
|
||||
for i in range(proj_len):
|
||||
idx: t.CSizeT = proj_len - 1 - i
|
||||
ch: t.CChar = proj_path[idx]
|
||||
if ch == '/' or ch == '\\':
|
||||
slash_pos = idx
|
||||
break
|
||||
proj_dir: str = ""
|
||||
if slash_pos > 0 and slash_pos < proj_len:
|
||||
proj_dir = stdlib.malloc(slash_pos + 1)
|
||||
if proj_dir is not None:
|
||||
string.memcpy(proj_dir, proj_path, slash_pos)
|
||||
proj_dir[slash_pos] = '\0'
|
||||
Config.resolve_paths(proj_dir)
|
||||
Config.print_config()
|
||||
|
||||
# === --clean: 清理 temp 和 output 目录 ===
|
||||
if _gb_clean:
|
||||
stdio.printf("\n[clean] 清理临时目录...\n")
|
||||
if Config.TempDir is not None:
|
||||
n: int = Utils.CleanDir(Config.TempDir)
|
||||
stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.TempDir, n)
|
||||
if Config.OutputDir is not None:
|
||||
n2: int = Utils.CleanDir(Config.OutputDir)
|
||||
stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.OutputDir, n2)
|
||||
|
||||
# === --phase 参数控制 ===
|
||||
# phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译
|
||||
# phase=2: 仅 stub 合并 + 编译(跳过 stub 分离)
|
||||
# phase=all: 两者都执行(默认)
|
||||
phase_mode: str = phase
|
||||
if phase_mode is None:
|
||||
phase_mode = "all"
|
||||
do_phase1: int = 0
|
||||
do_phase2: int = 0
|
||||
if phase_mode == "1" or phase_mode == "all":
|
||||
do_phase1 = 1
|
||||
if phase_mode == "2" or phase_mode == "all":
|
||||
do_phase2 = 1
|
||||
stdio.printf("[phase] 模式: %s (phase1=%d phase2=%d)\n", phase_mode, do_phase1, do_phase2)
|
||||
|
||||
# === Phase1: 扫描 includes(按需翻译)===
|
||||
# 对 includes 目录中每个 .py 文件,若 stub 不存在则翻译并分离 stub
|
||||
if do_phase1 != 0 and Config.IncludesDir is not None:
|
||||
ph1_temp: str = Config.TempDir
|
||||
if ph1_temp is None:
|
||||
ph1_temp = "."
|
||||
Phase1.RunPhase1(mb, Config.IncludesDir, ph1_temp, log)
|
||||
# 如果仅 Phase1(不执行 Phase2),直接退出
|
||||
if do_phase2 == 0:
|
||||
stdio.printf("[phase] Phase1 完成,退出\n")
|
||||
return 0
|
||||
|
||||
# AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树
|
||||
src_path: str = args.get_str("src")
|
||||
|
||||
# === 多文件项目模式 ===
|
||||
# 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .py 文件编译
|
||||
if src_path is None and project is not None and Config.SourceDir is not None:
|
||||
mf_temp: str = Config.TempDir if Config.TempDir is not None else "."
|
||||
mf_output: str = Config.OutputDir if Config.OutputDir is not None else "."
|
||||
mf_cc: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
|
||||
mf_cc_flags: str = Config.CompilerFlags if Config.CompilerFlags is not None else "-filetype=obj -relocation-model=pic"
|
||||
mf_linker: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
|
||||
mf_linker_flags: str = Config.LinkerFlags if Config.LinkerFlags is not None else "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition"
|
||||
mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe"
|
||||
mf_includes_bin: str = Config.get_includes_binary_dir()
|
||||
|
||||
mf_ret: int = Phase2.RunMultiFileProject(
|
||||
mb, Config.SourceDir, mf_temp, mf_output,
|
||||
mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out,
|
||||
mf_includes_bin, Config.IncludesDir, do_phase1, do_phase2, log, args)
|
||||
argparse.release(args)
|
||||
if log is not None:
|
||||
log.success("TransPyV 完成")
|
||||
return mf_ret
|
||||
|
||||
# === 单文件模式:--src 指定时使用指定文件;--project 但无 SourceDir 时回退 ===
|
||||
if src_path is None and project is not None:
|
||||
if Config.SourceDir is not None:
|
||||
# 构造入口路径: SourceDir/main.py
|
||||
sd_len: t.CSizeT = string.strlen(Config.SourceDir)
|
||||
path_buf: bytes = stdlib.malloc(sd_len + 16)
|
||||
if path_buf is not None:
|
||||
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir)
|
||||
src_path = path_buf
|
||||
stdio.printf("[project] 入口文件: %s\n", src_path)
|
||||
if src_path is not None:
|
||||
if log is not None:
|
||||
log.banner("AST 解析")
|
||||
# 打开文件
|
||||
f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
if log is not None:
|
||||
log.error("无法打开文件", "fileio")
|
||||
stdio.printf(" 路径: %s\n", src_path)
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 分配源代码缓冲区
|
||||
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
if src_buf is None:
|
||||
if log is not None:
|
||||
log.error("malloc for src_buf failed", "memhub")
|
||||
f.close()
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 读取文件内容
|
||||
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
||||
f.close()
|
||||
if bytes_read < 0:
|
||||
if log is not None:
|
||||
log.error("读取文件失败", "fileio")
|
||||
stdio.printf(" 错误码: %d\n", bytes_read)
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 添加 null 终止符,确保 strlen 和 SHA1 计算正确
|
||||
if bytes_read < SRC_BUF_SIZE:
|
||||
src_buf[bytes_read] = 0
|
||||
else:
|
||||
src_buf[SRC_BUF_SIZE - 1] = 0
|
||||
if log is not None:
|
||||
log.info("文件读取完成", "fileio")
|
||||
stdio.printf("读取 %d 字节\n", bytes_read)
|
||||
# 解析 AST(拆分为词法+语法两阶段,便于调试)
|
||||
ast._init_tables(mb)
|
||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||
ast._lexer_init(lx, src_buf, mb)
|
||||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||||
if tree is None:
|
||||
if log is not None:
|
||||
log.error("AST 解析失败", "ast")
|
||||
argparse.release(args)
|
||||
return 1
|
||||
|
||||
# === 翻译 AST → LLVM IR ===
|
||||
if log is not None:
|
||||
log.banner("LLVM IR 翻译")
|
||||
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
|
||||
result: int = tr.translate(tree)
|
||||
if result == 0:
|
||||
IR_BUF_SIZE: t.CSizeT = 262144
|
||||
ir_buf: bytes = stdlib.malloc(IR_BUF_SIZE)
|
||||
if ir_buf is not None:
|
||||
tr.dump_ir(ir_buf, IR_BUF_SIZE, llvmlite.OUTPUT_FULL)
|
||||
|
||||
# === 编译管线: .ll → .obj → .exe ===
|
||||
if log is not None:
|
||||
log.banner("编译管线")
|
||||
|
||||
# module_name 用源代码内容的 SHA1(前 16 字符),与 Projectrans.py 一致
|
||||
# output_name 从文件名推导(如 test.py -> test.exe),保持可读性
|
||||
module_name: str = Utils.compute_sha1(mb, src_buf)
|
||||
if module_name is None:
|
||||
module_name = "main"
|
||||
output_name: str = "test_prog.exe"
|
||||
# 从文件名提取 output_name(去掉路径和 .py 扩展名)
|
||||
src_len: t.CSizeT = string.strlen(src_path)
|
||||
if src_len > 0:
|
||||
# 找到最后一个 / 或 \ 之后的部分
|
||||
base_start: t.CSizeT = src_len
|
||||
i: t.CSizeT = src_len
|
||||
while i > 0:
|
||||
i -= 1
|
||||
ch: t.CChar = src_path[i]
|
||||
if ch == '/' or ch == '\\':
|
||||
base_start = i + 1
|
||||
break
|
||||
if i == 0:
|
||||
base_start = 0
|
||||
# 找到 .py 扩展名
|
||||
base_end: t.CSizeT = src_len
|
||||
j: t.CSizeT = base_start
|
||||
while j < src_len:
|
||||
if src_path[j] == '.':
|
||||
base_end = j
|
||||
break
|
||||
j += 1
|
||||
# 输出名 = 文件名 + ".exe"
|
||||
name_len: t.CSizeT = base_end - base_start
|
||||
if name_len > 0:
|
||||
out_len: t.CSizeT = name_len + 5
|
||||
output_name = stdlib.malloc(out_len)
|
||||
if output_name is not None:
|
||||
# 手动复制文件名并追加 .exe(viperlib.snprintf 不支持 %.*s,string 无 strcat)
|
||||
string.strncpy(output_name, src_path + base_start, name_len)
|
||||
output_name[name_len] = '.'
|
||||
output_name[name_len + 1] = 'e'
|
||||
output_name[name_len + 2] = 'x'
|
||||
output_name[name_len + 3] = 'e'
|
||||
output_name[name_len + 4] = '\0'
|
||||
# 使用 project.vpj 中的配置
|
||||
temp_dir: str = Config.TempDir if Config.TempDir is not None else "."
|
||||
output_dir: str = Config.OutputDir if Config.OutputDir is not None else "."
|
||||
cc_cmd: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
|
||||
cc_flags: str = "-filetype=obj -relocation-model=pic"
|
||||
linker_cmd: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
|
||||
linker_flags: str = "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition"
|
||||
# --project 模式且未显式指定 --src 时:使用 config 中的 linker_output(如 TransPyV.exe)
|
||||
# 显式指定 --src 时:使用从文件名推导的 output_name(如 test.exe),避免覆盖正在运行的 exe
|
||||
if project is not None and Config.LinkerOutput is not None and args.get_str("src") is None:
|
||||
linker_output: str = Config.LinkerOutput
|
||||
else:
|
||||
linker_output: str = output_name
|
||||
|
||||
# 计算 includes.binary 目录路径(链接时附加预编译 .obj)
|
||||
includes_binary_dir: str = Config.get_includes_binary_dir()
|
||||
|
||||
ir_len: t.CSizeT = string.strlen(ir_buf)
|
||||
|
||||
# (--phase 参数已在配置加载后处理,此处直接使用 do_phase1/do_phase2)
|
||||
|
||||
# === Phase1 stub 分离:使用 OUTPUT_STUB/TEXT 模式分别生成 stub.ll 和 text.ll ===
|
||||
if do_phase1 != 0 and temp_dir is not None and module_name is not None:
|
||||
if log is not None:
|
||||
log.banner("stub 分离")
|
||||
SF_IR_SIZE: t.CSizeT = 262144
|
||||
td_len_sf: t.CSizeT = string.strlen(temp_dir)
|
||||
# 保存 stub.ll
|
||||
sf_stub_buf: bytes = stdlib.malloc(SF_IR_SIZE)
|
||||
if sf_stub_buf is not None:
|
||||
tr.dump_ir(sf_stub_buf, SF_IR_SIZE, llvmlite.OUTPUT_STUB)
|
||||
sf_stub_len: t.CSizeT = string.strlen(sf_stub_buf)
|
||||
sf_stub_path: bytes = stdlib.malloc(td_len_sf + 32)
|
||||
if sf_stub_path is not None:
|
||||
viperlib.snprintf(sf_stub_path, td_len_sf + 32, "%s/%s.stub.ll", temp_dir, module_name)
|
||||
sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W)
|
||||
if not sf_f.closed:
|
||||
sf_f.write(sf_stub_buf, sf_stub_len)
|
||||
sf_f.close()
|
||||
stdlib.free(sf_stub_path)
|
||||
stdlib.free(sf_stub_buf)
|
||||
# 保存 text.ll
|
||||
sf_text_buf: bytes = stdlib.malloc(SF_IR_SIZE)
|
||||
if sf_text_buf is not None:
|
||||
tr.dump_ir(sf_text_buf, SF_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
||||
sf_text_len: t.CSizeT = string.strlen(sf_text_buf)
|
||||
sf_text_path: bytes = stdlib.malloc(td_len_sf + 32)
|
||||
if sf_text_path is not None:
|
||||
viperlib.snprintf(sf_text_path, td_len_sf + 32, "%s/%s.text.ll", temp_dir, module_name)
|
||||
sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W)
|
||||
if not sf_tf.closed:
|
||||
sf_tf.write(sf_text_buf, sf_text_len)
|
||||
sf_tf.close()
|
||||
stdlib.free(sf_text_path)
|
||||
stdlib.free(sf_text_buf)
|
||||
|
||||
# phase=1 模式:仅生成 stub,不执行编译
|
||||
if do_phase2 == 0:
|
||||
if log is not None:
|
||||
log.success("Phase1 完成(仅 stub 分离,跳过编译)")
|
||||
argparse.release(args)
|
||||
return 0
|
||||
|
||||
# === Phase2: 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR ===
|
||||
final_ir: bytes = ir_buf
|
||||
final_ir_len: t.CSizeT = ir_len
|
||||
if temp_dir is not None and module_name is not None:
|
||||
if log is not None:
|
||||
log.banner("IR 组合")
|
||||
SF_COMBINED_SIZE: t.CSizeT = 4194304 # 4MB
|
||||
combined_buf: bytes = stdlib.malloc(SF_COMBINED_SIZE)
|
||||
if combined_buf is not None:
|
||||
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, module_name, combined_buf, SF_COMBINED_SIZE)
|
||||
if combined_len > 0:
|
||||
final_ir = combined_buf
|
||||
final_ir_len = combined_len
|
||||
else:
|
||||
stdio.printf("[stub] BuildCombinedIR 失败,使用原始 IR\n")
|
||||
stdlib.free(combined_buf)
|
||||
|
||||
br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline(
|
||||
final_ir, final_ir_len, temp_dir, output_dir, module_name,
|
||||
cc_cmd, cc_flags, linker_cmd, linker_flags, linker_output,
|
||||
includes_binary_dir
|
||||
)
|
||||
if br is not None and br.Success == 1:
|
||||
if log is not None:
|
||||
log.success("编译管线完成")
|
||||
stdio.printf("输出: %s/%s\n", output_dir, linker_output)
|
||||
# --run 模式:执行生成的可执行文件
|
||||
if args.get_bool("run"):
|
||||
exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2)
|
||||
if exe_path is not None:
|
||||
viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output)
|
||||
stdio.printf("[run] 执行: %s\n", exe_path)
|
||||
r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
||||
if r is not None:
|
||||
stdio.printf("[run] 退出码: %d\n", r.returncode)
|
||||
else:
|
||||
if log is not None:
|
||||
log.error("编译管线失败", "pipeline")
|
||||
if br is not None and br.ErrorMsg is not None:
|
||||
stdio.printf("[FATAL] 编译管线失败: %s\n", br.ErrorMsg)
|
||||
sys.exit(1)
|
||||
else:
|
||||
if log is not None:
|
||||
log.error("malloc for IR buffer failed", "memhub")
|
||||
else:
|
||||
if log is not None:
|
||||
log.error("翻译失败", "translator")
|
||||
|
||||
argparse.release(args)
|
||||
if log is not None:
|
||||
log.success("TransPyV 完成")
|
||||
return 0
|
||||
47
Test/App/asm_test.py
Normal file
47
Test/App/asm_test.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# c.Asm 内联汇编测试
|
||||
# ============================================================
|
||||
|
||||
def asm_test() -> int:
|
||||
# 1. 简单无操作数汇编(nop + clobber)
|
||||
c.Asm("nop", op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
stdio.printf("asm: nop ok\n")
|
||||
|
||||
# 2. 仅汇编文本无 clobber
|
||||
c.Asm("nop")
|
||||
stdio.printf("asm: nop2 ok\n")
|
||||
|
||||
# 3. 多 clobber
|
||||
c.Asm("nop", op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_CC])
|
||||
stdio.printf("asm: multi-clobber ok\n")
|
||||
|
||||
# 4. 带输入操作数的汇编(读取 CPU ID)
|
||||
# 使用 f-string 内联 c.AsmInp
|
||||
# mov eax, 输入值; nop(保持简单,不使用会产生异常的指令)
|
||||
val: int = 42
|
||||
c.Asm(f"""mov eax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}
|
||||
nop""", op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
stdio.printf("asm: input ok val=%d\n", val)
|
||||
|
||||
# 5. 带输出操作数的汇编
|
||||
# c.AsmOut 获取结果
|
||||
result: int = 0
|
||||
c.Asm(f"""mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, 123
|
||||
nop""", op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
stdio.printf("asm: output result=%d\n", result)
|
||||
|
||||
# 6. 带输入和输出操作数
|
||||
# result2 = val + 1
|
||||
result2: int = 0
|
||||
input_val: int = 10
|
||||
c.Asm(f"""mov eax, {c.AsmInp(input_val, t.ASM_DESCR.REG_ANY)}
|
||||
add eax, 1
|
||||
mov {c.AsmOut(result2, t.ASM_DESCR.OUTPUT_REG)}, eax
|
||||
nop""", op=[t.ASM_DESCR.CLOBBER_RAX])
|
||||
stdio.printf("asm: in+out result2=%d (expect 11)\n", result2)
|
||||
|
||||
return 0
|
||||
234
Test/App/attr_test.py
Normal file
234
Test/App/attr_test.py
Normal file
@@ -0,0 +1,234 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import string
|
||||
|
||||
|
||||
# ============================================================
|
||||
# c.Attribute 装饰器测试
|
||||
#
|
||||
# 测试 @c.Attribute(...) 对函数属性的设置:
|
||||
# - t.attr.always_inline() -> alwaysinline
|
||||
# - t.attr.noinline() -> noinline
|
||||
# - t.attr.noreturn() -> noreturn
|
||||
# - t.attr.pure() -> readonly (LLVM 函数属性)
|
||||
# - t.attr.llvm.nounwind -> nounwind
|
||||
# ============================================================
|
||||
|
||||
|
||||
# Test 1: always_inline 属性
|
||||
@c.Attribute(t.attr.always_inline())
|
||||
def AlwaysInlineFunc(x: t.CInt) -> t.CInt:
|
||||
return x * 2
|
||||
|
||||
|
||||
# Test 2: noinline 属性
|
||||
@c.Attribute(t.attr.noinline())
|
||||
def NoInlineFunc(x: t.CInt) -> t.CInt:
|
||||
return x + 100
|
||||
|
||||
|
||||
# Test 3: noreturn 属性(函数确实不返回)
|
||||
@c.Attribute(t.attr.noreturn())
|
||||
def NoReturnFunc() -> t.CInt:
|
||||
stdio.printf("NoReturnFunc called (does not return)\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 4: 普通函数对照(无装饰器)
|
||||
def NormalFunc(x: t.CInt) -> t.CInt:
|
||||
return x * 3
|
||||
|
||||
|
||||
# Test 5: 多属性组合
|
||||
@c.Attribute(t.attr.always_inline(), t.attr.pure())
|
||||
def MultiAttrFunc(x: t.CInt) -> t.CInt:
|
||||
return x + 1
|
||||
|
||||
|
||||
# Test 6: 无括号属性引用 t.attr.packed
|
||||
@c.Attribute(t.attr.packed)
|
||||
def PackedAttrFunc(x: t.CInt) -> t.CInt:
|
||||
return x - 1
|
||||
|
||||
|
||||
def test_always_inline() -> t.CInt:
|
||||
stdio.printf("--- Test 1: c.Attribute(always_inline) ---\n")
|
||||
r: t.CInt = AlwaysInlineFunc(21)
|
||||
stdio.printf("AlwaysInlineFunc(21)=%d (expect 42)\n", r)
|
||||
if r == 42:
|
||||
stdio.printf("AlwaysInlineFunc OK\n")
|
||||
else:
|
||||
stdio.printf("AlwaysInlineFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_noinline() -> t.CInt:
|
||||
stdio.printf("--- Test 2: c.Attribute(noinline) ---\n")
|
||||
r: t.CInt = NoInlineFunc(5)
|
||||
stdio.printf("NoInlineFunc(5)=%d (expect 105)\n", r)
|
||||
if r == 105:
|
||||
stdio.printf("NoInlineFunc OK\n")
|
||||
else:
|
||||
stdio.printf("NoInlineFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_noreturn() -> t.CInt:
|
||||
stdio.printf("--- Test 3: c.Attribute(noreturn) ---\n")
|
||||
stdio.printf("NoReturnFunc declared with noreturn attr\n")
|
||||
stdio.printf("NoReturnFunc OK (not called to avoid UB)\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_normal() -> t.CInt:
|
||||
stdio.printf("--- Test 4: normal function (no attr) ---\n")
|
||||
r: t.CInt = NormalFunc(7)
|
||||
stdio.printf("NormalFunc(7)=%d (expect 21)\n", r)
|
||||
if r == 21:
|
||||
stdio.printf("NormalFunc OK\n")
|
||||
else:
|
||||
stdio.printf("NormalFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_multi_attr() -> t.CInt:
|
||||
stdio.printf("--- Test 5: c.Attribute(always_inline, pure) ---\n")
|
||||
r: t.CInt = MultiAttrFunc(10)
|
||||
stdio.printf("MultiAttrFunc(10)=%d (expect 11)\n", r)
|
||||
if r == 11:
|
||||
stdio.printf("MultiAttrFunc OK\n")
|
||||
else:
|
||||
stdio.printf("MultiAttrFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_packed_attr() -> t.CInt:
|
||||
stdio.printf("--- Test 6: c.Attribute(packed) ---\n")
|
||||
r: t.CInt = PackedAttrFunc(10)
|
||||
stdio.printf("PackedAttrFunc(10)=%d (expect 9)\n", r)
|
||||
if r == 9:
|
||||
stdio.printf("PackedAttrFunc OK\n")
|
||||
else:
|
||||
stdio.printf("PackedAttrFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 7: t.attr.llvm.nounwind 属性
|
||||
@c.Attribute(t.attr.llvm.nounwind)
|
||||
def NoUnwindFunc(x: t.CInt) -> t.CInt:
|
||||
return x + 1
|
||||
|
||||
|
||||
# Test 8: t.attr.llvm.noredzone 属性
|
||||
@c.Attribute(t.attr.llvm.noredzone)
|
||||
def NoRedZoneFunc(x: t.CInt) -> t.CInt:
|
||||
return x + 2
|
||||
|
||||
|
||||
# Test 9: t.attr.llvm.willreturn 属性
|
||||
@c.Attribute(t.attr.llvm.willreturn)
|
||||
def WillReturnFunc(x: t.CInt) -> t.CInt:
|
||||
return x + 3
|
||||
|
||||
|
||||
# Test 10: t.attr.llvm.mustprogress 属性
|
||||
@c.Attribute(t.attr.llvm.mustprogress)
|
||||
def MustProgressFunc(x: t.CInt) -> t.CInt:
|
||||
return x + 4
|
||||
|
||||
|
||||
# Test 11: t.attr.const() -> readnone
|
||||
@c.Attribute(t.attr.const())
|
||||
def ConstFunc(x: t.CInt) -> t.CInt:
|
||||
return x * 0 + 42
|
||||
|
||||
|
||||
# Test 12: 多属性组合(alwaysinline + nounwind + noredzone)
|
||||
@c.Attribute(t.attr.always_inline(), t.attr.llvm.nounwind, t.attr.llvm.noredzone)
|
||||
def TripleAttrFunc(x: t.CInt) -> t.CInt:
|
||||
return x + 5
|
||||
|
||||
|
||||
def test_nounwind() -> t.CInt:
|
||||
stdio.printf("--- Test 7: c.Attribute(llvm.nounwind) ---\n")
|
||||
r: t.CInt = NoUnwindFunc(10)
|
||||
stdio.printf("NoUnwindFunc(10)=%d (expect 11)\n", r)
|
||||
if r == 11:
|
||||
stdio.printf("NoUnwindFunc OK\n")
|
||||
else:
|
||||
stdio.printf("NoUnwindFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_noredzone() -> t.CInt:
|
||||
stdio.printf("--- Test 8: c.Attribute(llvm.noredzone) ---\n")
|
||||
r: t.CInt = NoRedZoneFunc(10)
|
||||
stdio.printf("NoRedZoneFunc(10)=%d (expect 12)\n", r)
|
||||
if r == 12:
|
||||
stdio.printf("NoRedZoneFunc OK\n")
|
||||
else:
|
||||
stdio.printf("NoRedZoneFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_willreturn() -> t.CInt:
|
||||
stdio.printf("--- Test 9: c.Attribute(llvm.willreturn) ---\n")
|
||||
r: t.CInt = WillReturnFunc(10)
|
||||
stdio.printf("WillReturnFunc(10)=%d (expect 13)\n", r)
|
||||
if r == 13:
|
||||
stdio.printf("WillReturnFunc OK\n")
|
||||
else:
|
||||
stdio.printf("WillReturnFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_mustprogress() -> t.CInt:
|
||||
stdio.printf("--- Test 10: c.Attribute(llvm.mustprogress) ---\n")
|
||||
r: t.CInt = MustProgressFunc(10)
|
||||
stdio.printf("MustProgressFunc(10)=%d (expect 14)\n", r)
|
||||
if r == 14:
|
||||
stdio.printf("MustProgressFunc OK\n")
|
||||
else:
|
||||
stdio.printf("MustProgressFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_const_attr() -> t.CInt:
|
||||
stdio.printf("--- Test 11: c.Attribute(const) ---\n")
|
||||
r: t.CInt = ConstFunc(99)
|
||||
stdio.printf("ConstFunc(99)=%d (expect 42)\n", r)
|
||||
if r == 42:
|
||||
stdio.printf("ConstFunc OK\n")
|
||||
else:
|
||||
stdio.printf("ConstFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def test_triple_attr() -> t.CInt:
|
||||
stdio.printf("--- Test 12: c.Attribute(always_inline, nounwind, noredzone) ---\n")
|
||||
r: t.CInt = TripleAttrFunc(10)
|
||||
stdio.printf("TripleAttrFunc(10)=%d (expect 15)\n", r)
|
||||
if r == 15:
|
||||
stdio.printf("TripleAttrFunc OK\n")
|
||||
else:
|
||||
stdio.printf("TripleAttrFunc FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def attr_test() -> t.CInt:
|
||||
stdio.printf("=== attr_test: c.Attribute 装饰器测试 ===\n\n")
|
||||
test_always_inline()
|
||||
test_noinline()
|
||||
test_noreturn()
|
||||
test_normal()
|
||||
test_multi_attr()
|
||||
test_packed_attr()
|
||||
test_nounwind()
|
||||
test_noredzone()
|
||||
test_willreturn()
|
||||
test_mustprogress()
|
||||
test_const_attr()
|
||||
test_triple_attr()
|
||||
stdio.printf("\n=== attr_test 完成 ===\n")
|
||||
return 0
|
||||
58
Test/App/augassign_test.py
Normal file
58
Test/App/augassign_test.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# AugAssign 测试:+= -= *= /= %= &= |= ^= <<= >>=
|
||||
# ============================================================
|
||||
|
||||
g_count: int = 0
|
||||
|
||||
|
||||
def test_local() -> int:
|
||||
x: int = 10
|
||||
x += 5
|
||||
stdio.printf("local +=: %d\n", x)
|
||||
x -= 3
|
||||
stdio.printf("local -=: %d\n", x)
|
||||
x *= 2
|
||||
stdio.printf("local *=: %d\n", x)
|
||||
x /= 4
|
||||
stdio.printf("local /=: %d\n", x)
|
||||
x %= 7
|
||||
stdio.printf("local %%=: %d\n", x)
|
||||
return 0
|
||||
|
||||
|
||||
def test_global_aug() -> int:
|
||||
global g_count
|
||||
g_count += 1
|
||||
stdio.printf("global +=: %d\n", g_count)
|
||||
g_count += 10
|
||||
stdio.printf("global +=: %d\n", g_count)
|
||||
g_count -= 3
|
||||
stdio.printf("global -=: %d\n", g_count)
|
||||
return 0
|
||||
|
||||
|
||||
def test_bitops() -> int:
|
||||
b: int = 0xFF
|
||||
b &= 0x0F
|
||||
stdio.printf("bit &=: %d\n", b)
|
||||
b |= 0x30
|
||||
stdio.printf("bit |=: %d\n", b)
|
||||
b ^= 0xFF
|
||||
stdio.printf("bit ^=: %d\n", b)
|
||||
b = 1
|
||||
b <<= 4
|
||||
stdio.printf("bit <<=: %d\n", b)
|
||||
b >>= 2
|
||||
stdio.printf("bit >>=: %d\n", b)
|
||||
return 0
|
||||
|
||||
|
||||
def augassign_test() -> int:
|
||||
test_local()
|
||||
test_global_aug()
|
||||
test_bitops()
|
||||
return 0
|
||||
45
Test/App/closure_test.py
Normal file
45
Test/App/closure_test.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 闭包 + nonlocal/global 测试
|
||||
# ============================================================
|
||||
|
||||
# 全局变量
|
||||
g_count: int = 0
|
||||
|
||||
|
||||
# global 关键字测试:修改全局变量
|
||||
def test_global() -> int:
|
||||
global g_count
|
||||
g_count = g_count + 1
|
||||
return g_count
|
||||
|
||||
|
||||
# nonlocal 关键字测试:嵌套函数修改外层局部变量
|
||||
def make_counter() -> t.CPtr:
|
||||
count: int = 0
|
||||
|
||||
# 内部函数(闭包)捕获 count
|
||||
def counter() -> int:
|
||||
nonlocal count
|
||||
count = count + 1
|
||||
return count
|
||||
|
||||
return counter
|
||||
|
||||
|
||||
def closure_test() -> int:
|
||||
# global 测试
|
||||
stdio.printf("global: %d\n", test_global())
|
||||
stdio.printf("global: %d\n", test_global())
|
||||
stdio.printf("global: %d\n", test_global())
|
||||
|
||||
# nonlocal/闭包测试
|
||||
f: t.CPtr = make_counter()
|
||||
stdio.printf("closure: %d\n", f())
|
||||
stdio.printf("closure: %d\n", f())
|
||||
stdio.printf("closure: %d\n", f())
|
||||
|
||||
return 0
|
||||
183
Test/App/deco_test.py
Normal file
183
Test/App/deco_test.py
Normal file
@@ -0,0 +1,183 @@
|
||||
import stdio
|
||||
import t, c
|
||||
import string
|
||||
|
||||
|
||||
# ============================================================
|
||||
# deco_test - t/c 装饰器测试
|
||||
#
|
||||
# 测试 t.CDefine / t.CExport / t.CInline / t.CExtern / t.State
|
||||
# ============================================================
|
||||
|
||||
|
||||
# Test 1: t.CDefine - 常量定义
|
||||
MAX_VALUE: t.CDefine = 256
|
||||
PI_APPROX: t.CDefine = 314
|
||||
# Test 10: t.CDefine 作为 t.CArray 的 count
|
||||
ARR_SIZE: t.CDefine = 8
|
||||
|
||||
|
||||
# Test 2: t.CExport - 导出函数标记
|
||||
def ExportedAdd(a: t.CInt, b: t.CInt) -> t.CInt | t.CExport:
|
||||
return a + b
|
||||
|
||||
|
||||
# Test 3: t.CInline - 内联函数标记
|
||||
def InlineSquare(x: t.CInt) -> t.CInt | t.CInline:
|
||||
return x * x
|
||||
|
||||
|
||||
# Test 4: 普通函数(无装饰器,作为对照)
|
||||
def NormalSub(a: t.CInt, b: t.CInt) -> t.CInt:
|
||||
return a - b
|
||||
|
||||
|
||||
# Test 5: t.CExport 与 t.CInline 组合
|
||||
def ExportedInlineCube(x: t.CInt) -> t.CInt | t.CExport | t.CInline:
|
||||
return x * x * x
|
||||
|
||||
|
||||
# Test 6: t.CExport 返回指针
|
||||
def ExportedFindChar(s: str, ch: t.CInt) -> str | t.CExport:
|
||||
return string.strchr(s, ch)
|
||||
|
||||
|
||||
def test_cdefine():
|
||||
stdio.printf("--- Test 1: t.CDefine ---\n")
|
||||
stdio.printf("MAX_VALUE=%d (expect 256)\n", MAX_VALUE)
|
||||
stdio.printf("PI_APPROX=%d (expect 314)\n", PI_APPROX)
|
||||
if MAX_VALUE == 256:
|
||||
stdio.printf("MAX_VALUE OK\n")
|
||||
else:
|
||||
stdio.printf("MAX_VALUE FAIL\n")
|
||||
if PI_APPROX == 314:
|
||||
stdio.printf("PI_APPROX OK\n")
|
||||
else:
|
||||
stdio.printf("PI_APPROX FAIL\n")
|
||||
|
||||
|
||||
def test_cexport():
|
||||
stdio.printf("--- Test 2: t.CExport ---\n")
|
||||
r: t.CInt = ExportedAdd(3, 4)
|
||||
stdio.printf("ExportedAdd(3,4)=%d (expect 7)\n", r)
|
||||
if r == 7:
|
||||
stdio.printf("ExportedAdd OK\n")
|
||||
else:
|
||||
stdio.printf("ExportedAdd FAIL\n")
|
||||
|
||||
|
||||
def test_cinline():
|
||||
stdio.printf("--- Test 3: t.CInline ---\n")
|
||||
r: t.CInt = InlineSquare(5)
|
||||
stdio.printf("InlineSquare(5)=%d (expect 25)\n", r)
|
||||
if r == 25:
|
||||
stdio.printf("InlineSquare OK\n")
|
||||
else:
|
||||
stdio.printf("InlineSquare FAIL\n")
|
||||
|
||||
|
||||
def test_deco_normal():
|
||||
stdio.printf("--- Test 4: normal function ---\n")
|
||||
r: t.CInt = NormalSub(10, 3)
|
||||
stdio.printf("NormalSub(10,3)=%d (expect 7)\n", r)
|
||||
if r == 7:
|
||||
stdio.printf("NormalSub OK\n")
|
||||
else:
|
||||
stdio.printf("NormalSub FAIL\n")
|
||||
|
||||
|
||||
def test_export_inline():
|
||||
stdio.printf("--- Test 5: t.CExport | t.CInline ---\n")
|
||||
r: t.CInt = ExportedInlineCube(3)
|
||||
stdio.printf("ExportedInlineCube(3)=%d (expect 27)\n", r)
|
||||
if r == 27:
|
||||
stdio.printf("ExportedInlineCube OK\n")
|
||||
else:
|
||||
stdio.printf("ExportedInlineCube FAIL\n")
|
||||
|
||||
|
||||
def test_export_ptr():
|
||||
stdio.printf("--- Test 6: t.CExport return ptr ---\n")
|
||||
p: str = ExportedFindChar("Hello", 108) # 'l' = 108
|
||||
if p is not None:
|
||||
stdio.printf("ExportedFindChar found, char=%d (expect 108)\n", c.Deref(p))
|
||||
if c.Deref(p) == 108:
|
||||
stdio.printf("ExportedFindChar OK\n")
|
||||
else:
|
||||
stdio.printf("ExportedFindChar FAIL\n")
|
||||
else:
|
||||
stdio.printf("ExportedFindChar NOT FOUND (FAIL)\n")
|
||||
|
||||
|
||||
# Test 7: t.CExtern | t.CExport - 外部声明函数(pass 体)
|
||||
# 声明一个外部函数,翻译器应生成 declare 而非 define
|
||||
def ExternalDecl(x: t.CInt) -> t.CInt | t.CExtern | t.CExport: pass
|
||||
|
||||
|
||||
# Test 8: t.State - 状态声明(等价于 CExtern | CExport)
|
||||
def StateDecl(x: t.CInt) -> t.CInt | t.State: pass
|
||||
|
||||
|
||||
# Test 9: t.State 返回 void
|
||||
def StateVoidDecl() -> t.State: pass
|
||||
|
||||
|
||||
def test_extern_decl():
|
||||
stdio.printf("--- Test 7: t.CExtern | t.CExport ---\n")
|
||||
# 外部声明函数,不调用(应由链接器解析符号)
|
||||
stdio.printf("ExternalDecl declared (not called)\n")
|
||||
stdio.printf("ExternalDecl OK\n")
|
||||
|
||||
|
||||
def test_state_decl():
|
||||
stdio.printf("--- Test 8: t.State ---\n")
|
||||
stdio.printf("StateDecl declared (not called)\n")
|
||||
stdio.printf("StateDecl OK\n")
|
||||
|
||||
|
||||
def test_state_void_decl():
|
||||
stdio.printf("--- Test 9: t.State (void) ---\n")
|
||||
stdio.printf("StateVoidDecl declared (not called)\n")
|
||||
stdio.printf("StateVoidDecl OK\n")
|
||||
|
||||
|
||||
# Test 10: t.CDefine 作为 t.CArray count
|
||||
# ARR_SIZE: t.CDefine = 8 已在文件顶部定义
|
||||
def test_cdefine_array_count():
|
||||
stdio.printf("--- Test 10: t.CArray[elem, CDefine] ---\n")
|
||||
# 使用 CDefine 常量名作为数组 count
|
||||
arr: t.CArray[t.CInt, ARR_SIZE]
|
||||
i: t.CInt
|
||||
# 初始化: arr[i] = i * 10
|
||||
for i in range(ARR_SIZE):
|
||||
arr[i] = i * 10
|
||||
# 求和验证: 0+10+20+...+70 = 280
|
||||
total: t.CInt = 0
|
||||
for i in range(ARR_SIZE):
|
||||
total += arr[i]
|
||||
stdio.printf("ARR_SIZE=%d (expect 8)\n", ARR_SIZE)
|
||||
stdio.printf("arr sum=%d (expect 280)\n", total)
|
||||
stdio.printf("arr[0]=%d (expect 0)\n", arr[0])
|
||||
stdio.printf("arr[7]=%d (expect 70)\n", arr[7])
|
||||
if ARR_SIZE == 8 and total == 280 and arr[0] == 0 and arr[7] == 70:
|
||||
stdio.printf("CArray CDefine count OK\n")
|
||||
else:
|
||||
stdio.printf("CArray CDefine count FAIL\n")
|
||||
|
||||
|
||||
def deco_test() -> int:
|
||||
stdio.printf("=== deco_test: t/c 装饰器测试 ===\n\n")
|
||||
|
||||
test_cdefine()
|
||||
test_cexport()
|
||||
test_cinline()
|
||||
test_deco_normal()
|
||||
test_export_inline()
|
||||
test_export_ptr()
|
||||
test_extern_decl()
|
||||
test_state_decl()
|
||||
test_state_void_decl()
|
||||
test_cdefine_array_count()
|
||||
|
||||
stdio.printf("\n=== deco_test 完成 ===\n")
|
||||
return 0
|
||||
9
Test/App/deref_min_test.py
Normal file
9
Test/App/deref_min_test.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
def deref_min_test() -> int:
|
||||
s: str = "hello"
|
||||
v: int = c.Deref(s)
|
||||
stdio.printf("deref: %d\n", v)
|
||||
return 0
|
||||
13
Test/App/deref_test.py
Normal file
13
Test/App/deref_test.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
def deref_test() -> int:
|
||||
s: str = "hello"
|
||||
sp: str = s
|
||||
slen: int = 0
|
||||
while c.Deref(sp) != 0:
|
||||
slen = slen + 1
|
||||
sp = sp + 1
|
||||
stdio.printf("ptr: len(hello)=%d\n", slen)
|
||||
return 0
|
||||
144
Test/App/eq_test.py
Normal file
144
Test/App/eq_test.py
Normal file
@@ -0,0 +1,144 @@
|
||||
import stdio
|
||||
import t, c
|
||||
import string
|
||||
|
||||
|
||||
# ============================================================
|
||||
# eq_test - ==、!=、is、is not、None 比较测试
|
||||
#
|
||||
# 验证比较表达式的翻译,特别是 None 常量和 is/is not 操作符
|
||||
# ============================================================
|
||||
|
||||
|
||||
def test_int_eq():
|
||||
stdio.printf("--- Test 1: int == / != ---\n")
|
||||
|
||||
a: t.CInt = 42
|
||||
b: t.CInt = 42
|
||||
c3: t.CInt = 99
|
||||
|
||||
if a == b:
|
||||
stdio.printf("int == int (same) OK\n")
|
||||
else:
|
||||
stdio.printf("int == int (same) FAIL\n")
|
||||
|
||||
if a != c3:
|
||||
stdio.printf("int != int (diff) OK\n")
|
||||
else:
|
||||
stdio.printf("int != int (diff) FAIL\n")
|
||||
|
||||
if not (a == c3):
|
||||
stdio.printf("not (int == diff) OK\n")
|
||||
else:
|
||||
stdio.printf("not (int == diff) FAIL\n")
|
||||
|
||||
|
||||
def test_int_cmp():
|
||||
stdio.printf("--- Test 2: int < > <= >= ---\n")
|
||||
|
||||
a: t.CInt = 5
|
||||
b: t.CInt = 10
|
||||
|
||||
if a < b:
|
||||
stdio.printf("int < OK\n")
|
||||
else:
|
||||
stdio.printf("int < FAIL\n")
|
||||
|
||||
if b > a:
|
||||
stdio.printf("int > OK\n")
|
||||
else:
|
||||
stdio.printf("int > FAIL\n")
|
||||
|
||||
if a <= 5:
|
||||
stdio.printf("int <= OK\n")
|
||||
else:
|
||||
stdio.printf("int <= FAIL\n")
|
||||
|
||||
if b >= 10:
|
||||
stdio.printf("int >= OK\n")
|
||||
else:
|
||||
stdio.printf("int >= FAIL\n")
|
||||
|
||||
|
||||
def test_ptr_is_none():
|
||||
stdio.printf("--- Test 3: ptr is None / is not None ---\n")
|
||||
|
||||
# strchr 找到字符返回非空指针,找不到返回 None
|
||||
p: str = string.strchr("Hello", 108) # 'l' = 108
|
||||
if p is not None:
|
||||
stdio.printf("strchr found, is not None OK\n")
|
||||
else:
|
||||
stdio.printf("strchr found, is not None FAIL\n")
|
||||
|
||||
p2: str = string.strchr("Hello", 122) # 'z' = 122, not found
|
||||
if p2 is None:
|
||||
stdio.printf("strchr not found, is None OK\n")
|
||||
else:
|
||||
stdio.printf("strchr not found, is None FAIL\n")
|
||||
|
||||
|
||||
def test_ptr_assign_none():
|
||||
stdio.printf("--- Test 4: assign None and compare ---\n")
|
||||
|
||||
p: str = None
|
||||
if p is None:
|
||||
stdio.printf("None assign, is None OK\n")
|
||||
else:
|
||||
stdio.printf("None assign, is None FAIL\n")
|
||||
|
||||
if p is not None:
|
||||
stdio.printf("None assign, is not None FAIL\n")
|
||||
else:
|
||||
stdio.printf("None assign, is not None OK\n")
|
||||
|
||||
|
||||
def test_ptr_eq_none():
|
||||
stdio.printf("--- Test 5: ptr == None / != None ---\n")
|
||||
|
||||
p: str = string.strstr("Hello World", "World")
|
||||
if p != None:
|
||||
stdio.printf("strstr found, != None OK\n")
|
||||
else:
|
||||
stdio.printf("strstr found, != None FAIL\n")
|
||||
|
||||
p2: str = string.strstr("Hello", "xyz")
|
||||
if p2 == None:
|
||||
stdio.printf("strstr not found, == None OK\n")
|
||||
else:
|
||||
stdio.printf("strstr not found, == None FAIL\n")
|
||||
|
||||
|
||||
def test_bool_logic():
|
||||
stdio.printf("--- Test 6: bool and/or ---\n")
|
||||
|
||||
a: t.CInt = 1
|
||||
b: t.CInt = 0
|
||||
|
||||
if a and b:
|
||||
stdio.printf("1 and 0 = true FAIL\n")
|
||||
else:
|
||||
stdio.printf("1 and 0 = false OK\n")
|
||||
|
||||
if a or b:
|
||||
stdio.printf("1 or 0 = true OK\n")
|
||||
else:
|
||||
stdio.printf("1 or 0 = true FAIL\n")
|
||||
|
||||
if not b:
|
||||
stdio.printf("not 0 = true OK\n")
|
||||
else:
|
||||
stdio.printf("not 0 = true FAIL\n")
|
||||
|
||||
|
||||
def eq_test() -> int:
|
||||
stdio.printf("=== eq_test: ==、!=、is、None 比较测试 ===\n\n")
|
||||
|
||||
test_int_eq()
|
||||
test_int_cmp()
|
||||
test_ptr_is_none()
|
||||
test_ptr_assign_none()
|
||||
test_ptr_eq_none()
|
||||
test_bool_logic()
|
||||
|
||||
stdio.printf("\n=== eq_test 完成 ===\n")
|
||||
return 0
|
||||
84
Test/App/float_test.py
Normal file
84
Test/App/float_test.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 联合体(t.CUnion)含浮点字段
|
||||
# ============================================================
|
||||
|
||||
class DataUnion(t.CUnion):
|
||||
i: t.CInt
|
||||
f: t.CFloat
|
||||
l: t.CInt64T
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主函数
|
||||
# ============================================================
|
||||
def float_test() -> int:
|
||||
# ============================================================
|
||||
# 测试 1: 基本浮点变量(float / double)
|
||||
# ============================================================
|
||||
f: t.CFloat = 3.14
|
||||
stdio.printf("float: f=%f\n", f)
|
||||
|
||||
d: t.CDouble = 3.141592653589793
|
||||
stdio.printf("double: d=%lf\n", d)
|
||||
|
||||
# 重新赋值
|
||||
f = 2.5
|
||||
stdio.printf("float: f=%f\n", f)
|
||||
|
||||
# ============================================================
|
||||
# 测试 2: 联合体浮点字段
|
||||
# ============================================================
|
||||
u: DataUnion
|
||||
u.f = 3.14
|
||||
stdio.printf("union: u.f=%f\n", u.f)
|
||||
|
||||
# 写入 i 字段后,f 的值已被覆盖
|
||||
u.i = 42
|
||||
stdio.printf("union: u.i=%d (after f overwritten)\n", u.i)
|
||||
|
||||
# ============================================================
|
||||
# 测试 3: 联合体共享内存验证(float 与 int 共享)
|
||||
# ============================================================
|
||||
u2: DataUnion
|
||||
u2.i = 0
|
||||
u2.f = 1.0
|
||||
# 写入 f 后,i 的值应不再是 0
|
||||
if u2.i != 0:
|
||||
stdio.printf("union: float overwrites int verified\n")
|
||||
|
||||
# ============================================================
|
||||
# 测试 4: 浮点算术运算(fadd/fsub/fmul/fdiv/frem)
|
||||
# ============================================================
|
||||
a: t.CFloat = 1.5
|
||||
b: t.CFloat = 2.5
|
||||
stdio.printf("arith: %.2f + %.2f = %.2f\n", a, b, a + b)
|
||||
stdio.printf("arith: %.2f - %.2f = %.2f\n", a, b, a - b)
|
||||
stdio.printf("arith: %.2f * %.2f = %.2f\n", a, b, a * b)
|
||||
stdio.printf("arith: %.2f / %.2f = %.2f\n", a, b, a / b)
|
||||
|
||||
# ============================================================
|
||||
# 测试 5: double 算术运算
|
||||
# ============================================================
|
||||
x: t.CDouble = 10.0
|
||||
y: t.CDouble = 3.0
|
||||
stdio.printf("arith: %.4lf + %.4lf = %.4lf\n", x, y, x + y)
|
||||
stdio.printf("arith: %.4lf - %.4lf = %.4lf\n", x, y, x - y)
|
||||
stdio.printf("arith: %.4lf * %.4lf = %.4lf\n", x, y, x * y)
|
||||
stdio.printf("arith: %.4lf / %.4lf = %.4lf\n", x, y, x / y)
|
||||
|
||||
# ============================================================
|
||||
# 测试 6: 浮点取模 (frem)
|
||||
# ============================================================
|
||||
stdio.printf("arith: 10.0 %% 3.0 = %.4lf\n", x % y)
|
||||
|
||||
# ============================================================
|
||||
# 测试 7: int 与 float 混合运算(int 自动转 float)
|
||||
# ============================================================
|
||||
n: t.CInt = 3
|
||||
stdio.printf("arith: %d + %.2f = %.2f\n", n, a, n + a)
|
||||
|
||||
return 0
|
||||
23
Test/App/flow_test.py
Normal file
23
Test/App/flow_test.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
def flow_test() -> int:
|
||||
i: int = 0
|
||||
total: int = 0
|
||||
while i < 5:
|
||||
total = total + i
|
||||
i = i + 1
|
||||
stdio.printf("while: total=%d i=%d\n", total, i)
|
||||
|
||||
for k in range(10):
|
||||
if k == 3:
|
||||
break
|
||||
stdio.printf("break: k=%d\n", k)
|
||||
|
||||
for m in range(5):
|
||||
if m == 2:
|
||||
continue
|
||||
stdio.printf("continue: m=%d\n", m)
|
||||
|
||||
return 0
|
||||
8
Test/App/for_test.py
Normal file
8
Test/App/for_test.py
Normal file
@@ -0,0 +1,8 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
def for_test() -> int:
|
||||
for j in range(5):
|
||||
stdio.printf("for: j=%d\n", j)
|
||||
return 0
|
||||
68
Test/App/func_test.py
Normal file
68
Test/App/func_test.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
def add(a: int, b: int) -> int:
|
||||
return a + b
|
||||
|
||||
|
||||
def mul(a: int, b: int) -> int:
|
||||
return a * b
|
||||
|
||||
|
||||
def square(x: int) -> int:
|
||||
return mul(x, x)
|
||||
|
||||
|
||||
def factorial(n: int) -> int:
|
||||
if n <= 1:
|
||||
return 1
|
||||
return n * factorial(n - 1)
|
||||
|
||||
|
||||
def greet(greeting: str, name: str, times: int) -> int:
|
||||
i: int = 0
|
||||
while i < times:
|
||||
stdio.printf("%s, %s!\n", greeting, name)
|
||||
i = i + 1
|
||||
return times
|
||||
|
||||
|
||||
def sub(a: int, b: int) -> int:
|
||||
return a - b
|
||||
|
||||
|
||||
def func_test() -> int:
|
||||
r1: int = add(3, 4)
|
||||
stdio.printf("add(3,4)=%d\n", r1)
|
||||
|
||||
r2: int = mul(5, 6)
|
||||
stdio.printf("mul(5,6)=%d\n", r2)
|
||||
|
||||
r3: int = square(7)
|
||||
stdio.printf("square(7)=%d\n", r3)
|
||||
|
||||
r5: int = factorial(5)
|
||||
stdio.printf("factorial(5)=%d\n", r5)
|
||||
|
||||
# ============================================================
|
||||
# 测试: 函数乱序传参(关键字参数)
|
||||
# ============================================================
|
||||
# 乱序传参:b=4, a=3 等价于 add(3, 4)
|
||||
r6: int = add(b=4, a=3)
|
||||
stdio.printf("add(b=4,a=3)=%d\n", r6)
|
||||
|
||||
# 乱序传参:a=10, b=3 等价于 sub(10, 3)
|
||||
r7: int = sub(b=3, a=10)
|
||||
stdio.printf("sub(b=3,a=10)=%d\n", r7)
|
||||
|
||||
# 混合传参:位置参数 + 关键字参数
|
||||
# greeting="Hello" 是位置参数,name="World" 和 times=2 是关键字
|
||||
r8: int = greet("Hello", name="World", times=2)
|
||||
stdio.printf("greet mixed: returned=%d\n", r8)
|
||||
|
||||
# 全关键字乱序传参
|
||||
r9: int = greet(times=1, name="TransPyC", greeting="Hi")
|
||||
stdio.printf("greet kwargs: returned=%d\n", r9)
|
||||
|
||||
return 0
|
||||
116
Test/App/func_vtable_test.py
Normal file
116
Test/App/func_vtable_test.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 场景 A: @t.NoVTable 类 + 函数级 @t.CVTable
|
||||
#
|
||||
# NoVTableClass 标记 @t.NoVTable(类级别禁用虚表)
|
||||
# 但 VirtualMethod 标记 @t.CVTable → 该方法单独进入虚表
|
||||
# NormalMethod 无装饰器 → 不进入虚表
|
||||
# 预期: 虚表 1 个方法 (VirtualMethod)
|
||||
# ============================================================
|
||||
@t.NoVTable
|
||||
class NoVTableClass:
|
||||
val: t.CInt
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self.val = v
|
||||
|
||||
@t.CVTable
|
||||
def VirtualMethod(self) -> t.CInt:
|
||||
return self.val + 10
|
||||
|
||||
def NormalMethod(self) -> t.CInt:
|
||||
return self.val + 20
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 场景 B: @t.CVTable 类 + 函数级 @t.NoVTable
|
||||
#
|
||||
# CVTableClass 标记 @t.CVTable(所有方法进入虚表)
|
||||
# KeptMethod 无装饰器 → 进入虚表
|
||||
# ExcludedMethod 标记 @t.NoVTable → 排除出虚表
|
||||
# 预期: 虚表 1 个方法 (KeptMethod)
|
||||
# ============================================================
|
||||
@t.CVTable
|
||||
class CVTableClass:
|
||||
val: t.CInt
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self.val = v
|
||||
|
||||
def KeptMethod(self) -> t.CInt:
|
||||
return self.val + 30
|
||||
|
||||
@t.NoVTable
|
||||
def ExcludedMethod(self) -> t.CInt:
|
||||
return self.val + 40
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 场景 C: 默认类(无装饰器无继承)+ 函数级 @t.CVTable
|
||||
#
|
||||
# DefaultClass 无装饰器(默认无虚表)
|
||||
# VirtualMethod 标记 @t.CVTable → 单独进入虚表
|
||||
# NormalMethod 无装饰器 → 不进入虚表
|
||||
# 预期: 虚表 1 个方法 (VirtualMethod)
|
||||
# ============================================================
|
||||
class DefaultClass:
|
||||
val: t.CInt
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self.val = v
|
||||
|
||||
@t.CVTable
|
||||
def VirtualMethod(self) -> t.CInt:
|
||||
return self.val + 50
|
||||
|
||||
def NormalMethod(self) -> t.CInt:
|
||||
return self.val + 60
|
||||
|
||||
|
||||
def func_vtable_test() -> int:
|
||||
stdio.printf("funcvt: === Test Start ===\n")
|
||||
|
||||
# 场景 A: NoVTableClass
|
||||
nvt: NoVTableClass = NoVTableClass(5)
|
||||
a1: int = nvt.VirtualMethod()
|
||||
stdio.printf("funcvt: A.VirtualMethod()=%d (expected 15)\n", a1)
|
||||
if a1 != 15:
|
||||
stdio.printf("[FAIL] A.VirtualMethod()=%d expected 15\n", a1)
|
||||
return 1
|
||||
a2: int = nvt.NormalMethod()
|
||||
stdio.printf("funcvt: A.NormalMethod()=%d (expected 25)\n", a2)
|
||||
if a2 != 25:
|
||||
stdio.printf("[FAIL] A.NormalMethod()=%d expected 25\n", a2)
|
||||
return 1
|
||||
|
||||
# 场景 B: CVTableClass
|
||||
cvt: CVTableClass = CVTableClass(7)
|
||||
b1: int = cvt.KeptMethod()
|
||||
stdio.printf("funcvt: B.KeptMethod()=%d (expected 37)\n", b1)
|
||||
if b1 != 37:
|
||||
stdio.printf("[FAIL] B.KeptMethod()=%d expected 37\n", b1)
|
||||
return 1
|
||||
b2: int = cvt.ExcludedMethod()
|
||||
stdio.printf("funcvt: B.ExcludedMethod()=%d (expected 47)\n", b2)
|
||||
if b2 != 47:
|
||||
stdio.printf("[FAIL] B.ExcludedMethod()=%d expected 47\n", b2)
|
||||
return 1
|
||||
|
||||
# 场景 C: DefaultClass
|
||||
dfc: DefaultClass = DefaultClass(9)
|
||||
c1: int = dfc.VirtualMethod()
|
||||
stdio.printf("funcvt: C.VirtualMethod()=%d (expected 59)\n", c1)
|
||||
if c1 != 59:
|
||||
stdio.printf("[FAIL] C.VirtualMethod()=%d expected 59\n", c1)
|
||||
return 1
|
||||
c2: int = dfc.NormalMethod()
|
||||
stdio.printf("funcvt: C.NormalMethod()=%d (expected 69)\n", c2)
|
||||
if c2 != 69:
|
||||
stdio.printf("[FAIL] C.NormalMethod()=%d expected 69\n", c2)
|
||||
return 1
|
||||
|
||||
stdio.printf("funcvt: === All Tests Passed ===\n")
|
||||
return 0
|
||||
102
Test/App/generic_test.py
Normal file
102
Test/App/generic_test.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import stdio
|
||||
import stdlib
|
||||
import t, c
|
||||
import testcheck
|
||||
import memhub
|
||||
import _list
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 泛型类 list[T] 测试
|
||||
# ============================================================
|
||||
def generic_test() -> int:
|
||||
testcheck.begin("GenericTest: list[T] 泛型类测试")
|
||||
|
||||
# 创建 mbuddy arena
|
||||
arena: bytes = stdlib.malloc(65536)
|
||||
bd: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, 65536)
|
||||
|
||||
# === Test 1: 创建和 append ===
|
||||
testcheck.section("Test 1: 创建和 append")
|
||||
nums = list[int](bd)
|
||||
nums.append(10)
|
||||
nums.append(20)
|
||||
nums.append(30)
|
||||
v0: t.CInt = nums.get(0)
|
||||
v1: t.CInt = nums.get(1)
|
||||
v2: t.CInt = nums.get(2)
|
||||
stdio.printf("v0=%d v1=%d v2=%d\n", v0, v1, v2)
|
||||
testcheck.check(v0 == 10 and v1 == 20 and v2 == 30,
|
||||
"append+get OK (10,20,30)", "append+get FAILED")
|
||||
|
||||
# === Test 2: __len__ ===
|
||||
testcheck.section("Test 2: __len__")
|
||||
n: t.CSizeT = nums.__len__()
|
||||
stdio.printf("len=%lu\n", n)
|
||||
testcheck.check(n == 3, "__len__ OK (3)", "__len__ FAILED expect 3")
|
||||
|
||||
# === Test 3: set ===
|
||||
testcheck.section("Test 3: set")
|
||||
nums.set(1, 99)
|
||||
v1b: t.CInt = nums.get(1)
|
||||
stdio.printf("after set(1,99): v1=%d\n", v1b)
|
||||
testcheck.check(v1b == 99, "set OK (idx1=99)", "set FAILED")
|
||||
|
||||
# === Test 4: pop ===
|
||||
testcheck.section("Test 4: pop")
|
||||
popped: t.CInt = nums.pop()
|
||||
stdio.printf("popped=%d\n", popped)
|
||||
testcheck.check(popped == 30, "pop OK (30)", "pop FAILED expect 30")
|
||||
n2: t.CSizeT = nums.__len__()
|
||||
testcheck.check(n2 == 2, "pop len OK (2)", "pop len FAILED expect 2")
|
||||
|
||||
# === Test 5: clear ===
|
||||
testcheck.section("Test 5: clear")
|
||||
nums.clear()
|
||||
n3: t.CSizeT = nums.__len__()
|
||||
testcheck.check(n3 == 0, "clear OK (0)", "clear FAILED expect 0")
|
||||
|
||||
# === Test 6: 容量增长 (append 超过初始容量 8) ===
|
||||
testcheck.section("Test 6: 容量增长")
|
||||
nums2 = list[int](bd)
|
||||
i: t.CInt
|
||||
for i in range(20):
|
||||
nums2.append(i * 5)
|
||||
n4: t.CSizeT = nums2.__len__()
|
||||
stdio.printf("after 20 appends: len=%lu\n", n4)
|
||||
testcheck.check(n4 == 20, "grow len OK (20)", "grow len FAILED")
|
||||
ok: t.CInt = 1
|
||||
for i in range(20):
|
||||
v: t.CInt = nums2.get(i)
|
||||
if v != i * 5:
|
||||
stdio.printf("MISMATCH at %d: got %d expect %d\n", i, v, i * 5)
|
||||
ok = 0
|
||||
break
|
||||
testcheck.check(ok == 1, "grow data OK", "grow data FAILED")
|
||||
|
||||
# === Test 7: 多个 list[int] 实例独立 ===
|
||||
testcheck.section("Test 7: 多实例独立")
|
||||
lst_a = list[int](bd)
|
||||
lst_b = list[int](bd)
|
||||
lst_a.append(111)
|
||||
lst_b.append(222)
|
||||
va: t.CInt = lst_a.get(0)
|
||||
vb: t.CInt = lst_b.get(0)
|
||||
stdio.printf("lst_a[0]=%d lst_b[0]=%d\n", va, vb)
|
||||
testcheck.check(va == 111 and vb == 222,
|
||||
"multi-instance OK (111,222)", "multi-instance FAILED")
|
||||
|
||||
# === Test 8: __getitem__ / __setitem__ ===
|
||||
testcheck.section("Test 8: __getitem__/__setitem__")
|
||||
nums3 = list[int](bd)
|
||||
nums3.append(1)
|
||||
nums3.append(2)
|
||||
nums3.append(3)
|
||||
nums3[0] = 100
|
||||
gv: t.CInt = nums3[0]
|
||||
stdio.printf("nums3[0]=%d after setitem\n", gv)
|
||||
testcheck.check(gv == 100, "__setitem__/__getitem__ OK",
|
||||
"__setitem__/__getitem__ FAILED")
|
||||
|
||||
stdlib.free(arena)
|
||||
return testcheck.end()
|
||||
121
Test/App/inherit_test.py
Normal file
121
Test/App/inherit_test.py
Normal file
@@ -0,0 +1,121 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 继承测试:字段展平 + vtable 继承 + 方法覆盖
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 基类 Animal(有虚方法)
|
||||
# ============================================================
|
||||
@t.CVTable
|
||||
class Animal:
|
||||
name: t.CInt
|
||||
|
||||
def __init__(self, n: t.CInt):
|
||||
self.name = n
|
||||
|
||||
def GetName(self) -> t.CInt:
|
||||
return self.name
|
||||
|
||||
def Speak(self) -> t.CInt:
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 子类 Dog(继承 Animal,覆盖 Speak,新增字段和方法)
|
||||
# ============================================================
|
||||
class Dog(Animal):
|
||||
breed: t.CInt
|
||||
|
||||
def __init__(self, n: t.CInt, b: t.CInt):
|
||||
self.name = n
|
||||
self.breed = b
|
||||
|
||||
def Speak(self) -> t.CInt:
|
||||
return 1
|
||||
|
||||
def GetBreed(self) -> t.CInt:
|
||||
return self.breed
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 子类 Cat(继承 Animal,不覆盖 Speak,新增字段和方法)
|
||||
# ============================================================
|
||||
class Cat(Animal):
|
||||
color: t.CInt
|
||||
|
||||
def __init__(self, n: t.CInt, col: t.CInt):
|
||||
self.name = n
|
||||
self.color = col
|
||||
|
||||
def GetColor(self) -> t.CInt:
|
||||
return self.color
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主函数
|
||||
# ============================================================
|
||||
def inherit_test() -> int:
|
||||
# ============================================================
|
||||
# 测试 1: 基类 Animal
|
||||
# ============================================================
|
||||
stdio.printf("inherit: === Test 1: Base Class ===\n")
|
||||
a: Animal = Animal(42)
|
||||
aname: int = a.GetName()
|
||||
stdio.printf("inherit: a.GetName()=%d (expected 42)\n", aname)
|
||||
if aname != 42:
|
||||
stdio.printf("[FAIL] a.GetName()=%d expected 42\n", aname)
|
||||
return 1
|
||||
aspeak: int = a.Speak()
|
||||
stdio.printf("inherit: a.Speak()=%d (expected 0)\n", aspeak)
|
||||
if aspeak != 0:
|
||||
stdio.printf("[FAIL] a.Speak()=%d expected 0\n", aspeak)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# 测试 2: 子类 Dog(覆盖 Speak,继承 GetName)
|
||||
# ============================================================
|
||||
stdio.printf("inherit: === Test 2: Dog (override Speak) ===\n")
|
||||
d: Dog = Dog(100, 7)
|
||||
dname: int = d.GetName()
|
||||
stdio.printf("inherit: d.GetName()=%d (expected 100)\n", dname)
|
||||
if dname != 100:
|
||||
stdio.printf("[FAIL] d.GetName()=%d expected 100\n", dname)
|
||||
return 1
|
||||
dspeak: int = d.Speak()
|
||||
stdio.printf("inherit: d.Speak()=%d (expected 1)\n", dspeak)
|
||||
if dspeak != 1:
|
||||
stdio.printf("[FAIL] d.Speak()=%d expected 1\n", dspeak)
|
||||
return 1
|
||||
dbreed: int = d.GetBreed()
|
||||
stdio.printf("inherit: d.GetBreed()=%d (expected 7)\n", dbreed)
|
||||
if dbreed != 7:
|
||||
stdio.printf("[FAIL] d.GetBreed()=%d expected 7\n", dbreed)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# 测试 3: 子类 Cat(不覆盖 Speak,继承 GetName)
|
||||
# ============================================================
|
||||
stdio.printf("inherit: === Test 3: Cat (inherit Speak) ===\n")
|
||||
ct: Cat = Cat(200, 3)
|
||||
cname: int = ct.GetName()
|
||||
stdio.printf("inherit: ct.GetName()=%d (expected 200)\n", cname)
|
||||
if cname != 200:
|
||||
stdio.printf("[FAIL] ct.GetName()=%d expected 200\n", cname)
|
||||
return 1
|
||||
cspeak: int = ct.Speak()
|
||||
stdio.printf("inherit: ct.Speak()=%d (expected 0)\n", cspeak)
|
||||
if cspeak != 0:
|
||||
stdio.printf("[FAIL] ct.Speak()=%d expected 0\n", cspeak)
|
||||
return 1
|
||||
ccolor: int = ct.GetColor()
|
||||
stdio.printf("inherit: ct.GetColor()=%d (expected 3)\n", ccolor)
|
||||
if ccolor != 3:
|
||||
stdio.printf("[FAIL] ct.GetColor()=%d expected 3\n", ccolor)
|
||||
return 1
|
||||
|
||||
stdio.printf("inherit: === All Tests Passed ===\n")
|
||||
return 0
|
||||
247
Test/App/llvmir_test.py
Normal file
247
Test/App/llvmir_test.py
Normal file
@@ -0,0 +1,247 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
|
||||
|
||||
# ============================================================
|
||||
# c.LLVMIR / c.LInp / c.LOut 内联 LLVM IR 测试
|
||||
#
|
||||
# 测试 c.LLVMIR 内联 LLVM IR 指令的生成和执行
|
||||
# - c.LInp(expr) 标记输入操作数
|
||||
# - c.LOut(expr) 标记输出操作数
|
||||
# ============================================================
|
||||
|
||||
|
||||
# Test 1: 基本加法 add
|
||||
def test_add() -> t.CInt:
|
||||
stdio.printf("--- Test 1: LLVMIR add ---\n")
|
||||
a: t.CInt = 10
|
||||
b: t.CInt = 20
|
||||
r: t.CInt = c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("add(10, 20)=%d (expect 30)\n", r)
|
||||
if r == 30:
|
||||
stdio.printf("LLVMIR add OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR add FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 2: 基本减法 sub
|
||||
def test_sub() -> t.CInt:
|
||||
stdio.printf("--- Test 2: LLVMIR sub ---\n")
|
||||
a: t.CInt = 50
|
||||
b: t.CInt = 20
|
||||
r: t.CInt = c.LLVMIR(f"sub i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("sub(50, 20)=%d (expect 30)\n", r)
|
||||
if r == 30:
|
||||
stdio.printf("LLVMIR sub OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR sub FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 3: 基本乘法 mul
|
||||
def test_mul() -> t.CInt:
|
||||
stdio.printf("--- Test 3: LLVMIR mul ---\n")
|
||||
a: t.CInt = 6
|
||||
b: t.CInt = 7
|
||||
r: t.CInt = c.LLVMIR(f"mul i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("mul(6, 7)=%d (expect 42)\n", r)
|
||||
if r == 42:
|
||||
stdio.printf("LLVMIR mul OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR mul FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 4: 基本除法 sdiv
|
||||
def test_sdiv() -> t.CInt:
|
||||
stdio.printf("--- Test 4: LLVMIR sdiv ---\n")
|
||||
a: t.CInt = 100
|
||||
b: t.CInt = 4
|
||||
r: t.CInt = c.LLVMIR(f"sdiv i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("sdiv(100, 4)=%d (expect 25)\n", r)
|
||||
if r == 25:
|
||||
stdio.printf("LLVMIR sdiv OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR sdiv FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 5: 位运算 and
|
||||
def test_and() -> t.CInt:
|
||||
stdio.printf("--- Test 5: LLVMIR and ---\n")
|
||||
a: t.CInt = 255
|
||||
b: t.CInt = 15
|
||||
r: t.CInt = c.LLVMIR(f"and i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("and(255, 15)=%d (expect 15)\n", r)
|
||||
if r == 15:
|
||||
stdio.printf("LLVMIR and OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR and FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 6: 位运算 or
|
||||
def test_or() -> t.CInt:
|
||||
stdio.printf("--- Test 6: LLVMIR or ---\n")
|
||||
a: t.CInt = 240
|
||||
b: t.CInt = 15
|
||||
r: t.CInt = c.LLVMIR(f"or i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("or(240, 15)=%d (expect 255)\n", r)
|
||||
if r == 255:
|
||||
stdio.printf("LLVMIR or OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR or FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 7: 位运算 xor
|
||||
def test_xor() -> t.CInt:
|
||||
stdio.printf("--- Test 7: LLVMIR xor ---\n")
|
||||
a: t.CInt = 255
|
||||
b: t.CInt = 15
|
||||
r: t.CInt = c.LLVMIR(f"xor i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("xor(255, 15)=%d (expect 240)\n", r)
|
||||
if r == 240:
|
||||
stdio.printf("LLVMIR xor OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR xor FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 8: 左移 shl
|
||||
def test_shl() -> t.CInt:
|
||||
stdio.printf("--- Test 8: LLVMIR shl ---\n")
|
||||
a: t.CInt = 1
|
||||
b: t.CInt = 4
|
||||
r: t.CInt = c.LLVMIR(f"shl i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("shl(1, 4)=%d (expect 16)\n", r)
|
||||
if r == 16:
|
||||
stdio.printf("LLVMIR shl OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR shl FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 9: LOut 输出赋值
|
||||
def test_lout() -> t.CInt:
|
||||
stdio.printf("--- Test 9: LLVMIR LOut ---\n")
|
||||
a: t.CInt = 10
|
||||
b: t.CInt = 20
|
||||
out_val: t.CInt = 0
|
||||
c.LLVMIR(f"{c.LOut(out_val)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("LOut add(10, 20)=%d (expect 30)\n", out_val)
|
||||
if out_val == 30:
|
||||
stdio.printf("LLVMIR LOut OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR LOut FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 10: icmp eq 比较
|
||||
# 注意: TransPyV 用 sext i1 to i32 扩展布尔结果,true -> -1
|
||||
def test_icmp_eq() -> t.CInt:
|
||||
stdio.printf("--- Test 10: LLVMIR icmp eq ---\n")
|
||||
a: t.CInt = 5
|
||||
b: t.CInt = 5
|
||||
r: t.CInt = c.LLVMIR(f"icmp eq i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("icmp eq(5, 5)=%d (expect nonzero)\n", r)
|
||||
if r != 0:
|
||||
stdio.printf("LLVMIR icmp eq OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR icmp eq FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 11: icmp ne 比较
|
||||
def test_icmp_ne() -> t.CInt:
|
||||
stdio.printf("--- Test 11: LLVMIR icmp ne ---\n")
|
||||
a: t.CInt = 5
|
||||
b: t.CInt = 3
|
||||
r: t.CInt = c.LLVMIR(f"icmp ne i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("icmp ne(5, 3)=%d (expect nonzero)\n", r)
|
||||
if r != 0:
|
||||
stdio.printf("LLVMIR icmp ne OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR icmp ne FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 12: icmp slt 比较
|
||||
def test_icmp_slt() -> t.CInt:
|
||||
stdio.printf("--- Test 12: LLVMIR icmp slt ---\n")
|
||||
a: t.CInt = 3
|
||||
b: t.CInt = 5
|
||||
r: t.CInt = c.LLVMIR(f"icmp slt i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("icmp slt(3, 5)=%d (expect nonzero)\n", r)
|
||||
if r != 0:
|
||||
stdio.printf("LLVMIR icmp slt OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR icmp slt FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 13: srem 取余
|
||||
def test_srem() -> t.CInt:
|
||||
stdio.printf("--- Test 13: LLVMIR srem ---\n")
|
||||
a: t.CInt = 17
|
||||
b: t.CInt = 5
|
||||
r: t.CInt = c.LLVMIR(f"srem i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("srem(17, 5)=%d (expect 2)\n", r)
|
||||
if r == 2:
|
||||
stdio.printf("LLVMIR srem OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR srem FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 14: lshr 逻辑右移
|
||||
def test_lshr() -> t.CInt:
|
||||
stdio.printf("--- Test 14: LLVMIR lshr ---\n")
|
||||
a: t.CInt = 256
|
||||
b: t.CInt = 2
|
||||
r: t.CInt = c.LLVMIR(f"lshr i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
stdio.printf("lshr(256, 2)=%d (expect 64)\n", r)
|
||||
if r == 64:
|
||||
stdio.printf("LLVMIR lshr OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR lshr FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
# Test 15: 嵌套在表达式中使用
|
||||
def test_nested() -> t.CInt:
|
||||
stdio.printf("--- Test 15: LLVMIR nested in expression ---\n")
|
||||
a: t.CInt = 10
|
||||
b: t.CInt = 20
|
||||
# c.LLVMIR 结果参与后续运算
|
||||
llvmir_result: t.CInt = c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
|
||||
final_result: t.CInt = llvmir_result + 10
|
||||
stdio.printf("(LLVMIR add(10,20)) + 10 = %d (expect 40)\n", final_result)
|
||||
if final_result == 40:
|
||||
stdio.printf("LLVMIR nested OK\n")
|
||||
else:
|
||||
stdio.printf("LLVMIR nested FAIL\n")
|
||||
return 0
|
||||
|
||||
|
||||
def llvmir_test() -> t.CInt:
|
||||
stdio.printf("=== llvmir_test: c.LLVMIR 内联 LLVM IR 测试 ===\n\n")
|
||||
test_add()
|
||||
test_sub()
|
||||
test_mul()
|
||||
test_sdiv()
|
||||
test_and()
|
||||
test_or()
|
||||
test_xor()
|
||||
test_shl()
|
||||
test_lout()
|
||||
test_icmp_eq()
|
||||
test_icmp_ne()
|
||||
test_icmp_slt()
|
||||
test_srem()
|
||||
test_lshr()
|
||||
test_nested()
|
||||
stdio.printf("\n=== llvmir_test 完成 ===\n")
|
||||
return 0
|
||||
60
Test/App/namespace_defs.py
Normal file
60
Test/App/namespace_defs.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 命名空间隔离测试:定义类模块
|
||||
#
|
||||
# 本文件定义供其他文件 import 使用的类,验证跨模块命名空间隔离:
|
||||
# - 裸名 Class(): 需要 from namespace_defs import Class
|
||||
# - 模块限定 namespace_defs.Class(): 需要 import namespace_defs
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 带虚表的类 Widget
|
||||
# ============================================================
|
||||
@t.CVTable
|
||||
class Widget:
|
||||
id: t.CInt
|
||||
|
||||
def __init__(self, i: t.CInt):
|
||||
self.id = i
|
||||
|
||||
def GetId(self) -> t.CInt:
|
||||
return self.id
|
||||
|
||||
def Render(self) -> t.CInt:
|
||||
return 100
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 子类 Gadget(继承 Widget,覆盖 Render)
|
||||
# ============================================================
|
||||
class Gadget(Widget):
|
||||
extra: t.CInt
|
||||
|
||||
def __init__(self, i: t.CInt, e: t.CInt):
|
||||
self.id = i
|
||||
self.extra = e
|
||||
|
||||
def Render(self) -> t.CInt:
|
||||
return 200
|
||||
|
||||
def GetExtra(self) -> t.CInt:
|
||||
return self.extra
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 普通结构体 PlainStruct(无虚表)
|
||||
# ============================================================
|
||||
class PlainStruct:
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
|
||||
def __init__(self, ax: t.CInt, ay: t.CInt):
|
||||
self.x = ax
|
||||
self.y = ay
|
||||
|
||||
def Sum(self) -> t.CInt:
|
||||
return self.x + self.y
|
||||
111
Test/App/namespace_test.py
Normal file
111
Test/App/namespace_test.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import stdio
|
||||
import t, c
|
||||
import namespace_defs
|
||||
from namespace_defs import Widget, Gadget, PlainStruct
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 命名空间隔离测试
|
||||
#
|
||||
# 验证跨模块类访问必须通过 import:
|
||||
# - Test 1: from X import Class → 裸名 Class() 构造
|
||||
# - Test 2: import X → 模块限定 X.Class() 构造
|
||||
# - Test 3: 类型注解使用导入的类
|
||||
# - Test 4: 继承类的虚分派(跨模块继承)
|
||||
# ============================================================
|
||||
|
||||
|
||||
def namespace_test() -> int:
|
||||
stdio.printf("nsisol: === Test Start ===\n")
|
||||
|
||||
# ============================================================
|
||||
# Test 1: from X import Class → 裸名 Class() 构造
|
||||
# ============================================================
|
||||
stdio.printf("nsisol: === Test 1: from-import bare constructor ===\n")
|
||||
|
||||
w: Widget = Widget(42)
|
||||
wid: int = w.GetId()
|
||||
stdio.printf("nsisol: w.GetId()=%d (expected 42)\n", wid)
|
||||
if wid != 42:
|
||||
stdio.printf("[FAIL] w.GetId()=%d expected 42\n", wid)
|
||||
return 1
|
||||
|
||||
wrender: int = w.Render()
|
||||
stdio.printf("nsisol: w.Render()=%d (expected 100)\n", wrender)
|
||||
if wrender != 100:
|
||||
stdio.printf("[FAIL] w.Render()=%d expected 100\n", wrender)
|
||||
return 1
|
||||
|
||||
g: Gadget = Gadget(7, 9)
|
||||
grender: int = g.Render()
|
||||
stdio.printf("nsisol: g.Render()=%d (expected 200)\n", grender)
|
||||
if grender != 200:
|
||||
stdio.printf("[FAIL] g.Render()=%d expected 200\n", grender)
|
||||
return 1
|
||||
|
||||
gextra: int = g.GetExtra()
|
||||
stdio.printf("nsisol: g.GetExtra()=%d (expected 9)\n", gextra)
|
||||
if gextra != 9:
|
||||
stdio.printf("[FAIL] g.GetExtra()=%d expected 9\n", gextra)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# Test 2: import X → 模块限定 X.Class() 构造
|
||||
# ============================================================
|
||||
stdio.printf("nsisol: === Test 2: module-qualified constructor ===\n")
|
||||
|
||||
ps: PlainStruct = PlainStruct(10, 20)
|
||||
psum: int = ps.Sum()
|
||||
stdio.printf("nsisol: ps.Sum()=%d (expected 30)\n", psum)
|
||||
if psum != 30:
|
||||
stdio.printf("[FAIL] ps.Sum()=%d expected 30\n", psum)
|
||||
return 1
|
||||
|
||||
ps2: namespace_defs.PlainStruct = namespace_defs.PlainStruct(5, 6)
|
||||
psum2: int = ps2.Sum()
|
||||
stdio.printf("nsisol: ps2.Sum()=%d (expected 11)\n", psum2)
|
||||
if psum2 != 11:
|
||||
stdio.printf("[FAIL] ps2.Sum()=%d expected 11\n", psum2)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# Test 3: 类型注解使用导入的类
|
||||
# ============================================================
|
||||
stdio.printf("nsisol: === Test 3: type annotation with imported class ===\n")
|
||||
|
||||
annot_w: Widget = Widget(99)
|
||||
annot_id: int = annot_w.GetId()
|
||||
stdio.printf("nsisol: annot_w.GetId()=%d (expected 99)\n", annot_id)
|
||||
if annot_id != 99:
|
||||
stdio.printf("[FAIL] annot_w.GetId()=%d expected 99\n", annot_id)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# Test 4: 跨模块继承的虚分派
|
||||
# ============================================================
|
||||
stdio.printf("nsisol: === Test 4: cross-module inheritance vtable ===\n")
|
||||
|
||||
# Gadget 继承 Widget,覆盖 Render
|
||||
# Widget.Render()=100, Gadget.Render()=200
|
||||
base: Widget = Widget(1)
|
||||
derived: Gadget = Gadget(2, 3)
|
||||
base_r: int = base.Render()
|
||||
deriv_r: int = derived.Render()
|
||||
stdio.printf("nsisol: base.Render()=%d (expected 100)\n", base_r)
|
||||
if base_r != 100:
|
||||
stdio.printf("[FAIL] base.Render()=%d expected 100\n", base_r)
|
||||
return 1
|
||||
stdio.printf("nsisol: derived.Render()=%d (expected 200)\n", deriv_r)
|
||||
if deriv_r != 200:
|
||||
stdio.printf("[FAIL] derived.Render()=%d expected 200\n", deriv_r)
|
||||
return 1
|
||||
|
||||
# 继承的方法:Gadget 继承 Widget.GetId
|
||||
gname: int = derived.GetId()
|
||||
stdio.printf("nsisol: derived.GetId()=%d (expected 2)\n", gname)
|
||||
if gname != 2:
|
||||
stdio.printf("[FAIL] derived.GetId()=%d expected 2\n", gname)
|
||||
return 1
|
||||
|
||||
stdio.printf("nsisol: === All Tests Passed ===\n")
|
||||
return 0
|
||||
119
Test/App/new_test.py
Normal file
119
Test/App/new_test.py
Normal file
@@ -0,0 +1,119 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# __new__ 函数测试:验证 __new__ 在创建 OOP 结构体前被调用,
|
||||
# 返回的指针作为结构体存储空间。
|
||||
#
|
||||
# __new__ 签名默认和 __init__ 一样(self + args),返回 Ptr(struct_ty)。
|
||||
# 如果 __new__ 返回 self,则使用默认 alloca 作为存储空间。
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 1: __new__ 返回 self(默认 alloca)
|
||||
# 验证 __new__ 被调用且不破坏 __init__ 正常功能
|
||||
# ============================================================
|
||||
class WithNew:
|
||||
value: t.CInt
|
||||
|
||||
def __new__(self, v: t.CInt):
|
||||
stdio.printf("new: WithNew.__new__ called\n")
|
||||
return self
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
stdio.printf("new: WithNew.__init__ called\n")
|
||||
self.value = v
|
||||
|
||||
def GetValue(self) -> t.CInt:
|
||||
return self.value
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 2: __new__ 不接受额外参数(仅 self)
|
||||
# 验证 __new__ 签名可以与 __init__ 不同
|
||||
# ============================================================
|
||||
class WithNewNoArgs:
|
||||
value: t.CInt
|
||||
|
||||
def __new__(self):
|
||||
stdio.printf("new: WithNewNoArgs.__new__ called\n")
|
||||
return self
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self.value = v
|
||||
|
||||
def GetValue(self) -> t.CInt:
|
||||
return self.value
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Test 3: __new__ + @t.CVTable 虚表类
|
||||
# 验证 __new__ 与虚表机制兼容(__new__ 不进入虚表)
|
||||
# ============================================================
|
||||
@t.CVTable
|
||||
class WithNewVTable:
|
||||
value: t.CInt
|
||||
|
||||
def __new__(self, v: t.CInt):
|
||||
stdio.printf("new: WithNewVTable.__new__ called\n")
|
||||
return self
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self.value = v
|
||||
|
||||
def GetValue(self) -> t.CInt:
|
||||
return self.value
|
||||
|
||||
def Speak(self) -> t.CInt:
|
||||
return self.value + 1
|
||||
|
||||
|
||||
def new_test() -> int:
|
||||
stdio.printf("new: === Test Start ===\n")
|
||||
|
||||
# ============================================================
|
||||
# Test 1: __new__ 返回 self
|
||||
# ============================================================
|
||||
stdio.printf("new: === Test 1: __new__ returns self ===\n")
|
||||
|
||||
w: WithNew = WithNew(42)
|
||||
v: int = w.GetValue()
|
||||
stdio.printf("new: w.GetValue()=%d (expected 42)\n", v)
|
||||
if v != 42:
|
||||
stdio.printf("[FAIL] w.GetValue()=%d expected 42\n", v)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# Test 2: __new__ 不接受额外参数
|
||||
# ============================================================
|
||||
stdio.printf("new: === Test 2: __new__ no extra args ===\n")
|
||||
|
||||
n: WithNewNoArgs = WithNewNoArgs(99)
|
||||
nv: int = n.GetValue()
|
||||
stdio.printf("new: n.GetValue()=%d (expected 99)\n", nv)
|
||||
if nv != 99:
|
||||
stdio.printf("[FAIL] n.GetValue()=%d expected 99\n", nv)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# Test 3: __new__ + 虚表类
|
||||
# ============================================================
|
||||
stdio.printf("new: === Test 3: __new__ + vtable ===\n")
|
||||
|
||||
vt: WithNewVTable = WithNewVTable(10)
|
||||
vtv: int = vt.GetValue()
|
||||
stdio.printf("new: vt.GetValue()=%d (expected 10)\n", vtv)
|
||||
if vtv != 10:
|
||||
stdio.printf("[FAIL] vt.GetValue()=%d expected 10\n", vtv)
|
||||
return 1
|
||||
|
||||
vts: int = vt.Speak()
|
||||
stdio.printf("new: vt.Speak()=%d (expected 11)\n", vts)
|
||||
if vts != 11:
|
||||
stdio.printf("[FAIL] vt.Speak()=%d expected 11\n", vts)
|
||||
return 1
|
||||
|
||||
stdio.printf("new: === All Tests Passed ===\n")
|
||||
return 0
|
||||
129
Test/App/oop_test.py
Normal file
129
Test/App/oop_test.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# OOP 测试:存在方法的 class 自动升级为 OOP 结构体
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# 测试 1: 基本方法(无 __init__,__before_init__ 零值填充)
|
||||
# ============================================================
|
||||
class Point:
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
|
||||
def MoveTo(self, nx: t.CInt, ny: t.CInt) -> t.CInt:
|
||||
self.x = nx
|
||||
self.y = ny
|
||||
return 0
|
||||
|
||||
def GetX(self) -> t.CInt:
|
||||
return self.x
|
||||
|
||||
def GetY(self) -> t.CInt:
|
||||
return self.y
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 2: 带默认值的 OOP 结构体(__before_init__ 应用默认值)
|
||||
# ============================================================
|
||||
class Counter:
|
||||
count: t.CInt = 0
|
||||
step: t.CInt = 1
|
||||
|
||||
def Increment(self) -> t.CInt:
|
||||
self.count = self.count + self.step
|
||||
return self.count
|
||||
|
||||
def Reset(self) -> t.CInt:
|
||||
self.count = 0
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 测试 3: __init__ 构造函数
|
||||
# ============================================================
|
||||
class Rect:
|
||||
width: t.CInt
|
||||
height: t.CInt
|
||||
|
||||
def __init__(self, w: t.CInt, h: t.CInt):
|
||||
self.width = w
|
||||
self.height = h
|
||||
|
||||
def Area(self) -> t.CInt:
|
||||
return self.width * self.height
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主函数
|
||||
# ============================================================
|
||||
def oop_test() -> int:
|
||||
# ============================================================
|
||||
# 测试 1: 基本方法调用
|
||||
# ============================================================
|
||||
stdio.printf("oop: === Test 1: Basic Methods ===\n")
|
||||
p: Point = Point()
|
||||
p.MoveTo(10, 20)
|
||||
stdio.printf("oop: p.x=%d p.y=%d\n", p.GetX(), p.GetY())
|
||||
|
||||
if p.GetX() != 10:
|
||||
stdio.printf("[FAIL] p.GetX()=%d expected 10\n", p.GetX())
|
||||
return 1
|
||||
if p.GetY() != 20:
|
||||
stdio.printf("[FAIL] p.GetY()=%d expected 20\n", p.GetY())
|
||||
return 1
|
||||
|
||||
# 修改字段后再次调用方法
|
||||
p.MoveTo(100, 200)
|
||||
stdio.printf("oop: after move p.x=%d p.y=%d\n", p.GetX(), p.GetY())
|
||||
if p.GetX() != 100:
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# 测试 2: 默认值 + 方法
|
||||
# ============================================================
|
||||
stdio.printf("oop: === Test 2: Defaults + Methods ===\n")
|
||||
cnt: Counter = Counter()
|
||||
stdio.printf("oop: initial count=%d step=%d\n", cnt.count, cnt.step)
|
||||
if cnt.count != 0:
|
||||
stdio.printf("[FAIL] cnt.count=%d expected 0\n", cnt.count)
|
||||
return 1
|
||||
if cnt.step != 1:
|
||||
stdio.printf("[FAIL] cnt.step=%d expected 1\n", cnt.step)
|
||||
return 1
|
||||
|
||||
r1: int = cnt.Increment()
|
||||
r2: int = cnt.Increment()
|
||||
r3: int = cnt.Increment()
|
||||
stdio.printf("oop: after 3 increments: %d %d %d\n", r1, r2, r3)
|
||||
if r1 != 1 or r2 != 2 or r3 != 3:
|
||||
stdio.printf("[FAIL] increments: %d %d %d\n", r1, r2, r3)
|
||||
return 1
|
||||
|
||||
cnt.Reset()
|
||||
r4: int = cnt.Increment()
|
||||
stdio.printf("oop: after reset+increment: %d\n", r4)
|
||||
if r4 != 1:
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# 测试 3: __init__ 构造函数
|
||||
# ============================================================
|
||||
stdio.printf("oop: === Test 3: __init__ ===\n")
|
||||
rect: Rect = Rect(3, 4)
|
||||
area: int = rect.Area()
|
||||
stdio.printf("oop: rect %dx%d area=%d\n", rect.width, rect.height, area)
|
||||
if area != 12:
|
||||
stdio.printf("[FAIL] area=%d expected 12\n", area)
|
||||
return 1
|
||||
if rect.width != 3:
|
||||
stdio.printf("[FAIL] width=%d expected 3\n", rect.width)
|
||||
return 1
|
||||
if rect.height != 4:
|
||||
stdio.printf("[FAIL] height=%d expected 4\n", rect.height)
|
||||
return 1
|
||||
|
||||
stdio.printf("oop: === All OOP Tests Passed ===\n")
|
||||
return 0
|
||||
253
Test/App/opovl_test.py
Normal file
253
Test/App/opovl_test.py
Normal file
@@ -0,0 +1,253 @@
|
||||
import stdio
|
||||
import stdlib
|
||||
import t, c
|
||||
import testcheck
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 运算符重载测试
|
||||
#
|
||||
# 验证: 当 lhs 是结构体指针时,二元/比较运算触发 dunder 方法调用
|
||||
# 支持: __add__/__sub__/__mul__/__div__/__mod__/__and__/__or__/__xor__
|
||||
# __lshift__/__rshift__/__floordiv__ (BinOp)
|
||||
# __eq__/__ne__/__lt__/__le__/__gt__/__ge__ (Compare)
|
||||
#
|
||||
# 三种测试场景:
|
||||
# 1. Counter/BitBox: dunder 返回 t.CInt(值类型变量触发重载)
|
||||
# 2. Vec2: dunder 返回 Vec2|t.CPtr(堆分配结构体,指针类型变量触发重载)
|
||||
# 3. 原生整数运算回退
|
||||
# ============================================================
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Counter: 演示 __add__/__mul__/__sub__ + 比较重载
|
||||
# dunder 返回 t.CInt
|
||||
# ============================================================
|
||||
class Counter:
|
||||
val: t.CInt
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self.val = v
|
||||
|
||||
def __add__(self, n: t.CInt) -> t.CInt:
|
||||
return self.val + n
|
||||
|
||||
def __sub__(self, n: t.CInt) -> t.CInt:
|
||||
return self.val - n
|
||||
|
||||
def __mul__(self, n: t.CInt) -> t.CInt:
|
||||
return self.val * n
|
||||
|
||||
def __div__(self, n: t.CInt) -> t.CInt:
|
||||
return self.val / n
|
||||
|
||||
def __mod__(self, n: t.CInt) -> t.CInt:
|
||||
return self.val % n
|
||||
|
||||
def __eq__(self, n: t.CInt) -> t.CInt:
|
||||
if self.val == n:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def __ne__(self, n: t.CInt) -> t.CInt:
|
||||
if self.val != n:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def __lt__(self, n: t.CInt) -> t.CInt:
|
||||
if self.val < n:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def __le__(self, n: t.CInt) -> t.CInt:
|
||||
if self.val <= n:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def __gt__(self, n: t.CInt) -> t.CInt:
|
||||
if self.val > n:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def __ge__(self, n: t.CInt) -> t.CInt:
|
||||
if self.val >= n:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# BitBox: 演示位运算重载
|
||||
# dunder 返回 t.CInt
|
||||
# ============================================================
|
||||
class BitBox:
|
||||
flags: t.CInt
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self.flags = v
|
||||
|
||||
def __and__(self, mask: t.CInt) -> t.CInt:
|
||||
return self.flags & mask
|
||||
|
||||
def __or__(self, mask: t.CInt) -> t.CInt:
|
||||
return self.flags | mask
|
||||
|
||||
def __xor__(self, mask: t.CInt) -> t.CInt:
|
||||
return self.flags ^ mask
|
||||
|
||||
def __lshift__(self, n: t.CInt) -> t.CInt:
|
||||
return self.flags << n
|
||||
|
||||
def __rshift__(self, n: t.CInt) -> t.CInt:
|
||||
return self.flags >> n
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Vec2: 演示结构体运算重载
|
||||
#
|
||||
# __new__ + stdlib.malloc 在堆上分配内存,使 Vec2|t.CPtr 变量
|
||||
# 能正确工作(dunder 方法返回堆上新对象)。
|
||||
#
|
||||
# __new__ 返回 malloc 的堆指针作为结构体存储空间,
|
||||
# 后续 __init__ 在堆指针上初始化字段。
|
||||
# ============================================================
|
||||
class Vec2:
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
|
||||
def __new__(self, x0: t.CInt, y0: t.CInt):
|
||||
r: Vec2 | t.CPtr = stdlib.malloc(Vec2.__sizeof__())
|
||||
return r
|
||||
|
||||
def __init__(self, x0: t.CInt, y0: t.CInt):
|
||||
self.x = x0
|
||||
self.y = y0
|
||||
|
||||
def __add__(self, other: Vec2 | t.CPtr) -> Vec2 | t.CPtr:
|
||||
r: Vec2 | t.CPtr = Vec2(0, 0)
|
||||
r.x = self.x + other.x
|
||||
r.y = self.y + other.y
|
||||
return r
|
||||
|
||||
def __sub__(self, other: Vec2 | t.CPtr) -> Vec2 | t.CPtr:
|
||||
r: Vec2 | t.CPtr = Vec2(0, 0)
|
||||
r.x = self.x - other.x
|
||||
r.y = self.y - other.y
|
||||
return r
|
||||
|
||||
def __eq__(self, other: Vec2 | t.CPtr) -> t.CInt:
|
||||
if self.x == other.x:
|
||||
if self.y == other.y:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def __ne__(self, other: Vec2 | t.CPtr) -> t.CInt:
|
||||
if self.x != other.x:
|
||||
return 1
|
||||
if self.y != other.y:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主测试入口
|
||||
# ============================================================
|
||||
def opovl_test() -> int:
|
||||
testcheck.begin("Operator Overload Tests")
|
||||
|
||||
# ============================================================
|
||||
# 测试 1: Counter + int 触发 __add__
|
||||
# ============================================================
|
||||
testcheck.section("Counter __add__")
|
||||
cnt: Counter = Counter(10)
|
||||
sum_val: int = cnt + 5
|
||||
testcheck.check(sum_val == 15, "cnt(10)+5=15", "cnt+5 expected 15 got ??")
|
||||
|
||||
# ============================================================
|
||||
# 测试 2: Counter - int / * int / / int / % int
|
||||
# ============================================================
|
||||
testcheck.section("Counter __sub__/__mul__/__div__/__mod__")
|
||||
sub_val: int = cnt - 3
|
||||
mul_val: int = cnt * 3
|
||||
div_val: int = cnt / 3
|
||||
mod_val: int = cnt % 3
|
||||
testcheck.check(sub_val == 7, "cnt-3=7", "cnt-3 expected 7")
|
||||
testcheck.check(mul_val == 30, "cnt*3=30", "cnt*3 expected 30")
|
||||
testcheck.check(div_val == 3, "cnt/3=3", "cnt/3 expected 3")
|
||||
testcheck.check(mod_val == 1, "cnt%3=1", "cnt%3 expected 1")
|
||||
|
||||
# ============================================================
|
||||
# 测试 3: Counter 比较重载 (==, !=, <, <=, >, >=)
|
||||
# ============================================================
|
||||
testcheck.section("Counter compare overloads")
|
||||
eq_10: int = cnt == 10
|
||||
ne_10: int = cnt != 10
|
||||
lt_20: int = cnt < 20
|
||||
le_10: int = cnt <= 10
|
||||
gt_5: int = cnt > 5
|
||||
ge_10: int = cnt >= 10
|
||||
testcheck.check(eq_10 == 1, "cnt==10:1", "cnt==10 expected 1")
|
||||
testcheck.check(ne_10 == 0, "cnt!=10:0", "cnt!=10 expected 0")
|
||||
testcheck.check(lt_20 == 1, "cnt<20:1", "cnt<20 expected 1")
|
||||
testcheck.check(le_10 == 1, "cnt<=10:1", "cnt<=10 expected 1")
|
||||
testcheck.check(gt_5 == 1, "cnt>5:1", "cnt>5 expected 1")
|
||||
testcheck.check(ge_10 == 1, "cnt>=10:1", "cnt>=10 expected 1")
|
||||
|
||||
# ============================================================
|
||||
# 测试 4: BitBox 位运算重载
|
||||
# ============================================================
|
||||
testcheck.section("BitBox bitwise overloads")
|
||||
bb: BitBox = BitBox(0xFF)
|
||||
and_val: int = bb & 0x0F
|
||||
or_val: int = bb | 0x100
|
||||
xor_val: int = bb ^ 0x55
|
||||
lsh_val: int = bb << 4
|
||||
rsh_val: int = bb >> 4
|
||||
testcheck.check(and_val == 0x0F, "bb&0x0F=15", "bb&0x0F expected 15")
|
||||
testcheck.check(or_val == 0x1FF, "bb|0x100=511", "bb|0x100 expected 511")
|
||||
testcheck.check(xor_val == 0xAA, "bb^0x55=170", "bb^0x55 expected 170")
|
||||
testcheck.check(lsh_val == 0xFF0, "bb<<4=4080", "bb<<4 expected 4080")
|
||||
testcheck.check(rsh_val == 0x0F, "bb>>4=15", "bb>>4 expected 15")
|
||||
|
||||
# ============================================================
|
||||
# 测试 5: 原生整数运算不受影响(回退路径)
|
||||
# ============================================================
|
||||
testcheck.section("Native int binop")
|
||||
x: int = 7 + 8
|
||||
y: int = 10 - 3
|
||||
z: int = 4 * 5
|
||||
testcheck.check(x == 15, "7+8=15", "7+8 expected 15")
|
||||
testcheck.check(y == 7, "10-3=7", "10-3 expected 7")
|
||||
testcheck.check(z == 20, "4*5=20", "4*5 expected 20")
|
||||
|
||||
# ============================================================
|
||||
# 测试 6: 原生整数比较不受影响
|
||||
# ============================================================
|
||||
testcheck.section("Native int compare")
|
||||
testcheck.check(3 < 5, "3<5", "3<5 broken")
|
||||
testcheck.check(10 == 10, "10==10", "10==10 broken")
|
||||
|
||||
# ============================================================
|
||||
# 测试 7: Vec2 结构体运算重载
|
||||
# ============================================================
|
||||
testcheck.section("Vec2 struct overloads")
|
||||
a: Vec2 | t.CPtr = Vec2(3, 4)
|
||||
b: Vec2 | t.CPtr = Vec2(1, 2)
|
||||
c: Vec2 | t.CPtr = a + b
|
||||
d: Vec2 | t.CPtr = a - b
|
||||
testcheck.check(c.x == 4, "a+b x=4", "a+b x expected 4")
|
||||
testcheck.check(c.y == 6, "a+b y=6", "a+b y expected 6")
|
||||
testcheck.check(d.x == 2, "a-b x=2", "a-b x expected 2")
|
||||
testcheck.check(d.y == 2, "a-b y=2", "a-b y expected 2")
|
||||
|
||||
# ============================================================
|
||||
# 测试 8: Vec2 比较重载
|
||||
# ============================================================
|
||||
testcheck.section("Vec2 compare overloads")
|
||||
p: Vec2 | t.CPtr = Vec2(5, 5)
|
||||
q: Vec2 | t.CPtr = Vec2(5, 5)
|
||||
eq_v: int = p == q
|
||||
ne_v: int = p != q
|
||||
testcheck.check(eq_v == 1, "(5,5)==(5,5):1", "p==q expected 1")
|
||||
testcheck.check(ne_v == 0, "(5,5)!=(5,5):0", "p!=q expected 0")
|
||||
|
||||
return testcheck.end()
|
||||
26
Test/App/ptr_only_test.py
Normal file
26
Test/App/ptr_only_test.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
def ptr_only_test() -> int:
|
||||
s: str = "hello"
|
||||
sp: str = s
|
||||
slen: int = 0
|
||||
while c.Deref(sp) != 0:
|
||||
slen = slen + 1
|
||||
sp = sp + 1
|
||||
stdio.printf("ptr: len(hello)=%d\n", slen)
|
||||
|
||||
x: int = 65
|
||||
px: str = c.Addr(x)
|
||||
c.DerefAs(px, 88)
|
||||
stdio.printf("ptr: after DerefAs x=%d\n", x)
|
||||
|
||||
p2: str = "ABC"
|
||||
total_ch: int = 0
|
||||
while c.Deref(p2) != 0:
|
||||
total_ch = total_ch + c.Deref(p2)
|
||||
p2 = p2 + 1
|
||||
stdio.printf("ptr: sum(A,B,C)=%d\n", total_ch)
|
||||
|
||||
return 0
|
||||
111
Test/App/ptr_test.py
Normal file
111
Test/App/ptr_test.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 简单指针 + 逻辑测试
|
||||
# ============================================================
|
||||
|
||||
def ptr_test() -> int:
|
||||
# 逻辑测试:if 语句
|
||||
x: int = 10
|
||||
if x:
|
||||
stdio.printf("if: x is truthy\n")
|
||||
|
||||
if 1 == 1:
|
||||
stdio.printf("if: 1==1 is truthy\n")
|
||||
|
||||
# While 循环 + 累加
|
||||
i: int = 0
|
||||
total: int = 0
|
||||
while i < 5:
|
||||
total = total + i
|
||||
i = i + 1
|
||||
stdio.printf("while: total=%d i=%d\n", total, i)
|
||||
|
||||
# For 循环
|
||||
for j in range(5):
|
||||
stdio.printf("for: j=%d\n", j)
|
||||
|
||||
# Break 测试
|
||||
for k in range(10):
|
||||
if k == 3:
|
||||
break
|
||||
stdio.printf("break: k=%d\n", k)
|
||||
|
||||
# Continue 测试
|
||||
for m in range(5):
|
||||
if m == 2:
|
||||
continue
|
||||
stdio.printf("continue: m=%d\n", m)
|
||||
|
||||
# 布尔运算 and(短路求值)
|
||||
if x > 5 and x < 100:
|
||||
stdio.printf("bool: x>5 and x<100 is true\n")
|
||||
|
||||
# 布尔运算 or(短路求值)
|
||||
if x > 100 or x > 5:
|
||||
stdio.printf("bool: x>100 or x>5 is true\n")
|
||||
|
||||
# ============================================================
|
||||
# 指针 + c.Deref / c.DerefAs 测试
|
||||
# ============================================================
|
||||
|
||||
# 字符串遍历: while c.Deref(p) != 0
|
||||
s: str = "hello"
|
||||
sp: str = s
|
||||
slen: int = 0
|
||||
while c.Deref(sp) != 0:
|
||||
slen = slen + 1
|
||||
sp = sp + 1
|
||||
stdio.printf("ptr: len(hello)=%d\n", slen)
|
||||
|
||||
# c.DerefAs 写入字符(使用 c.Addr 获取栈变量地址,字符串字面量是只读的)
|
||||
v: int = 65 # 'A'
|
||||
px: str = c.Addr(v)
|
||||
c.DerefAs(px, 88) # *px = 88
|
||||
stdio.printf("ptr: after DerefAs v=%d\n", v)
|
||||
|
||||
# 遍历字符串并累加字符值
|
||||
p2: str = "ABC"
|
||||
total_ch: int = 0
|
||||
while c.Deref(p2) != 0:
|
||||
total_ch = total_ch + c.Deref(p2)
|
||||
p2 = p2 + 1
|
||||
stdio.printf("ptr: sum(A,B,C)=%d\n", total_ch)
|
||||
|
||||
# ============================================================
|
||||
# c.Load 测试: *a = *b(加载源指针的值,存储到目标指针)
|
||||
# ============================================================
|
||||
|
||||
# 基本复制: v2 = v1
|
||||
v1: int = 42
|
||||
v2: int = 0
|
||||
c.Load(c.Addr(v2), c.Addr(v1))
|
||||
stdio.printf("ptr: c.Load v2=%d (expected 42)\n", v2)
|
||||
if v2 != 42:
|
||||
stdio.printf("[FAIL] c.Load expected 42 got %d\n", v2)
|
||||
return 1
|
||||
|
||||
# 覆盖已有值: v3 = v4
|
||||
v3: int = 100
|
||||
v4: int = 200
|
||||
c.Load(c.Addr(v3), c.Addr(v4))
|
||||
stdio.printf("ptr: c.Load overwrite v3=%d (expected 200)\n", v3)
|
||||
if v3 != 200:
|
||||
stdio.printf("[FAIL] c.Load overwrite expected 200 got %d\n", v3)
|
||||
return 1
|
||||
|
||||
# 验证源不被修改: v5 保持原值
|
||||
v5: int = 999
|
||||
v6: int = 0
|
||||
c.Load(c.Addr(v6), c.Addr(v5))
|
||||
stdio.printf("ptr: c.Load src unchanged v5=%d v6=%d (expected 999, 999)\n", v5, v6)
|
||||
if v5 != 999:
|
||||
stdio.printf("[FAIL] c.Load src changed v5=%d\n", v5)
|
||||
return 1
|
||||
if v6 != 999:
|
||||
stdio.printf("[FAIL] c.Load dst expected 999 got %d\n", v6)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
6
Test/App/simple_test.py
Normal file
6
Test/App/simple_test.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import stdio
|
||||
|
||||
def simple_test() -> int:
|
||||
stdio.printf("hello\n")
|
||||
return 0
|
||||
|
||||
9
Test/App/string_min_test.py
Normal file
9
Test/App/string_min_test.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import stdio
|
||||
import t, c
|
||||
import string
|
||||
|
||||
|
||||
def string_min_test() -> int:
|
||||
l: t.CSizeT = string.strlen("Hello")
|
||||
stdio.printf("strlen(Hello)=%lu\n", l)
|
||||
return 0
|
||||
106
Test/App/string_test.py
Normal file
106
Test/App/string_test.py
Normal file
@@ -0,0 +1,106 @@
|
||||
import stdio
|
||||
import t, c
|
||||
import string
|
||||
|
||||
|
||||
# ============================================================
|
||||
# string_test - string.py 库函数测试
|
||||
#
|
||||
# 测试 strlen / strcmp / strncmp / atoi / strchr / strstr
|
||||
# ============================================================
|
||||
|
||||
|
||||
def test_strlen():
|
||||
stdio.printf("--- Test 1: strlen ---\n")
|
||||
|
||||
l1: t.CSizeT = string.strlen("Hello")
|
||||
stdio.printf("strlen(Hello)=%lu (expect 5)\n", l1)
|
||||
|
||||
l2: t.CSizeT = string.strlen("")
|
||||
stdio.printf("strlen()=%lu (expect 0)\n", l2)
|
||||
|
||||
l3: t.CSizeT = string.strlen("Hello, World!")
|
||||
stdio.printf("strlen(Hello, World!)=%lu (expect 13)\n", l3)
|
||||
|
||||
|
||||
def test_strcmp():
|
||||
stdio.printf("--- Test 2: strcmp ---\n")
|
||||
|
||||
r1: t.CInt = string.strcmp("abc", "abc")
|
||||
stdio.printf("strcmp(abc,abc)=%d (expect 0)\n", r1)
|
||||
|
||||
r2: t.CInt = string.strcmp("abc", "abd")
|
||||
stdio.printf("strcmp(abc,abd)=%d (expect <0)\n", r2)
|
||||
|
||||
r3: t.CInt = string.strcmp("abd", "abc")
|
||||
stdio.printf("strcmp(abd,abc)=%d (expect >0)\n", r3)
|
||||
|
||||
|
||||
def test_strncmp():
|
||||
stdio.printf("--- Test 3: strncmp ---\n")
|
||||
|
||||
r1: t.CInt = string.strncmp("abcdef", "abcXYZ", 3)
|
||||
stdio.printf("strncmp(abcdef,abcXYZ,3)=%d (expect 0)\n", r1)
|
||||
|
||||
r2: t.CInt = string.strncmp("abcdef", "abcXYZ", 4)
|
||||
stdio.printf("strncmp(abcdef,abcXYZ,4)=%d (expect <0)\n", r2)
|
||||
|
||||
|
||||
def test_atoi():
|
||||
stdio.printf("--- Test 4: atoi ---\n")
|
||||
|
||||
n1: t.CInt = string.atoi("123")
|
||||
stdio.printf("atoi(123)=%d (expect 123)\n", n1)
|
||||
|
||||
n2: t.CInt = string.atoi("-456")
|
||||
stdio.printf("atoi(-456)=%d (expect -456)\n", n2)
|
||||
|
||||
n3: t.CInt = string.atoi(" 789")
|
||||
stdio.printf("atoi( 789)=%d (expect 789)\n", n3)
|
||||
|
||||
|
||||
def test_strchr():
|
||||
stdio.printf("--- Test 5: strchr ---\n")
|
||||
|
||||
# strchr 返回指向字符的指针,不为 None 表示找到
|
||||
p: str = string.strchr("Hello", 108) # 'l' = 108
|
||||
if p is not None:
|
||||
stdio.printf("strchr(Hello,'l') found, char=%d (expect 108)\n", c.Deref(p))
|
||||
else:
|
||||
stdio.printf("strchr(Hello,'l') NOT FOUND (FAIL)\n")
|
||||
|
||||
p2: str = string.strchr("Hello", 122) # 'z' = 122
|
||||
if p2 is None:
|
||||
stdio.printf("strchr(Hello,'z') not found OK\n")
|
||||
else:
|
||||
stdio.printf("strchr(Hello,'z') FAIL (should be None)\n")
|
||||
|
||||
|
||||
def test_strstr():
|
||||
stdio.printf("--- Test 6: strstr ---\n")
|
||||
|
||||
p: str = string.strstr("Hello World", "World")
|
||||
if p is not None:
|
||||
stdio.printf("strstr(Hello,World) found OK\n")
|
||||
else:
|
||||
stdio.printf("strstr(Hello,World) NOT FOUND (FAIL)\n")
|
||||
|
||||
p2: str = string.strstr("Hello World", "xyz")
|
||||
if p2 is None:
|
||||
stdio.printf("strstr(Hello,xyz) not found OK\n")
|
||||
else:
|
||||
stdio.printf("strstr(Hello,xyz) FAIL (should be None)\n")
|
||||
|
||||
|
||||
def string_test() -> int:
|
||||
stdio.printf("=== string_test: string.py 库函数测试 ===\n\n")
|
||||
|
||||
test_strlen()
|
||||
test_strcmp()
|
||||
test_strncmp()
|
||||
test_atoi()
|
||||
test_strchr()
|
||||
test_strstr()
|
||||
|
||||
stdio.printf("\n=== string_test 完成 ===\n")
|
||||
return 0
|
||||
235
Test/App/struct_test.py
Normal file
235
Test/App/struct_test.py
Normal file
@@ -0,0 +1,235 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 纯内存结构体(class)测试
|
||||
# ============================================================
|
||||
|
||||
class Point:
|
||||
x: t.CInt
|
||||
y: t.CInt
|
||||
|
||||
|
||||
class Box:
|
||||
width: t.CInt
|
||||
height: t.CInt
|
||||
depth: t.CInt
|
||||
|
||||
|
||||
class Size:
|
||||
w: t.CInt = 100
|
||||
h: t.CInt = 200
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 枚举(t.CEnum)测试
|
||||
# ============================================================
|
||||
|
||||
class State(t.CEnum):
|
||||
Idle: t.State
|
||||
Run: t.State
|
||||
Stop: t.State
|
||||
|
||||
|
||||
class Color(t.CEnum):
|
||||
Red: t.State = 10
|
||||
Green: t.State
|
||||
Blue: t.State = 20
|
||||
Yellow: t.State
|
||||
|
||||
|
||||
class MixedType(t.CEnum):
|
||||
Small: t.CInt8T
|
||||
Big: t.CInt64T
|
||||
Medium: t.CInt16T
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 联合体(t.CUnion)测试
|
||||
# ============================================================
|
||||
|
||||
class DataUnion(t.CUnion):
|
||||
i: t.CInt
|
||||
f: t.CFloat
|
||||
l: t.CInt64T
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 主函数
|
||||
# ============================================================
|
||||
def struct_test() -> int:
|
||||
# ============================================================
|
||||
# 测试 1: 结构体字段读写
|
||||
# ============================================================
|
||||
p: Point = Point()
|
||||
p.x = 10
|
||||
p.y = 20
|
||||
stdio.printf("struct: p.x=%d p.y=%d\n", p.x, p.y)
|
||||
|
||||
# 修改字段
|
||||
p.x = 100
|
||||
p.y = 200
|
||||
stdio.printf("struct: modified p.x=%d p.y=%d\n", p.x, p.y)
|
||||
|
||||
# 字段运算
|
||||
sum_xy: int = p.x + p.y
|
||||
stdio.printf("struct: sum=%d\n", sum_xy)
|
||||
|
||||
# ============================================================
|
||||
# 测试 2: 多字段结构体
|
||||
# ============================================================
|
||||
b: Box
|
||||
b.width = 3
|
||||
b.height = 4
|
||||
b.depth = 5
|
||||
vol: int = b.width * b.height * b.depth
|
||||
stdio.printf("struct: volume=%d\n", vol)
|
||||
|
||||
# ============================================================
|
||||
# 测试 3: t.CArray 数组遍历
|
||||
# ============================================================
|
||||
arr: t.CArray[t.CInt, 5]
|
||||
arr[0] = 100
|
||||
arr[1] = 200
|
||||
arr[2] = 300
|
||||
arr[3] = 400
|
||||
arr[4] = 500
|
||||
|
||||
arr_total: int = 0
|
||||
for i in range(5):
|
||||
arr_total = arr_total + arr[i]
|
||||
stdio.printf("array: total=%d\n", arr_total)
|
||||
|
||||
# 修改数组元素
|
||||
arr[2] = 999
|
||||
stdio.printf("array: arr[2]=%d\n", arr[2])
|
||||
|
||||
# ============================================================
|
||||
# 测试 4: 指针遍历(字符串)
|
||||
# ============================================================
|
||||
s: str = "hello"
|
||||
sp: str = s
|
||||
slen: int = 0
|
||||
while c.Deref(sp) != 0:
|
||||
slen = slen + 1
|
||||
sp = sp + 1
|
||||
stdio.printf("ptr: len(hello)=%d\n", slen)
|
||||
|
||||
# 累加字符值
|
||||
p2: str = "ABC"
|
||||
total_ch: int = 0
|
||||
while c.Deref(p2) != 0:
|
||||
total_ch = total_ch + c.Deref(p2)
|
||||
p2 = p2 + 1
|
||||
stdio.printf("ptr: sum(A,B,C)=%d\n", total_ch)
|
||||
|
||||
# ============================================================
|
||||
# 测试 5: 结构体构造函数 Point() / Point(x, y)
|
||||
# ============================================================
|
||||
# 无参数构造:零初始化
|
||||
z: Point = Point()
|
||||
stdio.printf("ctor: z.x=%d z.y=%d\n", z.x, z.y)
|
||||
|
||||
# 带参数构造:按位置赋值
|
||||
p3: Point = Point(7, 8)
|
||||
stdio.printf("ctor: p3.x=%d p3.y=%d\n", p3.x, p3.y)
|
||||
|
||||
# 多字段构造
|
||||
bx: Box = Box(10, 20, 30)
|
||||
stdio.printf("ctor: bx.w=%d bx.h=%d bx.d=%d\n", bx.width, bx.height, bx.depth)
|
||||
|
||||
# ============================================================
|
||||
# 测试 6: 结构体关键字参数(乱序传参)
|
||||
# ============================================================
|
||||
# 全关键字乱序
|
||||
p4: Point = Point(y=20, x=10)
|
||||
stdio.printf("kw: p4.x=%d p4.y=%d\n", p4.x, p4.y)
|
||||
|
||||
# 混合:位置 + 关键字
|
||||
p5: Point = Point(5, y=15)
|
||||
stdio.printf("kw: p5.x=%d p5.y=%d\n", p5.x, p5.y)
|
||||
|
||||
# 多字段关键字乱序
|
||||
bx2: Box = Box(depth=30, width=10, height=20)
|
||||
stdio.printf("kw: bx2.w=%d bx2.h=%d bx2.d=%d\n", bx2.width, bx2.height, bx2.depth)
|
||||
|
||||
# ============================================================
|
||||
# 测试 7: 结构体默认赋值
|
||||
# ============================================================
|
||||
# 无参数构造:使用默认值
|
||||
sz: Size = Size()
|
||||
stdio.printf("def: sz.w=%d sz.h=%d\n", sz.w, sz.h)
|
||||
|
||||
# 位置参数覆盖默认值
|
||||
sz2: Size = Size(5, 6)
|
||||
stdio.printf("def: sz2.w=%d sz2.h=%d\n", sz2.w, sz2.h)
|
||||
|
||||
# 关键字参数覆盖默认值(乱序)
|
||||
sz3: Size = Size(h=999, w=888)
|
||||
stdio.printf("def: sz3.w=%d sz3.h=%d\n", sz3.w, sz3.h)
|
||||
|
||||
# 混合:位置参数 + 默认值(w=7 覆盖默认值,h 保持默认值 200)
|
||||
sz4: Size = Size(7)
|
||||
stdio.printf("def: sz4.w=%d sz4.h=%d\n", sz4.w, sz4.h)
|
||||
|
||||
# ============================================================
|
||||
# 测试 8: 枚举自动赋值(Idle=0, Run=1, Stop=2)
|
||||
# ============================================================
|
||||
s_idle: int = State.Idle
|
||||
s_run: int = State.Run
|
||||
s_stop: int = State.Stop
|
||||
stdio.printf("enum: Idle=%d Run=%d Stop=%d\n", s_idle, s_run, s_stop)
|
||||
|
||||
# ============================================================
|
||||
# 测试 9: 枚举手动赋值(Red=10, Green=11, Blue=20, Yellow=21)
|
||||
# ============================================================
|
||||
c_red: int = Color.Red
|
||||
c_green: int = Color.Green
|
||||
c_blue: int = Color.Blue
|
||||
c_yellow: int = Color.Yellow
|
||||
stdio.printf("enum: Red=%d Green=%d Blue=%d Yellow=%d\n",
|
||||
c_red, c_green, c_blue, c_yellow)
|
||||
|
||||
# ============================================================
|
||||
# 测试 10: 枚举混用数字类型(基准类型应为 i64)
|
||||
# ============================================================
|
||||
m_small: int = MixedType.Small
|
||||
m_big: int = MixedType.Big
|
||||
m_medium: int = MixedType.Medium
|
||||
stdio.printf("enum: Small=%d Big=%d Medium=%d\n", m_small, m_big, m_medium)
|
||||
|
||||
# 枚举参与运算
|
||||
s_sum: int = State.Idle + State.Run + State.Stop
|
||||
stdio.printf("enum: sum(Idle,Run,Stop)=%d\n", s_sum)
|
||||
|
||||
# 枚举比较
|
||||
if State.Idle == 0:
|
||||
stdio.printf("enum: Idle==0 true\n")
|
||||
if Color.Red == 10:
|
||||
stdio.printf("enum: Red==10 true\n")
|
||||
if State.Run != State.Stop:
|
||||
stdio.printf("enum: Run!=Stop true\n")
|
||||
|
||||
# ============================================================
|
||||
# 测试 11: 联合体字段读写
|
||||
# ============================================================
|
||||
u: DataUnion
|
||||
u.i = 42
|
||||
stdio.printf("union: u.i=%d\n", u.i)
|
||||
|
||||
# 写入 l 字段(覆盖 i 的内存,因为 l 是 i64)
|
||||
u.l = 20015998343868
|
||||
stdio.printf("union: u.l=%lld\n", u.l)
|
||||
|
||||
# ============================================================
|
||||
# 测试 12: 联合体共享内存验证
|
||||
# ============================================================
|
||||
u2: DataUnion
|
||||
u2.i = 1
|
||||
# 写入 l 后,i 的值已被覆盖(不再是 1)
|
||||
u2.l = 100
|
||||
if u2.i != 1:
|
||||
stdio.printf("union: shared memory verified\n")
|
||||
|
||||
return 0
|
||||
109
Test/App/test_main.py
Normal file
109
Test/App/test_main.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import stdio
|
||||
import t, c
|
||||
import testcheck
|
||||
from stdint import *
|
||||
from asm_test import asm_test
|
||||
from attr_test import attr_test
|
||||
from augassign_test import augassign_test
|
||||
from closure_test import closure_test
|
||||
from deco_test import deco_test
|
||||
from deref_min_test import deref_min_test
|
||||
from deref_test import deref_test
|
||||
from eq_test import eq_test
|
||||
from float_test import float_test
|
||||
from flow_test import flow_test
|
||||
from for_test import for_test
|
||||
from func_test import func_test
|
||||
from llvmir_test import llvmir_test
|
||||
from oop_test import oop_test
|
||||
from ptr_only_test import ptr_only_test
|
||||
from ptr_test import ptr_test
|
||||
from simple_test import simple_test
|
||||
from string_min_test import string_min_test
|
||||
from string_test import string_test
|
||||
from struct_test import struct_test
|
||||
from type_bit_test import type_bit_test
|
||||
from vtable_test import vtable_test
|
||||
from inherit_test import inherit_test
|
||||
from func_vtable_test import func_vtable_test
|
||||
from virtual_dispatch_test import virtual_dispatch_test
|
||||
from new_test import new_test
|
||||
from namespace_test import namespace_test
|
||||
from testcheck_test import testcheck_test
|
||||
from opovl_test import opovl_test
|
||||
from generic_test import generic_test
|
||||
|
||||
|
||||
def main() -> int:
|
||||
stdio.printf("===== TransPyV Test Suite =====\n\n")
|
||||
|
||||
r: int = 0
|
||||
|
||||
stdio.fflush(None)
|
||||
r = asm_test()
|
||||
stdio.fflush(None)
|
||||
r = attr_test()
|
||||
stdio.fflush(None)
|
||||
r = augassign_test()
|
||||
stdio.fflush(None)
|
||||
r = closure_test()
|
||||
stdio.fflush(None)
|
||||
r = deco_test()
|
||||
stdio.fflush(None)
|
||||
r = deref_min_test()
|
||||
stdio.fflush(None)
|
||||
r = deref_test()
|
||||
stdio.fflush(None)
|
||||
r = eq_test()
|
||||
stdio.fflush(None)
|
||||
r = float_test()
|
||||
stdio.fflush(None)
|
||||
r = flow_test()
|
||||
stdio.fflush(None)
|
||||
r = for_test()
|
||||
stdio.fflush(None)
|
||||
r = func_test()
|
||||
stdio.fflush(None)
|
||||
r = llvmir_test()
|
||||
stdio.fflush(None)
|
||||
r = oop_test()
|
||||
stdio.fflush(None)
|
||||
r = ptr_only_test()
|
||||
stdio.fflush(None)
|
||||
r = ptr_test()
|
||||
stdio.fflush(None)
|
||||
r = simple_test()
|
||||
stdio.fflush(None)
|
||||
r = string_min_test()
|
||||
stdio.fflush(None)
|
||||
r = string_test()
|
||||
stdio.fflush(None)
|
||||
r = struct_test()
|
||||
stdio.fflush(None)
|
||||
r = type_bit_test()
|
||||
stdio.fflush(None)
|
||||
r = vtable_test()
|
||||
stdio.fflush(None)
|
||||
r = inherit_test()
|
||||
stdio.fflush(None)
|
||||
r = func_vtable_test()
|
||||
stdio.fflush(None)
|
||||
r = virtual_dispatch_test()
|
||||
stdio.fflush(None)
|
||||
r = new_test()
|
||||
stdio.fflush(None)
|
||||
r = namespace_test()
|
||||
stdio.fflush(None)
|
||||
r = testcheck_test()
|
||||
stdio.fflush(None)
|
||||
r = opovl_test()
|
||||
stdio.fflush(None)
|
||||
|
||||
stdio.printf("[TM] before generic_test\n")
|
||||
stdio.fflush(None)
|
||||
r = generic_test()
|
||||
stdio.printf("[TM] after generic_test r=%d\n", r)
|
||||
stdio.fflush(None)
|
||||
|
||||
stdio.printf("\n===== Test Suite Complete =====\n")
|
||||
return r
|
||||
37
Test/App/testcheck_test.py
Normal file
37
Test/App/testcheck_test.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import stdio
|
||||
import t, c
|
||||
import string
|
||||
import testcheck
|
||||
|
||||
|
||||
# ============================================================
|
||||
# testcheck_test - 测试 includes/testcheck 库导入与调用
|
||||
#
|
||||
# 验证命名空间隔离下,import testcheck + 模块限定函数调用能正常工作。
|
||||
# 同时测试 string 库的模块限定调用。
|
||||
# ============================================================
|
||||
def testcheck_test() -> int:
|
||||
testcheck.begin("testcheck_test")
|
||||
|
||||
testcheck.section("Arithmetic")
|
||||
a: int = 3 + 4
|
||||
testcheck.check(a == 7, "3+4=7", "3+4!=7")
|
||||
|
||||
b: int = 10 - 3
|
||||
testcheck.check(b == 7, "10-3=7", "10-3!=7")
|
||||
|
||||
m: int = 6 * 7
|
||||
testcheck.check(m == 42, "6*7=42", "6*7!=42")
|
||||
|
||||
testcheck.section("String")
|
||||
slen: int = string.strlen("hello")
|
||||
testcheck.check(slen == 5, "strlen(hello)=5", "strlen(hello)!=5")
|
||||
|
||||
scmp: int = string.strcmp("abc", "abc")
|
||||
testcheck.check(scmp == 0, "strcmp(abc,abc)=0", "strcmp(abc,abc)!=0")
|
||||
|
||||
testcheck.section("Module Import")
|
||||
testcheck.info("testcheck module imported and called successfully")
|
||||
testcheck.ok("import testcheck works")
|
||||
|
||||
return testcheck.end()
|
||||
26
Test/App/type_bit_test.py
Normal file
26
Test/App/type_bit_test.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
def type_bit_test() -> int:
|
||||
ti: t.CInt = 100
|
||||
ti32: t.CInt32T = 200
|
||||
tui32: t.CUInt32T = 300
|
||||
stdio.printf("type: CInt=%d CInt32T=%d CUInt32T=%d\n", ti, ti32, tui32)
|
||||
|
||||
tl: t.CLong = 1000
|
||||
tll: t.CLongLong = 2000
|
||||
ti64: t.CInt64T = 3000
|
||||
tsize: t.CSizeT = 4000
|
||||
stdio.printf("type: CLong=%d CLongLong=%d CInt64T=%d CSizeT=%d\n", tl, tll, ti64, tsize)
|
||||
|
||||
ba: int = 240
|
||||
bb: int = 15
|
||||
stdio.printf("bit: 240&15=%d\n", ba & bb)
|
||||
stdio.printf("bit: 240|15=%d\n", ba | bb)
|
||||
stdio.printf("bit: 240^15=%d\n", ba ^ bb)
|
||||
stdio.printf("bit: 240<<2=%d\n", ba << 2)
|
||||
stdio.printf("bit: 240>>2=%d\n", ba >> 2)
|
||||
stdio.printf("bit: 17%%5=%d\n", 17 % 5)
|
||||
|
||||
return 0
|
||||
83
Test/App/virtual_dispatch_test.py
Normal file
83
Test/App/virtual_dispatch_test.py
Normal file
@@ -0,0 +1,83 @@
|
||||
import stdio
|
||||
import t, c
|
||||
import string
|
||||
from inherit_test import Animal, Dog
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 虚分派测试:通过虚表指针验证虚分派机制
|
||||
#
|
||||
# 本测试验证:方法调用通过对象的 __vtable__ 字段进行虚分派,
|
||||
# 而非通过变量声明类型直接调用。
|
||||
#
|
||||
# 测试方法:
|
||||
# 1. 创建 Animal 对象 a(Animal 虚表,Speak 返回 0)
|
||||
# 2. 创建 Dog 对象 d
|
||||
# 3. 用内联汇编将 d 的虚表指针复制到 a
|
||||
# 4. 调用 a.Speak() — 应返回 1(Dog.Speak),证明虚分派生效
|
||||
#
|
||||
# 如果是直接调用(非虚分派),a.Speak() 会调用 Animal.Speak 返回 0
|
||||
#
|
||||
# 注意:Animal 和 Dog 类从 inherit_test.py 导入(命名空间隔离)
|
||||
# ============================================================
|
||||
|
||||
|
||||
def virtual_dispatch_test() -> int:
|
||||
stdio.printf("vdispatch: === Test Start ===\n")
|
||||
|
||||
# 创建对象
|
||||
a: Animal = Animal(42)
|
||||
d: Dog = Dog(100, 7)
|
||||
|
||||
# ============================================================
|
||||
# 测试 1: 直接分派(基线验证)
|
||||
# ============================================================
|
||||
stdio.printf("vdispatch: === Test 1: Direct Dispatch ===\n")
|
||||
|
||||
a_speak: int = a.Speak()
|
||||
stdio.printf("vdispatch: a.Speak()=%d (expected 0)\n", a_speak)
|
||||
if a_speak != 0:
|
||||
stdio.printf("[FAIL] a.Speak()=%d expected 0\n", a_speak)
|
||||
return 1
|
||||
|
||||
d_speak: int = d.Speak()
|
||||
stdio.printf("vdispatch: d.Speak()=%d (expected 1)\n", d_speak)
|
||||
if d_speak != 1:
|
||||
stdio.printf("[FAIL] d.Speak()=%d expected 1\n", d_speak)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# 测试 2: 虚分派验证(复制虚表指针)
|
||||
#
|
||||
# 将 Dog 的虚表指针复制到 Animal 对象 a
|
||||
# 虚表指针位于结构体偏移 0(__vtable__ 字段)
|
||||
# 复制后 a.Speak() 应通过虚表分发到 Dog.Speak(返回 1)
|
||||
# ============================================================
|
||||
stdio.printf("vdispatch: === Test 2: Virtual Dispatch ===\n")
|
||||
|
||||
# 使用 string.memcpy 复制虚表指针(8字节,结构体偏移0)
|
||||
# 将 d 的虚表指针复制到 a,使 a.Speak() 分发到 Dog.Speak
|
||||
string.memcpy(c.Addr(a), c.Addr(d), 8)
|
||||
|
||||
a_speak2: int = a.Speak()
|
||||
stdio.printf("vdispatch: a.Speak()=%d (expected 1 after vtable copy)\n", a_speak2)
|
||||
if a_speak2 != 1:
|
||||
stdio.printf("[FAIL] a.Speak()=%d expected 1 after vtable copy\n", a_speak2)
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
# 测试 3: GetName 验证(未被覆盖的虚方法)
|
||||
#
|
||||
# Dog 没有覆盖 GetName,Dog 虚表中 GetName 槽位指向 Animal.GetName
|
||||
# a.GetName() 应返回 a.name (42),证明虚表槽位一致性
|
||||
# ============================================================
|
||||
stdio.printf("vdispatch: === Test 3: GetName After VTable Copy ===\n")
|
||||
|
||||
a_name: int = a.GetName()
|
||||
stdio.printf("vdispatch: a.GetName()=%d (expected 42)\n", a_name)
|
||||
if a_name != 42:
|
||||
stdio.printf("[FAIL] a.GetName()=%d expected 42\n", a_name)
|
||||
return 1
|
||||
|
||||
stdio.printf("vdispatch: === All Tests Passed ===\n")
|
||||
return 0
|
||||
63
Test/App/vtable_test.py
Normal file
63
Test/App/vtable_test.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Animal:
|
||||
name: t.CInt
|
||||
|
||||
def __init__(self, n: t.CInt):
|
||||
self.name = n
|
||||
|
||||
def GetName(self) -> t.CInt:
|
||||
return self.name
|
||||
|
||||
def Speak(self) -> t.CInt:
|
||||
return 0
|
||||
|
||||
|
||||
@t.CVTable
|
||||
class Shape:
|
||||
sides: t.CInt
|
||||
|
||||
def SetSides(self, n: t.CInt) -> t.CInt:
|
||||
self.sides = n
|
||||
return 0
|
||||
|
||||
def GetSides(self) -> t.CInt:
|
||||
return self.sides
|
||||
|
||||
|
||||
def vtable_test() -> int:
|
||||
stdio.printf("vtable: === Test Start ===\n")
|
||||
|
||||
# 测试 1: Animal 虚方法调用(无参,访问 self 字段)
|
||||
a: Animal = Animal(42)
|
||||
name: int = a.GetName()
|
||||
stdio.printf("vtable: a.GetName()=%d (expected 42)\n", name)
|
||||
if name != 42:
|
||||
stdio.printf("[FAIL] a.GetName()=%d expected 42\n", name)
|
||||
return 1
|
||||
|
||||
speak: int = a.Speak()
|
||||
stdio.printf("vtable: a.Speak()=%d (expected 0)\n", speak)
|
||||
if speak != 0:
|
||||
stdio.printf("[FAIL] a.Speak()=%d expected 0\n", speak)
|
||||
return 1
|
||||
|
||||
# 测试 2: Shape 虚方法调用(带参,修改 self 字段)
|
||||
s: Shape = Shape()
|
||||
r: int = s.SetSides(4)
|
||||
stdio.printf("vtable: s.SetSides(4)=%d (expected 0)\n", r)
|
||||
if r != 0:
|
||||
stdio.printf("[FAIL] s.SetSides(4)=%d expected 0\n", r)
|
||||
return 1
|
||||
|
||||
sides: int = s.GetSides()
|
||||
stdio.printf("vtable: s.GetSides()=%d (expected 4)\n", sides)
|
||||
if sides != 4:
|
||||
stdio.printf("[FAIL] s.GetSides()=%d expected 4\n", sides)
|
||||
return 1
|
||||
|
||||
stdio.printf("vtable: === All Tests Passed ===\n")
|
||||
return 0
|
||||
20
Test/NegativeTest/App/defs.py
Normal file
20
Test/NegativeTest/App/defs.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import stdio
|
||||
import t, c
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 负向测试定义模块:定义 SecretClass
|
||||
#
|
||||
# 此文件定义 SecretClass,但 main.py 不 import 它。
|
||||
# 严格模式下 main.py 中的 SecretClass() 构造应编译失败。
|
||||
# ============================================================
|
||||
|
||||
|
||||
class SecretClass:
|
||||
val: t.CInt
|
||||
|
||||
def __init__(self, v: t.CInt):
|
||||
self.val = v
|
||||
|
||||
def GetVal(self) -> t.CInt:
|
||||
return self.val
|
||||
21
Test/NegativeTest/App/main.py
Normal file
21
Test/NegativeTest/App/main.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import stdio
|
||||
import t, c
|
||||
# 故意不 import defs.SecretClass — 严格模式下应编译失败
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 负向测试主入口
|
||||
#
|
||||
# 此文件故意不 import SecretClass,但尝试使用 SecretClass()。
|
||||
# 命名空间隔离严格模式下,SecretClass 不可见,
|
||||
# 构造器路径被跳过,生成 call i32 @SecretClass(...),
|
||||
# llc 报错 "use of undefined value '@SecretClass'"。
|
||||
#
|
||||
# 预期:TransPyV 编译失败(exit code != 0)
|
||||
# ============================================================
|
||||
def main() -> int:
|
||||
# SecretClass 未导入,严格模式下不可见
|
||||
s: SecretClass = SecretClass(42)
|
||||
v: int = s.GetVal()
|
||||
stdio.printf("negtest: v=%d (should not reach here)\n", v)
|
||||
return 0
|
||||
29
Test/NegativeTest/project.vpj
Normal file
29
Test/NegativeTest/project.vpj
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "NegativeTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"temp_dir": "./temp",
|
||||
"output_dir": "./output",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "neg_app.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
62
Test/Sha1Test/App/main.py
Normal file
62
Test/Sha1Test/App/main.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import stdio
|
||||
import stdlib
|
||||
import memhub
|
||||
import hashlib
|
||||
|
||||
|
||||
POOL_SIZE: t.CDefine = 16777480
|
||||
|
||||
|
||||
@t.CExport
|
||||
def main() -> int:
|
||||
arena: bytes = stdlib.malloc(POOL_SIZE)
|
||||
if arena is None:
|
||||
return 1
|
||||
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE)
|
||||
if mb is None:
|
||||
return 1
|
||||
hashlib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||
|
||||
# 测试 "abc" 的 SHA1
|
||||
# 期望: a9993e364706816aba3e25717850c26c9cd0d89d
|
||||
s: str = "abc"
|
||||
stdio.printf("input: %s\n", s)
|
||||
|
||||
# 计算 len(s)
|
||||
n: t.CSizeT = len(s)
|
||||
stdio.printf("len=%d\n", n)
|
||||
|
||||
# 构造 sha1 对象
|
||||
ctx: hashlib.sha1 | t.CPtr = hashlib.sha1()
|
||||
if ctx is None:
|
||||
stdio.printf("ctx is None\n")
|
||||
return 1
|
||||
|
||||
ctx.update(s)
|
||||
|
||||
digest: bytes = mb.alloc(hashlib.SHA1_DIGEST_LEN)
|
||||
if digest is None:
|
||||
stdio.printf("digest alloc failed\n")
|
||||
return 1
|
||||
|
||||
ctx.final(digest)
|
||||
|
||||
# 打印 digest(十六进制)
|
||||
stdio.printf("SHA1: ")
|
||||
for i in range(hashlib.SHA1_DIGEST_LEN):
|
||||
b: t.CUInt8T = digest[i]
|
||||
hi: t.CInt = (b >> 4) & 0xF
|
||||
lo: t.CInt = b & 0xF
|
||||
if hi < 10:
|
||||
stdio.printf("%c", '0' + hi)
|
||||
else:
|
||||
stdio.printf("%c", 'a' + (hi - 10))
|
||||
if lo < 10:
|
||||
stdio.printf("%c", '0' + lo)
|
||||
else:
|
||||
stdio.printf("%c", 'a' + (lo - 10))
|
||||
stdio.printf("\n")
|
||||
stdio.printf("expect: a9993e364706816aba3e25717850c26c9cd0d89d\n")
|
||||
return 0
|
||||
28
Test/Sha1Test/project.vpj
Normal file
28
Test/Sha1Test/project.vpj
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "Sha1Test",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"temp_dir": "./temp",
|
||||
"output_dir": "./output",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "sha1test.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
29
Test/project.vpj
Normal file
29
Test/project.vpj
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "AstTest",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"temp_dir": "./temp",
|
||||
"output_dir": "./output",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"],
|
||||
"output": "app.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
29
project.json
Normal file
29
project.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json",
|
||||
"name": "TransPyV",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./App",
|
||||
"temp_dir": "./temp",
|
||||
"output_dir": "./output",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "clang++",
|
||||
"flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition", "-Wl,--stack,0x1000000"],
|
||||
"output": "TransPyV.exe"
|
||||
},
|
||||
"includes": [
|
||||
"../includes"
|
||||
],
|
||||
"target": {
|
||||
"triple": "x86_64-pc-windows-gnu",
|
||||
"datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user