修正了一些错误
This commit is contained in:
@@ -3,7 +3,9 @@ from stdint import *
|
|||||||
import memhub
|
import memhub
|
||||||
import string
|
import string
|
||||||
import stdio
|
import stdio
|
||||||
|
import stdlib
|
||||||
import viperlib
|
import viperlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
from json.__parser import parse as json_parse
|
from json.__parser import parse as json_parse
|
||||||
from json import JsonValue, JSON_OBJECT, JSON_INT
|
from json import JsonValue, JSON_OBJECT, JSON_INT
|
||||||
import w32.fileio as fileio
|
import w32.fileio as fileio
|
||||||
@@ -50,86 +52,132 @@ def Load_project_config(path: str) -> int:
|
|||||||
global IncludesDir
|
global IncludesDir
|
||||||
|
|
||||||
if path is None:
|
if path is None:
|
||||||
|
stdio.printf("[CFG] FAIL: path is None\n")
|
||||||
|
stdio.fflush(0)
|
||||||
return 1
|
return 1
|
||||||
if _mbuddy is None:
|
if _mbuddy is None:
|
||||||
|
stdio.printf("[CFG] FAIL: _mbuddy is None\n")
|
||||||
|
stdio.fflush(0)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# 打开文件
|
# 打开文件
|
||||||
|
stdio.printf("[CFG] before File ctor path=%s\n", path)
|
||||||
|
stdio.fflush(0)
|
||||||
f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.R)
|
f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.R)
|
||||||
|
f_closed_flag: int = 1
|
||||||
|
if f is not None:
|
||||||
|
if f.closed:
|
||||||
|
f_closed_flag = 1
|
||||||
|
else:
|
||||||
|
f_closed_flag = 0
|
||||||
|
stdio.printf("[CFG] after File ctor f=%p closed=%d\n", f, f_closed_flag)
|
||||||
|
stdio.fflush(0)
|
||||||
|
if f is None:
|
||||||
|
stdio.printf("[CFG] FAIL: File ctor returned None\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
return 1
|
||||||
if f.closed:
|
if f.closed:
|
||||||
|
stdio.printf("[CFG] FAIL: f.closed is True\n")
|
||||||
|
stdio.fflush(0)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# 分配读取缓冲区
|
# 分配读取缓冲区
|
||||||
CFG_BUF_SIZE: t.CSizeT = 8192
|
CFG_BUF_SIZE: t.CSizeT = 8192
|
||||||
buf: bytes = _mbuddy.alloc(CFG_BUF_SIZE)
|
buf: bytes = _mbuddy.alloc(CFG_BUF_SIZE)
|
||||||
if buf is None:
|
if buf is None:
|
||||||
|
stdio.printf("[CFG] FAIL: alloc buf failed\n")
|
||||||
|
stdio.fflush(0)
|
||||||
f.close()
|
f.close()
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
stdio.printf("[CFG] before read_all\n")
|
||||||
|
stdio.fflush(0)
|
||||||
bytes_read: t.CInt64T = f.read_all(buf, CFG_BUF_SIZE)
|
bytes_read: t.CInt64T = f.read_all(buf, CFG_BUF_SIZE)
|
||||||
f.close()
|
f.close()
|
||||||
|
stdio.printf("[CFG] after read_all bytes_read=%d\n", bytes_read)
|
||||||
|
stdio.fflush(0)
|
||||||
if bytes_read <= 0:
|
if bytes_read <= 0:
|
||||||
|
stdio.printf("[CFG] FAIL: bytes_read <= 0\n")
|
||||||
|
stdio.fflush(0)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# 解析 JSON
|
# 解析 JSON
|
||||||
|
stdio.printf("[CFG] before json_parse\n")
|
||||||
|
stdio.fflush(0)
|
||||||
root: JsonValue | t.CPtr = json_parse(_mbuddy, buf)
|
root: JsonValue | t.CPtr = json_parse(_mbuddy, buf)
|
||||||
|
stdio.printf("[CFG] after json_parse root=%p\n", root)
|
||||||
|
stdio.fflush(0)
|
||||||
if root is None:
|
if root is None:
|
||||||
|
stdio.printf("[CFG] FAIL: json_parse returned None\n")
|
||||||
|
stdio.fflush(0)
|
||||||
return 1
|
return 1
|
||||||
if not root.is_object():
|
if not root.is_object():
|
||||||
|
stdio.printf("[CFG] FAIL: root is not object\n")
|
||||||
|
stdio.fflush(0)
|
||||||
return 1
|
return 1
|
||||||
|
stdio.printf("[CFG] root is object OK\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 读取顶层字段
|
# 读取顶层字段(使用显式 __getitem__ 调用,兼容旧编译器二进制)
|
||||||
SourceDir = root["source_dir"].as_string() if root["source_dir"] is not None else None
|
sd_val: JsonValue | t.CPtr = root.__getitem__("source_dir")
|
||||||
|
SourceDir = sd_val.as_string() if sd_val is not None else None
|
||||||
# build_dir: 统一构建目录(默认 ./.tpv_build),temp 和 output 作为其子目录
|
# build_dir: 统一构建目录(默认 ./.tpv_build),temp 和 output 作为其子目录
|
||||||
bd_val: JsonValue | t.CPtr = root["build_dir"]
|
bd_val: JsonValue | t.CPtr = root.__getitem__("build_dir")
|
||||||
if bd_val is not None and bd_val.is_string():
|
if bd_val is not None and bd_val.is_string():
|
||||||
BuildDir = bd_val.as_string()
|
BuildDir = bd_val.as_string()
|
||||||
else:
|
else:
|
||||||
BuildDir = "./.tpv_build"
|
BuildDir = "./.tpv_build"
|
||||||
ProjectName = root["name"].as_string() if root["name"] is not None else None
|
name_val: JsonValue | t.CPtr = root.__getitem__("name")
|
||||||
ProjectVersion = root["version"].as_string() if root["version"] is not None else None
|
ProjectName = name_val.as_string() if name_val is not None else None
|
||||||
|
ver_val: JsonValue | t.CPtr = root.__getitem__("version")
|
||||||
|
ProjectVersion = ver_val.as_string() if ver_val is not None else None
|
||||||
|
|
||||||
# 读取 compiler 子对象
|
# 读取 compiler 子对象
|
||||||
compiler: JsonValue | t.CPtr = root["compiler"]
|
compiler: JsonValue | t.CPtr = root.__getitem__("compiler")
|
||||||
if compiler is not None and compiler.is_object():
|
if compiler is not None and compiler.is_object():
|
||||||
CompilerCmd = compiler["cmd"].as_string() if compiler["cmd"] is not None else None
|
cc_cmd_val: JsonValue | t.CPtr = compiler.__getitem__("cmd")
|
||||||
|
CompilerCmd = cc_cmd_val.as_string() if cc_cmd_val is not None else None
|
||||||
# 读取 compiler.flags 数组,拼接成空格分隔的字符串
|
# 读取 compiler.flags 数组,拼接成空格分隔的字符串
|
||||||
cc_flags_val: JsonValue | t.CPtr = compiler["flags"]
|
cc_flags_val: JsonValue | t.CPtr = compiler.__getitem__("flags")
|
||||||
CompilerFlags = _join_flags_array(cc_flags_val)
|
CompilerFlags = _join_flags_array(cc_flags_val)
|
||||||
|
|
||||||
# 读取 linker 子对象
|
# 读取 linker 子对象
|
||||||
linker: JsonValue | t.CPtr = root["linker"]
|
linker: JsonValue | t.CPtr = root.__getitem__("linker")
|
||||||
if linker is not None and linker.is_object():
|
if linker is not None and linker.is_object():
|
||||||
LinkerCmd = linker["cmd"].as_string() if linker["cmd"] is not None else None
|
ld_cmd_val: JsonValue | t.CPtr = linker.__getitem__("cmd")
|
||||||
LinkerOutput = linker["output"].as_string() if linker["output"] is not None else None
|
LinkerCmd = ld_cmd_val.as_string() if ld_cmd_val is not None else None
|
||||||
|
ld_out_val: JsonValue | t.CPtr = linker.__getitem__("output")
|
||||||
|
LinkerOutput = ld_out_val.as_string() if ld_out_val is not None else None
|
||||||
# 读取 linker.flags 数组,拼接成空格分隔的字符串
|
# 读取 linker.flags 数组,拼接成空格分隔的字符串
|
||||||
ld_flags_val: JsonValue | t.CPtr = linker["flags"]
|
ld_flags_val: JsonValue | t.CPtr = linker.__getitem__("flags")
|
||||||
LinkerFlags = _join_flags_array(ld_flags_val)
|
LinkerFlags = _join_flags_array(ld_flags_val)
|
||||||
|
|
||||||
# 读取 target 子对象
|
# 读取 target 子对象
|
||||||
target: JsonValue | t.CPtr = root["target"]
|
target: JsonValue | t.CPtr = root.__getitem__("target")
|
||||||
if target is not None and target.is_object():
|
if target is not None and target.is_object():
|
||||||
TargetTriple = target["triple"].as_string() if target["triple"] is not None else None
|
tgt_triple_val: JsonValue | t.CPtr = target.__getitem__("triple")
|
||||||
TargetDataLayout = target["datalayout"].as_string() if target["datalayout"] is not None else None
|
TargetTriple = tgt_triple_val.as_string() if tgt_triple_val is not None else None
|
||||||
|
tgt_dl_val: JsonValue | t.CPtr = target.__getitem__("datalayout")
|
||||||
|
TargetDataLayout = tgt_dl_val.as_string() if tgt_dl_val is not None else None
|
||||||
|
|
||||||
# 读取 options 子对象
|
# 读取 options 子对象
|
||||||
# Sha1SliceLevel: SHA1 切片层数(默认 1,每层取 SHA1 前 2 字符作为子目录)
|
# Sha1SliceLevel: SHA1 切片层数(默认 1,每层取 SHA1 前 2 字符作为子目录)
|
||||||
# level=0 → 不切片,文件直接放 base_dir
|
# level=0 → 不切片,文件直接放 base_dir
|
||||||
# level=1 → b7/{sha1}.ext
|
# level=1 → b7/{sha1}.ext
|
||||||
# level=2 → b7/90/{sha1}.ext
|
# level=2 → b7/90/{sha1}.ext
|
||||||
options: JsonValue | t.CPtr = root["options"]
|
options: JsonValue | t.CPtr = root.__getitem__("options")
|
||||||
Sha1SliceLevel = 1
|
Sha1SliceLevel = 1
|
||||||
StrictMode = 1
|
StrictMode = 1
|
||||||
if options is not None and options.is_object():
|
if options is not None and options.is_object():
|
||||||
sl: JsonValue | t.CPtr = options["sha1_slice_level"]
|
sl: JsonValue | t.CPtr = options.__getitem__("sha1_slice_level")
|
||||||
if sl is not None and sl.is_int():
|
if sl is not None and sl.is_int():
|
||||||
Sha1SliceLevel = sl.as_int()
|
Sha1SliceLevel = sl.as_int()
|
||||||
sm: JsonValue | t.CPtr = options["strict_mode"]
|
sm: JsonValue | t.CPtr = options.__getitem__("strict_mode")
|
||||||
if sm is not None and sm.is_bool():
|
if sm is not None and sm.is_bool():
|
||||||
StrictMode = 1 if sm.as_bool() else 0
|
StrictMode = 1 if sm.as_bool() else 0
|
||||||
|
|
||||||
# 读取 includes 数组(取首个元素作为 includes 目录)
|
# 读取 includes 数组(取首个元素作为 includes 目录)
|
||||||
includes_val: JsonValue | t.CPtr = root["includes"]
|
includes_val: JsonValue | t.CPtr = root.__getitem__("includes")
|
||||||
if includes_val is not None and includes_val.is_array():
|
if includes_val is not None and includes_val.is_array():
|
||||||
arr_len: t.CSizeT = includes_val.__len__()
|
arr_len: t.CSizeT = includes_val.__len__()
|
||||||
if arr_len > 0:
|
if arr_len > 0:
|
||||||
@@ -307,24 +355,38 @@ def get_includes_binary_dir() -> str:
|
|||||||
|
|
||||||
|
|
||||||
def print_config():
|
def print_config():
|
||||||
"""打印当前配置(调试用)"""
|
"""打印当前配置"""
|
||||||
|
buf: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if buf is None:
|
||||||
|
return
|
||||||
if ProjectName is not None:
|
if ProjectName is not None:
|
||||||
stdio.printf(" project: %s v%s\n", ProjectName, ProjectVersion if ProjectVersion is not None else "?")
|
viperlib.snprintf(buf, 1024, "project: %s v%s", ProjectName,
|
||||||
|
ProjectVersion if ProjectVersion is not None else "?")
|
||||||
|
VLogger.info(buf, "config")
|
||||||
if SourceDir is not None:
|
if SourceDir is not None:
|
||||||
stdio.printf(" source_dir: %s\n", SourceDir)
|
viperlib.snprintf(buf, 1024, "source_dir: %s", SourceDir)
|
||||||
|
VLogger.info(buf, "config")
|
||||||
if BuildDir is not None:
|
if BuildDir is not None:
|
||||||
stdio.printf(" build_dir: %s\n", BuildDir)
|
viperlib.snprintf(buf, 1024, "build_dir: %s", BuildDir)
|
||||||
|
VLogger.info(buf, "config")
|
||||||
if TempDir is not None:
|
if TempDir is not None:
|
||||||
stdio.printf(" temp_dir: %s\n", TempDir)
|
viperlib.snprintf(buf, 1024, "temp_dir: %s", TempDir)
|
||||||
|
VLogger.info(buf, "config")
|
||||||
if OutputDir is not None:
|
if OutputDir is not None:
|
||||||
stdio.printf(" output_dir: %s\n", OutputDir)
|
viperlib.snprintf(buf, 1024, "output_dir: %s", OutputDir)
|
||||||
|
VLogger.info(buf, "config")
|
||||||
if CompilerCmd is not None:
|
if CompilerCmd is not None:
|
||||||
stdio.printf(" compiler: %s\n", CompilerCmd)
|
viperlib.snprintf(buf, 1024, "compiler: %s", CompilerCmd)
|
||||||
|
VLogger.info(buf, "config")
|
||||||
if LinkerCmd is not None:
|
if LinkerCmd is not None:
|
||||||
stdio.printf(" linker: %s -> %s\n", LinkerCmd, LinkerOutput if LinkerOutput is not None else "?")
|
viperlib.snprintf(buf, 1024, "linker: %s -> %s", LinkerCmd,
|
||||||
|
LinkerOutput if LinkerOutput is not None else "?")
|
||||||
|
VLogger.info(buf, "config")
|
||||||
if IncludesDir is not None:
|
if IncludesDir is not None:
|
||||||
stdio.printf(" includes: %s\n", IncludesDir)
|
viperlib.snprintf(buf, 1024, "includes: %s", IncludesDir)
|
||||||
stdio.printf(" sha1_slice_level: %d\n", Sha1SliceLevel)
|
VLogger.info(buf, "config")
|
||||||
|
viperlib.snprintf(buf, 1024, "sha1_slice_level: %d", Sha1SliceLevel)
|
||||||
|
VLogger.info(buf, "config")
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|||||||
@@ -63,12 +63,14 @@ def compute_sha1(pool: memhub.MemBuddy | t.CPtr, content: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# CleanDir - 删除目录中所有文件(非递归,保留目录本身)
|
# CleanDir - 递归删除目录中所有文件和子目录(保留 dir_path 本身)
|
||||||
#
|
#
|
||||||
# 用于 --clean 选项:清理 temp_dir 和 output_dir 中的旧文件。
|
# 用于 --clean 选项:清理 temp_dir 和 output_dir 中的旧文件。
|
||||||
|
# SHA1 分片目录结构(如 temp/1c/、temp/7a/)需要递归清理,
|
||||||
|
# 否则旧的截断文件(如 256KB text.ll)会被 Phase1 跳过逻辑复用。
|
||||||
# ============================================================
|
# ============================================================
|
||||||
def CleanDir(dir_path: str) -> int:
|
def CleanDir(dir_path: str) -> int:
|
||||||
"""删除目录中所有文件(非递归),返回删除的文件数,-1 表示错误"""
|
"""递归删除目录中所有文件和子目录,保留 dir_path 本身,返回删除的文件数,-1 表示错误"""
|
||||||
if dir_path is None:
|
if dir_path is None:
|
||||||
return -1
|
return -1
|
||||||
dir_len: t.CSizeT = string.strlen(dir_path)
|
dir_len: t.CSizeT = string.strlen(dir_path)
|
||||||
@@ -104,8 +106,19 @@ def CleanDir(dir_path: str) -> int:
|
|||||||
full_path: bytes = stdlib.malloc(dir_len + fname_len + 2)
|
full_path: bytes = stdlib.malloc(dir_len + fname_len + 2)
|
||||||
if full_path is not None:
|
if full_path is not None:
|
||||||
viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", dir_path, fname)
|
viperlib.snprintf(full_path, dir_len + fname_len + 2, "%s/%s", dir_path, fname)
|
||||||
if w32.win32file.DeleteFileA(full_path) != 0:
|
# 检查是否为目录(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
deleted += 1
|
is_dir: t.CUInt32T = find_data.dwFileAttributes & w32.win32file.FILE_ATTRIBUTE_DIRECTORY
|
||||||
|
if is_dir != 0:
|
||||||
|
# 递归清理子目录中的文件
|
||||||
|
sub_deleted: int = CleanDir(full_path)
|
||||||
|
if sub_deleted > 0:
|
||||||
|
deleted += sub_deleted
|
||||||
|
# 删除空子目录(RemoveDirectoryA 要求目录为空)
|
||||||
|
w32.win32file.RemoveDirectoryA(full_path)
|
||||||
|
else:
|
||||||
|
# 删除文件
|
||||||
|
if w32.win32file.DeleteFileA(full_path) != 0:
|
||||||
|
deleted += 1
|
||||||
stdlib.free(full_path)
|
stdlib.free(full_path)
|
||||||
|
|
||||||
if w32.win32file.FindNextFileA(handle, find_data) == 0:
|
if w32.win32file.FindNextFileA(handle, find_data) == 0:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from stdint import *
|
|||||||
import ast
|
import ast
|
||||||
import string
|
import string
|
||||||
import memhub
|
import memhub
|
||||||
|
import viperlib
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -117,12 +118,13 @@ def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
if k == ast.ASTKind.Tuple:
|
if k == ast.ASTKind.Tuple:
|
||||||
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(annot)
|
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(annot)
|
||||||
if tup.elts is not None:
|
if tup.elts is not None:
|
||||||
tn: t.CSizeT = tup.elts.__len__()
|
tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts
|
||||||
|
tn: t.CSizeT = tup_elts.__len__()
|
||||||
ti: t.CSizeT = 0
|
ti: t.CSizeT = 0
|
||||||
while ti < tn:
|
while ti < tn:
|
||||||
if ti > 0:
|
if ti > 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||||
el: ast.AST | t.CPtr = tup.elts.get(ti)
|
el: ast.AST | t.CPtr = tup_elts.get(ti)
|
||||||
pos = _PyiTypeStr(buf, buf_size, pos, el)
|
pos = _PyiTypeStr(buf, buf_size, pos, el)
|
||||||
ti += 1
|
ti += 1
|
||||||
return pos
|
return pos
|
||||||
@@ -133,12 +135,13 @@ def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
pos = _PyiTypeStr(buf, buf_size, pos, cl.func)
|
pos = _PyiTypeStr(buf, buf_size, pos, cl.func)
|
||||||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||||||
if cl.args is not None:
|
if cl.args is not None:
|
||||||
can: t.CSizeT = cl.args.__len__()
|
cl_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||||
|
can: t.CSizeT = cl_args.__len__()
|
||||||
cai: t.CSizeT = 0
|
cai: t.CSizeT = 0
|
||||||
while cai < can:
|
while cai < can:
|
||||||
if cai > 0:
|
if cai > 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||||
ca: ast.AST | t.CPtr = cl.args.get(cai)
|
ca: ast.AST | t.CPtr = cl_args.get(cai)
|
||||||
pos = _PyiTypeStr(buf, buf_size, pos, ca)
|
pos = _PyiTypeStr(buf, buf_size, pos, ca)
|
||||||
cai += 1
|
cai += 1
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ")")
|
pos = _PyiEmit(buf, buf_size, pos, ")")
|
||||||
@@ -159,10 +162,11 @@ def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
"""生成函数签名到 buf,返回新的 pos"""
|
"""生成函数签名到 buf,返回新的 pos"""
|
||||||
# 装饰器
|
# 装饰器
|
||||||
if fn.decorator_list is not None:
|
if fn.decorator_list is not None:
|
||||||
dn: t.CSizeT = fn.decorator_list.__len__()
|
fn_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = fn.decorator_list
|
||||||
|
dn: t.CSizeT = fn_decorator_list.__len__()
|
||||||
di: t.CSizeT = 0
|
di: t.CSizeT = 0
|
||||||
while di < dn:
|
while di < dn:
|
||||||
dec: ast.AST | t.CPtr = fn.decorator_list.get(di)
|
dec: ast.AST | t.CPtr = fn_decorator_list.get(di)
|
||||||
if dec is not None:
|
if dec is not None:
|
||||||
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
||||||
pos = _PyiEmit(buf, buf_size, pos, "@")
|
pos = _PyiEmit(buf, buf_size, pos, "@")
|
||||||
@@ -184,13 +188,14 @@ def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
|
|
||||||
# 位置参数
|
# 位置参数
|
||||||
if args.args is not None:
|
if args.args is not None:
|
||||||
an: t.CSizeT = args.args.__len__()
|
args_args: list[ast.AST | t.CPtr] | t.CPtr = args.args
|
||||||
|
an: t.CSizeT = args_args.__len__()
|
||||||
ai: t.CSizeT = 0
|
ai: t.CSizeT = 0
|
||||||
while ai < an:
|
while ai < an:
|
||||||
if first == 0:
|
if first == 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||||
first = 0
|
first = 0
|
||||||
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args.args.get(ai))
|
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(args_args.get(ai))
|
||||||
if ag.arg is not None:
|
if ag.arg is not None:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ag.arg)
|
pos = _PyiEmit(buf, buf_size, pos, ag.arg)
|
||||||
if ag.annotation is not None:
|
if ag.annotation is not None:
|
||||||
@@ -242,10 +247,11 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
"""生成类定义到 buf,返回新的 pos"""
|
"""生成类定义到 buf,返回新的 pos"""
|
||||||
# 装饰器
|
# 装饰器
|
||||||
if cls.decorator_list is not None:
|
if cls.decorator_list is not None:
|
||||||
dcn: t.CSizeT = cls.decorator_list.__len__()
|
cls_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = cls.decorator_list
|
||||||
|
dcn: t.CSizeT = cls_decorator_list.__len__()
|
||||||
dci: t.CSizeT = 0
|
dci: t.CSizeT = 0
|
||||||
while dci < dcn:
|
while dci < dcn:
|
||||||
ddec: ast.AST | t.CPtr = cls.decorator_list.get(dci)
|
ddec: ast.AST | t.CPtr = cls_decorator_list.get(dci)
|
||||||
if ddec is not None:
|
if ddec is not None:
|
||||||
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
||||||
pos = _PyiEmit(buf, buf_size, pos, "@")
|
pos = _PyiEmit(buf, buf_size, pos, "@")
|
||||||
@@ -260,14 +266,15 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
|
|
||||||
# PEP 695 类型参数 (class Foo[T]:)
|
# PEP 695 类型参数 (class Foo[T]:)
|
||||||
if cls.type_params is not None:
|
if cls.type_params is not None:
|
||||||
tpn: t.CSizeT = cls.type_params.__len__()
|
cls_type_params: list[ast.AST | t.CPtr] | t.CPtr = cls.type_params
|
||||||
|
tpn: t.CSizeT = cls_type_params.__len__()
|
||||||
if tpn > 0:
|
if tpn > 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||||||
tpi: t.CSizeT = 0
|
tpi: t.CSizeT = 0
|
||||||
while tpi < tpn:
|
while tpi < tpn:
|
||||||
if tpi > 0:
|
if tpi > 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||||
tpname: str = cls.type_params.get(tpi)
|
tpname: str = cls_type_params.get(tpi)
|
||||||
if tpname is not None:
|
if tpname is not None:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, tpname)
|
pos = _PyiEmit(buf, buf_size, pos, tpname)
|
||||||
tpi += 1
|
tpi += 1
|
||||||
@@ -275,14 +282,15 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
|
|
||||||
# 基类
|
# 基类
|
||||||
if cls.bases is not None:
|
if cls.bases is not None:
|
||||||
bn: t.CSizeT = cls.bases.__len__()
|
cls_bases: list[ast.AST | t.CPtr] | t.CPtr = cls.bases
|
||||||
|
bn: t.CSizeT = cls_bases.__len__()
|
||||||
if bn > 0:
|
if bn > 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||||||
bi: t.CSizeT = 0
|
bi: t.CSizeT = 0
|
||||||
while bi < bn:
|
while bi < bn:
|
||||||
if bi > 0:
|
if bi > 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||||
base: ast.AST | t.CPtr = cls.bases.get(bi)
|
base: ast.AST | t.CPtr = cls_bases.get(bi)
|
||||||
pos = _PyiTypeStr(buf, buf_size, pos, base)
|
pos = _PyiTypeStr(buf, buf_size, pos, base)
|
||||||
bi += 1
|
bi += 1
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ")")
|
pos = _PyiEmit(buf, buf_size, pos, ")")
|
||||||
@@ -293,10 +301,11 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
has_member: int = 0
|
has_member: int = 0
|
||||||
|
|
||||||
if cls.children is not None:
|
if cls.children is not None:
|
||||||
cn: t.CSizeT = cls.children.__len__()
|
cls_children: list[ast.AST | t.CPtr] | t.CPtr = cls.children
|
||||||
|
cn: t.CSizeT = cls_children.__len__()
|
||||||
ci: t.CSizeT = 0
|
ci: t.CSizeT = 0
|
||||||
while ci < cn:
|
while ci < cn:
|
||||||
stmt: ast.AST | t.CPtr = cls.children.get(ci)
|
stmt: ast.AST | t.CPtr = cls_children.get(ci)
|
||||||
if stmt is not None:
|
if stmt is not None:
|
||||||
sk: int = stmt.kind()
|
sk: int = stmt.kind()
|
||||||
|
|
||||||
@@ -306,10 +315,11 @@ def _PyiClass(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
|
|||||||
# __init__ 方法:先提取 self.x: Type 属性
|
# __init__ 方法:先提取 self.x: Type 属性
|
||||||
if mfn.name is not None and string.strcmp(mfn.name, "__init__") == 0:
|
if mfn.name is not None and string.strcmp(mfn.name, "__init__") == 0:
|
||||||
if mfn.children is not None:
|
if mfn.children is not None:
|
||||||
icn: t.CSizeT = mfn.children.__len__()
|
mfn_children: list[ast.AST | t.CPtr] | t.CPtr = mfn.children
|
||||||
|
icn: t.CSizeT = mfn_children.__len__()
|
||||||
ici: t.CSizeT = 0
|
ici: t.CSizeT = 0
|
||||||
while ici < icn:
|
while ici < icn:
|
||||||
ibody: ast.AST | t.CPtr = mfn.children.get(ici)
|
ibody: ast.AST | t.CPtr = mfn_children.get(ici)
|
||||||
if ibody is not None and ibody.kind() == ast.ASTKind.AnnAssign:
|
if ibody is not None and ibody.kind() == ast.ASTKind.AnnAssign:
|
||||||
iaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(ibody)
|
iaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(ibody)
|
||||||
if iaa.target is not None and iaa.target.kind() == ast.ASTKind.Attribute:
|
if iaa.target is not None and iaa.target.kind() == ast.ASTKind.Attribute:
|
||||||
@@ -391,21 +401,23 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
|||||||
buf[pos] = 0
|
buf[pos] = 0
|
||||||
return pos
|
return pos
|
||||||
|
|
||||||
n: t.CSizeT = tree.children.__len__()
|
tree_children: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||||
|
n: t.CSizeT = tree_children.__len__()
|
||||||
|
|
||||||
# 第一遍扫描:检测 import t/c
|
# 第一遍扫描:检测 import t/c
|
||||||
has_import_t: int = 0
|
has_import_t: int = 0
|
||||||
has_import_c: int = 0
|
has_import_c: int = 0
|
||||||
i: t.CSizeT = 0
|
i: t.CSizeT = 0
|
||||||
while i < n:
|
while i < n:
|
||||||
stmt: ast.AST | t.CPtr = tree.children.get(i)
|
stmt: ast.AST | t.CPtr = tree_children.get(i)
|
||||||
if stmt is not None and stmt.kind() == ast.ASTKind.Import:
|
if stmt is not None and stmt.kind() == ast.ASTKind.Import:
|
||||||
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt)
|
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt)
|
||||||
if imp.names is not None:
|
if imp.names is not None:
|
||||||
an: t.CSizeT = imp.names.__len__()
|
imp_names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
|
||||||
|
an: t.CSizeT = imp_names.__len__()
|
||||||
ai: t.CSizeT = 0
|
ai: t.CSizeT = 0
|
||||||
while ai < an:
|
while ai < an:
|
||||||
al: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp.names.get(ai))
|
al: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp_names.get(ai))
|
||||||
if al is not None and al.name is not None:
|
if al is not None and al.name is not None:
|
||||||
if string.strcmp(al.name, "t") == 0:
|
if string.strcmp(al.name, "t") == 0:
|
||||||
has_import_t = 1
|
has_import_t = 1
|
||||||
@@ -427,7 +439,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
|||||||
# 第二遍扫描:生成声明
|
# 第二遍扫描:生成声明
|
||||||
i = 0
|
i = 0
|
||||||
while i < n:
|
while i < n:
|
||||||
stmt = tree.children.get(i)
|
stmt = tree_children.get(i)
|
||||||
if stmt is not None:
|
if stmt is not None:
|
||||||
k: int = stmt.kind()
|
k: int = stmt.kind()
|
||||||
|
|
||||||
@@ -436,12 +448,13 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
|||||||
imp2: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt)
|
imp2: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt)
|
||||||
pos = _PyiEmit(buf, buf_size, pos, "import ")
|
pos = _PyiEmit(buf, buf_size, pos, "import ")
|
||||||
if imp2.names is not None:
|
if imp2.names is not None:
|
||||||
an2: t.CSizeT = imp2.names.__len__()
|
imp2_names: list[ast.AST | t.CPtr] | t.CPtr = imp2.names
|
||||||
|
an2: t.CSizeT = imp2_names.__len__()
|
||||||
ai2: t.CSizeT = 0
|
ai2: t.CSizeT = 0
|
||||||
while ai2 < an2:
|
while ai2 < an2:
|
||||||
if ai2 > 0:
|
if ai2 > 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||||
al2: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp2.names.get(ai2))
|
al2: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp2_names.get(ai2))
|
||||||
if al2 is not None and al2.name is not None:
|
if al2 is not None and al2.name is not None:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, al2.name)
|
pos = _PyiEmit(buf, buf_size, pos, al2.name)
|
||||||
if al2.asname is not None and string.strlen(al2.asname) > 0:
|
if al2.asname is not None and string.strlen(al2.asname) > 0:
|
||||||
@@ -462,12 +475,13 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
|||||||
pos = _PyiEmit(buf, buf_size, pos, ifr.module)
|
pos = _PyiEmit(buf, buf_size, pos, ifr.module)
|
||||||
pos = _PyiEmit(buf, buf_size, pos, " import ")
|
pos = _PyiEmit(buf, buf_size, pos, " import ")
|
||||||
if ifr.names is not None:
|
if ifr.names is not None:
|
||||||
an3: t.CSizeT = ifr.names.__len__()
|
ifr_names: list[ast.AST | t.CPtr] | t.CPtr = ifr.names
|
||||||
|
an3: t.CSizeT = ifr_names.__len__()
|
||||||
ai3: t.CSizeT = 0
|
ai3: t.CSizeT = 0
|
||||||
while ai3 < an3:
|
while ai3 < an3:
|
||||||
if ai3 > 0:
|
if ai3 > 0:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||||||
al3: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(ifr.names.get(ai3))
|
al3: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(ifr_names.get(ai3))
|
||||||
if al3 is not None and al3.name is not None:
|
if al3 is not None and al3.name is not None:
|
||||||
pos = _PyiEmit(buf, buf_size, pos, al3.name)
|
pos = _PyiEmit(buf, buf_size, pos, al3.name)
|
||||||
if al3.asname is not None and string.strlen(al3.asname) > 0:
|
if al3.asname is not None and string.strlen(al3.asname) > 0:
|
||||||
@@ -496,15 +510,31 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
|
|||||||
pos = _PyiEmit(buf, buf_size, pos, nm.id)
|
pos = _PyiEmit(buf, buf_size, pos, nm.id)
|
||||||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||||||
pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation)
|
pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation)
|
||||||
|
# 如果有值(如 CDefine 常量),输出 = value
|
||||||
|
if aa.value is not None and aa.value.kind() == ast.ASTKind.Constant:
|
||||||
|
cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
|
||||||
|
if cv.const_kind == ast.CONST_INT:
|
||||||
|
num_buf: bytes = mb.alloc(32)
|
||||||
|
if num_buf is not None:
|
||||||
|
viperlib.snprintf(num_buf, 32, " = %d", cv.int_val)
|
||||||
|
pos = _PyiEmit(buf, buf_size, pos, num_buf)
|
||||||
|
elif cv.const_kind == ast.CONST_BOOL:
|
||||||
|
if cv.int_val != 0:
|
||||||
|
pos = _PyiEmit(buf, buf_size, pos, " = True")
|
||||||
|
else:
|
||||||
|
pos = _PyiEmit(buf, buf_size, pos, " = False")
|
||||||
|
elif cv.const_kind == ast.CONST_NONE:
|
||||||
|
pos = _PyiEmit(buf, buf_size, pos, " = None")
|
||||||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||||||
|
|
||||||
# 全局赋值(无注解)— 从 Constant value 推断类型
|
# 全局赋值(无注解)— 从 Constant value 推断类型
|
||||||
elif k == ast.ASTKind.Assign:
|
elif k == ast.ASTKind.Assign:
|
||||||
asg: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt)
|
asg: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(stmt)
|
||||||
if asg.targets is not None and asg.value is not None:
|
if asg.targets is not None and asg.value is not None:
|
||||||
atn: t.CSizeT = asg.targets.__len__()
|
asg_targets: list[ast.AST | t.CPtr] | t.CPtr = asg.targets
|
||||||
|
atn: t.CSizeT = asg_targets.__len__()
|
||||||
if atn == 1:
|
if atn == 1:
|
||||||
atg: ast.AST | t.CPtr = asg.targets.get(0)
|
atg: ast.AST | t.CPtr = asg_targets.get(0)
|
||||||
if atg is not None and atg.kind() == ast.ASTKind.Name:
|
if atg is not None and atg.kind() == ast.ASTKind.Name:
|
||||||
agn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(atg)
|
agn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(atg)
|
||||||
aval: ast.AST | t.CPtr = asg.value
|
aval: ast.AST | t.CPtr = asg.value
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import w32.win32base
|
|||||||
import subprocess
|
import subprocess
|
||||||
import viperlib
|
import viperlib
|
||||||
import ast
|
import ast
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||||
import lib.core.Handles.HandlesType as HandlesType
|
import lib.core.Handles.HandlesType as HandlesType
|
||||||
@@ -68,6 +69,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
|||||||
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
||||||
f.close()
|
f.close()
|
||||||
if bytes_read <= 0:
|
if bytes_read <= 0:
|
||||||
|
stdlib.free(src_buf)
|
||||||
return None
|
return None
|
||||||
if bytes_read < SRC_BUF_SIZE:
|
if bytes_read < SRC_BUF_SIZE:
|
||||||
src_buf[bytes_read] = 0
|
src_buf[bytes_read] = 0
|
||||||
@@ -77,6 +79,8 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
|||||||
ast._lexer_init(lx, src_buf, mb)
|
ast._lexer_init(lx, src_buf, mb)
|
||||||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||||||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||||||
|
# parse 完成后 AST 树已独立,释放源代码缓冲区(避免 1MB/文件泄漏)
|
||||||
|
stdlib.free(src_buf)
|
||||||
if tree is None:
|
if tree is None:
|
||||||
return None
|
return None
|
||||||
tr: HandlesTranslator.Translator | t.CPtr = mb.alloc(HandlesTranslator.Translator.__sizeof__())
|
tr: HandlesTranslator.Translator | t.CPtr = mb.alloc(HandlesTranslator.Translator.__sizeof__())
|
||||||
@@ -268,12 +272,27 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
|||||||
|
|
||||||
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
||||||
if result is None:
|
if result is None:
|
||||||
stdio.printf("[FATAL][LLC] subprocess.run 返回 None: %s\n", module_name)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "subprocess.run 返回 None: %s", module_name)
|
||||||
|
VLogger.error(fb, "LLC")
|
||||||
return 1
|
return 1
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
stdio.printf("[FATAL][LLC] 编译失败 (module=%s, cmd=%s)\n", module_name, cmd)
|
# 先直接输出 llc 的具体错误信息(VLogger.error 会 sys.exit,必须先输出)
|
||||||
|
# 注意: subprocess 在 Windows 下将 stderr 合并到 stdout(si.hStdError = stdout_write)
|
||||||
|
# 因此 result.stderr 总是 None,错误信息在 result.stdout 中
|
||||||
|
# stdout 通常已含换行符,不再额外加 \n
|
||||||
if result.stdout is not None:
|
if result.stdout is not None:
|
||||||
stdio.printf("[LLC] 输出:\n%s\n", result.stdout)
|
stdio.printf("%s", result.stdout)
|
||||||
|
stdio.fflush(0)
|
||||||
|
if result.stderr is not None:
|
||||||
|
stdio.printf("%s", result.stderr)
|
||||||
|
stdio.fflush(0)
|
||||||
|
# 最后输出编译失败摘要(VLogger.error 会 sys.exit)
|
||||||
|
fb = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "编译失败 (module=%s, cmd=%s)", module_name, cmd)
|
||||||
|
VLogger.error(fb, "LLC")
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -370,9 +389,15 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
|||||||
if includes_binary_dir is not None:
|
if includes_binary_dir is not None:
|
||||||
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
|
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
|
||||||
if extra_len > 0:
|
if extra_len > 0:
|
||||||
stdio.printf("[link] 附加 %d 字节的 includes.binary .obj 文件\n", extra_len)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "附加 %d 字节的 includes.binary .obj 文件", extra_len)
|
||||||
|
VLogger.info(fb, "link")
|
||||||
else:
|
else:
|
||||||
stdio.printf("[link] 警告: includes.binary 无 .obj 文件: %s\n", includes_binary_dir)
|
fb = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "includes.binary 无 .obj 文件: %s", includes_binary_dir)
|
||||||
|
VLogger.warning(fb, "link")
|
||||||
|
|
||||||
# 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags
|
# 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags
|
||||||
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
|
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
|
||||||
@@ -391,16 +416,25 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
|||||||
|
|
||||||
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
||||||
if result is None:
|
if result is None:
|
||||||
stdio.printf("[link] subprocess.run 返回 None\n")
|
VLogger.error("subprocess.run 返回 None", "link")
|
||||||
return 1
|
return 1
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
stdio.printf("[link] 链接失败,返回码: %d\n", result.returncode)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
stdio.printf("[link] 命令: %s\n", cmd)
|
if fb is not None:
|
||||||
# 显示链接器错误输出(subprocess 将 stderr 合并到 stdout)
|
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d", result.returncode)
|
||||||
|
VLogger.error(fb, "link")
|
||||||
|
fb = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "命令: %s", cmd)
|
||||||
|
VLogger.error(fb, "link")
|
||||||
|
# 显示链接器错误输出
|
||||||
|
# 注意: subprocess 在 Windows 下将 stderr 合并到 stdout,result.stderr 总是 None
|
||||||
if result.stdout is not None:
|
if result.stdout is not None:
|
||||||
stdio.printf("[link] 链接器输出:\n%s\n", result.stdout)
|
VLogger.error(result.stdout, "link")
|
||||||
else:
|
else:
|
||||||
stdio.printf("[link] 无输出捕获\n")
|
VLogger.error("无输出捕获", "link")
|
||||||
|
if result.stderr is not None:
|
||||||
|
VLogger.error(result.stderr, "link")
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -428,7 +462,10 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
|
|||||||
# Step 1: 写 .ll 文件
|
# Step 1: 写 .ll 文件
|
||||||
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
|
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
|
||||||
if ret != 0:
|
if ret != 0:
|
||||||
stdio.printf("[compile] 写 .ll 失败: %s\n", module_name)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", module_name)
|
||||||
|
VLogger.error(fb, "compile")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Step 2: 构造切片 .ll 路径并编译 → .obj
|
# Step 2: 构造切片 .ll 路径并编译 → .obj
|
||||||
@@ -438,7 +475,10 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
|
|||||||
|
|
||||||
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
|
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
|
||||||
if ret != 0:
|
if ret != 0:
|
||||||
stdio.printf("[compile] llc 编译失败: %s\n", module_name)
|
fb = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "llc 编译失败: %s", module_name)
|
||||||
|
VLogger.error(fb, "compile")
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -486,13 +526,22 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
|
|||||||
|
|
||||||
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
|
||||||
if result is None:
|
if result is None:
|
||||||
stdio.printf("[link] subprocess.run 返回 None\n")
|
VLogger.error("subprocess.run 返回 None", "link")
|
||||||
return 1
|
return 1
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
stdio.printf("[link] 链接失败,返回码: %d\n", result.returncode)
|
# 先直接输出 linker 的具体错误信息(VLogger.error 会 sys.exit,必须先输出)
|
||||||
stdio.printf("[link] 命令: %s\n", cmd)
|
# stdout/stderr 通常已含换行符,不再额外加 \n
|
||||||
if result.stdout is not None:
|
if result.stdout is not None:
|
||||||
stdio.printf("[link] 链接器输出:\n%s\n", result.stdout)
|
stdio.printf("%s", result.stdout)
|
||||||
|
stdio.fflush(0)
|
||||||
|
if result.stderr is not None:
|
||||||
|
stdio.printf("%s", result.stderr)
|
||||||
|
stdio.fflush(0)
|
||||||
|
# 最后输出链接失败摘要(VLogger.error 会 sys.exit)
|
||||||
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", result.returncode, cmd)
|
||||||
|
VLogger.error(fb, "link")
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import lib.core.Handles.HandlesType as HandlesType
|
|||||||
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||||
|
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -62,6 +63,64 @@ def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
|
|||||||
return cn.int_val
|
return cn.int_val
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _annotation_contains_name - 递归检查注解中是否包含指定名称
|
||||||
|
#
|
||||||
|
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
|
||||||
|
# ============================================================
|
||||||
|
def _annotation_contains_name(annot: ast.AST | t.CPtr, name: str) -> int:
|
||||||
|
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含"""
|
||||||
|
if annot is None or name is None:
|
||||||
|
return 0
|
||||||
|
k: int = annot.kind()
|
||||||
|
if k == ast.ASTKind.Attribute:
|
||||||
|
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||||||
|
if at.attr is not None and string.strcmp(at.attr, name) == 0:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
if k == ast.ASTKind.Name:
|
||||||
|
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
|
||||||
|
if nm.id is not None and string.strcmp(nm.id, name) == 0:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
if k == ast.ASTKind.BinOp:
|
||||||
|
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||||
|
if _annotation_contains_name(bop.left, name) != 0:
|
||||||
|
return 1
|
||||||
|
if _annotation_contains_name(bop.right, name) != 0:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
|
||||||
|
#
|
||||||
|
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
|
||||||
|
#
|
||||||
|
# 规则:
|
||||||
|
# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1
|
||||||
|
# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0
|
||||||
|
# 纯 bytes / str → i8*(1 字节步长)→ 返回 0
|
||||||
|
#
|
||||||
|
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
|
||||||
|
# ============================================================
|
||||||
|
def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int:
|
||||||
|
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式"""
|
||||||
|
if annot is None:
|
||||||
|
return 0
|
||||||
|
k: int = annot.kind()
|
||||||
|
if k != ast.ASTKind.BinOp:
|
||||||
|
return 0
|
||||||
|
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||||||
|
if bop.op != ast.OpKind.BitOr:
|
||||||
|
return 0
|
||||||
|
if _annotation_contains_name(annot, "str") != 0:
|
||||||
|
return 1
|
||||||
|
if _annotation_contains_name(annot, "bytes") != 0:
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@t.NoVTable
|
@t.NoVTable
|
||||||
class AnnAssignHandle(HandlesBase.Mixin):
|
class AnnAssignHandle(HandlesBase.Mixin):
|
||||||
"""AnnAssign 语句处理器:继承 Mixin 获得 Trans 回指针"""
|
"""AnnAssign 语句处理器:继承 Mixin 获得 Trans 回指针"""
|
||||||
@@ -121,7 +180,7 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
|||||||
annot: ast.AST | t.CPtr = aa.annotation
|
annot: ast.AST | t.CPtr = aa.annotation
|
||||||
if annot is not None:
|
if annot is not None:
|
||||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||||
pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
|
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
|
||||||
if resolved is None:
|
if resolved is None:
|
||||||
# 尝试特化泛型类注解(如 list[str])
|
# 尝试特化泛型类注解(如 list[str])
|
||||||
# resolve_annotation_type 返回 None 可能是因为泛型类未特化
|
# resolve_annotation_type 返回 None 可能是因为泛型类未特化
|
||||||
@@ -138,11 +197,13 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
|||||||
self.Trans, sub_nm.id, type_args_ps)
|
self.Trans, sub_nm.id, type_args_ps)
|
||||||
if spec_name_ps is not None:
|
if spec_name_ps is not None:
|
||||||
resolved = HandlesType.resolve_annotation_type(
|
resolved = HandlesType.resolve_annotation_type(
|
||||||
pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
|
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
|
||||||
if resolved is not None:
|
if resolved is not None:
|
||||||
var_ty = resolved
|
var_ty = resolved
|
||||||
|
|
||||||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, var_ty)
|
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||||||
|
HandlesStruct.ensure_struct_def_in_module(pool, self.Trans.Module, var_ty)
|
||||||
|
alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, var_ty)
|
||||||
if alloca is not None:
|
if alloca is not None:
|
||||||
if HandlesVar.define_var(
|
if HandlesVar.define_var(
|
||||||
self.Trans.SymTab, nm.id, alloca) == 0:
|
self.Trans.SymTab, nm.id, alloca) == 0:
|
||||||
@@ -153,6 +214,10 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
|||||||
if cls_nm_ps is not None:
|
if cls_nm_ps is not None:
|
||||||
HandlesVar.set_var_annot_class_name(
|
HandlesVar.set_var_annot_class_name(
|
||||||
self.Trans.SymTab, nm.id, cls_nm_ps)
|
self.Trans.SymTab, nm.id, cls_nm_ps)
|
||||||
|
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
|
||||||
|
if _is_ptr_element_annotation(annot) != 0:
|
||||||
|
HandlesVar.set_var_ptr_element(
|
||||||
|
self.Trans.SymTab, nm.id)
|
||||||
return 0
|
return 0
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -193,7 +258,7 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
|||||||
annot: ast.AST | t.CPtr = aa.annotation
|
annot: ast.AST | t.CPtr = aa.annotation
|
||||||
if annot is not None:
|
if annot is not None:
|
||||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||||
pool, annot, self.Trans._imported_modules, self.Trans._from_imports)
|
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
|
||||||
if resolved is not None:
|
if resolved is not None:
|
||||||
var_ty = resolved
|
var_ty = resolved
|
||||||
|
|
||||||
@@ -243,6 +308,10 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
|||||||
if cls_nm_hd is not None:
|
if cls_nm_hd is not None:
|
||||||
HandlesVar.set_var_annot_class_name(
|
HandlesVar.set_var_annot_class_name(
|
||||||
self.Trans.SymTab, nm.id, cls_nm_hd)
|
self.Trans.SymTab, nm.id, cls_nm_hd)
|
||||||
|
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
|
||||||
|
if _is_ptr_element_annotation(annot) != 0:
|
||||||
|
HandlesVar.set_var_ptr_element(
|
||||||
|
self.Trans.SymTab, nm.id)
|
||||||
|
|
||||||
new_vars: int = 0
|
new_vars: int = 0
|
||||||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
|
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import memhub
|
|||||||
import string
|
import string
|
||||||
import stdio
|
import stdio
|
||||||
import viperlib
|
import viperlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
import lib.core.Handles.HandlesBase as HandlesBase
|
import lib.core.Handles.HandlesBase as HandlesBase
|
||||||
import lib.core.Handles.HandlesTranslator as HT
|
import lib.core.Handles.HandlesTranslator as HT
|
||||||
import lib.core.Handles.HandlesVar as HandlesVar
|
import lib.core.Handles.HandlesVar as HandlesVar
|
||||||
@@ -44,12 +45,12 @@ class AssignHandle(HandlesBase.Mixin):
|
|||||||
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
def Handle(self, node: ast.AST | t.CPtr) -> int:
|
||||||
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||||||
if asgn is None:
|
if asgn is None:
|
||||||
stdio.printf("[ASGN] cast failed\n")
|
VLogger.error("cast failed", "ASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
|
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
|
||||||
if targets is None:
|
if targets is None:
|
||||||
stdio.printf("[ASGN] targets is None\n")
|
VLogger.error("targets is None", "ASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 从 self.Trans 取共享状态(替代 11 个参数)
|
# 从 self.Trans 取共享状态(替代 11 个参数)
|
||||||
@@ -61,7 +62,23 @@ class AssignHandle(HandlesBase.Mixin):
|
|||||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||||
builder, pool, mod, asgn.value, None, 0, self.Trans)
|
builder, pool, mod, asgn.value, None, 0, self.Trans)
|
||||||
if rhs_val is None:
|
if rhs_val is None:
|
||||||
stdio.printf("[ASGN] rhs_val is None\n")
|
# 增强错误信息:包含 sha1 + lineno + AST 节点类型,便于定位
|
||||||
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None and asgn.value is not None:
|
||||||
|
sha1: str = self.Trans.ModuleSha1
|
||||||
|
val_kind: int = asgn.value.kind()
|
||||||
|
val_line: t.CInt = asgn.value.lineno
|
||||||
|
if sha1 is not None:
|
||||||
|
viperlib.snprintf(fb, 1024,
|
||||||
|
"rhs_val is None [sha1=%s lineno=%d kind=%d]",
|
||||||
|
sha1, val_line, val_kind)
|
||||||
|
else:
|
||||||
|
viperlib.snprintf(fb, 1024,
|
||||||
|
"rhs_val is None [lineno=%d kind=%d]",
|
||||||
|
val_line, val_kind)
|
||||||
|
VLogger.error(fb, "ASGN")
|
||||||
|
else:
|
||||||
|
VLogger.error("rhs_val is None", "ASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
new_vars: int = 0
|
new_vars: int = 0
|
||||||
@@ -116,23 +133,115 @@ class AssignHandle(HandlesBase.Mixin):
|
|||||||
sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee
|
sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee
|
||||||
if sub_pointee is not None:
|
if sub_pointee is not None:
|
||||||
cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee)
|
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(
|
||||||
obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
builder, sub_pointee, sub_alloca)
|
||||||
builder, sub_pointee, sub_alloca)
|
# 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct),
|
||||||
if obj_val_set is not None:
|
# 需 load 获取 Ptr(Struct) 再检查 inner struct
|
||||||
key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
if cls_nm_set is None and obj_val_set is not None:
|
||||||
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
if HandlesExpr.is_ptr_type(sub_pointee) != 0:
|
||||||
if key_val_set is not None:
|
inner_ty_set: llvmlite.LLVMType | t.CPtr = sub_pointee.Pointee
|
||||||
arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16)
|
if inner_ty_set is not None:
|
||||||
if arg_vals_set is not None:
|
cls_nm_set = HandlesStruct.get_class_name_by_type(pool, inner_ty_set)
|
||||||
arg_vals_set[0] = t.CSizeT(key_val_set)
|
if cls_nm_set is not None and obj_val_set is not None:
|
||||||
arg_vals_set[1] = t.CSizeT(rhs_val)
|
key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||||
HandlesExprCall._call_method_on_ptr(
|
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||||||
pool, builder, mod, cls_nm_set, "__setitem__",
|
if key_val_set is not None:
|
||||||
obj_val_set, arg_vals_set, 2, self.Trans)
|
arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16)
|
||||||
setitem_done = 1
|
if arg_vals_set is not None:
|
||||||
|
arg_vals_set[0] = t.CSizeT(key_val_set)
|
||||||
|
arg_vals_set[1] = t.CSizeT(rhs_val)
|
||||||
|
HandlesExprCall._call_method_on_ptr(
|
||||||
|
pool, builder, mod, cls_nm_set, "__setitem__",
|
||||||
|
obj_val_set, arg_vals_set, 2, self.Trans)
|
||||||
|
setitem_done = 1
|
||||||
|
elif sub_asgn.value.kind() == ast.ASTKind.Attribute:
|
||||||
|
# self._ht[key] = val → self._ht.__setitem__(key, val)
|
||||||
|
# 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__
|
||||||
|
field_ptr_set: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||||||
|
builder, pool, mod, sub_asgn.value, self.Trans)
|
||||||
|
if field_ptr_set is not None and field_ptr_set.Ty is not None:
|
||||||
|
if HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0:
|
||||||
|
field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee
|
||||||
|
if field_pointee_set is not None:
|
||||||
|
cls_nm_attr: str = HandlesStruct.get_class_name_by_type(pool, field_pointee_set)
|
||||||
|
obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set
|
||||||
|
# field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段):
|
||||||
|
# load 解引用获取 Ptr(Struct)
|
||||||
|
if cls_nm_attr is None and HandlesExpr.is_ptr_type(field_pointee_set) != 0:
|
||||||
|
inner_struct_attr: llvmlite.LLVMType | t.CPtr = field_pointee_set.Pointee
|
||||||
|
if inner_struct_attr is not None:
|
||||||
|
cls_nm_attr = HandlesStruct.get_class_name_by_type(pool, inner_struct_attr)
|
||||||
|
if cls_nm_attr is not None:
|
||||||
|
obj_val_attr = llvmlite.build_load(
|
||||||
|
builder, field_pointee_set, field_ptr_set)
|
||||||
|
if cls_nm_attr is not None and obj_val_attr is not None:
|
||||||
|
key_val_attr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||||
|
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||||||
|
if key_val_attr is not None:
|
||||||
|
arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16)
|
||||||
|
if arg_vals_attr is not None:
|
||||||
|
arg_vals_attr[0] = t.CSizeT(key_val_attr)
|
||||||
|
arg_vals_attr[1] = t.CSizeT(rhs_val)
|
||||||
|
HandlesExprCall._call_method_on_ptr(
|
||||||
|
pool, builder, mod, cls_nm_attr, "__setitem__",
|
||||||
|
obj_val_attr, arg_vals_attr, 2, self.Trans)
|
||||||
|
setitem_done = 1
|
||||||
if setitem_done == 0:
|
if setitem_done == 0:
|
||||||
HandlesType.fatal_error(target, "subscript ptr is None")
|
# 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store
|
||||||
|
# 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况
|
||||||
|
if sub_asgn is not None and sub_asgn.value is not None:
|
||||||
|
obj_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||||
|
builder, pool, mod, sub_asgn.value, None, 0, self.Trans)
|
||||||
|
key_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||||
|
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
|
||||||
|
if obj_val_gen is not None and key_val_gen is not None \
|
||||||
|
and obj_val_gen.Ty is not None:
|
||||||
|
# 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数)
|
||||||
|
cls_nm_gen: str = HandlesStruct.get_class_name_by_type(
|
||||||
|
pool, obj_val_gen.Ty)
|
||||||
|
if cls_nm_gen is None and HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0:
|
||||||
|
inner_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
|
||||||
|
if inner_gen is not None:
|
||||||
|
cls_nm_gen = HandlesStruct.get_class_name_by_type(pool, inner_gen)
|
||||||
|
if cls_nm_gen is not None:
|
||||||
|
# 自定义结构体: 调用 __setitem__
|
||||||
|
arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16)
|
||||||
|
if arg_vals_gen is not None:
|
||||||
|
arg_vals_gen[0] = t.CSizeT(key_val_gen)
|
||||||
|
arg_vals_gen[1] = t.CSizeT(rhs_val)
|
||||||
|
HandlesExprCall._call_method_on_ptr(
|
||||||
|
pool, builder, mod, cls_nm_gen, "__setitem__",
|
||||||
|
obj_val_gen, arg_vals_gen, 2, self.Trans)
|
||||||
|
setitem_done = 1
|
||||||
|
else:
|
||||||
|
# 非自定义结构体: 直接 GEP + store
|
||||||
|
# 处理 get_subscript_ptr 因边界情况返回 None 的指针下标
|
||||||
|
if HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0:
|
||||||
|
elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
|
||||||
|
if elem_gen is not None:
|
||||||
|
store_val_gen: llvmlite.Value | t.CPtr = rhs_val
|
||||||
|
elem_ptr_gen: llvmlite.Value | t.CPtr = None
|
||||||
|
match elem_gen:
|
||||||
|
case llvmlite.LLVMType.Array(arr_elem_gen, _):
|
||||||
|
elem_ptr_gen = llvmlite.build_gep_array(
|
||||||
|
builder, elem_gen, arr_elem_gen,
|
||||||
|
obj_val_gen, key_val_gen)
|
||||||
|
case _:
|
||||||
|
elem_ptr_gen = llvmlite.build_gep(
|
||||||
|
builder, elem_gen, obj_val_gen, key_val_gen)
|
||||||
|
if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None:
|
||||||
|
pt_gen: llvmlite.LLVMType | t.CPtr = elem_ptr_gen.Ty.Pointee
|
||||||
|
if pt_gen is not None:
|
||||||
|
store_val_gen = HandlesExpr.coerce_to_type(
|
||||||
|
builder, rhs_val, pt_gen)
|
||||||
|
llvmlite.build_store(builder, store_val_gen, elem_ptr_gen)
|
||||||
|
setitem_done = 1
|
||||||
|
if setitem_done == 0:
|
||||||
|
sub_vk: int = sub_asgn.value.kind()
|
||||||
|
stdio.printf("[ASGN-SUB] fallback failed: val_kind=%d\n", sub_vk)
|
||||||
|
stdio.fflush(0)
|
||||||
|
if setitem_done == 0:
|
||||||
|
HandlesType.fatal_error(target, "subscript ptr is None")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Attribute 赋值: obj.field = val
|
# Attribute 赋值: obj.field = val
|
||||||
@@ -140,14 +249,25 @@ class AssignHandle(HandlesBase.Mixin):
|
|||||||
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||||||
builder, pool, mod, target, self.Trans)
|
builder, pool, mod, target, self.Trans)
|
||||||
if field_ptr is not None:
|
if field_ptr is not None:
|
||||||
|
stdio.printf("[ASGN-ATTR] field_ptr ok ty_not_null=%d\n",
|
||||||
|
1 if field_ptr.Ty is not None else 0)
|
||||||
|
stdio.fflush(0)
|
||||||
# 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64)
|
# 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64)
|
||||||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||||||
if field_ptr.Ty is not None:
|
if field_ptr.Ty is not None:
|
||||||
field_ty: llvmlite.LLVMType | t.CPtr = field_ptr.Ty.Pointee
|
field_ty: llvmlite.LLVMType | t.CPtr = field_ptr.Ty.Pointee
|
||||||
if field_ty is not None:
|
if field_ty is not None:
|
||||||
|
stdio.printf("[ASGN-ATTR] coerce rhs_ty=%d field_ty=%d\n",
|
||||||
|
HandlesExpr.get_llvm_type_bits(rhs_val.Ty),
|
||||||
|
HandlesExpr.get_llvm_type_bits(field_ty))
|
||||||
|
stdio.fflush(0)
|
||||||
store_val = HandlesExpr.coerce_to_type(
|
store_val = HandlesExpr.coerce_to_type(
|
||||||
builder, rhs_val, field_ty)
|
builder, rhs_val, field_ty)
|
||||||
|
stdio.printf("[ASGN-ATTR] pre_store\n")
|
||||||
|
stdio.fflush(0)
|
||||||
llvmlite.build_store(builder, store_val, field_ptr)
|
llvmlite.build_store(builder, store_val, field_ptr)
|
||||||
|
stdio.printf("[ASGN-ATTR] post_store\n")
|
||||||
|
stdio.fflush(0)
|
||||||
else:
|
else:
|
||||||
# 构造详细错误信息
|
# 构造详细错误信息
|
||||||
attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
|
attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
|
||||||
@@ -213,7 +333,10 @@ class AssignHandle(HandlesBase.Mixin):
|
|||||||
if existing is None:
|
if existing is None:
|
||||||
new_vars += 1
|
new_vars += 1
|
||||||
else:
|
else:
|
||||||
stdio.printf("[ASGN] alloca failed for %s\n", nm.id)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "alloca failed for %s", nm.id)
|
||||||
|
VLogger.error(fb, "ASGN")
|
||||||
|
|
||||||
return new_vars
|
return new_vars
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import llvmlite
|
|||||||
import memhub
|
import memhub
|
||||||
import stdio
|
import stdio
|
||||||
import string
|
import string
|
||||||
|
import viperlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
import lib.core.Handles.HandlesBase as HandlesBase
|
import lib.core.Handles.HandlesBase as HandlesBase
|
||||||
import lib.core.Handles.HandlesTranslator as HT
|
import lib.core.Handles.HandlesTranslator as HT
|
||||||
import lib.core.Handles.HandlesVar as HandlesVar
|
import lib.core.Handles.HandlesVar as HandlesVar
|
||||||
@@ -58,7 +60,7 @@ class AugAssignHandle(HandlesBase.Mixin):
|
|||||||
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||||||
builder, pool, mod, target, self.Trans)
|
builder, pool, mod, target, self.Trans)
|
||||||
if field_ptr is None:
|
if field_ptr is None:
|
||||||
stdio.printf("[AUGASGN] attribute ptr is None\n")
|
VLogger.error("attribute ptr is None", "AUGASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 2. 确定字段类型并加载当前值
|
# 2. 确定字段类型并加载当前值
|
||||||
@@ -68,21 +70,24 @@ class AugAssignHandle(HandlesBase.Mixin):
|
|||||||
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||||
builder, target_ty, field_ptr)
|
builder, target_ty, field_ptr)
|
||||||
if cur_val is None:
|
if cur_val is None:
|
||||||
stdio.printf("[AUGASGN] cannot load attribute\n")
|
VLogger.error("cannot load attribute", "AUGASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 3. 翻译 RHS 值
|
# 3. 翻译 RHS 值
|
||||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||||
builder, pool, mod, aug.value, None, 0, self.Trans)
|
builder, pool, mod, aug.value, None, 0, self.Trans)
|
||||||
if rhs_val is None:
|
if rhs_val is None:
|
||||||
stdio.printf("[AUGASGN] rhs is None\n")
|
VLogger.error("rhs is None", "AUGASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 4. 应用二元运算
|
# 4. 应用二元运算
|
||||||
result: llvmlite.Value | t.CPtr = _apply_aug_op(
|
result: llvmlite.Value | t.CPtr = _apply_aug_op(
|
||||||
pool, builder, aug.op, cur_val, rhs_val)
|
pool, builder, aug.op, cur_val, rhs_val)
|
||||||
if result is None:
|
if result is None:
|
||||||
stdio.printf("[AUGASGN] binop failed for attr op=%d\n", aug.op)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "binop failed for attr op=%d", aug.op)
|
||||||
|
VLogger.error(fb, "AUGASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 5. 类型对齐并存储
|
# 5. 类型对齐并存储
|
||||||
@@ -92,8 +97,56 @@ class AugAssignHandle(HandlesBase.Mixin):
|
|||||||
llvmlite.build_store(builder, result, field_ptr)
|
llvmlite.build_store(builder, result, field_ptr)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
# Subscript 目标: self.state[i] += x / arr[i] += x
|
||||||
|
# 流程: get_subscript_ptr → load → binop → store
|
||||||
|
if tk == ast.ASTKind.Subscript:
|
||||||
|
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
|
||||||
|
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
|
||||||
|
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
|
||||||
|
|
||||||
|
# 1. 获取元素指针
|
||||||
|
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
|
||||||
|
builder, pool, mod, target, self.Trans)
|
||||||
|
if elem_ptr is None:
|
||||||
|
VLogger.error("subscript ptr is None", "AUGASGN")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# 2. 确定元素类型并加载当前值
|
||||||
|
target_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||||
|
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||||||
|
target_ty = elem_ptr.Ty.Pointee
|
||||||
|
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||||
|
builder, target_ty, elem_ptr)
|
||||||
|
if cur_val is None:
|
||||||
|
VLogger.error("cannot load subscript element", "AUGASGN")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# 3. 翻译 RHS 值
|
||||||
|
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||||
|
builder, pool, mod, aug.value, None, 0, self.Trans)
|
||||||
|
if rhs_val is None:
|
||||||
|
VLogger.error("rhs is None", "AUGASGN")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# 4. 应用二元运算
|
||||||
|
result: llvmlite.Value | t.CPtr = _apply_aug_op(
|
||||||
|
pool, builder, aug.op, cur_val, rhs_val)
|
||||||
|
if result is None:
|
||||||
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "binop failed for sub op=%d", aug.op)
|
||||||
|
VLogger.error(fb, "AUGASGN")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# 5. 类型对齐并存储
|
||||||
|
result = HandlesExpr.coerce_to_type(builder, result, target_ty)
|
||||||
|
if result is None:
|
||||||
|
return 0
|
||||||
|
llvmlite.build_store(builder, result, elem_ptr)
|
||||||
|
return 0
|
||||||
|
|
||||||
if tk != ast.ASTKind.Name:
|
if tk != ast.ASTKind.Name:
|
||||||
stdio.printf("[AUGASGN] only Name/Attribute target supported\n")
|
VLogger.error("only Name/Attribute/Subscript target supported", "AUGASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||||||
@@ -139,14 +192,17 @@ class AugAssignHandle(HandlesBase.Mixin):
|
|||||||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
|
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
|
||||||
|
|
||||||
if cur_val is None:
|
if cur_val is None:
|
||||||
stdio.printf("[AUGASGN] cannot load target %s\n", nm.id)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "cannot load target %s", nm.id)
|
||||||
|
VLogger.error(fb, "AUGASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 3. 翻译 RHS 值
|
# 3. 翻译 RHS 值
|
||||||
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||||
builder, pool, mod, aug.value, None, 0, self.Trans)
|
builder, pool, mod, aug.value, None, 0, self.Trans)
|
||||||
if rhs_val is None:
|
if rhs_val is None:
|
||||||
stdio.printf("[AUGASGN] rhs is None\n")
|
VLogger.error("rhs is None", "AUGASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 4. 类型对齐 + 应用二元运算
|
# 4. 类型对齐 + 应用二元运算
|
||||||
@@ -154,7 +210,10 @@ class AugAssignHandle(HandlesBase.Mixin):
|
|||||||
result: llvmlite.Value | t.CPtr = _apply_aug_op(
|
result: llvmlite.Value | t.CPtr = _apply_aug_op(
|
||||||
pool, builder, aug.op, cur_val, rhs_val)
|
pool, builder, aug.op, cur_val, rhs_val)
|
||||||
if result is None:
|
if result is None:
|
||||||
stdio.printf("[AUGASGN] binop failed for op=%d\n", aug.op)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "binop failed for op=%d", aug.op)
|
||||||
|
VLogger.error(fb, "AUGASGN")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 5. 存储结果
|
# 5. 存储结果
|
||||||
@@ -226,6 +285,8 @@ def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return llvmlite.build_mul(builder, lhs, rhs)
|
return llvmlite.build_mul(builder, lhs, rhs)
|
||||||
elif op == ast.OpKind.Div:
|
elif op == ast.OpKind.Div:
|
||||||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||||
|
elif op == ast.OpKind.FloorDiv:
|
||||||
|
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||||
elif op == ast.OpKind.Mod:
|
elif op == ast.OpKind.Mod:
|
||||||
return llvmlite.build_srem(builder, lhs, rhs)
|
return llvmlite.build_srem(builder, lhs, rhs)
|
||||||
elif op == ast.OpKind.BitAnd:
|
elif op == ast.OpKind.BitAnd:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@ import memhub
|
|||||||
import string
|
import string
|
||||||
import llvmlite
|
import llvmlite
|
||||||
import stdio
|
import stdio
|
||||||
|
import viperlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -110,7 +112,10 @@ def register_enum(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return existing
|
return existing
|
||||||
|
|
||||||
if _enum_count >= ENUM_MAX:
|
if _enum_count >= ENUM_MAX:
|
||||||
stdio.printf("[ENUM] table full, cannot register %s\n", name)
|
fb_et: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_et is not None:
|
||||||
|
viperlib.snprintf(fb_et, 1024, "table full, cannot register %s", name)
|
||||||
|
VLogger.error(fb_et, "ENUM")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
entry: EnumEntry | t.CPtr = _get_enum_entry(_enum_count)
|
entry: EnumEntry | t.CPtr = _get_enum_entry(_enum_count)
|
||||||
@@ -151,7 +156,10 @@ def add_enum_member(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return -1
|
return -1
|
||||||
|
|
||||||
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
|
if enum_entry.MemberCount >= ENUM_MEMBER_MAX:
|
||||||
stdio.printf("[ENUM] member table full for %s\n", enum_entry.Name)
|
fb_em: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_em is not None:
|
||||||
|
viperlib.snprintf(fb_em, 1024, "member table full for %s", enum_entry.Name)
|
||||||
|
VLogger.error(fb_em, "ENUM")
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
idx: int = enum_entry.MemberCount
|
idx: int = enum_entry.MemberCount
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -272,6 +272,8 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return llvmlite.build_mul(builder, lhs, rhs)
|
return llvmlite.build_mul(builder, lhs, rhs)
|
||||||
elif op == ast.OpKind.Div:
|
elif op == ast.OpKind.Div:
|
||||||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||||
|
elif op == ast.OpKind.FloorDiv:
|
||||||
|
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||||||
elif op == ast.OpKind.Mod:
|
elif op == ast.OpKind.Mod:
|
||||||
return llvmlite.build_srem(builder, lhs, rhs)
|
return llvmlite.build_srem(builder, lhs, rhs)
|
||||||
elif op == ast.OpKind.BitAnd:
|
elif op == ast.OpKind.BitAnd:
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class ForHandle(HandlesBase.Mixin):
|
|||||||
trans.SymTab, var_name)
|
trans.SymTab, var_name)
|
||||||
new_vars: int = 0
|
new_vars: int = 0
|
||||||
if var_alloca is None:
|
if var_alloca is None:
|
||||||
var_alloca = llvmlite.build_alloca(builder, i32_ty)
|
var_alloca = HandlesVar._alloca_at_entry(builder, i32_ty)
|
||||||
if HandlesVar.define_var(
|
if HandlesVar.define_var(
|
||||||
trans.SymTab, var_name, var_alloca) == 0:
|
trans.SymTab, var_name, var_alloca) == 0:
|
||||||
new_vars = 1
|
new_vars = 1
|
||||||
@@ -294,13 +294,13 @@ class ForHandle(HandlesBase.Mixin):
|
|||||||
trans.SymTab, var_name)
|
trans.SymTab, var_name)
|
||||||
new_vars: int = 0
|
new_vars: int = 0
|
||||||
if var_alloca is None:
|
if var_alloca is None:
|
||||||
var_alloca = llvmlite.build_alloca(builder, elem_ty)
|
var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty)
|
||||||
if HandlesVar.define_var(
|
if HandlesVar.define_var(
|
||||||
trans.SymTab, var_name, var_alloca) == 0:
|
trans.SymTab, var_name, var_alloca) == 0:
|
||||||
new_vars = 1
|
new_vars = 1
|
||||||
|
|
||||||
# 创建隐式 index 变量,初始为 0
|
# 创建隐式 index 变量,初始为 0
|
||||||
idx_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i32_ty)
|
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty)
|
||||||
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
|
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
|
||||||
|
|
||||||
# 创建基本块: cond / body / incr / end
|
# 创建基本块: cond / body / incr / end
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import string
|
|||||||
import viperlib
|
import viperlib
|
||||||
import stdio
|
import stdio
|
||||||
import stdlib
|
import stdlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
import lib.core.Handles.HandlesTranslator as HT
|
import lib.core.Handles.HandlesTranslator as HT
|
||||||
import lib.core.Handles.HandlesVar as HandlesVar
|
import lib.core.Handles.HandlesVar as HandlesVar
|
||||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||||
@@ -17,6 +18,10 @@ import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
|||||||
import lib.core.Handles.HandlesImports as HandlesImports
|
import lib.core.Handles.HandlesImports as HandlesImports
|
||||||
|
|
||||||
|
|
||||||
|
# 作用域类型常量(本地副本,避免旧编译器跨模块 CDefine 查找 bug)
|
||||||
|
SCOPE_FUNCTION: t.CDefine = 1
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性
|
# extract_func_attrs - 从 decorator_list 提取 c.Attribute 属性
|
||||||
#
|
#
|
||||||
@@ -311,7 +316,7 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr,
|
|||||||
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||||
if fd.returns is not None:
|
if fd.returns is not None:
|
||||||
ret_ty = HandlesType.resolve_annotation_type(
|
ret_ty = HandlesType.resolve_annotation_type(
|
||||||
pool, fd.returns, imported_modules, from_imports)
|
pool, fd.returns, imported_modules, from_imports, trans)
|
||||||
if ret_ty is None and fd.returns is not None:
|
if ret_ty is None and fd.returns is not None:
|
||||||
if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
|
if HandlesType.has_decorator_marker(fd.returns, "State") != 0:
|
||||||
ret_ty = llvmlite.Void(pool)
|
ret_ty = llvmlite.Void(pool)
|
||||||
@@ -347,10 +352,24 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr,
|
|||||||
if func is None:
|
if func is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# 提取默认参数信息
|
||||||
|
fd_args_node: ast.Arguments | t.CPtr = fd.args
|
||||||
|
fd_defaults: t.CVoid | t.CPtr = None
|
||||||
|
fd_default_count: int = 0
|
||||||
|
fd_param_count: int = 0
|
||||||
|
if fd_args_node is not None:
|
||||||
|
fd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_args_node)
|
||||||
|
if fd_ags.args is not None:
|
||||||
|
fd_param_count = fd_ags.args.__len__()
|
||||||
|
if fd_ags.defaults is not None:
|
||||||
|
fd_defaults = fd_ags.defaults
|
||||||
|
fd_default_count = fd_ags.defaults.__len__()
|
||||||
|
|
||||||
# 注册到函数表(用裸名 fd.name,不是 mangled_name)
|
# 注册到函数表(用裸名 fd.name,不是 mangled_name)
|
||||||
max_funcs: int = 256
|
max_funcs: int = 256
|
||||||
cur_count: int = trans._func_count
|
cur_count: int = trans._func_count
|
||||||
if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs) == 0:
|
if HandlesExprCall.add_func_to_table(funcs_ptr, cur_count, fd.name, func, max_funcs,
|
||||||
|
fd_defaults, fd_default_count, fd_param_count) == 0:
|
||||||
trans._func_count = cur_count + 1
|
trans._func_count = cur_count + 1
|
||||||
|
|
||||||
# 注册 CExport 函数到全局表
|
# 注册 CExport 函数到全局表
|
||||||
@@ -375,7 +394,7 @@ def forward_declare_functions(trans: HT.Translator | t.CPtr,
|
|||||||
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||||
if arg.annotation is not None:
|
if arg.annotation is not None:
|
||||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||||
pool, arg.annotation, imported_modules, from_imports)
|
pool, arg.annotation, imported_modules, from_imports, trans)
|
||||||
if resolved is not None:
|
if resolved is not None:
|
||||||
param_ty = resolved
|
param_ty = resolved
|
||||||
pname: t.CChar | t.CPtr = pool.alloc(32)
|
pname: t.CChar | t.CPtr = pool.alloc(32)
|
||||||
@@ -412,7 +431,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||||
if fd.returns is not None:
|
if fd.returns is not None:
|
||||||
ret_ty = HandlesType.resolve_annotation_type(
|
ret_ty = HandlesType.resolve_annotation_type(
|
||||||
pool, fd.returns, imported_modules, from_imports)
|
pool, fd.returns, imported_modules, from_imports, trans)
|
||||||
|
|
||||||
# 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void
|
# 如果返回类型注解纯装饰器标记(如 t.State,无实际类型),使用 void
|
||||||
# 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32
|
# 注意:必须在 infer_return_type 之前检测,因为 infer_return_type 至少返回 i32
|
||||||
@@ -490,7 +509,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty
|
param_ty_e: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||||
if arg_e.annotation is not None:
|
if arg_e.annotation is not None:
|
||||||
resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
resolved_e: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||||
pool, arg_e.annotation, imported_modules, from_imports)
|
pool, arg_e.annotation, imported_modules, from_imports, trans)
|
||||||
if resolved_e is not None:
|
if resolved_e is not None:
|
||||||
param_ty_e = resolved_e
|
param_ty_e = resolved_e
|
||||||
pname_e: t.CChar | t.CPtr = pool.alloc(32)
|
pname_e: t.CChar | t.CPtr = pool.alloc(32)
|
||||||
@@ -521,7 +540,10 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
|
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
|
||||||
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
|
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
|
||||||
if func is None:
|
if func is None:
|
||||||
stdio.printf("[FUNC] create_function %s failed\n", fd.name)
|
fb_cf: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_cf is not None:
|
||||||
|
viperlib.snprintf(fb_cf, 1024, "create_function %s failed", fd.name)
|
||||||
|
VLogger.error(fb_cf, "FUNC")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 提取 @c.Attribute 装饰器属性并设置到函数
|
# 提取 @c.Attribute 装饰器属性并设置到函数
|
||||||
@@ -529,9 +551,22 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
if func_attrs is not None:
|
if func_attrs is not None:
|
||||||
llvmlite.function_set_attrs(func, func_attrs)
|
llvmlite.function_set_attrs(func, func_attrs)
|
||||||
|
|
||||||
|
# 提取默认参数信息
|
||||||
|
tfd_defaults: t.CVoid | t.CPtr = None
|
||||||
|
tfd_default_count: int = 0
|
||||||
|
tfd_param_count: int = 0
|
||||||
|
if args_node is not None:
|
||||||
|
tfd_ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
|
||||||
|
if tfd_ags.args is not None:
|
||||||
|
tfd_param_count = tfd_ags.args.__len__()
|
||||||
|
if tfd_ags.defaults is not None:
|
||||||
|
tfd_defaults = tfd_ags.defaults
|
||||||
|
tfd_default_count = tfd_ags.defaults.__len__()
|
||||||
|
|
||||||
# 注册到函数表
|
# 注册到函数表
|
||||||
max_funcs: int = 256
|
max_funcs: int = 256
|
||||||
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs) == 0:
|
if HandlesExprCall.add_func_to_table(funcs_ptr, func_count, fd.name, func, max_funcs,
|
||||||
|
tfd_defaults, tfd_default_count, tfd_param_count) == 0:
|
||||||
trans._func_count = func_count + 1
|
trans._func_count = func_count + 1
|
||||||
|
|
||||||
# 添加参数(支持类型注解)
|
# 添加参数(支持类型注解)
|
||||||
@@ -550,7 +585,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||||
if arg.annotation is not None:
|
if arg.annotation is not None:
|
||||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||||
pool, arg.annotation, imported_modules, from_imports)
|
pool, arg.annotation, imported_modules, from_imports, trans)
|
||||||
if resolved is not None:
|
if resolved is not None:
|
||||||
param_ty = resolved
|
param_ty = resolved
|
||||||
pname: t.CChar | t.CPtr = pool.alloc(32)
|
pname: t.CChar | t.CPtr = pool.alloc(32)
|
||||||
@@ -569,7 +604,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
llvmlite.position_at_end(func_builder, entry_blk)
|
llvmlite.position_at_end(func_builder, entry_blk)
|
||||||
|
|
||||||
# 进入函数作用域(嵌套符号表)
|
# 进入函数作用域(嵌套符号表)
|
||||||
HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION)
|
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
|
||||||
|
|
||||||
# 为参数创建 alloca
|
# 为参数创建 alloca
|
||||||
if args_node is not None:
|
if args_node is not None:
|
||||||
@@ -587,7 +622,7 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty
|
param_ty2: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||||
if arg2.annotation is not None:
|
if arg2.annotation is not None:
|
||||||
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
resolved2: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||||
pool, arg2.annotation, imported_modules, from_imports)
|
pool, arg2.annotation, imported_modules, from_imports, trans)
|
||||||
if resolved2 is not None:
|
if resolved2 is not None:
|
||||||
param_ty2 = resolved2
|
param_ty2 = resolved2
|
||||||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
|
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, param_ty2)
|
||||||
@@ -633,6 +668,8 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
for bi2 in range(bn2):
|
for bi2 in range(bn2):
|
||||||
stmt2: ast.AST | t.CPtr = body.get(bi2)
|
stmt2: ast.AST | t.CPtr = body.get(bi2)
|
||||||
if stmt2 is not None:
|
if stmt2 is not None:
|
||||||
|
stdio.printf("[DBG] TR body stmt=%d kind=%d\n", bi2, stmt2.kind())
|
||||||
|
stdio.fflush(0)
|
||||||
HandlesBody.translate_stmt(trans, stmt2)
|
HandlesBody.translate_stmt(trans, stmt2)
|
||||||
|
|
||||||
# 如果函数体最后一条语句不是 Return,添加隐式 ret
|
# 如果函数体最后一条语句不是 Return,添加隐式 ret
|
||||||
@@ -644,8 +681,24 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
|
if last_stmt is not None and last_stmt.kind() == ast.ASTKind.Return:
|
||||||
last_is_return = 1
|
last_is_return = 1
|
||||||
if last_is_return == 0:
|
if last_is_return == 0:
|
||||||
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
if llvmlite.builder_cur_block_is_terminated(func_builder) == 0:
|
||||||
llvmlite.build_ret(func_builder, zero_val)
|
# 根据返回类型生成正确的零值返回
|
||||||
|
_is_void: int = 0
|
||||||
|
_is_ptr: int = 0
|
||||||
|
if ret_ty is not None:
|
||||||
|
match ret_ty:
|
||||||
|
case llvmlite.LLVMType.Void():
|
||||||
|
_is_void = 1
|
||||||
|
case llvmlite.LLVMType.Ptr(_pe):
|
||||||
|
_is_ptr = 1
|
||||||
|
if _is_void != 0:
|
||||||
|
llvmlite.build_ret_void(func_builder)
|
||||||
|
elif _is_ptr != 0:
|
||||||
|
_null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
|
||||||
|
llvmlite.build_ret(func_builder, _null_val)
|
||||||
|
else:
|
||||||
|
_zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||||
|
llvmlite.build_ret(func_builder, _zero_val)
|
||||||
|
|
||||||
# 恢复模块级作用域(退出函数作用域)
|
# 恢复模块级作用域(退出函数作用域)
|
||||||
HandlesVar.exit_scope(trans.SymTab)
|
HandlesVar.exit_scope(trans.SymTab)
|
||||||
@@ -706,7 +759,7 @@ def translate_nested_function_def(trans: HT.Translator | t.CPtr,
|
|||||||
llvmlite.position_at_end(func_builder, entry_blk)
|
llvmlite.position_at_end(func_builder, entry_blk)
|
||||||
|
|
||||||
# 4. 进入嵌套函数作用域(嵌套符号表)
|
# 4. 进入嵌套函数作用域(嵌套符号表)
|
||||||
HandlesVar.enter_scope(trans.SymTab, HandlesVar.SCOPE_FUNCTION)
|
HandlesVar.enter_scope(trans.SymTab, SCOPE_FUNCTION)
|
||||||
|
|
||||||
# 5. 创建 _env_ptr alloca 并存储 %env 参数
|
# 5. 创建 _env_ptr alloca 并存储 %env 参数
|
||||||
env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty)
|
env_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(func_builder, i8_ptr_ty)
|
||||||
@@ -927,7 +980,7 @@ def create_function(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
param_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||||||
if arg.annotation is not None:
|
if arg.annotation is not None:
|
||||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||||
pool, arg.annotation, None, None)
|
pool, arg.annotation, None, None, None)
|
||||||
if resolved is not None:
|
if resolved is not None:
|
||||||
param_ty = resolved
|
param_ty = resolved
|
||||||
pname: t.CChar | t.CPtr = pool.alloc(32)
|
pname: t.CChar | t.CPtr = pool.alloc(32)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from stdint import *
|
|||||||
import ast
|
import ast
|
||||||
import memhub
|
import memhub
|
||||||
import string
|
import string
|
||||||
|
import stdlib
|
||||||
import viperlib
|
import viperlib
|
||||||
import stdio
|
import stdio
|
||||||
import lib.core.Handles.HandlesBase as HandlesBase
|
import lib.core.Handles.HandlesBase as HandlesBase
|
||||||
@@ -88,14 +89,24 @@ def is_module_imported(imported_modules: str, name: str) -> int:
|
|||||||
def add_from_import(pool: memhub.MemBuddy | t.CPtr,
|
def add_from_import(pool: memhub.MemBuddy | t.CPtr,
|
||||||
from_imports: str,
|
from_imports: str,
|
||||||
local_name: str,
|
local_name: str,
|
||||||
module_name: str) -> str:
|
module_name: str,
|
||||||
"""添加 from-import 映射 "name:module",返回新的 from_imports 字符串"""
|
original_name: str = None) -> str:
|
||||||
|
"""添加 from-import 映射,返回新的 from_imports 字符串
|
||||||
|
|
||||||
|
格式:
|
||||||
|
无别名: "local_name:module_name"
|
||||||
|
有别名: "local_name:module_name:original_name"
|
||||||
|
(original_name 为源模块中的真实函数名,用于跨模块 SHA1 修饰)
|
||||||
|
"""
|
||||||
if local_name is None or module_name is None:
|
if local_name is None or module_name is None:
|
||||||
return from_imports
|
return from_imports
|
||||||
entry: t.CChar | t.CPtr = pool.alloc(128)
|
entry: t.CChar | t.CPtr = pool.alloc(256)
|
||||||
if entry is None:
|
if entry is None:
|
||||||
return from_imports
|
return from_imports
|
||||||
viperlib.snprintf(entry, 128, "%s:%s", local_name, module_name)
|
if original_name is not None and original_name != local_name:
|
||||||
|
viperlib.snprintf(entry, 256, "%s:%s:%s", local_name, module_name, original_name)
|
||||||
|
else:
|
||||||
|
viperlib.snprintf(entry, 256, "%s:%s", local_name, module_name)
|
||||||
if from_imports is None:
|
if from_imports is None:
|
||||||
return entry
|
return entry
|
||||||
else:
|
else:
|
||||||
@@ -111,6 +122,75 @@ def add_from_import(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return from_imports
|
return from_imports
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 查找 from-import 名称 → 返回原始函数名(别名场景)
|
||||||
|
#
|
||||||
|
# 对于 from X import Y as Z,返回 Y(源模块中的真实函数名)。
|
||||||
|
# 无别名时返回 None(local_name 即为原始名)。
|
||||||
|
# ============================================================
|
||||||
|
def lookup_from_import_original(from_imports: str,
|
||||||
|
local_name: str) -> str:
|
||||||
|
"""查找 from-import 别名对应的原始函数名,返回 None=无别名或未找到"""
|
||||||
|
if local_name is None or from_imports is None:
|
||||||
|
return None
|
||||||
|
name_len: t.CSizeT = string.strlen(local_name)
|
||||||
|
cur: t.CChar | t.CPtr = from_imports
|
||||||
|
ci: t.CSizeT = 0
|
||||||
|
total_len: t.CSizeT = string.strlen(from_imports)
|
||||||
|
while ci < total_len:
|
||||||
|
# 跳过前导空格
|
||||||
|
while ci < total_len and cur[ci] == ' ':
|
||||||
|
ci += 1
|
||||||
|
if ci >= total_len:
|
||||||
|
break
|
||||||
|
# 找到第一个 ':' 的位置
|
||||||
|
colon1: t.CSizeT = ci
|
||||||
|
while colon1 < total_len and cur[colon1] != ':' and cur[colon1] != ' ':
|
||||||
|
colon1 += 1
|
||||||
|
if colon1 >= total_len or cur[colon1] != ':':
|
||||||
|
break
|
||||||
|
entry_name_len: t.CSizeT = colon1 - ci
|
||||||
|
# 跳过 star import
|
||||||
|
if entry_name_len == 1 and cur[ci] == '*':
|
||||||
|
ci = colon1
|
||||||
|
while ci < total_len and cur[ci] != ' ':
|
||||||
|
ci += 1
|
||||||
|
continue
|
||||||
|
# 比较名称
|
||||||
|
if entry_name_len == name_len:
|
||||||
|
match: int = 1
|
||||||
|
ei: t.CSizeT = 0
|
||||||
|
while ei < name_len:
|
||||||
|
if cur[ci + ei] != local_name[ei]:
|
||||||
|
match = 0
|
||||||
|
break
|
||||||
|
ei += 1
|
||||||
|
if match == 1:
|
||||||
|
# 找到匹配,检查是否有第三个字段(原始名)
|
||||||
|
pos: t.CSizeT = colon1 + 1
|
||||||
|
# 跳过模块名
|
||||||
|
while pos < total_len and cur[pos] != ':' and cur[pos] != ' ' and cur[pos] != '\0':
|
||||||
|
pos += 1
|
||||||
|
if pos < total_len and cur[pos] == ':':
|
||||||
|
# 有第三个字段: original_name
|
||||||
|
orig_start: t.CSizeT = pos + 1
|
||||||
|
orig_end: t.CSizeT = orig_start
|
||||||
|
while orig_end < total_len and cur[orig_end] != ' ' and cur[orig_end] != '\0':
|
||||||
|
orig_end += 1
|
||||||
|
orig_len: t.CSizeT = orig_end - orig_start
|
||||||
|
if orig_len > 0:
|
||||||
|
orig_buf: str = cur + orig_start
|
||||||
|
# 返回指向内部的指针(调用方需在使用期内保持 from_imports 有效)
|
||||||
|
return orig_buf
|
||||||
|
return None
|
||||||
|
return None
|
||||||
|
# 跳到下一个条目
|
||||||
|
ci = colon1
|
||||||
|
while ci < total_len and cur[ci] != ' ':
|
||||||
|
ci += 1
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 查找 from-import 名称 → 返回模块名或 None
|
# 查找 from-import 名称 → 返回模块名或 None
|
||||||
#
|
#
|
||||||
@@ -150,7 +230,7 @@ def lookup_from_import(from_imports: str, name: str,
|
|||||||
if entry_name_len == 1 and cur[ci] == '*':
|
if entry_name_len == 1 and cur[ci] == '*':
|
||||||
mod_start: t.CSizeT = colon_pos + 1
|
mod_start: t.CSizeT = colon_pos + 1
|
||||||
mod_end: t.CSizeT = mod_start
|
mod_end: t.CSizeT = mod_start
|
||||||
while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0':
|
while mod_end < total_len and cur[mod_end] != ' ' and cur[mod_end] != '\0' and cur[mod_end] != ':':
|
||||||
mod_end += 1
|
mod_end += 1
|
||||||
star_mod = cur + mod_start
|
star_mod = cur + mod_start
|
||||||
# 比较名称
|
# 比较名称
|
||||||
@@ -165,7 +245,8 @@ def lookup_from_import(from_imports: str, name: str,
|
|||||||
if match == 1:
|
if match == 1:
|
||||||
mod_start2: t.CSizeT = colon_pos + 1
|
mod_start2: t.CSizeT = colon_pos + 1
|
||||||
mod_end2: t.CSizeT = mod_start2
|
mod_end2: t.CSizeT = mod_start2
|
||||||
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0':
|
# 模块名结束于: 空格、null、或第二个':'(别名格式的分隔符)
|
||||||
|
while mod_end2 < total_len and cur[mod_end2] != ' ' and cur[mod_end2] != '\0' and cur[mod_end2] != ':':
|
||||||
mod_end2 += 1
|
mod_end2 += 1
|
||||||
return cur + mod_start2
|
return cur + mod_start2
|
||||||
# 跳到下一个条目
|
# 跳到下一个条目
|
||||||
@@ -178,6 +259,93 @@ def lookup_from_import(from_imports: str, name: str,
|
|||||||
return star_mod
|
return star_mod
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 全局 re-export 映射表(module_sha1 + func_name → source_module)
|
||||||
|
#
|
||||||
|
# 当 ast/__init__.py 中有 from .lexer import _lexer_init 时,
|
||||||
|
# _lexer_init 被 re-export 为 ast._lexer_init。
|
||||||
|
# 跨模块调用 ast._lexer_init(...) 需使用 ast.lexer 的 SHA1 混淆,
|
||||||
|
# 而非 ast 的 SHA1。
|
||||||
|
#
|
||||||
|
# 数据布局:
|
||||||
|
# _g_reexport_sha1s: 每条 17 字节(SHA1 16字符 + null)
|
||||||
|
# _g_reexport_funcs: 每条 64 字节(函数名 + null)
|
||||||
|
# _g_reexport_srcs: 每条 64 字节(源模块名 + null)
|
||||||
|
# ============================================================
|
||||||
|
MAX_REEXPORT: t.CDefine = 512
|
||||||
|
|
||||||
|
_g_reexport_sha1s: bytes = None
|
||||||
|
_g_reexport_funcs: bytes = None
|
||||||
|
_g_reexport_srcs: bytes = None
|
||||||
|
_g_reexport_count: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# register_reexport - 注册 re-export 映射
|
||||||
|
#
|
||||||
|
# 在 HandleImportFromNames 中调用:当处理 from .X import Y 时,
|
||||||
|
# 记录当前模块(通过 ModuleSha1)re-export 了函数 Y,源模块为 X。
|
||||||
|
#
|
||||||
|
# 幂等:重复注册相同映射不会增加条目。
|
||||||
|
# 内存用 stdlib.malloc 分配(全局存储器,跨 Phase 持久化)。
|
||||||
|
# ============================================================
|
||||||
|
def register_reexport(mod_sha1: str, func_name: str, source_module: str) -> int:
|
||||||
|
"""注册 re-export 映射(幂等),返回 0 成功,-1 失败"""
|
||||||
|
global _g_reexport_sha1s, _g_reexport_funcs, _g_reexport_srcs, _g_reexport_count
|
||||||
|
if mod_sha1 is None or func_name is None or source_module is None:
|
||||||
|
return -1
|
||||||
|
# 懒初始化
|
||||||
|
if _g_reexport_sha1s is None:
|
||||||
|
_g_reexport_sha1s = stdlib.malloc(MAX_REEXPORT * 17)
|
||||||
|
_g_reexport_funcs = stdlib.malloc(MAX_REEXPORT * 64)
|
||||||
|
_g_reexport_srcs = stdlib.malloc(MAX_REEXPORT * 64)
|
||||||
|
if _g_reexport_sha1s is None or _g_reexport_funcs is None or _g_reexport_srcs is None:
|
||||||
|
return -1
|
||||||
|
string.memset(_g_reexport_sha1s, 0, MAX_REEXPORT * 17)
|
||||||
|
string.memset(_g_reexport_funcs, 0, MAX_REEXPORT * 64)
|
||||||
|
string.memset(_g_reexport_srcs, 0, MAX_REEXPORT * 64)
|
||||||
|
if _g_reexport_count >= MAX_REEXPORT:
|
||||||
|
return -1
|
||||||
|
# 幂等检查:查找是否已存在相同映射
|
||||||
|
for i in range(_g_reexport_count):
|
||||||
|
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||||
|
fidx: t.CSizeT = t.CSizeT(i) * 64
|
||||||
|
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
|
||||||
|
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
|
||||||
|
# 已存在,更新 source_module(以防变化)
|
||||||
|
string.strcpy(_g_reexport_srcs + fidx, source_module)
|
||||||
|
return 0
|
||||||
|
# 添加新条目
|
||||||
|
idx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 17
|
||||||
|
fidx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 64
|
||||||
|
string.strcpy(_g_reexport_sha1s + idx2, mod_sha1)
|
||||||
|
string.strcpy(_g_reexport_funcs + fidx2, func_name)
|
||||||
|
string.strcpy(_g_reexport_srcs + fidx2, source_module)
|
||||||
|
_g_reexport_count += 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# lookup_reexport - 查找 re-export 映射
|
||||||
|
#
|
||||||
|
# 给定模块 SHA1 和函数名,返回源模块名(如 "ast.lexer")或 None。
|
||||||
|
# 调用方通过 _lookup_module_sha1(source_module) 获取源模块的 SHA1。
|
||||||
|
# ============================================================
|
||||||
|
def lookup_reexport(mod_sha1: str, func_name: str) -> str:
|
||||||
|
"""查找 re-export 映射,返回源模块名或 None"""
|
||||||
|
if mod_sha1 is None or func_name is None:
|
||||||
|
return None
|
||||||
|
if _g_reexport_sha1s is None or _g_reexport_count <= 0:
|
||||||
|
return None
|
||||||
|
for i in range(_g_reexport_count):
|
||||||
|
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||||
|
fidx: t.CSizeT = t.CSizeT(i) * 64
|
||||||
|
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
|
||||||
|
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
|
||||||
|
return _g_reexport_srcs + fidx
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# _resolve_relative_module - 解析相对导入为完整模块名
|
# _resolve_relative_module - 解析相对导入为完整模块名
|
||||||
#
|
#
|
||||||
@@ -335,6 +503,24 @@ class ImportsHandle(HandlesBase.Mixin):
|
|||||||
if alias.asname is not None:
|
if alias.asname is not None:
|
||||||
self.Trans._imported_modules = add_imported_module(
|
self.Trans._imported_modules = add_imported_module(
|
||||||
pool_val, self.Trans._imported_modules, alias.asname)
|
pool_val, self.Trans._imported_modules, alias.asname)
|
||||||
|
# 别名也加入 from_imports(asname:fullname),
|
||||||
|
# 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1
|
||||||
|
# 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator)
|
||||||
|
self.Trans._from_imports = add_from_import(
|
||||||
|
pool_val, self.Trans._from_imports, alias.asname, alias.name)
|
||||||
|
else:
|
||||||
|
# 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules,
|
||||||
|
# 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查
|
||||||
|
dot_ptr: str = string.strstr(alias.name, '.')
|
||||||
|
if dot_ptr is not None:
|
||||||
|
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name))
|
||||||
|
if pkg_len > 0 and pkg_len < 256:
|
||||||
|
pkg_buf: bytes = pool_val.alloc(pkg_len + 1)
|
||||||
|
if pkg_buf is not None:
|
||||||
|
string.strncpy(pkg_buf, alias.name, pkg_len)
|
||||||
|
pkg_buf[pkg_len] = '\0'
|
||||||
|
self.Trans._imported_modules = add_imported_module(
|
||||||
|
pool_val, self.Trans._imported_modules, pkg_buf)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -381,13 +567,19 @@ class ImportsHandle(HandlesBase.Mixin):
|
|||||||
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
|
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
|
||||||
if alias is not None and alias.name is not None:
|
if alias is not None and alias.name is not None:
|
||||||
local_name: str = alias.name
|
local_name: str = alias.name
|
||||||
|
orig_name: str = None
|
||||||
if alias.asname is not None:
|
if alias.asname is not None:
|
||||||
local_name = alias.asname
|
local_name = alias.asname
|
||||||
|
orig_name = alias.name
|
||||||
self.Trans._from_imports = add_from_import(
|
self.Trans._from_imports = add_from_import(
|
||||||
self.Trans.Pool, self.Trans._from_imports,
|
self.Trans.Pool, self.Trans._from_imports,
|
||||||
local_name, resolved)
|
local_name, resolved, orig_name)
|
||||||
# 命名空间隔离:from-import 的名称标记为可见结构体
|
# 命名空间隔离:from-import 的名称标记为可见结构体
|
||||||
HandlesStruct.add_visible_struct(self.Trans.Pool, local_name)
|
HandlesStruct.add_visible_struct(self.Trans.Pool, local_name)
|
||||||
|
# 注册 re-export 映射:当前模块 re-export 了 local_name,源模块为 resolved
|
||||||
|
# 使跨模块调用 module.func() 能解析到正确的源模块 SHA1
|
||||||
|
if self.Trans.ModuleSha1 is not None:
|
||||||
|
register_reexport(self.Trans.ModuleSha1, local_name, resolved)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import memhub
|
|||||||
import string
|
import string
|
||||||
import stdio
|
import stdio
|
||||||
import viperlib
|
import viperlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
import lib.core.Handles.HandlesTranslator as HT
|
import lib.core.Handles.HandlesTranslator as HT
|
||||||
import lib.core.Handles.HandlesVar as HandlesVar
|
import lib.core.Handles.HandlesVar as HandlesVar
|
||||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||||
@@ -96,6 +97,10 @@ def translate_children(trans: HT.Translator | t.CPtr,
|
|||||||
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
|
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
|
||||||
# Phase 1b 全量翻译:正常翻译函数体
|
# Phase 1b 全量翻译:正常翻译函数体
|
||||||
if trans._declare_only == 0:
|
if trans._declare_only == 0:
|
||||||
|
fd_dbg: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||||||
|
if fd_dbg is not None and fd_dbg.name is not None:
|
||||||
|
stdio.printf("[DBG] TR func=%s\n", fd_dbg.name)
|
||||||
|
stdio.fflush(0)
|
||||||
added: int = HandlesFunctions.translate_function_def(trans, child)
|
added: int = HandlesFunctions.translate_function_def(trans, child)
|
||||||
added_total += added
|
added_total += added
|
||||||
elif trans._declare_only == 1:
|
elif trans._declare_only == 1:
|
||||||
@@ -104,6 +109,10 @@ def translate_children(trans: HT.Translator | t.CPtr,
|
|||||||
# ClassDef 在模块级直接处理(不需要 builder)
|
# ClassDef 在模块级直接处理(不需要 builder)
|
||||||
# _declare_only=2(import扫描模式)时跳过,只处理 import 依赖
|
# _declare_only=2(import扫描模式)时跳过,只处理 import 依赖
|
||||||
if trans._declare_only != 2:
|
if trans._declare_only != 2:
|
||||||
|
cd_dbg: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
|
||||||
|
if cd_dbg is not None and cd_dbg.name is not None:
|
||||||
|
stdio.printf("[DBG] TR class=%s\n", cd_dbg.name)
|
||||||
|
stdio.fflush(0)
|
||||||
HandlesClassDef.translate_class_def(trans, child)
|
HandlesClassDef.translate_class_def(trans, child)
|
||||||
elif trans._declare_only == 0 and trans._cur_builder is not None:
|
elif trans._declare_only == 0 and trans._cur_builder is not None:
|
||||||
# 有 builder → 委托 HandlesBody 分派
|
# 有 builder → 委托 HandlesBody 分派
|
||||||
@@ -171,7 +180,7 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
|
|||||||
# 解析类型
|
# 解析类型
|
||||||
if aa.annotation is not None:
|
if aa.annotation is not None:
|
||||||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||||||
pool, aa.annotation, trans._imported_modules, trans._from_imports)
|
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans)
|
||||||
if resolved is not None:
|
if resolved is not None:
|
||||||
var_ty = resolved
|
var_ty = resolved
|
||||||
# 解析初始值
|
# 解析初始值
|
||||||
@@ -208,6 +217,11 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
# 创建全局变量 @var_name
|
# 创建全局变量 @var_name
|
||||||
|
# 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明
|
||||||
|
# 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报
|
||||||
|
# "use of undefined type named 'sha1.ClassName'" 错误
|
||||||
|
# (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager")))
|
||||||
|
llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty)
|
||||||
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, var_name, var_ty)
|
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, var_name, var_ty)
|
||||||
if gv is None:
|
if gv is None:
|
||||||
return 0
|
return 0
|
||||||
@@ -221,7 +235,9 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
|
|||||||
viperlib.snprintf(init_buf, 48, "%lld", init_val)
|
viperlib.snprintf(init_buf, 48, "%lld", init_val)
|
||||||
gv.Initializer = init_buf
|
gv.Initializer = init_buf
|
||||||
else:
|
else:
|
||||||
gv.Initializer = "0"
|
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
|
||||||
|
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
|
||||||
|
gv.Initializer = "zeroinitializer"
|
||||||
|
|
||||||
# 创建 Value 引用(@var_name, 类型为 var_ty*)
|
# 创建 Value 引用(@var_name, 类型为 var_ty*)
|
||||||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||||||
@@ -232,6 +248,16 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
|
|||||||
|
|
||||||
# 注册到模块作用域
|
# 注册到模块作用域
|
||||||
if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
|
if HandlesVar.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
|
||||||
|
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
|
||||||
|
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
|
||||||
|
if k == ast.ASTKind.AnnAssign:
|
||||||
|
aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||||||
|
if aa_ml is not None and aa_ml.annotation is not None:
|
||||||
|
cls_nm_ml: str = HandlesType.extract_class_name_from_annotation(
|
||||||
|
aa_ml.annotation, trans._imported_modules)
|
||||||
|
if cls_nm_ml is not None:
|
||||||
|
HandlesVar.set_var_annot_class_name(
|
||||||
|
trans.SymTab, var_name, cls_nm_ml)
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -262,18 +288,18 @@ def create_wrapper_main(trans: HT.Translator | t.CPtr,
|
|||||||
main_func: llvmlite.Function | t.CPtr = llvmlite.create_function(
|
main_func: llvmlite.Function | t.CPtr = llvmlite.create_function(
|
||||||
pool, mod, "main", i32_ty)
|
pool, mod, "main", i32_ty)
|
||||||
if main_func is None:
|
if main_func is None:
|
||||||
stdio.printf("[TR] CreateFunction main returned NULL\n")
|
VLogger.error("CreateFunction main returned NULL", "TR")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||||||
pool, main_func, "entry")
|
pool, main_func, "entry")
|
||||||
if entry_blk is None:
|
if entry_blk is None:
|
||||||
stdio.printf("[TR] CreateBlock returned NULL\n")
|
VLogger.error("CreateBlock returned NULL", "TR")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
|
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
|
||||||
if builder is None:
|
if builder is None:
|
||||||
stdio.printf("[TR] NewBuilder returned NULL\n")
|
VLogger.error("NewBuilder returned NULL", "TR")
|
||||||
return 0
|
return 0
|
||||||
llvmlite.position_at_end(builder, entry_blk)
|
llvmlite.position_at_end(builder, entry_blk)
|
||||||
|
|
||||||
|
|||||||
@@ -55,31 +55,47 @@ class ReturnHandle(HandlesBase.Mixin):
|
|||||||
self.Trans._funcs, self.Trans._func_count, self.Trans)
|
self.Trans._funcs, self.Trans._func_count, self.Trans)
|
||||||
|
|
||||||
# val 为 None 时(裸 return):检查当前函数返回类型
|
# val 为 None 时(裸 return):检查当前函数返回类型
|
||||||
# void 函数(如 __init__/__before_init__)生成 ret void,否则 ret i32 0
|
# void 函数(如 __init__/__before_init__)生成 ret void,
|
||||||
|
# ptr 函数生成 ret ptr null,否则 ret i32 0
|
||||||
if val is None:
|
if val is None:
|
||||||
cur_func: llvmlite.Function | t.CPtr = self.Trans._cur_func
|
cur_func: llvmlite.Function | t.CPtr = self.Trans._cur_func
|
||||||
is_void_ret: int = 0
|
is_void_ret: int = 0
|
||||||
|
is_ptr_ret: int = 0
|
||||||
|
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||||
if cur_func is not None:
|
if cur_func is not None:
|
||||||
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func)
|
ret_ty = llvmlite.function_get_ret_ty(cur_func)
|
||||||
if ret_ty is not None:
|
if ret_ty is not None:
|
||||||
match ret_ty:
|
match ret_ty:
|
||||||
case llvmlite.LLVMType.Void():
|
case llvmlite.LLVMType.Void():
|
||||||
is_void_ret = 1
|
is_void_ret = 1
|
||||||
|
case llvmlite.LLVMType.Ptr(_pe):
|
||||||
|
is_ptr_ret = 1
|
||||||
if is_void_ret != 0:
|
if is_void_ret != 0:
|
||||||
llvmlite.build_ret_void(builder)
|
llvmlite.build_ret_void(builder)
|
||||||
return 0
|
return 0
|
||||||
|
if is_ptr_ret != 0:
|
||||||
|
null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
|
||||||
|
llvmlite.build_ret(builder, null_val)
|
||||||
|
return 0
|
||||||
val = llvmlite.const_int32(pool, 0)
|
val = llvmlite.const_int32(pool, 0)
|
||||||
|
|
||||||
# 类型转换:确保 val 类型与函数返回类型匹配
|
# 类型转换:确保 val 类型与函数返回类型匹配
|
||||||
# 处理 i1(bool 比较结果)→ i8(t.CBool)等情况
|
# 处理 i1(bool 比较结果)→ i8(t.CBool)等情况
|
||||||
# i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF)
|
# i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF)
|
||||||
|
# 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr),
|
||||||
|
# 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type"
|
||||||
cur_func_rt: llvmlite.Function | t.CPtr = self.Trans._cur_func
|
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:
|
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)
|
ret_ty_rt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(cur_func_rt)
|
||||||
if ret_ty_rt is not None:
|
if ret_ty_rt is not None:
|
||||||
val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
|
val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
|
||||||
ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt)
|
ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt)
|
||||||
if val_bits != 0 and ret_bits != 0 and val_bits != ret_bits:
|
val_is_ptr: int = HandlesExpr.is_ptr_type(val.Ty)
|
||||||
|
ret_is_ptr: int = HandlesExpr.is_ptr_type(ret_ty_rt)
|
||||||
|
# ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换
|
||||||
|
if val_is_ptr != ret_is_ptr:
|
||||||
|
val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt)
|
||||||
|
elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits:
|
||||||
if val_bits == 1 and val_bits < ret_bits:
|
if val_bits == 1 and val_bits < ret_bits:
|
||||||
val = llvmlite.build_zext(builder, val, ret_ty_rt)
|
val = llvmlite.build_zext(builder, val, ret_ty_rt)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import llvmlite
|
|||||||
import stdio
|
import stdio
|
||||||
import ast
|
import ast
|
||||||
import hashtable
|
import hashtable
|
||||||
|
import viperlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -19,7 +21,7 @@ import hashtable
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
STRUCT_MAX: t.CDefine = 512
|
STRUCT_MAX: t.CDefine = 512
|
||||||
FIELD_MAX: t.CDefine = 32
|
FIELD_MAX: t.CDefine = 48
|
||||||
FIELD_NAME_MAX: t.CDefine = 64
|
FIELD_NAME_MAX: t.CDefine = 64
|
||||||
|
|
||||||
|
|
||||||
@@ -196,7 +198,10 @@ def register_struct(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return existing
|
return existing
|
||||||
|
|
||||||
if _struct_count >= STRUCT_MAX:
|
if _struct_count >= STRUCT_MAX:
|
||||||
stdio.printf("[STRUCT] table full, cannot register %s\n", name)
|
fb_st: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_st is not None:
|
||||||
|
viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name)
|
||||||
|
VLogger.error(fb_st, "STRUCT")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
entry: StructEntry | t.CPtr = _get_struct_entry(_struct_count)
|
entry: StructEntry | t.CPtr = _get_struct_entry(_struct_count)
|
||||||
@@ -290,7 +295,10 @@ def add_field(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return -1
|
return -1
|
||||||
|
|
||||||
if struct_entry.FieldCount >= FIELD_MAX:
|
if struct_entry.FieldCount >= FIELD_MAX:
|
||||||
stdio.printf("[STRUCT] field table full for %s\n", struct_entry.Name)
|
fb_sf: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_sf is not None:
|
||||||
|
viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name)
|
||||||
|
VLogger.error(fb_sf, "STRUCT")
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
idx: int = struct_entry.FieldCount
|
idx: int = struct_entry.FieldCount
|
||||||
@@ -314,18 +322,41 @@ def add_field(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# get_struct_count — 获取已注册结构体数量(供 Phase2 多遍预注册判断收敛)
|
||||||
|
# ============================================================
|
||||||
|
def get_struct_count() -> int:
|
||||||
|
"""返回当前已注册的结构体数量"""
|
||||||
|
return _struct_count
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# find_struct — 按类名查找结构体
|
# find_struct — 按类名查找结构体
|
||||||
# ============================================================
|
# ============================================================
|
||||||
def find_struct(name: str) -> StructEntry | t.CPtr:
|
def find_struct(name: str) -> StructEntry | t.CPtr:
|
||||||
"""按类名查找结构体,返回 StructEntry 或 None"""
|
"""按类名查找结构体,返回 StructEntry 或 None
|
||||||
|
|
||||||
|
支持模块限定名(如 "HT.Translator"):
|
||||||
|
第一遍精确匹配,第二遍按类名(最后一个 '.' 之后的部分)回退
|
||||||
|
"""
|
||||||
if name is None or _struct_table is None:
|
if name is None or _struct_table is None:
|
||||||
return None
|
return None
|
||||||
|
# 第一遍:精确匹配
|
||||||
for i in range(_struct_count):
|
for i in range(_struct_count):
|
||||||
entry: StructEntry | t.CPtr = _get_struct_entry(i)
|
entry: StructEntry | t.CPtr = _get_struct_entry(i)
|
||||||
if entry is not None and entry.Name is not None:
|
if entry is not None and entry.Name is not None:
|
||||||
if string.strcmp(entry.Name, name) == 0:
|
if string.strcmp(entry.Name, name) == 0:
|
||||||
return entry
|
return entry
|
||||||
|
# 第二遍:类名回退(处理模块限定名 "HT.Translator" → "Translator")
|
||||||
|
dot_pos: str = string.strrchr(name, '.')
|
||||||
|
if dot_pos is not None:
|
||||||
|
class_name: str = dot_pos + 1
|
||||||
|
if class_name is not None and class_name[0] != '\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:
|
||||||
|
return entry
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -455,12 +486,27 @@ def lookup_field_by_class(class_name: str,
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
# 优先用 SHA1 匹配(跨模块同名类区分)
|
# 优先用 SHA1 匹配(跨模块同名类区分)
|
||||||
|
# 支持模块限定名:class_name 可能是 "HT.Translator",entry.Name 是 "Translator"
|
||||||
|
# 先精确匹配,失败后用 strrchr 提取类名部分回退匹配
|
||||||
if sha1 is not None:
|
if sha1 is not None:
|
||||||
sha1_matched: int = 0
|
sha1_matched: int = 0
|
||||||
|
# 计算类名回退部分("HT.Translator" → "Translator")
|
||||||
|
bare_name: str = class_name
|
||||||
|
dot_pos_lfbc: str = string.strrchr(class_name, '.')
|
||||||
|
if dot_pos_lfbc is not None:
|
||||||
|
bare_name = dot_pos_lfbc + 1
|
||||||
|
if bare_name is None or bare_name[0] == '\0':
|
||||||
|
bare_name = class_name
|
||||||
for i in range(_struct_count):
|
for i in range(_struct_count):
|
||||||
entry: StructEntry | t.CPtr = _get_struct_entry(i)
|
entry: StructEntry | t.CPtr = _get_struct_entry(i)
|
||||||
if entry is not None and entry.Name is not None:
|
if entry is not None and entry.Name is not None:
|
||||||
|
# 精确匹配或类名回退匹配
|
||||||
|
name_match: int = 0
|
||||||
if string.strcmp(entry.Name, class_name) == 0:
|
if string.strcmp(entry.Name, class_name) == 0:
|
||||||
|
name_match = 1
|
||||||
|
elif bare_name is not class_name and string.strcmp(entry.Name, bare_name) == 0:
|
||||||
|
name_match = 1
|
||||||
|
if name_match != 0:
|
||||||
if entry.ModuleSha1 is not None:
|
if entry.ModuleSha1 is not None:
|
||||||
if string.strcmp(entry.ModuleSha1, sha1) == 0:
|
if string.strcmp(entry.ModuleSha1, sha1) == 0:
|
||||||
sha1_matched = 1
|
sha1_matched = 1
|
||||||
@@ -475,12 +521,65 @@ def lookup_field_by_class(class_name: str,
|
|||||||
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
|
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
|
||||||
entry = find_struct(class_name)
|
entry = find_struct(class_name)
|
||||||
if entry is None:
|
if entry is None:
|
||||||
|
# 诊断:遍历打印所有已注册结构体名,确认目标类是否在注册表中
|
||||||
|
stdio.printf("[LFBC-DIAG] FAIL class=%s field=%s sha1=%s count=%d\n",
|
||||||
|
class_name, field_name,
|
||||||
|
sha1 if sha1 is not None else "(null)", _struct_count)
|
||||||
|
for diag_i in range(_struct_count):
|
||||||
|
diag_entry: StructEntry | t.CPtr = _get_struct_entry(diag_i)
|
||||||
|
if diag_entry is not None and diag_entry.Name is not None:
|
||||||
|
stdio.printf("[LFBC-DIAG] [%d] %s sha1=%s fc=%d\n",
|
||||||
|
diag_i, diag_entry.Name,
|
||||||
|
diag_entry.ModuleSha1 if diag_entry.ModuleSha1 is not None else "(null)",
|
||||||
|
diag_entry.FieldCount)
|
||||||
return None
|
return None
|
||||||
for fi in range(entry.FieldCount):
|
for fi in range(entry.FieldCount):
|
||||||
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
|
fe: FieldEntry | t.CPtr = _get_field_entry(entry, fi)
|
||||||
if fe is not None and fe.Name is not None:
|
if fe is not None and fe.Name is not None:
|
||||||
if string.strcmp(fe.Name, field_name) == 0:
|
if string.strcmp(fe.Name, field_name) == 0:
|
||||||
return fe
|
return fe
|
||||||
|
# 诊断:找到结构体但字段未找到
|
||||||
|
stdio.printf("[LFBC-DIAG] NOFIELD class=%s field=%s sname=%s fc=%d\n",
|
||||||
|
class_name, field_name, entry.Name, entry.FieldCount)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# find_subclass_with_field — 在基类的所有子类中搜索包含指定字段的结构体
|
||||||
|
#
|
||||||
|
# 用于处理 "注解类型是基类但实际值是派生类" 的场景:
|
||||||
|
# node: AST | t.CPtr = If(...)
|
||||||
|
# node.orelse = orelse ← orelse 在 If 上,不在 AST 上
|
||||||
|
#
|
||||||
|
# 遍历所有已注册结构体,通过 ParentName 链检查继承关系,
|
||||||
|
# 返回第一个包含 field_name 的子类 StructEntry。
|
||||||
|
# ============================================================
|
||||||
|
def find_subclass_with_field(base_class_name: str,
|
||||||
|
field_name: str) -> StructEntry | t.CPtr:
|
||||||
|
"""在 base_class_name 的所有子类中搜索包含 field_name 的结构体
|
||||||
|
|
||||||
|
返回第一个找到的 StructEntry(包含正确的 Ty),None=未找到
|
||||||
|
"""
|
||||||
|
if base_class_name is None or field_name is None:
|
||||||
|
return None
|
||||||
|
sc_i: int
|
||||||
|
for sc_i in range(_struct_count):
|
||||||
|
sc_entry: StructEntry | t.CPtr = _get_struct_entry(sc_i)
|
||||||
|
if sc_entry is None or sc_entry.Name is None:
|
||||||
|
continue
|
||||||
|
# 检查 sc_entry 是否是 base_class_name 的子类(传递性)
|
||||||
|
cur_parent: str = get_parent_name(sc_entry.Name)
|
||||||
|
while cur_parent is not None:
|
||||||
|
if string.strcmp(cur_parent, base_class_name) == 0:
|
||||||
|
# 是子类,检查是否有该字段
|
||||||
|
sc_fi: int
|
||||||
|
for sc_fi in range(sc_entry.FieldCount):
|
||||||
|
sc_fe: FieldEntry | t.CPtr = _get_field_entry(sc_entry, sc_fi)
|
||||||
|
if sc_fe is not None and sc_fe.Name is not None:
|
||||||
|
if string.strcmp(sc_fe.Name, field_name) == 0:
|
||||||
|
return sc_entry
|
||||||
|
break
|
||||||
|
cur_parent = get_parent_name(cur_parent)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -546,6 +645,28 @@ def _is_struct_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def _is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||||
|
"""检查 ty 是否是 Ptr 类型(独立函数,规避嵌套 match 编译器 BUG)"""
|
||||||
|
if ty is None:
|
||||||
|
return 0
|
||||||
|
match ty:
|
||||||
|
case llvmlite.LLVMType.Ptr(pointee):
|
||||||
|
return 1
|
||||||
|
case _:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def _get_ptr_pointee(ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||||||
|
"""获取 Ptr 类型的 pointee(独立函数,规避嵌套 match 编译器 BUG)"""
|
||||||
|
if ty is None:
|
||||||
|
return None
|
||||||
|
match ty:
|
||||||
|
case llvmlite.LLVMType.Ptr(pointee):
|
||||||
|
return pointee
|
||||||
|
case _:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_struct_type_from_value(val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
def get_struct_type_from_value(val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||||||
"""从 Value 的类型推断结构体类型"""
|
"""从 Value 的类型推断结构体类型"""
|
||||||
if val is None or val.Ty is None:
|
if val is None or val.Ty is None:
|
||||||
@@ -935,6 +1056,119 @@ def get_field_count(name: str) -> int:
|
|||||||
return entry.FieldCount
|
return entry.FieldCount
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# ensure_struct_def_in_module — 确保跨模块结构体的完整定义在当前模块中可用
|
||||||
|
#
|
||||||
|
# 当局部变量声明为值类型(如 f: File)时,alloca 需要完整类型定义。
|
||||||
|
# 如果结构体定义在另一个模块(名称含 SHA1 前缀,如 "0035c95a18d4f8e8.File"),
|
||||||
|
# 将其完整定义复制到当前模块。module_add_named_type 会用完整定义替换
|
||||||
|
# 已存在的 opaque 声明,使 alloca 能正确分配空间。
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# pool: 内存池
|
||||||
|
# mod: 当前 LLVM 模块
|
||||||
|
# ty: 变量类型(Struct/Ptr/其他)
|
||||||
|
# ============================================================
|
||||||
|
def ensure_struct_def_in_module(pool: memhub.MemBuddy | t.CPtr,
|
||||||
|
mod: llvmlite.LLVMModule | t.CPtr,
|
||||||
|
ty: llvmlite.LLVMType | t.CPtr):
|
||||||
|
"""确保跨模块结构体的完整定义在当前模块中可用(供 alloca 使用)
|
||||||
|
|
||||||
|
处理两种情况:
|
||||||
|
1. Struct 值类型:需要完整定义(供 alloca 分配空间)
|
||||||
|
2. Ptr(Struct) 指针类型:需要 pointee 至少有 opaque 声明
|
||||||
|
"""
|
||||||
|
if ty is None or mod is None or pool is None:
|
||||||
|
return
|
||||||
|
# 指针类型:确保 pointee 至少有 opaque 声明
|
||||||
|
# 用 _is_ptr_type 检查(独立函数,规避嵌套 match BUG)
|
||||||
|
if _is_ptr_type(ty) != 0:
|
||||||
|
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
|
||||||
|
# 如果 pointee 是 Struct,递归复制完整定义
|
||||||
|
# (GEP 访问字段需要 sized 类型,仅 opaque 会导致 llc 报错)
|
||||||
|
pointee: llvmlite.LLVMType | t.CPtr = _get_ptr_pointee(ty)
|
||||||
|
if pointee is not None:
|
||||||
|
ensure_struct_def_in_module(pool, mod, pointee)
|
||||||
|
return
|
||||||
|
# 获取结构体名称(非 Struct 类型返回 None)
|
||||||
|
sname: t.CChar | t.CPtr = llvmlite.get_struct_name(ty)
|
||||||
|
if sname is None:
|
||||||
|
return
|
||||||
|
# 检查是否为跨模块引用(名称包含 '.')
|
||||||
|
if string.strchr(sname, 46) is None:
|
||||||
|
return # 非跨模块引用,无需处理
|
||||||
|
# 提取类名(第一个 '.' 之后的部分)
|
||||||
|
# 必须用 strchr 而非 strrchr:泛型特化名如 "list[ast.AST|t.CPtr]"
|
||||||
|
# 内部含 '.'(ast.AST),strrchr 会错误地把类名解析为 "AST|t.CPtr]"
|
||||||
|
dot_pos: str = string.strchr(sname, '.')
|
||||||
|
if dot_pos is None:
|
||||||
|
return
|
||||||
|
class_name: str = dot_pos + 1
|
||||||
|
if class_name is None or class_name[0] == '\0':
|
||||||
|
return
|
||||||
|
# 提取 SHA1(sname 到 dot_pos 之间,用 strlen 避免指针减法)
|
||||||
|
total_len: t.CSizeT = string.strlen(sname)
|
||||||
|
class_name_len: t.CSizeT = string.strlen(class_name)
|
||||||
|
sha1_len: t.CSizeT = total_len - class_name_len - 1
|
||||||
|
sha1_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||||
|
if sha1_buf is None:
|
||||||
|
return
|
||||||
|
string.strncpy(sha1_buf, sname, sha1_len)
|
||||||
|
sha1_buf[sha1_len] = '\0'
|
||||||
|
# 按类名 + SHA1 查找结构体定义
|
||||||
|
entry: StructEntry | t.CPtr = find_struct_by_module(class_name, sha1_buf)
|
||||||
|
if entry is None:
|
||||||
|
# 回退到按类名查找(可能找到不同模块的同名类,但总比没有好)
|
||||||
|
entry = find_struct(class_name)
|
||||||
|
if entry is None:
|
||||||
|
return
|
||||||
|
if entry.Ty is None:
|
||||||
|
return
|
||||||
|
# 将完整定义添加到当前模块(会替换已存在的 opaque 声明)
|
||||||
|
llvmlite.module_add_named_type(mod, pool, entry.Ty)
|
||||||
|
# 递归扫描字段类型,确保值类型子结构体(如 WIN32_FIND_DATAA 中的 FILETIME)
|
||||||
|
# 也有完整定义。指针类型字段只需 opaque 声明(已由 module_ensure_opaque_for_type 处理)。
|
||||||
|
_ensure_field_types_in_module(pool, mod, entry.Ty)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _ensure_field_types_in_module - 递归扫描结构体字段类型
|
||||||
|
#
|
||||||
|
# 遍历 Struct 的 Fields 链表,对每个值类型子结构体调用
|
||||||
|
# ensure_struct_def_in_module。指针/数组/基本类型递归到 pointee/element。
|
||||||
|
# ============================================================
|
||||||
|
def _ensure_field_types_in_module(pool: memhub.MemBuddy | t.CPtr,
|
||||||
|
mod: llvmlite.LLVMModule | t.CPtr,
|
||||||
|
ty: llvmlite.LLVMType | t.CPtr):
|
||||||
|
"""递归扫描类型树,确保值类型子结构体有完整定义"""
|
||||||
|
if ty is None or mod is None or pool is None:
|
||||||
|
return
|
||||||
|
# 用 match 遍历类型(独立函数,规避嵌套 match BUG)
|
||||||
|
match ty:
|
||||||
|
case llvmlite.LLVMType.Struct(fields, fcount, sname):
|
||||||
|
# 遍历字段链表
|
||||||
|
if fields is not None:
|
||||||
|
fld: llvmlite.ParamNode | t.CPtr = fields
|
||||||
|
while fld is not None:
|
||||||
|
if fld.Ty is not None:
|
||||||
|
# 值类型子结构体(如 FILETIME)需要完整定义
|
||||||
|
if _is_struct_type(fld.Ty) != 0:
|
||||||
|
ensure_struct_def_in_module(pool, mod, fld.Ty)
|
||||||
|
_ensure_field_types_in_module(pool, mod, fld.Ty)
|
||||||
|
fld = fld.Next
|
||||||
|
case llvmlite.LLVMType.Ptr(pointee):
|
||||||
|
# 指针类型:pointee 只需 opaque 声明,不需要完整定义
|
||||||
|
# 但如果 pointee 是 Struct,确保 opaque 声明存在
|
||||||
|
if pointee is not None:
|
||||||
|
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
|
||||||
|
case llvmlite.LLVMType.Array(elem_ty, acount):
|
||||||
|
# 数组类型:元素如果是值类型结构体,需要完整定义
|
||||||
|
if elem_ty is not None:
|
||||||
|
_ensure_field_types_in_module(pool, mod, elem_ty)
|
||||||
|
case _:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# get_field_name_ptr — 获取 FieldEntry 的字段名指针(访问器)
|
# get_field_name_ptr — 获取 FieldEntry 的字段名指针(访问器)
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import memhub
|
|||||||
import string
|
import string
|
||||||
import stdio
|
import stdio
|
||||||
import stdlib
|
import stdlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
import lib.core.Handles.HandlesVar as HandlesVar
|
import lib.core.Handles.HandlesVar as HandlesVar
|
||||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||||
import lib.core.Handles.HandlesMain as HandlesMain
|
import lib.core.Handles.HandlesMain as HandlesMain
|
||||||
@@ -212,7 +213,7 @@ class Translator:
|
|||||||
# 创建 LLVM 模块
|
# 创建 LLVM 模块
|
||||||
mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main")
|
mod: llvmlite.LLVMModule | t.CPtr = llvmlite.new_module(pool, "main")
|
||||||
if mod is None:
|
if mod is None:
|
||||||
stdio.printf("[TR] NewModule returned NULL\n")
|
VLogger.error("NewModule returned NULL", "TR")
|
||||||
return 1
|
return 1
|
||||||
self.Module = mod
|
self.Module = mod
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ class Translator:
|
|||||||
printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
printf_func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||||||
pool, mod, "printf", i32_ty)
|
pool, mod, "printf", i32_ty)
|
||||||
if printf_func is None:
|
if printf_func is None:
|
||||||
stdio.printf("[TR] CreateDeclare printf returned NULL\n")
|
VLogger.error("CreateDeclare printf returned NULL", "TR")
|
||||||
return 1
|
return 1
|
||||||
llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt")
|
llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt")
|
||||||
printf_func.IsVarArg = 1
|
printf_func.IsVarArg = 1
|
||||||
@@ -305,6 +306,21 @@ class Translator:
|
|||||||
elif kd == ast.ASTKind.ImportFrom:
|
elif kd == ast.ASTKind.ImportFrom:
|
||||||
self.ImportsH.HandleImportFromModule(child)
|
self.ImportsH.HandleImportFromModule(child)
|
||||||
self.ImportsH.HandleImportFromNames(child)
|
self.ImportsH.HandleImportFromNames(child)
|
||||||
|
# 预注册模块级变量(AnnAssign/Assign)到 SymTab
|
||||||
|
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
|
||||||
|
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
|
||||||
|
# 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None
|
||||||
|
# 预处理先于 translate_children 注册所有模块级变量,
|
||||||
|
# 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var
|
||||||
|
# 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209)
|
||||||
|
if ch is not None:
|
||||||
|
for ci in range(cn_count):
|
||||||
|
child: ast.AST | t.CPtr = ch.get(ci)
|
||||||
|
if child is None:
|
||||||
|
continue
|
||||||
|
kd_mv: int = child.kind()
|
||||||
|
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
|
||||||
|
HandlesMain.handle_module_level_var(self, child)
|
||||||
# 创建前向声明
|
# 创建前向声明
|
||||||
HandlesFunctions.forward_declare_functions(self, tree)
|
HandlesFunctions.forward_declare_functions(self, tree)
|
||||||
added: int = HandlesMain.translate_children(self, tree)
|
added: int = HandlesMain.translate_children(self, tree)
|
||||||
|
|||||||
@@ -26,6 +26,27 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
|
|||||||
_g_current_file: str = None
|
_g_current_file: str = None
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 全局 temp_dir(pyi 文件所在目录,由 BuildPipeline/Phase1 设置)
|
||||||
|
#
|
||||||
|
# 用于跨模块 CDefine 常量查找:当当前模块的 CDefine 表中找不到
|
||||||
|
# 某个 Name 时,从 from_imports 解析出源模块,再从该模块的 pyi
|
||||||
|
# 文件中解析 CDefine 常量值。
|
||||||
|
# ============================================================
|
||||||
|
_g_temp_dir: str = None
|
||||||
|
|
||||||
|
|
||||||
|
def set_temp_dir(temp_dir: str) -> None:
|
||||||
|
"""设置全局 temp_dir(每个项目编译开始时由 BuildPipeline/Phase1 设置)"""
|
||||||
|
global _g_temp_dir
|
||||||
|
_g_temp_dir = temp_dir
|
||||||
|
|
||||||
|
|
||||||
|
def get_temp_dir() -> str:
|
||||||
|
"""获取全局 temp_dir"""
|
||||||
|
return _g_temp_dir
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 全局泛型特化上下文(由 _specialize_generic_class 设置/清除)
|
# 全局泛型特化上下文(由 _specialize_generic_class 设置/清除)
|
||||||
#
|
#
|
||||||
@@ -46,11 +67,55 @@ _g_generic_type_args: list[str] | t.CPtr = None
|
|||||||
_g_cdefine_names: list[str] | t.CPtr = None
|
_g_cdefine_names: list[str] | t.CPtr = None
|
||||||
_g_cdefine_values: list[str] | t.CPtr = None
|
_g_cdefine_values: list[str] | t.CPtr = None
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 全局跨模块 CDefine 表(按模块 SHA1 索引,跨模块持久化)
|
||||||
|
#
|
||||||
|
# 本地表在模块切换时被 clear_cdefine_constants 清空,
|
||||||
|
# 导致跨模块引用(如 HandlesVar.SCOPE_FUNCTION)找不到常量。
|
||||||
|
# 全局表在模块切换时不清空,跨模块查找直接查表,无需文件 I/O。
|
||||||
|
#
|
||||||
|
# 数据布局:
|
||||||
|
# _g_gcdef_sha1s: 每条 17 字节(模块 SHA1 16字符 + null)
|
||||||
|
# _g_gcdef_names: 每条 64 字节(常量名 + null)
|
||||||
|
# _g_gcdef_values: 每条 32 字节(值字符串 + null)
|
||||||
|
# ============================================================
|
||||||
|
MAX_GLOBAL_CDEFINE: t.CDefine = 1024
|
||||||
|
_g_gcdef_sha1s: bytes = None
|
||||||
|
_g_gcdef_names: bytes = None
|
||||||
|
_g_gcdef_values: bytes = None
|
||||||
|
_g_gcdef_count: int = 0
|
||||||
|
_g_current_module_sha1: str = None
|
||||||
|
|
||||||
|
|
||||||
|
def set_current_module_sha1(sha1: str) -> None:
|
||||||
|
"""设置当前正在编译的模块 SHA1(Phase1 在模块开始翻译前调用)"""
|
||||||
|
global _g_current_module_sha1
|
||||||
|
_g_current_module_sha1 = sha1
|
||||||
|
|
||||||
|
|
||||||
|
def _global_cdefine_init(pool: memhub.MemBuddy | t.CPtr) -> int:
|
||||||
|
"""懒初始化全局 CDefine 表"""
|
||||||
|
global _g_gcdef_sha1s, _g_gcdef_names, _g_gcdef_values
|
||||||
|
if _g_gcdef_sha1s is None:
|
||||||
|
_g_gcdef_sha1s = stdlib.malloc(MAX_GLOBAL_CDEFINE * 17)
|
||||||
|
_g_gcdef_names = stdlib.malloc(MAX_GLOBAL_CDEFINE * 64)
|
||||||
|
_g_gcdef_values = stdlib.malloc(MAX_GLOBAL_CDEFINE * 32)
|
||||||
|
if _g_gcdef_sha1s is None or _g_gcdef_names is None or _g_gcdef_values is None:
|
||||||
|
return 1
|
||||||
|
string.memset(_g_gcdef_sha1s, 0, MAX_GLOBAL_CDEFINE * 17)
|
||||||
|
string.memset(_g_gcdef_names, 0, MAX_GLOBAL_CDEFINE * 64)
|
||||||
|
string.memset(_g_gcdef_values, 0, MAX_GLOBAL_CDEFINE * 32)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
|
def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
|
||||||
name: str, value: int) -> None:
|
name: str, value: int) -> None:
|
||||||
"""注册 CDefine 编译期常量到全局表"""
|
"""注册 CDefine 编译期常量到本地表和全局表
|
||||||
global _g_cdefine_names, _g_cdefine_values
|
|
||||||
|
值以十进制字符串存储。注意:value 是 32 位有符号整数,
|
||||||
|
0xFFFFFFFF 会存储为 "-1",lookup 时用 found 标志区分"未找到"和值为 -1。
|
||||||
|
"""
|
||||||
|
global _g_cdefine_names, _g_cdefine_values, _g_gcdef_count
|
||||||
if _g_cdefine_names is None:
|
if _g_cdefine_names is None:
|
||||||
_g_cdefine_names = list[str](pool, 64)
|
_g_cdefine_names = list[str](pool, 64)
|
||||||
_g_cdefine_values = list[str](pool, 64)
|
_g_cdefine_values = list[str](pool, 64)
|
||||||
@@ -61,12 +126,54 @@ def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
_g_cdefine_values.append(val_buf)
|
_g_cdefine_values.append(val_buf)
|
||||||
else:
|
else:
|
||||||
_g_cdefine_values.append("0")
|
_g_cdefine_values.append("0")
|
||||||
|
# 同时注册到全局跨模块表(用当前模块 SHA1 索引)
|
||||||
|
if _g_current_module_sha1 is not None and _g_gcdef_count < MAX_GLOBAL_CDEFINE:
|
||||||
|
if _global_cdefine_init(pool) == 0:
|
||||||
|
sidx: t.CSizeT = t.CSizeT(_g_gcdef_count) * 17
|
||||||
|
nidx: t.CSizeT = t.CSizeT(_g_gcdef_count) * 64
|
||||||
|
vidx: t.CSizeT = t.CSizeT(_g_gcdef_count) * 32
|
||||||
|
string.strcpy(_g_gcdef_sha1s + sidx, _g_current_module_sha1)
|
||||||
|
string.strcpy(_g_gcdef_names + nidx, name)
|
||||||
|
vbuf: str = _g_gcdef_values + vidx
|
||||||
|
viperlib.snprintf(vbuf, 32, "%d", value)
|
||||||
|
_g_gcdef_count += 1
|
||||||
|
|
||||||
|
|
||||||
|
def lookup_global_cdefine(module_sha1: str, name: str) -> int:
|
||||||
|
"""从全局跨模块表查找 CDefine 常量
|
||||||
|
|
||||||
|
用 module_sha1 + name 精确匹配。
|
||||||
|
找到时设置 _g_cdefine_found=1 并返回值;未找到返回 0。
|
||||||
|
"""
|
||||||
|
global _g_cdefine_found
|
||||||
|
if module_sha1 is None or name is None:
|
||||||
|
return 0
|
||||||
|
if _g_gcdef_sha1s is None or _g_gcdef_count <= 0:
|
||||||
|
return 0
|
||||||
|
i: t.CSizeT = 0
|
||||||
|
while i < _g_gcdef_count:
|
||||||
|
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||||
|
nidx: t.CSizeT = t.CSizeT(i) * 64
|
||||||
|
vidx: t.CSizeT = t.CSizeT(i) * 32
|
||||||
|
if string.strcmp(_g_gcdef_sha1s + sidx, module_sha1) == 0:
|
||||||
|
if string.strcmp(_g_gcdef_names + nidx, name) == 0:
|
||||||
|
_g_cdefine_found = 1
|
||||||
|
return string.atoi(_g_gcdef_values + vidx)
|
||||||
|
i += 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def lookup_cdefine_constant(name: str) -> int:
|
def lookup_cdefine_constant(name: str) -> int:
|
||||||
"""查找 CDefine 编译期常量,返回值或 -1(未找到)"""
|
"""查找 CDefine 编译期常量
|
||||||
|
|
||||||
|
返回找到的值。由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1),
|
||||||
|
用全局 _g_cdefine_found 标志区分"未找到"和值为 -1。
|
||||||
|
调用方应在调用后检查 _g_cdefine_found。
|
||||||
|
"""
|
||||||
|
global _g_cdefine_found
|
||||||
|
_g_cdefine_found = 0
|
||||||
if _g_cdefine_names is None:
|
if _g_cdefine_names is None:
|
||||||
return -1
|
return 0
|
||||||
n: t.CSizeT = _g_cdefine_names.__len__()
|
n: t.CSizeT = _g_cdefine_names.__len__()
|
||||||
i: t.CSizeT
|
i: t.CSizeT
|
||||||
for i in range(n):
|
for i in range(n):
|
||||||
@@ -74,8 +181,23 @@ def lookup_cdefine_constant(name: str) -> int:
|
|||||||
if nm is not None and string.strcmp(nm, name) == 0:
|
if nm is not None and string.strcmp(nm, name) == 0:
|
||||||
val_str: str = _g_cdefine_values.get(i)
|
val_str: str = _g_cdefine_values.get(i)
|
||||||
if val_str is not None:
|
if val_str is not None:
|
||||||
|
_g_cdefine_found = 1
|
||||||
return string.atoi(val_str)
|
return string.atoi(val_str)
|
||||||
return -1
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
_g_cdefine_found: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
def is_cdefine_found() -> int:
|
||||||
|
"""检查上次 lookup_cdefine_constant 是否找到值"""
|
||||||
|
return _g_cdefine_found
|
||||||
|
|
||||||
|
|
||||||
|
def set_cdefine_found(val: int) -> None:
|
||||||
|
"""设置 cdefine_found 标志(供跨模块查找函数使用)"""
|
||||||
|
global _g_cdefine_found
|
||||||
|
_g_cdefine_found = val
|
||||||
|
|
||||||
|
|
||||||
def clear_cdefine_constants() -> None:
|
def clear_cdefine_constants() -> None:
|
||||||
@@ -228,6 +350,20 @@ def _parse_type_string(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
return ast.Name(pool, type_str, ctx)
|
return ast.Name(pool, type_str, ctx)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _parse_type_string_ptr - _parse_type_string 的 t.CPtr 返回类型包装
|
||||||
|
#
|
||||||
|
# 旧编译器对 ast.AST | t.CPtr 跨模块返回类型推断有 bug(解析为 i32),
|
||||||
|
# 用 t.CPtr 包装绕过,外部模块应调用此函数而非 _parse_type_string
|
||||||
|
# ============================================================
|
||||||
|
def _parse_type_string_ptr(pool: memhub.MemBuddy | t.CPtr,
|
||||||
|
type_str: str,
|
||||||
|
ctx: t.CInt) -> t.CPtr:
|
||||||
|
"""_parse_type_string 的 t.CPtr 返回类型包装(绕过旧编译器类型推断 bug)"""
|
||||||
|
result: ast.AST | t.CPtr = _parse_type_string(pool, type_str, ctx)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# set_current_file - 设置当前编译的文件名
|
# set_current_file - 设置当前编译的文件名
|
||||||
#
|
#
|
||||||
@@ -709,7 +845,8 @@ def extract_class_name_from_annotation(node: ast.AST | t.CPtr,
|
|||||||
def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
||||||
node: ast.AST | t.CPtr,
|
node: ast.AST | t.CPtr,
|
||||||
imported_modules: str,
|
imported_modules: str,
|
||||||
from_imports: str) -> llvmlite.LLVMType | t.CPtr:
|
from_imports: str,
|
||||||
|
trans: HT.Translator | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr:
|
||||||
"""解析类型注解节点为 LLVMType
|
"""解析类型注解节点为 LLVMType
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -717,6 +854,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
node: 类型注解 AST 节点(Name 或 Attribute)
|
node: 类型注解 AST 节点(Name 或 Attribute)
|
||||||
imported_modules: 已导入模块名字符串(空格分隔)
|
imported_modules: 已导入模块名字符串(空格分隔)
|
||||||
from_imports: from-import 映射字符串("name:module name:module" 格式)
|
from_imports: from-import 映射字符串("name:module name:module" 格式)
|
||||||
|
trans: 翻译器对象(可选,用于触发泛型特化)
|
||||||
"""
|
"""
|
||||||
if node is None:
|
if node is None:
|
||||||
return None
|
return None
|
||||||
@@ -727,9 +865,9 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
if k == ast.ASTKind.Constant:
|
if k == ast.ASTKind.Constant:
|
||||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||||||
if cn.const_kind == ast.CONST_STR and cn.str_val is not None:
|
if cn.const_kind == ast.CONST_STR and cn.str_val is not None:
|
||||||
sub_node: ast.AST | t.CPtr = _parse_type_string(pool, cn.str_val, ast.Ctx.Load)
|
sub_node: ast.AST | t.CPtr = _parse_type_string(pool, cn.str_val, ast.ASTCtx.Load)
|
||||||
if sub_node is not None:
|
if sub_node is not None:
|
||||||
return resolve_annotation_type(pool, sub_node, imported_modules, from_imports)
|
return resolve_annotation_type(pool, sub_node, imported_modules, from_imports, trans)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Name 节点: str, int, bytes, from-import 名称, class 名称等
|
# Name 节点: str, int, bytes, from-import 名称, class 名称等
|
||||||
@@ -749,7 +887,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
# 用具体类型名递归解析(支持 BinOp/Attribute 类型实参)
|
# 用具体类型名递归解析(支持 BinOp/Attribute 类型实参)
|
||||||
gp_sub_node: ast.AST | t.CPtr = _parse_type_string(pool, gp_ta, nm.ctx)
|
gp_sub_node: ast.AST | t.CPtr = _parse_type_string(pool, gp_ta, nm.ctx)
|
||||||
if gp_sub_node is not None:
|
if gp_sub_node is not None:
|
||||||
return resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports)
|
return resolve_annotation_type(pool, gp_sub_node, imported_modules, from_imports, trans)
|
||||||
# str = bytes = t.CChar | t.CPtr = i8*
|
# str = bytes = t.CChar | t.CPtr = i8*
|
||||||
if string.strcmp(nm.id, "str") == 0:
|
if string.strcmp(nm.id, "str") == 0:
|
||||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||||
@@ -817,7 +955,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
if other_is_cvoid != 0:
|
if other_is_cvoid != 0:
|
||||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||||
other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
||||||
pool, other_node, imported_modules, from_imports)
|
pool, other_node, imported_modules, from_imports, trans)
|
||||||
if other_ty is None:
|
if other_ty is None:
|
||||||
# CPtr 单独使用或其他无效类型 → i8*
|
# CPtr 单独使用或其他无效类型 → i8*
|
||||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||||
@@ -825,11 +963,11 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
|
|
||||||
# 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略)
|
# 无 CPtr 标记:返回第一个非 None(装饰器标记如 CExport/CExtern 被忽略)
|
||||||
left_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
left_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
||||||
pool, bop.left, imported_modules, from_imports)
|
pool, bop.left, imported_modules, from_imports, trans)
|
||||||
if left_ty is not None:
|
if left_ty is not None:
|
||||||
return left_ty
|
return left_ty
|
||||||
right_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
right_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
||||||
pool, bop.right, imported_modules, from_imports)
|
pool, bop.right, imported_modules, from_imports, trans)
|
||||||
if right_ty is not None:
|
if right_ty is not None:
|
||||||
return right_ty
|
return right_ty
|
||||||
return None
|
return None
|
||||||
@@ -891,6 +1029,22 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled)
|
gen_spec_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(gen_mangled)
|
||||||
if gen_spec_ty is not None:
|
if gen_spec_ty is not None:
|
||||||
return gen_spec_ty
|
return gen_spec_ty
|
||||||
|
# 未特化:尝试主动触发泛型特化(与 TPC _HandleSubscript 对齐)
|
||||||
|
# 当 trans 可用时,检查是否是泛型模板并触发特化
|
||||||
|
if trans is not None:
|
||||||
|
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||||
|
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||||
|
template_cd_chk: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_nm.id)
|
||||||
|
if template_cd_chk is not None:
|
||||||
|
type_args_chk: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(
|
||||||
|
pool, sub.slice)
|
||||||
|
if type_args_chk is not None and type_args_chk.__len__() > 0:
|
||||||
|
spec_name_chk: str = HandlesClassDef._specialize_generic_class(
|
||||||
|
trans, gen_nm.id, type_args_chk)
|
||||||
|
if spec_name_chk is not None:
|
||||||
|
gen_spec_ty = HandlesStruct.get_struct_type(gen_mangled)
|
||||||
|
if gen_spec_ty is not None:
|
||||||
|
return gen_spec_ty
|
||||||
# 未特化:返回 None(不报错,让后续流程处理)
|
# 未特化:返回 None(不报错,让后续流程处理)
|
||||||
return None
|
return None
|
||||||
# 检查 value 是否是 Attribute(Name('t'), 'CArray')
|
# 检查 value 是否是 Attribute(Name('t'), 'CArray')
|
||||||
@@ -912,7 +1066,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
# 相当于 t.CArray[elem_ty, None],表示静态推导长度数组
|
# 相当于 t.CArray[elem_ty, None],表示静态推导长度数组
|
||||||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||||||
elem_ty_single: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
elem_ty_single: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
||||||
pool, sub.slice, imported_modules, from_imports)
|
pool, sub.slice, imported_modules, from_imports, trans)
|
||||||
if elem_ty_single is None:
|
if elem_ty_single is None:
|
||||||
fatal_type_error(sub.slice, "t.CArray[?] 元素类型解析失败")
|
fatal_type_error(sub.slice, "t.CArray[?] 元素类型解析失败")
|
||||||
return llvmlite.Ptr(pool, elem_ty_single)
|
return llvmlite.Ptr(pool, elem_ty_single)
|
||||||
@@ -930,7 +1084,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
fatal_type_error(node, "t.CArray Tuple 元素为 None")
|
fatal_type_error(node, "t.CArray Tuple 元素为 None")
|
||||||
# 递归解析元素类型
|
# 递归解析元素类型
|
||||||
elem_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
elem_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type(
|
||||||
pool, elem_node, imported_modules, from_imports)
|
pool, elem_node, imported_modules, from_imports, trans)
|
||||||
if elem_ty is None:
|
if elem_ty is None:
|
||||||
fatal_type_error(elem_node, "t.CArray 元素类型解析失败")
|
fatal_type_error(elem_node, "t.CArray 元素类型解析失败")
|
||||||
# 解析 count(必须是整数常量、None 或 CDefine 常量名)
|
# 解析 count(必须是整数常量、None 或 CDefine 常量名)
|
||||||
@@ -950,7 +1104,7 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
if cnt_nm.id is None:
|
if cnt_nm.id is None:
|
||||||
fatal_type_error(count_node, "t.CArray count Name 节点 id 为 None")
|
fatal_type_error(count_node, "t.CArray count Name 节点 id 为 None")
|
||||||
looked_up: int = lookup_cdefine_constant(cnt_nm.id)
|
looked_up: int = lookup_cdefine_constant(cnt_nm.id)
|
||||||
if looked_up < 0:
|
if is_cdefine_found() == 0:
|
||||||
fatal_type_error(count_node, "t.CArray count 不是已注册的 CDefine 常量")
|
fatal_type_error(count_node, "t.CArray count 不是已注册的 CDefine 常量")
|
||||||
count_val = looked_up
|
count_val = looked_up
|
||||||
else:
|
else:
|
||||||
@@ -1180,6 +1334,11 @@ def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr)
|
|||||||
remain: t.CSizeT = dst_size - dlen
|
remain: t.CSizeT = dst_size - dlen
|
||||||
if remain <= 0:
|
if remain <= 0:
|
||||||
return
|
return
|
||||||
for i in range(min(slen, remain - 1)):
|
# 内联 min(slen, remain - 1) 避免 builtin min 未定义(TransPyV 无 builtin min)
|
||||||
|
limit: t.CSizeT = slen
|
||||||
|
cap: t.CSizeT = remain - 1
|
||||||
|
if cap < limit:
|
||||||
|
limit = cap
|
||||||
|
for i in range(limit):
|
||||||
dst[dlen + i] = src[i]
|
dst[dlen + i] = src[i]
|
||||||
dst[dlen + i] = '\0'
|
dst[dlen + i] = '\0'
|
||||||
@@ -36,6 +36,7 @@ class VarEntry:
|
|||||||
Alloca: llvmlite.Value | t.CPtr
|
Alloca: llvmlite.Value | t.CPtr
|
||||||
Used: t.CInt
|
Used: t.CInt
|
||||||
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
|
AnnotClassName: t.CChar | t.CPtr # 原始类型注解的类名(str 别名在结构体字段中触发编译器 bug,改用显式联合类型)
|
||||||
|
IsPtrElement: t.CInt # 标志: 1=注解为 bytes|t.CPtr 或 str|t.CPtr, 下标按 8 字节步长
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -154,6 +155,25 @@ def set_var_annot_class_name(symtab: SymbolTable | t.CPtr,
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# set_var_ptr_element — 标记变量为"指针到 str/bytes"类型
|
||||||
|
#
|
||||||
|
# 注解为 bytes|t.CPtr 或 str|t.CPtr 的变量,其 alloca 类型是 i8*,
|
||||||
|
# 但下标访问应按 8 字节步长(i8** 语义),而非 1 字节步长(i8* 语义)。
|
||||||
|
# 此标志在 HandlesAnnAssign 中根据注解形式设置。
|
||||||
|
# ============================================================
|
||||||
|
def set_var_ptr_element(symtab: SymbolTable | t.CPtr,
|
||||||
|
name: str) -> int:
|
||||||
|
"""标记变量为 ptr_element 类型,返回 0=成功 / 1=失败"""
|
||||||
|
if symtab is None or name is None:
|
||||||
|
return 1
|
||||||
|
entry: VarEntry | t.CPtr = lookup_var_entry(symtab, name)
|
||||||
|
if entry is None:
|
||||||
|
return 1
|
||||||
|
entry.IsPtrElement = 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# add_var — 添加变量到变量表
|
# add_var — 添加变量到变量表
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -175,6 +195,27 @@ def add_var(vars_ptr: VarEntry | t.CPtr,
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _alloca_at_entry - 在函数入口块生成 alloca(确保支配性)
|
||||||
|
#
|
||||||
|
# LLVM IR 要求指令支配所有使用点。如果 alloca 在条件分支内生成,
|
||||||
|
# 但在其他分支使用,会违反支配性(Instruction does not dominate all uses)。
|
||||||
|
# 标准做法:所有 alloca 在函数入口块生成。
|
||||||
|
#
|
||||||
|
# 临时切换 builder.CurBlock 到入口块,生成 alloca,然后恢复。
|
||||||
|
# ============================================================
|
||||||
|
def _alloca_at_entry(builder: llvmlite.IRBuilder | t.CPtr,
|
||||||
|
ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||||
|
"""在函数入口块生成 alloca,返回 alloca 值
|
||||||
|
|
||||||
|
使用 llvmlite.build_alloca_at_entry 在入口块终止指令之前插入 alloca,
|
||||||
|
确保所有 alloca 在入口块,避免支配性违规。
|
||||||
|
"""
|
||||||
|
if builder is None or ty is None:
|
||||||
|
return None
|
||||||
|
return llvmlite.build_alloca_at_entry(builder, ty)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# get_or_create_var — 查找或创建变量 alloca(旧版兼容)
|
# get_or_create_var — 查找或创建变量 alloca(旧版兼容)
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -188,7 +229,7 @@ def get_or_create_var(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
existing: llvmlite.Value | t.CPtr = find_var(vars_ptr, var_count, name)
|
existing: llvmlite.Value | t.CPtr = find_var(vars_ptr, var_count, name)
|
||||||
if existing is not None:
|
if existing is not None:
|
||||||
return existing
|
return existing
|
||||||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, ty)
|
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
|
||||||
if alloca is None:
|
if alloca is None:
|
||||||
return None
|
return None
|
||||||
if add_var(vars_ptr, var_count, name, alloca) != 0:
|
if add_var(vars_ptr, var_count, name, alloca) != 0:
|
||||||
@@ -358,7 +399,7 @@ def get_or_create_sym(symtab: SymbolTable | t.CPtr,
|
|||||||
existing: llvmlite.Value | t.CPtr = lookup_current(symtab, name)
|
existing: llvmlite.Value | t.CPtr = lookup_current(symtab, name)
|
||||||
if existing is not None:
|
if existing is not None:
|
||||||
return existing
|
return existing
|
||||||
alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, ty)
|
alloca: llvmlite.Value | t.CPtr = _alloca_at_entry(builder, ty)
|
||||||
if alloca is None:
|
if alloca is None:
|
||||||
return None
|
return None
|
||||||
define_var(symtab, name, alloca)
|
define_var(symtab, name, alloca)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import w32.win32base as win32base
|
|||||||
import w32.fileio as fileio
|
import w32.fileio as fileio
|
||||||
import hashlib
|
import hashlib
|
||||||
import viperlib
|
import viperlib
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -312,7 +313,10 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
|||||||
sha1: str = compute_file_sha1(pool, full_path)
|
sha1: str = compute_file_sha1(pool, full_path)
|
||||||
if sha1 is not None:
|
if sha1 is not None:
|
||||||
add_file_entry(result, pool, full_path, rel_path, sha1)
|
add_file_entry(result, pool, full_path, rel_path, sha1)
|
||||||
stdio.printf(" [scan] %s -> %s\n", rel_path, sha1)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "扫描: %s -> %s", rel_path, sha1)
|
||||||
|
VLogger.debug(fb, "scan")
|
||||||
|
|
||||||
# 继续搜索下一个文件
|
# 继续搜索下一个文件
|
||||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
|
|||||||
import lib.core.Handles.HandlesType as HandlesType
|
import lib.core.Handles.HandlesType as HandlesType
|
||||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||||
import lib.core.Handles.HandlesImports as HandlesImports
|
import lib.core.Handles.HandlesImports as HandlesImports
|
||||||
|
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||||
import lib.core.IncludesScanner as IncludesScanner
|
import lib.core.IncludesScanner as IncludesScanner
|
||||||
import lib.core.StubMerger as StubMerger
|
import lib.core.StubMerger as StubMerger
|
||||||
import lib.core.BuildPipeline as BuildPipeline
|
import lib.core.BuildPipeline as BuildPipeline
|
||||||
@@ -31,6 +32,431 @@ SRC_BUF_SIZE: t.CDefine = 1048576
|
|||||||
# pyi 缓冲区大小(256KB)
|
# pyi 缓冲区大小(256KB)
|
||||||
PYI_BUF_SIZE: t.CSizeT = 262144
|
PYI_BUF_SIZE: t.CSizeT = 262144
|
||||||
|
|
||||||
|
# 拓扑排序相关常量
|
||||||
|
MAX_CLASSES: t.CDefine = 512
|
||||||
|
MAX_FILE_DEPS: t.CDefine = 256
|
||||||
|
MAX_DEP_EDGES: t.CDefine = 16
|
||||||
|
SHA1_LEN: t.CDefine = 17
|
||||||
|
CLASS_NAME_LEN: t.CDefine = 64
|
||||||
|
|
||||||
|
# 拓扑排序使用扁平字节数组存储类信息和文件依赖,
|
||||||
|
# 避免结构体中的 str 指针字段在 mb.alloc 零填充时为 NULL 导致崩溃。
|
||||||
|
# 类名/父类名存储在 class_names_buf/parent_names_buf(每个 CLASS_NAME_LEN 字节),
|
||||||
|
# 定义 SHA1 存储在 def_sha1s_buf(每个 SHA1_LEN 字节)。
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _ScanClassInheritance - 预扫描 includes 文件,收集类继承关系
|
||||||
|
#
|
||||||
|
# 遍历所有可达 includes 文件,解析 AST 收集 ClassDef 的类名和父类名。
|
||||||
|
# 结果存入扁平字节数组,返回收集到的类数量。
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# mb: 内存池
|
||||||
|
# result: IncludesScanner 扫描结果
|
||||||
|
# reachable_set: 可达 SHA1 集合
|
||||||
|
# reachable_count: 可达 SHA1 数量
|
||||||
|
# use_reachable: 是否使用可达集合过滤
|
||||||
|
# sha1_set: SHA1 集合(use_reachable=0 时使用)
|
||||||
|
# set_count: SHA1 集合数量
|
||||||
|
# class_names_buf: 类名扁平数组(每个 CLASS_NAME_LEN 字节,连续内存)
|
||||||
|
# parent_names_buf: 父类名扁平数组(每个 CLASS_NAME_LEN 字节,无父类填 '\0')
|
||||||
|
# def_sha1s_buf: 定义 SHA1 扁平数组(每个 SHA1_LEN 字节)
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# 收集到的类数量,-1 失败
|
||||||
|
# ============================================================
|
||||||
|
def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||||
|
result: IncludesScanner.ScanResult | t.CPtr,
|
||||||
|
reachable_set: str, reachable_count: int,
|
||||||
|
use_reachable: int,
|
||||||
|
sha1_set: str, set_count: int,
|
||||||
|
class_names_buf: bytes,
|
||||||
|
parent_names_buf: bytes,
|
||||||
|
def_sha1s_buf: bytes) -> int:
|
||||||
|
"""预扫描 includes 文件,收集类继承关系"""
|
||||||
|
if result is None or class_names_buf is None or parent_names_buf is None or def_sha1s_buf is None:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||||
|
class_count: int = 0
|
||||||
|
|
||||||
|
for i in range(result.Count):
|
||||||
|
entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
|
||||||
|
entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||||
|
if entry is None or entry.Sha1 is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sha1_e: str = entry.Sha1
|
||||||
|
|
||||||
|
# 按需翻译过滤
|
||||||
|
in_set: int = 0
|
||||||
|
if use_reachable != 0:
|
||||||
|
in_set = StubMerger._is_in_sha1_set(sha1_e, reachable_set, reachable_count)
|
||||||
|
else:
|
||||||
|
in_set = StubMerger._is_in_sha1_set(sha1_e, sha1_set, set_count)
|
||||||
|
if in_set == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 读取文件
|
||||||
|
file_path: str = entry.Path
|
||||||
|
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||||
|
if f.closed:
|
||||||
|
continue
|
||||||
|
|
||||||
|
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||||
|
if src_buf is None:
|
||||||
|
f.close()
|
||||||
|
continue
|
||||||
|
|
||||||
|
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
||||||
|
f.close()
|
||||||
|
if bytes_read <= 0:
|
||||||
|
stdlib.free(src_buf)
|
||||||
|
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)
|
||||||
|
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:
|
||||||
|
stdlib.free(src_buf)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 遍历 AST 顶层节点,收集 ClassDef
|
||||||
|
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||||
|
if ch is not None:
|
||||||
|
cn: t.CSizeT = ch.__len__()
|
||||||
|
for ci in range(cn):
|
||||||
|
child: ast.AST | t.CPtr = ch.get(ci)
|
||||||
|
if child is None:
|
||||||
|
continue
|
||||||
|
kd: int = child.kind()
|
||||||
|
if kd != ast.ASTKind.ClassDef:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cd: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
|
||||||
|
if cd is None or cd.name is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if class_count >= MAX_CLASSES:
|
||||||
|
break
|
||||||
|
|
||||||
|
# 填充扁平数组:类名(偏移 = class_count * CLASS_NAME_LEN)
|
||||||
|
name_dst: str = class_names_buf + class_count * CLASS_NAME_LEN
|
||||||
|
nm_len: t.CSizeT = string.strlen(cd.name)
|
||||||
|
if nm_len >= CLASS_NAME_LEN:
|
||||||
|
string.strncpy(name_dst, cd.name, CLASS_NAME_LEN - 1)
|
||||||
|
name_dst[CLASS_NAME_LEN - 1] = '\0'
|
||||||
|
else:
|
||||||
|
string.strcpy(name_dst, cd.name)
|
||||||
|
|
||||||
|
# 填充扁平数组:父类名(无父类填 '\0')
|
||||||
|
parent_dst: str = parent_names_buf + class_count * CLASS_NAME_LEN
|
||||||
|
parent_dst[0] = '\0'
|
||||||
|
parent_nm: str = HandlesClassDef._get_parent_class(cd, None)
|
||||||
|
# parent_nm 是 AST 节点内部指针,不需要释放
|
||||||
|
if parent_nm is not None:
|
||||||
|
pnm_len: t.CSizeT = string.strlen(parent_nm)
|
||||||
|
if pnm_len >= CLASS_NAME_LEN:
|
||||||
|
string.strncpy(parent_dst, parent_nm, CLASS_NAME_LEN - 1)
|
||||||
|
parent_dst[CLASS_NAME_LEN - 1] = '\0'
|
||||||
|
else:
|
||||||
|
string.strcpy(parent_dst, parent_nm)
|
||||||
|
|
||||||
|
# 填充扁平数组:定义 SHA1(偏移 = class_count * SHA1_LEN)
|
||||||
|
sha1_dst: str = def_sha1s_buf + class_count * SHA1_LEN
|
||||||
|
string.strcpy(sha1_dst, sha1_e)
|
||||||
|
|
||||||
|
class_count += 1
|
||||||
|
|
||||||
|
stdlib.free(src_buf)
|
||||||
|
|
||||||
|
return class_count
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _FindClassDefSha1 - 在扁平数组中查找类名对应的定义文件 SHA1
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# class_names_buf: 类名扁平数组
|
||||||
|
# def_sha1s_buf: 定义 SHA1 扁平数组
|
||||||
|
# class_count: 类数量
|
||||||
|
# class_name: 要查找的类名
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# SHA1 字符串指针(指向 def_sha1s_buf 内部偏移),None 未找到
|
||||||
|
# ============================================================
|
||||||
|
def _FindClassDefSha1(class_names_buf: bytes, def_sha1s_buf: bytes,
|
||||||
|
class_count: int, class_name: str) -> str:
|
||||||
|
"""查找类名对应的定义文件 SHA1"""
|
||||||
|
if class_names_buf is None or def_sha1s_buf is None or class_name is None:
|
||||||
|
return None
|
||||||
|
for i in range(class_count):
|
||||||
|
name_ptr: str = class_names_buf + i * CLASS_NAME_LEN
|
||||||
|
if string.strcmp(name_ptr, class_name) == 0:
|
||||||
|
return def_sha1s_buf + i * SHA1_LEN
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _TopoSortFiles - 根据类继承关系对文件进行拓扑排序
|
||||||
|
#
|
||||||
|
# 算法(Kahn):
|
||||||
|
# 1. 从扁平类信息数组构建"文件 SHA1 → 依赖文件 SHA1 集合"映射
|
||||||
|
# 2. 计算每个文件的入度(依赖数量)
|
||||||
|
# 3. 入度为 0 的文件先处理,处理后减少依赖它的文件入度
|
||||||
|
# 4. 重复直到所有文件处理完成
|
||||||
|
#
|
||||||
|
# 注意:依赖方向是"父类所在文件 → 子类所在文件",
|
||||||
|
# 即父类文件必须先处理。Kahn 用 DepCount 作为剩余依赖计数,
|
||||||
|
# 依赖为 0 的先处理,初始化 InDegree = DepCount。
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# mb: 内存池
|
||||||
|
# result: IncludesScanner 扫描结果
|
||||||
|
# reachable_set: 可达 SHA1 集合
|
||||||
|
# reachable_count: 可达 SHA1 数量
|
||||||
|
# use_reachable: 是否使用可达集合过滤
|
||||||
|
# sha1_set: SHA1 集合
|
||||||
|
# set_count: SHA1 集合数量
|
||||||
|
# class_names_buf: 类名扁平数组
|
||||||
|
# parent_names_buf: 父类名扁平数组
|
||||||
|
# def_sha1s_buf: 定义 SHA1 扁平数组
|
||||||
|
# class_count: 类数量
|
||||||
|
# out_order: 输出拓扑顺序的文件索引数组(调用者分配,int 数组)
|
||||||
|
# out_count: 输出文件数量
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# 0 成功,-1 失败
|
||||||
|
# ============================================================
|
||||||
|
def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||||
|
result: IncludesScanner.ScanResult | t.CPtr,
|
||||||
|
reachable_set: str, reachable_count: int,
|
||||||
|
use_reachable: int,
|
||||||
|
sha1_set: str, set_count: int,
|
||||||
|
class_names_buf: bytes, parent_names_buf: bytes,
|
||||||
|
def_sha1s_buf: bytes, class_count: int,
|
||||||
|
out_order: t.CPtr, out_count: t.CPtr) -> int:
|
||||||
|
"""根据类继承关系对文件进行拓扑排序"""
|
||||||
|
if result is None or out_order is None or out_count is None:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
entry_size: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||||
|
|
||||||
|
# 1. 分配扁平数组:文件 SHA1、依赖 SHA1 列表、依赖数量、入度、处理状态
|
||||||
|
# 用扁平数组代替 FileDepEntry 结构体,避免 str 指针字段 NULL 崩溃
|
||||||
|
file_sha1s_buf: bytes = mb.alloc(MAX_FILE_DEPS * SHA1_LEN)
|
||||||
|
file_deps_buf: bytes = mb.alloc(MAX_FILE_DEPS * MAX_DEP_EDGES * SHA1_LEN)
|
||||||
|
file_dep_counts: t.CPtr = mb.alloc(MAX_FILE_DEPS * 4)
|
||||||
|
file_indegrees: t.CPtr = mb.alloc(MAX_FILE_DEPS * 4)
|
||||||
|
file_processed: t.CPtr = mb.alloc(MAX_FILE_DEPS * 4)
|
||||||
|
|
||||||
|
if file_sha1s_buf is None or file_deps_buf is None or file_dep_counts is None or file_indegrees is None or file_processed is None:
|
||||||
|
if file_sha1s_buf is not None:
|
||||||
|
mb.free(file_sha1s_buf)
|
||||||
|
if file_deps_buf is not None:
|
||||||
|
mb.free(file_deps_buf)
|
||||||
|
if file_dep_counts is not None:
|
||||||
|
mb.free(file_dep_counts)
|
||||||
|
if file_indegrees is not None:
|
||||||
|
mb.free(file_indegrees)
|
||||||
|
if file_processed is not None:
|
||||||
|
mb.free(file_processed)
|
||||||
|
return -1
|
||||||
|
|
||||||
|
string.memset(file_sha1s_buf, 0, MAX_FILE_DEPS * SHA1_LEN)
|
||||||
|
string.memset(file_deps_buf, 0, MAX_FILE_DEPS * MAX_DEP_EDGES * SHA1_LEN)
|
||||||
|
string.memset(file_dep_counts, 0, MAX_FILE_DEPS * 4)
|
||||||
|
string.memset(file_indegrees, 0, MAX_FILE_DEPS * 4)
|
||||||
|
string.memset(file_processed, 0, MAX_FILE_DEPS * 4)
|
||||||
|
|
||||||
|
file_count: int = 0
|
||||||
|
# sha1→file_index 映射(简单线性查找,文件数不多)
|
||||||
|
for i in range(result.Count):
|
||||||
|
entry_addr: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
|
||||||
|
entry: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||||
|
if entry is None or entry.Sha1 is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sha1_e: str = entry.Sha1
|
||||||
|
in_set: int = 0
|
||||||
|
if use_reachable != 0:
|
||||||
|
in_set = StubMerger._is_in_sha1_set(sha1_e, reachable_set, reachable_count)
|
||||||
|
else:
|
||||||
|
in_set = StubMerger._is_in_sha1_set(sha1_e, sha1_set, set_count)
|
||||||
|
if in_set == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if file_count >= MAX_FILE_DEPS:
|
||||||
|
break
|
||||||
|
|
||||||
|
# 初始化扁平数组:文件 SHA1(偏移 = file_count * SHA1_LEN)
|
||||||
|
# DepCount/InDegree/Processed 已由 memset 清零
|
||||||
|
sha1_dst: str = file_sha1s_buf + file_count * SHA1_LEN
|
||||||
|
string.strcpy(sha1_dst, sha1_e)
|
||||||
|
|
||||||
|
file_count += 1
|
||||||
|
|
||||||
|
# 2. 构建依赖边:对每个类,找到父类定义所在文件,建立 子文件→父文件 依赖
|
||||||
|
for ci in range(class_count):
|
||||||
|
# 读取父类名(偏移 = ci * CLASS_NAME_LEN)
|
||||||
|
parent_ptr: str = parent_names_buf + ci * CLASS_NAME_LEN
|
||||||
|
if parent_ptr[0] == '\0':
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 读取子类定义 SHA1(偏移 = ci * SHA1_LEN)
|
||||||
|
child_def_sha1: str = def_sha1s_buf + ci * SHA1_LEN
|
||||||
|
|
||||||
|
# 查找父类定义所在文件的 SHA1
|
||||||
|
parent_sha1: str = _FindClassDefSha1(class_names_buf, def_sha1s_buf, class_count, parent_ptr)
|
||||||
|
if parent_sha1 is None:
|
||||||
|
continue # 父类不在 includes 中(如 Object、CEnum 等标记基类)
|
||||||
|
|
||||||
|
# 父类文件 SHA1 不能等于子类文件 SHA1(同文件内继承不需要依赖)
|
||||||
|
if string.strcmp(parent_sha1, child_def_sha1) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 找到子类文件对应的索引,添加父文件 SHA1 到依赖列表
|
||||||
|
for fi in range(file_count):
|
||||||
|
fsha1: str = file_sha1s_buf + fi * SHA1_LEN
|
||||||
|
if string.strcmp(fsha1, child_def_sha1) != 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 读取当前依赖数量
|
||||||
|
cnt_addr: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi * 4
|
||||||
|
cnt_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr, t.CPtr))
|
||||||
|
if cnt_ptr is None:
|
||||||
|
break
|
||||||
|
cur_cnt: int = cnt_ptr[0]
|
||||||
|
|
||||||
|
# 检查依赖是否已添加(去重)
|
||||||
|
already: int = 0
|
||||||
|
for di in range(cur_cnt):
|
||||||
|
dep_slot: str = file_deps_buf + fi * MAX_DEP_EDGES * SHA1_LEN + di * SHA1_LEN
|
||||||
|
if string.strcmp(dep_slot, parent_sha1) == 0:
|
||||||
|
already = 1
|
||||||
|
break
|
||||||
|
if already != 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
if cur_cnt < MAX_DEP_EDGES:
|
||||||
|
dep_dst: str = file_deps_buf + fi * MAX_DEP_EDGES * SHA1_LEN + cur_cnt * SHA1_LEN
|
||||||
|
string.strcpy(dep_dst, parent_sha1)
|
||||||
|
cnt_ptr[0] = cur_cnt + 1
|
||||||
|
break
|
||||||
|
|
||||||
|
# 3. Kahn 算法:InDegree = DepCount(依赖多少个父文件)
|
||||||
|
# 依赖为 0 的先处理,处理后减少依赖它的文件入度
|
||||||
|
for fi in range(file_count):
|
||||||
|
cnt_addr3: t.CUInt64T = t.CUInt64T(file_dep_counts) + fi * 4
|
||||||
|
cnt_ptr3: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr3, t.CPtr))
|
||||||
|
ind_addr3: t.CUInt64T = t.CUInt64T(file_indegrees) + fi * 4
|
||||||
|
ind_ptr3: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr3, t.CPtr))
|
||||||
|
if cnt_ptr3 is not None and ind_ptr3 is not None:
|
||||||
|
ind_ptr3[0] = cnt_ptr3[0]
|
||||||
|
|
||||||
|
# 4. 拓扑排序输出
|
||||||
|
out_idx: int = 0
|
||||||
|
changed: int = 1
|
||||||
|
while changed != 0:
|
||||||
|
changed = 0
|
||||||
|
for fi in range(file_count):
|
||||||
|
# 检查处理状态
|
||||||
|
proc_addr4: t.CUInt64T = t.CUInt64T(file_processed) + fi * 4
|
||||||
|
proc_ptr4: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr4, t.CPtr))
|
||||||
|
if proc_ptr4 is None or proc_ptr4[0] != 0:
|
||||||
|
continue
|
||||||
|
# 检查入度
|
||||||
|
ind_addr4: t.CUInt64T = t.CUInt64T(file_indegrees) + fi * 4
|
||||||
|
ind_ptr4: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr4, t.CPtr))
|
||||||
|
if ind_ptr4 is None or ind_ptr4[0] > 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 入度为 0,可以处理
|
||||||
|
# 找到对应的 result.Entries 索引
|
||||||
|
target_sha1: str = file_sha1s_buf + fi * SHA1_LEN
|
||||||
|
for ri in range(result.Count):
|
||||||
|
ea_r: t.CUInt64T = t.CUInt64T(result.Entries) + ri * entry_size
|
||||||
|
ent_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_r, t.CPtr))
|
||||||
|
if ent_r is not None and ent_r.Sha1 is not None:
|
||||||
|
if string.strcmp(ent_r.Sha1, target_sha1) == 0:
|
||||||
|
# 写入输出索引数组
|
||||||
|
out_idx_addr: t.CUInt64T = t.CUInt64T(out_order) + out_idx * 4
|
||||||
|
out_int_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_idx_addr, t.CPtr))
|
||||||
|
if out_int_ptr is not None:
|
||||||
|
out_int_ptr[0] = ri
|
||||||
|
out_idx += 1
|
||||||
|
break
|
||||||
|
|
||||||
|
# 标记已处理
|
||||||
|
proc_ptr4[0] = 1
|
||||||
|
changed = 1
|
||||||
|
|
||||||
|
# 减少依赖该文件的其他文件的入度
|
||||||
|
for fj in range(file_count):
|
||||||
|
proc_addr5: t.CUInt64T = t.CUInt64T(file_processed) + fj * 4
|
||||||
|
proc_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr5, t.CPtr))
|
||||||
|
if proc_ptr5 is None or proc_ptr5[0] != 0:
|
||||||
|
continue
|
||||||
|
# 读取 fj 的依赖数量
|
||||||
|
cnt_addr5: t.CUInt64T = t.CUInt64T(file_dep_counts) + fj * 4
|
||||||
|
cnt_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(cnt_addr5, t.CPtr))
|
||||||
|
if cnt_ptr5 is None:
|
||||||
|
continue
|
||||||
|
fj_dep_cnt: int = cnt_ptr5[0]
|
||||||
|
for di in range(fj_dep_cnt):
|
||||||
|
dep_slot5: str = file_deps_buf + fj * MAX_DEP_EDGES * SHA1_LEN + di * SHA1_LEN
|
||||||
|
if string.strcmp(dep_slot5, target_sha1) == 0:
|
||||||
|
ind_addr5: t.CUInt64T = t.CUInt64T(file_indegrees) + fj * 4
|
||||||
|
ind_ptr5: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(ind_addr5, t.CPtr))
|
||||||
|
if ind_ptr5 is not None:
|
||||||
|
ind_ptr5[0] = ind_ptr5[0] - 1
|
||||||
|
break
|
||||||
|
|
||||||
|
# 处理循环依赖(未处理的文件按原顺序追加)
|
||||||
|
if out_idx < file_count:
|
||||||
|
for fi in range(file_count):
|
||||||
|
proc_addr6: t.CUInt64T = t.CUInt64T(file_processed) + fi * 4
|
||||||
|
proc_ptr6: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(proc_addr6, t.CPtr))
|
||||||
|
if proc_ptr6 is None or proc_ptr6[0] != 0:
|
||||||
|
continue
|
||||||
|
target_sha1_2: str = file_sha1s_buf + fi * SHA1_LEN
|
||||||
|
for ri in range(result.Count):
|
||||||
|
ea_r2: t.CUInt64T = t.CUInt64T(result.Entries) + ri * entry_size
|
||||||
|
ent_r2: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_r2, t.CPtr))
|
||||||
|
if ent_r2 is not None and ent_r2.Sha1 is not None:
|
||||||
|
if string.strcmp(ent_r2.Sha1, target_sha1_2) == 0:
|
||||||
|
out_idx_addr2: t.CUInt64T = t.CUInt64T(out_order) + out_idx * 4
|
||||||
|
out_int_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_idx_addr2, t.CPtr))
|
||||||
|
if out_int_ptr2 is not None:
|
||||||
|
out_int_ptr2[0] = ri
|
||||||
|
out_idx += 1
|
||||||
|
break
|
||||||
|
proc_ptr6[0] = 1
|
||||||
|
|
||||||
|
# 写入输出数量
|
||||||
|
out_count_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(out_count, t.CPtr))
|
||||||
|
if out_count_ptr is not None:
|
||||||
|
out_count_ptr[0] = out_idx
|
||||||
|
|
||||||
|
# 释放扁平数组
|
||||||
|
mb.free(file_sha1s_buf)
|
||||||
|
mb.free(file_deps_buf)
|
||||||
|
mb.free(file_dep_counts)
|
||||||
|
mb.free(file_indegrees)
|
||||||
|
mb.free(file_processed)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# RunPhase1 - Phase1: 扫描 includes 目录,按需翻译并生成 stub
|
# RunPhase1 - Phase1: 扫描 includes 目录,按需翻译并生成 stub
|
||||||
@@ -51,9 +477,12 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
log: VLogger.Logger | t.CPtr) -> int:
|
log: VLogger.Logger | t.CPtr) -> int:
|
||||||
"""Phase1: 扫描 includes 目录,按需翻译并生成 stub"""
|
"""Phase1: 扫描 includes 目录,按需翻译并生成 stub"""
|
||||||
if includes_dir is None or temp_dir is None:
|
if includes_dir is None or temp_dir is None:
|
||||||
stdio.printf("[Phase1] includes_dir 或 temp_dir 为空,跳过\n")
|
VLogger.warning("includes_dir 或 temp_dir 为空,跳过", "Phase1")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
# 设置全局 temp_dir(供跨模块 CDefine 查找使用)
|
||||||
|
HandlesType.set_temp_dir(temp_dir)
|
||||||
|
|
||||||
# 确保 temp 目录存在(build_dir/temp 可能尚未创建)
|
# 确保 temp 目录存在(build_dir/temp 可能尚未创建)
|
||||||
BuildPipeline.ensure_dir(temp_dir)
|
BuildPipeline.ensure_dir(temp_dir)
|
||||||
|
|
||||||
@@ -63,25 +492,35 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
# 扫描 includes 目录
|
# 扫描 includes 目录
|
||||||
result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
|
result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
|
||||||
if result is None:
|
if result is None:
|
||||||
stdio.printf("[Phase1] 扫描失败\n")
|
VLogger.error("扫描失败", "Phase1")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# 读取 _sha1_map.txt 获取需要的 includes SHA1 集合
|
# 从扫描结果直接构建 SHA1 集合(不依赖 _sha1_map.txt 文件)
|
||||||
# 优先使用 Projectrans.py 生成的 _sha1_map.txt(含依赖分析,只包含需要的 includes)
|
# Phase1 作为编译器自身,应从内存中的扫描结果获取 SHA1,避免外部文件依赖
|
||||||
# 若不存在,则从扫描结果生成(包含所有 includes,可能导致结构体表溢出)
|
|
||||||
sha1_set: str = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17)
|
sha1_set: str = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17)
|
||||||
if sha1_set is None:
|
if sha1_set is None:
|
||||||
stdio.printf("[Phase1] sha1_set 分配失败\n")
|
VLogger.error("sha1_set 分配失败", "Phase1")
|
||||||
return 1
|
return 1
|
||||||
string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
|
string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
|
||||||
set_count: int = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set)
|
set_count: int = 0
|
||||||
|
p1_entry_size_init: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||||
|
for se_i in range(result.Count):
|
||||||
|
if set_count >= StubMerger.MAX_INCLUDES_SHA1:
|
||||||
|
break
|
||||||
|
se_addr: t.CUInt64T = t.CUInt64T(result.Entries) + se_i * p1_entry_size_init
|
||||||
|
se_ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(se_addr, t.CPtr))
|
||||||
|
if se_ent is None or se_ent.Sha1 is None:
|
||||||
|
continue
|
||||||
|
string.strcpy(sha1_set + set_count * 17, se_ent.Sha1)
|
||||||
|
set_count += 1
|
||||||
if set_count <= 0:
|
if set_count <= 0:
|
||||||
stdio.printf("[Phase1] _sha1_map.txt 不存在或为空,从扫描结果生成\n")
|
VLogger.warning("扫描结果无有效 SHA1,跳过 Phase1(项目可能无 includes 依赖)", "Phase1")
|
||||||
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, None, 0)
|
stdlib.free(sha1_set)
|
||||||
set_count = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set)
|
return 0
|
||||||
if set_count < 0:
|
# 写入 _sha1_map.txt(人类可读输出,程序内部不读取;机器分析使用 PopulateSha1MapStore 内存存储器)
|
||||||
stdio.printf("[Phase1] 无法加载 _sha1_map.txt,跳过 Phase1\n")
|
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, None, 0)
|
||||||
return 1
|
# 填充全局 SHA1 映射存储器(内存中,不依赖 _sha1_map.txt 文件)
|
||||||
|
StubMerger.PopulateSha1MapStore(result)
|
||||||
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
|
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
|
||||||
td_len_p1map: t.CSizeT = string.strlen(temp_dir)
|
td_len_p1map: t.CSizeT = string.strlen(temp_dir)
|
||||||
p1_sha1_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
p1_sha1_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
|
||||||
@@ -172,6 +611,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
tr_a._declare_only = 2
|
tr_a._declare_only = 2
|
||||||
tr_a.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_a.RelPath)
|
tr_a.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_a.RelPath)
|
||||||
HandlesType.set_current_file(file_path_a)
|
HandlesType.set_current_file(file_path_a)
|
||||||
|
HandlesType.set_current_module_sha1(sha1_a)
|
||||||
HandlesType.clear_cdefine_constants()
|
HandlesType.clear_cdefine_constants()
|
||||||
HandlesStruct.reset_visible_structs(mb, 0)
|
HandlesStruct.reset_visible_structs(mb, 0)
|
||||||
ret_a: int = tr_a.translate(tree_a)
|
ret_a: int = tr_a.translate(tree_a)
|
||||||
@@ -235,13 +675,69 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
# 前面就需要用。Phase 1a 先注册所有 struct/enum/union 到全局表,
|
# 前面就需要用。Phase 1a 先注册所有 struct/enum/union 到全局表,
|
||||||
# Phase 1b 全量翻译时 struct 已注册,走 existing 路径只翻译方法体。
|
# Phase 1b 全量翻译时 struct 已注册,走 existing 路径只翻译方法体。
|
||||||
# 只处理可达文件,避免翻译不需要的 includes(如 Test 不依赖 ast 模块)。
|
# 只处理可达文件,避免翻译不需要的 includes(如 Test 不依赖 ast 模块)。
|
||||||
|
#
|
||||||
|
# 拓扑排序:预扫描所有文件收集类继承关系,按依赖顺序处理文件,
|
||||||
|
# 确保父类所在文件先于子类所在文件处理(如 base.py 先于 astaux.py)。
|
||||||
# ============================================================
|
# ============================================================
|
||||||
p1a_reg: int = 0
|
p1a_reg: int = 0
|
||||||
p1a_skp: int = 0
|
p1a_skp: int = 0
|
||||||
p1a_fl: int = 0
|
p1a_fl: int = 0
|
||||||
|
|
||||||
for i in range(result.Count):
|
# 预扫描类继承关系,构建拓扑顺序(用扁平字节数组,避免结构体 str 指针 NULL 崩溃)
|
||||||
entry_addr_r: t.CUInt64T = t.CUInt64T(result.Entries) + i * entry_size
|
class_names_buf: bytes = mb.alloc(MAX_CLASSES * CLASS_NAME_LEN)
|
||||||
|
parent_names_buf: bytes = mb.alloc(MAX_CLASSES * CLASS_NAME_LEN)
|
||||||
|
def_sha1s_buf: bytes = mb.alloc(MAX_CLASSES * SHA1_LEN)
|
||||||
|
topo_order: t.CPtr = mb.alloc(4 * MAX_FILE_DEPS)
|
||||||
|
topo_count_box: t.CPtr = mb.alloc(4)
|
||||||
|
topo_count: int = 0
|
||||||
|
|
||||||
|
if class_names_buf is not None and parent_names_buf is not None and def_sha1s_buf is not None and topo_order is not None and topo_count_box is not None:
|
||||||
|
string.memset(class_names_buf, 0, MAX_CLASSES * CLASS_NAME_LEN)
|
||||||
|
string.memset(parent_names_buf, 0, MAX_CLASSES * CLASS_NAME_LEN)
|
||||||
|
string.memset(def_sha1s_buf, 0, MAX_CLASSES * SHA1_LEN)
|
||||||
|
string.memset(topo_order, 0, 4 * MAX_FILE_DEPS)
|
||||||
|
string.memset(topo_count_box, 0, 4)
|
||||||
|
|
||||||
|
class_count_scanned: int = _ScanClassInheritance(
|
||||||
|
mb, result, reachable_set, reachable_count,
|
||||||
|
use_reachable, sha1_set, set_count,
|
||||||
|
class_names_buf, parent_names_buf, def_sha1s_buf)
|
||||||
|
|
||||||
|
if class_count_scanned > 0:
|
||||||
|
ret_topo: int = _TopoSortFiles(
|
||||||
|
mb, result, reachable_set, reachable_count,
|
||||||
|
use_reachable, sha1_set, set_count,
|
||||||
|
class_names_buf, parent_names_buf, def_sha1s_buf, class_count_scanned,
|
||||||
|
topo_order, topo_count_box)
|
||||||
|
if ret_topo == 0:
|
||||||
|
tc_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(topo_count_box, t.CPtr))
|
||||||
|
if tc_ptr is not None:
|
||||||
|
topo_count = tc_ptr[0]
|
||||||
|
fb_topo: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb_topo is not None:
|
||||||
|
viperlib.snprintf(fb_topo, 1024,
|
||||||
|
"拓扑排序: %d 个类, %d 个文件按依赖顺序处理",
|
||||||
|
class_count_scanned, topo_count)
|
||||||
|
VLogger.info(fb_topo, "Phase1")
|
||||||
|
else:
|
||||||
|
VLogger.warning("拓扑排序失败,回退到字母序", "Phase1")
|
||||||
|
topo_count = 0
|
||||||
|
else:
|
||||||
|
VLogger.warning("类继承预扫描无结果,回退到字母序", "Phase1")
|
||||||
|
topo_count = 0
|
||||||
|
|
||||||
|
# 遍历文件:优先使用拓扑顺序,回退到字母序
|
||||||
|
iter_count: int = topo_count if topo_count > 0 else result.Count
|
||||||
|
for i in range(iter_count):
|
||||||
|
# 获取文件索引:拓扑顺序或字母序
|
||||||
|
file_idx: int = i
|
||||||
|
if topo_count > 0:
|
||||||
|
od_addr: t.CUInt64T = t.CUInt64T(topo_order) + i * 4
|
||||||
|
od_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(od_addr, t.CPtr))
|
||||||
|
if od_ptr is not None:
|
||||||
|
file_idx = od_ptr[0]
|
||||||
|
|
||||||
|
entry_addr_r: t.CUInt64T = t.CUInt64T(result.Entries) + file_idx * entry_size
|
||||||
entry_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_r, t.CPtr))
|
entry_r: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(entry_addr_r, t.CPtr))
|
||||||
if entry_r is None:
|
if entry_r is None:
|
||||||
p1a_fl += 1
|
p1a_fl += 1
|
||||||
@@ -252,15 +748,16 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
p1a_fl += 1
|
p1a_fl += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 按需翻译过滤:只处理可达文件
|
# 按需翻译过滤(拓扑排序已过滤,但字母序回退需要检查)
|
||||||
if use_reachable != 0:
|
if topo_count == 0:
|
||||||
if StubMerger._is_in_sha1_set(sha1_r, reachable_set, reachable_count) == 0:
|
if use_reachable != 0:
|
||||||
p1a_skp += 1
|
if StubMerger._is_in_sha1_set(sha1_r, reachable_set, reachable_count) == 0:
|
||||||
continue
|
p1a_skp += 1
|
||||||
else:
|
continue
|
||||||
if StubMerger._is_in_sha1_set(sha1_r, sha1_set, set_count) == 0:
|
else:
|
||||||
p1a_skp += 1
|
if StubMerger._is_in_sha1_set(sha1_r, sha1_set, set_count) == 0:
|
||||||
continue
|
p1a_skp += 1
|
||||||
|
continue
|
||||||
|
|
||||||
# 读取文件内容
|
# 读取文件内容
|
||||||
file_path_r: str = entry_r.Path
|
file_path_r: str = entry_r.Path
|
||||||
@@ -310,6 +807,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
tr_r._declare_only = 1
|
tr_r._declare_only = 1
|
||||||
tr_r.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_r.RelPath)
|
tr_r.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry_r.RelPath)
|
||||||
HandlesType.set_current_file(file_path_r)
|
HandlesType.set_current_file(file_path_r)
|
||||||
|
HandlesType.set_current_module_sha1(sha1_r)
|
||||||
HandlesType.clear_cdefine_constants()
|
HandlesType.clear_cdefine_constants()
|
||||||
HandlesStruct.reset_visible_structs(mb, 0)
|
HandlesStruct.reset_visible_structs(mb, 0)
|
||||||
ret_r: int = tr_r.translate(tree_r)
|
ret_r: int = tr_r.translate(tree_r)
|
||||||
@@ -325,6 +823,18 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
stdlib.free(tr_r._nonlocal_names)
|
stdlib.free(tr_r._nonlocal_names)
|
||||||
stdlib.free(src_buf_r)
|
stdlib.free(src_buf_r)
|
||||||
|
|
||||||
|
# 释放拓扑排序资源
|
||||||
|
if class_names_buf is not None:
|
||||||
|
mb.free(class_names_buf)
|
||||||
|
if parent_names_buf is not None:
|
||||||
|
mb.free(parent_names_buf)
|
||||||
|
if def_sha1s_buf is not None:
|
||||||
|
mb.free(def_sha1s_buf)
|
||||||
|
if topo_order is not None:
|
||||||
|
mb.free(topo_order)
|
||||||
|
if topo_count_box is not None:
|
||||||
|
mb.free(topo_count_box)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Phase 1b: 全量翻译(struct 已注册,走 existing 路径翻译方法体)
|
# Phase 1b: 全量翻译(struct 已注册,走 existing 路径翻译方法体)
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -380,12 +890,17 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
stdlib.free(text_path)
|
stdlib.free(text_path)
|
||||||
# text.ll 不存在,需要重新翻译
|
# text.ll 不存在,需要重新翻译
|
||||||
rp: str = entry.RelPath
|
rp: str = entry.RelPath
|
||||||
stdio.printf("[Phase1] text.ll 不存在,重新翻译: %s (sha1=%s)\n", rp, sha1)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "text.ll 不存在,重新翻译: %s (sha1=%s)", rp, sha1)
|
||||||
|
VLogger.info(fb, "Phase1")
|
||||||
else:
|
else:
|
||||||
# stub 不存在,需要翻译
|
# stub 不存在,需要翻译
|
||||||
rp: str = entry.RelPath
|
rp: str = entry.RelPath
|
||||||
stdio.printf("[Phase1] 翻译: %s (sha1=%s)\n", rp, sha1)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
stdio.fflush(0)
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "翻译: %s (sha1=%s)", rp, sha1)
|
||||||
|
VLogger.info(fb, "Phase1")
|
||||||
|
|
||||||
stdlib.free(stub_path)
|
stdlib.free(stub_path)
|
||||||
|
|
||||||
@@ -393,13 +908,17 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
file_path: str = entry.Path
|
file_path: str = entry.Path
|
||||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||||
if f is None:
|
if f is None:
|
||||||
stdio.printf("[Phase1] 无法打开(None): %s\n", file_path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
stdio.fflush(0)
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "无法打开(None): %s", file_path)
|
||||||
|
VLogger.error(fb, "Phase1")
|
||||||
failed += 1
|
failed += 1
|
||||||
continue
|
continue
|
||||||
if f.closed:
|
if f.closed:
|
||||||
stdio.printf("[Phase1] 无法打开: %s\n", file_path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
stdio.fflush(0)
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "无法打开: %s", file_path)
|
||||||
|
VLogger.error(fb, "Phase1")
|
||||||
failed += 1
|
failed += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -412,8 +931,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
||||||
f.close()
|
f.close()
|
||||||
if bytes_read <= 0:
|
if bytes_read <= 0:
|
||||||
stdio.printf("[Phase1] 读取失败: %s\n", file_path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
stdio.fflush(0)
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "读取失败: %s", file_path)
|
||||||
|
VLogger.error(fb, "Phase1")
|
||||||
stdlib.free(src_buf)
|
stdlib.free(src_buf)
|
||||||
failed += 1
|
failed += 1
|
||||||
continue
|
continue
|
||||||
@@ -423,6 +944,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
src_buf[SRC_BUF_SIZE - 1] = 0
|
src_buf[SRC_BUF_SIZE - 1] = 0
|
||||||
|
|
||||||
# 解析 AST
|
# 解析 AST
|
||||||
|
stdio.printf("[P1B-1] parse %s\n", entry.RelPath)
|
||||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||||
if lx is None:
|
if lx is None:
|
||||||
stdlib.free(src_buf)
|
stdlib.free(src_buf)
|
||||||
@@ -431,14 +953,18 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
ast._lexer_init(lx, src_buf, mb)
|
ast._lexer_init(lx, src_buf, mb)
|
||||||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||||||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||||||
|
stdio.printf("[P1B-1a] parse-done %s\n", entry.RelPath)
|
||||||
if tree is None:
|
if tree is None:
|
||||||
stdio.printf("[Phase1] AST 解析失败: %s\n", file_path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
stdio.fflush(0)
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "AST 解析失败: %s", file_path)
|
||||||
|
VLogger.error(fb, "Phase1")
|
||||||
stdlib.free(src_buf)
|
stdlib.free(src_buf)
|
||||||
failed += 1
|
failed += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 生成 .pyi 存根文件(直接遍历 AST,不依赖 PythonToStubConverter)
|
# 生成 .pyi 存根文件(直接遍历 AST,不依赖 PythonToStubConverter)
|
||||||
|
stdio.printf("[P1B-2] pyi %s\n", entry.RelPath)
|
||||||
pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE)
|
pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE)
|
||||||
if pyi_buf is not None:
|
if pyi_buf is not None:
|
||||||
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, PYI_BUF_SIZE)
|
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, PYI_BUF_SIZE)
|
||||||
@@ -453,6 +979,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
stdlib.free(pyi_buf)
|
stdlib.free(pyi_buf)
|
||||||
|
|
||||||
# 翻译 AST → LLVM IR
|
# 翻译 AST → LLVM IR
|
||||||
|
stdio.printf("[P1B-3] translate %s\n", entry.RelPath)
|
||||||
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
|
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
|
||||||
if tr is None:
|
if tr is None:
|
||||||
stdlib.free(src_buf)
|
stdlib.free(src_buf)
|
||||||
@@ -461,11 +988,16 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
tr.ModuleSha1 = sha1
|
tr.ModuleSha1 = sha1
|
||||||
tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry.RelPath)
|
tr.CurrentPackage = HandlesImports.compute_package_from_relpath(mb, entry.RelPath)
|
||||||
HandlesType.set_current_file(file_path)
|
HandlesType.set_current_file(file_path)
|
||||||
|
HandlesType.set_current_module_sha1(sha1)
|
||||||
HandlesType.clear_cdefine_constants()
|
HandlesType.clear_cdefine_constants()
|
||||||
HandlesStruct.reset_visible_structs(mb, 0)
|
HandlesStruct.reset_visible_structs(mb, 0)
|
||||||
ret: int = tr.translate(tree)
|
ret: int = tr.translate(tree)
|
||||||
|
stdio.printf("[P1B-3a] translate-done %s ret=%d\n", entry.RelPath, ret)
|
||||||
if ret != 0:
|
if ret != 0:
|
||||||
stdio.printf("[Phase1] 翻译失败: %s\n", file_path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "翻译失败: %s", file_path)
|
||||||
|
VLogger.error(fb, "Phase1")
|
||||||
stdlib.free(src_buf)
|
stdlib.free(src_buf)
|
||||||
if tr._global_names is not None:
|
if tr._global_names is not None:
|
||||||
stdlib.free(tr._global_names)
|
stdlib.free(tr._global_names)
|
||||||
@@ -475,7 +1007,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# dump stub IR (declarations only)
|
# dump stub IR (declarations only)
|
||||||
PHASE1_IR_SIZE: t.CSizeT = 262144
|
stdio.printf("[P1B-4] stub %s\n", entry.RelPath)
|
||||||
|
PHASE1_IR_SIZE: t.CSizeT = 1048576
|
||||||
stub_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE)
|
stub_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE)
|
||||||
if stub_buf is None:
|
if stub_buf is None:
|
||||||
stdlib.free(src_buf)
|
stdlib.free(src_buf)
|
||||||
@@ -500,6 +1033,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
stdlib.free(stub_buf)
|
stdlib.free(stub_buf)
|
||||||
|
|
||||||
# dump text IR (definitions only)
|
# dump text IR (definitions only)
|
||||||
|
stdio.printf("[P1B-5] text %s\n", entry.RelPath)
|
||||||
text_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE)
|
text_buf: bytes = stdlib.malloc(PHASE1_IR_SIZE)
|
||||||
if text_buf is None:
|
if text_buf is None:
|
||||||
stdlib.free(src_buf)
|
stdlib.free(src_buf)
|
||||||
@@ -544,7 +1078,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
|||||||
|
|
||||||
translated += 1
|
translated += 1
|
||||||
|
|
||||||
stdio.printf("[Phase1] 完成: 翻译=%d 跳过=%d 失败=%d\n", translated, skipped, failed)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "完成: 翻译=%d 跳过=%d 失败=%d", translated, skipped, failed)
|
||||||
|
VLogger.info(fb, "Phase1")
|
||||||
|
|
||||||
# 释放可达 SHA1 集合(如果分配了)
|
# 释放可达 SHA1 集合(如果分配了)
|
||||||
if reachable_set is not None:
|
if reachable_set is not None:
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import lib.core.VLogger as VLogger
|
|||||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||||
import lib.core.Handles.HandlesImports as HandlesImports
|
import lib.core.Handles.HandlesImports as HandlesImports
|
||||||
|
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||||
import lib.core.BuildPipeline as BuildPipeline
|
import lib.core.BuildPipeline as BuildPipeline
|
||||||
import lib.core.StubMerger as StubMerger
|
import lib.core.StubMerger as StubMerger
|
||||||
import lib.Projectrans.Utils as Utils
|
import lib.Projectrans.Utils as Utils
|
||||||
@@ -138,7 +139,10 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
ent.Path = full_path
|
ent.Path = full_path
|
||||||
ent.Sha1 = sha1_val
|
ent.Sha1 = sha1_val
|
||||||
file_count += 1
|
file_count += 1
|
||||||
stdio.printf("[project] %s (sha1=%s)\n", fname, sha1_val)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "%s (sha1=%s)", fname, sha1_val)
|
||||||
|
VLogger.info(fb, "project")
|
||||||
stdlib.free(sbuf)
|
stdlib.free(sbuf)
|
||||||
# full_path 不释放:ent.Path 引用它
|
# full_path 不释放:ent.Path 引用它
|
||||||
|
|
||||||
@@ -165,10 +169,16 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
Returns: 0 成功,非 0 失败
|
Returns: 0 成功,非 0 失败
|
||||||
"""
|
"""
|
||||||
if source_dir is None:
|
if source_dir is None:
|
||||||
stdio.printf("[project] source_dir 为空\n")
|
VLogger.error("source_dir 为空", "project")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
stdio.printf("[project] 多文件项目编译: %s\n", source_dir)
|
stdio.printf("[DBG] RunMultiFileProject enter src=%s\n", source_dir)
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir)
|
||||||
|
VLogger.info(fb, "project")
|
||||||
|
|
||||||
# === 1. 递归扫描 source_dir 下的 .py 文件(包括子目录)===
|
# === 1. 递归扫描 source_dir 下的 .py 文件(包括子目录)===
|
||||||
entry_size: t.CSizeT = SrcFileEntry.__sizeof__()
|
entry_size: t.CSizeT = SrcFileEntry.__sizeof__()
|
||||||
@@ -178,7 +188,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
string.memset(entries, 0, MAX_SRC_FILES * entry_size)
|
string.memset(entries, 0, MAX_SRC_FILES * entry_size)
|
||||||
|
|
||||||
file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES)
|
file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES)
|
||||||
stdio.printf("[project] 共 %d 个源文件\n", file_count)
|
stdio.printf("[DBG] scan done file_count=%d\n", file_count)
|
||||||
|
stdio.fflush(0)
|
||||||
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "共 %d 个源文件", file_count)
|
||||||
|
VLogger.info(fb, "project")
|
||||||
|
|
||||||
if file_count == 0:
|
if file_count == 0:
|
||||||
stdlib.free(entries)
|
stdlib.free(entries)
|
||||||
@@ -191,34 +206,47 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
BuildPipeline.ensure_dir(temp_dir)
|
BuildPipeline.ensure_dir(temp_dir)
|
||||||
BuildPipeline.ensure_dir(output_dir)
|
BuildPipeline.ensure_dir(output_dir)
|
||||||
|
|
||||||
# 追加 App 源文件 SHA1 到 _sha1_map.txt(供日志转存和符号查找使用)
|
# 追加 App 源文件 SHA1 到 _sha1_map.txt(人类可读输出,程序内部不读取此文件)
|
||||||
# 格式: {sha1}:App/{filename}\n (与 includes 条目格式对应)
|
# 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.py)
|
||||||
|
# 同步追加到内存存储器(AppendToSha1MapStore,供跨模块 CDefine 查找)
|
||||||
td_len_am: t.CSizeT = string.strlen(temp_dir)
|
td_len_am: t.CSizeT = string.strlen(temp_dir)
|
||||||
|
src_dir_len_am: t.CSizeT = string.strlen(source_dir)
|
||||||
map_path_am: bytes = stdlib.malloc(td_len_am + 32)
|
map_path_am: bytes = stdlib.malloc(td_len_am + 32)
|
||||||
if map_path_am is not None:
|
if map_path_am is not None:
|
||||||
viperlib.snprintf(map_path_am, td_len_am + 32, "%s/_sha1_map.txt", temp_dir)
|
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)
|
mf: fileio.File | t.CPtr = fileio.File(map_path_am, fileio.MODE.A)
|
||||||
|
line_am: bytes = stdlib.malloc(512)
|
||||||
|
# 先遍历一次填充内存存储器(不依赖文件 I/O),再写入 _sha1_map.txt
|
||||||
|
app_filled: int = 0
|
||||||
|
for i in range(file_count):
|
||||||
|
ea_am: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||||
|
ent_am: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_am, t.CPtr))
|
||||||
|
if ent_am is None or ent_am.Path is None or ent_am.Sha1 is None:
|
||||||
|
continue
|
||||||
|
# 计算相对路径(去除 source_dir 前缀,保留目录结构)
|
||||||
|
p_str: str = ent_am.Path
|
||||||
|
p_len: t.CSizeT = string.strlen(p_str)
|
||||||
|
rel_path_am: str = p_str
|
||||||
|
if p_len > src_dir_len_am + 1:
|
||||||
|
if string.strncmp(p_str, source_dir, src_dir_len_am) == 0:
|
||||||
|
rel_path_am = p_str + src_dir_len_am + 1
|
||||||
|
# 同步追加到内存存储器(供跨模块 CDefine 查找)
|
||||||
|
# rel_path_am 格式如 "lib/core/StubMerger.py",与 _sha1_map.txt 一致
|
||||||
|
if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) == 0:
|
||||||
|
app_filled += 1
|
||||||
|
# 写入 _sha1_map.txt(人类可读输出)
|
||||||
|
if not mf.closed and line_am is not None:
|
||||||
|
viperlib.snprintf(line_am, 512, "%s:%s\n", ent_am.Sha1, rel_path_am)
|
||||||
|
ll_am: t.CSizeT = string.strlen(line_am)
|
||||||
|
mf.write(line_am, ll_am)
|
||||||
|
if line_am is not None:
|
||||||
|
stdlib.free(line_am)
|
||||||
if not mf.closed:
|
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()
|
mf.close()
|
||||||
stdio.printf("[project] 已追加 %d 个 App 文件到 _sha1_map.txt\n", file_count)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "已追加 %d 个 App 文件到 _sha1_map.txt 和内存存储器", app_filled)
|
||||||
|
VLogger.info(fb, "project")
|
||||||
stdlib.free(map_path_am)
|
stdlib.free(map_path_am)
|
||||||
|
|
||||||
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
|
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
|
||||||
@@ -231,6 +259,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
# 追加用户源文件的 (模块名, SHA1) 到全局映射
|
# 追加用户源文件的 (模块名, SHA1) 到全局映射
|
||||||
# 使跨模块方法调用能通过 from_imports + _lookup_module_sha1 找到正确的 SHA1
|
# 使跨模块方法调用能通过 from_imports + _lookup_module_sha1 找到正确的 SHA1
|
||||||
if pb_sha1_arr is not None and pb_mod_arr is not None:
|
if pb_sha1_arr is not None and pb_mod_arr is not None:
|
||||||
|
src_dir_len_us: t.CSizeT = string.strlen(source_dir)
|
||||||
for i in range(file_count):
|
for i in range(file_count):
|
||||||
ea_us: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
ea_us: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||||
ent_us: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_us, t.CPtr))
|
ent_us: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_us, t.CPtr))
|
||||||
@@ -238,24 +267,26 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
continue
|
continue
|
||||||
if pb_inc_count >= StubMerger.MAX_INCLUDES:
|
if pb_inc_count >= StubMerger.MAX_INCLUDES:
|
||||||
break
|
break
|
||||||
# 从路径提取模块名(文件名去掉 .py 后缀)
|
# 计算相对路径并转换为点分模块名(保留完整包路径)
|
||||||
path_str: str = ent_us.Path
|
path_str: str = ent_us.Path
|
||||||
path_len: t.CSizeT = string.strlen(path_str)
|
path_len_us: t.CSizeT = string.strlen(path_str)
|
||||||
fname_start: t.CSizeT = 0
|
rel_path_us: str = path_str
|
||||||
for j in range(path_len):
|
if path_len_us > src_dir_len_us + 1:
|
||||||
if path_str[j] == '/' or path_str[j] == '\\':
|
if string.strncmp(path_str, source_dir, src_dir_len_us) == 0:
|
||||||
fname_start = j + 1
|
rel_path_us = path_str + src_dir_len_us + 1
|
||||||
mod_len: t.CSizeT = path_len - fname_start
|
# 使用 _PathToModuleName 转换为点分模块名(处理 __init__.py → 包名)
|
||||||
if mod_len < 4:
|
mod_name_us: str = StubMerger._PathToModuleName(rel_path_us)
|
||||||
|
if mod_name_us is None:
|
||||||
continue
|
continue
|
||||||
mod_len -= 3
|
|
||||||
if mod_len >= 64:
|
|
||||||
mod_len = 63
|
|
||||||
# 写入模块名
|
# 写入模块名
|
||||||
mod_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 64
|
mod_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 64
|
||||||
for k in range(mod_len):
|
mn_len_us: t.CSizeT = string.strlen(mod_name_us)
|
||||||
pb_mod_arr[mod_idx + k] = path_str[fname_start + k]
|
if mn_len_us >= 64:
|
||||||
pb_mod_arr[mod_idx + mod_len] = '\0'
|
string.strncpy(pb_mod_arr + mod_idx, mod_name_us, 63)
|
||||||
|
pb_mod_arr[mod_idx + 63] = '\0'
|
||||||
|
else:
|
||||||
|
string.strcpy(pb_mod_arr + mod_idx, mod_name_us)
|
||||||
|
stdlib.free(mod_name_us)
|
||||||
# 写入 SHA1
|
# 写入 SHA1
|
||||||
sha1_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 17
|
sha1_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 17
|
||||||
string.strcpy(pb_sha1_arr + sha1_idx, ent_us.Sha1)
|
string.strcpy(pb_sha1_arr + sha1_idx, ent_us.Sha1)
|
||||||
@@ -265,36 +296,60 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
|
|
||||||
# === 2. Phase A: 为每个文件生成 stub + text ===
|
# === 2. Phase A: 为每个文件生成 stub + text ===
|
||||||
if do_phase1 != 0:
|
if do_phase1 != 0:
|
||||||
|
stdio.printf("[DBG] before Phase A\n")
|
||||||
|
stdio.fflush(0)
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.banner("Phase A: 生成 stub + text")
|
log.banner("Phase A: 生成 stub + text")
|
||||||
|
|
||||||
# === Phase A-pre: 预注册所有源文件的 struct/enum/union ===
|
# === Phase A-pre: 预注册所有源文件的 struct/enum/union ===
|
||||||
# 解决循环引用问题:circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义
|
# 解决循环引用问题:circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义
|
||||||
# 仅注册 struct/enum/union(declare_only=1),不翻译方法体
|
# 仅注册 struct/enum/union(declare_only=1),不翻译方法体
|
||||||
stdio.printf("[Phase A-pre] 预注册 struct/enum/union...\n")
|
# 多遍扫描:解决跨文件继承的字母序问题(如 HandlesAnnAssign.py 在 HandlesBase.py 之前,
|
||||||
|
# AnnAssignHandle 继承 Mixin 时 Mixin 未注册)。每遍注册新类后,下一遍子类可继承。
|
||||||
|
VLogger.info("预注册 struct/enum/union...", "PhaseA")
|
||||||
src_dir_len_pre: t.CSizeT = string.strlen(source_dir)
|
src_dir_len_pre: t.CSizeT = string.strlen(source_dir)
|
||||||
for i in range(file_count):
|
PHASE_A_PRE_MAX_PASSES: t.CInt = 3
|
||||||
ea_pre: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
for pass_i in range(PHASE_A_PRE_MAX_PASSES):
|
||||||
ent_pre: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pre, t.CPtr))
|
struct_count_before: int = HandlesStruct.get_struct_count()
|
||||||
if ent_pre is None or ent_pre.Path is None:
|
stdio.printf("[DBG] PhaseA-pre pass=%d struct_count_before=%d\n", pass_i, struct_count_before)
|
||||||
continue
|
stdio.fflush(0)
|
||||||
pkg_pre: str = None
|
for i in range(file_count):
|
||||||
if string.strlen(ent_pre.Path) > src_dir_len_pre + 1:
|
ea_pre: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||||
rel_path_pre: str = ent_pre.Path + src_dir_len_pre + 1
|
ent_pre: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pre, t.CPtr))
|
||||||
pkg_pre = HandlesImports.compute_package_from_relpath(mb, rel_path_pre)
|
if ent_pre is None or ent_pre.Path is None:
|
||||||
tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1)
|
continue
|
||||||
if tr_pre is None:
|
pkg_pre: str = None
|
||||||
stdio.printf("[Phase A-pre] 警告: 预注册失败: %s\n", ent_pre.Path)
|
if string.strlen(ent_pre.Path) > src_dir_len_pre + 1:
|
||||||
stdio.printf("[Phase A-pre] 预注册完成\n")
|
rel_path_pre: str = ent_pre.Path + src_dir_len_pre + 1
|
||||||
|
pkg_pre = HandlesImports.compute_package_from_relpath(mb, rel_path_pre)
|
||||||
|
stdio.printf("[DBG] PhaseA-pre pass=%d file=%s\n", pass_i, ent_pre.Path)
|
||||||
|
stdio.fflush(0)
|
||||||
|
tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1)
|
||||||
|
if tr_pre is None:
|
||||||
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path)
|
||||||
|
VLogger.warning(fb, "PhaseA")
|
||||||
|
struct_count_after: int = HandlesStruct.get_struct_count()
|
||||||
|
stdio.printf("[DBG] PhaseA-pre pass=%d done struct_count_after=%d\n", pass_i, struct_count_after)
|
||||||
|
stdio.fflush(0)
|
||||||
|
# 收敛检查:本遍没有新结构体注册 → 所有类已注册
|
||||||
|
if struct_count_after == struct_count_before:
|
||||||
|
break
|
||||||
|
VLogger.info("预注册完成", "PhaseA")
|
||||||
|
|
||||||
PHASE_A_IR_SIZE: t.CSizeT = 262144
|
PHASE_A_IR_SIZE: t.CSizeT = 1048576
|
||||||
td_len_pa: t.CSizeT = string.strlen(temp_dir)
|
td_len_pa: t.CSizeT = string.strlen(temp_dir)
|
||||||
|
|
||||||
|
stdio.printf("[DBG] PhaseA full-translate start\n")
|
||||||
|
stdio.fflush(0)
|
||||||
for i in range(file_count):
|
for i in range(file_count):
|
||||||
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||||
if ent is None or ent.Path is None:
|
if ent is None or ent.Path is None:
|
||||||
continue
|
continue
|
||||||
|
stdio.printf("[DBG] PhaseA file=%s\n", ent.Path)
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 计算源文件的包名(相对 source_dir 的目录部分)
|
# 计算源文件的包名(相对 source_dir 的目录部分)
|
||||||
src_dir_len_pa: t.CSizeT = string.strlen(source_dir)
|
src_dir_len_pa: t.CSizeT = string.strlen(source_dir)
|
||||||
@@ -352,12 +407,14 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
stdlib.free(deps_path_a)
|
stdlib.free(deps_path_a)
|
||||||
|
|
||||||
if do_phase2 == 0:
|
if do_phase2 == 0:
|
||||||
stdio.printf("[project] Phase A 完成(仅 stub 生成)\n")
|
VLogger.info("Phase A 完成(仅 stub 生成)", "project")
|
||||||
stdlib.free(entries)
|
stdlib.free(entries)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# === 3. Phase B: 编译每个文件为 .obj ===
|
# === 3. Phase B: 编译每个文件为 .obj ===
|
||||||
if do_phase2 != 0:
|
if do_phase2 != 0:
|
||||||
|
stdio.printf("[DBG] before Phase B\n")
|
||||||
|
stdio.fflush(0)
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.banner("Phase B: 编译 .obj")
|
log.banner("Phase B: 编译 .obj")
|
||||||
|
|
||||||
@@ -384,28 +441,51 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
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:
|
if ent is None or ent.Path is None or ent.Sha1 is None:
|
||||||
continue
|
continue
|
||||||
|
stdio.printf("[DBG] PhaseB file=%s\n", ent.Path)
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR
|
# 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR
|
||||||
|
stdio.printf("[DBG] PhaseB step=alloc combined_ir\n")
|
||||||
|
stdio.fflush(0)
|
||||||
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
||||||
if combined_ir is None:
|
if combined_ir is None:
|
||||||
stdio.printf("[Phase B] combined_ir 分配失败: %s\n", ent.Path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path)
|
||||||
|
VLogger.error(fb, "PhaseB")
|
||||||
continue
|
continue
|
||||||
|
stdio.printf("[DBG] PhaseB step=BuildCombinedIR sha1=%s\n", ent.Sha1)
|
||||||
|
stdio.fflush(0)
|
||||||
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
|
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
|
||||||
|
stdio.printf("[DBG] PhaseB step=BuildCombinedIR done len=%d\n", combined_len)
|
||||||
|
stdio.fflush(0)
|
||||||
if combined_len == 0:
|
if combined_len == 0:
|
||||||
stdio.printf("[Phase B] BuildCombinedIR 失败: %s\n", ent.Path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", ent.Path)
|
||||||
|
VLogger.error(fb, "PhaseB")
|
||||||
stdlib.free(combined_ir)
|
stdlib.free(combined_ir)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 编译为 .obj
|
# 编译为 .obj
|
||||||
|
stdio.printf("[DBG] PhaseB step=compile_module_to_obj\n")
|
||||||
|
stdio.fflush(0)
|
||||||
cret: int = BuildPipeline.compile_module_to_obj(
|
cret: int = BuildPipeline.compile_module_to_obj(
|
||||||
combined_ir, combined_len, temp_dir, output_dir, ent.Sha1,
|
combined_ir, combined_len, temp_dir, output_dir, ent.Sha1,
|
||||||
cc_cmd, cc_flags)
|
cc_cmd, cc_flags)
|
||||||
|
stdio.printf("[DBG] PhaseB step=compile_module_to_obj done cret=%d\n", cret)
|
||||||
|
stdio.fflush(0)
|
||||||
stdlib.free(combined_ir)
|
stdlib.free(combined_ir)
|
||||||
if cret != 0:
|
if cret != 0:
|
||||||
stdio.printf("[FATAL][Phase B] llc 编译失败,终止编译: %s\n", ent.Path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", ent.Path)
|
||||||
|
VLogger.error(fb, "PhaseB")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
compiled_count += 1
|
compiled_count += 1
|
||||||
|
stdio.printf("[DBG] PhaseB step=obj_path construct\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 构造 .obj 路径,检测是否是 main 模块(test_main.py 或 main.py)
|
# 构造 .obj 路径,检测是否是 main 模块(test_main.py 或 main.py)
|
||||||
od_len: t.CSizeT = string.strlen(output_dir)
|
od_len: t.CSizeT = string.strlen(output_dir)
|
||||||
@@ -424,7 +504,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
if op_sliced_len < 512:
|
if op_sliced_len < 512:
|
||||||
string.strcpy(main_obj_path, obj_path_sliced)
|
string.strcpy(main_obj_path, obj_path_sliced)
|
||||||
else:
|
else:
|
||||||
stdio.printf("[Phase B] 警告: main_obj_path 缓冲区不足\n")
|
VLogger.warning("main_obj_path 缓冲区不足", "PhaseB")
|
||||||
else:
|
else:
|
||||||
# 其他模块: 追加到 obj_paths
|
# 其他模块: 追加到 obj_paths
|
||||||
if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE:
|
if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE:
|
||||||
@@ -435,13 +515,20 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
obj_pos += op_sliced_len
|
obj_pos += op_sliced_len
|
||||||
obj_paths[obj_pos] = '\0'
|
obj_paths[obj_pos] = '\0'
|
||||||
else:
|
else:
|
||||||
stdio.printf("[Phase B] 警告: .obj 路径缓冲区不足\n")
|
VLogger.warning(".obj 路径缓冲区不足", "PhaseB")
|
||||||
stdlib.free(obj_path_sliced)
|
stdlib.free(obj_path_sliced)
|
||||||
|
stdio.printf("[DBG] PhaseB step=obj_path done\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
stdio.printf("[Phase B] 编译完成: %d/%d\n", compiled_count, file_count)
|
stdio.printf("[DBG] PhaseB loop done compiled_count=%d\n", compiled_count)
|
||||||
|
stdio.fflush(0)
|
||||||
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "编译完成: %d/%d", compiled_count, file_count)
|
||||||
|
VLogger.success(fb, "PhaseB")
|
||||||
|
|
||||||
if compiled_count == 0:
|
if compiled_count == 0:
|
||||||
stdio.printf("[Phase B] 无成功编译的文件\n")
|
VLogger.error("无成功编译的文件", "PhaseB")
|
||||||
stdlib.free(entries)
|
stdlib.free(entries)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@@ -449,198 +536,191 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
# includes.binary 可能缺少某些 includes .obj(如 testcheck.py),
|
# includes.binary 可能缺少某些 includes .obj(如 testcheck.py),
|
||||||
# 这些文件被用户项目导入但未被 TransPyV 自身依赖,Projectrans.py 未编译它们。
|
# 这些文件被用户项目导入但未被 TransPyV 自身依赖,Projectrans.py 未编译它们。
|
||||||
# 检测并编译缺失的 includes 文件到 output_dir,加入链接命令。
|
# 检测并编译缺失的 includes 文件到 output_dir,加入链接命令。
|
||||||
|
# 数据来源:StubMerger 全局内存存储器(不读取 _sha1_map.txt 文件)
|
||||||
if includes_dir is not None and includes_binary_dir is not None:
|
if includes_dir is not None and includes_binary_dir is not None:
|
||||||
|
stdio.printf("[DBG] PhaseB+ start\n")
|
||||||
|
stdio.fflush(0)
|
||||||
inc_compiled: int = 0
|
inc_compiled: int = 0
|
||||||
td_len_mi: t.CSizeT = string.strlen(temp_dir)
|
td_len_mi: t.CSizeT = string.strlen(temp_dir)
|
||||||
map_path_mi: bytes = stdlib.malloc(td_len_mi + 32)
|
# 从全局存储器获取 SHA1/模块名/rel_path 数组(直接访问器,避免 box 解引用问题)
|
||||||
if map_path_mi is not None:
|
store_count_mi: int = StubMerger.GetSha1StoreCount()
|
||||||
viperlib.snprintf(map_path_mi, td_len_mi + 32, "%s/_sha1_map.txt", temp_dir)
|
stdio.printf("[DBG] PhaseB+ store_count=%d\n", store_count_mi)
|
||||||
mapf_mi: fileio.File | t.CPtr = fileio.File(map_path_mi, fileio.MODE.R)
|
stdio.fflush(0)
|
||||||
if not mapf_mi.closed:
|
if store_count_mi > 0:
|
||||||
map_buf_mi: bytes = stdlib.malloc(65536)
|
store_sha1_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
|
||||||
if map_buf_mi is not None:
|
store_mod_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreModArrPtr()
|
||||||
map_br_mi: t.CInt64T = mapf_mi.read_all(map_buf_mi, 65536)
|
store_rel_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||||||
mapf_mi.close()
|
stdio.printf("[DBG] PhaseB+ arrs ok sha1=%p mod=%p rel=%p\n", store_sha1_arr_mi, store_mod_arr_mi, store_rel_arr_mi)
|
||||||
if map_br_mi > 0:
|
stdio.fflush(0)
|
||||||
if map_br_mi < 65536:
|
for si_mi in range(store_count_mi):
|
||||||
map_buf_mi[map_br_mi] = '\0'
|
# 获取当前条目的 SHA1 和 rel_path
|
||||||
else:
|
inc_sha1_mi: str = store_sha1_arr_mi + t.CSizeT(si_mi) * 17
|
||||||
map_buf_mi[65535] = '\0'
|
inc_rel_mi: str = store_rel_arr_mi + t.CSizeT(si_mi) * StubMerger.MAX_REL_PATH_LEN
|
||||||
map_len_mi: t.CSizeT = map_br_mi
|
stdio.printf("[DBG] PhaseB+ iter=%d sha1=%s rel=%s\n", si_mi, inc_sha1_mi, inc_rel_mi)
|
||||||
mpos_mi: t.CSizeT = 0
|
stdio.fflush(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
|
# 检查 .obj 是否已存在于 includes.binary
|
||||||
if ml_len_mi < 26:
|
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
|
||||||
continue
|
check_pat_mi: bytes = stdlib.malloc(ibd_len_mi + 35)
|
||||||
if map_buf_mi[ml_start_mi + 16] != ':':
|
if check_pat_mi is None:
|
||||||
continue
|
continue
|
||||||
rp_start_mi: t.CSizeT = ml_start_mi + 17
|
viperlib.snprintf(check_pat_mi, ibd_len_mi + 35, "%s/%s*.obj", includes_binary_dir, inc_sha1_mi)
|
||||||
if string.strncmp(map_buf_mi + rp_start_mi, "includes/", 9) != 0:
|
check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||||
continue
|
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
|
||||||
|
|
||||||
# 提取 SHA1
|
# .obj 不存在,需要编译
|
||||||
inc_sha1_mi: str = stdlib.malloc(17)
|
# 构造源文件路径: {includes_dir}/{rel_path}
|
||||||
if inc_sha1_mi is None:
|
rel_path_len_mi: t.CSizeT = string.strlen(inc_rel_mi)
|
||||||
continue
|
inc_dir_len_mi: t.CSizeT = string.strlen(includes_dir)
|
||||||
string.strncpy(inc_sha1_mi, map_buf_mi + ml_start_mi, 16)
|
src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1)
|
||||||
inc_sha1_mi[16] = '\0'
|
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, inc_rel_mi)
|
||||||
|
|
||||||
# 检查 .obj 是否已存在于 includes.binary
|
# 检查是否为声明文件(只有 declare 没有实质 define)
|
||||||
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
|
# 判断方法: text.ll 中若有混淆函数 define(含 @")则为实现文件
|
||||||
check_pat_mi: bytes = stdlib.malloc(ibd_len_mi + 35)
|
is_decl_mi: int = -1
|
||||||
if check_pat_mi is None:
|
tpath_mi: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||||
continue
|
if tpath_mi is not None:
|
||||||
viperlib.snprintf(check_pat_mi, ibd_len_mi + 35, "%s/%s*.obj", includes_binary_dir, inc_sha1_mi)
|
tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R)
|
||||||
check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
if not tf_mi.closed:
|
||||||
obj_exists_mi: int = 0
|
is_decl_mi = 1
|
||||||
if check_fd_mi is not None:
|
tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
|
||||||
string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
if tbuf_mi is not None:
|
||||||
check_h_mi: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(check_pat_mi, check_fd_mi)
|
tbr_mi: t.CInt64T = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE)
|
||||||
if check_h_mi != w32.win32base.INVALID_HANDLE_VALUE:
|
if tbr_mi > 0:
|
||||||
w32.win32file.FindClose(check_h_mi)
|
if tbr_mi < StubMerger.STUB_READ_BUF_SIZE:
|
||||||
obj_exists_mi = 1
|
tbuf_mi[tbr_mi] = '\0'
|
||||||
if obj_exists_mi != 0:
|
else:
|
||||||
continue
|
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)
|
||||||
|
# is_decl_mi == -1: text.ll 不存在(Phase1 未翻译此文件,可能不被项目导入)
|
||||||
|
# is_decl_mi == 1: 声明文件(仅 declare 无 define)
|
||||||
|
# 两种情况都跳过:不编译未被 Phase1 翻译的 includes 文件
|
||||||
|
if is_decl_mi != 0:
|
||||||
|
continue
|
||||||
|
|
||||||
# .obj 不存在,需要编译
|
# 尝试 BuildCombinedIR(stub/text 应已由 Phase1 生成)
|
||||||
# 构造源文件路径: {includes_dir}/{rel_path_without_includes_prefix}
|
inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
||||||
rel_path_len_mi: t.CSizeT = ml_len_mi - 26
|
inc_combined_len_mi: t.CSizeT = 0
|
||||||
inc_dir_len_mi: t.CSizeT = string.strlen(includes_dir)
|
if inc_combined_mi is not None:
|
||||||
src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1)
|
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||||
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)
|
# 如果 stub/text 不存在,翻译源文件并保存 stub + text,然后重试
|
||||||
# 判断方法: text.ll 中若有混淆函数 define(含 @\")则为实现文件
|
if inc_combined_len_mi == 0 and inc_combined_mi is not None:
|
||||||
is_decl_mi: int = -1
|
# 计算 includes 文件的包名(相对 includes_dir 的目录部分)
|
||||||
tpath_mi: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
inc_pkg_mi: str = None
|
||||||
if tpath_mi is not None:
|
if string.strlen(src_fp_mi) > inc_dir_len_mi + 1:
|
||||||
tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R)
|
inc_rel_mi2: str = src_fp_mi + inc_dir_len_mi + 1
|
||||||
if not tf_mi.closed:
|
inc_pkg_mi = HandlesImports.compute_package_from_relpath(mb, inc_rel_mi2)
|
||||||
is_decl_mi = 1
|
tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi)
|
||||||
tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
|
if tr_mi is not None:
|
||||||
if tbuf_mi is not None:
|
PBP_IR_SIZE: t.CSizeT = 1048576
|
||||||
tbr_mi: t.CInt64T = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE)
|
# 保存 stub.ll (切片路径)
|
||||||
if tbr_mi > 0:
|
inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
|
||||||
if tbr_mi < StubMerger.STUB_READ_BUF_SIZE:
|
if inc_stub_buf is not None:
|
||||||
tbuf_mi[tbr_mi] = '\0'
|
tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB)
|
||||||
else:
|
inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf)
|
||||||
tbuf_mi[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0'
|
inc_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
|
||||||
# 逐行扫描: 找 define 行中含 @\" 的(混淆函数名)
|
if inc_stub_path is not None:
|
||||||
tpos_mi: t.CSizeT = 0
|
isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W)
|
||||||
while tpos_mi < tbr_mi:
|
if not isf.closed:
|
||||||
tls_mi: t.CSizeT = tpos_mi
|
isf.write(inc_stub_buf, inc_stub_len)
|
||||||
while tpos_mi < tbr_mi:
|
isf.close()
|
||||||
if tbuf_mi[tpos_mi] == '\n':
|
stdlib.free(inc_stub_path)
|
||||||
break
|
stdlib.free(inc_stub_buf)
|
||||||
tpos_mi += 1
|
# 保存 text.ll (切片路径)
|
||||||
tll_mi: t.CSizeT = tpos_mi - tls_mi
|
inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
|
||||||
if tpos_mi < tbr_mi:
|
if inc_text_buf is not None:
|
||||||
tpos_mi += 1
|
tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
||||||
if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0:
|
inc_text_len: t.CSizeT = string.strlen(inc_text_buf)
|
||||||
# 临时在行尾加 \0 供 strstr 使用
|
inc_text_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||||
saved_mi: t.CChar = tbuf_mi[tls_mi + tll_mi]
|
if inc_text_path is not None:
|
||||||
tbuf_mi[tls_mi + tll_mi] = '\0'
|
itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W)
|
||||||
if string.strstr(tbuf_mi + tls_mi, "@\"") is not None:
|
if not itf.closed:
|
||||||
tbuf_mi[tls_mi + tll_mi] = saved_mi
|
itf.write(inc_text_buf, inc_text_len)
|
||||||
is_decl_mi = 0
|
itf.close()
|
||||||
break
|
stdlib.free(inc_text_path)
|
||||||
tbuf_mi[tls_mi + tll_mi] = saved_mi
|
stdlib.free(inc_text_buf)
|
||||||
stdlib.free(tbuf_mi)
|
# 重试 BuildCombinedIR
|
||||||
tf_mi.close()
|
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||||
stdlib.free(tpath_mi)
|
|
||||||
if is_decl_mi == 1:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 尝试 BuildCombinedIR(stub/text 应已由 Phase1 生成)
|
if inc_combined_len_mi == 0:
|
||||||
inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
inc_combined_len_mi: t.CSizeT = 0
|
if fb is not None:
|
||||||
if inc_combined_mi is not None:
|
viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", src_fp_mi)
|
||||||
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
VLogger.error(fb, "PhaseB+")
|
||||||
|
if inc_combined_mi is not None:
|
||||||
|
stdlib.free(inc_combined_mi)
|
||||||
|
continue
|
||||||
|
|
||||||
# 如果 stub/text 不存在,翻译源文件并保存 stub + text,然后重试
|
# 编译为 .obj
|
||||||
if inc_combined_len_mi == 0 and inc_combined_mi is not None:
|
inc_cret_mi: int = BuildPipeline.compile_module_to_obj(
|
||||||
# 计算 includes 文件的包名(相对 includes_dir 的目录部分)
|
inc_combined_mi, inc_combined_len_mi, temp_dir, output_dir, inc_sha1_mi,
|
||||||
inc_pkg_mi: str = None
|
cc_cmd, cc_flags)
|
||||||
if string.strlen(src_fp_mi) > inc_dir_len_mi + 1:
|
stdlib.free(inc_combined_mi)
|
||||||
inc_rel_mi: str = src_fp_mi + inc_dir_len_mi + 1
|
if inc_cret_mi != 0:
|
||||||
inc_pkg_mi = HandlesImports.compute_package_from_relpath(mb, inc_rel_mi)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi)
|
if fb is not None:
|
||||||
if tr_mi is not None:
|
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", src_fp_mi)
|
||||||
PBP_IR_SIZE: t.CSizeT = 262144
|
VLogger.error(fb, "PhaseB+")
|
||||||
# 保存 stub.ll (切片路径)
|
sys.exit(1)
|
||||||
inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
|
|
||||||
if inc_stub_buf is not None:
|
|
||||||
tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB)
|
|
||||||
inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf)
|
|
||||||
inc_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
|
|
||||||
if inc_stub_path is not None:
|
|
||||||
isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W)
|
|
||||||
if not isf.closed:
|
|
||||||
isf.write(inc_stub_buf, inc_stub_len)
|
|
||||||
isf.close()
|
|
||||||
stdlib.free(inc_stub_path)
|
|
||||||
stdlib.free(inc_stub_buf)
|
|
||||||
# 保存 text.ll (切片路径)
|
|
||||||
inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
|
|
||||||
if inc_text_buf is not None:
|
|
||||||
tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
|
||||||
inc_text_len: t.CSizeT = string.strlen(inc_text_buf)
|
|
||||||
inc_text_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
|
||||||
if inc_text_path is not None:
|
|
||||||
itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W)
|
|
||||||
if not itf.closed:
|
|
||||||
itf.write(inc_text_buf, inc_text_len)
|
|
||||||
itf.close()
|
|
||||||
stdlib.free(inc_text_path)
|
|
||||||
stdlib.free(inc_text_buf)
|
|
||||||
# 重试 BuildCombinedIR
|
|
||||||
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
|
||||||
|
|
||||||
if inc_combined_len_mi == 0:
|
inc_compiled += 1
|
||||||
stdio.printf("[Phase B+] BuildCombinedIR 失败: %s\n", src_fp_mi)
|
|
||||||
if inc_combined_mi is not None:
|
|
||||||
stdlib.free(inc_combined_mi)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 编译为 .obj
|
# 添加到 obj_paths (切片路径)
|
||||||
inc_cret_mi: int = BuildPipeline.compile_module_to_obj(
|
od_len_mi: t.CSizeT = string.strlen(output_dir)
|
||||||
inc_combined_mi, inc_combined_len_mi, temp_dir, output_dir, inc_sha1_mi,
|
inc_obj_sliced: str = StubMerger._sliced_path(output_dir, od_len_mi, inc_sha1_mi, "obj")
|
||||||
cc_cmd, cc_flags)
|
if inc_obj_sliced is not None:
|
||||||
stdlib.free(inc_combined_mi)
|
inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced)
|
||||||
if inc_cret_mi != 0:
|
if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE:
|
||||||
stdio.printf("[FATAL][Phase B+] llc 编译失败,终止编译: %s\n", src_fp_mi)
|
if obj_pos > 0:
|
||||||
sys.exit(1)
|
obj_paths[obj_pos] = ' '
|
||||||
|
obj_pos += 1
|
||||||
|
string.strcpy(obj_paths + obj_pos, inc_obj_sliced)
|
||||||
|
obj_pos += inc_obj_len
|
||||||
|
obj_paths[obj_pos] = '\0'
|
||||||
|
stdlib.free(inc_obj_sliced)
|
||||||
|
|
||||||
inc_compiled += 1
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
# 添加到 obj_paths (切片路径)
|
viperlib.snprintf(fb, 1024, "编译缺失 includes: %d 个", inc_compiled)
|
||||||
od_len_mi: t.CSizeT = string.strlen(output_dir)
|
VLogger.info(fb, "PhaseB+")
|
||||||
inc_obj_sliced: str = StubMerger._sliced_path(output_dir, od_len_mi, inc_sha1_mi, "obj")
|
|
||||||
if inc_obj_sliced is not None:
|
|
||||||
inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced)
|
|
||||||
if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE:
|
|
||||||
if obj_pos > 0:
|
|
||||||
obj_paths[obj_pos] = ' '
|
|
||||||
obj_pos += 1
|
|
||||||
string.strcpy(obj_paths + obj_pos, inc_obj_sliced)
|
|
||||||
obj_pos += inc_obj_len
|
|
||||||
obj_paths[obj_pos] = '\0'
|
|
||||||
stdlib.free(inc_obj_sliced)
|
|
||||||
|
|
||||||
stdio.printf("[Phase B+] 编译缺失 includes: %d 个\n", inc_compiled)
|
|
||||||
|
|
||||||
# === 4. Phase C: 链接所有 .obj → .exe ===
|
# === 4. Phase C: 链接所有 .obj → .exe ===
|
||||||
|
stdio.printf("[DBG] PhaseC start\n")
|
||||||
|
stdio.fflush(0)
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.banner("Phase C: 链接")
|
log.banner("Phase C: 链接")
|
||||||
|
|
||||||
@@ -674,20 +754,33 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
|||||||
final_obj_paths[fop_pos] = '\0'
|
final_obj_paths[fop_pos] = '\0'
|
||||||
|
|
||||||
obj_paths_len: t.CSizeT = fop_pos
|
obj_paths_len: t.CSizeT = fop_pos
|
||||||
|
stdio.printf("[DBG] PhaseC before link_objs_to_exe len=%d\n", obj_paths_len)
|
||||||
|
stdio.fflush(0)
|
||||||
lret: int = BuildPipeline.link_objs_to_exe(
|
lret: int = BuildPipeline.link_objs_to_exe(
|
||||||
final_obj_paths, obj_paths_len,
|
final_obj_paths, obj_paths_len,
|
||||||
linker_cmd, linker_flags, exe_path,
|
linker_cmd, linker_flags, exe_path,
|
||||||
includes_binary_dir)
|
includes_binary_dir)
|
||||||
|
stdio.printf("[DBG] PhaseC link_objs_to_exe done lret=%d\n", lret)
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
if lret == 0:
|
if lret == 0:
|
||||||
stdio.printf("输出: %s\n", exe_path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "输出: %s", exe_path)
|
||||||
|
VLogger.success(fb, "PhaseC")
|
||||||
if args.get_bool("run"):
|
if args.get_bool("run"):
|
||||||
stdio.printf("[run] 执行: %s\n", exe_path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "执行: %s", exe_path)
|
||||||
|
VLogger.info(fb, "run")
|
||||||
rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
||||||
if rp is not None:
|
if rp is not None:
|
||||||
stdio.printf("[run] 退出码: %d\n", rp.returncode)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "退出码: %d", rp.returncode)
|
||||||
|
VLogger.info(fb, "run")
|
||||||
else:
|
else:
|
||||||
stdio.printf("[Phase C] 链接失败\n")
|
VLogger.error("链接失败", "PhaseC")
|
||||||
stdlib.free(entries)
|
stdlib.free(entries)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import w32.fileio as fileio
|
|||||||
import viperlib
|
import viperlib
|
||||||
import sys
|
import sys
|
||||||
import ast
|
import ast
|
||||||
|
import lib.core.VLogger as VLogger
|
||||||
import lib.core.IncludesScanner as IncludesScanner
|
import lib.core.IncludesScanner as IncludesScanner
|
||||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||||
import lib.core.Handles.HandlesImports as HandlesImports
|
import lib.core.Handles.HandlesImports as HandlesImports
|
||||||
@@ -39,10 +40,20 @@ _mbuddy: memhub.MemManager | t.CPtr
|
|||||||
# 最大 includes SHA1 数(用于过滤)
|
# 最大 includes SHA1 数(用于过滤)
|
||||||
MAX_INCLUDES_SHA1: t.CDefine = 256
|
MAX_INCLUDES_SHA1: t.CDefine = 256
|
||||||
# stub 读取缓冲区大小
|
# stub 读取缓冲区大小
|
||||||
STUB_READ_BUF_SIZE: t.CDefine = 262144
|
STUB_READ_BUF_SIZE: t.CDefine = 1048576
|
||||||
# 最大 includes 条目数
|
# 最大 includes 条目数
|
||||||
MAX_INCLUDES: t.CDefine = 256
|
MAX_INCLUDES: t.CDefine = 256
|
||||||
|
|
||||||
|
# 全局 SHA1 映射存储器(内存中,不依赖 _sha1_map.txt 文件)
|
||||||
|
# Phase1 扫描完成后填充,供所有函数使用
|
||||||
|
_sha1_store_arr: bytes # SHA1 数组(每个 17 字节,MAX_INCLUDES 个)
|
||||||
|
_sha1_store_mod: bytes # 模块名数组(每个 64 字节,MAX_INCLUDES 个)
|
||||||
|
_sha1_store_rel: bytes # 相对路径数组(每个 256 字节,MAX_INCLUDES 个)
|
||||||
|
_sha1_store_count: int # 条目数
|
||||||
|
|
||||||
|
# rel_path 最大长度
|
||||||
|
MAX_REL_PATH_LEN: t.CDefine = 256
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# _sliced_path - 构建切片路径(stdlib.malloc 分配,调用者负责 free)
|
# _sliced_path - 构建切片路径(stdlib.malloc 分配,调用者负责 free)
|
||||||
@@ -217,77 +228,31 @@ def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int,
|
|||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# _load_includes_sha1_set - 读取 _sha1_map.txt,收集 includes/ 开头的 SHA1
|
# _load_includes_sha1_set - 从全局内存存储器收集 includes 的 SHA1
|
||||||
#
|
#
|
||||||
# _sha1_map.txt 格式:{sha16}:{rel_path}
|
# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。
|
||||||
# 仅收集 rel_path 以 "includes/" 开头的 SHA1,用于过滤 stub 文件,
|
# 用于过滤 stub 文件,避免加载 TransPyV 自身源文件(lib/*)的 stub 导致链接失败。
|
||||||
# 避免加载 TransPyV 自身源文件(lib/*)的 stub 导致链接失败。
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr,
|
def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr,
|
||||||
temp_dir: str,
|
temp_dir: str,
|
||||||
sha1_set: str) -> int:
|
sha1_set: str) -> int:
|
||||||
"""读取 _sha1_map.txt,将 includes/ 开头的 SHA1 写入 sha1_set
|
"""从全局内存存储器将 includes 的 SHA1 写入 sha1_set
|
||||||
|
|
||||||
|
pool/temp_dir 参数保留以兼容现有调用者,但不再使用。
|
||||||
|
数据来源是 PopulateSha1MapStore 填充的全局存储器。
|
||||||
sha1_set 大小为 MAX_INCLUDES_SHA1 * 17(每个 SHA1 16字符+null)
|
sha1_set 大小为 MAX_INCLUDES_SHA1 * 17(每个 SHA1 16字符+null)
|
||||||
返回找到的 includes SHA1 数量,-1 表示错误"""
|
返回找到的 includes SHA1 数量,-1 表示错误"""
|
||||||
if pool is None or temp_dir is None or sha1_set is None:
|
if sha1_set is None:
|
||||||
return -1
|
return -1
|
||||||
|
if _sha1_store_arr is None:
|
||||||
# 构造路径 temp_dir/_sha1_map.txt(使用 stdlib.malloc 避免 mbuddy 池耗尽)
|
|
||||||
dir_len: t.CSizeT = string.strlen(temp_dir)
|
|
||||||
map_path: bytes = stdlib.malloc(dir_len + 32)
|
|
||||||
if map_path is None:
|
|
||||||
return -1
|
return -1
|
||||||
viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir)
|
|
||||||
|
|
||||||
# 打开文件
|
|
||||||
f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.R)
|
|
||||||
if f.closed:
|
|
||||||
return -1
|
|
||||||
|
|
||||||
# 读取内容(使用 stdlib.malloc 避免 mbuddy 池耗尽)
|
|
||||||
MAP_BUF_SIZE: t.CSizeT = 65536
|
|
||||||
content: str = stdlib.malloc(MAP_BUF_SIZE)
|
|
||||||
if content is None:
|
|
||||||
f.close()
|
|
||||||
return -1
|
|
||||||
bytes_read: t.CInt64T = f.read_all(content, MAP_BUF_SIZE)
|
|
||||||
f.close()
|
|
||||||
if bytes_read <= 0:
|
|
||||||
return -1
|
|
||||||
if bytes_read < MAP_BUF_SIZE:
|
|
||||||
content[bytes_read] = '\0'
|
|
||||||
else:
|
|
||||||
content[MAP_BUF_SIZE - 1] = '\0'
|
|
||||||
|
|
||||||
# 解析行: {sha1}:{rel_path}
|
|
||||||
count: int = 0
|
count: int = 0
|
||||||
pos: t.CSizeT = 0
|
for i in range(_sha1_store_count):
|
||||||
content_len: t.CSizeT = bytes_read
|
if count >= MAX_INCLUDES_SHA1:
|
||||||
while pos < content_len:
|
break
|
||||||
# 找行尾
|
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||||
line_start: t.CSizeT = pos
|
string.strcpy(sha1_set + t.CSizeT(count) * 17, _sha1_store_arr + idx)
|
||||||
while pos < content_len:
|
count += 1
|
||||||
if content[pos] == '\n':
|
|
||||||
break
|
|
||||||
pos += 1
|
|
||||||
line_len: t.CSizeT = pos - line_start
|
|
||||||
pos += 1 # skip \n
|
|
||||||
|
|
||||||
# 最小长度: 16(sha1) + 1(:) + 9(includes/) = 26
|
|
||||||
if line_len < 26:
|
|
||||||
continue
|
|
||||||
# 检查第17个字符是 ':'
|
|
||||||
if content[line_start + 16] != ':':
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 检查 rel_path 是否以 "includes/" 开头
|
|
||||||
rel_start: t.CSizeT = line_start + 17
|
|
||||||
if string.strncmp(content + rel_start, "includes/", 9) == 0:
|
|
||||||
if count < MAX_INCLUDES_SHA1:
|
|
||||||
string.strncpy(sha1_set + count * 17, content + line_start, 16)
|
|
||||||
sha1_set[count * 17 + 16] = '\0'
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
|
||||||
@@ -305,10 +270,10 @@ def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int:
|
|||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt
|
# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt(人类可读输出)
|
||||||
#
|
#
|
||||||
# TransPyV.exe 自己生成 _sha1_map.txt(不再依赖 Projectrans.py 预生成),
|
# _sha1_map.txt 仅作为人类可读的调试输出,程序内部不读取此文件。
|
||||||
# 确保所有 includes 文件的 SHA1 都被记录,供 StubMerger 加载 stub 时过滤。
|
# 机器分析使用 PopulateSha1MapStore 填充的全局内存存储器。
|
||||||
#
|
#
|
||||||
# Args:
|
# Args:
|
||||||
# mb: 内存池
|
# mb: 内存池
|
||||||
@@ -322,7 +287,7 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
|
|||||||
scan_result: IncludesScanner.ScanResult | t.CPtr,
|
scan_result: IncludesScanner.ScanResult | t.CPtr,
|
||||||
filter_set: t.CChar | t.CPtr,
|
filter_set: t.CChar | t.CPtr,
|
||||||
filter_count: int) -> int:
|
filter_count: int) -> int:
|
||||||
"""将 includes 扫描结果写入 _sha1_map.txt(供 StubMerger 使用)
|
"""将 includes 扫描结果写入 _sha1_map.txt(人类可读输出,程序内部使用内存存储器)
|
||||||
|
|
||||||
若 filter_set 不为 None 且 filter_count > 0,只写入 filter_set 中的条目。
|
若 filter_set 不为 None 且 filter_count > 0,只写入 filter_set 中的条目。
|
||||||
"""
|
"""
|
||||||
@@ -367,6 +332,212 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PopulateSha1MapStore - 从扫描结果填充全局 SHA1 映射存储器
|
||||||
|
#
|
||||||
|
# 遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。
|
||||||
|
# 模块名通过 _PathToModuleName(includes/rel_path) 计算。
|
||||||
|
# 内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# scan_result: IncludesScanner 扫描结果
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# 填充的条目数,-1 表示失败
|
||||||
|
# ============================================================
|
||||||
|
def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> int:
|
||||||
|
"""从扫描结果填充全局 SHA1 映射存储器
|
||||||
|
|
||||||
|
遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。
|
||||||
|
模块名通过 _PathToModuleName(includes/rel_path) 计算。
|
||||||
|
内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||||||
|
"""
|
||||||
|
global _sha1_store_arr, _sha1_store_mod, _sha1_store_rel, _sha1_store_count
|
||||||
|
if scan_result is None:
|
||||||
|
return -1
|
||||||
|
# 释放旧存储器
|
||||||
|
if _sha1_store_arr is not None:
|
||||||
|
stdlib.free(_sha1_store_arr)
|
||||||
|
if _sha1_store_mod is not None:
|
||||||
|
stdlib.free(_sha1_store_mod)
|
||||||
|
if _sha1_store_rel is not None:
|
||||||
|
stdlib.free(_sha1_store_rel)
|
||||||
|
_sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17)
|
||||||
|
_sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64)
|
||||||
|
_sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN)
|
||||||
|
if _sha1_store_arr is None or _sha1_store_mod is None or _sha1_store_rel is None:
|
||||||
|
return -1
|
||||||
|
string.memset(_sha1_store_arr, 0, MAX_INCLUDES * 17)
|
||||||
|
string.memset(_sha1_store_mod, 0, MAX_INCLUDES * 64)
|
||||||
|
string.memset(_sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
|
||||||
|
_sha1_store_count = 0
|
||||||
|
entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||||
|
for i in range(scan_result.Count):
|
||||||
|
if _sha1_store_count >= MAX_INCLUDES:
|
||||||
|
break
|
||||||
|
ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p
|
||||||
|
ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||||
|
if ent is None or ent.Sha1 is None or ent.RelPath is None:
|
||||||
|
continue
|
||||||
|
# 构建完整路径 includes/{RelPath}(_PathToModuleName 需要)
|
||||||
|
rp_len: t.CSizeT = string.strlen(ent.RelPath)
|
||||||
|
full_path_buf: bytes = stdlib.malloc(rp_len + 10)
|
||||||
|
if full_path_buf is None:
|
||||||
|
continue
|
||||||
|
viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath)
|
||||||
|
mod_name: str = _PathToModuleName(full_path_buf)
|
||||||
|
stdlib.free(full_path_buf)
|
||||||
|
if mod_name is not None:
|
||||||
|
idx: t.CSizeT = t.CSizeT(_sha1_store_count) * 17
|
||||||
|
string.strcpy(_sha1_store_arr + idx, ent.Sha1)
|
||||||
|
idx2: t.CSizeT = t.CSizeT(_sha1_store_count) * 64
|
||||||
|
mn_len: t.CSizeT = string.strlen(mod_name)
|
||||||
|
if mn_len < 64:
|
||||||
|
string.strcpy(_sha1_store_mod + idx2, mod_name)
|
||||||
|
else:
|
||||||
|
string.strncpy(_sha1_store_mod + idx2, mod_name, 63)
|
||||||
|
_sha1_store_mod[idx2 + 63] = '\0'
|
||||||
|
stdlib.free(mod_name)
|
||||||
|
# 保存 rel_path(供 Phase2 3.5 编译缺失 includes 使用)
|
||||||
|
idx3: t.CSizeT = t.CSizeT(_sha1_store_count) * MAX_REL_PATH_LEN
|
||||||
|
if rp_len < MAX_REL_PATH_LEN:
|
||||||
|
string.strcpy(_sha1_store_rel + idx3, ent.RelPath)
|
||||||
|
else:
|
||||||
|
string.strncpy(_sha1_store_rel + idx3, ent.RelPath, MAX_REL_PATH_LEN - 1)
|
||||||
|
_sha1_store_rel[idx3 + MAX_REL_PATH_LEN - 1] = '\0'
|
||||||
|
_sha1_store_count += 1
|
||||||
|
return _sha1_store_count
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# AppendToSha1MapStore - 追加条目到全局 SHA1 映射存储器
|
||||||
|
#
|
||||||
|
# Phase1 调用 PopulateSha1MapStore 填充 includes 文件,
|
||||||
|
# Phase2 扫描 App 源文件后调用此函数追加 App 模块条目,
|
||||||
|
# 确保编译 App 自身时跨模块 CDefine 查找能命中 App 模块
|
||||||
|
# (如 StubMerger.MAX_INCLUDES 在编译 Phase2 时通过
|
||||||
|
# _build_source_path_from_sha1 查找 StubMerger 的源路径)。
|
||||||
|
#
|
||||||
|
# 若存储器未初始化(PopulateSha1MapStore 未调用),自动初始化。
|
||||||
|
# 若 SHA1 已存在(去重),跳过。
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
# sha1: SHA1 字符串(16 字符 + null)
|
||||||
|
# rel_path: 相对路径(如 "lib/core/StubMerger.py",
|
||||||
|
# 不含 includes/ 前缀,与 _sha1_map.txt 格式一致)
|
||||||
|
#
|
||||||
|
# Returns:
|
||||||
|
# 0 成功(含去重跳过),1 失败
|
||||||
|
# ============================================================
|
||||||
|
def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||||
|
"""追加条目到全局 SHA1 映射存储器(Phase2 用)"""
|
||||||
|
global _sha1_store_arr, _sha1_store_mod, _sha1_store_rel, _sha1_store_count
|
||||||
|
if sha1 is None or rel_path is None:
|
||||||
|
return 1
|
||||||
|
# 存储器未初始化:自动初始化(Phase2 可能先于 Phase1 调用)
|
||||||
|
if _sha1_store_arr is None:
|
||||||
|
_sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17)
|
||||||
|
_sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64)
|
||||||
|
_sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN)
|
||||||
|
if _sha1_store_arr is None or _sha1_store_mod is None or _sha1_store_rel is None:
|
||||||
|
return 1
|
||||||
|
string.memset(_sha1_store_arr, 0, MAX_INCLUDES * 17)
|
||||||
|
string.memset(_sha1_store_mod, 0, MAX_INCLUDES * 64)
|
||||||
|
string.memset(_sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
|
||||||
|
_sha1_store_count = 0
|
||||||
|
if _sha1_store_count >= MAX_INCLUDES:
|
||||||
|
return 1
|
||||||
|
# 去重:若 SHA1 已存在则跳过
|
||||||
|
for i in range(_sha1_store_count):
|
||||||
|
sidx_d: t.CSizeT = t.CSizeT(i) * 17
|
||||||
|
if string.strcmp(_sha1_store_arr + sidx_d, sha1) == 0:
|
||||||
|
return 0
|
||||||
|
# 模块名:rel_path "lib/core/StubMerger.py" → "lib.core.StubMerger"
|
||||||
|
full_path_buf: bytes = stdlib.malloc(string.strlen(rel_path) + 10)
|
||||||
|
if full_path_buf is None:
|
||||||
|
return 1
|
||||||
|
viperlib.snprintf(full_path_buf, string.strlen(rel_path) + 10, "includes/%s", rel_path)
|
||||||
|
mod_name: str = _PathToModuleName(full_path_buf)
|
||||||
|
stdlib.free(full_path_buf)
|
||||||
|
if mod_name is None:
|
||||||
|
return 1
|
||||||
|
# 写入 SHA1
|
||||||
|
idx_a: t.CSizeT = t.CSizeT(_sha1_store_count) * 17
|
||||||
|
string.strcpy(_sha1_store_arr + idx_a, sha1)
|
||||||
|
# 写入模块名
|
||||||
|
idx_m: t.CSizeT = t.CSizeT(_sha1_store_count) * 64
|
||||||
|
mn_len: t.CSizeT = string.strlen(mod_name)
|
||||||
|
if mn_len < 64:
|
||||||
|
string.strcpy(_sha1_store_mod + idx_m, mod_name)
|
||||||
|
else:
|
||||||
|
string.strncpy(_sha1_store_mod + idx_m, mod_name, 63)
|
||||||
|
_sha1_store_mod[idx_m + 63] = '\0'
|
||||||
|
stdlib.free(mod_name)
|
||||||
|
# 写入相对路径
|
||||||
|
idx_r: t.CSizeT = t.CSizeT(_sha1_store_count) * MAX_REL_PATH_LEN
|
||||||
|
rp_len: t.CSizeT = string.strlen(rel_path)
|
||||||
|
if rp_len < MAX_REL_PATH_LEN:
|
||||||
|
string.strcpy(_sha1_store_rel + idx_r, rel_path)
|
||||||
|
else:
|
||||||
|
string.strncpy(_sha1_store_rel + idx_r, rel_path, MAX_REL_PATH_LEN - 1)
|
||||||
|
_sha1_store_rel[idx_r + MAX_REL_PATH_LEN - 1] = '\0'
|
||||||
|
_sha1_store_count += 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# GetSha1StoreCount - 获取全局存储器条目数
|
||||||
|
# ============================================================
|
||||||
|
def GetSha1StoreCount() -> int:
|
||||||
|
"""返回全局 SHA1 存储器的条目数"""
|
||||||
|
return _sha1_store_count
|
||||||
|
|
||||||
|
|
||||||
|
def GetSha1StoreArrPtr() -> bytes | t.CPtr:
|
||||||
|
"""返回 SHA1 数组指针(每个条目 17 字节)"""
|
||||||
|
return _sha1_store_arr
|
||||||
|
|
||||||
|
|
||||||
|
def GetSha1StoreModArrPtr() -> bytes | t.CPtr:
|
||||||
|
"""返回模块名数组指针(每个条目 64 字节)"""
|
||||||
|
return _sha1_store_mod
|
||||||
|
|
||||||
|
|
||||||
|
def GetSha1StoreRelArrPtr() -> bytes | t.CPtr:
|
||||||
|
"""返回相对路径数组指针(每个条目 MAX_REL_PATH_LEN 字节)"""
|
||||||
|
return _sha1_store_rel
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# GetSha1StoreArr - 获取全局存储器数组指针(直接遍历用)
|
||||||
|
#
|
||||||
|
# 返回 sha1_arr、mod_arr、rel_arr 三个数组的指针和条目数。
|
||||||
|
# 调用者直接遍历数组:sha1_arr[i*17]、mod_arr[i*64]、rel_arr[i*MAX_REL_PATH_LEN]
|
||||||
|
# 内存归全局存储器所有,调用者不要 free
|
||||||
|
# ============================================================
|
||||||
|
def GetSha1StoreArr(out_sha1_arr: t.CPtr, out_mod_arr: t.CPtr, out_rel_arr: t.CPtr) -> int:
|
||||||
|
"""获取全局存储器数组指针
|
||||||
|
|
||||||
|
out_sha1_arr/out_mod_arr/out_rel_arr 是调用者提供的 t.CPtr 指针,
|
||||||
|
函数将存储器数组指针写入这些位置。
|
||||||
|
返回条目数,-1 失败
|
||||||
|
"""
|
||||||
|
if out_sha1_arr is None or out_mod_arr is None or out_rel_arr is None:
|
||||||
|
return -1
|
||||||
|
if _sha1_store_arr is None or _sha1_store_mod is None or _sha1_store_rel is None:
|
||||||
|
return -1
|
||||||
|
sp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_sha1_arr, t.CPtr))
|
||||||
|
if sp is not None:
|
||||||
|
sp[0] = _sha1_store_arr
|
||||||
|
mp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_mod_arr, t.CPtr))
|
||||||
|
if mp is not None:
|
||||||
|
mp[0] = _sha1_store_mod
|
||||||
|
rp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_rel_arr, t.CPtr))
|
||||||
|
if rp is not None:
|
||||||
|
rp[0] = _sha1_store_rel
|
||||||
|
return _sha1_store_count
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define
|
# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define
|
||||||
#
|
#
|
||||||
@@ -499,6 +670,39 @@ def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# _is_submodule_of_imported - 检查模块名是否是已导入包的子模块
|
||||||
|
#
|
||||||
|
# deps.txt 只记录直接导入的模块名(如 "ast"),但包的 __init__.py
|
||||||
|
# 内部 from .lexer import Lexer 会让 IR 引用 ast.lexer 子模块类型。
|
||||||
|
# 当模块名包含 '.' 时,检查其顶层包名是否在 deps_buf 中。
|
||||||
|
#
|
||||||
|
# 例如:
|
||||||
|
# deps_buf = "ast stdio string"
|
||||||
|
# mod_name = "ast.lexer" → 顶层包 "ast" 在 deps_buf 中 → 返回 1
|
||||||
|
# mod_name = "ast.token" → 顶层包 "ast" 在 deps_buf 中 → 返回 1
|
||||||
|
# mod_name = "foo.bar" → 顶层包 "foo" 不在 deps_buf 中 → 返回 0
|
||||||
|
# ============================================================
|
||||||
|
def _is_submodule_of_imported(deps_buf: str, mod_name: str) -> int:
|
||||||
|
"""检查 mod_name 是否是 deps_buf 中已导入包的子模块"""
|
||||||
|
if deps_buf is None or mod_name is None:
|
||||||
|
return 0
|
||||||
|
# 查找第一个 '.',提取顶层包名
|
||||||
|
dot_pos: str = string.strchr(mod_name, 46) # '.' = 46
|
||||||
|
if dot_pos is None:
|
||||||
|
return 0
|
||||||
|
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_pos) - t.CUInt64T(mod_name))
|
||||||
|
if pkg_len == 0 or pkg_len >= 256:
|
||||||
|
return 0
|
||||||
|
# 构造顶层包名(截断到 '.' 之前)
|
||||||
|
# 直接在 mod_name 上临时截断检查,避免分配
|
||||||
|
saved_ch: t.CChar = mod_name[pkg_len]
|
||||||
|
mod_name[pkg_len] = '\0'
|
||||||
|
result: int = HandlesImports.is_module_imported(deps_buf, mod_name)
|
||||||
|
mod_name[pkg_len] = saved_ch
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# _HasFullTypeDefinition - 检查 out_buf 中是否已有完整类型定义(非 opaque)
|
# _HasFullTypeDefinition - 检查 out_buf 中是否已有完整类型定义(非 opaque)
|
||||||
#
|
#
|
||||||
@@ -806,7 +1010,70 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
|||||||
in_body = 1
|
in_body = 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 跳过其他行(global 带初值定义、type 定义等,stub 已有 external 声明)
|
# 提取类型定义(%... = type { ... } 或 %... = type < ... >)
|
||||||
|
# stub.ll 中只有 opaque 声明,需要从 text.ll 中提取完整定义
|
||||||
|
# 用于 alloca 和 getelementptr 等需要完整类型的指令
|
||||||
|
if ll > 0 and dep_buf[ls] == '%':
|
||||||
|
eq_td: t.CSizeT = ls + 1
|
||||||
|
while eq_td < ls + ll:
|
||||||
|
if dep_buf[eq_td] == '=':
|
||||||
|
break
|
||||||
|
eq_td += 1
|
||||||
|
if eq_td < ls + ll:
|
||||||
|
# 检查是否为完整定义(= type { 或 = type <)
|
||||||
|
dep_is_full_td: int = 0
|
||||||
|
if eq_td + 8 <= ls + ll:
|
||||||
|
if dep_buf[eq_td + 2] == 't' and dep_buf[eq_td + 3] == 'y' \
|
||||||
|
and dep_buf[eq_td + 4] == 'p' and dep_buf[eq_td + 5] == 'e' \
|
||||||
|
and dep_buf[eq_td + 6] == ' ':
|
||||||
|
if dep_buf[eq_td + 7] == '{' or dep_buf[eq_td + 7] == '<':
|
||||||
|
dep_is_full_td = 1
|
||||||
|
if dep_is_full_td == 1:
|
||||||
|
# 临时截断到 '=' 之前(不含 '='),辅助函数期望纯类型名前缀
|
||||||
|
saved_eq_td: t.CChar = dep_buf[eq_td]
|
||||||
|
dep_buf[eq_td] = '\0'
|
||||||
|
# 1. 注释掉 out_buf 中的 opaque 声明(如果有)
|
||||||
|
_CommentOutOpaqueTypeInBuf(out_buf, dep_buf + ls)
|
||||||
|
# 2. 检查 out_buf 中是否已有完整定义(避免重复)
|
||||||
|
has_full_td: int = _HasFullTypeDefinition(out_buf, dep_buf + ls)
|
||||||
|
dep_buf[eq_td] = saved_eq_td
|
||||||
|
if has_full_td == 0:
|
||||||
|
# 追加完整类型定义
|
||||||
|
if out_pos + ll + 2 < out_size:
|
||||||
|
string.strncpy(out_buf + out_pos, dep_buf + ls, ll)
|
||||||
|
out_pos += ll
|
||||||
|
out_buf[out_pos] = '\n'
|
||||||
|
out_pos += 1
|
||||||
|
out_buf[out_pos] = '\0'
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 提取全局变量定义(@... = ...)
|
||||||
|
# 依赖 text.ll 中的全局变量带初值定义(如 @_mbuddy = global ...)
|
||||||
|
# stub.ll 中只有 external 声明,需要从 text.ll 提取完整定义
|
||||||
|
# 注释掉 out_buf 中的同名行(external 声明或旧定义),追加 text.ll 中的完整定义
|
||||||
|
if ll > 0 and dep_buf[ls] == '@':
|
||||||
|
eq_gv: t.CSizeT = ls + 1
|
||||||
|
while eq_gv < ls + ll:
|
||||||
|
if dep_buf[eq_gv] == '=':
|
||||||
|
break
|
||||||
|
eq_gv += 1
|
||||||
|
if eq_gv < ls + ll:
|
||||||
|
# 截断到 '=' 之前(不含 '='),得到全局变量名 @name
|
||||||
|
saved_gv: t.CChar = dep_buf[eq_gv]
|
||||||
|
dep_buf[eq_gv] = '\0'
|
||||||
|
# 注释掉 out_buf 中的同名行(external 声明或旧定义)
|
||||||
|
_CommentOutGlobalInBuf(out_buf, dep_buf + ls)
|
||||||
|
dep_buf[eq_gv] = saved_gv
|
||||||
|
# 追加完整定义
|
||||||
|
if out_pos + ll + 2 < out_size:
|
||||||
|
string.strncpy(out_buf + out_pos, dep_buf + ls, ll)
|
||||||
|
out_pos += ll
|
||||||
|
out_buf[out_pos] = '\n'
|
||||||
|
out_pos += 1
|
||||||
|
out_buf[out_pos] = '\0'
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 跳过其他行
|
||||||
return out_pos
|
return out_pos
|
||||||
|
|
||||||
|
|
||||||
@@ -826,13 +1093,14 @@ def _PathToModuleName(path: str) -> str:
|
|||||||
if path is None:
|
if path is None:
|
||||||
return None
|
return None
|
||||||
plen: t.CSizeT = string.strlen(path)
|
plen: t.CSizeT = string.strlen(path)
|
||||||
# 跳过 includes/ 前缀
|
# 跳过 includes/ 或 includes\ 前缀(Windows 反斜杠兼容)
|
||||||
prefix: str = "includes/"
|
|
||||||
prefix_len: t.CSizeT = 9
|
prefix_len: t.CSizeT = 9
|
||||||
path_start: t.CSizeT = 0
|
path_start: t.CSizeT = 0
|
||||||
if plen > prefix_len and string.strncmp(path, prefix, prefix_len) == 0:
|
if plen > prefix_len and string.strncmp(path, "includes", 8) == 0:
|
||||||
path_start = prefix_len
|
psep_ch: t.CChar = path[8]
|
||||||
plen = plen - prefix_len
|
if psep_ch == '/' or psep_ch == '\\':
|
||||||
|
path_start = prefix_len
|
||||||
|
plen = plen - prefix_len
|
||||||
# 去掉 .py 后缀
|
# 去掉 .py 后缀
|
||||||
if plen > 3 and path[path_start + plen - 3] == '.' and path[path_start + plen - 2] == 'p' and path[path_start + plen - 1] == 'y':
|
if plen > 3 and path[path_start + plen - 3] == '.' and path[path_start + plen - 2] == 'p' and path[path_start + plen - 1] == 'y':
|
||||||
plen -= 3
|
plen -= 3
|
||||||
@@ -869,94 +1137,33 @@ def _PathToModuleName(path: str) -> str:
|
|||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# _BuildIncludesSha1Map - 从 _sha1_map.txt 构建 sha1 → module_name 映射
|
# _BuildIncludesSha1Map - 从全局内存存储器构建 sha1 → module_name 映射
|
||||||
#
|
#
|
||||||
# _sha1_map.txt 格式: {sha1}:includes/{rel_path}\n
|
# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。
|
||||||
# 返回两个数组(sha1_list 和 mod_list),长度存储在 count 中。
|
# 返回两个数组(sha1_list 和 mod_list),长度存储在 count 中。
|
||||||
# 所有内存由 stdlib.malloc 分配,调用者负责释放。
|
# 所有内存由 stdlib.malloc 分配,调用者负责释放。
|
||||||
# ============================================================
|
# ============================================================
|
||||||
def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
|
def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
|
||||||
sha1_list: t.CChar | t.CPtr,
|
sha1_list: t.CChar | t.CPtr,
|
||||||
mod_list: t.CChar | t.CPtr) -> int:
|
mod_list: t.CChar | t.CPtr) -> int:
|
||||||
"""从 _sha1_map.txt 构建 sha1→module_name 映射,返回条目数"""
|
"""从全局内存存储器复制 sha1→module_name 映射到调用者数组
|
||||||
if temp_dir is None or sha1_list is None or mod_list is None:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
map_path: bytes = stdlib.malloc(td_len + 32)
|
temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。
|
||||||
if map_path is None:
|
数据来源是 PopulateSha1MapStore 填充的全局存储器。
|
||||||
|
"""
|
||||||
|
if sha1_list is None or mod_list is None:
|
||||||
return 0
|
return 0
|
||||||
viperlib.snprintf(map_path, td_len + 32, "%s/_sha1_map.txt", temp_dir)
|
if _sha1_store_arr is None or _sha1_store_mod is None:
|
||||||
mf: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.R)
|
|
||||||
if mf.closed:
|
|
||||||
stdlib.free(map_path)
|
|
||||||
return 0
|
return 0
|
||||||
map_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE)
|
|
||||||
if map_buf is None:
|
|
||||||
mf.close()
|
|
||||||
stdlib.free(map_path)
|
|
||||||
return 0
|
|
||||||
map_br: t.CInt64T = mf.read_all(map_buf, STUB_READ_BUF_SIZE)
|
|
||||||
mf.close()
|
|
||||||
stdlib.free(map_path)
|
|
||||||
if map_br <= 0:
|
|
||||||
stdlib.free(map_buf)
|
|
||||||
return 0
|
|
||||||
if map_br < STUB_READ_BUF_SIZE:
|
|
||||||
map_buf[map_br] = '\0'
|
|
||||||
else:
|
|
||||||
map_buf[STUB_READ_BUF_SIZE - 1] = '\0'
|
|
||||||
|
|
||||||
count: int = 0
|
count: int = 0
|
||||||
pos: t.CSizeT = 0
|
for i in range(_sha1_store_count):
|
||||||
# 在循环外分配 sha1 缓冲区,避免反复 malloc/free 导致堆碎片化
|
if count >= MAX_INCLUDES:
|
||||||
sha1: t.CChar | t.CPtr = stdlib.malloc(17)
|
break
|
||||||
if sha1 is None:
|
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||||
stdlib.free(map_buf)
|
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||||||
return 0
|
string.strcpy(sha1_list + t.CSizeT(count) * 17, _sha1_store_arr + idx)
|
||||||
while pos < map_br and count < MAX_INCLUDES:
|
string.strcpy(mod_list + t.CSizeT(count) * 64, _sha1_store_mod + idx2)
|
||||||
# 提取 SHA1(16 hex)
|
count += 1
|
||||||
string.strncpy(sha1, map_buf + pos, 16)
|
|
||||||
sha1[16] = '\0'
|
|
||||||
pos += 16
|
|
||||||
# 跳过 ':'
|
|
||||||
if pos < map_br and map_buf[pos] == ':':
|
|
||||||
pos += 1
|
|
||||||
# 提取路径(到 \r、\n 或 \0)
|
|
||||||
# 注意: Windows CRLF 换行符是 \r\n,必须同时检查 \r 避免路径包含 \r
|
|
||||||
path_start: t.CSizeT = pos
|
|
||||||
while pos < map_br and map_buf[pos] != '\n' and map_buf[pos] != '\r' and map_buf[pos] != '\0':
|
|
||||||
pos += 1
|
|
||||||
path_len: t.CSizeT = pos - path_start
|
|
||||||
# 跳过 \r\n 或 \n
|
|
||||||
if pos < map_br and map_buf[pos] == '\r':
|
|
||||||
pos += 1
|
|
||||||
if pos < map_br and map_buf[pos] == '\n':
|
|
||||||
pos += 1
|
|
||||||
if path_len > 0:
|
|
||||||
# 仅收集 includes/ 前缀的条目(用户文件如 App/ 不应进入 includes 映射)
|
|
||||||
# 否则用户文件会被误判为 includes,导致 is_module_imported 模块名不匹配而跳过加载
|
|
||||||
if path_len >= 9 and string.strncmp(map_buf + path_start, "includes/", 9) == 0:
|
|
||||||
path_buf: t.CChar | t.CPtr = stdlib.malloc(path_len + 1)
|
|
||||||
if path_buf is not None:
|
|
||||||
string.strncpy(path_buf, map_buf + path_start, path_len)
|
|
||||||
path_buf[path_len] = '\0'
|
|
||||||
mod_name: str = _PathToModuleName(path_buf)
|
|
||||||
stdlib.free(path_buf)
|
|
||||||
if mod_name is not None:
|
|
||||||
# 存储 sha1 和 mod_name 到数组中
|
|
||||||
idx: t.CSizeT = t.CSizeT(count) * 17
|
|
||||||
string.strcpy(sha1_list + idx, sha1)
|
|
||||||
idx2: t.CSizeT = t.CSizeT(count) * 64
|
|
||||||
mn_len: t.CSizeT = string.strlen(mod_name)
|
|
||||||
if mn_len < 64:
|
|
||||||
string.strcpy(mod_list + idx2, mod_name)
|
|
||||||
else:
|
|
||||||
string.strncpy(mod_list + idx2, mod_name, 63)
|
|
||||||
mod_list[idx2 + 63] = '\0'
|
|
||||||
stdlib.free(mod_name)
|
|
||||||
count += 1
|
|
||||||
stdlib.free(sha1)
|
|
||||||
stdlib.free(map_buf)
|
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
|
||||||
@@ -977,16 +1184,33 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
def _FindSha1ByModName(sha1_arr: t.CChar | t.CPtr, mod_arr: t.CChar | t.CPtr,
|
def _FindSha1ByModName(sha1_arr: t.CChar | t.CPtr, mod_arr: t.CChar | t.CPtr,
|
||||||
count: int, mod_name: str) -> str:
|
count: int, mod_name: str) -> str:
|
||||||
"""从模块名查找 SHA1(精确匹配)"""
|
"""从模块名查找 SHA1(精确匹配 + 包名回退)
|
||||||
|
|
||||||
|
精确匹配失败时,尝试 "{mod_name}.__init__" 回退,
|
||||||
|
支持 import ast(包)→ ast.__init__ 的 SHA1 查找。
|
||||||
|
"""
|
||||||
if sha1_arr is None or mod_arr is None or mod_name is None:
|
if sha1_arr is None or mod_arr is None or mod_name is None:
|
||||||
return None
|
return None
|
||||||
if count <= 0:
|
if count <= 0:
|
||||||
return None
|
return None
|
||||||
|
# 第一遍:精确匹配
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
idx: t.CSizeT = t.CSizeT(i) * 64
|
idx: t.CSizeT = t.CSizeT(i) * 64
|
||||||
if string.strcmp(mod_arr + idx, mod_name) == 0:
|
if string.strcmp(mod_arr + idx, mod_name) == 0:
|
||||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||||
return sha1_arr + sidx
|
return sha1_arr + sidx
|
||||||
|
# 第二遍:包名回退("ast" → "ast.__init__")
|
||||||
|
nm_len: t.CSizeT = string.strlen(mod_name)
|
||||||
|
init_buf: bytes = stdlib.malloc(nm_len + 12)
|
||||||
|
if init_buf is not None:
|
||||||
|
viperlib.snprintf(init_buf, nm_len + 12, "%s.__init__", mod_name)
|
||||||
|
for i in range(count):
|
||||||
|
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||||||
|
if string.strcmp(mod_arr + idx2, init_buf) == 0:
|
||||||
|
sidx2: t.CSizeT = t.CSizeT(i) * 17
|
||||||
|
stdlib.free(init_buf)
|
||||||
|
return sha1_arr + sidx2
|
||||||
|
stdlib.free(init_buf)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -1027,13 +1251,13 @@ def _AddSha1ToSet(set_buf: t.CChar | t.CPtr, count: int, sha1: str) -> int:
|
|||||||
#
|
#
|
||||||
# 算法(工作列表):
|
# 算法(工作列表):
|
||||||
# 1. 扫描 source_dir 下的 .py 文件,解析 AST 获取 _imported_modules
|
# 1. 扫描 source_dir 下的 .py 文件,解析 AST 获取 _imported_modules
|
||||||
# 2. 构建 SHA1→module_name 映射(从 _sha1_map.txt)
|
# 2. 构建 SHA1→module_name 映射(从全局内存存储器)
|
||||||
# 3. 工作列表递归:模块名 → 查 SHA1 → 加入 reachable_set → 读 .deps.txt → 追加新模块名
|
# 3. 工作列表递归:模块名 → 查 SHA1 → 加入 reachable_set → 读 .deps.txt → 追加新模块名
|
||||||
#
|
#
|
||||||
# Args:
|
# Args:
|
||||||
# mb: 内存池
|
# mb: 内存池
|
||||||
# source_dir: 源文件目录(Config.SourceDir)
|
# source_dir: 源文件目录(Config.SourceDir)
|
||||||
# temp_dir: 临时目录(_sha1_map.txt 和 .deps.txt 所在位置)
|
# temp_dir: 临时目录(.deps.txt 所在位置;_sha1_map.txt 仅人类可读输出,不读取)
|
||||||
# reachable_set: 输出参数,可达 SHA1 集合缓冲区(MAX_INCLUDES_SHA1 * 17 字节)
|
# reachable_set: 输出参数,可达 SHA1 集合缓冲区(MAX_INCLUDES_SHA1 * 17 字节)
|
||||||
#
|
#
|
||||||
# Returns:
|
# Returns:
|
||||||
@@ -1060,11 +1284,14 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
|||||||
return -1
|
return -1
|
||||||
map_count: int = _BuildIncludesSha1Map(temp_dir, td_len_r, sha1_arr, mod_arr)
|
map_count: int = _BuildIncludesSha1Map(temp_dir, td_len_r, sha1_arr, mod_arr)
|
||||||
if map_count <= 0:
|
if map_count <= 0:
|
||||||
stdio.printf("[Reachable] 无法构建 SHA1 映射\n")
|
VLogger.error("无法构建 SHA1 映射", "Reachable")
|
||||||
stdlib.free(sha1_arr)
|
stdlib.free(sha1_arr)
|
||||||
stdlib.free(mod_arr)
|
stdlib.free(mod_arr)
|
||||||
return -1
|
return -1
|
||||||
stdio.printf("[Reachable] SHA1 映射: %d 个\n", map_count)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "SHA1 映射: %d 个", map_count)
|
||||||
|
VLogger.debug(fb, "Reachable")
|
||||||
|
|
||||||
# 2. 扫描 source_dir 下的 .py 文件,收集直接依赖
|
# 2. 扫描 source_dir 下的 .py 文件,收集直接依赖
|
||||||
dir_len: t.CSizeT = string.strlen(source_dir)
|
dir_len: t.CSizeT = string.strlen(source_dir)
|
||||||
@@ -1099,7 +1326,10 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
|||||||
|
|
||||||
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
|
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
|
||||||
if handle == win32base.INVALID_HANDLE_VALUE:
|
if handle == win32base.INVALID_HANDLE_VALUE:
|
||||||
stdio.printf("[Reachable] 未找到 .py 文件: %s\n", pattern)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "未找到 .py 文件: %s", pattern)
|
||||||
|
VLogger.warning(fb, "Reachable")
|
||||||
stdlib.free(pattern)
|
stdlib.free(pattern)
|
||||||
stdlib.free(find_data)
|
stdlib.free(find_data)
|
||||||
stdlib.free(sha1_arr)
|
stdlib.free(sha1_arr)
|
||||||
@@ -1176,7 +1406,10 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
|||||||
worklist[wl_len - 1] = '\0'
|
worklist[wl_len - 1] = '\0'
|
||||||
wl_len -= 1
|
wl_len -= 1
|
||||||
|
|
||||||
stdio.printf("[Reachable] 源文件直接依赖: '%s'\n", worklist)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "源文件直接依赖: '%s'", worklist)
|
||||||
|
VLogger.debug(fb, "Reachable")
|
||||||
|
|
||||||
# 2.5. 全局预加入基础容器模块(_list/_dict/json)
|
# 2.5. 全局预加入基础容器模块(_list/_dict/json)
|
||||||
#
|
#
|
||||||
@@ -1223,7 +1456,10 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
|||||||
worklist[wl_len] = ' '
|
worklist[wl_len] = ' '
|
||||||
wl_len += 1
|
wl_len += 1
|
||||||
worklist[wl_len] = '\0'
|
worklist[wl_len] = '\0'
|
||||||
stdio.printf("[Reachable] 预加入容器模块后: '%s'\n", worklist)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "预加入容器模块后: '%s'", worklist)
|
||||||
|
VLogger.debug(fb, "Reachable")
|
||||||
|
|
||||||
# 3. 工作列表算法:递归收集可达 SHA1
|
# 3. 工作列表算法:递归收集可达 SHA1
|
||||||
processed: bytes = stdlib.malloc(8192)
|
processed: bytes = stdlib.malloc(8192)
|
||||||
@@ -1261,13 +1497,14 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
|||||||
if HandlesImports.is_module_imported(processed, mod_buf) != 0:
|
if HandlesImports.is_module_imported(processed, mod_buf) != 0:
|
||||||
already = 1
|
already = 1
|
||||||
if already == 0:
|
if already == 0:
|
||||||
# 加入 processed
|
# 加入 processed(嵌套 if 拆分 + 用 = 代替 += 绕过 TPC AUGASGN bug)
|
||||||
if proc_len + name_len + 1 < 8192:
|
if processed is not None:
|
||||||
string.strcpy(processed + proc_len, mod_buf)
|
if proc_len + name_len + 1 < 8192:
|
||||||
proc_len += name_len
|
string.strcpy(processed + proc_len, mod_buf)
|
||||||
processed[proc_len] = ' '
|
proc_len = proc_len + name_len
|
||||||
proc_len += 1
|
processed[proc_len] = ' '
|
||||||
processed[proc_len] = '\0'
|
proc_len = proc_len + 1
|
||||||
|
processed[proc_len] = '\0'
|
||||||
|
|
||||||
# 查找 SHA1
|
# 查找 SHA1
|
||||||
found_sha1: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, mod_buf)
|
found_sha1: str = _FindSha1ByModName(sha1_arr, mod_arr, map_count, mod_buf)
|
||||||
@@ -1289,17 +1526,18 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
|||||||
deps_buf[dbr] = '\0'
|
deps_buf[dbr] = '\0'
|
||||||
else:
|
else:
|
||||||
deps_buf[2047] = '\0'
|
deps_buf[2047] = '\0'
|
||||||
# 追加到 worklist(确保前面有空格分隔符,避免模块名合并)
|
# 追加到 worklist(嵌套 if 拆分 + 用 = 代替 += 绕过 TPC AUGASGN bug)
|
||||||
dl: t.CSizeT = string.strlen(deps_buf)
|
dl: t.CSizeT = string.strlen(deps_buf)
|
||||||
if dl > 0 and wl_len + dl + 2 < 8192:
|
if worklist is not None:
|
||||||
if wl_len > 0 and worklist[wl_len - 1] != ' ':
|
if dl > 0 and wl_len + dl + 2 < 8192:
|
||||||
|
if wl_len > 0 and worklist[wl_len - 1] != ' ':
|
||||||
|
worklist[wl_len] = ' '
|
||||||
|
wl_len = wl_len + 1
|
||||||
|
string.strcpy(worklist + wl_len, deps_buf)
|
||||||
|
wl_len = wl_len + dl
|
||||||
worklist[wl_len] = ' '
|
worklist[wl_len] = ' '
|
||||||
wl_len += 1
|
wl_len = wl_len + 1
|
||||||
string.strcpy(worklist + wl_len, deps_buf)
|
worklist[wl_len] = '\0'
|
||||||
wl_len += dl
|
|
||||||
worklist[wl_len] = ' '
|
|
||||||
wl_len += 1
|
|
||||||
worklist[wl_len] = '\0'
|
|
||||||
stdlib.free(deps_buf)
|
stdlib.free(deps_buf)
|
||||||
else:
|
else:
|
||||||
df.close()
|
df.close()
|
||||||
@@ -1310,15 +1548,19 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
|||||||
stdlib.free(worklist)
|
stdlib.free(worklist)
|
||||||
stdlib.free(processed)
|
stdlib.free(processed)
|
||||||
|
|
||||||
stdio.printf("[Reachable] 可达 SHA1: %d 个\n", reachable_count)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "可达 SHA1: %d 个", reachable_count)
|
||||||
|
VLogger.debug(fb, "Reachable")
|
||||||
return reachable_count
|
return reachable_count
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# BuildCombinedIR - 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR
|
# BuildCombinedIR - 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR
|
||||||
#
|
#
|
||||||
# 按需加载:读取 deps.txt 获取导入模块名,通过 _sha1_map.txt 查找 SHA1,
|
# 按需加载:读取 deps.txt 获取导入模块名,通过内存存储器查找 SHA1,
|
||||||
# 仅加载实际使用的依赖 stub(而非全部扫描)。
|
# 仅加载实际使用的依赖 stub(而非全部扫描)。
|
||||||
|
# _sha1_map.txt 仅作为人类可读输出,程序内部不读取。
|
||||||
# ============================================================
|
# ============================================================
|
||||||
def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||||
out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT:
|
out_buf: bytes, out_size: t.CSizeT) -> t.CSizeT:
|
||||||
@@ -1387,7 +1629,7 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
|||||||
|
|
||||||
# 2. 按需加载依赖 stubs(根据 deps.txt 过滤,而非扫描全部)
|
# 2. 按需加载依赖 stubs(根据 deps.txt 过滤,而非扫描全部)
|
||||||
# 先加载依赖 stub(含 type 定义),确保 type 定义在本地 text.ll 的 define 块之前
|
# 先加载依赖 stub(含 type 定义),确保 type 定义在本地 text.ll 的 define 块之前
|
||||||
# 2a. 构建 includes SHA1 → module_name 映射(从 _sha1_map.txt)
|
# 2a. 构建 includes SHA1 → module_name 映射(从全局内存存储器)
|
||||||
sha1_arr: bytes = stdlib.malloc(MAX_INCLUDES * 17)
|
sha1_arr: bytes = stdlib.malloc(MAX_INCLUDES * 17)
|
||||||
mod_arr: bytes = stdlib.malloc(MAX_INCLUDES * 64)
|
mod_arr: bytes = stdlib.malloc(MAX_INCLUDES * 64)
|
||||||
inc_count: int = 0
|
inc_count: int = 0
|
||||||
@@ -1436,8 +1678,17 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
|||||||
is_include = 1
|
is_include = 1
|
||||||
if deps_loaded != 0:
|
if deps_loaded != 0:
|
||||||
idx_mi: t.CSizeT = t.CSizeT(ii) * 64
|
idx_mi: t.CSizeT = t.CSizeT(ii) * 64
|
||||||
if HandlesImports.is_module_imported(deps_buf, mod_arr + idx_mi) != 0:
|
dep_mod_name: str = mod_arr + idx_mi
|
||||||
|
if HandlesImports.is_module_imported(deps_buf, dep_mod_name) != 0:
|
||||||
should_load = 1
|
should_load = 1
|
||||||
|
else:
|
||||||
|
# 传递性依赖:deps.txt 只记录直接导入(如 ast),
|
||||||
|
# 但包的 __init__.py 内部 from .lexer import Lexer
|
||||||
|
# 会让 IR 引用 ast.lexer 子模块类型。
|
||||||
|
# 检查 dep_mod_name 是否是已导入包的子模块
|
||||||
|
# (如 ast.lexer 是 ast 的子模块)
|
||||||
|
if _is_submodule_of_imported(deps_buf, dep_mod_name) != 0:
|
||||||
|
should_load = 1
|
||||||
break
|
break
|
||||||
if is_include == 0:
|
if is_include == 0:
|
||||||
# 非 includes stub(用户文件),总是加载
|
# 非 includes stub(用户文件),总是加载
|
||||||
@@ -1492,7 +1743,10 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
|||||||
if chk_path is not None:
|
if chk_path is not None:
|
||||||
chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R)
|
chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R)
|
||||||
if chk_f.closed:
|
if chk_f.closed:
|
||||||
stdio.printf("[FATAL][BuildCombinedIR] 依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译\n", mod_nm, found_s, chk_path)
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译", mod_nm, found_s, chk_path)
|
||||||
|
VLogger.error(fb, "BuildCombinedIR")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
chk_f.close()
|
chk_f.close()
|
||||||
stdlib.free(chk_path)
|
stdlib.free(chk_path)
|
||||||
|
|||||||
@@ -1,14 +1,29 @@
|
|||||||
import t, c
|
import t, c
|
||||||
from stdint import *
|
from stdint import *
|
||||||
import stdio
|
import stdio
|
||||||
|
import stdlib
|
||||||
import memhub
|
import memhub
|
||||||
|
import sys
|
||||||
import w32.win32console as w32cmd
|
import w32.win32console as w32cmd
|
||||||
import w32.win32file as w32file
|
import w32.win32file as w32file
|
||||||
import w32.win32base as w32base
|
import w32.win32base as win32base
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# VLogger - 原生日志系统(Windows 控制台彩色输出)
|
# VLogger - 原生日志系统(Windows 控制台彩色输出)
|
||||||
|
#
|
||||||
|
# 输出格式与 TPC (lib/core/VLogger.py) 对齐:
|
||||||
|
# ├ INFO: message
|
||||||
|
# ├ INFO[category]: message
|
||||||
|
# ├ WARN: message
|
||||||
|
# ├ ERROR: message
|
||||||
|
# ├ SUCCESS: message
|
||||||
|
# ├ DEBUG: message
|
||||||
|
# ╠ CRITICAL: message (红底白字,致命错误)
|
||||||
|
# ╠ CRITICAL[category]: message
|
||||||
|
#
|
||||||
|
# 分段着色:前缀符号(├/╠) 用级别色,LEVEL 标签用亮色,消息用默认色
|
||||||
|
# CRITICAL 级别使用 ╠ 前缀和红底白字标签,与 TPC critical 对齐
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
# 日志级别
|
# 日志级别
|
||||||
@@ -18,6 +33,7 @@ class LogLevel(t.CEnum):
|
|||||||
WARNING = 2
|
WARNING = 2
|
||||||
ERROR = 3
|
ERROR = 3
|
||||||
SUCCESS = 4
|
SUCCESS = 4
|
||||||
|
CRITICAL = 5
|
||||||
|
|
||||||
|
|
||||||
# Win32 控制台前景色属性
|
# Win32 控制台前景色属性
|
||||||
@@ -60,42 +76,72 @@ class Logger:
|
|||||||
return w32cmd.SetConsoleTextAttribute(self._console_handle, FOREGROUND_WHITE)
|
return w32cmd.SetConsoleTextAttribute(self._console_handle, FOREGROUND_WHITE)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def _log(self, level: int, prefix: str, msg: str, color: WORD,
|
# ============================================================
|
||||||
|
# _log - 核心日志输出(分段着色)
|
||||||
|
#
|
||||||
|
# 格式: ├ LEVEL: msg 或 ├ LEVEL[category]: msg
|
||||||
|
# 分三段着色:
|
||||||
|
# 1. 前缀符号 ├ (sym_color)
|
||||||
|
# 2. LEVEL 标签 (level_color)
|
||||||
|
# 3. 消息内容 (默认白色)
|
||||||
|
# ============================================================
|
||||||
|
def _log(self, level: int, prefix_sym: str, level_str: str, msg: str,
|
||||||
|
sym_color: WORD, level_color: WORD,
|
||||||
category: str = "") -> int:
|
category: str = "") -> int:
|
||||||
if level < self._level:
|
if level < self._level:
|
||||||
return 0
|
return 0
|
||||||
self._set_color(color)
|
# 前缀符号(如 ├)
|
||||||
|
self._set_color(sym_color)
|
||||||
|
stdio.printf("%s ", prefix_sym)
|
||||||
|
# LEVEL 标签(亮色)
|
||||||
|
self._set_color(level_color)
|
||||||
if category is not None:
|
if category is not None:
|
||||||
if category[0] != 0:
|
if category[0] != 0:
|
||||||
stdio.printf("%s[%s] %s\n", prefix, category, msg)
|
stdio.printf("%s[%s]: ", level_str, category)
|
||||||
else:
|
else:
|
||||||
stdio.printf("%s %s\n", prefix, msg)
|
stdio.printf("%s: ", level_str)
|
||||||
else:
|
else:
|
||||||
stdio.printf("%s %s\n", prefix, msg)
|
stdio.printf("%s: ", level_str)
|
||||||
|
# 消息内容(默认色)
|
||||||
self._reset_color()
|
self._reset_color()
|
||||||
|
stdio.printf("%s\n", msg)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def debug(self, msg: str, category: str = "") -> int:
|
def debug(self, msg: str, category: str = "") -> int:
|
||||||
return self._log(LogLevel.DEBUG, "[DEBUG]", msg,
|
return self._log(LogLevel.DEBUG, "├", "DEBUG", msg,
|
||||||
FOREGROUND_INTENSITY, category)
|
FOREGROUND_INTENSITY, FOREGROUND_INTENSITY, category)
|
||||||
|
|
||||||
def info(self, msg: str, category: str = "") -> int:
|
def info(self, msg: str, category: str = "") -> int:
|
||||||
return self._log(LogLevel.INFO, "[INFO]", msg,
|
return self._log(LogLevel.INFO, "├", "INFO", msg,
|
||||||
|
FOREGROUND_GREEN,
|
||||||
FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
||||||
|
|
||||||
def warning(self, msg: str, category: str = "") -> int:
|
def warning(self, msg: str, category: str = "") -> int:
|
||||||
return self._log(LogLevel.WARNING, "[WARN]", msg,
|
return self._log(LogLevel.WARNING, "├", "WARN", msg,
|
||||||
|
FOREGROUND_YELLOW,
|
||||||
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
||||||
category)
|
category)
|
||||||
|
|
||||||
def error(self, msg: str, category: str = "") -> int:
|
def error(self, msg: str, category: str = "") -> int:
|
||||||
return self._log(LogLevel.ERROR, "[ERROR]", msg,
|
ret: int = self._log(LogLevel.ERROR, "├", "ERROR", msg,
|
||||||
FOREGROUND_RED | FOREGROUND_INTENSITY, category)
|
FOREGROUND_RED,
|
||||||
|
FOREGROUND_RED | FOREGROUND_INTENSITY, category)
|
||||||
|
# 错误立即终止进程(避免错误后继续执行导致连锁崩溃)
|
||||||
|
sys.exit(1)
|
||||||
|
return ret
|
||||||
|
|
||||||
def success(self, msg: str, category: str = "") -> int:
|
def success(self, msg: str, category: str = "") -> int:
|
||||||
return self._log(LogLevel.SUCCESS, "[SUCCESS]", msg,
|
return self._log(LogLevel.SUCCESS, "├", "SUCCESS", msg,
|
||||||
|
FOREGROUND_GREEN,
|
||||||
FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
FOREGROUND_GREEN | FOREGROUND_INTENSITY, category)
|
||||||
|
|
||||||
|
def critical(self, msg: str, category: str = "") -> int:
|
||||||
|
# CRITICAL 使用 ╠ 前缀(红底白字标签,对齐 TPC critical 风格)
|
||||||
|
return self._log(LogLevel.CRITICAL, "╠", "CRITICAL", msg,
|
||||||
|
FOREGROUND_RED,
|
||||||
|
BACKGROUND_RED | FOREGROUND_WHITE | FOREGROUND_INTENSITY,
|
||||||
|
category)
|
||||||
|
|
||||||
def set_level(self, level: int) -> int:
|
def set_level(self, level: int) -> int:
|
||||||
self._level = level
|
self._level = level
|
||||||
return 0
|
return 0
|
||||||
@@ -105,8 +151,8 @@ class Logger:
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
def banner(self, msg: str) -> int:
|
def banner(self, msg: str) -> int:
|
||||||
"""输出分节标题(青色高亮)。"""
|
"""输出分节标题(蓝色高亮,与 TPC banner 风格对齐)。"""
|
||||||
self._set_color(FOREGROUND_CYAN | FOREGROUND_INTENSITY)
|
self._set_color(FOREGROUND_BLUE | FOREGROUND_INTENSITY)
|
||||||
stdio.printf("\n=== %s ===\n\n", msg)
|
stdio.printf("\n=== %s ===\n\n", msg)
|
||||||
self._reset_color()
|
self._reset_color()
|
||||||
return 0
|
return 0
|
||||||
@@ -148,9 +194,28 @@ _mbuddy: memhub.MemManager | t.CPtr
|
|||||||
# 全局 logger 指针
|
# 全局 logger 指针
|
||||||
_g_logger: Logger | t.CPtr
|
_g_logger: Logger | t.CPtr
|
||||||
|
|
||||||
|
# 全局格式化缓冲区(用于带变量的日志消息,1024 字节)
|
||||||
|
_fmt_buf: t.CChar | t.CPtr
|
||||||
|
|
||||||
|
|
||||||
|
def fmt_buf() -> t.CChar | t.CPtr:
|
||||||
|
"""获取全局格式化缓冲区(1024 字节)。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
buf: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if buf is not None:
|
||||||
|
viperlib.snprintf(buf, 1024, "翻译: %s (sha1=%s)", rp, sha1)
|
||||||
|
log.info(buf, "Phase1")
|
||||||
|
"""
|
||||||
|
global _fmt_buf
|
||||||
|
if _fmt_buf is None:
|
||||||
|
_fmt_buf = stdlib.malloc(1024)
|
||||||
|
return _fmt_buf
|
||||||
|
|
||||||
|
|
||||||
def get_logger() -> Logger | t.CPtr:
|
def get_logger() -> Logger | t.CPtr:
|
||||||
"""获取全局 logger 实例。若不存在则通过 _mbuddy 分配并初始化。"""
|
"""获取全局 logger 实例。若不存在则通过 _mbuddy 分配并初始化。"""
|
||||||
|
global _g_logger
|
||||||
if _g_logger is None:
|
if _g_logger is None:
|
||||||
if _mbuddy is None:
|
if _mbuddy is None:
|
||||||
return None
|
return None
|
||||||
@@ -167,5 +232,63 @@ def get_logger() -> Logger | t.CPtr:
|
|||||||
|
|
||||||
def set_logger(logger: Logger | t.CPtr) -> int:
|
def set_logger(logger: Logger | t.CPtr) -> int:
|
||||||
"""设置全局 logger 实例。"""
|
"""设置全局 logger 实例。"""
|
||||||
|
global _g_logger
|
||||||
_g_logger = logger
|
_g_logger = logger
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 模块级便捷函数(与 TPC 的 lib.core.VLogger 对齐)
|
||||||
|
#
|
||||||
|
# 调用方式: VLogger.info("msg", "category")
|
||||||
|
# 无需先 get_logger(),方便各模块直接使用
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def info(msg: str, category: str = "") -> int:
|
||||||
|
"""输出 INFO 级别日志。"""
|
||||||
|
log: Logger | t.CPtr = get_logger()
|
||||||
|
if log is not None:
|
||||||
|
return log.info(msg, category)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def warning(msg: str, category: str = "") -> int:
|
||||||
|
"""输出 WARN 级别日志。"""
|
||||||
|
log: Logger | t.CPtr = get_logger()
|
||||||
|
if log is not None:
|
||||||
|
return log.warning(msg, category)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def error(msg: str, category: str = "") -> int:
|
||||||
|
"""输出 ERROR 级别日志并立即终止进程。"""
|
||||||
|
log: Logger | t.CPtr = get_logger()
|
||||||
|
if log is not None:
|
||||||
|
return log.error(msg, category)
|
||||||
|
# logger 不可用时也直接退出
|
||||||
|
sys.exit(1)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def success(msg: str, category: str = "") -> int:
|
||||||
|
"""输出 SUCCESS 级别日志。"""
|
||||||
|
log: Logger | t.CPtr = get_logger()
|
||||||
|
if log is not None:
|
||||||
|
return log.success(msg, category)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def critical(msg: str, category: str = "") -> int:
|
||||||
|
"""输出 CRITICAL 级别日志(致命错误,红底白字)。"""
|
||||||
|
log: Logger | t.CPtr = get_logger()
|
||||||
|
if log is not None:
|
||||||
|
return log.critical(msg, category)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def debug(msg: str, category: str = "") -> int:
|
||||||
|
"""输出 DEBUG 级别日志。"""
|
||||||
|
log: Logger | t.CPtr = get_logger()
|
||||||
|
if log is not None:
|
||||||
|
return log.debug(msg, category)
|
||||||
|
return 0
|
||||||
|
|||||||
163
App/main.py
163
App/main.py
@@ -16,6 +16,7 @@ import lib.core.VLogger as VLogger
|
|||||||
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
import lib.core.Handles.HandlesTranslator as HandlesTranslator
|
||||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||||
|
import lib.core.Handles.HandlesType as HandlesType
|
||||||
import lib.core.BuildPipeline as BuildPipeline
|
import lib.core.BuildPipeline as BuildPipeline
|
||||||
import lib.core.IncludesScanner as IncludesScanner
|
import lib.core.IncludesScanner as IncludesScanner
|
||||||
import lib.core.StubMerger as StubMerger
|
import lib.core.StubMerger as StubMerger
|
||||||
@@ -31,8 +32,9 @@ import hashlib
|
|||||||
|
|
||||||
# 内存大小: fl_bytes=264 (33*8), POOL_SIZE-fl_bytes 必须是 2 的幂以避免浪费
|
# 内存大小: fl_bytes=264 (33*8), POOL_SIZE-fl_bytes 必须是 2 的幂以避免浪费
|
||||||
# 1073742088 - 264 = 1073741824 (1024MB usable = 2^30)
|
# 1073742088 - 264 = 1073741824 (1024MB usable = 2^30)
|
||||||
|
# 注意: POOL_SIZE 必须是 2^30+264=1073742088,否则 _largest_pow2_le 会取 2^29=512MB
|
||||||
# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件,512MB 不足导致 Phase2 崩溃
|
# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件,512MB 不足导致 Phase2 崩溃
|
||||||
POOL_SIZE: t.CDefine = 1073741824
|
POOL_SIZE: t.CDefine = 1073742088
|
||||||
# 语言编码页
|
# 语言编码页
|
||||||
CODE_PAGE: t.CDefine = 65001
|
CODE_PAGE: t.CDefine = 65001
|
||||||
# 源代码缓冲区大小(1MB)
|
# 源代码缓冲区大小(1MB)
|
||||||
@@ -47,18 +49,33 @@ SRC_BUF_SIZE: t.CDefine = 1048576
|
|||||||
def main() -> int:
|
def main() -> int:
|
||||||
w32cmd.SetConsoleOutputCP(CODE_PAGE)
|
w32cmd.SetConsoleOutputCP(CODE_PAGE)
|
||||||
w32cmd.SetConsoleCP(CODE_PAGE)
|
w32cmd.SetConsoleCP(CODE_PAGE)
|
||||||
|
# 用 fflush(0) 刷新所有流,确保崩溃前输出可见(0=NULL 刷新所有输出流)
|
||||||
|
stdio.printf("[DBG] main enter\n")
|
||||||
|
stdio.fflush(0)
|
||||||
# 初始化 mbuddy 内存池
|
# 初始化 mbuddy 内存池
|
||||||
|
stdio.printf("[DBG] before malloc\n")
|
||||||
|
stdio.fflush(0)
|
||||||
arena: bytes = stdlib.malloc(POOL_SIZE)
|
arena: bytes = stdlib.malloc(POOL_SIZE)
|
||||||
|
stdio.printf("[DBG] after malloc arena=%p\n", arena)
|
||||||
|
stdio.fflush(0)
|
||||||
if arena is None:
|
if arena is None:
|
||||||
stdio.printf("FAIL: malloc for arena failed\n")
|
stdio.printf("FAIL: malloc for arena failed\n")
|
||||||
return 1
|
return 1
|
||||||
|
stdio.printf("[DBG] before MemBuddy\n")
|
||||||
|
stdio.fflush(0)
|
||||||
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE)
|
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE)
|
||||||
|
stdio.printf("[DBG] after MemBuddy mb=%p\n", mb)
|
||||||
|
stdio.fflush(0)
|
||||||
if mb is None:
|
if mb is None:
|
||||||
stdio.printf("FAIL: MemBuddy init failed\n")
|
stdio.printf("FAIL: MemBuddy init failed\n")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# 设置全局 mbuddy 指针(sys 和 argparse 都需要)
|
# 设置全局 mbuddy 指针(sys 和 argparse 都需要)
|
||||||
|
stdio.printf("[DBG] before _mbuddy setup\n")
|
||||||
|
stdio.fflush(0)
|
||||||
sys._mbuddy = mb
|
sys._mbuddy = mb
|
||||||
|
stdio.printf("[DBG] sys._mbuddy ok\n")
|
||||||
|
stdio.fflush(0)
|
||||||
argparse._mbuddy = mb
|
argparse._mbuddy = mb
|
||||||
ast._mbuddy = mb
|
ast._mbuddy = mb
|
||||||
lib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
lib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||||
@@ -72,44 +89,87 @@ def main() -> int:
|
|||||||
Phase2._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
Phase2._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||||
subprocess._mbuddy = mb
|
subprocess._mbuddy = mb
|
||||||
hashlib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
hashlib._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||||
|
VLogger._mbuddy = (memhub.MemManager | t.CPtr)(mb)
|
||||||
|
stdio.printf("[DBG] before InitLib\n")
|
||||||
|
stdio.fflush(0)
|
||||||
lib.InitLib((memhub.MemManager | t.CPtr)(mb))
|
lib.InitLib((memhub.MemManager | t.CPtr)(mb))
|
||||||
|
stdio.printf("[DBG] after InitLib\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 初始化 VLogger 并打印启动日志
|
# 初始化 VLogger 并打印启动日志
|
||||||
log: VLogger.Logger | t.CPtr = VLogger.get_logger()
|
log: VLogger.Logger | t.CPtr = VLogger.get_logger()
|
||||||
|
stdio.printf("[DBG] after get_logger log=%p\n", log)
|
||||||
|
stdio.fflush(0)
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.info("TransPyV 启动")
|
log.info("TransPyV 启动")
|
||||||
|
stdio.printf("[DBG] after log.info\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline)
|
# 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline)
|
||||||
|
stdio.printf("[DBG] before _init_argv\n")
|
||||||
|
stdio.fflush(0)
|
||||||
sys._init_argv()
|
sys._init_argv()
|
||||||
|
stdio.printf("[DBG] after _init_argv\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 创建参数解析器
|
# 创建参数解析器
|
||||||
|
stdio.printf("[DBG] before ArgumentParser\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser: argparse.ArgumentParser | t.CPtr = argparse.ArgumentParser(
|
parser: argparse.ArgumentParser | t.CPtr = argparse.ArgumentParser(
|
||||||
"TransPyV", "TransPyV 命令行参数解析", pool=mb)
|
"TransPyV", "TransPyV 命令行参数解析", pool=mb)
|
||||||
|
stdio.printf("[DBG] after ArgumentParser parser=%p\n", parser)
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 注册参数(与 Projectrans.py main() 一致)
|
# 注册参数(与 Projectrans.py main() 一致)
|
||||||
|
stdio.printf("[DBG] before add_argument --project\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--project", None, argparse.STRING, 0, None, False,
|
parser.add_argument("--project", None, argparse.STRING, 0, None, False,
|
||||||
argparse.STORE, "project.json 路径(默认查找当前目录)")
|
argparse.STORE, "project.json 路径(默认查找当前目录)")
|
||||||
|
stdio.printf("[DBG] after add_argument --project\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--src", None, argparse.STRING, 0, None, False,
|
parser.add_argument("--src", None, argparse.STRING, 0, None, False,
|
||||||
argparse.STORE, "源文件目录(覆盖 project.json)")
|
argparse.STORE, "源文件目录(覆盖 project.json)")
|
||||||
|
stdio.printf("[DBG] after --src\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--temp", None, argparse.STRING, 0, None, False,
|
parser.add_argument("--temp", None, argparse.STRING, 0, None, False,
|
||||||
argparse.STORE, "声明接口临时目录(覆盖 project.json)")
|
argparse.STORE, "声明接口临时目录(覆盖 project.json)")
|
||||||
|
stdio.printf("[DBG] after --temp\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--output", None, argparse.STRING, 0, None, False,
|
parser.add_argument("--output", None, argparse.STRING, 0, None, False,
|
||||||
argparse.STORE, "输出目录(覆盖 project.json)")
|
argparse.STORE, "输出目录(覆盖 project.json)")
|
||||||
|
stdio.printf("[DBG] after --output\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--phase", None, argparse.STRING, 0, None, False,
|
parser.add_argument("--phase", None, argparse.STRING, 0, None, False,
|
||||||
argparse.STORE, "阶段: 1=生成声明, 2=翻译+编译, all=全部")
|
argparse.STORE, "阶段: 1=生成声明, 2=翻译+编译, all=全部")
|
||||||
|
stdio.printf("[DBG] after --phase\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--cc", None, argparse.STRING, 0, None, False,
|
parser.add_argument("--cc", None, argparse.STRING, 0, None, False,
|
||||||
argparse.STORE, "LLVM 编译器命令(覆盖 project.json)")
|
argparse.STORE, "LLVM 编译器命令(覆盖 project.json)")
|
||||||
|
stdio.printf("[DBG] after --cc\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--clean", None, argparse.BOOL, 0, None, False,
|
parser.add_argument("--clean", None, argparse.BOOL, 0, None, False,
|
||||||
argparse.STORE_TRUE, "清理 output 和 temp 目录")
|
argparse.STORE_TRUE, "清理 output 和 temp 目录")
|
||||||
|
stdio.printf("[DBG] after --clean\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--run", None, argparse.BOOL, 0, None, False,
|
parser.add_argument("--run", None, argparse.BOOL, 0, None, False,
|
||||||
argparse.STORE_TRUE, "编译成功后立即执行生成的可执行文件")
|
argparse.STORE_TRUE, "编译成功后立即执行生成的可执行文件")
|
||||||
|
stdio.printf("[DBG] after --run\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--rebuild-includes", None, argparse.BOOL, 0, None, False,
|
parser.add_argument("--rebuild-includes", None, argparse.BOOL, 0, None, False,
|
||||||
argparse.STORE_TRUE, "删除 includes.binary 预编译缓存并重新编译所有 includes")
|
argparse.STORE_TRUE, "删除 includes.binary 预编译缓存并重新编译所有 includes")
|
||||||
|
stdio.printf("[DBG] after --rebuild-includes\n")
|
||||||
|
stdio.fflush(0)
|
||||||
parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False,
|
parser.add_argument("--clear-cache", None, argparse.BOOL, 0, None, False,
|
||||||
argparse.STORE_TRUE, "清除 .transpyc_cache 全局缓存")
|
argparse.STORE_TRUE, "清除 .transpyc_cache 全局缓存")
|
||||||
|
stdio.printf("[DBG] after --clear-cache\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# 解析命令行参数
|
# 解析命令行参数
|
||||||
|
stdio.printf("[DBG] before parse_args\n")
|
||||||
|
stdio.fflush(0)
|
||||||
args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv)
|
args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv)
|
||||||
|
stdio.printf("[DBG] after parse_args args=%p\n", args)
|
||||||
|
stdio.fflush(0)
|
||||||
if args is None:
|
if args is None:
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.error("参数解析失败", "argparse")
|
log.error("参数解析失败", "argparse")
|
||||||
@@ -184,12 +244,21 @@ def main() -> int:
|
|||||||
proj_loaded: int = 0
|
proj_loaded: int = 0
|
||||||
proj_path: str = project
|
proj_path: str = project
|
||||||
if proj_path is not None:
|
if proj_path is not None:
|
||||||
|
stdio.printf("[DBG] before Load_project_config path=%s\n", proj_path)
|
||||||
|
stdio.fflush(0)
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.banner("工程配置")
|
log.banner("工程配置")
|
||||||
if Config.Load_project_config(proj_path) == 0:
|
if Config.Load_project_config(proj_path) == 0:
|
||||||
|
stdio.printf("[DBG] Load_project_config OK\n")
|
||||||
|
stdio.fflush(0)
|
||||||
proj_loaded = 1
|
proj_loaded = 1
|
||||||
else:
|
else:
|
||||||
stdio.printf(" 警告: 无法加载 project.vpj: %s\n", proj_path)
|
if log is not None:
|
||||||
|
warn_buf: str = stdlib.malloc(256)
|
||||||
|
if warn_buf is not None:
|
||||||
|
viperlib.snprintf(warn_buf, 256, "无法加载 project.vpj: %s", proj_path)
|
||||||
|
log.warning(warn_buf, "config")
|
||||||
|
stdlib.free(warn_buf)
|
||||||
else:
|
else:
|
||||||
# 尝试默认路径 project.vpj(当前目录和上级目录)
|
# 尝试默认路径 project.vpj(当前目录和上级目录)
|
||||||
proj_path = "project.vpj"
|
proj_path = "project.vpj"
|
||||||
@@ -215,18 +284,33 @@ def main() -> int:
|
|||||||
if proj_dir is not None:
|
if proj_dir is not None:
|
||||||
string.memcpy(proj_dir, proj_path, slash_pos)
|
string.memcpy(proj_dir, proj_path, slash_pos)
|
||||||
proj_dir[slash_pos] = '\0'
|
proj_dir[slash_pos] = '\0'
|
||||||
|
stdio.printf("[DBG] before resolve_paths dir=%s\n", proj_dir)
|
||||||
|
stdio.fflush(0)
|
||||||
Config.resolve_paths(proj_dir)
|
Config.resolve_paths(proj_dir)
|
||||||
|
stdio.printf("[DBG] resolve_paths OK\n")
|
||||||
|
stdio.fflush(0)
|
||||||
Config.print_config()
|
Config.print_config()
|
||||||
|
stdio.printf("[DBG] print_config OK\n")
|
||||||
|
stdio.fflush(0)
|
||||||
|
|
||||||
# === --clean: 清理 temp 和 output 目录 ===
|
# === --clean: 清理 temp 和 output 目录 ===
|
||||||
if _gb_clean:
|
if _gb_clean:
|
||||||
stdio.printf("\n[clean] 清理临时目录...\n")
|
if log is not None:
|
||||||
|
log.info("清理临时目录...", "clean")
|
||||||
if Config.TempDir is not None:
|
if Config.TempDir is not None:
|
||||||
n: int = Utils.CleanDir(Config.TempDir)
|
n: int = Utils.CleanDir(Config.TempDir)
|
||||||
stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.TempDir, n)
|
if log is not None:
|
||||||
|
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb is not None:
|
||||||
|
viperlib.snprintf(fb, 1024, "%s: 删除 %d 个文件", Config.TempDir, n)
|
||||||
|
log.info(fb, "clean")
|
||||||
if Config.OutputDir is not None:
|
if Config.OutputDir is not None:
|
||||||
n2: int = Utils.CleanDir(Config.OutputDir)
|
n2: int = Utils.CleanDir(Config.OutputDir)
|
||||||
stdio.printf("[clean] %s: 删除 %d 个文件\n", Config.OutputDir, n2)
|
if log is not None:
|
||||||
|
fb2: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb2 is not None:
|
||||||
|
viperlib.snprintf(fb2, 1024, "%s: 删除 %d 个文件", Config.OutputDir, n2)
|
||||||
|
log.info(fb2, "clean")
|
||||||
|
|
||||||
# === --phase 参数控制 ===
|
# === --phase 参数控制 ===
|
||||||
# phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译
|
# phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译
|
||||||
@@ -241,7 +325,11 @@ def main() -> int:
|
|||||||
do_phase1 = 1
|
do_phase1 = 1
|
||||||
if phase_mode == "2" or phase_mode == "all":
|
if phase_mode == "2" or phase_mode == "all":
|
||||||
do_phase2 = 1
|
do_phase2 = 1
|
||||||
stdio.printf("[phase] 模式: %s (phase1=%d phase2=%d)\n", phase_mode, do_phase1, do_phase2)
|
if log is not None:
|
||||||
|
fb3: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb3 is not None:
|
||||||
|
viperlib.snprintf(fb3, 1024, "模式: %s (phase1=%d phase2=%d)", phase_mode, do_phase1, do_phase2)
|
||||||
|
log.info(fb3, "phase")
|
||||||
|
|
||||||
# === Phase1: 扫描 includes(按需翻译)===
|
# === Phase1: 扫描 includes(按需翻译)===
|
||||||
# 对 includes 目录中每个 .py 文件,若 stub 不存在则翻译并分离 stub
|
# 对 includes 目录中每个 .py 文件,若 stub 不存在则翻译并分离 stub
|
||||||
@@ -249,10 +337,15 @@ def main() -> int:
|
|||||||
ph1_temp: str = Config.TempDir
|
ph1_temp: str = Config.TempDir
|
||||||
if ph1_temp is None:
|
if ph1_temp is None:
|
||||||
ph1_temp = "."
|
ph1_temp = "."
|
||||||
|
stdio.printf("[DBG] before Phase1.RunPhase1 inc=%s temp=%s\n", Config.IncludesDir, ph1_temp)
|
||||||
|
stdio.fflush(0)
|
||||||
Phase1.RunPhase1(mb, Config.IncludesDir, ph1_temp, log)
|
Phase1.RunPhase1(mb, Config.IncludesDir, ph1_temp, log)
|
||||||
|
stdio.printf("[DBG] Phase1.RunPhase1 OK\n")
|
||||||
|
stdio.fflush(0)
|
||||||
# 如果仅 Phase1(不执行 Phase2),直接退出
|
# 如果仅 Phase1(不执行 Phase2),直接退出
|
||||||
if do_phase2 == 0:
|
if do_phase2 == 0:
|
||||||
stdio.printf("[phase] Phase1 完成,退出\n")
|
if log is not None:
|
||||||
|
log.info("Phase1 完成,退出", "phase")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树
|
# AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树
|
||||||
@@ -270,10 +363,14 @@ def main() -> int:
|
|||||||
mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe"
|
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_includes_bin: str = Config.get_includes_binary_dir()
|
||||||
|
|
||||||
|
stdio.printf("[DBG] before Phase2.RunMultiFileProject src=%s temp=%s out=%s\n", Config.SourceDir, mf_temp, mf_output)
|
||||||
|
stdio.fflush(0)
|
||||||
mf_ret: int = Phase2.RunMultiFileProject(
|
mf_ret: int = Phase2.RunMultiFileProject(
|
||||||
mb, Config.SourceDir, mf_temp, mf_output,
|
mb, Config.SourceDir, mf_temp, mf_output,
|
||||||
mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out,
|
mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out,
|
||||||
mf_includes_bin, Config.IncludesDir, do_phase1, do_phase2, log, args)
|
mf_includes_bin, Config.IncludesDir, do_phase1, do_phase2, log, args)
|
||||||
|
stdio.printf("[DBG] Phase2.RunMultiFileProject OK ret=%d\n", mf_ret)
|
||||||
|
stdio.fflush(0)
|
||||||
argparse.release(args)
|
argparse.release(args)
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.success("TransPyV 完成")
|
log.success("TransPyV 完成")
|
||||||
@@ -288,7 +385,11 @@ def main() -> int:
|
|||||||
if path_buf is not None:
|
if path_buf is not None:
|
||||||
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir)
|
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir)
|
||||||
src_path = path_buf
|
src_path = path_buf
|
||||||
stdio.printf("[project] 入口文件: %s\n", src_path)
|
if log is not None:
|
||||||
|
fb4: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb4 is not None:
|
||||||
|
viperlib.snprintf(fb4, 1024, "入口文件: %s", src_path)
|
||||||
|
log.info(fb4, "project")
|
||||||
if src_path is not None:
|
if src_path is not None:
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.banner("AST 解析")
|
log.banner("AST 解析")
|
||||||
@@ -296,8 +397,10 @@ def main() -> int:
|
|||||||
f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R)
|
f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R)
|
||||||
if f.closed:
|
if f.closed:
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.error("无法打开文件", "fileio")
|
fb5: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
stdio.printf(" 路径: %s\n", src_path)
|
if fb5 is not None:
|
||||||
|
viperlib.snprintf(fb5, 1024, "无法打开文件: %s", src_path)
|
||||||
|
log.error(fb5, "fileio")
|
||||||
argparse.release(args)
|
argparse.release(args)
|
||||||
return 1
|
return 1
|
||||||
# 分配源代码缓冲区
|
# 分配源代码缓冲区
|
||||||
@@ -313,8 +416,10 @@ def main() -> int:
|
|||||||
f.close()
|
f.close()
|
||||||
if bytes_read < 0:
|
if bytes_read < 0:
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.error("读取文件失败", "fileio")
|
fb6: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
stdio.printf(" 错误码: %d\n", bytes_read)
|
if fb6 is not None:
|
||||||
|
viperlib.snprintf(fb6, 1024, "读取文件失败 (错误码: %d)", bytes_read)
|
||||||
|
log.error(fb6, "fileio")
|
||||||
argparse.release(args)
|
argparse.release(args)
|
||||||
return 1
|
return 1
|
||||||
# 添加 null 终止符,确保 strlen 和 SHA1 计算正确
|
# 添加 null 终止符,确保 strlen 和 SHA1 计算正确
|
||||||
@@ -324,7 +429,10 @@ def main() -> int:
|
|||||||
src_buf[SRC_BUF_SIZE - 1] = 0
|
src_buf[SRC_BUF_SIZE - 1] = 0
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.info("文件读取完成", "fileio")
|
log.info("文件读取完成", "fileio")
|
||||||
stdio.printf("读取 %d 字节\n", bytes_read)
|
fb7: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb7 is not None:
|
||||||
|
viperlib.snprintf(fb7, 1024, "读取 %d 字节", bytes_read)
|
||||||
|
log.info(fb7, "fileio")
|
||||||
# 解析 AST(拆分为词法+语法两阶段,便于调试)
|
# 解析 AST(拆分为词法+语法两阶段,便于调试)
|
||||||
ast._init_tables(mb)
|
ast._init_tables(mb)
|
||||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||||
@@ -396,6 +504,8 @@ def main() -> int:
|
|||||||
# 使用 project.vpj 中的配置
|
# 使用 project.vpj 中的配置
|
||||||
temp_dir: str = Config.TempDir if Config.TempDir is not None else "."
|
temp_dir: str = Config.TempDir if Config.TempDir is not None else "."
|
||||||
output_dir: str = Config.OutputDir if Config.OutputDir is not None else "."
|
output_dir: str = Config.OutputDir if Config.OutputDir is not None else "."
|
||||||
|
# 设置全局 temp_dir(供跨模块 CDefine 查找使用)
|
||||||
|
HandlesType.set_temp_dir(temp_dir)
|
||||||
cc_cmd: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
|
cc_cmd: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
|
||||||
cc_flags: str = "-filetype=obj -relocation-model=pic"
|
cc_flags: str = "-filetype=obj -relocation-model=pic"
|
||||||
linker_cmd: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
|
linker_cmd: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
|
||||||
@@ -468,7 +578,8 @@ def main() -> int:
|
|||||||
final_ir = combined_buf
|
final_ir = combined_buf
|
||||||
final_ir_len = combined_len
|
final_ir_len = combined_len
|
||||||
else:
|
else:
|
||||||
stdio.printf("[stub] BuildCombinedIR 失败,使用原始 IR\n")
|
if log is not None:
|
||||||
|
log.warning("BuildCombinedIR 失败,使用原始 IR", "stub")
|
||||||
stdlib.free(combined_buf)
|
stdlib.free(combined_buf)
|
||||||
|
|
||||||
br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline(
|
br: BuildPipeline.BuildResult | t.CPtr = BuildPipeline.run_pipeline(
|
||||||
@@ -479,21 +590,35 @@ def main() -> int:
|
|||||||
if br is not None and br.Success == 1:
|
if br is not None and br.Success == 1:
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.success("编译管线完成")
|
log.success("编译管线完成")
|
||||||
stdio.printf("输出: %s/%s\n", output_dir, linker_output)
|
fb8: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb8 is not None:
|
||||||
|
viperlib.snprintf(fb8, 1024, "输出: %s/%s", output_dir, linker_output)
|
||||||
|
log.info(fb8)
|
||||||
# --run 模式:执行生成的可执行文件
|
# --run 模式:执行生成的可执行文件
|
||||||
if args.get_bool("run"):
|
if args.get_bool("run"):
|
||||||
exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2)
|
exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2)
|
||||||
if exe_path is not None:
|
if exe_path is not None:
|
||||||
viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output)
|
viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output)
|
||||||
stdio.printf("[run] 执行: %s\n", exe_path)
|
if log is not None:
|
||||||
|
fb9: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb9 is not None:
|
||||||
|
viperlib.snprintf(fb9, 1024, "执行: %s", exe_path)
|
||||||
|
log.info(fb9, "run")
|
||||||
r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
||||||
if r is not None:
|
if r is not None:
|
||||||
stdio.printf("[run] 退出码: %d\n", r.returncode)
|
if log is not None:
|
||||||
|
fb10: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb10 is not None:
|
||||||
|
viperlib.snprintf(fb10, 1024, "退出码: %d", r.returncode)
|
||||||
|
log.info(fb10, "run")
|
||||||
else:
|
else:
|
||||||
if log is not None:
|
if log is not None:
|
||||||
log.error("编译管线失败", "pipeline")
|
log.error("编译管线失败", "pipeline")
|
||||||
if br is not None and br.ErrorMsg is not None:
|
if br is not None and br.ErrorMsg is not None:
|
||||||
stdio.printf("[FATAL] 编译管线失败: %s\n", br.ErrorMsg)
|
fb11: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||||
|
if fb11 is not None:
|
||||||
|
viperlib.snprintf(fb11, 1024, "编译管线失败: %s", br.ErrorMsg)
|
||||||
|
log.error(fb11, "FATAL")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
if log is not None:
|
if log is not None:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"slice_level": 3,
|
"slice_level": 3,
|
||||||
"sha1_slice_level": 3,
|
"sha1_slice_level": 1,
|
||||||
"target": "llvm",
|
"target": "llvm",
|
||||||
"strict_mode": true
|
"strict_mode": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"slice_level": 3,
|
"slice_level": 3,
|
||||||
"sha1_slice_level": 3,
|
"sha1_slice_level": 1,
|
||||||
"target": "llvm",
|
"target": "llvm",
|
||||||
"strict_mode": true
|
"strict_mode": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"slice_level": 3,
|
"slice_level": 3,
|
||||||
"sha1_slice_level": 3,
|
"sha1_slice_level": 1,
|
||||||
"target": "llvm",
|
"target": "llvm",
|
||||||
"strict_mode": true
|
"strict_mode": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
├ INFO: [剥离] 调试段已移除 (llvm-strip)
|
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
"name": "TransPyV",
|
"name": "TransPyV",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"source_dir": "./App",
|
"source_dir": "./App",
|
||||||
"build_dir": "./.tpv_build",
|
"temp_dir": "./temp",
|
||||||
|
"output_dir": "./output",
|
||||||
"compiler": {
|
"compiler": {
|
||||||
"cmd": "llc",
|
"cmd": "llc",
|
||||||
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
"flags": ["-filetype=obj", "-relocation-model=pic"]
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"slice_level": 3,
|
"slice_level": 3,
|
||||||
"sha1_slice_level": 3,
|
"sha1_slice_level": 1,
|
||||||
"target": "llvm",
|
"target": "llvm",
|
||||||
"strict_mode": true
|
"strict_mode": true
|
||||||
}
|
}
|
||||||
|
|||||||
0
stderr.log
Normal file
0
stderr.log
Normal file
0
stderr2.log
Normal file
0
stderr2.log
Normal file
0
stdout.log
Normal file
0
stdout.log
Normal file
0
stdout2.log
Normal file
0
stdout2.log
Normal file
483
test_crash_dbg.log
Normal file
483
test_crash_dbg.log
Normal file
@@ -0,0 +1,483 @@
|
|||||||
|
[DBG] main enter
|
||||||
|
├ INFO: TransPyV 启动
|
||||||
|
|
||||||
|
=== TransPyV 参数解析结果 ===
|
||||||
|
|
||||||
|
--project: TransPyV/Test/project.vpj
|
||||||
|
--src: (未指定)
|
||||||
|
--temp: (未指定)
|
||||||
|
--output: (未指定)
|
||||||
|
--phase: (未指定,默认 all)
|
||||||
|
--cc: (未指定)
|
||||||
|
--clean: True
|
||||||
|
--run: False
|
||||||
|
--rebuild-includes: False
|
||||||
|
--clear-cache: False
|
||||||
|
|
||||||
|
参数解析完成。
|
||||||
|
[DBG] before Load_project_config path=TransPyV/Test/project.vpj
|
||||||
|
|
||||||
|
=== 工程配置 ===
|
||||||
|
|
||||||
|
[DBG] Load_project_config OK
|
||||||
|
[DBG] before resolve_paths dir=TransPyV/Test
|
||||||
|
[DBG] resolve_paths OK
|
||||||
|
├ INFO[config]: project: AstTest v1.0.0
|
||||||
|
├ INFO[config]: source_dir: TransPyV/Test/App
|
||||||
|
├ INFO[config]: build_dir: TransPyV/Test/.tpv_build
|
||||||
|
├ INFO[config]: temp_dir: TransPyV/Test/.tpv_build/temp
|
||||||
|
├ INFO[config]: output_dir: TransPyV/Test/.tpv_build/output
|
||||||
|
├ INFO[config]: compiler: llc
|
||||||
|
├ INFO[config]: linker: clang++ -> app.exe
|
||||||
|
├ INFO[config]: includes: TransPyV/Test/../../includes
|
||||||
|
├ INFO[config]: sha1_slice_level: 1
|
||||||
|
[DBG] print_config OK
|
||||||
|
├ INFO[clean]: 清理临时目录...
|
||||||
|
├ INFO[clean]: TransPyV/Test/.tpv_build/temp: 删除 1 个文件
|
||||||
|
├ INFO[clean]: TransPyV/Test/.tpv_build/output: 删除 0 个文件
|
||||||
|
├ INFO[phase]: 模式: all (phase1=1 phase2=1)
|
||||||
|
[DBG] before Phase1.RunPhase1 inc=TransPyV/Test/../../includes temp=TransPyV/Test/.tpv_build/temp
|
||||||
|
|
||||||
|
=== Phase1: 扫描 includes(按需翻译) ===
|
||||||
|
|
||||||
|
├ INFO[Phase1]: 拓扑排序: 25 个类, 15 个文件按依赖顺序处理
|
||||||
|
├ INFO[Phase1]: 完成: 翻译=0 跳过=78 失败=0
|
||||||
|
[DBG] Phase1.RunPhase1 OK
|
||||||
|
[DBG] before Phase2.RunMultiFileProject src=TransPyV/Test/App temp=TransPyV/Test/.tpv_build/temp out=TransPyV/Test/.tpv_build/output
|
||||||
|
[DBG] RunMultiFileProject enter src=TransPyV/Test/App
|
||||||
|
├ INFO[project]: 多文件项目编译: TransPyV/Test/App
|
||||||
|
├ INFO[project]: asm_test.py (sha1=80241c7d6f357bd1)
|
||||||
|
├ INFO[project]: attr_test.py (sha1=17c0dfbcebfa3a0e)
|
||||||
|
├ INFO[project]: augassign_test.py (sha1=0eccc2393466d940)
|
||||||
|
├ INFO[project]: circ_a.py (sha1=ac47a9dc68e6834c)
|
||||||
|
├ INFO[project]: circ_b.py (sha1=04d33c721a603632)
|
||||||
|
├ INFO[project]: circ_test.py (sha1=5314f09055045035)
|
||||||
|
├ INFO[project]: closure_test.py (sha1=9d8e1c9631c28b1b)
|
||||||
|
├ INFO[project]: deco_test.py (sha1=b7bbe6a1c1e75ad8)
|
||||||
|
├ INFO[project]: deref_min_test.py (sha1=6f5e876273093314)
|
||||||
|
├ INFO[project]: deref_test.py (sha1=eb252050d92f8fb9)
|
||||||
|
├ INFO[project]: eq_test.py (sha1=b8cbe044a10adcca)
|
||||||
|
├ INFO[project]: float_test.py (sha1=e74870eba3e6d774)
|
||||||
|
├ INFO[project]: flow_test.py (sha1=969c589035910845)
|
||||||
|
├ INFO[project]: for_test.py (sha1=1eb1c9fc7e85d9f8)
|
||||||
|
├ INFO[project]: func_test.py (sha1=3c2fbc9e35ad3bf2)
|
||||||
|
├ INFO[project]: func_vtable_test.py (sha1=a9df037d9178888f)
|
||||||
|
├ INFO[project]: inherit_test.py (sha1=97043f0d52da437f)
|
||||||
|
├ INFO[project]: llvmir_test.py (sha1=c39f3e540adb7b4e)
|
||||||
|
├ INFO[project]: namespace_defs.py (sha1=b7eeff93aa63e70f)
|
||||||
|
├ INFO[project]: namespace_test.py (sha1=ef45adce81bf5b2d)
|
||||||
|
├ INFO[project]: new_test.py (sha1=9d798d964b9d3411)
|
||||||
|
├ INFO[project]: oop_test.py (sha1=1b9ab264a942c56b)
|
||||||
|
├ INFO[project]: opovl_test.py (sha1=a7cf0ce4066332ae)
|
||||||
|
├ INFO[project]: ptr_only_test.py (sha1=ed1c124f3cb787c9)
|
||||||
|
├ INFO[project]: ptr_test.py (sha1=07f7da85af876124)
|
||||||
|
├ INFO[project]: simple_test.py (sha1=b078e9c9c74a2a0c)
|
||||||
|
├ INFO[project]: string_min_test.py (sha1=74ca31446cac2107)
|
||||||
|
├ INFO[project]: string_test.py (sha1=e0009679269c6b63)
|
||||||
|
├ INFO[project]: struct_test.py (sha1=33a854a5c4f67d74)
|
||||||
|
├ INFO[project]: testcheck_test.py (sha1=d7662500f1c2c0ff)
|
||||||
|
├ INFO[project]: test_main.py (sha1=ff744980c190e9b0)
|
||||||
|
├ INFO[project]: type_bit_test.py (sha1=55cbbb5dec4fef2c)
|
||||||
|
├ INFO[project]: virtual_dispatch_test.py (sha1=cc3ad7f3bc880326)
|
||||||
|
├ INFO[project]: vtable_test.py (sha1=2769dee537308b00)
|
||||||
|
[DBG] scan done file_count=34
|
||||||
|
├ INFO[project]: 共 34 个源文件
|
||||||
|
├ INFO[project]: 已追加 34 个 App 文件到 _sha1_map.txt
|
||||||
|
[DBG] before Phase A
|
||||||
|
|
||||||
|
=== Phase A: 生成 stub + text ===
|
||||||
|
|
||||||
|
├ INFO[PhaseA]: 预注册 struct/enum/union...
|
||||||
|
[DBG] PhaseA-pre pass=0 struct_count_before=24
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/asm_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/attr_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/augassign_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/circ_a.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/circ_b.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/circ_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/closure_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/deco_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/deref_min_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/deref_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/eq_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/float_test.py
|
||||||
|
├ INFO[UNION]: registered DataUnion with 3 fields, max_size=8
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/flow_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/for_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/func_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/func_vtable_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/inherit_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/llvmir_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/namespace_defs.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/namespace_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/new_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/oop_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/opovl_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/ptr_only_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/ptr_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/simple_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/string_min_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/string_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/struct_test.py
|
||||||
|
├ INFO[ENUM]: registered State with 3 members, base_bits=32
|
||||||
|
├ INFO[ENUM]: registered Color with 4 members, base_bits=32
|
||||||
|
├ INFO[ENUM]: registered MixedType with 3 members, base_bits=64
|
||||||
|
├ INFO[UNION]: registered DataUnion with 3 fields, max_size=8
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/testcheck_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/test_main.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/type_bit_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/virtual_dispatch_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/vtable_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 done struct_count_after=51
|
||||||
|
[DBG] PhaseA-pre pass=1 struct_count_before=51
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/asm_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/attr_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/augassign_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/circ_a.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/circ_b.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/circ_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/closure_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/deco_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/deref_min_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/deref_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/eq_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/float_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/flow_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/for_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/func_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/func_vtable_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/inherit_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/llvmir_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/namespace_defs.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/namespace_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/new_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/oop_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/opovl_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/ptr_only_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/ptr_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/simple_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/string_min_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/string_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/struct_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/testcheck_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/test_main.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/type_bit_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/virtual_dispatch_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/vtable_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 done struct_count_after=51
|
||||||
|
├ INFO[PhaseA]: 预注册完成
|
||||||
|
[DBG] PhaseA full-translate start
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/asm_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/attr_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/augassign_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/circ_a.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/circ_b.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/circ_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/closure_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/deco_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/deref_min_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/deref_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/eq_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/float_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/flow_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/for_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/func_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/func_vtable_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/inherit_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/llvmir_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/namespace_defs.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/namespace_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/new_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/oop_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/opovl_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/ptr_only_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/ptr_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/simple_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/string_min_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/string_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/struct_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/testcheck_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/test_main.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/type_bit_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/virtual_dispatch_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/vtable_test.py
|
||||||
|
[DBG] before Phase B
|
||||||
|
|
||||||
|
=== Phase B: 编译 .obj ===
|
||||||
|
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/asm_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=80241c7d6f357bd1
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=51574
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/attr_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=17c0dfbcebfa3a0e
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=72070
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/augassign_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=0eccc2393466d940
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=53827
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/circ_a.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=ac47a9dc68e6834c
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=51031
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/circ_b.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=04d33c721a603632
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=51025
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/circ_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=5314f09055045035
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=56407
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/closure_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=9d8e1c9631c28b1b
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=52838
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/deco_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=b7bbe6a1c1e75ad8
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=68777
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/deref_min_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=6f5e876273093314
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=50111
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/deref_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=eb252050d92f8fb9
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=50661
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/eq_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=b8cbe044a10adcca
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=67044
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/float_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=e74870eba3e6d774
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=57074
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/flow_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=969c589035910845
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=51773
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/for_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=1eb1c9fc7e85d9f8
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=50124
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/func_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=3c2fbc9e35ad3bf2
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=54695
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/func_vtable_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=a9df037d9178888f
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=60040
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/inherit_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=97043f0d52da437f
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=63006
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/llvmir_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=c39f3e540adb7b4e
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=72025
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/namespace_defs.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=b7eeff93aa63e70f
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=52547
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/namespace_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=ef45adce81bf5b2d
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=63978
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/new_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=9d798d964b9d3411
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=59175
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/oop_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=1b9ab264a942c56b
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=62087
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/opovl_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=a7cf0ce4066332ae
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=82295
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/ptr_only_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=ed1c124f3cb787c9
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=52176
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/ptr_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=07f7da85af876124
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=59942
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/simple_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=b078e9c9c74a2a0c
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=49754
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/string_min_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=74ca31446cac2107
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=54019
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/string_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=e0009679269c6b63
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=65173
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/struct_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=33a854a5c4f67d74
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=71825
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/testcheck_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=d7662500f1c2c0ff
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=58573
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/test_main.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=ff744980c190e9b0
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=57150
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/type_bit_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=55cbbb5dec4fef2c
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=52348
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/virtual_dispatch_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=cc3ad7f3bc880326
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=59792
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/vtable_test.py
|
||||||
|
[DBG] PhaseB step=alloc combined_ir
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR sha1=2769dee537308b00
|
||||||
|
[DBG] PhaseB step=BuildCombinedIR done len=56517
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj
|
||||||
|
[DBG] PhaseB step=compile_module_to_obj done cret=0
|
||||||
|
[DBG] PhaseB step=obj_path construct
|
||||||
|
[DBG] PhaseB step=obj_path done
|
||||||
|
[DBG] PhaseB loop done compiled_count=34
|
||||||
|
├ SUCCESS[PhaseB]: 编译完成: 34/34
|
||||||
|
[DBG] PhaseB+ start
|
||||||
|
[DBG] PhaseB+ store_count=93
|
||||||
0
test_stderr.log
Normal file
0
test_stderr.log
Normal file
241
test_stdout.log
Normal file
241
test_stdout.log
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
[DBG] main enter
|
||||||
|
├ INFO: TransPyV 启动
|
||||||
|
|
||||||
|
=== TransPyV 参数解析结果 ===
|
||||||
|
|
||||||
|
--project: TransPyV/Test/project.vpj
|
||||||
|
--src: (未指定)
|
||||||
|
--temp: (未指定)
|
||||||
|
--output: (未指定)
|
||||||
|
--phase: (未指定,默认 all)
|
||||||
|
--cc: (未指定)
|
||||||
|
--clean: True
|
||||||
|
--run: False
|
||||||
|
--rebuild-includes: False
|
||||||
|
--clear-cache: False
|
||||||
|
|
||||||
|
参数解析完成。
|
||||||
|
[DBG] before Load_project_config path=TransPyV/Test/project.vpj
|
||||||
|
|
||||||
|
=== 工程配置 ===
|
||||||
|
|
||||||
|
[DBG] Load_project_config OK
|
||||||
|
[DBG] before resolve_paths dir=TransPyV/Test
|
||||||
|
[DBG] resolve_paths OK
|
||||||
|
├ INFO[config]: project: AstTest v1.0.0
|
||||||
|
├ INFO[config]: source_dir: TransPyV/Test/App
|
||||||
|
├ INFO[config]: build_dir: TransPyV/Test/.tpv_build
|
||||||
|
├ INFO[config]: temp_dir: TransPyV/Test/.tpv_build/temp
|
||||||
|
├ INFO[config]: output_dir: TransPyV/Test/.tpv_build/output
|
||||||
|
├ INFO[config]: compiler: llc
|
||||||
|
├ INFO[config]: linker: clang++ -> app.exe
|
||||||
|
├ INFO[config]: includes: TransPyV/Test/../../includes
|
||||||
|
├ INFO[config]: sha1_slice_level: 1
|
||||||
|
[DBG] print_config OK
|
||||||
|
├ INFO[clean]: 清理临时目录...
|
||||||
|
├ INFO[clean]: TransPyV/Test/.tpv_build/temp: 删除 1 个文件
|
||||||
|
├ INFO[clean]: TransPyV/Test/.tpv_build/output: 删除 0 个文件
|
||||||
|
├ INFO[phase]: 模式: all (phase1=1 phase2=1)
|
||||||
|
[DBG] before Phase1.RunPhase1 inc=TransPyV/Test/../../includes temp=TransPyV/Test/.tpv_build/temp
|
||||||
|
|
||||||
|
=== Phase1: 扫描 includes(按需翻译) ===
|
||||||
|
|
||||||
|
├ INFO[Phase1]: 拓扑排序: 25 个类, 15 个文件按依赖顺序处理
|
||||||
|
├ INFO[Phase1]: 完成: 翻译=0 跳过=78 失败=0
|
||||||
|
[DBG] Phase1.RunPhase1 OK
|
||||||
|
[DBG] before Phase2.RunMultiFileProject src=TransPyV/Test/App temp=TransPyV/Test/.tpv_build/temp out=TransPyV/Test/.tpv_build/output
|
||||||
|
[DBG] RunMultiFileProject enter src=TransPyV/Test/App
|
||||||
|
├ INFO[project]: 多文件项目编译: TransPyV/Test/App
|
||||||
|
├ INFO[project]: asm_test.py (sha1=80241c7d6f357bd1)
|
||||||
|
├ INFO[project]: attr_test.py (sha1=17c0dfbcebfa3a0e)
|
||||||
|
├ INFO[project]: augassign_test.py (sha1=0eccc2393466d940)
|
||||||
|
├ INFO[project]: circ_a.py (sha1=ac47a9dc68e6834c)
|
||||||
|
├ INFO[project]: circ_b.py (sha1=04d33c721a603632)
|
||||||
|
├ INFO[project]: circ_test.py (sha1=5314f09055045035)
|
||||||
|
├ INFO[project]: closure_test.py (sha1=9d8e1c9631c28b1b)
|
||||||
|
├ INFO[project]: deco_test.py (sha1=b7bbe6a1c1e75ad8)
|
||||||
|
├ INFO[project]: deref_min_test.py (sha1=6f5e876273093314)
|
||||||
|
├ INFO[project]: deref_test.py (sha1=eb252050d92f8fb9)
|
||||||
|
├ INFO[project]: eq_test.py (sha1=b8cbe044a10adcca)
|
||||||
|
├ INFO[project]: float_test.py (sha1=e74870eba3e6d774)
|
||||||
|
├ INFO[project]: flow_test.py (sha1=969c589035910845)
|
||||||
|
├ INFO[project]: for_test.py (sha1=1eb1c9fc7e85d9f8)
|
||||||
|
├ INFO[project]: func_test.py (sha1=3c2fbc9e35ad3bf2)
|
||||||
|
├ INFO[project]: func_vtable_test.py (sha1=a9df037d9178888f)
|
||||||
|
├ INFO[project]: inherit_test.py (sha1=97043f0d52da437f)
|
||||||
|
├ INFO[project]: llvmir_test.py (sha1=c39f3e540adb7b4e)
|
||||||
|
├ INFO[project]: namespace_defs.py (sha1=b7eeff93aa63e70f)
|
||||||
|
├ INFO[project]: namespace_test.py (sha1=ef45adce81bf5b2d)
|
||||||
|
├ INFO[project]: new_test.py (sha1=9d798d964b9d3411)
|
||||||
|
├ INFO[project]: oop_test.py (sha1=1b9ab264a942c56b)
|
||||||
|
├ INFO[project]: opovl_test.py (sha1=a7cf0ce4066332ae)
|
||||||
|
├ INFO[project]: ptr_only_test.py (sha1=ed1c124f3cb787c9)
|
||||||
|
├ INFO[project]: ptr_test.py (sha1=07f7da85af876124)
|
||||||
|
├ INFO[project]: simple_test.py (sha1=b078e9c9c74a2a0c)
|
||||||
|
├ INFO[project]: string_min_test.py (sha1=74ca31446cac2107)
|
||||||
|
├ INFO[project]: string_test.py (sha1=e0009679269c6b63)
|
||||||
|
├ INFO[project]: struct_test.py (sha1=33a854a5c4f67d74)
|
||||||
|
├ INFO[project]: testcheck_test.py (sha1=d7662500f1c2c0ff)
|
||||||
|
├ INFO[project]: test_main.py (sha1=ff744980c190e9b0)
|
||||||
|
├ INFO[project]: type_bit_test.py (sha1=55cbbb5dec4fef2c)
|
||||||
|
├ INFO[project]: virtual_dispatch_test.py (sha1=cc3ad7f3bc880326)
|
||||||
|
├ INFO[project]: vtable_test.py (sha1=2769dee537308b00)
|
||||||
|
[DBG] scan done file_count=34
|
||||||
|
├ INFO[project]: 共 34 个源文件
|
||||||
|
├ INFO[project]: 已追加 34 个 App 文件到 _sha1_map.txt
|
||||||
|
[DBG] before Phase A
|
||||||
|
|
||||||
|
=== Phase A: 生成 stub + text ===
|
||||||
|
|
||||||
|
├ INFO[PhaseA]: 预注册 struct/enum/union...
|
||||||
|
[DBG] PhaseA-pre pass=0 struct_count_before=24
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/asm_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/attr_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/augassign_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/circ_a.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/circ_b.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/circ_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/closure_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/deco_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/deref_min_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/deref_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/eq_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/float_test.py
|
||||||
|
├ INFO[UNION]: registered DataUnion with 3 fields, max_size=8
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/flow_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/for_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/func_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/func_vtable_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/inherit_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/llvmir_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/namespace_defs.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/namespace_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/new_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/oop_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/opovl_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/ptr_only_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/ptr_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/simple_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/string_min_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/string_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/struct_test.py
|
||||||
|
├ INFO[ENUM]: registered State with 3 members, base_bits=32
|
||||||
|
├ INFO[ENUM]: registered Color with 4 members, base_bits=32
|
||||||
|
├ INFO[ENUM]: registered MixedType with 3 members, base_bits=64
|
||||||
|
├ INFO[UNION]: registered DataUnion with 3 fields, max_size=8
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/testcheck_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/test_main.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/type_bit_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/virtual_dispatch_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 file=TransPyV/Test/App/vtable_test.py
|
||||||
|
[DBG] PhaseA-pre pass=0 done struct_count_after=51
|
||||||
|
[DBG] PhaseA-pre pass=1 struct_count_before=51
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/asm_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/attr_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/augassign_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/circ_a.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/circ_b.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/circ_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/closure_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/deco_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/deref_min_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/deref_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/eq_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/float_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/flow_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/for_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/func_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/func_vtable_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/inherit_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/llvmir_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/namespace_defs.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/namespace_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/new_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/oop_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/opovl_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/ptr_only_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/ptr_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/simple_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/string_min_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/string_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/struct_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/testcheck_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/test_main.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/type_bit_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/virtual_dispatch_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 file=TransPyV/Test/App/vtable_test.py
|
||||||
|
[DBG] PhaseA-pre pass=1 done struct_count_after=51
|
||||||
|
├ INFO[PhaseA]: 预注册完成
|
||||||
|
[DBG] PhaseA full-translate start
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/asm_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/attr_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/augassign_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/circ_a.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/circ_b.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/circ_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/closure_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/deco_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/deref_min_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/deref_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/eq_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/float_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/flow_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/for_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/func_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/func_vtable_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/inherit_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/llvmir_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/namespace_defs.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/namespace_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/new_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/oop_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/opovl_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/ptr_only_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/ptr_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/simple_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/string_min_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/string_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/struct_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/testcheck_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/test_main.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/type_bit_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/virtual_dispatch_test.py
|
||||||
|
[DBG] PhaseA file=TransPyV/Test/App/vtable_test.py
|
||||||
|
[DBG] before Phase B
|
||||||
|
|
||||||
|
=== Phase B: 编译 .obj ===
|
||||||
|
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/asm_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/attr_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/augassign_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/circ_a.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/circ_b.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/circ_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/closure_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/deco_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/deref_min_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/deref_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/eq_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/float_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/flow_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/for_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/func_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/func_vtable_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/inherit_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/llvmir_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/namespace_defs.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/namespace_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/new_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/oop_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/opovl_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/ptr_only_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/ptr_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/simple_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/string_min_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/string_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/struct_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/testcheck_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/test_main.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/type_bit_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/virtual_dispatch_test.py
|
||||||
|
[DBG] PhaseB file=TransPyV/Test/App/vtable_test.py
|
||||||
Reference in New Issue
Block a user