commit bffb0cb6b79e0c2a8e50c8c50a9ec903736a3609 Author: TermiNexus Date: Tue Jun 16 16:09:42 2026 +0800 补充 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42ac223 --- /dev/null +++ b/.gitignore @@ -0,0 +1,73 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# 编译输出 +*.exe +*.out +*.o +*.obj +*.a +*.lib +*.dll +*.so + +# 调试文件 +*.p2c +debug.txt +*.ll + +# 备份文件 +* copy.py +* copy.c + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# 测试输出 +test.exe +test_split.exe + +# 排除独立仓库的目录 +ViperOS/ +zlib copy/ + +# 磁盘镜像 +*.img +*.vmdk +*.7z +*.fd + +# 日志文件 +*.log + +# 字体文件 +*.ttc +*.ttf + +# VMware +Undo/vmware/ + +# Trae AI +.trae/ diff --git a/BenchmarkProject/App/benchmark_main.py b/BenchmarkProject/App/benchmark_main.py new file mode 100644 index 0000000..4c4261e --- /dev/null +++ b/BenchmarkProject/App/benchmark_main.py @@ -0,0 +1,391 @@ +from stdlib import malloc, free +from stdint import * +import string +import w32.win32console +from stdarg import va_start, va_end, va_arg, va_list +import t +import c + + +class Struct1: + a: UINT + b: UINT = 123 + + +class Item: + data: t.CVoid | t.CPtr + size: t.CSizeT + + +class List: + items: Item | t.CPtr + count: t.CSizeT = 0 + capacity: t.CSizeT = 4 + + def __init__(self): + self.count = 0 + self.capacity = 4 + self.items = malloc(self.capacity * Item.__sizeof__()) + + def append(self, data: t.CVoid | t.CPtr, size: t.CSizeT): + self.count += 1 + item: Item | t.CPtr = self.items[self.count - 1] + item.size = size + item.data = malloc(size + 1) + memcpy(item.data, data, size) + + def get(self, index: t.CSizeT) -> t.CInt8T | t.CPtr: + if index >= self.count: + return None + return self.items[index].data + + def free(self): + i: t.CSizeT = 0 + for i in range(self.count): + if self.items[i].data != 0: + free(self.items[i].data) + free(self.items) + + +class EnumTest(t.CEnum): + A: c.State + B: c.State + C: c.State + Len: c.State + + +@t.Object +class OOPTest: + a: UINT + b: UINT = 12345 + c: UINT + + def __init__(self): + self.a = 451 + + def set_c(self, v: UINT): + self.c = v + + def __call__(self, a: UINT, b: UINT) -> UINT: + return a + b + + def __enter__(self) -> 'OOPTest' | t.CPtr: + return self + + def __exit__(self): + self.a = 99 + self.b = 99 + self.c = 99 + + def __add__(self, other: 'OOPTest' | t.CPtr) -> 'OOPTest' | t.CPtr: + s = OOPTest() + s.a = (self.a + other.a) + return s + + def __str__(self) -> str: + return f"OOPTest ({self.a}) ({self.b}) ({self.c})" + + def __bool__(self) -> bool: + return bool(self.a != 0) + + def __len__(self) -> UINT: + return self.a + + +@t.Object +class RangeOOPSimulation: + start: UINT + end: UINT + + def __init__(self, start: UINT, end: UINT): + self.start = start + self.end = end + + def __iter__(self) -> 'RangeOOPSimulation' | t.CPtr: + return self + + def __next__(self) -> UINT: + if self.start >= self.end: + raise StopIteration + self.start += 1 + return self.start - 1 + + +GLOBAL_VAR: t.CInt = 0 + + +def rebutnotreGLOBAL_VAR() -> t.CInt: + GLOBAL_VAR = 100 + + +def reGLOBAL_VAR() -> t.CInt: + global GLOBAL_VAR + GLOBAL_VAR = 100 + + +def function2function() -> t.CInt: + def func() -> t.CInt: + x = 1000 + + def func2() -> t.CInt: + nonlocal x + x = 1000000 + + func2() + return x + + return func() + + +def manyreturn() -> tuple[t.CInt, t.CInt]: + return 114, 514 + + +def str_to_hex(s: str) -> str: + buf: str = malloc(1024) + out: str = buf + hex_chars: list[t.CChar, None] = "0123456789ABCDEF" + while c.Cast(s) != 0: + cr: t.CUnsignedChar = c.CCast(s) + c.Set(c.CCast(out), hex_chars[(cr >> 4) & 0xF]) + out += 1 + c.Set(c.CCast(out), hex_chars[cr & 0xF]) + out += 1 + s += 1 + c.Set(c.CCast(out), 0) + return buf + + +def int_to_hex(num: int) -> str: + buf = t.CChar(malloc(128), t.CPtr) + if not buf: + return None + + hex_chars: list[t.CChar, None] = "0123456789ABCDEF" + i = 0 + + buf[i] = '0' + buf[i + 1] = 'x' + i += 2 + + if num == 0: + buf[i] = '0' + i += 1 + buf[i] = '0' + i += 1 + buf[i] = '\0' + return buf + + temp: list[t.CChar, 32] + temp_idx = 0 + + n: t.CUnsignedInt = t.CUnsignedInt(num) + + while n > 0: + rem: t.CInt = n & 0xF + temp[temp_idx] = hex_chars[rem] + temp_idx += 1 + n = n >> 4 + + while temp_idx > 0: + temp_idx -= 1 + buf[i] = temp[temp_idx] + i += 1 + + buf[i] = '\0' + return buf + + +def int_to_str(num: int) -> str: + buf: t.CChar | t.CPtr = t.CChar(malloc(128), t.CPtr) + if not buf: + return None + is_negative = 0 + i = 0 + if num == 0: + buf[i] = '0' + i += 1 + buf[i] = '\0' + return buf + if num < 0: + is_negative = 1 + num = -num + while num > 0: + rem = num % 10 + buf[i] = '0' + rem + i += 1 + num = num / 10 + if is_negative: + buf[i] = '-' + i += 1 + buf[i] = '\0' + start = 0 + end = i - 1 + while start < end: + tr: t.CChar = buf[start] + buf[start] = buf[end] + buf[end] = tr + start += 1 + end -= 1 + return buf + + +def main(): + w32.win32console.SetConsoleOutputCP(65001) + w32.win32console.SetConsoleCP(65001) + + print("============== BENCHMARK 1: Structures & OOP ==============") + + print("\nTesting Struct1:") + s1_: Struct1 = Struct1(10) + print("s1_.a:", s1_.a) + print("s1_.b:", s1_.b) + + print("\nTesting OOPTest class:") + d = OOPTest() + d.set_c(100) + d.a = 1 + print("d.a:", d.a) + print("d.b:", d.b) + print("d.c:", d.c) + + print("\nTesting __call__ (d(1, 2)):") + print("d(1, 2):", d(1, 2)) + + print("\nTesting __bool__:") + if d: + print("d is truthy (d.a != 0)") + else: + print("d is falsy (d.a == 0)") + + print("\nTesting __len__:") + print("len(d):", len(d)) + + print("\nTesting __str__:") + print("str(d):", str(d)) + + print("\nTesting __add__:") + l = OOPTest() + l.a = 100 + result = d + l + print("(d + l).a:", result.a) + free(l) + free(result) + + print("\nTesting context manager (with statement):") + with OOPTest() as d2: + print("Inside with block, d2(1, 2):", d2(1, 2)) + print("After exit, d2.__str__():", str(d2)) + + print("\nTesting List class:") + l = List() + nihao = "你好!世界" + l.append(c.Addr(114514), t.CInt.__sizeof__()) + l.append(nihao, len(nihao)) + print("List count:", l.count) + l.free() + + print("\n============== BENCHMARK 2: Global Variables & Functions ==============") + + print("\nTesting global variable re-assignment:") + print("Initial GLOBAL_VAR:", GLOBAL_VAR) + rebutnotreGLOBAL_VAR() + print("After rebutnotreGLOBAL_VAR():", GLOBAL_VAR) + reGLOBAL_VAR() + print("After reGLOBAL_VAR():", GLOBAL_VAR) + + print("\nTesting function2function with nonlocal:") + print("function2function():", function2function()) + + print("\nTesting tuple return:") + a: t.CInt + b: t.CInt + a, b = manyreturn() + print("manyreturn():", a, b) + + print("\nTesting walrus operator:") + kkkkk = 0 + if not GLOBAL_VAR or (kkkkk := 1): + print("GLOBAL_VAR is 0, kkkkk:", kkkkk) + print("Final kkkkk:", kkkkk) + + print("\n============== BENCHMARK 3: Memory & Pointers ==============") + + print("\nTesting malloc/free:") + p2 = malloc(100) + i: t.CInt = 0 + while i <= 100: + p2[i] = 4 + i += 1 + all_four = 1 + for i in range(0, 100 + 1): + if p2[i] != 4: + all_four = 0 + break + if all_four: + print("All 4 - Memory write/read verified") + free(p2) + + print("\nTesting for loop with range:") + add_num = 0 + for i in range(0, 100 + 1): + add_num += 1 + print("i:", i, "add_num:", add_num) + + print("\nTesting for loop with continue:") + lll = 0 + for i in range(0, 10 + 1): + if i % 2 != 0: + continue + lll += i + print("Sum of even numbers 0-10:", lll) + + print("\n============== BENCHMARK 4: Iteration & Strings ==============") + + print("\nTesting RangeOOPSimulation (custom iterator):") + print("Iterating RangeOOPSimulation(0, 6):") + for i in RangeOOPSimulation(0, 6): + print("RangeOOPSimulation item:", i) + + print("\nTesting str_to_hex:") + hex_str = str_to_hex("ABCDEF") + print("hex of ABCDEF:", hex_str) + free(hex_str) + + print("\nTesting int_to_hex:") + hex_num = int_to_hex(255) + print("hex of 255:", hex_num) + free(hex_num) + + print("\nTesting int_to_str:") + num_str = int_to_str(-12345) + print("str of -12345:", num_str) + free(num_str) + + print("\nTesting f-string with Chinese characters:") + chinese = "你好" + print(f"{chinese},世界") + + print("\n============== BENCHMARK 5: Exception Handling ==============") + + print("\nTesting try/except/else/finally:") + try: + print("In try block") + assert 1 != 1, "1 == 1" + print("This should not print") + except AssertionError as e: + print("AssertionError caught:", e) + except ValueError as e: + print("ValueError caught:", e) + else: + print("No exception in try block") + finally: + print("Finally block executed") + + free(d) + free(d2) + + print("\n============== All Benchmarks Completed ==============") + + +main() \ No newline at end of file diff --git a/BenchmarkProject/project.json b/BenchmarkProject/project.json new file mode 100644 index 0000000..8104600 --- /dev/null +++ b/BenchmarkProject/project.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "BenchmarkProject", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-lmsvcrt", "-lucrt", "-lpthread"], + "output": "BenchmarkProject.exe" + }, + "includes": [ + "./includes" + ], + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} \ No newline at end of file diff --git a/BenchmarkProject/temp/0a468e9defed89b4.pyi b/BenchmarkProject/temp/0a468e9defed89b4.pyi new file mode 100644 index 0000000..3a375f7 --- /dev/null +++ b/BenchmarkProject/temp/0a468e9defed89b4.pyi @@ -0,0 +1,18 @@ +""" +Auto-generated Python stub file from win32.win32console.py +Module: win32.win32console +""" + + +c.CIfndef(__WIN32.WIN32CONSOLE_DEFINE__) +__WIN32.WIN32CONSOLE_DEFINE__: t.CDefine + +from stdint import * +import t, c + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | c.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | c.State: pass + + +c.CEndif() \ No newline at end of file diff --git a/BenchmarkProject/temp/0fe4ed83e40705a3.pyi b/BenchmarkProject/temp/0fe4ed83e40705a3.pyi new file mode 100644 index 0000000..18ab9bd --- /dev/null +++ b/BenchmarkProject/temp/0fe4ed83e40705a3.pyi @@ -0,0 +1,60 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +c.CIfndef(__STDINT_DEFINE__) +__STDINT_DEFINE__: t.CDefine + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = t.CChar | t.CPtr[t.CPtr] +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr + +c.CEndif() \ No newline at end of file diff --git a/BenchmarkProject/temp/35b3672a3f08a5f6.pyi b/BenchmarkProject/temp/35b3672a3f08a5f6.pyi new file mode 100644 index 0000000..dead830 --- /dev/null +++ b/BenchmarkProject/temp/35b3672a3f08a5f6.pyi @@ -0,0 +1,20 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + + +c.CIfndef(__STDLIB_DEFINE__) +__STDLIB_DEFINE__: t.CDefine + +from stdint import * +import t, c + +def malloc(size: UINT) -> t.CVoid | t.CPtr | c.State: pass + +def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | c.State: pass + +def free(p: t.CVoid | t.CPtr) -> None | c.State: pass + + +c.CEndif() \ No newline at end of file diff --git a/BenchmarkProject/temp/6185874d64b55d5f.pyi b/BenchmarkProject/temp/6185874d64b55d5f.pyi new file mode 100644 index 0000000..c8dac18 --- /dev/null +++ b/BenchmarkProject/temp/6185874d64b55d5f.pyi @@ -0,0 +1,21 @@ +""" +Auto-generated Python stub file from stdarg.py +Module: stdarg +""" + + +c.CIfndef(__STDARG_DEFINE__) +__STDARG_DEFINE__: t.CDefine + +import t, c + +def va_start(args: t.CPtr, last_arg: t.CPtr) -> c.State: pass + +def va_arg(args: t.CPtr, type: t.CType) -> t.CType | c.State: pass + +def va_end(args: t.CPtr) -> c.State: pass + + +va_list: t.CTypedef = t.CUnsignedChar | t.CPtr + +c.CEndif() \ No newline at end of file diff --git a/BenchmarkProject/temp/89a417151096c9c8.pyi b/BenchmarkProject/temp/89a417151096c9c8.pyi new file mode 100644 index 0000000..4237345 --- /dev/null +++ b/BenchmarkProject/temp/89a417151096c9c8.pyi @@ -0,0 +1,39 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +c.CIfndef(__STRING_DEFINE__) +__STRING_DEFINE__: t.CDefine + +import t, c + +def strcpy(dest: t.CChar | t.CPtr, src: t.CConst | t.CChar | t.CPtr) -> t.CChar | t.CPtr | c.State: pass + +def strncpy(dest: t.CChar | t.CPtr, src: t.CConst | t.CChar | t.CPtr, n: t.CSizeT) -> t.CChar | t.CPtr | c.State: pass + +def strlen(str: t.CConst | t.CChar | t.CPtr) -> t.CSizeT | c.State: pass + +def strcmp(str1: t.CConst | t.CChar | t.CPtr, str2: t.CConst | t.CChar | t.CPtr) -> t.CInt | c.State: pass + +def strncmp(str1: t.CConst | t.CChar | t.CPtr, str2: t.CConst | t.CChar | t.CPtr, n: t.CSizeT) -> t.CInt | c.State: pass + +def memcmp(ptr1: t.CConst | t.CVoid | t.CPtr, ptr2: t.CConst | t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt | c.State: pass + +def strchr(str: t.CConst | t.CChar | t.CPtr, cr: t.CInt) -> t.CChar | t.CPtr | c.State: pass + +def strrchr(str: t.CConst | t.CChar | t.CPtr, cr: t.CInt) -> t.CChar | t.CPtr | c.State: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | c.State: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CConst | t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | c.State: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CConst | t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | c.State: pass + +def atoi(s: str) -> t.CInt | c.State: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CConst | t.CChar | t.CPtr, *args) -> t.CInt | c.State: pass + + +c.CEndif() \ No newline at end of file diff --git a/BenchmarkProject/temp/_sha1_map.txt b/BenchmarkProject/temp/_sha1_map.txt new file mode 100644 index 0000000..f14c951 --- /dev/null +++ b/BenchmarkProject/temp/_sha1_map.txt @@ -0,0 +1,6 @@ +0a468e9defed89b4:includes/win32\win32console.pyi +0fe4ed83e40705a3:includes/stdint.pyi +35b3672a3f08a5f6:includes/stdlib.pyi +6185874d64b55d5f:includes/stdarg.pyi +89a417151096c9c8:includes/string.pyi +a5c3e35ade4bf308:benchmark_main.py diff --git a/BenchmarkProject/temp/a5c3e35ade4bf308.pyi b/BenchmarkProject/temp/a5c3e35ade4bf308.pyi new file mode 100644 index 0000000..2c4ba98 --- /dev/null +++ b/BenchmarkProject/temp/a5c3e35ade4bf308.pyi @@ -0,0 +1,78 @@ +""" +Auto-generated Python stub file from benchmark_main.py +Module: benchmark_main +""" + + +c.CIfndef(__BENCHMARK_MAIN_DEFINE__) +__BENCHMARK_MAIN_DEFINE__: t.CDefine + +from stdlib import malloc, free +from stdint import * +import string +import win32.win32console +from stdarg import va_start, va_end, va_arg, va_list +import t +import c + +class Struct1: + a: UINT + b: UINT +class Item: + data: t.CVoid | t.CPtr + size: t.CSizeT +class List: + items: Item | t.CPtr + count: t.CSizeT + capacity: t.CSizeT + def __init__(self: List) -> t.CVoid | c.State: pass + def append(self: List, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | c.State: pass + def get(self: List, index: t.CSizeT) -> t.CInt8T | t.CPtr | c.State: pass + def free(self: List) -> t.CVoid | c.State: pass +class EnumTest(t.CEnum): + A: c.State + B: c.State + C: c.State + Len: c.State +@t.CPythonObject +class OOPTest: + a: UINT + b: UINT + c: UINT + def __init__(self: OOPTest) -> t.CVoid | c.State: pass + def set_c(self: OOPTest, v: UINT) -> t.CVoid | c.State: pass + def __call__(self: OOPTest, a: UINT, b: UINT) -> UINT | c.State: pass + def __enter__(self: OOPTest) -> 'OOPTest' | t.CPtr | c.State: pass + def __exit__(self: OOPTest) -> t.CVoid | c.State: pass + def __add__(self: OOPTest, other: 'OOPTest' | t.CPtr) -> 'OOPTest' | t.CPtr | c.State: pass + def __str__(self: OOPTest) -> str | c.State: pass + def __bool__(self: OOPTest) -> bool | c.State: pass + def __len__(self: OOPTest) -> UINT | c.State: pass +@t.CPythonObject +class RangeOOPSimulation: + start: UINT + end: UINT + def __init__(self: RangeOOPSimulation, start: UINT, end: UINT) -> t.CVoid | c.State: pass + def __iter__(self: RangeOOPSimulation) -> 'RangeOOPSimulation' | t.CPtr | c.State: pass + def __next__(self: RangeOOPSimulation) -> UINT | c.State: pass + +GLOBAL_VAR: t.CExtern | t.CInt + +def rebutnotreGLOBAL_VAR() -> t.CInt | c.State: pass + +def reGLOBAL_VAR() -> t.CInt | c.State: pass + +def function2function() -> t.CInt | c.State: pass + +def manyreturn() -> tuple[t.CInt, t.CInt] | c.State: pass + +def str_to_hex(s: str) -> str | c.State: pass + +def int_to_hex(num: int) -> str | c.State: pass + +def int_to_str(num: int) -> str | c.State: pass + +def main() -> t.CVoid | c.State: pass + + +c.CEndif() \ No newline at end of file diff --git a/CPython/1.c b/CPython/1.c new file mode 100644 index 0000000..f1b3dc9 --- /dev/null +++ b/CPython/1.c @@ -0,0 +1,32 @@ +#include +#include + + +// gcc 1.c -ID:\Python312\include -LD:\Python312\libs -lpython312 -static-libgcc -o 1 +int main() { + SetDllDirectoryW(L"D:\\Python312"); + + PyConfig config; + PyConfig_InitPythonConfig(&config); + config.home = Py_DecodeLocale("D:\\Python312", NULL); + + PyStatus status = Py_InitializeFromConfig(&config); + PyConfig_Clear(&config); + + if (PyStatus_Exception(status)) { + fprintf(stderr, "Failed to initialize Python: %s\n", status.err_msg); + return 1; + } + + PyObject* py_num = PyLong_FromLong(12345); + + PyObject* py_str = PyObject_Str(py_num); + const char* c_str = PyUnicode_AsUTF8(py_str); + printf("%s\n", c_str); + + Py_DECREF(py_str); + Py_DECREF(py_num); + + Py_Finalize(); + return 0; +} diff --git a/CPython/Python/P312/Object.py b/CPython/Python/P312/Object.py new file mode 100644 index 0000000..4c76444 --- /dev/null +++ b/CPython/Python/P312/Object.py @@ -0,0 +1,178 @@ +import t, c + + +Py_uintptr_t: t.CTypedef = t.CUIntPtrT +Py_intptr_t: t.CTypedef = t.CIntPtrT + +PY_UINT32_T: t.CTypedef = t.CUInt32T +PY_UINT64_T: t.CTypedef = t.CUInt64T + +# Signed variants of the above +PY_INT32_T: t.CTypedef = t.CInt32T +PY_INT64_T: t.CTypedef = t.CInt64T + +# * Py_ssize_t is a signed integral type such that sizeof(Py_ssize_t) == +# * sizeof(size_t). C99 doesn't define such a thing directly (size_t is an +# * unsigned integral type). See PEP 353 for details. +# * PY_SSIZE_T_MAX is the largest positive value of type Py_ssize_t. + +Py_ssize_t: t.CTypedef = Py_intptr_t +Py_hash_t: t.CTypedef = Py_ssize_t + +SIZEOF_VOID_P: t.CDefine = 8 + + + +# If this structure is modified, Doc/includes/typestruct.h should be updated +# as well. +class PyTypeObject: + ob_base: PyVarObject + + tp_name: t.CConst | str # For printing, in format "." + tp_basicsize: Py_ssize_t + tp_itemsize: Py_ssize_t # For allocation + + # Methods to implement standard operations + + tp_dealloc: destructor + tp_vectorcall_offset: Py_ssize_t + tp_getattr: getattrfunc + tp_setattr: setattrfunc + tp_as_async: PyAsyncMethods | t.CPtr # formerly known as tp_compare (Python 2) or tp_reserved (Python 3) + tp_repr: reprfunc + + # Method suites for standard classes + + tp_as_number: PyNumberMethods | t.CPtr + tp_as_sequence: PySequenceMethods | t.CPtr + tp_as_mapping: PyMappingMethods | t.CPtr + + # More standard operations (here for binary compatibility) + + tp_hash: hashfunc + tp_call: ternaryfunc + tp_str: reprfunc + tp_getattro: getattrofunc + tp_setattro: setattrofunc + + # Functions to access object as input/output buffer + tp_as_buffer: PyBufferProcs | t.CPtr + + # Flags to define presence of optional/expanded features + tp_flags: t.CUnsignedLong + + tp_doc: t.CConst | str # Documentation string + + # Assigned meaning in release 2.0 + # call function for all accessible objects + tp_traverse: traverseproc + + # delete references to contained objects */ + tp_clear: inquiry + + # Assigned meaning in release 2.1 + # rich comparisons + tp_richcompare: richcmpfunc + + # weak reference enabler + tp_weaklistoffset: Py_ssize_t + + # Iterators + tp_iter: getiterfunc + tp_iternext: iternextfunc + + # Attribute descriptor and subclassing stuff + tp_methods: PyMethodDef | t.CPtr + tp_members: PyMemberDef | t.CPtr + tp_getset: PyGetSetDef | t.CPtr + # Strong reference on a heap type, borrowed reference on a static type + tp_base: PyTypeObject | t.CPtr + tp_dict: PyObject | t.CPtr + tp_descr_get: descrgetfunc + tp_descr_set: descrgetfunc + tp_dictoffset: Py_ssize_t + tp_init: initproc + tp_alloc: allocfunc + tp_new: newfunc + tp_free: freefunc # Low-level free-memory routine + tp_is_gc: inquiry # For PyObject_IS_GC + tp_bases: PyObjectPtr + tp_mro: PyObjectPtr # method resolution order + tp_cache: PyObjectPtr # no longer used + tp_subclasses: t.CVoid | t.CPtr # for static builtin types this is an index + tp_weaklist: PyObjectPtr # not used for static builtin types + tp_del: destructor + + # Type attribute cache version tag. Added in version 2.6 + tp_version_tag: t.CUnsignedInt + + tp_finalize: destructor + tp_vectorcall: vectorcallfunc + + # bitset of which type-watchers care about this type + tp_watched: t.CUnsignedChar + + +class PyMethodDef: + ml_name: t.CConst | str # The name of the built-in function/method */ + ml_meth: PyCFunction # The C function that implements it */ + ml_flags: int # Combination of METH_xxx flags, which mostly describe the args expected by the C func + ml_doc: t.CConst | str # The __doc__ attribute, or NULL + +class PyModuleDef: + m_base: PyModuleDef_Base + m_name: t.CConst | str + m_doc: t.CConst | str + m_size: Py_ssize_t + m_methods: PyMethodDef | t.CPtr + m_slots: PyModuleDef_Slot | t.CPtr + m_traverse: traverseproc + m_clear: inquiry + m_free: freefunc + +class PyMemberDef: + name: t.CConst | str + type: int + offset: Py_ssize_t + flags: int + doc: t.CConst | str + +class PyGetSetDef: + name: t.CConst | str + get: getter + set: setter + doc: t.CConst | str + closure: t.CVoid | t.CPtr + + + + +class PyVarObject: + ob_base: PyObject + ob_size: Py_ssize_t # Number of items in variable part + +class PyObject: + # _PyObject_HEAD_EXTRA + class ob(t.CUnion): + ob_refcnt: Py_ssize_t + if c.CIf(SIZEOF_VOID_P > 4): + ob_refcnt_split: list[PY_UINT32_T, 2] + ob_type: PyTypeObject | t.CPtr + +PyObjectPtr: t.CTypedef = PyObject | t.CPtr + + +#typedef struct PyModuleDef PyModuleDef; +#typedef struct PyModuleDef_Slot PyModuleDef_Slot; +#typedef struct PyMethodDef PyMethodDef; +#typedef struct PyGetSetDef PyGetSetDef; +#typedef struct PyMemberDef PyMemberDef; + +#typedef struct _object PyObject; +#typedef struct _longobject PyLongObject; +#typedef struct _typeobject PyTypeObject; +#typedef struct PyCodeObject PyCodeObject; +#typedef struct _frame PyFrameObject; + +#typedef struct _ts PyThreadState; +#typedef struct _is PyInterpreterState; \ No newline at end of file diff --git a/CPython/Python/P312/PyBytesObject.py b/CPython/Python/P312/PyBytesObject.py new file mode 100644 index 0000000..e126697 --- /dev/null +++ b/CPython/Python/P312/PyBytesObject.py @@ -0,0 +1,37 @@ +import Object +import t, c + + +class PyBytesObject: + ob_base: Object.PyVarObject + ob_shash: Object.Py_hash_t + ob_sval: list[t.CChar, 1] + +def _PyBytes_Resize(arg0: Object.PyObjectPtr[t.CPtr], arg1: Object.Py_ssize_t) -> int | t.State: pass +def _PyBytes_FormatEx(format: t.CConst | str, format_len: Object.Py_ssize_t, args: Object.PyObjectPtr, use_bytearray: int) -> Object.PyObjectPtr | t.State: pass +def _PyBytes_FromHex(string: Object.PyObjectPtr, use_bytearray: int) -> Object.PyObjectPtr | t.State: pass +def _PyBytes_DecodeEscape(arg0: t.CConst | str, arg1: Object.Py_ssize_t, arg2: t.CConst | str, arg3: t.CConst | str | t.CPtr) -> Object.PyObjectPtr | t.State: pass + +def _PyBytes_CAST(op) -> t.CDefine | PyBytesObject: (PyBytesObject | t.CPtr)(op) + +def PyBytes_AS_STRING(op: Object.PyObjectPtr) -> t.CStatic | t.CInline | bytes: + return _PyBytes_CAST(op).ob_sval + +def _PyBytes_Join(sep: Object.PyObjectPtr, x: Object.PyObjectPtr) -> Object.PyObjectPtr | t.State: pass + +class _PyBytesWriter: + buffer: Object.PyObjectPtr + allocated: Object.Py_ssize_t + min_size: Object.Py_ssize_t + use_bytearray: int + overallocate: int + use_small_buffer: int + small_buffer: list[t.CChar, 512] + +def _PyBytesWriter_Init(writer: _PyBytesWriter | t.CPtr) -> t.State: pass +def _PyBytesWriter_Finish(writer: _PyBytesWriter | t.CPtr, str: str) -> Object.PyObjectPtr | t.State: pass +def _PyBytesWriter_Dealloc(writer: _PyBytesWriter | t.CPtr) -> t.State: pass +def _PyBytesWriter_Alloc(writer: _PyBytesWriter | t.CPtr, size: Object.Py_ssize_t) -> bytes | t.State: pass +def _PyBytesWriter_Prepare(writer: _PyBytesWriter | t.CPtr, str: str, size: Object.Py_ssize_t) -> bytes | t.State: pass +def _PyBytesWriter_Resize(writer: _PyBytesWriter | t.CPtr, str: str, size: Object.Py_ssize_t) -> bytes | t.State: pass +def _PyBytesWriter_WriteBytes(writer: _PyBytesWriter | t.CPtr, str: str, bytes: t.CConst | bytes, size: Object.Py_ssize_t) -> bytes | t.State: pass diff --git a/CPython/Python/P312/PyFloatObject.py b/CPython/Python/P312/PyFloatObject.py new file mode 100644 index 0000000..33240db --- /dev/null +++ b/CPython/Python/P312/PyFloatObject.py @@ -0,0 +1,19 @@ +import Object +import t, c + + +class PyFloatObject: + ob_base: Object.PyObject + ob_fval: t.CDouble + + +def PyFloat_AS_DOUBLE(op: Object.PyObjectPtr) -> t.CStatic | t.CInline | t.CDouble: + return (PyFloatObject | t.CPtr)(op).ob_fval + +def PyFloat_Pack2(x: t.CDouble, p: str, le: int) -> int | t.State: pass +def PyFloat_Pack4(x: t.CDouble, p: str, le: int) -> int | t.State: pass +def PyFloat_Pack8(x: t.CDouble, p: str, le: int) -> int | t.State: pass + +def PyFloat_Unpack2(p: t.CConst | str, le: int) -> t.CDouble | t.State: pass +def PyFloat_Unpack4(p: t.CConst | str, le: int) -> t.CDouble | t.State: pass +def PyFloat_Unpack8(p: t.CConst | str, le: int) -> t.CDouble | t.State: pass diff --git a/CPython/Python/P312/PyListObject.py b/CPython/Python/P312/PyListObject.py new file mode 100644 index 0000000..9b905f1 --- /dev/null +++ b/CPython/Python/P312/PyListObject.py @@ -0,0 +1,11 @@ +import Object +import t, c + + +class PyListObject: + ob_base: Object.PyVarObject + ob_item: Object.PyObjectPtr[t.CPtr] + allocated: Object.Py_ssize_t + +def _PyList_Extend(arg0: PyListObject | t.CPtr, arg1: PyListObject | t.CPtr) -> PyListObject | t.CPtr | t.State: pass +def _PyList_DebugMallocStats(out: FILE | t.CPtr) -> t.State: pass diff --git a/CPython/Python/P312/PyLongObject.py b/CPython/Python/P312/PyLongObject.py new file mode 100644 index 0000000..b816284 --- /dev/null +++ b/CPython/Python/P312/PyLongObject.py @@ -0,0 +1,16 @@ +import Object +import t, c + + +digit: t.CTypedef = t.CUInt32T +sdigit: t.CTypedef = t.CInt32T # signed variant of digit +twodigits: t.CTypedef = t.CUInt64T +stwodigits: t.CTypedef = t.CInt64T # signed variant of twodigits + +class _PyLongValue: + lv_tag: t.CUIntPtrT # Number of digits, sign and flags + ob_digit: list[digit, 1] + +class PyLongObject: + ob_base: Object.PyObject + long_value: _PyLongValue diff --git a/CPython/Python/P312/PyUnicodeObject.py b/CPython/Python/P312/PyUnicodeObject.py new file mode 100644 index 0000000..d5b9f92 --- /dev/null +++ b/CPython/Python/P312/PyUnicodeObject.py @@ -0,0 +1,38 @@ +import Object +import t, c + + +# --- Unicode Type ------------------------------------------------------- +# ASCII-only strings created through PyUnicode_New use the PyASCIIObject +# structure. state.ascii and state.compact are set, and the data +# immediately follow the structure. utf8_length can be found +# in the length field; the utf8 pointer is equal to the data pointer. */ +class PyASCIIObject: + ob_base: Object.PyObject + length: Object.Py_ssize_t # Number of code points in the string + hash: Object.Py_hash_t # Hash value; -1 if not set + class state: + interned: t.CUnsignedInt | t.Bit[2] + kind: t.CUnsignedInt | t.Bit[3] + compact: t.CUnsignedInt | t.Bit[1] + ascii: t.CUnsignedInt | t.Bit[1] + _: t.CUnsignedInt | t.Bit[25] + +class PyCompactUnicodeObject: + _base: PyASCIIObject + utf8_length: Object.Py_ssize_t # Number of bytes in utf8, excluding the * terminating \0. + utf8: str # UTF-8 representation (null-terminated) + +Py_UCS4: t.CTypedef = t.CUInt32T +Py_UCS2: t.CTypedef = t.CUInt16T +Py_UCS1: t.CTypedef = t.CUInt8T + +# Object format for Unicode subclasses. +class PyUnicodeObject: + _base: PyCompactUnicodeObject + class data(t.CUnion): + any: t.CVoid | t.CPtr + latin1: Py_UCS1 | t.CPtr + ucs2: Py_UCS2 | t.CPtr + ucs4: Py_UCS4 | t.CPtr + # Canonical, smallest-form Unicode buffer diff --git a/CPython/c.py b/CPython/c.py new file mode 100644 index 0000000..3370618 --- /dev/null +++ b/CPython/c.py @@ -0,0 +1,690 @@ +# C语法定义模块 + +import ast +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) + +from . import t + +def _to_str(node): + if node is None: + return '' + if isinstance(node, str): + return node + if isinstance(node, list): + return ' && '.join([_to_str(n) for n in node]) + NodeType = type(node).__name__ + if NodeType == 'Constant': + return node.value + elif NodeType == 'ID': + return node.name + elif NodeType == 'BinaryOp': + left = _to_str(node.left) + right = _to_str(node.right) + return f'{left} {node.op} {right}' + elif NodeType == 'UnaryOp': + expr = _to_str(node.expr) + return f'{node.op}{expr}' + else: + return repr(node) + +class Asm: + @staticmethod + def HandleCall(translator, args, keywords): + if not args: + return ['__asm__ volatile ("nop");'] + + # ========== 核心变量 ========== + output_ops = [] # (值表达式, 约束符) + input_ops = [] # (值表达式, 约束符) + clobbers = [] # 破坏列表实际值 + operand_seq = 0 # 占位符编号 + + # ========== 核心修复:递归提取ASM_DESCR值(支持|组合) ========== + def parse_asm_descr(expr): + """ + 递归解析AST节点,确保获取t.ASM_DESCR的实际值,支持|组合 + 处理场景: + 1. t.ASM_DESCR.XXX → 取属性值 + 2. t.ASM_DESCR.XXX | t.ASM_DESCR.YYY → 拼接两个值 + 3. 常量字符串 → 直接返回 + """ + # 场景1:位或组合(XXX | YYY) + if isinstance(expr, ast.BinOp): + left_val = parse_asm_descr(expr.left) + right_val = parse_asm_descr(expr.right) + return left_val + right_val + + # 场景2:t.ASM_DESCR.XXX 多层属性访问 + elif isinstance(expr, ast.Attribute): + # 第一步:判断是否是 t.ASM_DESCR 的属性 + if isinstance(expr.value, ast.Attribute): + # 内层是 t.ASM_DESCR + if (isinstance(expr.value.value, ast.Name) and + expr.value.value.id == 't' and + expr.value.attr == 'ASM_DESCR'): + # 取 t.ASM_DESCR.XXX 的实际值 + AttrName = expr.attr + if hasattr(t.ASM_DESCR, AttrName): + return getattr(t.ASM_DESCR, AttrName, "") + + # 兼容 t.XXX 简化写法(如果有的话) + elif isinstance(expr.value, ast.Name) and expr.value.id == 't': + AttrName = expr.attr + if hasattr(t.ASM_DESCR, AttrName): + return getattr(t.ASM_DESCR, AttrName, "") + + # 场景3:直接传常量(如 "r"、"cc") + elif isinstance(expr, ast.Constant): + return expr.value + + # 其他场景返回空 + return "" + + # ========== 步骤1:处理f-string中的内联AsmInp/AsmOut ========== + asm_code = "" + first_arg = args[0] + + if isinstance(first_arg, ast.JoinedStr): + asm_parts = [] + for part in first_arg.values: + if isinstance(part, ast.Constant): + asm_parts.append(part.value) + elif isinstance(part, ast.FormattedValue): + expr = part.value + if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute) and expr.func.value.id == 'c': + # 解析内联的AsmInp/AsmOut + call_node = expr + val_ExprNode = translator.HandleExpr(call_node.args[0])[0] if len(call_node.args)>=1 else "" + if isinstance(val_ExprNode, str): + val_expr = val_ExprNode + else: + try: + val_expr = str(val_ExprNode) + except: + val_expr = '' + constraint = parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" + + if call_node.func.attr == 'AsmOut': + output_ops.append((val_expr, constraint)) + asm_parts.append(f"%{operand_seq}") + operand_seq += 1 + elif call_node.func.attr == 'AsmInp': + input_ops.append((val_expr, constraint)) + asm_parts.append(f"%{operand_seq}") + operand_seq += 1 + else: + asm_parts.append(translator.HandleExpr(expr)[0]) + asm_code = ''.join(asm_parts) + elif isinstance(first_arg, ast.Constant): + asm_code = first_arg.value + + # ========== 步骤2:处理参数中的AsmInp/AsmOut和破坏列表 ========== + def parse_operand(arg): + """解析 AsmInp/AsmOut 参数""" + if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute) and arg.func.value.id == 'c': + call_node = arg + val_ExprNode = translator.HandleExpr(call_node.args[0])[0] if len(call_node.args)>=1 else "" + if isinstance(val_ExprNode, str): + val_expr = val_ExprNode + else: + try: + val_expr = str(val_ExprNode) + except: + val_expr = '' + constraint = parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" + + if call_node.func.attr == 'AsmOut': + return ('out', val_expr, constraint) + elif call_node.func.attr == 'AsmInp': + return ('in', val_expr, constraint) + return None + + for arg in args[1:]: + result = parse_operand(arg) + if result: + direction, val_expr, constraint = result + if direction == 'out': + output_ops.append((val_expr, constraint)) + operand_seq += 1 + elif direction == 'in': + input_ops.append((val_expr, constraint)) + operand_seq += 1 + elif isinstance(arg, ast.List): + # 解析破坏列表(支持|组合) + for elt in arg.elts: + clobber_val = parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + + # ========== 步骤2.5:处理关键字参数 out 和 op ========== + for kw in keywords: + if kw.arg == 'out': + # 处理 out 关键字参数 (输出操作数) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + result = parse_operand(elt) + if result and result[0] == 'out': + output_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Call): + result = parse_operand(kw.value) + if result and result[0] == 'out': + output_ops.append((result[1], result[2])) + operand_seq += 1 + elif kw.arg == 'op': + # 处理 op 关键字参数 (clobber,破坏列表) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + clobber_val = parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + elif kw.arg == 'inp' or kw.arg == 'inputs': + # 处理 inp/inputs 关键字参数 (输入操作数,追加到f-string中已有输入之后) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + if isinstance(elt, ast.Tuple): + # 处理列表中的 (value, constraint) 元组格式 + if len(elt.elts) >= 2: + val_ExprNode = translator.HandleExpr(elt.elts[0])[0] if len(elt.elts) >= 1 else "" + if isinstance(val_ExprNode, str): + val_expr = val_ExprNode + else: + try: + val_expr = str(val_ExprNode) + except: + val_expr = '' + constraint = parse_asm_descr(elt.elts[1]) + input_ops.append((val_expr, constraint)) + operand_seq += 1 + else: + result = parse_operand(elt) + if result and result[0] == 'in': + input_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Call): + result = parse_operand(kw.value) + if result and result[0] == 'in': + input_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Tuple): + # 处理 (value, constraint) 元组格式 + if len(kw.value.elts) >= 2: + val_ExprNode = translator.HandleExpr(kw.value.elts[0])[0] if len(kw.value.elts) >= 1 else "" + if isinstance(val_ExprNode, str): + val_expr = val_ExprNode + else: + try: + val_expr = str(val_ExprNode) + except: + val_expr = '' + constraint = parse_asm_descr(kw.value.elts[1]) + input_ops.append((val_expr, constraint)) + operand_seq += 1 + elif kw.arg == 'clobber': + # 处理 clobber 关键字参数 + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + clobber_val = parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + + # ========== 步骤3:格式化汇编代码 ========== + asm_lines = [line.strip() for line in asm_code.split('\n') if line.strip()] + formatted_asm = '\n '.join([f'"{line}\\n"' for line in asm_lines]) + + # ========== 步骤4:拼接约束字符串 ========== + # 输出约束:如果约束已包含 = 或 +,直接使用;否则添加 = + def format_constraint(constraint, is_output=True): + if not constraint: + return "" + # 如果约束已包含修饰符,直接返回 + if '=' in constraint or '+' in constraint: + return constraint + # 否则添加适当的修饰符 + return ('=' if is_output else '') + constraint + + out_const = ', '.join([f'"{format_constraint(c, True)}"({v})' for v, c in output_ops]) if output_ops else "" + in_const = ', '.join([f'"{format_constraint(c, False)}"({v})' for v, c in input_ops]) if input_ops else "" + clobber_const = ', '.join([f'"{x}"' for x in clobbers]) if clobbers else "" + + # 构建约束部分:确保冒号格式正确 + constraint_parts = [] + # 输出约束 + if output_ops: + constraint_parts.append(f': {out_const}') + elif input_ops or clobbers: + constraint_parts.append(':') + + # 输入约束 + if input_ops: + constraint_parts.append(f': {in_const}') + elif clobbers: + constraint_parts.append(':') + + # 破坏列表 + if clobbers: + constraint_parts.append(f': {clobber_const}') + + constraint_str = ' '.join(constraint_parts) + + # ========== 生成最终代码 ========== + final_asm = f'__asm__ __volatile__ (\n {formatted_asm} {constraint_str});' + return [final_asm] + +class AsmInp: + def __init__(self, value, constraint): + self.value = value + self.constraint = constraint + @staticmethod + def HandleCall(translator, args, keywords): + return [] + +class AsmOut: + def __init__(self, value, constraint): + self.value = value + self.constraint = constraint + @staticmethod + def HandleCall(translator, args, keywords): + return [] + +class NoBreak: + """ switch 分支无break """ + pass + +class Break: + """ switch 分支提前break """ + pass + +class Load: + """解引用a写入b,等价于 *b = *a,无拷贝副作用""" + def __init__(self, src, dst): + self.src = src + self.dst = dst + + @staticmethod + def HandleCall(translator, args, keywords): + if len(args) >= 2: + src = translator.HandleExpr(args[0])[0] + dst = translator.HandleExpr(args[1])[0] + return [f'*({dst}) = *({src})'] + return [] + + +class Addr: + """取地址""" + def __init__(self, addr): + self.addr = addr + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.Addr() 调用""" + if args: + expr = translator.HandleExpr(args[0])[0] + if isinstance(expr, str): + return [f'&{expr}'] + return [f'&{_to_str(expr)}'] + return ['0'] + + +class Deref: + """解引用""" + def __init__(self, ptr): + self.ptr = ptr + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.Deref() 调用""" + if args: + expr = translator.HandleExpr(args[0])[0] + if hasattr(expr, 'op') and expr.op == '*': + return [expr] + return [f'*({_to_str(expr)})'] + return ['0'] + + +class DerefAs: + """解引用写入,等价于 *ptr = value""" + def __init__(self, ptr, value): + self.ptr = ptr + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.DerefAs() 调用""" + if len(args) >= 2: + ptr = translator.HandleExpr(args[0])[0] + val = translator.HandleExpr(args[1])[0] + return [f'*({_to_str(ptr)}) = {_to_str(val)}'] + return [] + + +class Set: + """设置值""" + def __init__(self, key, value): + self.key = key + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.Set() 调用""" + if len(args) >= 2: + target = translator.HandleExpr(args[0])[0] + value = translator.HandleExpr(args[1])[0] + return [f'{_to_str(target)} = {_to_str(value)}'] + return [] + + +class CReturn: + """多返回值装饰器 + + 用于实现函数多返回值,通过匿名结构体返回实现。 + 例如:@c.CReturn(t.CInt, t.CInt) 表示函数返回两个 int 值。 + 等价于 -> tuple[t.CInt, t.CInt] 返回类型注解。 + + 规则: + 1. CReturn 中有几个类型就说明要返回几个值 + 2. 函数返回类型为匿名结构体 { type1, type2, ... } + 3. return 语句使用 insert_value 构建结构体 + 4. 调用处使用 extract_value 提取各字段 + """ + def __init__(self, *ReturnTypes): + self.ReturnTypes = ReturnTypes + + def __call__(self, func): + """装饰器调用""" + # 将返回类型信息附加到函数上 + func._CreturnTypes = self.ReturnTypes + return func + + +class CDefine: + """#define 宏定义""" + def __init__(self, name, value): + self.name = name + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CDefine() 调用""" + if len(args) >= 1: + if isinstance(args[0], ast.Constant): + name = args[0].value + else: + name = 'MACRO' + if len(args) >= 2: + value = translator.HandleExpr(args[1])[0] + return ['#define ' + str(name) + ' ' + _to_str(value)] + return ['#define ' + str(name)] + return [] + + +class CIfndef: + """#ifndef 条件编译""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CIfndef() 调用""" + if args: + condition = translator.HandleExpr(args[0])[0] + return ['#ifndef ' + _to_str(condition)] + return ['#if 0'] + +class CIfdef: + """#ifdef 条件编译""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CIfdef() 调用""" + if args: + condition = translator.HandleExpr(args[0])[0] + return ['#ifdef ' + _to_str(condition)] + return ['#if 0'] + +class CError: + """#error 错误信息""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CError() 调用""" + if args: + # 如果是字符串常量,保留引号 + if isinstance(args[0], ast.Constant) and isinstance(args[0].value, str): + return ['#error "' + args[0].value + '"'] + elif isinstance(args[0], ast.Str): + return ['#error "' + args[0].s + '"'] + else: + condition = translator.HandleExpr(args[0])[0] + return ['#error ' + _to_str(condition)] + return ['#error "Error: Condition is not met."'] + + +class TokenPast: + """## 连接符""" + def __init__(self, left, right): + self.left = left + self.right = right + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.TokenPast() 调用""" + if len(args) >= 2: + # 处理左操作数 - 去掉引号 + if isinstance(args[0], ast.Constant): + left = str(args[0].value) + elif isinstance(args[0], ast.Str): + left = str(args[0].s) + elif isinstance(args[0], ast.Name): + left = args[0].id + else: + left = _to_str(translator.HandleExpr(args[0])[0]) + + # 处理右操作数 - 去掉引号 + if isinstance(args[1], ast.Constant): + right = str(args[1].value) + elif isinstance(args[1], ast.Str): + right = str(args[1].s) + elif isinstance(args[1], ast.Name): + right = args[1].id + else: + right = _to_str(translator.HandleExpr(args[1])[0]) + + # 返回字符串,但用特殊标记包装,让 _AstNodeToStr 能正确处理 + result = left + ' ## ' + right + # 使用一个特殊的类来包装结果,让 _AstNodeToStr 直接返回其值 + class TokenPastResult: + def __init__(self, value): + self.value = value + def __str__(self): + return self.value + return [TokenPastResult(result)] + return [''] + + +class CIf: + """#if 条件编译""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CIf() 调用""" + if args: + condition = translator.HandleExpr(args[0])[0] + return ['#if ' + _to_str(condition)] + return ['#if 0'] + + +class CElif: + """#elif 条件编译""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CElif() 调用""" + if args: + condition = translator.HandleExpr(args[0])[0] + return ['#elif ' + _to_str(condition)] + return ['#else'] + + +class CElse: + """#else 条件编译""" + def __init__(self): + pass + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CElse() 调用""" + return ['#else'] + + +class CEndif: + """#endif 条件编译""" + def __init__(self): + pass + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CEndif() 调用""" + return ['#endif'] + + +class CUndef: + """#undef 取消宏定义""" + def __init__(self, name): + self.name = name + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CUndef(name) 调用""" + import ast + if args: + arg = args[0] + if isinstance(arg, str): + name = arg + elif isinstance(arg, ast.Name): + name = arg.id + elif isinstance(arg, ast.Constant): + name = str(arg.value) + else: + name = str(arg) + return [f'#undef {name}'] + return ['#undef'] + + +class LLVMIR: + """内联 LLVM IR + + 用法: c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + 或: c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + + c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 临时变量名 + c.LOut(expr) - 输出操作数,翻译后替换为对应的 LLVM 临时变量名 + """ + def __init__(self, ir_template, ret_type=None): + self.ir_template = ir_template + self.ret_type = ret_type + + @staticmethod + def HandleCall(translator, args, keywords): + return ['/* LLVMIR */'] + + +class LInp: + """LLVM IR 输入操作数标记 + + 用法: c.LInp(expr) - 标记 expr 为输入操作数 + 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 + """ + def __init__(self, value): + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + return [] + + +class LOut: + """LLVM IR 输出操作数标记 + + 用法: c.LOut(expr) - 标记 expr 为输出操作数 + 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 + """ + def __init__(self, value): + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + return [] + + +class CPragma: + """#pragma 指令 + + 用于生成 C 语言的 #pragma 指令。 + 例如:c.CPragma("GCC diagnostic push") 生成 #pragma GCC diagnostic push + """ + def __init__(self, directive): + self.directive = directive + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CPragma() 调用""" + if args: + arg = args[0] + if isinstance(arg, ast.Constant): + directive = arg.value + elif isinstance(arg, ast.Str): + directive = arg.s + else: + expr = translator.HandleExpr(arg)[0] + directive = _to_str(expr) + return [f'#pragma {directive}'] + return ['#pragma'] + + +# C 库类字典,用于 HandleCSpecialCall +Library_C = { + 'Asm': Asm, + 'Load': Load, + 'Addr': Addr, + 'Deref': Deref, + 'Set': Set, + 'AsmInp': AsmInp, + 'AsmOut': AsmOut, + 'CDefine': CDefine, + 'CIfndef': CIfndef, + 'CIfdef': CIfdef, + 'CIf': CIf, + 'CElif': CElif, + 'CElse': CElse, + 'CEndif': CEndif, + 'CUndef': CUndef, + 'CError': CError, + 'TokenPast': TokenPast, + 'CReturn': CReturn, + 'CPragma': CPragma, + 'LLVMIR': LLVMIR, + 'LInp': LInp, + 'LOut': LOut, +} + + +class Attribute: + """函数/变量属性装饰器""" + def __init__(self, *attrs): + self.attrs = attrs + + def __call__(self, func): + # 将属性附加到函数上 + func._c_attributes = self.attrs + return func diff --git a/CPython/t.py b/CPython/t.py new file mode 100644 index 0000000..495d5e8 --- /dev/null +++ b/CPython/t.py @@ -0,0 +1,1283 @@ +# 类型定义模块 + +import re +import types +from typing import TypeVar, Generic, TypeAlias + + +# ============================================================================= +# 类型映射常量 +# ============================================================================= + +# 类型映射常量(由 _build_type_maps() 在模块末尾自动生成) +_BASIC_TYPES_MAP = {} +_T_TYPE_PATTERNS = [] + +def _build_type_maps(): + global _BASIC_TYPES_MAP, _T_TYPE_PATTERNS + for _name in dir(): + _obj = eval(_name) + if isinstance(_obj, type) and issubclass(_obj, CType) and _obj is not CType: + try: + _inst = _obj() + _cname = getattr(_inst, 'CName', '') + if _cname and _obj.IsBasicType(): + _BASIC_TYPES_MAP[_cname] = _cname + _T_TYPE_PATTERNS.append((_name, _cname)) + except Exception: + pass + + +# ============================================================================= +# CType 基类 +# ============================================================================= + +class CType: + """C 类型基类""" + + PREFIX = 'prefix' + BASE = 'base' + POINTER = 'ptr' + ARRAY = 'array' + NAMED = 'named' + STORAGE_CLASS = 'storage_class' + TYPE_QUALIFIER = 'type_qualifier' + + position = frozenset({BASE}) # 类属性,支持联合类型如 BASE | SPECIAL + + def __init__(self, value=None, *types): + self.value = value + self.types = types + self.Name = '' + self.IsBasicType = False + self.IsPointer = False + self.IsSigned = None + self.Size = None + if not hasattr(self, 'CName'): + self.CName = '' + + def GetPositions(self) -> frozenset: + """获取 position 的 frozenset 形式""" + return self.position + + @classmethod + def HasPosition(cls, pos) -> bool: + """检查是否包含指定的位置""" + return pos in cls.position + + @classmethod + def IsNamed(cls) -> bool: + """检查是否是命名类型(struct/union/enum/typedef 等)""" + return cls.NAMED in cls.position + + @classmethod + def IsStorageClass(cls) -> bool: + """检查是否是存储类修饰符""" + return cls.STORAGE_CLASS in cls.position + + @classmethod + def IsTypeQualifier(cls) -> bool: + """检查是否是类型限定符""" + return cls.TYPE_QUALIFIER in cls.position + + @classmethod + def IsBasicType(cls) -> bool: + """检查是否是基本类型""" + return cls.BASE in cls.position + + @classmethod + def IsPrefix(cls) -> bool: + """检查是否是前缀类型""" + return cls.PREFIX in cls.position + + def rfind(self, s): + """注解""" + pass + + def get_position(self): + """获取类型在声明中的位置""" + return self.position + + def GetCAame(self): + """获取 C 类型名称""" + return self.CName + + def __merge__(self, types): + return types + + def __or__(self, other): + return [self, other] + + def __set_default__(self, **kwargs): + """设置默认值/初始值,用于 static/global 变量的初始化 + + Args: + **kwargs: 成员名称和值的键值对 + + Returns: + 包含默认值信息的 CTypeDefault 对象 + """ + return CTypeDefault(self, **kwargs) + + @classmethod + def FromAnnotation(cls, AnnotationStr, TypeName=''): + """从类型注解字符串解析类型信息 + + Args: + AnnotationStr: 类型注解的字符串表示(ast.dump结果) + TypeName: 类型名称(可选) + + Returns: + CType 实例 + """ + ctype = cls() + + # 检查是否是基本类型 + if TypeName in _BASIC_TYPES_MAP: + ctype.IsBasicType = True + ctype.Name = _BASIC_TYPES_MAP[TypeName] + else: + for pattern, c_name in _T_TYPE_PATTERNS: + if pattern in AnnotationStr: + ctype.IsBasicType = True + ctype.Name = c_name + break + + # 检查是否包含指针 + if 'CPtr' in AnnotationStr: + ctype.IsPointer = True + + return ctype + + @classmethod + def FromTypeName(cls, TypeName): + """从类型名称创建 CType + + Args: + TypeName: 类型名称 + + Returns: + CType 实例 + """ + ctype = cls() + + if TypeName in _BASIC_TYPES_MAP: + ctype.IsBasicType = True + ctype.Name = _BASIC_TYPES_MAP[TypeName] + + return ctype + + def GetFullType(self, VarName='', ArraySizeStr=''): + """获取完整的类型声明字符串 + + Args: + VarName: 变量名 + ArraySizeStr: 数组大小字符串 + + Returns: + 完整的类型声明字符串 + """ + ptr_str = '*' if self.IsPointer else '' + if VarName: + return f'{self.Name}{ptr_str} {VarName}{ArraySizeStr}' + return f'{self.Name}{ptr_str}' + + def __repr__(self): + ptr_str = '*' if self.IsPointer else '' + return f'CType({self.Name}{ptr_str}, IsBasicType={self.IsBasicType})' + +class CChar(CType): + def __init__(self, value=None): + self.CName = 'char' + super().__init__(value) + self.IsSigned = True + self.Size = 8 + +class CInt(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int' + super().__init__(value) + self.IsSigned = True + self.Size = 32 + +class CShort(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'short' + super().__init__(value) + self.IsSigned = True + self.Size = 16 + +class CLong(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'long' + super().__init__(value) + self.IsSigned = True + self.Size = 64 + +class CFloat(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float' + super().__init__(value) + self.IsSigned = None + self.Size = 32 + +class CDouble(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'double' + super().__init__(value) + self.IsSigned = None + self.Size = 64 + +class CFloat8T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float8_t' + super().__init__(value) + self.IsSigned = None + self.Size = 8 + +class CFloat16T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float16_t' + super().__init__(value) + self.IsSigned = None + self.Size = 16 + +class CFloat32T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float32_t' + super().__init__(value) + self.IsSigned = None + self.Size = 32 + +class CFloat64T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float64_t' + super().__init__(value) + self.IsSigned = None + self.Size = 64 + +class CFloat128T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float128_t' + super().__init__(value) + self.IsSigned = None + self.Size = 128 + +class CVoid(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'void' + super().__init__(value) + self.IsSigned = None + self.Size = 0 + +class CUnsigned(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned' + super().__init__(value) + self.IsSigned = False + self.Size = 32 + +class CUnsignedChar(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned char' + super().__init__(value) + self.IsSigned = False + self.Size = 8 + +class CUnsignedInt(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned int' + super().__init__(value) + self.IsSigned = False + self.Size = 32 + +class CUnsignedShort(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned short' + super().__init__(value) + self.IsSigned = False + self.Size = 16 + +class CUnsignedLong(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned long' + super().__init__(value) + self.IsSigned = False + self.Size = 64 + +class CSignedChar(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'signed char' + super().__init__(value) + self.IsSigned = True + self.Size = 8 + +class CStruct(CType): + position = frozenset({CType.BASE, CType.NAMED}) + def __init__(self, value=None, name=None): + self.CName = f'struct {name}' if name else 'struct' + super().__init__(value) + +class CUnion(CType): + position = frozenset({CType.BASE, CType.NAMED}) + def __init__(self, value=None): + self.CName = 'union' + super().__init__(value) + +class CEnum(CType): + position = frozenset({CType.BASE, CType.NAMED}) + def __init__(self, value=None): + self.CName = 'enum' + super().__init__(value) + self.b = 1 + +Enum = CEnum # 别名,允许使用 t.Enum + +''' +class Object(CType): + """Python 对象类型,用于支持类方法外联函数""" + position = frozenset({CType.BASE, CType.NAMED}) + def __init__(self, value=None): + self.CName = 'struct' + super().__init__(value) + def __call__(self, cls): + return cls +''' +def Object(): + pass + +def CVTable(): + pass + +CTypedef = TypeAlias + +class _CTypedef(CType): + position = frozenset({CType.PREFIX, CType.NAMED}) + def __init__(self, value=None): + self.CName = 'typedef' + super().__init__(value) + + +class CAuto(CType): + position = frozenset({CType.PREFIX}) + def __init__(self, value=None): + self.CName = 'auto' + super().__init__(value) + +class CRegister(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'register' + super().__init__(value) + +class CStatic(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'static' + super().__init__(value) + +class CExtern(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'extern' + super().__init__(value) + +class CConst(CType): + position = frozenset({CType.PREFIX, CType.TYPE_QUALIFIER}) + def __init__(self, value=None): + self.CName = 'const' + super().__init__(value) + +class CInline(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'inline' + super().__init__(value) + +class CExport(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'export' + super().__init__(value) + +class CVolatile(CType): + position = frozenset({CType.PREFIX, CType.TYPE_QUALIFIER}) + def __init__(self, value=None): + self.CName = 'volatile' + super().__init__(value) + +class CSizeT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'size_t' + super().__init__(value) + self.IsSigned = False + self.Size = 64 + +class CInt8T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int8_t' + super().__init__(value) + self.IsSigned = True + self.Size = 8 + +class CInt16T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int16_t' + super().__init__(value) + self.IsSigned = True + self.Size = 16 + +class CInt32T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int32_t' + super().__init__(value) + self.IsSigned = True + self.Size = 32 + +class CInt64T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int64_t' + super().__init__(value) + self.IsSigned = True + self.Size = 64 + +class CUInt8T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uint8_t' + super().__init__(value) + self.IsSigned = False + self.Size = 8 + +class CUInt16T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uint16_t' + super().__init__(value) + self.IsSigned = False + self.Size = 16 + +class CUInt32T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uint32_t' + super().__init__(value) + self.IsSigned = False + self.Size = 32 + +class CUInt64T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uint64_t' + super().__init__(value) + self.IsSigned = False + self.Size = 64 + +class CIntPtrT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'intptr_t' + super().__init__(value) + self.IsSigned = True + self.Size = 64 + +class CUIntPtrT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uintptr_t' + super().__init__(value) + self.IsSigned = False + self.Size = 64 + +class CPtrDiffT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'ptrdiff_t' + super().__init__(value) + self.IsSigned = True + self.Size = 64 + +class CWCharT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'wchar_t' + super().__init__(value) + self.IsSigned = True + self.Size = 32 + +class CChar8T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'char8_t' + super().__init__(value) + self.IsSigned = False + self.Size = 8 + +class CChar16T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'char16_t' + super().__init__(value) + self.IsSigned = False + self.Size = 16 + +class CChar32T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'char32_t' + super().__init__(value) + self.IsSigned = False + self.Size = 32 + +class CBool(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'bool' + super().__init__(value) + self.IsSigned = False + self.Size = 8 + +class CComplex(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = '_Complex' + super().__init__(value) + +class CImaginary(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = '_Imaginary' + super().__init__(value) + +T = TypeVar("T") +Callable = Generic[T] + +class CPtr(CType, Generic[T]): + position = frozenset({CType.POINTER}) + def __init__(self, value=None): + self.CName = '*' + super().__init__(value) + +class CTypeDefault(CType): + """用于存储 C 类型默认值/初始化的包装类 + + 当使用 t.CStatic.__set_default__(open=mouse_open, ...) 时创建 + """ + def __init__(self, BaseType, **kwargs): + super().__init__() + self.BaseType = BaseType + self.defaults = kwargs + self.CName = BaseType.CName if hasattr(BaseType, 'CName') else '' + self.position = BaseType.position if hasattr(BaseType, 'position') else CType.BASE + + def __repr__(self): + return f'CTypeDefault({self.BaseType}, {self.defaults})' + +class CArrayPtr(CType): + position = frozenset({CType.POINTER}) + def __init__(self, value=None): + self.CName = '(*)' # 特殊标记表示数组指针 + super().__init__(value) + +class CDefine(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = '#define' + super().__init__(value) + +class CPass(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = '' + super().__init__(value) + +class State(CType): + """状态标记,用于仅声明不定义,等价于 CExport | CExtern""" + position = frozenset({CType.PREFIX}) + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 t.State() 调用""" + return ['t.State'] + +class Anonymous: + def __init__(): + pass + +class Postdefinition: + def __init__(self, c): + pass + +class Bit: + def __init__(self, i): + pass + +class BigEndian(CType): + """大端序(Big-Endian)字节序标记类 + + 用于标记结构体成员应使用大端序存储。 + 在小端序平台(如x86)上读取时,会自动进行字节交换。 + + 用法示例: + class MyStruct: + a: t.CInt | t.BigEndian # 大端序存储的整数 + """ + IsSigned = True + Size = 4 + Align = 4 + +class LittleEndian(CType): + """小端序(Little-Endian)字节序标记类 + + 用于标记结构体成员应使用小端序存储。 + 在小端序平台(如x86)上读取时,不需要进行字节交换。 + + 用法示例: + class MyStruct: + b: t.CInt | t.LittleEndian # 小端序存储的整数 + """ + IsSigned = True + Size = 4 + Align = 4 + +class ASM_DESCR: + """内嵌 ASM 破坏描述符类 + + 定义了所有可能的破坏描述符和约束字符,用于 GCC 内嵌汇编 + """ + # 操作数修饰符 + MODIFIER_OUTPUT = '=' # 输出操作数 + MODIFIER_READWRITE = '+' # 读写操作数 + MODIFIER_INPUT = '' # 输入操作数(默认) + MODIFIER_GLOBAL = '&' # 全局操作数 + + # 寄存器约束(32位命名) + REG_ANY = 'r' # 任何通用寄存器 + REG_EAX = 'a' # EAX/RAX 寄存器 + REG_EBX = 'b' # EBX/RBX 寄存器 + REG_ECX = 'c' # ECX/RCX 寄存器 + REG_EDX = 'd' # EDX/RDX 寄存器 + REG_ESI = 'S' # ESI/RSI 寄存器 + REG_EDI = 'D' # EDI/RDI 寄存器 + REG_STACK = 'q' # 任何通用寄存器(EAX, EBX, ECX, EDX) + REG_FLOAT = 'f' # 浮点寄存器 + REG_MMX = 'y' # MMX 寄存器 + REG_XMM = 'x' # XMM 寄存器 + + # 寄存器约束(64位命名,GCC约束字符与32位相同) + REG_RAX = 'a' # RAX 寄存器 + REG_RBX = 'b' # RBX 寄存器 + REG_RCX = 'c' # RCX 寄存器 + REG_RDX = 'd' # RDX 寄存器 + REG_RSI = 'S' # RSI 寄存器 + REG_RDI = 'D' # RDI 寄存器 + REG_R8 = 'r' # R8 寄存器(需通过r约束+显式指定) + REG_R9 = 'r' # R9 寄存器 + REG_R10 = 'r' # R10 寄存器 + REG_R11 = 'r' # R11 寄存器 + REG_R12 = 'r' # R12 寄存器 + REG_R13 = 'r' # R13 寄存器 + REG_R14 = 'r' # R14 寄存器 + REG_R15 = 'r' # R15 寄存器 + REG_RBP = 'r' # RBP 寄存器 + REG_RSP = 'r' # RSP 寄存器 + + # 内存约束 + MEMORY = 'm' # 内存操作数 + + # 立即数约束 + IMMEDIATE = 'i' # 立即数 + IMMEDIATE_CONST = 'n' # 常量立即数 + + # 综合约束 + ANY = 'g' # 任何通用寄存器、内存或立即数 + MEMORY_OR_REG = 'o' # 内存或寄存器 + + # 破坏描述符(clobber list) + CLOBBER_EAX = 'eax' # 破坏 EAX/RAX 寄存器 + CLOBBER_EBX = 'ebx' # 破坏 EBX/RBX 寄存器 + CLOBBER_ECX = 'ecx' # 破坏 ECX/RCX 寄存器 + CLOBBER_EDX = 'edx' # 破坏 EDX/RDX 寄存器 + CLOBBER_ESI = 'esi' # 破坏 ESI/RSI 寄存器 + CLOBBER_EDI = 'edi' # 破坏 EDI/RDI 寄存器 + CLOBBER_EBP = 'ebp' # 破坏 EBP/RBP 寄存器 + CLOBBER_ESP = 'esp' # 破坏 ESP/RSP 寄存器 + CLOBBER_AL = 'al' # 破坏 AL 寄存器(EAX/RAX 低8位) + CLOBBER_AH = 'ah' # 破坏 AH 寄存器(EAX/RAX 高8位) + CLOBBER_BL = 'bl' # 破坏 BL 寄存器(EBX/RBX 低8位) + CLOBBER_BH = 'bh' # 破坏 BH 寄存器(EBX/RBX 高8位) + CLOBBER_CL = 'cl' # 破坏 CL 寄存器(ECX/RCX 低8位) + CLOBBER_CH = 'ch' # 破坏 CH 寄存器(ECX/RCX 高8位) + CLOBBER_DL = 'dl' # 破坏 DL 寄存器(EDX/RDX 低8位) + CLOBBER_DH = 'dh' # 破坏 DH 寄存器(EDX/RDX 高8位) + CLOBBER_CC = 'cc' # 破坏条件代码寄存器(标志寄存器) + CLOBBER_MEMORY = 'memory' # 破坏内存(表示汇编代码修改了内存) + # 16 位寄存器破坏描述符 + CLOBBER_AX = 'ax' # 破坏 AX 寄存器 + CLOBBER_BX = 'bx' # 破坏 BX 寄存器 + CLOBBER_CX = 'cx' # 破坏 CX 寄存器 + CLOBBER_DX = 'dx' # 破坏 DX 寄存器 + CLOBBER_SI = 'si' # 破坏 SI 寄存器 + CLOBBER_DI = 'di' # 破坏 DI 寄存器 + CLOBBER_BP = 'bp' # 破坏 BP 寄存器 + + # 64位寄存器破坏描述符 + CLOBBER_RAX = 'rax' # 破坏 RAX 寄存器 + CLOBBER_RBX = 'rbx' # 破坏 RBX 寄存器 + CLOBBER_RCX = 'rcx' # 破坏 RCX 寄存器 + CLOBBER_RDX = 'rdx' # 破坏 RDX 寄存器 + CLOBBER_RSI = 'rsi' # 破坏 RSI 寄存器 + CLOBBER_RDI = 'rdi' # 破坏 RDI 寄存器 + CLOBBER_RBP = 'rbp' # 破坏 RBP 寄存器 + CLOBBER_RSP = 'rsp' # 破坏 RSP 寄存器 + CLOBBER_R8 = 'r8' # 破坏 R8 寄存器 + CLOBBER_R9 = 'r9' # 破坏 R9 寄存器 + CLOBBER_R10 = 'r10' # 破坏 R10 寄存器 + CLOBBER_R11 = 'r11' # 破坏 R11 寄存器 + CLOBBER_R12 = 'r12' # 破坏 R12 寄存器 + CLOBBER_R13 = 'r13' # 破坏 R13 寄存器 + CLOBBER_R14 = 'r14' # 破坏 R14 寄存器 + CLOBBER_R15 = 'r15' # 破坏 R15 寄存器 + + # 预定义的组合约束(32位命名) + OUTPUT_REG = '=r' # 输出操作数,使用任何通用寄存器 + OUTPUT_MEM = '=m' # 输出操作数,使用内存 + OUTPUT_EAX = '=a' # 输出操作数,使用 EAX/RAX 寄存器 + OUTPUT_EBX = '=b' # 输出操作数,使用 EBX/RBX 寄存器 + OUTPUT_ECX = '=c' # 输出操作数,使用 ECX/RCX 寄存器 + OUTPUT_EDX = '=d' # 输出操作数,使用 EDX/RDX 寄存器 + OUTPUT_ESI = '=S' # 输出操作数,使用 ESI/RSI 寄存器 + OUTPUT_EDI = '=D' # 输出操作数,使用 EDI/RDI 寄存器 + + # 预定义的组合约束(64位命名) + OUTPUT_RAX = '=a' # 输出操作数,使用 RAX 寄存器 + OUTPUT_RBX = '=b' # 输出操作数,使用 RBX 寄存器 + OUTPUT_RCX = '=c' # 输出操作数,使用 RCX 寄存器 + OUTPUT_RDX = '=d' # 输出操作数,使用 RDX 寄存器 + OUTPUT_RSI = '=S' # 输出操作数,使用 RSI 寄存器 + OUTPUT_RDI = '=D' # 输出操作数,使用 RDI 寄存器 + + INPUT_REG = 'r' # 输入操作数,使用任何通用寄存器 + INPUT_MEM = 'm' # 输入操作数,使用内存 + INPUT_EAX = 'a' # 输入操作数,使用 EAX/RAX 寄存器 + INPUT_EBX = 'b' # 输入操作数,使用 EBX/RBX 寄存器 + INPUT_ECX = 'c' # 输入操作数,使用 ECX/RCX 寄存器 + INPUT_EDX = 'd' # 输入操作数,使用 EDX/RDX 寄存器 + INPUT_ESI = 'S' # 输入操作数,使用 ESI/RSI 寄存器 + INPUT_EDI = 'D' # 输入操作数,使用 EDI/RDI 寄存器 + INPUT_IMM = 'i' # 输入操作数,使用立即数 + INPUT_ANY = 'g' # 输入操作数,使用任何通用寄存器、内存或立即数 + + # 输入约束(64位命名) + INPUT_RAX = 'a' # 输入操作数,使用 RAX 寄存器 + INPUT_RBX = 'b' # 输入操作数,使用 RBX 寄存器 + INPUT_RCX = 'c' # 输入操作数,使用 RCX 寄存器 + INPUT_RDX = 'd' # 输入操作数,使用 RDX 寄存器 + INPUT_RSI = 'S' # 输入操作数,使用 RSI 寄存器 + INPUT_RDI = 'D' # 输入操作数,使用 RDI 寄存器 + + # 所有单独约束字符列表 + ALL_CONSTRAINTS = [ + # 操作数修饰符 + MODIFIER_OUTPUT, MODIFIER_READWRITE, MODIFIER_INPUT, MODIFIER_GLOBAL, + + # 寄存器约束 + REG_ANY, REG_EAX, REG_EBX, REG_ECX, REG_EDX, REG_ESI, REG_EDI, + REG_STACK, REG_FLOAT, REG_MMX, REG_XMM, + + # 内存约束 + MEMORY, + + # 立即数约束 + IMMEDIATE, IMMEDIATE_CONST, + + # 综合约束 + ANY, MEMORY_OR_REG + ] + + # 所有破坏描述符列表 + ALL_CLOBBERS = [ + CLOBBER_EAX, CLOBBER_EBX, CLOBBER_ECX, CLOBBER_EDX, + CLOBBER_ESI, CLOBBER_EDI, CLOBBER_EBP, CLOBBER_ESP, + CLOBBER_CC, CLOBBER_MEMORY, + CLOBBER_RAX, CLOBBER_RBX, CLOBBER_RCX, CLOBBER_RDX, + CLOBBER_RSI, CLOBBER_RDI, CLOBBER_RBP, CLOBBER_RSP, + CLOBBER_R8, CLOBBER_R9, CLOBBER_R10, CLOBBER_R11, + CLOBBER_R12, CLOBBER_R13, CLOBBER_R14, CLOBBER_R15 + ] + + # 所有描述符列表 + ALL = ALL_CONSTRAINTS + ALL_CLOBBERS + + +# 定义 ASM_LIST,包含所有可能的汇编约束字符 +ASM_LIST = ASM_DESCR.ALL + + +class attr: + """C 语言 __attribute__ 属性操作类型""" + + @staticmethod + def noreturn(): + return "noreturn" + + @staticmethod + def format(printf, arg1, arg2): + return f"format({printf}, {arg1}, {arg2})" + + @staticmethod + def section(name): + return f'section("{name}")' + + @staticmethod + def aligned(bytes): + return f"aligned({bytes})" + + @staticmethod + def packed(): + return "packed" + + @staticmethod + def unused(): + return "unused" + + @staticmethod + def used(): + return "used" + + @staticmethod + def weak(): + return "weak" + + @staticmethod + def alias(name): + return f'alias("{name}")' + + @staticmethod + def visibility(type): + return f'visibility("{type}")' + + @staticmethod + def constructor(): + return "constructor" + + @staticmethod + def destructor(): + return "destructor" + + @staticmethod + def always_inline(): + return "always_inline" + + @staticmethod + def noinline(): + return "noinline" + + @staticmethod + def pure(): + return "pure" + + @staticmethod + def const(): + return "const" + + @staticmethod + def malloc(): + return "malloc" + + @staticmethod + def alloc_size(n): + return f"alloc_size({n})" + + @staticmethod + def warn_unused_result(): + return "warn_unused_result" + + @staticmethod + def deprecated(msg=None): + if msg: + return f'deprecated("{msg}")' + return "deprecated" + + @staticmethod + def fallthrough(): + return "fallthrough" + + @staticmethod + def likely(): + return "likely" + + @staticmethod + def unlikely(): + return "unlikely" + + @staticmethod + def hot(): + return "hot" + + @staticmethod + def cold(): + return "cold" + + @staticmethod + def interrupt(): + return "interrupt" + + @staticmethod + def naked(): + return "naked" + + @staticmethod + def sentinel(n=0): + return f"sentinel({n})" + + @staticmethod + def nonnull(*args): + if args: + return f"nonnull({', '.join(map(str, args))})" + return "nonnull" + + @staticmethod + def returns_nonnull(): + return "returns_nonnull" + + @staticmethod + def access(mode, *args): + return f"access({mode}, {', '.join(map(str, args))})" + + @staticmethod + def cleanup(func): + return f'cleanup({func})' + + @staticmethod + def transparent_union(): + return "transparent_union" + + @staticmethod + def mode(mode_name): + return f"mode({mode_name})" + + @staticmethod + def vector_size(bytes): + return f"vector_size({bytes})" + + @staticmethod + def target(string): + return f'target("{string}")' + + @staticmethod + def optimize(level): + return f'optimize("{level}")' + + @staticmethod + def no_instrument_function(): + return "no_instrument_function" + + @staticmethod + def no_sanitize(type): + return f"no_sanitize({type})" + + @staticmethod + def no_stack_protector(): + return "no_stack_protector" + + @staticmethod + def stack_protector(): + return "stack_protector" + + @staticmethod + def error(msg): + return f'error("{msg}")' + + @staticmethod + def warning(msg): + return f'warning("{msg}")' + + class llvm: + """LLVM 函数属性描述符 + + 用于在返回类型注解中指定 LLVM 函数属性。 + 例如: def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind: + """ + + class nobuiltin: + CName = '#attr.llvm.nobuiltin' + + class nounwind: + CName = '#attr.llvm.nounwind' + + class noredzone: + CName = '#attr.llvm.noredzone' + + class willreturn: + CName = '#attr.llvm.willreturn' + + class mustprogress: + CName = '#attr.llvm.mustprogress' + + class optnone: + CName = '#attr.llvm.optnone' + + class noinline: + CName = '#attr.llvm.noinline' + + class alwaysinline: + CName = '#attr.llvm.alwaysinline' + + class readnone: + CName = '#attr.llvm.readnone' + + class readonly: + CName = '#attr.llvm.readonly' + + class writeonly: + CName = '#attr.llvm.writeonly' + + class inaccessiblememonly: + CName = '#attr.llvm.inaccessiblememonly' + + class inaccessiblemem_or_argmemonly: + CName = '#attr.llvm.inaccessiblemem_or_argmemonly' + + +def NewCType(size, signed): + ct = CType() + ct.Size = size + ct.IsSigned = signed + return ct + +i1 = NewCType(1, True) +i8 = NewCType(8, True) +i16 = NewCType(16, True) +i32 = NewCType(32, True) +i64 = NewCType(64, True) + +u1 = NewCType(1, False) +u8 = NewCType(8, False) +u16 = NewCType(16, False) +u32 = NewCType(32, False) +u64 = NewCType(64, False) + + +class CTypeRegistry: + """基于 CType 元属性的类型注册表,替代手动映射表 + + 利用 CType 子类的 position/IsSigned/Size 元属性自动推导: + - LLVM IR 类型字符串 (如 'i32', 'double', 'i8*') + - C 类型名称 (如 'int', 'unsigned char', 'long long') + - Python CType 类引用 (如 t.CInt32T) + """ + + _name_to_class = None + _cname_to_class = None + + @classmethod + def _build(cls): + if cls._name_to_class is not None: + return + import sys + mod = sys.modules.get(__name__) + if mod is None: + return + cls._name_to_class = {} + cls._cname_to_class = {} + for name, obj in vars(mod).items(): + if not isinstance(obj, type) or not issubclass(obj, CType) or obj is CType: + continue + if obj in (CTypeDefault, BigEndian, LittleEndian): + continue + try: + inst = obj() + except Exception: + continue + pos = getattr(obj, 'position', frozenset()) + if CType.PREFIX in pos and CType.BASE not in pos: + continue + if CType.POINTER in pos and CType.BASE not in pos: + cls._name_to_class[name] = obj + continue + if getattr(inst, 'Size', None) is not None or getattr(inst, 'CName', ''): + cls._name_to_class[name] = obj + cname = getattr(inst, 'CName', '') + if cname and cname not in cls._cname_to_class: + cls._cname_to_class[cname] = obj + + @classmethod + def GetClassByName(cls, name: str): + """根据 Python 类名获取 CType 类 (如 'CInt32T' -> t.CInt32T)""" + cls._build() + return cls._name_to_class.get(name) + + @classmethod + def GetClassByCName(cls, cname: str): + """根据 C 类型名获取 CType 类 (如 'int32_t' -> t.CInt32T)""" + cls._build() + return cls._cname_to_class.get(cname) + + @staticmethod + def CTypeToLLVM(ctype_class) -> str: + """从 CType 类的元属性推导 LLVM IR 类型字符串 + + 规则: + - position 含 POINTER 且不含 BASE → 'i8*' + - position 含 PREFIX 且不含 BASE → '' (修饰符,无LLVM类型) + - Size == 0 且 IsSigned is None → 'void' + - IsSigned is None 且 Size > 0 → 浮点: half/float/double/fp128 + - IsSigned is True/False 且 Size > 0 → 整数: i{Size} + """ + if ctype_class is None: + return 'i8*' + pos = getattr(ctype_class, 'position', frozenset()) + if CType.POINTER in pos and CType.BASE not in pos: + return 'i8*' + if CType.PREFIX in pos and CType.BASE not in pos: + return '' + try: + inst = ctype_class() + except Exception: + return 'i8*' + size = getattr(inst, 'Size', None) + is_signed = getattr(inst, 'IsSigned', None) + if size is None or size == 0: + if is_signed is None: + return 'void' + return 'i8*' + if is_signed is None: + float_map = {8: 'half', 16: 'half', 32: 'float', 64: 'double', 128: 'fp128'} + return float_map.get(size, f'f{size}') + return f'i{size}' + + @staticmethod + def CTypeToCName(ctype_class) -> str: + """从 CType 类推导 C 类型名称 (用于 printf 格式化等) + + 规则: + - IsSigned is None 且 Size > 0 → 浮点: float/double/long double + - IsSigned is True → 有符号整数: char/short/int/long long + - IsSigned is False → 无符号整数: unsigned char/unsigned short/unsigned int/unsigned long long + """ + if ctype_class is None: + return '' + try: + inst = ctype_class() + except Exception: + return '' + size = getattr(inst, 'Size', None) + is_signed = getattr(inst, 'IsSigned', None) + if size is None: + return '' + if is_signed is None and size > 0: + float_cname = {32: 'float', 64: 'double', 128: 'long double'} + return float_cname.get(size, 'double') + int_cname_signed = {8: 'char', 16: 'short', 32: 'int', 64: 'long long'} + int_cname_unsigned = {8: 'unsigned char', 16: 'unsigned short', 32: 'unsigned int', 64: 'unsigned long long'} + if is_signed: + return int_cname_signed.get(size, 'int') + else: + return int_cname_unsigned.get(size, 'unsigned int') + + @classmethod + def NameToLLVM(cls, name: str) -> str: + """根据 Python 类型名推导 LLVM IR 类型 (如 'CFloat64T' -> 'double') + + 修饰符类型 (CConst, CStatic 等) 返回空字符串。 + 指针类型 (CPtr) 返回 'i8*'。 + 未知类型返回 None。 + """ + cls._build() + import sys + mod = sys.modules.get(__name__) + if mod and hasattr(mod, name): + obj = getattr(mod, name) + if isinstance(obj, type) and issubclass(obj, CType): + return cls.CTypeToLLVM(obj) + return None + + @classmethod + def NameToCName(cls, name: str) -> str: + """根据 Python 类型名推导 C 类型名 (如 'CInt32T' -> 'int')""" + ctype_class = cls.GetClassByName(name) + if ctype_class is not None: + return cls.CTypeToCName(ctype_class) + return None + + @classmethod + def CNameToClass(cls, cname: str): + """根据 C 类型名获取 CType 类 (如 'int32_t' -> t.CInt32T, 'unsigned char' -> t.CUnsignedChar)""" + cls._build() + return cls._cname_to_class.get(cname) + + @classmethod + def ResolveName(cls, name: str): + """解析类型名到 (CType类, 指针层级) + + 支持的格式: + - Python 类名: 'CInt32T' -> (t.CInt32T, 0) + - C 类型名: 'int32_t' -> (t.CInt32T, 0) + - stdint 大写别名: 'INT32' -> (t.CInt32T, 0) + - 指针别名: 'INT32PTR' -> (t.CInt32T, 1) + - 大写别名: 'BYTE' -> (t.CUnsignedChar, 0), 'DWORD' -> (t.CUInt32T, 0) + - 浮点别名: 'FLOAT64' -> (t.CFloat64T, 0) + - void指针: 'VOIDPTR' -> (t.CVoid, 1) + """ + cls._build() + direct = cls._name_to_class.get(name) + if direct is not None: + pos = getattr(direct, 'position', frozenset()) + ptr_level = 1 if CType.POINTER in pos and CType.BASE not in pos else 0 + return (direct, ptr_level) + cnameres = cls._cname_to_class.get(name) + if cnameres is not None: + return (cnameres, 0) + if name.endswith('PTR'): + base_name = name[:-3] + base_result = cls.ResolveName(base_name) + if base_result is not None: + return (base_result[0], base_result[1] + 1) + if name.startswith('FLOAT') and name[5:].isdigit(): + bits = int(name[5:]) + float_name = f'CFloat{bits}T' + float_cls = cls._name_to_class.get(float_name) + if float_cls is not None: + return (float_cls, 0) + _UPPER_ALIAS = { + 'BYTE': 'CUInt8T', 'INT8': 'CInt8T', 'UINT8': 'CUInt8T', + 'WORD': 'CUInt16T', 'INT16': 'CInt16T', 'UINT16': 'CUInt16T', + 'DWORD': 'CUInt32T', 'INT32': 'CInt32T', 'UINT32': 'CUInt32T', + 'UINT': 'CUnsignedInt', 'INT': 'CInt', + 'QWORD': 'CUInt64T', 'INT64': 'CInt64T', 'UINT64': 'CUInt64T', + 'INTPTR': 'CIntPtrT', 'UINTPTR': 'CUIntPtrT', + 'SIZE_T': 'CSizeT', 'SSIZE_T': 'CPtrDiffT', 'PTRDIFF_T': 'CPtrDiffT', + 'VOID': 'CVoid', + } + alias = _UPPER_ALIAS.get(name) + if alias: + alias_cls = cls._name_to_class.get(alias) + if alias_cls is not None: + return (alias_cls, 0) + return None + + +_build_type_maps() \ No newline at end of file diff --git a/LIST b/LIST new file mode 100644 index 0000000..a59b01c --- /dev/null +++ b/LIST @@ -0,0 +1,24 @@ +### 问题 3:isr32_handler 中调用 _yield() 的安全性 +idt.py:165-169 : + +``` +def isr32_handler(): +    timer.timer_handler() +    if s.needs_reschedule: +        sched.Scheduler._yield() +``` +_yield() 内部会切换栈帧( _do_switch 修改 RSP)。但在中断上下文中,当前栈是中断帧(由 ISR_NOERR 32 宏 push 的寄存器)。如果 _yield() 切换到另一个线程,那个线程的 _do_switch 返回时会 ret 到 _yield() 的调用者——而不是 iretq 返回中断。 + +这意味着中断帧被"遗弃"在旧线程的栈上 ,直到旧线程再次被调度回来时, _yield() 返回,然后 isr32_handler 返回,ISR_NOERR 宏执行 iretq 。 + +这个设计是 可以工作的 ,因为: + +1. _yield() 保存了完整的 callee-saved 寄存器 +2. 中断帧在旧线程栈上,旧线程恢复时会继续执行 iretq +3. _yield() 内部有自旋锁保护 +但有一个隐患:如果在中断上下文中 _yield() 切换到的线程也触发了定时器中断,就会 嵌套中断 + 嵌套 _yield() 。虽然自旋锁 _yield_lock 会阻止第二次 _yield() ,但这意味着时间片到期后无法切换,直到第一次 _yield() 返回。 + + +继续进行剩余的进程隔离,内存管理增强,以及上述的几个工作,依旧是分步 +注意,需要循序渐进,每一步后立即进行测试,也就是在每个小改进后立即进行测试,我将在出现任何问题后立即告诉你 + diff --git a/Projectrans.py b/Projectrans.py new file mode 100644 index 0000000..0b8f3d4 --- /dev/null +++ b/Projectrans.py @@ -0,0 +1,3742 @@ +#!/usr/bin/env python3 +""" +ProjectTrans.py - 工程级 TransPyC 翻译器 + +两阶段翻译流程: + 阶段一:从源文件生成声明接口 .pyi(仅有签名)和 .stub.ll(仅有声明) + 阶段二:使用声明接口翻译源文件,嵌入 .stub.ll 声明,生成含代码的 .ll 并编译为 .obj + +SHA1 = SHA1(source file content) +""" + +import sys +import os +import re +import hashlib +import shutil +from typing import List +import subprocess +import tempfile +import ast +import traceback +import json +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.includes import t +from pathlib import Path + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +import TransPyC +from StubGen import PythonToStubConverter +from lib.core.logger import Logger, LogLevel, set_logger + +# 创建全局日志实例 +logger = Logger( + name="TransPyC", + log_file="build.log", + level=LogLevel.INFO, + use_colors=True +) +set_logger(logger) + + +def compute_sha1(content: str) -> str: + return hashlib.sha1(content.encode('utf-8')).hexdigest()[:16] + + +def _check_annotation_for_export(annotation) -> bool: + """递归检查类型注解中是否包含 CExport""" + if annotation is None: + return False + if isinstance(annotation, ast.Attribute): + if hasattr(annotation, 'attr') and annotation.attr == 'CExport': + return True + elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return _check_annotation_for_export(annotation.left) or _check_annotation_for_export(annotation.right) + elif isinstance(annotation, ast.Name): + return annotation.id == 'CExport' + return False + + +def sha1_file(filepath: str) -> str: + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + return compute_sha1(content) + + +def get_file_dependencies(filepath: str, src_root: str) -> set: + """解析 Python 文件的导入依赖""" + dependencies = set() + try: + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + tree = ast.parse(content) + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + module = alias.name + dependencies.add(module) + elif isinstance(node, ast.ImportFrom): + if node.module: + module = node.module + if node.level > 0: + # from .module import name → 依赖 pkg.module(模块本身) + pkg_dir = os.path.dirname(filepath) + pkg_rel = os.path.relpath(pkg_dir, src_root).replace(os.sep, '.').replace('/', '.') + if pkg_rel == '.': + pkg_rel = '' + if pkg_rel: + dep_module = f'{pkg_rel}.{module}' + else: + dep_module = module + dependencies.add(dep_module) + else: + if not module.startswith('_'): + dependencies.add(module) + elif node.level > 0 and node.names: + # from . import name → 依赖 pkg.name(子模块) + for alias in node.names: + pkg_dir = os.path.dirname(filepath) + pkg_rel = os.path.relpath(pkg_dir, src_root).replace(os.sep, '.').replace('/', '.') + if pkg_rel == '.': + pkg_rel = '' + dep_module = f'{pkg_rel}.{alias.name}' if pkg_rel else alias.name + dependencies.add(dep_module) + except Exception: + pass + return dependencies + + +def find_reachable_files_from_entries(src_root: str, entry_files: list) -> set: + """从入口文件出发,找出所有可达的 .py 文件(通过导入关系)""" + all_files = {} # module_name -> filepath + for root, dirs, files in os.walk(src_root): + dirs[:] = [d for d in dirs if d not in ('__pycache__',)] + for file in files: + if file.endswith('.py'): + filepath = os.path.join(root, file) + rel = os.path.relpath(filepath, src_root) + module = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + if filepath.endswith('__init__.py'): + all_files[module] = filepath + parent_module = module.rsplit('.', 1)[0] if '.' in module else module + if parent_module not in all_files or not all_files[parent_module].endswith('__init__.py'): + all_files[parent_module] = filepath + elif module not in all_files: + all_files[module] = filepath + top_module = module.split('.')[0] + if top_module not in all_files: + all_files[top_module] = filepath + + reachable = set() + queue = list(entry_files) + + while queue: + current = queue.pop(0) + if current in reachable: + continue + reachable.add(current) + deps = get_file_dependencies(current, src_root) + for dep in deps: + if dep in all_files and all_files[dep] not in reachable: + queue.append(all_files[dep]) + else: + for key, val in all_files.items(): + if key.endswith('.' + dep) or key == dep: + if val not in reachable: + queue.append(val) + break + + return reachable + + +def topological_sort_files(py_files: list, src_root: str) -> list: + """对 Python 文件进行拓扑排序,确保依赖模块先被处理""" + # 构建模块名到文件路径的映射 + module_to_file = {} + for filepath in py_files: + rel = os.path.relpath(filepath, src_root) + module = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + module_to_file[module] = filepath + # 也添加顶层模块名 + top_module = module.split('.')[0] + if top_module not in module_to_file: + module_to_file[top_module] = filepath + + # 构建依赖图 + graph = {f: set() for f in py_files} + for filepath in py_files: + deps = get_file_dependencies(filepath, src_root) + for dep in deps: + if dep in module_to_file: + dep_file = module_to_file[dep] + if dep_file != filepath: # 避免自依赖 + graph[filepath].add(dep_file) + + # 拓扑排序 (Kahn's algorithm) + in_degree = {f: 0 for f in py_files} + for f, deps in graph.items(): + for dep in deps: + if dep in in_degree: + in_degree[f] += 1 + + queue = [f for f, degree in in_degree.items() if degree == 0] + sorted_files = [] + + while queue: + # 按字母顺序处理同级别的文件,确保确定性 + queue.sort() + current = queue.pop(0) + sorted_files.append(current) + + for f, deps in graph.items(): + if current in deps: + in_degree[f] -= 1 + if in_degree[f] == 0: + queue.append(f) + + # 如果有环,添加剩余文件 + if len(sorted_files) < len(py_files): + remaining = [f for f in py_files if f not in sorted_files] + sorted_files.extend(remaining) + + return sorted_files + + +class Phase1Generator: + """阶段一:从源文件生成声明接口""" + + def __init__(self, src_root: str, temp_dir: str, include_dirs: list = None, entry_files: list = None, target_triple: str = None, target_datalayout: str = None): + self.src_root = os.path.abspath(src_root) + self.temp_dir = os.path.abspath(temp_dir) + self.include_dirs = include_dirs or [] + self.sha1_map: dict[str, str] = {} + self.include_py_map: dict[str, str] = {} + self.entry_files = entry_files + self.target_triple = target_triple + self.target_datalayout = target_datalayout + os.makedirs(self.temp_dir, exist_ok=True) + + def _get_needed_include_files(self, reachable_source_files: set) -> list: + """从可达源文件收集所有被引用(含传递依赖)的 include 文件""" + include_file_map = {} + for includes_dir in self.include_dirs: + if not os.path.isdir(includes_dir): + continue + for root, dirs, files in os.walk(includes_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith('.py') or fname.endswith('.pyi'): + src_path = os.path.join(root, fname) + rel_from_inc = os.path.relpath(src_path, includes_dir) + module_path = rel_from_inc.replace(os.sep, '.').replace('/', '.') + module_name = os.path.splitext(module_path)[0] + info = (src_path, rel_from_inc, includes_dir) + include_file_map[module_name] = info + top_pkg = module_name.split('.')[0] + if top_pkg not in include_file_map: + include_file_map[top_pkg] = info + + imported_from_src = set() + for src_path in reachable_source_files: + deps = get_file_dependencies(src_path, self.src_root) + imported_from_src.update(deps) + + needed = set() + queue = list(imported_from_src) + while queue: + mod_name = queue.pop(0) + if mod_name in needed: + continue + if mod_name in include_file_map: + needed.add(mod_name) + src_path = include_file_map[mod_name][0] + includes_dir = include_file_map[mod_name][2] + deps = get_file_dependencies(src_path, includes_dir) + for dep in deps: + if dep in include_file_map and dep not in needed: + queue.append(dep) + + needed_infos = [] + for mod_name in sorted(needed): + if mod_name in include_file_map: + info = include_file_map[mod_name] + if info not in needed_infos: + needed_infos.append(info) + + return needed_infos + + def run(self): + """扫描源目录,只处理入口文件可达的 .py 文件(导入遍历)""" + if self.entry_files: + py_files = list(self.entry_files) + else: + main_py = os.path.join(self.src_root, 'main.py') + if os.path.exists(main_py): + py_files = [main_py] + else: + py_files = [] + for root, dirs, files in os.walk(self.src_root): + dirs[:] = [d for d in dirs if d not in ('__pycache__',)] + for file in files: + if file.endswith('.py'): + py_files.append(os.path.join(root, file)) + + if not py_files: + print("[阶段一] 未找到入口文件或源文件") + return + + if self.entry_files: + reachable = find_reachable_files_from_entries(self.src_root, py_files) + else: + reachable = find_reachable_files_from_entries(self.src_root, py_files) + + print(f"[阶段一] 找到 {len(reachable)} 个可达源文件(从入口遍历)") + + for i, src_path in enumerate(sorted(reachable), 1): + rel = os.path.relpath(src_path, self.src_root) + print(f"[{i}/{len(reachable)}] 生成签名: {rel}") + try: + self._process_file_pyi(src_path, rel) + except Exception as e: + print(f" [错误] {e}") + traceback.print_exc() + + needed_includes = self._get_needed_include_files(reachable) + self._process_include_py_files_pyi(needed_includes) + + struct_names, enum_names, struct_sha1_map, exception_names = self._build_struct_registry() + print(f"\n[阶段一] 结构体注册表: {len(struct_names)} 个类型, {len(enum_names)} 个枚举") + for name in sorted(struct_names): + print(f" {name}") + + for i, src_path in enumerate(sorted(reachable), 1): + rel = os.path.relpath(src_path, self.src_root) + try: + self._process_file_stub(src_path, rel, struct_names, enum_names=enum_names, struct_sha1_map=struct_sha1_map, exception_names=exception_names) + except Exception as e: + print(f" [错误] {e}") + traceback.print_exc() + + self._process_include_py_files_stub(struct_names, needed_includes, enum_names=enum_names, struct_sha1_map=struct_sha1_map, exception_names=exception_names) + + print(f"\n[阶段一完成] 声明接口生成到: {self.temp_dir}") + print(f"SHA1 映射表 ({len(self.sha1_map)} 个文件):") + for sha1, rel in sorted(self.sha1_map.items()): + print(f" {sha1} -> {rel}") + + def _collect_include_py_files(self): + include_py_files = [] + for includes_dir in self.include_dirs: + if not os.path.isdir(includes_dir): + continue + for root, dirs, files in os.walk(includes_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith('.py') or fname.endswith('.pyi'): + src_path = os.path.join(root, fname) + rel_from_inc = os.path.relpath(src_path, includes_dir) + include_py_files.append((src_path, rel_from_inc, includes_dir)) + return include_py_files + + def _process_include_py_files_pyi(self, needed_includes: list = None): + if needed_includes is not None: + include_py_files = needed_includes + else: + include_py_files = self._collect_include_py_files() + if not include_py_files: + return + print(f"\n[阶段一-includes] 处理 {len(include_py_files)} 个被引用的 Python 库文件") + for src_path, rel_from_inc, includes_dir in include_py_files: + module_path = rel_from_inc.replace(os.sep, '.').replace('/', '.') + module_name = os.path.splitext(module_path)[0] + try: + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + sha1 = compute_sha1(content) + self.sha1_map[sha1] = f"includes/{rel_from_inc}" + top_module = rel_from_inc.split(os.sep)[0].split('/')[0] + if top_module not in self.include_py_map: + self.include_py_map[top_module] = sha1 + self.include_py_map[module_name] = sha1 + + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + if os.path.isfile(sig_path): + print(f" 缓存命中: {rel_from_inc} -> {sha1}.pyi") + continue + + sig_content = PythonToStubConverter.convert(content, module_name) + with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(sig_content) + print(f" 生成签名: {rel_from_inc} -> {sha1}.pyi") + except Exception as e: + print(f" [错误] {rel_from_inc}: {e}") + + def _collect_typedef_map(self): + import ast as _ast + typedef_map = {} + if not os.path.isdir(self.temp_dir): + return typedef_map + for fname in os.listdir(self.temp_dir): + if not fname.endswith('.pyi'): + continue + pyi_path = os.path.join(self.temp_dir, fname) + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + content = f.read() + tree = _ast.parse(content) + for node in _ast.iter_child_nodes(tree): + if isinstance(node, _ast.AnnAssign) and isinstance(node.target, _ast.Name): + var_name = node.target.id + is_typedef = False + if isinstance(node.annotation, _ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': + is_typedef = True + elif isinstance(node.annotation, _ast.Name) and node.annotation.id == 'CTypedef': + is_typedef = True + elif isinstance(node.annotation, _ast.BinOp) and isinstance(node.annotation.left, _ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': + is_typedef = True + if is_typedef and node.value and var_name not in typedef_map: + typedef_map[var_name] = node.value + except Exception: + pass + return typedef_map + + def _process_include_py_files_stub(self, struct_names: set, needed_includes: list = None, enum_names: set = None, struct_sha1_map: dict = None, exception_names: set = None): + if needed_includes is not None: + include_py_files = needed_includes + else: + include_py_files = self._collect_include_py_files() + if not include_py_files: + return + typedef_map = self._collect_typedef_map() + for src_path, rel_from_inc, includes_dir in include_py_files: + module_path = rel_from_inc.replace(os.sep, '.').replace('/', '.') + module_name = os.path.splitext(module_path)[0] + try: + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + sha1 = compute_sha1(content) + + stub_path = os.path.join(self.temp_dir, f"{sha1}.stub.ll") + if os.path.isfile(stub_path): + print(f" 缓存命中: {rel_from_inc} -> {sha1}.stub.ll") + continue + + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + with open(sig_path, 'r', encoding='utf-8') as f: + sig_content = f.read() + + self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) + print(f" 生成声明: {rel_from_inc} -> {sha1}.stub.ll") + except Exception as e: + print(f" [错误] {rel_from_inc}: {e}") + + def _process_file_pyi(self, src_path: str, rel_path: str): + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + + sha1 = compute_sha1(content) + self.sha1_map[sha1] = rel_path + + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + if os.path.isfile(sig_path): + print(f" -> {sha1}.pyi (缓存)") + return + + module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + sig_content = PythonToStubConverter.convert(content, module_name) + with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(sig_content) + print(f" -> {sha1}.pyi (签名)") + + def _process_file_stub(self, src_path: str, rel_path: str, struct_names: set, enum_names: set = None, struct_sha1_map: dict = None, exception_names: set = None): + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + + sha1 = compute_sha1(content) + stub_path = os.path.join(self.temp_dir, f"{sha1}.stub.ll") + if os.path.isfile(stub_path): + print(f" -> {sha1}.stub.ll (缓存)") + return + + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + with open(sig_path, 'r', encoding='utf-8') as f: + sig_content = f.read() + + typedef_map = self._collect_typedef_map() + self._generate_decl_ll(sig_content, stub_path, src_path, struct_names, enum_names=enum_names, module_sha1=sha1, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) + print(f" -> {sha1}.stub.ll (声明)") + + def _build_struct_registry(self): + struct_names = set() + enum_names = set() + exception_names = set() + struct_sha1_map = {} + valid_sha1_keys = set(self.sha1_map.keys()) + for fname in os.listdir(self.temp_dir): + if not fname.endswith('.pyi'): + continue + sha1_key = fname.replace('.pyi', '') + if sha1_key not in valid_sha1_keys: + continue + pyi_path = os.path.join(self.temp_dir, fname) + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + content = f.read() + tree = ast.parse(content) + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.ClassDef): + is_enum = False + is_exception = False + if node.bases: + for base in node.bases: + if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): + if base.attr in ('CEnum', 'Enum'): + is_enum = True + break + elif base.attr == 'Exception' or base.attr in exception_names: + is_exception = True + break + elif isinstance(base, ast.Name) and hasattr(base, 'id'): + if base.id in ('CEnum', 'Enum'): + is_enum = True + break + elif base.id == 'Exception' or base.id in exception_names: + is_exception = True + break + if is_enum: + enum_names.add(node.name) + elif is_exception: + exception_names.add(node.name) + else: + struct_names.add(node.name) + struct_sha1_map[node.name] = sha1_key + except Exception: + pass + return struct_names, enum_names, struct_sha1_map, exception_names + + def _generate_decl_ll(self, pyi_content: str, ll_path: str, src_path: str, struct_names: set = None, enum_names: set = None, module_sha1: str = None, struct_sha1_map: dict = None, exception_names: set = None, typedef_map: dict = None): + try: + decl_gen = DeclarationGenerator(struct_names=struct_names, enum_names=enum_names, module_sha1=module_sha1, target_triple=self.target_triple, target_datalayout=self.target_datalayout, struct_sha1_map=struct_sha1_map, exception_names=exception_names, typedef_map=typedef_map) + decl_ll = decl_gen.generate(pyi_content, src_path) + with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(decl_ll) + except Exception as e: + print(f" [警告] .ll 声明生成失败: {e}") + with open(ll_path, 'w', encoding='utf-8') as f: + f.write(f"; declaration for {os.path.basename(src_path)}\n; error: {e}\n") + + +class DeclarationGenerator: + """从 .pyi AST 生成纯 LLVM IR 声明(不使用字符串操作)""" + + def __init__(self, struct_names=None, enum_names=None, module_sha1=None, target_triple=None, target_datalayout=None, struct_sha1_map=None, exception_names=None, typedef_map=None): + import llvmlite.ir as ir + self.ir = ir + self.module = None + self.builder = None + self._define_constants = {} + self.struct_names = struct_names or set() + self.enum_names = enum_names or set() + self.module_sha1 = module_sha1 + self.struct_sha1_map = struct_sha1_map or {} + self.exception_names = exception_names or set() + self.target_triple = target_triple or "x86_64-none-elf" + self.target_datalayout = target_datalayout or "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + self.typedef_map = typedef_map or {} + t.configure_platform(self.target_triple) + + def generate(self, pyi_content: str, src_path: str) -> str: + import ast + tree = ast.parse(pyi_content) + + self._define_constants = {} + self._pyi_tree = tree + global_typedef_map = self.typedef_map + self.typedef_map = {} + if global_typedef_map: + self.typedef_map.update(global_typedef_map) + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): + var_name = node.target.id + if node.value and isinstance(node.value, ast.Constant): + self._define_constants[var_name] = node.value.value + elif node.value and isinstance(node.value, ast.Name): + self._define_constants[var_name] = node.value.id + is_typedef = False + if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': + is_typedef = True + elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': + is_typedef = True + elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': + is_typedef = True + if is_typedef: + if node.value: + self.typedef_map[var_name] = node.value + elif isinstance(node.annotation, ast.BinOp) and node.annotation.right: + self.typedef_map[var_name] = node.annotation.right + + lines = [] + lines.append('; ModuleID = "transpyc_decl"') + lines.append(f'target triple = "{self.target_triple}"') + lines.append(f'target datalayout = "{self.target_datalayout}"') + lines.append('') + + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.FunctionDef): + if hasattr(node, 'type_params') and node.type_params: + continue + decl = self._generate_func_decl(node) + if decl: + lines.append(decl) + elif isinstance(node, ast.AnnAssign): + decl = self._generate_global_decl(node) + if decl: + lines.append(decl) + elif isinstance(node, ast.Assign): + decl = self._generate_global_assign_decl(node) + if decl: + lines.append(decl) + elif isinstance(node, ast.ClassDef): + if hasattr(node, 'type_params') and node.type_params: + continue + decls = self._generate_class_decl(node) + lines.extend(decls) + + return '\n'.join(lines) + + def _generate_func_decl(self, node: ast.FunctionDef) -> str: + """生成函数声明""" + func_name = node.name + is_export = self._is_export_func(node) + if self.module_sha1 and not is_export: + func_name = f"{self.module_sha1}.{func_name}" + CReturnTypes = [] + if node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): + if decorator.func.attr == 'CReturn': + for arg in decorator.args: + CReturnTypes.append(arg) + if node.returns: + if isinstance(node.returns, ast.Subscript) and isinstance(node.returns.value, ast.Name) and node.returns.value.id == 'tuple': + slice_node = node.returns.slice + if isinstance(slice_node, ast.Tuple): + for elt in slice_node.elts: + CReturnTypes.append(elt) + else: + CReturnTypes.append(slice_node) + if CReturnTypes: + elem_types = [self._get_type_str(rt, embedded=True) for rt in CReturnTypes] + ret_type = '{ ' + ', '.join(elem_types) + ' }' + else: + ret_type = self._get_type_str(node.returns) + if not ret_type or ret_type == 'void': + ret_type = 'void' + elif ret_type == 'i8*': + if node.returns is None: + ret_type = 'void' + + params = [] + for arg in node.args.args: + if arg.annotation: + arg_type = self._get_type_str(arg.annotation) + else: + arg_type = 'i8*' + if arg_type and arg_type != 'void': + params.append(arg_type) + + param_str = ', '.join(params) if params else '' + if node.args.vararg: + param_str = param_str + ', ...' if param_str else '...' + if func_name[0].isdigit(): + return f'declare {ret_type} @"{func_name}"({param_str})' + return f'declare {ret_type} @{func_name}({param_str})' + + def _is_export_func(self, node: ast.FunctionDef) -> bool: + """检查函数是否标记为 CExport""" + if not node.returns: + return False + return self._check_annotation_for_export(node.returns) + + def _check_annotation_for_export(self, annotation) -> bool: + """递归检查类型注解中是否包含 CExport 或 t.State""" + if isinstance(annotation, ast.Attribute): + if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'State'): + return True + elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return self._check_annotation_for_export(annotation.left) or self._check_annotation_for_export(annotation.right) + elif isinstance(annotation, ast.Name): + return annotation.id in ('CExport', 'State') + return False + + def _generate_global_decl(self, node: ast.AnnAssign) -> str: + """生成全局变量声明""" + if not isinstance(node.target, ast.Name): + return None + var_name = node.target.id + if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine': + return None + if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': + return None + if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': + return None + if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': + return None + if isinstance(node.annotation, ast.List): + for elt in node.annotation.elts: + if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'): + return None + if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable': + return None + var_type = self._get_type_str(node.annotation) + if var_type.startswith('[0 x ') and node.value and isinstance(node.value, ast.List): + elem_type = var_type[5:-1] + actual_count = len(node.value.elts) + if actual_count > 0: + var_type = f'[{actual_count} x {elem_type}]' + return f'@{var_name} = external global {var_type}' + + def _generate_global_assign_decl(self, node: ast.Assign) -> str: + """从无类型标注赋值推断并生成全局变量声明""" + if not node.targets or not isinstance(node.targets[0], ast.Name): + return None + var_name = node.targets[0].id + var_type = self._infer_type(node.value) + if var_type: + return f'@{var_name} = external global {var_type}' + return None + + def _generate_class_decl(self, node: ast.ClassDef) -> List[str]: + """生成结构体/类声明""" + decls = [] + class_name = node.name + is_enum = False + is_exception = False + if node.bases: + for base in node.bases: + if isinstance(base, ast.Attribute) and hasattr(base, 'attr'): + if base.attr == 'CEnum' or base.attr == 'Enum': + is_enum = True + break + elif base.attr == 'Exception' or base.attr in self.exception_names: + is_exception = True + break + elif isinstance(base, ast.Name) and hasattr(base, 'id'): + if base.id == 'CEnum' or base.id == 'Enum': + is_enum = True + break + elif base.id == 'Exception' or base.id in self.exception_names: + is_exception = True + break + if is_exception: + return decls + if is_enum: + enum_values = {} + next_value = 0 + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + var_name = item.target.id + if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + enum_values[var_name] = item.value.value + else: + enum_values[var_name] = next_value + next_value += 1 + elif isinstance(item, ast.Assign) and len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): + var_name = item.targets[0].id + if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + enum_values[var_name] = item.value.value + next_value = item.value.value + 1 + else: + enum_values[var_name] = next_value + next_value += 1 + for var_name, value in enum_values.items(): + decls.append(f'@__config_{class_name}_{var_name} = external global i32') + return decls + member_types = [] + has_bitfield = False + total_bits = 0 + has_methods = any(isinstance(item, ast.FunctionDef) for item in node.body) + is_cvtable = False + is_cpython_object = False + if hasattr(node, 'decorator_list') and node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Attribute): + if getattr(decorator.value, 'id', None) == 't': + if decorator.attr == 'CVTable': + is_cvtable = True + elif decorator.attr == 'Object': + is_cpython_object = True + elif isinstance(decorator, ast.Name): + if decorator.id == 'CVTable': + is_cvtable = True + elif decorator.id == 'Object': + is_cpython_object = True + if has_methods and not is_cpython_object: + is_cpython_object = True + has_parent_class = False + for base in node.bases: + base_name = None + if isinstance(base, ast.Attribute): + base_name = base.attr + elif isinstance(base, ast.Name): + base_name = base.id + elif isinstance(base, ast.Subscript): + if isinstance(base.value, ast.Attribute): + base_name = base.value.attr + elif isinstance(base.value, ast.Name): + base_name = base.value.id + if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): + has_parent_class = True + break + if has_parent_class and not is_cvtable: + is_cvtable = True + base_has_vtable = False + for base in node.bases: + base_name = None + if isinstance(base, ast.Attribute): + base_name = base.attr + elif isinstance(base, ast.Name): + base_name = base.id + elif isinstance(base, ast.Subscript): + if isinstance(base.value, ast.Attribute): + base_name = base.value.attr + elif isinstance(base.value, ast.Name): + base_name = base.value.id + if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): + for n in ast.iter_child_nodes(self._pyi_tree): + if isinstance(n, ast.ClassDef) and n.name == base_name: + if hasattr(n, 'decorator_list') and n.decorator_list: + for dec in n.decorator_list: + if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable': + base_has_vtable = True + elif isinstance(dec, ast.Name) and dec.id == 'CVTable': + base_has_vtable = True + break + if base_has_vtable: + break + if has_methods and is_cvtable and not base_has_vtable: + member_types.append('i8*') + seen_member_names = set() + for base in node.bases: + base_name = None + if isinstance(base, ast.Attribute): + base_name = base.attr + elif isinstance(base, ast.Name): + base_name = base.id + elif isinstance(base, ast.Subscript): + if isinstance(base.value, ast.Attribute): + base_name = base.value.attr + elif isinstance(base.value, ast.Name): + base_name = base.value.id + if base_name and base_name not in ('Object', 'CVTable', 'CEnum', 'Enum', 'CStruct', 'CUnion'): + base_member_types, base_seen = self._get_inherited_members(base_name) + for mt in base_member_types: + member_types.append(mt) + seen_member_names.update(base_seen) + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + seen_member_names.add(item.target.id) + init_members = [] + for item in node.body: + if isinstance(item, ast.FunctionDef) and item.name == '__init__': + for stmt in item.body: + if (isinstance(stmt, ast.AnnAssign) + and isinstance(stmt.target, ast.Attribute) + and isinstance(stmt.target.value, ast.Name) + and stmt.target.value.id == 'self'): + init_members.append(stmt) + untyped_self_members = [] + for m_name in [m.attr for m in init_members if isinstance(m.target, ast.Attribute)]: + seen_member_names.add(m_name) + for item in node.body: + if isinstance(item, ast.FunctionDef): + if hasattr(item, 'type_params') and item.type_params: + continue + for stmt in item.body: + if (isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + and isinstance(stmt.targets[0], ast.Attribute) + and isinstance(stmt.targets[0].value, ast.Name) + and stmt.targets[0].value.id == 'self'): + attr_name = stmt.targets[0].attr + if attr_name not in seen_member_names: + seen_member_names.add(attr_name) + untyped_self_members.append(stmt) + for item in list(node.body) + init_members + untyped_self_members: + if isinstance(item, ast.AnnAssign): + bit_width = self._get_bitfield_width(item.annotation) + if bit_width is not None: + has_bitfield = True + total_bits += bit_width + else: + var_type = self._get_type_str(item.annotation, embedded=True) + if (isinstance(item.annotation, ast.Subscript) + and isinstance(item.annotation.value, ast.Name) + and item.annotation.value.id == 'list'): + slice_node = item.annotation.slice + is_dynamic = False + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + count_node = slice_node.elts[1] + if isinstance(count_node, ast.Constant) and count_node.value is None: + is_dynamic = True + elif not (isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0): + if not isinstance(count_node, (ast.Name, ast.BinOp)): + is_dynamic = True + elif not isinstance(slice_node, ast.Tuple): + is_dynamic = True + if is_dynamic: + elem_type = self._get_type_str(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0], embedded=True) + init_len = 0 + if isinstance(item.value, ast.List): + init_len = len(item.value.elts) + elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): + init_len = len(item.value.value) + 1 + var_type = f'[{init_len} x {elem_type}]' + member_types.append(var_type) + elif isinstance(item, ast.Assign): + if (len(item.targets) == 1 + and isinstance(item.targets[0], ast.Attribute) + and isinstance(item.targets[0].value, ast.Name) + and item.targets[0].value.id == 'self'): + attr_name = item.targets[0].attr + if attr_name in seen_member_names: + continue + InferredType = 'i32' + if item.value and isinstance(item.value, ast.Constant): + if isinstance(item.value.value, float): + InferredType = 'float' + elif isinstance(item.value.value, bool): + InferredType = 'i8' + elif isinstance(item.value.value, str): + InferredType = 'i8*' + member_types.append(InferredType) + else: + member_types.append('i32') + if has_bitfield: + if total_bits <= 8: + member_types.insert(0, 'i8') + elif total_bits <= 16: + member_types.insert(0, 'i16') + elif total_bits <= 32: + member_types.insert(0, 'i32') + else: + member_types.insert(0, 'i64') + struct_type_name = f'%"{self.module_sha1}.{class_name}"' if self.module_sha1 else f'%struct.{class_name}' + struct_decl = f'{struct_type_name} = type {{ {", ".join(member_types)} }}' + decls.append(struct_decl) + if is_cpython_object or is_cvtable: + new_func_name = f'{class_name}.__before_init__' + if self.module_sha1: + new_func_name = f"{self.module_sha1}.{new_func_name}" + if new_func_name[0].isdigit(): + new_func_decl = f'declare void @"{new_func_name}"({struct_type_name}*)' + else: + new_func_decl = f'declare void @{new_func_name}({struct_type_name}*)' + decls.append(new_func_decl) + for item in node.body: + if isinstance(item, ast.FunctionDef): + if hasattr(item, 'type_params') and item.type_params: + continue + method_name = f'{class_name}.{item.name}' + if self.module_sha1: + method_name = f"{self.module_sha1}.{method_name}" + ret_type = self._get_type_str(item.returns) if item.returns else 'void' + if not ret_type: + ret_type = 'void' + params = [] + for arg_idx, arg in enumerate(item.args.args): + if arg.annotation: + arg_type = self._get_type_str(arg.annotation) + elif arg_idx == 0 and arg.arg == 'self': + arg_type = f'{struct_type_name}*' + else: + arg_type = 'i8*' + params.append(arg_type) + param_str = ', '.join(params) if params else '' + if method_name[0].isdigit(): + decls.append(f'declare {ret_type} @"{method_name}"({param_str})') + else: + decls.append(f'declare {ret_type} @{method_name}({param_str})') + return decls + + def _get_inherited_members(self, base_name: str): + import ast + member_types = [] + seen_names = set() + if not hasattr(self, '_pyi_tree') or self._pyi_tree is None: + return member_types, seen_names + base_node = None + for node in ast.iter_child_nodes(self._pyi_tree): + if isinstance(node, ast.ClassDef) and node.name == base_name: + base_node = node + break + if base_node is None: + return member_types, seen_names + base_decls = self._generate_class_decl(base_node) + for decl in base_decls: + if '= type {' in decl: + type_body = decl.split('= type {')[1].rstrip('}').strip() + if type_body: + for t in type_body.split(','): + t = t.strip() + if t: + member_types.append(t) + break + for item in base_node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + seen_names.add(item.target.id) + elif isinstance(item, ast.Assign) and len(item.targets) == 1: + if isinstance(item.targets[0], ast.Attribute) and isinstance(item.targets[0].value, ast.Name) and item.targets[0].value.id == 'self': + seen_names.add(item.targets[0].attr) + for item in base_node.body: + if isinstance(item, ast.FunctionDef) and item.name == '__init__': + for stmt in item.body: + if isinstance(stmt, ast.AnnAssign) and isinstance(stmt.target, ast.Attribute) and isinstance(stmt.target.value, ast.Name) and stmt.target.value.id == 'self': + seen_names.add(stmt.target.attr) + elif isinstance(stmt, ast.Assign) and len(stmt.targets) == 1 and isinstance(stmt.targets[0], ast.Attribute) and isinstance(stmt.targets[0].value, ast.Name) and stmt.targets[0].value.id == 'self': + seen_names.add(stmt.targets[0].attr) + return member_types, seen_names + + @staticmethod + def _ctype_name_to_llvm(name: str) -> str: + """根据 CType 元属性自动推导 LLVM IR 类型 + + 通过 CTypeRegistry.NameToLLVM 查询,利用 CType 的 + position/IsSigned/Size 元属性自动推导,无需手动映射表。 + """ + from lib.includes.t import CTypeRegistry + result = CTypeRegistry.NameToLLVM(name) + return result + + def _get_type_str(self, annotation: ast.AST, embedded: bool = False) -> str: + import ast + from lib.includes.t import CTypeRegistry + if annotation is None: + return 'i8*' + + non_struct_types = {'list', 'dict', 'tuple', 'set', 'array'} + + if isinstance(annotation, ast.Name): + if annotation.id == 'None': + return 'void' + if annotation.id in ('str', 'bytes'): + return 'i8*' + llvm_type = CTypeRegistry.NameToLLVM(annotation.id) + if llvm_type is not None: + return llvm_type + resolved = CTypeRegistry.ResolveName(annotation.id) + if resolved is not None: + ctype_cls, ptr_level = resolved + base = CTypeRegistry.CTypeToLLVM(ctype_cls) + if ptr_level > 0: + if base == 'void': + return 'i8*' + if '*' in base: + return base + return f'{base}*' + return base + if annotation.id in non_struct_types: + return 'i32' + if annotation.id in self.enum_names: + return 'i32' + if annotation.id in self.struct_names: + sha1 = self.struct_sha1_map.get(annotation.id, self.module_sha1) + sname = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' + if embedded: + return sname + else: + return f'{sname}*' + if annotation.id in self.typedef_map: + resolved = self._get_type_str(self.typedef_map[annotation.id], embedded=embedded) + return resolved + sha1 = self.struct_sha1_map.get(annotation.id, self.module_sha1) + sname = f'%"{sha1}.{annotation.id}"' if sha1 else f'%struct.{annotation.id}' + return f'{sname}*' + elif isinstance(annotation, ast.Attribute): + attr_name = annotation.attr if hasattr(annotation, 'attr') else '' + module_name = '' + if hasattr(annotation, 'value'): + if isinstance(annotation.value, ast.Name): + module_name = annotation.value.id + elif isinstance(annotation.value, ast.Attribute) and hasattr(annotation.value, 'attr'): + module_name = annotation.value.attr + if (module_name == 't' and attr_name == 'State') or attr_name == 'State': + return '' + if (module_name == 't' and attr_name == 'Callable') or attr_name == 'Callable': + return 'i8*' + llvm_type = CTypeRegistry.NameToLLVM(attr_name) + if llvm_type is not None: + return llvm_type + resolved = CTypeRegistry.ResolveName(attr_name) + if resolved is not None: + ctype_cls, ptr_level = resolved + base = CTypeRegistry.CTypeToLLVM(ctype_cls) + if ptr_level > 0: + if base == 'void': + return 'i8*' + if '*' in base: + return base + return f'{base}*' + return base + if attr_name in self.typedef_map: + return self._get_type_str(self.typedef_map[attr_name], embedded=embedded) + if attr_name in self.enum_names: + return 'i32' + if attr_name in self.struct_names: + sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) + sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' + if embedded: + return sname + else: + return f'{sname}*' + if attr_name and attr_name[0].isupper() and attr_name not in non_struct_types: + sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) + sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' + return f'{sname}*' + if attr_name and attr_name not in non_struct_types: + sha1 = self.struct_sha1_map.get(attr_name, self.module_sha1) + sname = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}' + return f'{sname}*' + return 'i32' + elif isinstance(annotation, ast.BinOp): + left_type = self._get_type_str(annotation.left, embedded=embedded) + right_type = self._get_type_str(annotation.right, embedded=embedded) + if left_type in ('', 'void'): + return right_type if right_type not in ('', 'void') else (left_type or right_type) + if right_type in ('', 'void'): + return left_type + if '*' in left_type: + return left_type + if '*' in right_type: + if right_type == 'i8*': + return self._type_to_llvm_ptr(left_type) + return right_type + return left_type + elif isinstance(annotation, ast.Subscript): + base = self._get_type_str(annotation.value) + if base == 'i8*' and isinstance(annotation.slice, ast.Constant): + return f'[{self._get_const_int(annotation.slice)} x i8]' + if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): + return f'[{annotation.slice.value} x {base}]' + if isinstance(annotation.value, ast.Name) and annotation.value.id == 'list': + slice_node = annotation.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + elem_type = self._get_type_str(slice_node.elts[0], embedded=True) + count_node = slice_node.elts[1] + array_count = self._get_const_int(count_node) + if array_count > 0: + return f'[{array_count} x {elem_type}]' + else: + return f'[0 x {elem_type}]' + elem_type = self._get_type_str(slice_node, embedded=True) + return f'[0 x {elem_type}]' + if isinstance(annotation.value, ast.Name) and annotation.value.id == 'tuple': + slice_node = annotation.slice + if isinstance(slice_node, ast.Tuple): + elem_types = [self._get_type_str(e, embedded=True) for e in slice_node.elts] + else: + elem_types = [self._get_type_str(slice_node, embedded=True)] + return '{ ' + ', '.join(elem_types) + ' }' + return f'{base}' + elif isinstance(annotation, ast.Constant): + if annotation.value is None: + return 'void' + if isinstance(annotation.value, int): + return 'i32' + if isinstance(annotation.value, str): + type_name = annotation.value + if type_name in self.enum_names: + return 'i32' + if type_name in self.struct_names: + sha1 = self.struct_sha1_map.get(type_name, self.module_sha1) + sname = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' + if embedded: + return sname + else: + return f'{sname}*' + llvm_type = CTypeRegistry.NameToLLVM(type_name) + if llvm_type is not None: + return llvm_type + resolved = CTypeRegistry.ResolveName(type_name) + if resolved is not None: + ctype_cls, ptr_level = resolved + base = CTypeRegistry.CTypeToLLVM(ctype_cls) + if ptr_level > 0: + if base == 'void': + return 'i8*' + if '*' in base: + return base + return f'{base}*' + return base + sha1 = self.struct_sha1_map.get(type_name, self.module_sha1) + sname = f'%"{sha1}.{type_name}"' if sha1 else f'%struct.{type_name}' + return f'{sname}*' + return 'i8*' + elif isinstance(annotation, ast.Call): + if isinstance(annotation.func, ast.Name) and annotation.func.id == 'callable': + return 'i8*' + if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Callable': + return 'i8*' + return 'i32' + + def _type_to_llvm_ptr(self, type_str: str) -> str: + if type_str.startswith('%struct.') and not type_str.endswith('*'): + return type_str + '*' + if type_str.startswith('%') and not type_str.endswith('*'): + return type_str + '*' + if type_str.endswith('*'): + return type_str + from lib.includes.t import CTypeRegistry + resolved = CTypeRegistry.ResolveName(type_str) + if resolved is not None: + ctype_cls, ptr_level = resolved + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str: + return f'{llvm_str}{"*" * (ptr_level + 1)}' + cnameres = CTypeRegistry.CNameToClass(type_str) + if cnameres is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(cnameres) + if llvm_str: + return f'{llvm_str}*' + return f'{type_str}*' + + def _infer_type(self, value: ast.AST) -> str: + """从值推断类型""" + import ast + if isinstance(value, ast.Constant): + if isinstance(value.value, int): + return 'i32' + elif isinstance(value.value, float): + return 'double' + elif isinstance(value.value, str): + return 'i8*' + elif isinstance(value.value, bool): + return 'i8' + elif isinstance(value, ast.List): + return 'i8*' + elif isinstance(value, ast.Dict): + return 'i8*' + elif isinstance(value, ast.Name): + return 'i32' + elif isinstance(value, ast.BinOp): + return self._infer_type(value.left) + elif isinstance(value, ast.Call): + return 'i8*' + return 'i32' + + def _get_bitfield_width(self, annotation: ast.AST): + import ast + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + right_width = self._get_bitfield_width(annotation.right) + if right_width is not None: + return right_width + return self._get_bitfield_width(annotation.left) + if isinstance(annotation, ast.Call): + if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Bit': + if annotation.args: + arg = annotation.args[0] + if isinstance(arg, ast.Constant) and isinstance(arg.value, int): + return arg.value + if isinstance(annotation, ast.Subscript): + if isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'Bit': + if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int): + return annotation.slice.value + return None + + def _get_const_int(self, node: ast.AST) -> int: + """获取常量整数值,支持符号常量和简单表达式""" + import ast + if isinstance(node, ast.Constant) and isinstance(node.value, int): + return node.value + if isinstance(node, ast.Name): + if node.id in self._define_constants: + val = self._define_constants[node.id] + if isinstance(val, int): + return val + if isinstance(node, ast.BinOp): + left_val = self._get_const_int(node.left) + right_val = self._get_const_int(node.right) + if left_val and right_val: + if isinstance(node.op, ast.Add): + return left_val + right_val + if isinstance(node.op, ast.Sub): + return left_val - right_val + if isinstance(node.op, ast.Mult): + return left_val * right_val + if isinstance(node.op, ast.Div): + return left_val // right_val + if isinstance(node.op, ast.FloorDiv): + return left_val // right_val + return 0 + + +def _parallel_translate_worker(src_path, out_path, src_root, temp_dir, output_dir, + include_dirs, triple, datalayout, sha1_map, sig_files, + stub_files, include_py_map, slice_level, + shared_sym_pickle_path, struct_sha1_map): + try: + import pickle + from Projectrans import Phase2Translator, compute_sha1 + trans = Phase2Translator(src_root, temp_dir, output_dir, + compile_cmd='llc', include_dirs=include_dirs, + target_triple=triple, target_datalayout=datalayout) + trans.sha1_map = sha1_map + trans.sig_files = sig_files + trans.stub_files = stub_files + trans.include_py_map = include_py_map + trans.slice_level = slice_level + trans.struct_sha1_map = struct_sha1_map + + if shared_sym_pickle_path and os.path.exists(shared_sym_pickle_path): + with open(shared_sym_pickle_path, 'rb') as f: + shared_data = pickle.load(f) + trans._shared_symbol_table = shared_data['symbol_table'] + trans._shared_source_module_sig_files = shared_data['source_module_sig_files'] + trans._shared_all_dc = shared_data['all_dc'] + trans._shared_export_extern_funcs = shared_data['export_extern_funcs'] + trans.inline_func_symbols = shared_data['inline_func_symbols'] + trans.function_default_args = shared_data['function_default_args'] + trans._shared_generic_class_templates = shared_data.get('generic_class_templates', {}) + else: + trans._precollect_inline_symbols() + trans._build_shared_symbol_data() + + trans._translate_file(src_path, out_path) + return ('ok', src_path, '') + except Exception as e: + import traceback + return ('error', src_path, f'{e}\n{traceback.format_exc(limit=50)}') + + +class Phase2Translator: + """阶段二:使用声明接口翻译源文件""" + + INCLUDE_LIB_EXTENSIONS = ('.dll', '.ll', '.so', '.o', '.a', '.lib') + INCLUDE_SRC_EXTENSIONS = ('.c', '.cpp', '.cc', '.cxx', '.m', '.mm') + INCLUDE_DIRS = [ + os.path.join(os.path.dirname(os.path.abspath(__file__)), 'includes'), + r"d:\Users\TermiNexus\Desktop\TransPyC\includes", + ] + + def __init__(self, src_root: str, temp_dir: str, output_dir: str, compile_cmd: str = 'llc', compile_flags: list = None, linker_cmd: str = None, linker_flags: list = None, linker_output: str = None, include_dirs: list = None, entry_files: list = None, target_triple: str = None, target_datalayout: str = None): + self.src_root = os.path.abspath(src_root) + self.temp_dir = os.path.abspath(temp_dir) + self.output_dir = os.path.abspath(output_dir) + self.compile_cmd = compile_cmd + self.compile_flags = compile_flags or ['-filetype=obj'] + self.triple = target_triple + self.datalayout = target_datalayout + if not self.triple: + for i, flag in enumerate(self.compile_flags): + if flag.startswith('-mtriple='): + self.triple = flag[len('-mtriple='):] + elif flag == '-mtriple' and i + 1 < len(self.compile_flags): + self.triple = self.compile_flags[i + 1] + self.linker_cmd = linker_cmd + self.linker_flags = linker_flags or [] + self.linker_output = linker_output + self.slice_level = 3 + self.sha1_map: dict[str, str] = {} + self.sig_files: dict[str, str] = {} + self.stub_files: dict[str, str] = {} + self.include_py_map: dict[str, str] = {} + self.used_includes: set = set() + self._last_error_stack = None + self.function_default_args: dict = {} + self.inline_func_symbols: dict = {} + self.extra_link_files: list = [] + self.extra_compile_files: list = [] + self.extra_py_files: list = [] + self._include_sha1s: set = set() + self.entry_files = entry_files + self._shared_symbol_table = None + self._shared_source_module_sig_files = {} + self._shared_all_dc = {} + self._shared_export_extern_funcs = set() + self._stub_decls_cache = {} + default_dirs = [d for d in self.INCLUDE_DIRS if os.path.isdir(d)] + if include_dirs: + seen = set() + self.include_dirs = [] + for d in list(include_dirs) + default_dirs: + d = os.path.abspath(d) + if d not in seen and os.path.isdir(d): + self.include_dirs.append(d) + seen.add(d) + else: + self.include_dirs = default_dirs + self._load_sha1_map() + + def _load_sha1_map(self): + """从 temp_dir 加载 SHA1 映射、签名文件和 stub 声明文件列表""" + if not os.path.exists(self.temp_dir): + print(f"[错误] 声明目录不存在: {self.temp_dir}") + return + + for fname in os.listdir(self.temp_dir): + fpath = os.path.join(self.temp_dir, fname) + if fname.startswith('_'): + continue + if fname.endswith('.pyi'): + sha1 = fname[:-4] + self.sig_files[sha1] = fpath + elif fname.endswith('.stub.ll'): + sha1 = fname[:-8] + self.stub_files[sha1] = fpath + + sha1_file_path = os.path.join(self.temp_dir, '_sha1_map.txt') + if os.path.exists(sha1_file_path): + with open(sha1_file_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if ':' in line: + sha1, rel = line.split(':', 1) + self.sha1_map[sha1] = rel + if rel.startswith('includes/'): + module_name = os.path.splitext(os.path.basename(rel))[0] + self.include_py_map[module_name] = sha1 + else: + for sha1, stub_path in self.stub_files.items(): + self.sha1_map[sha1] = sha1 + + def _build_struct_sha1_map(self): + struct_sha1_map = {} + valid_sha1_keys = set(self.sha1_map.keys()) + for fname in os.listdir(self.temp_dir): + if not fname.endswith('.pyi'): + continue + sha1_key = fname.replace('.pyi', '') + if sha1_key not in valid_sha1_keys: + continue + pyi_path = os.path.join(self.temp_dir, fname) + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + tree = ast.parse(f.read()) + except Exception: + continue + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef): + struct_sha1_map[node.name] = sha1_key + return struct_sha1_map + + def run(self): + """扫描源目录,翻译并生成 .ll 含代码文件(导入遍历)""" + if self.entry_files: + py_files = list(self.entry_files) + else: + main_py = os.path.join(self.src_root, 'main.py') + if os.path.exists(main_py): + py_files = [main_py] + else: + py_files = [] + for root, dirs, files in os.walk(self.src_root): + dirs[:] = [d for d in dirs if d not in ('__pycache__',)] + for file in files: + if file.endswith('.py'): + py_files.append(os.path.join(root, file)) + + if not py_files: + print("[阶段二] 未找到入口文件或源文件") + return + + reachable = find_reachable_files_from_entries(self.src_root, py_files) + py_files = list(reachable) + + py_files = topological_sort_files(py_files, self.src_root) + + print(f"[阶段二] 找到 {len(py_files)} 个可达源文件(已按依赖排序)") + print("[阶段二] 处理顺序:") + for i, f in enumerate(py_files[:10], 1): + rel = os.path.relpath(f, self.src_root) + print(f" {i}. {rel}") + os.makedirs(self.output_dir, exist_ok=True) + + valid_sha1s = set(self.sha1_map.keys()) + old_stub_count = len(self.stub_files) + old_sig_count = len(self.sig_files) + self.stub_files = {k: v for k, v in self.stub_files.items() if k in valid_sha1s} + self.sig_files = {k: v for k, v in self.sig_files.items() if k in valid_sha1s} + if old_stub_count != len(self.stub_files) or old_sig_count != len(self.sig_files): + print(f"[阶段二] 过滤旧文件: stub {old_stub_count}->{len(self.stub_files)}, sig {old_sig_count}->{len(self.sig_files)}") + + active_sha1s = set() + self._precollect_inline_symbols() + self._build_shared_symbol_data() + self.struct_sha1_map = self._build_struct_sha1_map() + + need_translate = [] + for i, src_path in enumerate(py_files, 1): + rel = os.path.relpath(src_path, self.src_root) + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + sha1 = compute_sha1(content) + active_sha1s.add(sha1) + out_path = os.path.join(self.output_dir, f"{sha1}.ll") + + current_module_sha1_map = self._build_current_module_sha1_map(sha1) + + try: + tree = ast.parse(content) + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + self.used_includes.add(alias.name.split('.')[0]) + elif isinstance(node, ast.ImportFrom): + if node.module: + self.used_includes.add(node.module.split('.')[0]) + except Exception: + pass + + if os.path.isfile(out_path): + deps_changed = self._check_deps_changed(sha1, current_module_sha1_map) + if not deps_changed: + print(f"[{i}/{len(py_files)}] 跳过(缓存): {rel} -> {sha1}.ll") + continue + else: + if self._recombine_ll(sha1, current_module_sha1_map): + print(f"[{i}/{len(py_files)}] 重组(依赖变化): {rel} -> {sha1}.ll") + continue + print(f"[{i}/{len(py_files)}] 重译(依赖变化): {rel} -> {sha1}.ll") + + else: + stub_cache = os.path.join(self.output_dir, f"{sha1}.stub.ll") + text_cache = os.path.join(self.output_dir, f"{sha1}.text.ll") + if os.path.isfile(stub_cache) and os.path.isfile(text_cache): + if self._recombine_ll(sha1, current_module_sha1_map): + print(f"[{i}/{len(py_files)}] 重组(缓存恢复): {rel} -> {sha1}.ll") + continue + + need_translate.append((i, src_path, out_path, sha1, current_module_sha1_map)) + + if need_translate: + print(f"\n[阶段二] 需要翻译 {len(need_translate)} 个文件") + import time + t_start = time.time() + + n_workers = min(os.cpu_count() or 4, len(need_translate), 8) + + if n_workers > 1 and len(need_translate) > 1: + from concurrent.futures import ProcessPoolExecutor, as_completed + import pickle + print(f" 并行翻译 (workers={n_workers})") + + shared_pickle_path = os.path.join(self.temp_dir, '_shared_sym.pkl') + try: + shared_data = { + 'symbol_table': self._shared_symbol_table, + 'source_module_sig_files': self._shared_source_module_sig_files, + 'all_dc': self._shared_all_dc, + 'export_extern_funcs': self._shared_export_extern_funcs, + 'inline_func_symbols': self.inline_func_symbols, + 'function_default_args': self.function_default_args, + 'generic_class_templates': self._shared_generic_class_templates, + } + with open(shared_pickle_path, 'wb') as f: + pickle.dump(shared_data, f, protocol=pickle.HIGHEST_PROTOCOL) + print(f" 共享符号表已序列化 ({os.path.getsize(shared_pickle_path)//1024}KB)") + except Exception as e: + print(f" [警告] 符号表序列化失败({e}),worker将自行构建") + shared_pickle_path = '' + + errors = [] + with ProcessPoolExecutor(max_workers=n_workers) as executor: + futures = {} + for i, src_path, out_path, sha1, msm in need_translate: + rel = os.path.relpath(src_path, self.src_root) + future = executor.submit( + _parallel_translate_worker, + src_path, out_path, + self.src_root, self.temp_dir, self.output_dir, + self.include_dirs, self.triple, self.datalayout, + self.sha1_map, self.sig_files, self.stub_files, + self.include_py_map, self.slice_level, + shared_pickle_path, self.struct_sha1_map + ) + futures[future] = (i, rel) + + done_count = 0 + for future in as_completed(futures): + i, rel = futures[future] + done_count += 1 + try: + status, _, err = future.result() + if status == 'ok': + print(f" [{done_count}/{len(need_translate)}] 完成: {rel}") + else: + print(f" [错误] {rel}: {err[:2000]}") + errors.append((rel, err)) + except Exception as e: + print(f" [错误] {rel}: {e}") + errors.append((rel, str(e))) + + if errors: + print(f"\n[编译终止] {len(errors)} 个文件翻译失败") + sys.exit(1) + else: + for idx, (i, src_path, out_path, sha1, msm) in enumerate(need_translate): + rel = os.path.relpath(src_path, self.src_root) + t0 = time.time() + try: + self._translate_file(src_path, out_path, prebuilt_module_sha1_map=msm) + t1 = time.time() + print(f" [{idx+1}/{len(need_translate)}] {rel} ({t1-t0:.1f}s)") + except Exception as e: + print(f" [错误] {rel}: {e}") + traceback.print_exc() + print(f"\n[编译终止] 翻译失败") + sys.exit(1) + t_end = time.time() + print(f" 翻译总耗时: {t_end-t_start:.1f}s") + + print(f"\n[阶段二完成] .ll 文件生成到: {self.output_dir}") + self._scan_include_libraries() + self._compile_include_py_files(active_sha1s) + self._compile_ll_files(active_sha1s) + self._compile_include_sources() + if self.linker_cmd: + self._link_obj_files(active_sha1s) + + def _build_current_module_sha1_map(self, self_sha1: str) -> dict: + """构建当前模块的依赖 SHA1 映射(与 _translate_file 中逻辑一致)""" + module_sha1_map = {} + for sha1_key, sig_path in self.sig_files.items(): + if sha1_key == self_sha1: + continue + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + inc_mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + inc_mod_name = inc_mod_name[len('includes/'):] + inc_short_name = inc_mod_name.split('.')[-1] if '.' in inc_mod_name else inc_mod_name + actual_sha1 = sha1_key + for inc_dir in self.include_dirs: + if os.path.isdir(inc_dir): + py_path = os.path.join(inc_dir, rel_path[len('includes/'):].replace(os.sep, '/')) + py_path = os.path.splitext(py_path)[0] + '.py' + if os.path.isfile(py_path): + with open(py_path, 'r', encoding='utf-8') as f: + py_sha1 = compute_sha1(f.read()) + actual_sha1 = py_sha1 + break + module_sha1_map[inc_mod_name] = actual_sha1 + module_sha1_map[inc_short_name] = actual_sha1 + # Also add parent package name (e.g., 'hashlib' for 'hashlib.__init__') + if inc_short_name == '__init__' and '.' in inc_mod_name: + parent_pkg = inc_mod_name.rsplit('.', 1)[0] + module_sha1_map[parent_pkg] = actual_sha1 + continue + module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + module_sha1_map[module_name] = sha1_key + short_name = module_name.split('.')[-1] if '.' in module_name else module_name + module_sha1_map[short_name] = sha1_key + return module_sha1_map + + @staticmethod + def _split_ll(ll_content: str): + """将 .ll 内容拆分为 stub(声明)和 text(代码)两部分 + + stub: target, 注释, %type = type, declare, @xxx = external global + text: define ... { ... }, @xxx = global/constant (带初始化器) + """ + import re + stub_lines = [] + text_lines = [] + in_define = False + brace_depth = 0 + module_sha1 = None + defined_names = set() + + for line in ll_content.splitlines(True): + stripped = line.strip() + + if stripped.startswith('define '): + dm = re.match(r'define\s+[^@]*@"?([a-f0-9]+)\.', stripped) + if dm and module_sha1 is None: + module_sha1 = dm.group(1) + dm2 = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm2: + defined_names.add(dm2.group(1)) + + in_global_def = False + global_var_name = None + global_type_parts = [] + global_brace_depth = 0 + + for line in ll_content.splitlines(True): + stripped = line.strip() + + if in_global_def: + text_lines.append(line) + global_type_parts.append(stripped) + global_brace_depth += stripped.count('{') - stripped.count('}') + if global_brace_depth <= 0: + full_type = ' '.join(global_type_parts).strip() + depth = 0 + type_end = len(full_type) + for ci, cc in enumerate(full_type): + if cc in ('{', '['): + depth += 1 + elif cc in ('}', ']'): + depth -= 1 + elif depth == 0 and cc == ' ': + type_end = ci + break + var_type = full_type[:type_end].strip() + if var_type: + stub_lines.append(f'{global_var_name} = external global {var_type}\n') + in_global_def = False + global_var_name = None + global_type_parts = [] + global_brace_depth = 0 + continue + + if in_define: + text_lines.append(line) + brace_depth += stripped.count('{') - stripped.count('}') + if brace_depth <= 0: + in_define = False + continue + + if stripped.startswith('define '): + text_lines.append(line) + in_define = True + brace_depth = stripped.count('{') - stripped.count('}') + decl_line = re.sub(r'^define\s+', 'declare ', stripped) + decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line) + decl_line = re.sub(r'\balwaysinline\s+', '', decl_line) + paren_pos = decl_line.rfind(')') + if paren_pos >= 0: + decl_line = decl_line[:paren_pos + 1] + stub_lines.append(decl_line + '\n') + continue + + if stripped == '{' and text_lines and not in_define: + prev_stripped = text_lines[-1].strip() if text_lines else '' + if prev_stripped.startswith('define ') or prev_stripped.endswith('noredzone') or prev_stripped.endswith(')'): + text_lines.append(line) + brace_depth = 1 + in_define = True + if prev_stripped.startswith('define '): + decl_line = re.sub(r'^define\s+', 'declare ', prev_stripped) + decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line) + decl_line = re.sub(r'\balwaysinline\s+', '', decl_line) + paren_pos = decl_line.rfind(')') + if paren_pos >= 0: + decl_line = decl_line[:paren_pos + 1] + stub_lines.append(decl_line + '\n') + continue + + if stripped.startswith('@') and ' global ' in stripped and 'external global' not in stripped: + text_lines.append(line) + if ' internal ' not in stripped and ' private ' not in stripped: + name_match = re.match(r'(@\S+)', stripped) + if name_match: + var_name = name_match.group(1) + global_pos = stripped.find(' global ') + after_global = stripped[global_pos + 8:] + depth = 0 + type_end = len(after_global) + for ci, cc in enumerate(after_global): + if cc in ('{', '['): + depth += 1 + elif cc in ('}', ']'): + depth -= 1 + elif depth == 0 and cc == ' ': + type_end = ci + break + var_type = after_global[:type_end].strip() + brace_depth_gv = 0 + for cc in var_type: + if cc == '{': + brace_depth_gv += 1 + elif cc == '}': + brace_depth_gv -= 1 + if brace_depth_gv > 0: + in_global_def = True + global_var_name = var_name + global_type_parts = [var_type] + global_brace_depth = brace_depth_gv + elif var_type: + stub_lines.append(f'{var_name} = external global {var_type}\n') + continue + if stripped.startswith('@') and ' constant ' in stripped: + text_lines.append(line) + continue + + if stripped.startswith('declare'): + dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm: + fname = dm.group(1) + if fname in defined_names: + stub_lines.append(line) + continue + dot_pos = fname.find('.') + if dot_pos > 0: + fname_sha1 = fname[:dot_pos] + if module_sha1 and fname_sha1 != module_sha1 and len(fname_sha1) >= 16: + continue + if re.match(r'^[a-f0-9]{16}\.', fname): + continue + stub_lines.append(line) + continue + + stub_lines.append(line) + + return ''.join(stub_lines), ''.join(text_lines) + + def _save_deps(self, sha1: str, module_sha1_map: dict): + """保存依赖指纹到 .deps.json""" + deps_path = os.path.join(self.output_dir, f"{sha1}.deps.json") + deps = {} + for mod_name, dep_sha1 in module_sha1_map.items(): + deps[mod_name] = dep_sha1 + with open(deps_path, 'w', encoding='utf-8') as f: + json.dump(deps, f) + + def _load_deps(self, sha1: str) -> dict: + """加载依赖指纹""" + deps_path = os.path.join(self.output_dir, f"{sha1}.deps.json") + if os.path.isfile(deps_path): + try: + with open(deps_path, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception: + pass + return None + + def _check_deps_changed(self, sha1: str, current_module_sha1_map: dict) -> bool: + """检查依赖指纹是否变化""" + saved_deps = self._load_deps(sha1) + if saved_deps is None: + return True + for mod_name, dep_sha1 in current_module_sha1_map.items(): + if saved_deps.get(mod_name) != dep_sha1: + return True + for mod_name, dep_sha1 in saved_deps.items(): + if current_module_sha1_map.get(mod_name) != dep_sha1: + return True + return False + + def _recombine_ll(self, sha1: str, current_module_sha1_map: dict) -> bool: + """依赖变化时重新组合 .ll:更新 .stub.ll 中的 SHA1 前缀,拼接 .stub.ll + .text.ll""" + saved_deps = self._load_deps(sha1) + if saved_deps is None: + return False + + stub_path = os.path.join(self.output_dir, f"{sha1}.stub.ll") + text_path = os.path.join(self.output_dir, f"{sha1}.text.ll") + ll_path = os.path.join(self.output_dir, f"{sha1}.ll") + + if not os.path.isfile(stub_path) or not os.path.isfile(text_path): + return False + + with open(stub_path, 'r', encoding='utf-8') as f: + stub_content = f.read() + with open(text_path, 'r', encoding='utf-8') as f: + text_content = f.read() + + sha1_replacements = {} + for mod_name, old_sha1 in saved_deps.items(): + new_sha1 = current_module_sha1_map.get(mod_name) + if new_sha1 and old_sha1 != new_sha1: + sha1_replacements[old_sha1] = new_sha1 + + if sha1_replacements: + for old_sha1, new_sha1 in sha1_replacements.items(): + stub_content = stub_content.replace(old_sha1, new_sha1) + text_content = text_content.replace(old_sha1, new_sha1) + + combined = stub_content + if not combined.endswith('\n'): + combined += '\n' + combined += text_content + + with open(ll_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(combined) + with open(stub_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(stub_content) + with open(text_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(text_content) + + self._save_deps(sha1, current_module_sha1_map) + + obj_path = os.path.join(self.output_dir, f"{sha1}.obj") + if os.path.isfile(obj_path): + os.remove(obj_path) + + return True + + def _translate_file(self, src_path: str, out_path: str, prebuilt_module_sha1_map: dict = None): + """翻译单个源文件,嵌入相关 .stub.ll 声明""" + with open(src_path, 'r', encoding='utf-8') as f: + code = f.read() + + sha1 = compute_sha1(code) + + if prebuilt_module_sha1_map is not None: + module_sha1_map = prebuilt_module_sha1_map + else: + module_sha1_map = self._build_current_module_sha1_map(sha1) + + trans = TransPyC.TransPyC(code=code, triple=self.triple, datalayout=self.datalayout) + trans.translator.CurrentFile = src_path + trans.SliceLevel = self.slice_level + trans.translator.SliceLevel = self.slice_level + trans.translator.SliceCount = 0 + trans.translator.SliceInfos = [] + trans.translator.LlvmGen = None + trans.translator._module_sha1 = sha1 + trans.translator._module_sha1_map = module_sha1_map + trans.translator._struct_sha1_map = self.struct_sha1_map + trans.translator._global_function_default_args = self.function_default_args + trans.translator._temp_dir = self.temp_dir + + if hasattr(self, '_shared_symbol_table') and self._shared_symbol_table is not None: + trans.translator.SymbolTable = self._shared_symbol_table + # 确保共享符号表的 translator 指向当前 translator,以便 import 别名解析正确 + if hasattr(self._shared_symbol_table, 'translator'): + self._shared_symbol_table.translator = trans.translator + trans.translator._source_module_sig_files = self._shared_source_module_sig_files + trans.translator._all_define_constants = self._shared_all_dc + trans.translator._export_extern_funcs = self._shared_export_extern_funcs + if hasattr(self, '_shared_generic_class_templates') and self._shared_generic_class_templates: + if not hasattr(trans.translator.ClassHandler, '_generic_class_templates'): + trans.translator.ClassHandler._generic_class_templates = {} + trans.translator.ClassHandler._generic_class_templates.update(self._shared_generic_class_templates) + else: + export_extern_funcs = set() + for sha1_key, sig_path in self.sig_files.items(): + if sha1_key == sha1: + continue + try: + with open(sig_path, 'r', encoding='utf-8') as f: + sig_content = f.read() + sig_tree = ast.parse(sig_content) + for node in ast.iter_child_nodes(sig_tree): + if isinstance(node, ast.FunctionDef): + if _check_annotation_for_export(node.returns): + export_extern_funcs.add(node.name) + except Exception: + pass + if export_extern_funcs: + trans.translator._export_extern_funcs = export_extern_funcs + + for includes_dir in self.include_dirs: + if os.path.isdir(includes_dir): + for pyi_file in os.listdir(includes_dir): + if pyi_file.endswith('.pyi'): + pyi_path = os.path.join(includes_dir, pyi_file) + module_name = os.path.splitext(pyi_file)[0] + trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0) + for py_file in os.listdir(includes_dir): + if py_file.endswith('.py') and not py_file.startswith('_'): + module_name = os.path.splitext(py_file)[0] + sha1_key = self.include_py_map.get(module_name) + if sha1_key and sha1_key in self.sig_files: + sig_path = self.sig_files[sha1_key] + trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) + for sha1_key, sig_path in self.sig_files.items(): + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + mod_name = mod_name[len('includes/'):] + trans.translator.SymbolTable.LoadModuleSymbols(sig_path, mod_name, lineno=0) + if mod_name.endswith('.__init__'): + package_name = mod_name[:-len('.__init__')] + self._register_package_reexports(trans, sig_path, package_name) + + for sha1_key, sig_path in self.sig_files.items(): + if sha1_key == sha1: + continue + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + continue + module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) + trans.translator._source_module_sig_files[module_name] = sig_path + short_name = module_name.split('.')[-1] if '.' in module_name else module_name + if short_name != module_name: + trans.translator._source_module_sig_files[short_name] = sig_path + + all_dc = {} + for sha1_key, stub_path in self.stub_files.items(): + if sha1_key == sha1: + continue + if os.path.exists(stub_path): + try: + with open(stub_path, 'r', encoding='utf-8') as f: + stub_content = f.read() + for line in stub_content.splitlines(): + line = line.strip() + if line.startswith('@') and '= global' in line and 'i32' in line and not line.startswith('@llvm'): + var_name = line.split('=')[0].strip().lstrip('@') + val_part = line.split('i32')[-1].strip().rstrip(']').lstrip('[').lstrip('i32') + try: + val = int(val_part) + all_dc[var_name] = val + except: + pass + except: + pass + for sha1_key, pyi_path in self.sig_files.items(): + if sha1_key == sha1: + continue + if os.path.exists(pyi_path): + try: + import ast as _ast + with open(pyi_path, 'r', encoding='utf-8') as f: + pyi_content = f.read() + tree = _ast.parse(pyi_content) + for node in _ast.iter_child_nodes(tree): + if isinstance(node, _ast.AnnAssign) and isinstance(node.target, _ast.Name): + ann_str = _ast.dump(node.annotation) + if 'CDefine' in ann_str and node.value: + val = None + if isinstance(node.value, _ast.Constant): + val = node.value.value + elif isinstance(node.value, _ast.Call) and isinstance(node.value.func, _ast.Name) and node.value.func.id == 'float' and node.value.args and isinstance(node.value.args[0], _ast.Constant): + val = node.value.args[0].value + if val is not None: + all_dc[f"{node.target.id}"] = val + except: + pass + if all_dc: + trans.translator._all_define_constants = all_dc + + for sym_name, sym_info in self.inline_func_symbols.items(): + if sym_name not in trans.translator.SymbolTable: + trans.translator.SymbolTable[sym_name] = sym_info + else: + existing = trans.translator.SymbolTable[sym_name] + if not getattr(existing, 'InlineBody', None) and getattr(sym_info, 'InlineBody', None): + existing.IsInline = sym_info.IsInline + existing.InlineBody = sym_info.InlineBody + existing.InlineParams = sym_info.InlineParams + + try: + result = trans.Convert( + OutputFilename=out_path, + SourceFilename=src_path, + target='llvm' + ) + except Exception as e: + error_stack = getattr(trans.translator, '_error_stack', []) + if error_stack: + self._last_error_stack = error_stack + chain_lines = [] + for entry in reversed(error_stack): + if len(entry) >= 3: + exc_msg, line_info = entry[1], entry[2] + chain_lines.append(" %s\n %s" % (line_info, exc_msg)) + if chain_lines: + enriched = str(e) + "\n" + "\n".join(chain_lines) + raise type(e)(enriched) from e + node_info = "" + if hasattr(trans.translator, 'LlvmGen') and trans.translator.LlvmGen: + node_info = trans.translator.LlvmGen._get_node_info() + if node_info: + enriched = "%s\n %s" % (str(e), node_info.strip()) + raise type(e)(enriched) from e + raise + + if result and isinstance(result, str): + for func_name, func_def in trans.translator.FunctionDefCache.items(): + if hasattr(func_def, 'args') and hasattr(func_def.args, 'defaults') and func_def.args.defaults: + mangled = trans.translator.LlvmGen._mangle_func_name(func_name) if trans.translator.LlvmGen else func_name + defaults = [] + for d in func_def.args.defaults: + if isinstance(d, ast.Constant): + defaults.append(d.value) + else: + defaults.append(None) + self.function_default_args[mangled] = defaults + self.function_default_args[func_name] = defaults + for sym_name, sym_info in trans.translator.SymbolTable.items(): + if isinstance(sym_info, CTypeInfo) and getattr(sym_info, 'IsInline', False) and getattr(sym_info, 'InlineBody', None): + self.inline_func_symbols[sym_name] = sym_info + # stub声明现在通过_dso.ll编译时拼接依赖模块stub.ll提供 + # stub_decls = self._collect_stub_decls_for_module(sha1) + # if stub_decls: + # result = self._inject_stub_decls(result, stub_decls) + + out_dir = os.path.dirname(out_path) + if out_dir: + os.makedirs(out_dir, exist_ok=True) + with open(out_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(result) + + stub_content, text_content = self._split_ll(result) + base = os.path.splitext(out_path)[0] + with open(base + '.stub.ll', 'w', encoding='utf-8', newline='\n') as f: + f.write(stub_content) + with open(base + '.text.ll', 'w', encoding='utf-8', newline='\n') as f: + f.write(text_content) + self._save_deps(sha1, module_sha1_map) + + print(f" -> {os.path.basename(out_path)}") + else: + stub_path = self.stub_files.get(sha1) + if stub_path and os.path.exists(stub_path): + out_dir = os.path.dirname(out_path) + if out_dir: + os.makedirs(out_dir, exist_ok=True) + with open(stub_path, 'r', encoding='utf-8') as f: + stub_content = f.read() + with open(out_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(stub_content) + print(f" -> {os.path.basename(out_path)} (仅声明)") + + def _register_package_reexports(self, trans, init_pyi_path, package_name): + """解析 __init__.pyi 中的 from .xxx import yyy 或 from __xxx import yyy,在包级别注册导出符号""" + try: + with open(init_pyi_path, 'r', encoding='utf-8') as f: + content = f.read() + tree = ast.parse(content) + for node in ast.walk(tree): + if isinstance(node, ast.ImportFrom) and node.module: + sub_module = node.module.lstrip('.') + for alias in node.names: + symbol_name = alias.name + exported_name = alias.asname if alias.asname else symbol_name + source_keys = [ + f"{package_name}.{sub_module}.{symbol_name}", + f"{package_name}.__{sub_module}.{symbol_name}" if not sub_module.startswith('__') else None, + symbol_name, + ] + target_key = f"{package_name}.{exported_name}" + if target_key not in trans.translator.SymbolTable: + for source_key in source_keys: + if source_key and source_key in trans.translator.SymbolTable: + trans.translator.SymbolTable[target_key] = trans.translator.SymbolTable[source_key] + break + if exported_name not in trans.translator.SymbolTable: + for source_key in source_keys: + if source_key and source_key in trans.translator.SymbolTable: + trans.translator.SymbolTable[exported_name] = trans.translator.SymbolTable[source_key] + break + except Exception as e: + print(f" [警告] 解析包重导出失败 {init_pyi_path}: {e}") + + def _collect_stub_decls(self, self_sha1: str) -> str: + """收集 includes 目录中模块的 .stub.ll 声明内容,去重""" + seen_symbols = set() + decl_lines = [] + for sha1_key, stub_path in self.stub_files.items(): + if sha1_key == self_sha1: + continue + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if not rel_path.startswith('includes/'): + continue + if os.path.exists(stub_path): + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + for line in content.splitlines(): + stripped = line.strip() + if not stripped: + continue + if stripped.startswith(';'): + continue + if stripped.startswith('target '): + continue + if stripped.startswith('source_filename'): + continue + if stripped.startswith('@') and '=' in stripped: + name = stripped.split('=', 1)[0].strip() + if name in seen_symbols: + continue + seen_symbols.add(name) + elif stripped.startswith('%') and '= type' in stripped: + name = stripped.split('=', 1)[0].strip() + if name in seen_symbols: + continue + seen_symbols.add(name) + elif stripped.startswith('declare'): + parts = stripped.split('@', 1) + if len(parts) > 1: + name = '@' + parts[1].split('(', 1)[0].strip() + if name in seen_symbols: + continue + seen_symbols.add(name) + decl_lines.append(line) + if decl_lines: + result = '\n'.join(decl_lines) + self._stub_decls_cache[self_sha1] = result + return result + self._stub_decls_cache[self_sha1] = '' + return '' + + def _collect_stub_decls_for_module(self, self_sha1: str) -> str: + """收集特定模块需要的 .stub.ll 声明(包括结构体类型定义、函数声明和 typedef)""" + if self_sha1 in self._stub_decls_cache: + return self._stub_decls_cache[self_sha1] + import re + seen_symbols = set() + seen_func_symbols = set() + decl_lines = [] + + non_struct_types = {'UINT', 'INT', 'BYTE', 'BYTEPTR', 'WORD', 'DWORD', 'QWORD', + 'INT8', 'INT16', 'INT32', 'INT64', 'UINT8', 'UINT16', 'UINT32', 'UINT64', + 'INTPTR', 'UINTPTR', 'SIZE_T', 'SSIZE_T', 'PTRDIFF_T', + 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', + 'atomic_int', 'atomic_uint', 'atomic_long', 'atomic_ulong', + 'atomic_int8', 'atomic_uint8', 'atomic_int16', 'atomic_uint16', + 'atomic_int32', 'atomic_uint32', 'atomic_int64', 'atomic_uint64', + 'atomic_ptr', 'atomic_flag', 'typedef', + 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array'} + + struct_names = set() + struct_source_sha1 = {} + + def _extract_struct_name(type_def_str): + m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=\s*type', type_def_str) + if m: + raw = m.group(1) + if '.' in raw: + return raw.split('.', 1)[1], raw.split('.', 1)[0] + return raw, None + return None, None + + def _replace_struct_refs(type_str): + def replace_struct_name(name): + if name in struct_names: + name_sha1 = struct_source_sha1.get(name, '') + return f'%"{name_sha1}.{name}"' if name_sha1 else None + return None + def replace_struct_match(match): + name = match.group(1) + replaced = replace_struct_name(name) + return replaced if replaced else match.group(0) + def replace_sha1_struct_match(match): + name = match.group(2) + replaced = replace_struct_name(name) + return replaced if replaced else match.group(0) + result = re.sub(r'%struct\.(\w+)', replace_struct_match, type_str) + result = re.sub(r'%"?([a-f0-9]+)\.(\w+)"?', replace_sha1_struct_match, result) + return result + + for sha1_key, stub_path in self.stub_files.items(): + if os.path.exists(stub_path): + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + for line in content.splitlines(): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + clean_name, sha1_part = _extract_struct_name(stripped) + if clean_name and clean_name not in non_struct_types: + struct_names.add(clean_name) + if clean_name not in struct_source_sha1: + struct_source_sha1[clean_name] = sha1_part or sha1_key + + for sha1_key, stub_path in self.stub_files.items(): + if sha1_key == self_sha1: + continue + if os.path.exists(stub_path): + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + for line in content.splitlines(): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + clean_name, sha1_part = _extract_struct_name(stripped) + if not clean_name or clean_name in non_struct_types: + continue + if clean_name in seen_symbols: + continue + parts = stripped.split('= type', 1) + struct_type_body = parts[1].strip() if len(parts) > 1 else '' + if 'opaque' in struct_type_body: + seen_symbols.add(clean_name) + name_sha1 = struct_source_sha1.get(clean_name, sha1_key) + decl_lines.append(f'%"{name_sha1}.{clean_name}" = type opaque') + continue + if clean_name in struct_names: + struct_type_body = _replace_struct_refs(struct_type_body) + name_sha1 = struct_source_sha1.get(clean_name, sha1_key) + new_def = f'%"{name_sha1}.{clean_name}" = type {struct_type_body}' + seen_symbols.add(clean_name) + decl_lines.append(new_def) + if decl_lines: + return '\n'.join(decl_lines) + return '' + + def _inject_stub_decls(self, ll_content: str, stub_decls: str) -> str: + """将 stub 声明注入到 LLVM IR 模块头之后,替换 opaque 类型为具体定义""" + def normalize_type_name(name): + name = name.strip() + if name.startswith('%'): + return '%' + name[1:].strip().strip('"') + return name + + existing_symbols = {} # normalized_name -> (line_index, full_line) + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith('@') and '=' in stripped: + name = stripped.split('=', 1)[0].strip() + existing_symbols[name] = (i, line) + elif stripped.startswith('%') and '= type' in stripped: + name = normalize_type_name(stripped.split('=', 1)[0].strip()) + existing_symbols[name] = (i, line) + elif stripped.startswith('declare') or stripped.startswith('define'): + parts = stripped.split('@', 1) + if len(parts) > 1: + name = '@' + parts[1].split('(', 1)[0].strip() + existing_symbols[name] = (i, line) + + lines = ll_content.splitlines() + replacements = {} # line_index -> new_line + new_decls = [] # 新类型定义(不在现有输出中的) + + def normalize_type_name(name): + name = name.strip() + if name.startswith('%'): + return '%' + name[1:].strip().strip('"') + return name + + for line in stub_decls.splitlines(): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + name = normalize_type_name(stripped.split('=', 1)[0].strip()) + if name in existing_symbols: + idx, existing_line = existing_symbols[name] + existing_type_body = existing_line.strip().split('= type', 1)[1].strip() if '= type' in existing_line else '' + stub_type_body = stripped.split('= type', 1)[1].strip() if '= type' in stripped else '' + if 'opaque' in existing_line and 'opaque' not in stripped: + replacements[idx] = line + else: + new_decls.append(line) + + # 应用替换 + for idx, new_line in replacements.items(): + lines[idx] = new_line + + # 追加新类型定义到末尾(去重处理) + if new_decls: + # 过滤掉已经在 Translator 输出中存在的类型定义 + existing_types = set() + for line in lines: + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + type_name = normalize_type_name(stripped.split('=', 1)[0].strip()) + existing_types.add(type_name) + filtered_decls = [] + for line in new_decls: + stripped = line.strip() + if '= type' in stripped: + type_name = normalize_type_name(stripped.split('=', 1)[0].strip()) + if type_name not in existing_types: + filtered_decls.append(line) + existing_types.add(type_name) + if filtered_decls: + lines.append('') + lines.extend(filtered_decls) + + # 确保所有类型定义在全局变量之前,LLVM 要求在常量初始化器中使用类型之前必须先定义 + type_def_indices = [] + first_global_idx = None + for i, line in enumerate(lines): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + if first_global_idx is not None: + type_def_indices.append(i) + elif stripped.startswith('@') and ' global' in stripped: + if first_global_idx is None: + first_global_idx = i + + if type_def_indices and first_global_idx is not None: + type_defs = [lines[i] for i in reversed(type_def_indices)] + for i in reversed(type_def_indices): + del lines[i] + insert_pos = first_global_idx + if type_def_indices[0] < first_global_idx: + insert_pos = first_global_idx - len(type_def_indices) + for j, td in enumerate(type_defs): + lines.insert(insert_pos, td) + + result = '\n'.join(lines) + + return result + + def _compile_ll_files(self, active_sha1s: set): + """将 output_dir 中属于 active_sha1s 的 .ll 文件编译为 .obj(跳过已编译过的 include 文件)""" + stale_files = [] + for root, dirs, files in os.walk(self.output_dir): + for file in files: + fpath = os.path.join(root, file) + for ext in ('.ll', '.obj', '.stub.ll', '.text.ll', '.deps.json', '_dso.ll'): + if file.endswith(ext): + sha1 = file[:-(len(ext))] + if sha1 not in active_sha1s: + stale_files.append(fpath) + break + if stale_files: + for fpath in stale_files: + try: + os.remove(fpath) + except: + pass + print(f"[清理] 删除 {len(stale_files)} 个过时文件") + ll_files = [] + for root, dirs, files in os.walk(self.output_dir): + for file in files: + if file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): + sha1 = file[:-3] + if sha1 in active_sha1s: + obj_path = os.path.join(root, file[:-3] + '.obj') + if not os.path.isfile(obj_path): + ll_files.append(os.path.join(root, file)) + + if not ll_files: + print("[编译] 无 .ll 文件需要重新编译") + else: + print(f"\n[编译] 找到 {len(ll_files)} 个 .ll 文件需要编译") + + has_inline = False + all_ll_files = [] + for root, dirs, files in os.walk(self.output_dir): + for file in files: + if file.endswith('.ll') and not file.endswith('.stub.ll') and not file.endswith('.text.ll'): + sha1 = file[:-3] + if sha1 in active_sha1s and sha1 not in self._include_sha1s: + all_ll_files.append(os.path.join(root, file)) + for ll_path in all_ll_files: + try: + with open(ll_path, 'r', encoding='utf-8') as f: + content = f.read() + if 'alwaysinline' in content: + has_inline = True + break + except: + pass + + if has_inline: + llvm_link = shutil.which('llvm-link') or shutil.which('llvm-link.exe') + opt_cmd = shutil.which('opt') or shutil.which('opt.exe') + if llvm_link and opt_cmd: + print(" [内联] 检测到 alwaysinline 函数,执行跨模块内联优化...") + for ll_path in all_ll_files: + try: + with open(ll_path, 'r', encoding='utf-8') as f: + content = f.read() + type_defs = [] + type_def_indices = set() + for i, line in enumerate(content.splitlines()): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + type_defs.append(line) + type_def_indices.add(i) + if type_def_indices: + lines = content.splitlines(True) + content_no_types = ''.join(line for i, line in enumerate(lines) if i not in type_def_indices) + header_end = 0 + for i, line in enumerate(content_no_types.splitlines()): + stripped = line.strip() + if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: + header_end = i + 1 + continue + break + lines2 = content_no_types.splitlines(True) + fixed = ''.join(lines2[:header_end]) + '\n'.join(type_defs) + '\n' + ''.join(lines2[header_end:]) + with open(ll_path, 'w', encoding='utf-8') as f: + f.write(fixed) + except: + pass + merged_ll = os.path.join(self.output_dir, '_merged.ll') + optimized_ll = os.path.join(self.output_dir, '_merged_opt.ll') + try: + link_cmd = [llvm_link] + all_ll_files + ['-o', merged_ll] + result = subprocess.run(link_cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f" [警告] llvm-link 失败: {result.stderr.strip()},回退到单独编译") + has_inline = False + else: + opt_result_cmd = [opt_cmd, '-passes=always-inline', merged_ll, '-S', '-o', optimized_ll] + result = subprocess.run(opt_result_cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f" [警告] opt 失败: {result.stderr.strip()},回退到单独编译") + has_inline = False + else: + print(" [内联] 跨模块内联优化完成") + with open(optimized_ll, 'r', encoding='utf-8') as f: + opt_content = f.read() + import re + opt_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', opt_content) + opt_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', opt_content) + opt_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', opt_content) + opt_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = linkonce_odr \2', opt_content) + with open(optimized_ll, 'w', encoding='utf-8') as f: + f.write(opt_content) + merged_obj = os.path.join(self.output_dir, '_merged.obj') + try: + cmd = [self.compile_cmd] + self.compile_flags + ['-o', merged_obj, optimized_ll] + result = subprocess.run(cmd, capture_output=True, text=True, + cwd=self.output_dir) + if result.returncode == 0: + print(f" [成功] 合并模块编译完成") + for ll_path in ll_files: + obj_path = ll_path[:-3] + '.obj' + sha1_obj = os.path.join(self.output_dir, os.path.basename(ll_path)[:-3] + '.obj') + if os.path.isfile(sha1_obj): + os.remove(sha1_obj) + return + else: + print(f" [警告] 合并模块编译失败: {result.stderr.strip()},回退到单独编译") + has_inline = False + except Exception as e: + print(f" [警告] 合并模块编译异常: {e},回退到单独编译") + has_inline = False + except FileNotFoundError: + print(f" [警告] 找不到 llvm-link 或 opt,回退到单独编译") + has_inline = False + else: + print(" [警告] 未找到 llvm-link/opt 工具,回退到单独编译(alwaysinline 可能不生效)") + + from concurrent.futures import ThreadPoolExecutor, as_completed + import re + + def _compile_one(ll_path): + rel = os.path.relpath(ll_path, self.output_dir) + obj_path = ll_path[:-3] + '.obj' + if os.path.isfile(obj_path): + return (rel, 'cached', '') + try: + with open(ll_path, 'r', encoding='utf-8') as f: + ll_content = f.read() + sha1 = os.path.basename(ll_path)[:-3] + deps = self._load_deps(sha1) + stub_prefix = '' + if deps: + existing_symbols = {} + opaque_line_indices = {} + existing_declares = set() + existing_declare_lines = {} + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=', stripped) + if m: + name = m.group(1) + if '= type opaque' in stripped: + existing_symbols[name] = 'opaque' + opaque_line_indices[name] = i + else: + existing_symbols[name] = 'full' + elif stripped.startswith('declare'): + dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm: + fname = dm.group(1) + existing_declares.add(fname) + existing_declare_lines[fname] = i + seen_stub_sha1 = set() + replaced_opaque_names = set() + replaced_declare_names = set() + all_stub_lines = [] + stub_type_map = {} + stub_declare_names = set() + stub_declare_lines = {} + existing_defines = set() + existing_global_defs = set() + stub_global_defs = set() + for line in ll_content.splitlines(): + stripped = line.strip() + if stripped.startswith('define'): + dm = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm: + existing_defines.add(dm.group(1)) + elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): + gm = re.match(r'(@\S+)', stripped) + if gm: + existing_global_defs.add(gm.group(1)) + for dep_name, dep_sha1 in deps.items(): + if dep_sha1 in seen_stub_sha1: + continue + seen_stub_sha1.add(dep_sha1) + stub_path = os.path.join(self.output_dir, f"{dep_sha1}.stub.ll") + if not os.path.isfile(stub_path): + stub_path = os.path.join(self.temp_dir, f"{dep_sha1}.stub.ll") + if os.path.isfile(stub_path): + with open(stub_path, 'r', encoding='utf-8') as sf: + stub_content = sf.read() + for line in stub_content.splitlines(): + stripped = line.strip() + if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: + continue + if stripped.startswith('declare'): + dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped) + if dm: + fname = dm.group(1) + if re.search(r'%("[^"]+"|[a-f0-9]+\.[A-Za-z_]\w*)\s+%', stripped): + continue + if fname in existing_defines: + continue + if fname in existing_declares or fname in stub_declare_names: + existing_decl_line = stub_declare_lines.get(fname) + if existing_decl_line is not None: + has_struct = '%' in stripped + existing_has_struct = '%' in existing_decl_line if existing_decl_line else False + if has_struct and not existing_has_struct: + for i, l in enumerate(all_stub_lines): + if l is not None and l.strip().startswith('declare'): + em = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', l.strip()) + if em and em.group(1) == fname: + all_stub_lines[i] = line + break + continue + elif fname in existing_declares: + has_struct = '%' in stripped + if has_struct: + replaced_declare_names.add(fname) + stub_declare_names.add(fname) + stub_declare_lines[fname] = line + all_stub_lines.append(line) + continue + continue + stub_declare_names.add(fname) + stub_declare_lines[fname] = line + all_stub_lines.append(line) + continue + if stripped.startswith('%') and '= type' in stripped: + m = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=', stripped) + if m: + name = m.group(1) + is_opaque = '= type opaque' in stripped + if name in existing_symbols: + if existing_symbols[name] == 'opaque' and not is_opaque: + replaced_opaque_names.add(name) + existing_symbols[name] = 'full' + idx = len(all_stub_lines) + all_stub_lines.append(line) + stub_type_map[name] = (is_opaque, idx) + continue + if name in stub_type_map: + prev_opaque, prev_idx = stub_type_map[name] + if prev_opaque and not is_opaque: + all_stub_lines[prev_idx] = None + idx = len(all_stub_lines) + all_stub_lines.append(line) + stub_type_map[name] = (is_opaque, idx) + continue + idx = len(all_stub_lines) + all_stub_lines.append(line) + stub_type_map[name] = (is_opaque, idx) + else: + all_stub_lines.append(line) + elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped): + gm = re.match(r'(@\S+)', stripped) + if gm and (gm.group(1) in existing_global_defs or gm.group(1) in stub_global_defs): + continue + if gm: + stub_global_defs.add(gm.group(1)) + all_stub_lines.append(line) + else: + all_stub_lines.append(line) + filtered = [l for l in all_stub_lines if l is not None] + if filtered: + stub_prefix = '\n'.join(filtered) + '\n' + lines_to_remove = set() + if replaced_opaque_names: + for name in replaced_opaque_names: + if name in opaque_line_indices: + lines_to_remove.add(opaque_line_indices[name]) + if replaced_declare_names: + for fname in replaced_declare_names: + if fname in existing_declare_lines: + lines_to_remove.add(existing_declare_lines[fname]) + if lines_to_remove: + ll_lines = ll_content.splitlines(True) + ll_content = ''.join(line for i, line in enumerate(ll_lines) if i not in lines_to_remove) + type_defs_in_ll = [] + type_def_line_indices = set() + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + type_defs_in_ll.append(line) + type_def_line_indices.add(i) + if type_def_line_indices: + ll_lines = ll_content.splitlines(True) + ll_content = ''.join(line for i, line in enumerate(ll_lines) if i not in type_def_line_indices) + if type_defs_in_ll: + stub_prefix += '\n'.join(type_defs_in_ll) + '\n' + if stub_prefix: + header_end = 0 + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: + header_end = i + 1 + continue + break + ll_lines = ll_content.splitlines(True) + ll_content = ''.join(ll_lines[:header_end]) + stub_prefix + ''.join(ll_lines[header_end:]) + ll_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content) + ll_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', ll_content) + ll_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content) + ll_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content) + final_type_defs = [] + final_type_def_indices = set() + for i, line in enumerate(ll_content.splitlines()): + stripped = line.strip() + if stripped.startswith('%') and '= type' in stripped: + final_type_defs.append(line) + final_type_def_indices.add(i) + if final_type_def_indices: + final_lines = ll_content.splitlines(True) + ll_content_no_types = ''.join(line for i, line in enumerate(final_lines) if i not in final_type_def_indices) + header_end = 0 + for i, line in enumerate(ll_content_no_types.splitlines()): + stripped = line.strip() + if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped: + header_end = i + 1 + continue + break + final_lines2 = ll_content_no_types.splitlines(True) + ll_content = ''.join(final_lines2[:header_end]) + '\n'.join(final_type_defs) + '\n' + ''.join(final_lines2[header_end:]) + dso_ll_path = ll_path[:-3] + '_dso.ll' + with open(dso_ll_path, 'w', encoding='utf-8') as f: + f.write(ll_content) + cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path] + result = subprocess.run(cmd, capture_output=True, text=True, + cwd=os.path.dirname(ll_path) or '.') + if result.returncode == 0: + return (rel, 'ok', '') + else: + return (rel, 'error', result.stderr.strip()) + except FileNotFoundError: + return (rel, 'error', f'找不到编译器: {self.compile_cmd}') + except Exception as e: + return (rel, 'error', str(e)) + + need_compile = [] + for ll_path in ll_files: + obj_path = ll_path[:-3] + '.obj' + if not os.path.isfile(obj_path): + need_compile.append(ll_path) + + if need_compile: + n_workers = min(os.cpu_count() or 4, len(need_compile), 8) + print(f" 并行编译 {len(need_compile)} 个文件 (workers={n_workers})") + errors = [] + with ThreadPoolExecutor(max_workers=n_workers) as executor: + futures = {executor.submit(_compile_one, ll_path): ll_path for ll_path in need_compile} + for future in as_completed(futures): + rel, status, err = future.result() + if status == 'ok': + print(f" [成功] {rel}") + elif status == 'error': + print(f" [错误] {rel}: {err}") + errors.append((rel, err)) + elif status == 'cached': + pass + if errors: + print(f"\n[编译终止] {len(errors)} 个文件编译失败") + sys.exit(1) + + def _scan_include_libraries(self): + """扫描 includes 目录,检测被使用的模块对应的库文件和源文件""" + if not self.used_includes: + return + + for includes_dir in self.include_dirs: + if not os.path.isdir(includes_dir): + continue + + for module_name in self.used_includes: + module_dir = os.path.join(includes_dir, module_name) + if os.path.isdir(module_dir): + self._scan_dir_for_libs(module_dir, module_name) + for root, dirs, files in os.walk(module_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith('.py'): + py_path = os.path.join(root, fname) + if py_path not in self.extra_py_files: + self.extra_py_files.append(py_path) + print(f" [includes] 发现 Python 包文件: {os.path.relpath(py_path, includes_dir)}") + + for ext in self.INCLUDE_LIB_EXTENSIONS: + lib_path = os.path.join(includes_dir, module_name + ext) + if os.path.isfile(lib_path): + self.extra_link_files.append(lib_path) + print(f" [includes] 发现库文件: {os.path.relpath(lib_path, includes_dir)}") + + for ext in self.INCLUDE_SRC_EXTENSIONS: + src_path = os.path.join(includes_dir, module_name + ext) + if os.path.isfile(src_path): + self.extra_compile_files.append(src_path) + print(f" [includes] 发现源文件: {os.path.relpath(src_path, includes_dir)}") + + py_path = os.path.join(includes_dir, module_name + '.py') + if os.path.isfile(py_path): + self.extra_py_files.append(py_path) + print(f" [includes] 发现 Python 源文件: {os.path.relpath(py_path, includes_dir)}") + + discovered = set() + for ef in list(self.extra_py_files): + self._discover_transitive_deps(ef, includes_dir, discovered) + + if self.extra_link_files: + print(f"\n[includes] 需要链接的库文件: {len(self.extra_link_files)} 个") + if self.extra_compile_files: + print(f"[includes] 需要编译的源文件: {len(self.extra_compile_files)} 个") + + def _scan_dir_for_libs(self, directory: str, module_name: str): + """递归扫描目录中的库文件和源文件""" + for root, dirs, files in os.walk(directory): + for fname in files: + fpath = os.path.join(root, fname) + _, ext = os.path.splitext(fname) + ext = ext.lower() + if ext in self.INCLUDE_LIB_EXTENSIONS: + self.extra_link_files.append(fpath) + print(f" [includes] 发现库文件: {os.path.relpath(fpath, directory)}") + elif ext in self.INCLUDE_SRC_EXTENSIONS: + self.extra_compile_files.append(fpath) + print(f" [includes] 发现源文件: {os.path.relpath(fpath, directory)}") + + def _discover_transitive_deps(self, py_path: str, includes_dir: str, discovered: set): + """递归发现 Python 文件的间接依赖""" + if py_path in discovered: + return + discovered.add(py_path) + try: + with open(py_path, 'r', encoding='utf-8') as f: + content = f.read() + import ast as _ast + tree = _ast.parse(content) + for node in _ast.walk(tree): + if isinstance(node, _ast.Import): + for alias in node.names: + mod = alias.name.split('.')[0] + self._try_add_include_dep(mod, includes_dir, discovered) + elif isinstance(node, _ast.ImportFrom): + if node.module and node.level == 0: + mod = node.module.split('.')[0] + self._try_add_include_dep(mod, includes_dir, discovered) + except Exception: + pass + + def _try_add_include_dep(self, module_name: str, includes_dir: str, discovered: set): + """尝试将模块添加为 include 依赖""" + py_path = os.path.join(includes_dir, module_name + '.py') + if os.path.isfile(py_path) and py_path not in self.extra_py_files: + self.extra_py_files.append(py_path) + print(f" [includes] 发现间接依赖: {os.path.relpath(py_path, includes_dir)}") + self._discover_transitive_deps(py_path, includes_dir, discovered) + + def _is_decl_only_file(self, src_path: str) -> bool: + try: + with open(src_path, 'r', encoding='utf-8') as f: + content = f.read() + import ast as _ast + tree = _ast.parse(content) + for node in _ast.walk(tree): + if isinstance(node, _ast.ClassDef): + return False + if isinstance(node, _ast.FunctionDef): + body = node.body + if len(body) == 1: + stmt = body[0] + if isinstance(stmt, _ast.Expr) and isinstance(stmt.value, _ast.Constant) and stmt.value.value is ...: + continue + if isinstance(stmt, _ast.Pass): + continue + return False + return True + except Exception: + return False + + def _sort_include_files_by_deps(self, file_list: list) -> list: + """按依赖关系对 include 文件进行拓扑排序,确保被依赖的文件先编译""" + import ast as _ast + + # 构建文件名到路径的映射 + name_to_path = {} + for fpath in file_list: + basename = os.path.splitext(os.path.basename(fpath))[0] + name_to_path[basename] = fpath + + # 也支持包内模块: vpsdk/window -> path + for fpath in file_list: + # 尝试从 includes 目录推断模块全名 + for includes_dir in self.include_dirs: + try: + rel = os.path.relpath(fpath, includes_dir) + mod_name = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + name_to_path[mod_name] = fpath + except ValueError: + pass + + # 分析每个文件的 import 依赖 + deps = {} # path -> set of paths it depends on + for fpath in file_list: + deps[fpath] = set() + try: + with open(fpath, 'r', encoding='utf-8') as f: + content = f.read() + tree = _ast.parse(content) + for node in _ast.iter_child_nodes(tree): + if isinstance(node, _ast.Import): + for alias in node.names: + mod = alias.name.split('.')[0] + if mod in name_to_path and name_to_path[mod] != fpath: + deps[fpath].add(name_to_path[mod]) + elif isinstance(node, _ast.ImportFrom): + if node.module and node.level == 0: + mod = node.module.split('.')[0] + if mod in name_to_path and name_to_path[mod] != fpath: + deps[fpath].add(name_to_path[mod]) + except Exception: + pass + + # 拓扑排序 (Kahn's algorithm) + in_degree = {fpath: len(deps[fpath]) for fpath in file_list} + # 反向邻接表:如果 A 依赖 B,则 B -> A + reverse_adj = {fpath: [] for fpath in file_list} + for fpath in file_list: + for dep in deps[fpath]: + if dep in reverse_adj: + reverse_adj[dep].append(fpath) + + result = [] + queue = [fpath for fpath in file_list if in_degree[fpath] == 0] + # 对队列排序以保持确定性 + queue.sort(key=lambda x: x) + + while queue: + current = queue.pop(0) + result.append(current) + for neighbor in reverse_adj[current]: + in_degree[neighbor] -= 1 + if in_degree[neighbor] == 0: + queue.append(neighbor) + queue.sort(key=lambda x: x) + + # 如果有循环依赖,把剩余文件也加入 + for fpath in file_list: + if fpath not in result: + result.append(fpath) + + return result + + def _compile_include_py_files(self, active_sha1s: set): + """通过 TransPyC 翻译器编译 includes 目录中发现的 .py 文件""" + if not self.extra_py_files: + return + + # 按依赖关系排序 include 文件,确保被依赖的文件先编译 + sorted_files = self._sort_include_files_by_deps(self.extra_py_files) + + print(f"\n[includes 编译] 找到 {len(sorted_files)} 个 Python 源文件") + + # 构建 include 文件的模块 SHA1 映射 + # 必须在编译前预构建完整的映射,否则后续文件引用前面文件时会用错误的 SHA1 + include_module_sha1_map = self._build_current_module_sha1_map(None) + # 预先为所有 include 文件计算 SHA1 并添加到映射中 + for src_path in sorted_files: + module_name = os.path.splitext(os.path.basename(src_path))[0] + with open(src_path, 'r', encoding='utf-8') as f: + py_content = f.read() + sha1 = compute_sha1(py_content) + self.include_py_map[module_name] = sha1 + active_sha1s.add(sha1) + self._include_sha1s.add(sha1) + + # 将 include 文件的模块名映射到其 SHA1 + for includes_dir in self.include_dirs: + try: + rel = os.path.relpath(src_path, includes_dir) + mod_full = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + include_module_sha1_map[mod_full] = sha1 + include_module_sha1_map[module_name] = sha1 + except ValueError: + pass + include_module_sha1_map[module_name] = sha1 + ll_path = os.path.join(self.output_dir, f"{sha1}.ll") + obj_path = os.path.join(self.output_dir, f"{sha1}.obj") + + if self._is_decl_only_file(src_path): + print(f" 跳过(声明文件): {module_name}.py") + self._collect_inline_symbols(src_path) + continue + + if os.path.isfile(obj_path): + print(f" 跳过(缓存): {module_name}.py -> {sha1}.obj") + self._collect_inline_symbols(src_path) + self.extra_link_files.append(obj_path) + continue + + print(f" 翻译: {os.path.basename(src_path)} -> {sha1}.ll") + + try: + self._translate_file(src_path, ll_path, prebuilt_module_sha1_map=include_module_sha1_map) + if os.path.isfile(ll_path): + print(f" 编译: {sha1}.ll -> {sha1}.obj") + with open(ll_path, 'r', encoding='utf-8') as f: + ll_content = f.read() + import re + ll_content = re.sub(r'\b(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content) + ll_content = re.sub(r'\b(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)', r'\1 dso_local ', ll_content) + ll_content = re.sub(r'(@[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content) + ll_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content) + stub_decls = [] + for other_sha1, other_stub in self.stub_files.items(): + if other_sha1 == sha1: + continue + if os.path.exists(other_stub): + try: + with open(other_stub, 'r', encoding='utf-8') as sf: + for sline in sf: + sl = sline.strip() + if sl.startswith('%') and '= type' in sl and 'opaque' not in sl: + struct_name_match = re.match(r'%"?([\w.]+)"?\s*=', sl) + if struct_name_match: + stub_decls.append(sl) + except: + pass + if stub_decls: + for sdecl in stub_decls: + sname_match = re.match(r'%"?([\w.]+)"?\s*=\s*type', sdecl) + if sname_match: + sname = sname_match.group(1) + short = sname.split('.')[-1] if '.' in sname else sname + ll_content = re.sub( + r'%"?' + re.escape(sname) + r'"?\s*=\s*type\s*opaque', + sdecl, ll_content) + if short != sname: + ll_content = re.sub( + r'%"?' + re.escape(short) + r'"?\s*=\s*type\s*opaque', + sdecl, ll_content) + dso_ll_path = ll_path[:-3] + '_dso.ll' + with open(dso_ll_path, 'w', encoding='utf-8') as f: + f.write(ll_content) + cmd = [self.compile_cmd] + self.compile_flags + ['-o', obj_path, dso_ll_path] + result = subprocess.run( + cmd, + capture_output=True, + text=True, + cwd=self.output_dir + ) + if result.returncode == 0: + print(f" [成功]") + self.extra_link_files.append(obj_path) + + # 编译成功后,生成 .pyi 签名文件和 .stub.ll 文件 + # 并注册到符号表和签名映射中,以便后续 include 文件可以引用 + self._register_compiled_include(src_path, sha1, ll_content, include_module_sha1_map) + else: + print(f" [警告] 编译失败: {result.stderr.strip()}") + for ext in ['.ll', '_dso.ll']: + p = ll_path[:-3] + ext + if os.path.isfile(p): + os.remove(p) + else: + print(f" [错误] 翻译未生成 .ll 文件") + except Exception as e: + import traceback + for ext in ['.ll', '_dso.ll']: + p = ll_path[:-3] + ext + if os.path.isfile(p): + os.remove(p) + print(f" [错误] 翻译异常: {e}") + traceback.print_exc() + print(f"\n[编译终止] includes 文件翻译失败") + sys.exit(1) + + def _register_compiled_include(self, src_path, sha1, ll_content, include_module_sha1_map): + """编译 include 文件成功后,生成签名和 stub 文件并注册到符号表中""" + module_name = os.path.splitext(os.path.basename(src_path))[0] + + # 确定完整模块名(如 vpsdk.window) + mod_full = module_name + for includes_dir in self.include_dirs: + try: + rel = os.path.relpath(src_path, includes_dir) + mod_full = os.path.splitext(rel)[0].replace(os.sep, '.').replace('/', '.') + break + except ValueError: + pass + + # 1. 生成 .pyi 签名文件(如果还没有的话) + sig_path = os.path.join(self.temp_dir, f"{sha1}.pyi") + if not os.path.isfile(sig_path): + try: + with open(src_path, 'r', encoding='utf-8') as f: + py_content = f.read() + sig_content = PythonToStubConverter.convert(py_content, mod_full) + os.makedirs(self.temp_dir, exist_ok=True) + with open(sig_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(sig_content) + except Exception as e: + pass # 签名生成失败不阻塞编译 + + # 注册到 sig_files 和 _source_module_sig_files + if os.path.isfile(sig_path): + self.sig_files[sha1] = sig_path + self.sha1_map[sha1] = f"includes/{mod_full.replace('.', os.sep)}.py" + if hasattr(self, '_shared_source_module_sig_files') and self._shared_source_module_sig_files is not None: + self._shared_source_module_sig_files[mod_full] = sig_path + self._shared_source_module_sig_files[module_name] = sig_path + + # 将签名信息加载到共享符号表中 + if hasattr(self, '_shared_symbol_table') and self._shared_symbol_table is not None: + try: + self._shared_symbol_table.LoadModuleSymbols(sig_path, mod_full, lineno=0) + except Exception: + pass + + # 2. 生成 .stub.ll 文件 + stub_path = os.path.join(self.output_dir, f"{sha1}.stub.ll") + if not os.path.isfile(stub_path) and ll_content: + try: + stub_content, _ = self._split_ll(ll_content) + with open(stub_path, 'w', encoding='utf-8', newline='\n') as f: + f.write(stub_content) + except Exception: + pass + + # 注册到 stub_files + if os.path.isfile(stub_path): + self.stub_files[sha1] = stub_path + elif os.path.isfile(sig_path): + # 如果 stub 文件不存在,也尝试从 temp 目录查找 + temp_stub = os.path.join(self.temp_dir, f"{sha1}.stub.ll") + if os.path.isfile(temp_stub): + self.stub_files[sha1] = temp_stub + + def _precollect_inline_symbols(self): + """在主翻译循环之前,扫描includes目录中used_includes相关的模块收集内联函数AST""" + if not self.used_includes: + return + for includes_dir in self.include_dirs: + if not os.path.isdir(includes_dir): + continue + for module_name in self.used_includes: + module_dir = os.path.join(includes_dir, module_name) + if os.path.isdir(module_dir): + for root, dirs, files in os.walk(module_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith('.py'): + src_path = os.path.join(root, fname) + self._collect_inline_symbols(src_path) + py_path = os.path.join(includes_dir, module_name + '.py') + if os.path.isfile(py_path): + self._collect_inline_symbols(py_path) + for ef in self.extra_py_files: + self._collect_inline_symbols(ef) + + def _collect_inline_symbols(self, src_path: str): + """解析源文件,收集内联函数的AST信息到inline_func_symbols""" + try: + with open(src_path, 'r', encoding='utf-8') as f: + code = f.read() + tree = ast.parse(code) + module_name = os.path.splitext(os.path.basename(src_path))[0] + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.FunctionDef) and node.returns: + is_inline = False + if isinstance(node.returns, ast.BinOp) and isinstance(node.returns.op, ast.BitOr): + for part in [node.returns.left, node.returns.right]: + if isinstance(part, ast.Attribute) and part.attr == 'CInline': + is_inline = True + break + if isinstance(part, ast.Name) and part.id == 'CInline': + is_inline = True + break + elif isinstance(node.returns, ast.Attribute) and node.returns.attr == 'CInline': + is_inline = True + elif isinstance(node.returns, ast.Name) and node.returns.id == 'CInline': + is_inline = True + if is_inline: + func_name = node.name + sym_key = f"{module_name}.{func_name}" + info = CTypeInfo() + info.Name = func_name + info.IsFunction = True + info.IsInline = True + info.InlineBody = node.body + info.InlineParams = [arg.arg for arg in node.args.args] + info.Storage = t.CInline() + self.inline_func_symbols[func_name] = info + self.inline_func_symbols[sym_key] = info + except Exception: + pass + + def _build_shared_symbol_data(self): + """一次性构建所有文件共享的符号表数据,避免每个文件重复加载""" + import copy + import time + t0 = time.time() + + print("[缓存] 构建共享符号表数据...") + + base_trans = TransPyC.TransPyC(code="pass", triple=self.triple, datalayout=self.datalayout) + base_trans.translator.LlvmGen = None + base_trans.translator._module_sha1_map = {} + base_trans.translator._global_function_default_args = self.function_default_args + + for includes_dir in self.include_dirs: + if os.path.isdir(includes_dir): + for pyi_file in os.listdir(includes_dir): + if pyi_file.endswith('.pyi'): + pyi_path = os.path.join(includes_dir, pyi_file) + module_name = os.path.splitext(pyi_file)[0] + base_trans.translator.SymbolTable.LoadModuleSymbols(pyi_path, module_name, lineno=0) + for py_file in os.listdir(includes_dir): + if py_file.endswith('.py') and not py_file.startswith('_'): + module_name = os.path.splitext(py_file)[0] + sha1_key = self.include_py_map.get(module_name) + if sha1_key and sha1_key in self.sig_files: + sig_path = self.sig_files[sha1_key] + base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) + for sha1_key, sig_path in self.sig_files.items(): + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + mod_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + mod_name = mod_name[len('includes/'):] + base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, mod_name, lineno=0) + if mod_name.endswith('.__init__'): + package_name = mod_name[:-len('.__init__')] + self._register_package_reexports(base_trans, sig_path, package_name) + + for sha1_key, sig_path in self.sig_files.items(): + rel_path = self.sha1_map.get(sha1_key, sha1_key) + if rel_path.startswith('includes/'): + continue + module_name = os.path.splitext(rel_path)[0].replace(os.sep, '.').replace('/', '.') + base_trans.translator.SymbolTable.LoadModuleSymbols(sig_path, module_name, lineno=0) + base_trans.translator._source_module_sig_files[module_name] = sig_path + short_name = module_name.split('.')[-1] if '.' in module_name else module_name + if short_name != module_name: + base_trans.translator._source_module_sig_files[short_name] = sig_path + + all_dc = {} + for sha1_key, stub_path in self.stub_files.items(): + if os.path.exists(stub_path): + try: + with open(stub_path, 'r', encoding='utf-8') as f: + stub_content = f.read() + for line in stub_content.splitlines(): + line = line.strip() + if line.startswith('@') and '= global' in line and 'i32' in line and not line.startswith('@llvm'): + var_name = line.split('=')[0].strip().lstrip('@') + val_part = line.split('i32')[-1].strip().rstrip(']').lstrip('[').lstrip('i32') + try: + val = int(val_part) + all_dc[var_name] = val + except: + pass + except: + pass + for sha1_key, pyi_path in self.sig_files.items(): + if os.path.exists(pyi_path): + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + pyi_content = f.read() + tree = ast.parse(pyi_content) + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): + ann_str = ast.dump(node.annotation) + if 'CDefine' in ann_str and node.value: + val = None + if isinstance(node.value, ast.Constant): + val = node.value.value + elif isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Name) and node.value.func.id == 'float' and node.value.args and isinstance(node.value.args[0], ast.Constant): + val = node.value.args[0].value + if val is not None: + all_dc[f"{node.target.id}"] = val + except: + pass + + export_extern_funcs = set() + for sha1_key, sig_path in self.sig_files.items(): + try: + with open(sig_path, 'r', encoding='utf-8') as f: + sig_content = f.read() + sig_tree = ast.parse(sig_content) + for node in ast.iter_child_nodes(sig_tree): + if isinstance(node, ast.FunctionDef): + if _check_annotation_for_export(node.returns): + export_extern_funcs.add(node.name) + except Exception: + pass + + for sym_name, sym_info in self.inline_func_symbols.items(): + if sym_name not in base_trans.translator.SymbolTable: + base_trans.translator.SymbolTable[sym_name] = sym_info + else: + existing = base_trans.translator.SymbolTable[sym_name] + if not getattr(existing, 'InlineBody', None) and getattr(sym_info, 'InlineBody', None): + existing.IsInline = sym_info.IsInline + existing.InlineBody = sym_info.InlineBody + existing.InlineParams = sym_info.InlineParams + + self._shared_symbol_table = base_trans.translator.SymbolTable + self._shared_source_module_sig_files = dict(base_trans.translator._source_module_sig_files) + self._shared_all_dc = all_dc + self._shared_export_extern_funcs = export_extern_funcs + + generic_class_templates = {} + for includes_dir in self.include_dirs: + if os.path.isdir(includes_dir): + abs_includes = os.path.join(self.src_root, includes_dir) if not os.path.isabs(includes_dir) else includes_dir + if not os.path.isdir(abs_includes): + abs_includes = includes_dir + for py_file in os.listdir(abs_includes): + if py_file.endswith('.py') and not py_file.startswith('_'): + py_path = os.path.join(abs_includes, py_file) + try: + with open(py_path, 'r', encoding='utf-8') as f: + py_code = f.read() + py_tree = ast.parse(py_code) + for node in py_tree.body: + if isinstance(node, ast.ClassDef) and hasattr(node, 'type_params') and node.type_params: + type_params = [tp.name for tp in node.type_params] + generic_class_templates[node.name] = { + 'node': node, + 'type_params': type_params, + } + except Exception: + pass + self._shared_generic_class_templates = generic_class_templates + + t1 = time.time() + print(f"[缓存] 共享符号表构建完成 ({t1-t0:.2f}s, {len(self._shared_symbol_table)} 符号, {len(generic_class_templates)} 泛型模板)") + + def _compile_include_sources(self): + """扫描项目目录中的汇编存根,编译 includes 目录中发现的 C/C++ 源文件""" + extra_sources = list(self.extra_compile_files) + scan_dirs = [] + if self.src_root and os.path.isdir(self.src_root): + scan_dirs.append(self.src_root) + project_dir = os.path.dirname(self.output_dir) + if project_dir and os.path.isdir(project_dir) and project_dir not in scan_dirs: + scan_dirs.append(project_dir) + for scan_dir in scan_dirs: + for root, dirs, files in os.walk(scan_dir): + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for fname in files: + if fname.endswith(('.S', '.s', '.c', '.cpp')): + if fname.startswith('test_'): + continue + fpath = os.path.join(root, fname) + if fpath not in extra_sources: + extra_sources.append(fpath) + if not extra_sources: + return + + cc_map = { + '.c': 'gcc', + '.cpp': 'g++', '.cc': 'g++', '.cxx': 'g++', + '.m': 'clang', '.mm': 'clang++', + '.s': 'gcc', '.S': 'gcc', + } + + print(f"\n[includes 编译] 找到 {len(extra_sources)} 个源文件") + + for src_path in extra_sources: + _, ext = os.path.splitext(src_path) + ext = ext.lower() + obj_path = os.path.join(self.output_dir, os.path.splitext(os.path.basename(src_path))[0] + '.obj') + if ext in ('.s', '.S') and any('oformat' in f for f in self.linker_flags): + cc = 'clang' + compile_src = src_path + extra_flags = ['-c', '-target', 'x86_64-none-elf', '-o', obj_path, compile_src] + else: + cc = cc_map.get(ext, 'gcc') + extra_flags = ['-c', '-o', obj_path, src_path] + + print(f" 编译: {os.path.basename(src_path)} -> {os.path.basename(obj_path)}") + + try: + cmd = [cc] + extra_flags + result = subprocess.run(cmd, capture_output=True, text=True) + if result.returncode == 0: + print(f" [成功]") + self.extra_link_files.append(obj_path) + else: + print(f" [错误] 编译失败: {result.stderr.strip()}") + print(f"\n[编译终止] C/C++ 源文件编译失败,立即终止编译。") + sys.exit(1) + except FileNotFoundError: + print(f" [错误] 找不到编译器: {cc}") + print(f"\n[编译终止] 找不到编译器,立即终止编译。") + sys.exit(1) + except Exception as e: + print(f" [错误] {e}") + print(f"\n[编译终止] 编译异常,立即终止编译。") + sys.exit(1) + + def _strip_debug_sections(self, exe_path: str): + """剥离 .exe 中的调试段(跳过裸机二进制)""" + if not os.path.exists(exe_path): + return + ext = os.path.splitext(exe_path)[1].lower() + if ext not in ('.exe', '.dll', '.obj', '.o', '.elf'): + print(f" [剥离] 跳过({ext} 格式无需剥离)") + return + import shutil + for tool in ['llvm-strip', 'strip']: + strip_cmd = shutil.which(tool) + if strip_cmd: + try: + result = subprocess.run( + [strip_cmd, '--strip-debug', exe_path], + capture_output=True, text=True + ) + if result.returncode == 0: + print(f" [剥离] 调试段已移除 ({tool})") + else: + print(f" [剥离] 警告: {result.stderr.strip()}") + except Exception: + pass + break + + def _link_obj_files(self, active_sha1s: set): + """将 active_sha1s 对应的 .obj 文件和 includes 库文件链接为可执行文件""" + obj_files = [] + merged_obj = os.path.join(self.output_dir, '_merged.obj') + if os.path.isfile(merged_obj): + obj_files.append(merged_obj) + else: + for root, dirs, files in os.walk(self.output_dir): + for file in files: + if file.endswith('.obj'): + sha1 = file[:-4] + if sha1 in active_sha1s and sha1 not in self._include_sha1s: + obj_files.append(os.path.join(root, file)) + + if not obj_files and not self.extra_link_files: + print("[链接] 无文件可链接") + return + + print(f"\n[链接] 找到 {len(obj_files)} 个 .obj 文件") + + all_link_files = obj_files + self.extra_link_files + seen = set() + all_link_files = [f for f in all_link_files if not (f in seen or seen.add(f))] + if self.extra_link_files: + print(f"[链接] 额外库文件: {len(self.extra_link_files)} 个") + for lib in self.extra_link_files: + print(f" - {os.path.basename(lib)}") + + if not self.linker_cmd: + print("[链接] 未配置链接器") + return + + exe_path = os.path.join(self.output_dir, self.linker_output) if self.linker_output else os.path.join(self.output_dir, 'a.exe') + is_binary = self.linker_output and self.linker_output.endswith('.bin') + + # 检查是否直接输出二进制(使用 --oformat binary / -oformat binary 标志) + is_direct_binary = is_binary and any('oformat' in f for f in self.linker_flags) + + if is_binary and not is_direct_binary: + link_output = exe_path[:-4] + '_pe.exe' + else: + link_output = exe_path + + # 自动复制或生成 linker.ld 到输出目录 + linker_ld_src = os.path.join(os.path.dirname(self.output_dir), 'linker.ld') + linker_ld_dst = os.path.join(self.output_dir, 'linker.ld') + if os.path.isfile(linker_ld_src) and not os.path.isfile(linker_ld_dst): + import shutil + shutil.copy2(linker_ld_src, linker_ld_dst) + print(f" [链接] 使用链接脚本: linker.ld") + elif not os.path.isfile(linker_ld_dst) and any('-T' in f or '-T' in f.replace(',', ' ') for f in self.linker_flags): + default_ld = """ENTRY(_start) + +SECTIONS { + . = 0x100000; + + .text : { + *(.text.startup) + *(.text) + *(.text.*) + } + + .rodata : { + *(.rodata) + *(.rodata.*) + } + + .data : { + *(.data) + *(.data.*) + } + + .bss : { + *(.bss) + *(.bss.*) + } + + /DISCARD/ : { + *(.comment) + *(.note) + *(.eh_frame) + *(.eh_frame_hdr) + *(.reloc) + *(.rela) + *(.debug*) + } +} +""" + with open(linker_ld_dst, 'w', encoding='utf-8', newline='\n') as f: + f.write(default_ld) + print(f" [链接] 自动创建默认链接脚本: linker.ld") + + try: + cmd = [self.linker_cmd] + self.linker_flags + ['-o', link_output] + all_link_files + print(f" 执行: {' '.join(cmd)}") + result = subprocess.run( + cmd, + capture_output=True, + text=True, + cwd=self.output_dir or '.' + ) + if result.returncode == 0: + if is_binary and not is_direct_binary: + import shutil + objcopy = shutil.which('llvm-objcopy') or shutil.which('objcopy') + if objcopy: + conv = subprocess.run( + [objcopy, '-O', 'binary', link_output, exe_path], + capture_output=True, text=True + ) + if conv.returncode == 0: + os.remove(link_output) + print(f" [成功] 生成裸机二进制: {exe_path}") + file_size = os.path.getsize(exe_path) + print(f" [大小] {file_size} 字节") + else: + print(f" [错误] 二进制转换失败: {conv.stderr.strip()}") + sys.exit(1) + else: + print(" [错误] 找不到 llvm-objcopy,无法生成裸机二进制") + sys.exit(1) + else: + print(f" [成功] 生成: {exe_path}") + file_size = os.path.getsize(exe_path) + print(f" [大小] {file_size} 字节") + if not is_binary: + self._strip_debug_sections(exe_path) + else: + print(f" [错误] 链接失败: {result.stderr.strip()}") + print(f"\n[编译终止] 链接失败,立即终止编译。") + sys.exit(1) + except FileNotFoundError: + print(f" [错误] 找不到链接器: {self.linker_cmd}") + print(f"\n[编译终止] 找不到链接器,立即终止编译。") + sys.exit(1) + except Exception as e: + print(f" [错误] {e}") + print(f"\n[编译终止] 链接异常,立即终止编译。") + sys.exit(1) + + +def save_sha1_map(temp_dir: str, sha1_map: dict[str, str]): + """将 SHA1 映射表保存到文件""" + map_path = os.path.join(temp_dir, '_sha1_map.txt') + with open(map_path, 'w', encoding='utf-8') as f: + for sha1, rel in sorted(sha1_map.items()): + f.write(f"{sha1}:{rel}\n") + + +def load_sha1_map(temp_dir: str) -> dict[str, str]: + """从文件加载 SHA1 映射表""" + map_path = os.path.join(temp_dir, '_sha1_map.txt') + result = {} + if os.path.exists(map_path): + with open(map_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if ':' in line: + sha1, rel = line.split(':', 1) + result[sha1] = rel + return result + + +def load_project_config(project_file: str) -> dict: + """从 project.json 加载配置""" + import json + with open(project_file, 'r', encoding='utf-8') as f: + return json.load(f) + + +def resolve_paths(config: dict, project_file: str) -> dict: + """将配置中的相对路径转换为绝对路径""" + project_dir = os.path.dirname(os.path.abspath(project_file)) + result = dict(config) + + def resolve(p): + if p is None: + return None + if os.path.isabs(p): + return p + return os.path.normpath(os.path.join(project_dir, p)) + + if 'source_dir' in result: + result['source_dir'] = resolve(result.get('source_dir')) + elif 'sources' in result: + resolved_sources = [] + for src in result['sources']: + if '*' in src or '?' in src: + import glob as glob_module + for matched in glob_module.glob(os.path.join(project_dir, src), recursive=True): + if os.path.isfile(matched): + resolved_sources.append(matched) + else: + resolved_sources.append(resolve(src)) + result['sources'] = [s for s in resolved_sources if os.path.isfile(s)] + + result['temp_dir'] = resolve(config.get('temp_dir')) + result['output_dir'] = resolve(config.get('output_dir')) + + if 'includes' in result: + result['includes'] = [resolve(inc) for inc in result['includes']] + + result['_project_dir'] = project_dir + return result + + +def main(): + import argparse + parser = argparse.ArgumentParser( + description='TransPyC 工程翻译器 - 基于 project.json 的两阶段翻译', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=''' +示例: + # 从 project.json 读取配置并执行(默认查找当前目录) + python ProjectTrans.py + + # 指定 project.json 文件 + python ProjectTrans.py --project ./TestProject/project.json + + # 使用命令行参数覆盖 project.json 配置 + python ProjectTrans.py --src ./src --temp ./decl --output ./out --phase all + + # 仅运行阶段一 + python ProjectTrans.py --phase 1 + + # 仅运行阶段二 + python ProjectTrans.py --phase 2 + + # 清理临时目录 + python ProjectTrans.py --clean +''' + ) + parser.add_argument('--project', help='project.json 路径(默认查找当前目录)') + parser.add_argument('--src', help='源文件目录(覆盖 project.json)') + parser.add_argument('--temp', help='声明接口临时目录(覆盖 project.json)') + parser.add_argument('--output', help='输出目录(覆盖 project.json)') + parser.add_argument('--phase', choices=['1', '2', 'all'], help='阶段: 1=生成声明, 2=翻译+编译, all=全部') + parser.add_argument('--cc', help='LLVM 编译器命令(覆盖 project.json)') + parser.add_argument('--clean', action='store_true', help='清理 output 和 temp 目录') + + args = parser.parse_args() + + project_file = args.project + if not project_file: + candidates = ['project.json', './project.json'] + for c in candidates: + if os.path.exists(c): + project_file = c + break + + if project_file and os.path.exists(project_file): + print(f"[配置] 读取: {project_file}") + config = load_project_config(project_file) + project_dir = os.path.dirname(os.path.abspath(project_file)) + print(f"[配置] 项目目录: {project_dir}") + else: + print("[错误] 未找到 project.json,请使用 --project 指定") + sys.exit(1) + + resolved = resolve_paths(config, project_file) + src = args.src or resolved.get('source_dir') or resolved.get('sources') + temp_dir = args.temp or resolved.get('temp_dir') + output_dir = args.output or resolved.get('output_dir') + phase = args.phase or 'all' + cc_cmd = args.cc or resolved.get('compiler', {}).get('cmd', 'llc') + cc_flags = resolved.get('compiler', {}).get('flags', ['-filetype=obj']) + slice_level = resolved.get('options', {}).get('slice_level', 3) + project_include_dirs = resolved.get('includes', []) + target_triple = resolved.get('target', {}).get('triple') + target_datalayout = resolved.get('target', {}).get('datalayout') + + if isinstance(src, list): + if len(src) == 1 and os.path.isdir(src[0]): + src = src[0] + else: + src = src[0] if len(src) == 1 else os.path.dirname(os.path.commonpath(src)) if all(os.path.exists(p) for p in src) else src[0] + + print(f"[配置] 源目录: {src}") + print(f"[配置] 临时目录: {temp_dir}") + print(f"[配置] 输出目录: {output_dir}") + print(f"[配置] 阶段: {phase}") + print(f"[配置] 编译器: {cc_cmd} {' '.join(cc_flags)}") + if target_triple: + print(f"[配置] 目标三元组: {target_triple}") + if target_datalayout: + print(f"[配置] 数据布局: {target_datalayout}") + + if args.clean: + if output_dir and os.path.exists(output_dir): + for f in os.listdir(output_dir): + fpath = os.path.join(output_dir, f) + try: + if os.path.isfile(fpath) or os.path.islink(fpath): + os.remove(fpath) + elif os.path.isdir(fpath): + shutil.rmtree(fpath, ignore_errors=True) + except: + pass + print(f"[清理] output: 已清空 {output_dir}") + if temp_dir and os.path.exists(temp_dir): + for f in os.listdir(temp_dir): + fpath = os.path.join(temp_dir, f) + try: + if os.path.isfile(fpath) or os.path.islink(fpath): + os.remove(fpath) + elif os.path.isdir(fpath): + shutil.rmtree(fpath, ignore_errors=True) + except: + pass + print(f"[清理] temp: 已清空 {temp_dir}") + print("[清理] 完成") + if (not phase or phase == 'all') and not args.project: + return + + if phase in ('1', 'all'): + if isinstance(src, list): + print("[错误] 阶段一需要指定源目录,不支持文件列表") + sys.exit(1) + all_include_dirs = list(project_include_dirs) if project_include_dirs else [] + for d in Phase2Translator.INCLUDE_DIRS: + if os.path.isdir(d): + d = os.path.abspath(d) + if d not in [os.path.abspath(x) for x in all_include_dirs]: + all_include_dirs.append(d) + gen = Phase1Generator(src, temp_dir, include_dirs=all_include_dirs, target_triple=target_triple, target_datalayout=target_datalayout) + gen.run() + save_sha1_map(temp_dir, gen.sha1_map) + + if phase in ('2', 'all'): + if not output_dir: + print("[错误] 阶段二需要指定 --output 目录") + sys.exit(1) + if not os.path.exists(temp_dir): + print(f"[错误] 声明目录不存在,请先运行阶段一: {temp_dir}") + sys.exit(1) + if isinstance(src, list): + print("[错误] 阶段二需要指定源目录,不支持文件列表") + sys.exit(1) + linker_cmd = resolved.get('linker', {}).get('cmd') + linker_flags = resolved.get('linker', {}).get('flags', []) + linker_output = resolved.get('linker', {}).get('output') + target_triple = resolved.get('target', {}).get('triple') + target_datalayout = resolved.get('target', {}).get('datalayout') + trans = Phase2Translator(src, temp_dir, output_dir, compile_cmd=cc_cmd, compile_flags=cc_flags, linker_cmd=linker_cmd, linker_flags=linker_flags, linker_output=linker_output, include_dirs=project_include_dirs, target_triple=target_triple, target_datalayout=target_datalayout) + trans.sha1_map = load_sha1_map(temp_dir) + trans.slice_level = slice_level + trans.run() + + +if __name__ == '__main__': + main() diff --git a/README.md b/README.md new file mode 100644 index 0000000..0550059 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# Viper 语言规范 + +Viper 是一种基于 Python 语法的系统级编程语言,通过 TransPyC 编译器编译为 LLVM IR,最终生成原生机器码。Viper 不是 Python 的子集,也不是 C 的语法糖——它拥有独立的类型系统、两阶段编译模型和 SHA1 命名空间机制,适用于操作系统内核、嵌入式系统、驱动程序等底层开发场景。 + +## 核心设计理念 + +- **Python 语法,LLVM 语义**:源文件是合法的 Python 语法,但通过 `t` 模块类型注解赋予 LLVM 级别的语义 +- **类型注解即编译指令**:类型注解决定 LLVM IR 的生成,不是可选的提示 +- **两阶段编译**:先提取声明接口(`.pyi` + `.stub.ll`),再翻译源文件为含代码的 `.ll` +- **SHA1 命名空间**:每个源文件按内容 SHA1 哈希命名,自动消除跨模块符号冲突 +- **零运行时开销**:编译为原生代码,无 GC、无解释器、无虚拟机 + +## 模块总览 + +Viper 语言通过两个核心模块提供类型和操作支持: + +| 模块 | 用途 | 导入方式 | +|------|------|----------| +| `t` | 类型定义系统 | `import t` | +| `c` | C 语言操作指令 | `import c` | + +## 文档索引 + +| 文件 | 内容 | +|------|------| +| [01-overview.md](01-overview.md) | 语言概述、两阶段编译流程、SHA1 命名空间、`t.CDefine`/`t.CExport`/`t.CInline` 深度解析 | +| [02-type-system.md](02-type-system.md) | 类型系统(基本类型、指针、数组、结构体、联合体、枚举、typedef、`__attribute__`) | +| [03-variables.md](03-variables.md) | 变量声明与赋值(含 `t.CDefine` 常量) | +| [04-functions.md](04-functions.md) | 函数定义与调用(含 `t.CExport`、`t.CInline`、`t.CDefine` 函数、`@c.CReturn`) | +| [05-classes.md](05-classes.md) | 类与数据布局(结构体、联合体、枚举、typedef、位域) | +| [06-oop.md](06-oop.md) | 面向对象与运算符重载(`@t.Object`、`@t.CVTable`、继承、dunder 方法) | +| [07-control-flow.md](07-control-flow.md) | 控制流(条件、循环、match) | +| [08-c-operations.md](08-c-operations.md) | C 语言操作(指针、内联汇编、预处理指令、LLVM IR 内联) | +| [09-exceptions.md](09-exceptions.md) | 异常处理 | +| [10-imports.md](10-imports.md) | 模块与导入系统(存根生成、SHA1 命名空间与导入) | +| [11-builtins.md](11-builtins.md) | 内置函数与运算符 | +| [12-project.md](12-project.md) | 项目配置与构建(增量编译、SHA1 映射) | diff --git a/StubGen.py b/StubGen.py new file mode 100644 index 0000000..823e842 --- /dev/null +++ b/StubGen.py @@ -0,0 +1,1337 @@ +#!/usr/bin/env python3 +""" +StubGen - C/H/Py 文件到 Python 存根文件生成器(工程化版本) + +用法: + python StubGen.py -c config.json + python StubGen.py -i input.h -o output.py + python StubGen.py -d ./kernel -o ./kernel/include + +示例配置: + { + "InputDir": "./kernel", + "OutputDir": "./kernel/include", + "IncludePatterns": ["*.h", "*.c", "*.py"], + "ExcludePatterns": ["*_test.py"], + "PreserveStructure": true, + "GenerateGuards": true, + "TypeMappings": { + "custom_type": "t.CCustom" + } + } +""" + +import sys +import os +import re +import json +import ast +import argparse +import logging +from pathlib import Path +from typing import List, Dict, Optional, Set, Tuple +from dataclasses import dataclass, field + +sys.path.insert(0, os.path.dirname(__file__)) + +from lib.core.stub_generator import CHeaderParser, PythonStubGenerator, CTypeMapper + + +@dataclass +class StubGenConfig: + """存根生成器配置""" + InputDir: Optional[str] = None + OutputDir: str = "./stubs" + InputFiles: List[str] = field(default_factory=list) + IncludePatterns: List[str] = field(default_factory=lambda: ["*.h", "*.c", "*.py"]) + ExcludePatterns: List[str] = field(default_factory=list) + TypeMappings: Dict[str, str] = field(default_factory=dict) + PreserveStructure: bool = True # 保持目录结构 + GenerateGuards: bool = True # 生成宏守卫 + verbose: bool = False + DryRun: bool = False + + @classmethod + def from_dict(cls, data: Dict) -> 'StubGenConfig': + """从字典创建配置""" + return cls( + InputDir=data.get('InputDir'), + OutputDir=data.get('OutputDir', './stubs'), + InputFiles=data.get('InputFiles', []), + IncludePatterns=data.get('IncludePatterns', ['*.h', '*.c', '*.py']), + ExcludePatterns=data.get('ExcludePatterns', []), + TypeMappings=data.get('TypeMappings', {}), + PreserveStructure=data.get('PreserveStructure', True), + GenerateGuards=data.get('GenerateGuards', True), + verbose=data.get('verbose', False), + DryRun=data.get('DryRun', False), + ) + + @classmethod + def from_file(cls, FilePath: str) -> 'StubGenConfig': + """从 JSON 文件加载配置""" + with open(FilePath, 'r', encoding='utf-8') as f: + data = json.load(f) + return cls.from_dict(data) + + +class PythonToStubConverter: + """将 Python 文件转换为存根格式""" + + # __include 别名映射表 {alias: ModuleName} + IncludeAliasMap: Dict[str, str] = {} + + # 变量排除列表 - 匹配这些模式的变量不会被添加到存根文件 + VarExcludeList: List[str] = [] + + # 宏排除列表 - 匹配这些模式的宏不会被添加到存根文件 + MacroExcludeList: List[str] = [] + + @classmethod + def SetIncludeAliasMap(cls, alias_map: Dict[str, str]): + """设置 __include 别名映射表""" + cls.IncludeAliasMap = alias_map + + @classmethod + def SetVarExcludeList(cls, exclude_list: List[str]): + """设置变量排除列表""" + cls.VarExcludeList = exclude_list + + @classmethod + def SetMacroExcludeList(cls, exclude_list: List[str]): + """设置宏排除列表""" + cls.MacroExcludeList = exclude_list + + @classmethod + def _ShouldExcludeVar(cls, VarName: str) -> bool: + """检查变量是否应该被排除""" + import fnmatch + for pattern in cls.VarExcludeList: + if fnmatch.fnmatch(VarName, pattern): + return True + return False + + @classmethod + def _ShouldExcludeMacro(cls, MacroName: str) -> bool: + """检查宏是否应该被排除""" + import fnmatch + for pattern in cls.MacroExcludeList: + if fnmatch.fnmatch(MacroName, pattern): + return True + return False + + @staticmethod + def convert(PyContent: str, ModuleName: str) -> str: + """将 Python 代码转换为存根格式""" + lines = PyContent.split('\n') + StubLines = [] + + # 添加文件头 + StubLines.append('"""') + StubLines.append(f'Auto-generated Python stub file from {ModuleName}.py') + StubLines.append(f'Module: {ModuleName}') + StubLines.append('"""') + StubLines.append('') + + # 解析 Python 代码,检查是否已经导入了 t 和 c + import ast + HasImportT = False + HasImportC = False + try: + tree = ast.parse(PyContent) + for node in tree.body: + if isinstance(node, ast.Import): + for alias in node.names: + if alias.name == 't': + HasImportT = True + elif alias.name == 'c': + HasImportC = True + except: + pass + + # 添加默认导入(如果源代码中没有) + if not HasImportT: + StubLines.append('import t') + if not HasImportC: + StubLines.append('import c') + if not HasImportT or not HasImportC: + StubLines.append('') + + # 添加 c.CPragma("once") + # StubLines.append('c.CPragma("once")') + StubLines.append('') + + # 生成文件级别宏守卫名称 + #FileGuardName = f'__{ModuleName.upper()}_DEFINE__' + + # 添加文件开头宏守卫 + #StubLines.append(f'c.CIfndef({FileGuardName})') + #StubLines.append(f'{FileGuardName}: t.CDefine') + #StubLines.append('') + + # 解析 Python 代码,提取类型定义 + try: + tree = ast.parse(PyContent) + + # 第一遍扫描:收集 Postdefinition 变量 + PostdefVars = {} # {ClassName: [(VarName, TypeStr, node), ...]} + for node in tree.body: + if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): + TypeStr = PythonToStubConverter._GetTypeString(node.annotation) + # 检查是否是 Postdefinition 类型 + if 't.Postdefinition' in TypeStr: + # 提取引用的类名 + ClassName = PythonToStubConverter._ExtractPostdefClass(node.annotation) + if ClassName: + if ClassName not in PostdefVars: + PostdefVars[ClassName] = [] + PostdefVars[ClassName].append((node.target.id, TypeStr, node)) + + # 按原始顺序处理节点,保持代码的原始顺序 + PrevType = None # 记录前一个节点的类型 + + for node in tree.body: + CurrentType = None + + if isinstance(node, ast.ClassDef): + CurrentType = 'class' + # 如果前一个不是类,添加空行分隔 + if PrevType is not None and PrevType != 'class': + StubLines.append('') + # 检查是否有对应的 Postdefinition 变量 + ClassPostdefs = PostdefVars.get(node.name, []) + ClassLines = PythonToStubConverter._ConvertClass( + node, SourceLines=lines, PostdefVars=ClassPostdefs + ) + StubLines.extend(ClassLines) + elif isinstance(node, ast.FunctionDef): + CurrentType = 'function' + # 如果前一个是类或者是第一个函数,添加空行分隔 + if PrevType == 'class' or (PrevType is not None and PrevType != 'function'): + StubLines.append('') + FuncLines = PythonToStubConverter._ConvertFunction(node, SourceLines=lines) + StubLines.extend(FuncLines) + StubLines.append('') # 函数后空行 + elif isinstance(node, ast.AnnAssign): + CurrentType = 'variable' + # 跳过 Postdefinition 变量(已经在类中处理) + TypeStr = PythonToStubConverter._GetTypeString(node.annotation) + if 't.Postdefinition' in TypeStr: + continue + # 检查是否带有 t.CStatic 标志,如果有则不排除 + HasStatic = 't.CStatic' in TypeStr + # 检查变量是否应该被排除 + ShouldExclude = False + if isinstance(node.target, ast.Name) and not HasStatic: + VarName = node.target.id + if PythonToStubConverter._ShouldExcludeVar(VarName): + ShouldExclude = True + if ShouldExclude: + continue + # 如果前一个不是变量,添加空行分隔 + if PrevType is not None and PrevType != 'variable': + StubLines.append('') + VarLines = PythonToStubConverter._ConvertVariable(node, SourceLines=lines) + # 移除多余的空行 + VarLines = [line for line in VarLines if line.strip()] + StubLines.extend(VarLines) + elif isinstance(node, ast.Import): + # 处理导入语句 + CurrentType = 'import' + ImportStr = PythonToStubConverter._GetImportString(node, SourceLines=lines) + if ImportStr: + if PrevType is not None and PrevType != 'import': + StubLines.append('') + StubLines.append(ImportStr) + elif isinstance(node, ast.Assign): + CurrentType = 'variable' + # 处理模块级别的全局变量(无类型标注) + if PrevType is not None and PrevType != 'variable': + StubLines.append('') + AssignLines = PythonToStubConverter._ConvertGlobalAssign(node) + StubLines.extend(AssignLines) + elif isinstance(node, ast.ImportFrom): + # 处理 from ... import ... 语句 + CurrentType = 'import' + ImportStr = PythonToStubConverter._GetImportFromString(node, SourceLines=lines) + if ImportStr: + if PrevType is not None and PrevType != 'import': + StubLines.append('') + StubLines.append(ImportStr) + elif isinstance(node, ast.Expr): + # 处理模块级别的宏调用,如 c.CIf(...), c.CEndif() + ExprStr = PythonToStubConverter._GetExprString(node.value) + if ExprStr: + CurrentType = 'macro' + StubLines.append(ExprStr) + StubLines.append('') # 宏后空行 + elif isinstance(node, ast.If): + # 处理模块级别的 if 宏条件,如 if c.CIf(FF_MULTI_PARTITION): + IfStr = PythonToStubConverter._GetModuleIfMacroString(node) + if IfStr: + CurrentType = 'macro' + StubLines.append(IfStr) + StubLines.append('') # 宏后空行 + + if CurrentType: + PrevType = CurrentType + + # 添加文件结尾宏守卫 + #StubLines.append('') + #StubLines.append('c.CEndif()') + + except SyntaxError as e: + # 如果解析失败,添加注释说明 + StubLines.append(f'# Warning: Failed to parse Python code: {e}') + StubLines.append('# Original content:') + StubLines.append('"""') + StubLines.append(PyContent[:1000]) # 只显示前1000字符 + StubLines.append('"""') + + return '\n'.join(StubLines) + + @staticmethod + def _ConvertClass(node: ast.ClassDef, SourceLines: List[str] = None, PostdefVars: List[Tuple[str, str, ast.AnnAssign]] = None, indent: int = 0) -> List[str]: + """转换类定义 + + Args: + node: 类定义节点 + SourceLines: 源代码行列表 + PostdefVars: Postdefinition 变量列表 [(VarName, TypeStr, node), ...] + indent: 缩进级别(用于嵌套类) + """ + lines = [] + PostdefVars = PostdefVars or [] + IndentStr = ' ' * indent + + # 处理类装饰器 + for decorator in node.decorator_list: + DecoratorStr = PythonToStubConverter._GetDecoratorString(decorator) + if DecoratorStr: + lines.append(f'{IndentStr}@{DecoratorStr}') + + # 检查是否是结构体、联合体或枚举 + BaseNames = [base.attr if isinstance(base, ast.Attribute) else base.id + for base in node.bases + if isinstance(base, (ast.Name, ast.Attribute))] + + # 保留原始基类 + if node.bases: + BaseStrs = [] + for base in node.bases: + if isinstance(base, ast.Name): + BaseStrs.append(base.id) + elif isinstance(base, ast.Attribute): + BaseStrs.append(f'{base.value.id}.{base.attr}') + elif isinstance(base, ast.Subscript): + # 处理泛型类型,如 memory_block_t[MAX_ORDER + 1] + BaseStrs.append(PythonToStubConverter._GetTypeString(base)) + ClassTypeParamStr = '' + if hasattr(node, 'type_params') and node.type_params: + param_names = [tp.name for tp in node.type_params] + ClassTypeParamStr = f'[{", ".join(param_names)}]' + if BaseStrs: + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}({", ".join(BaseStrs)}):') + else: + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') + else: + ClassTypeParamStr = '' + if hasattr(node, 'type_params') and node.type_params: + param_names = [tp.name for tp in node.type_params] + ClassTypeParamStr = f'[{", ".join(param_names)}]' + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') + + # 处理类成员 + HasMembers = False + seen_member_names = set() + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + seen_member_names.add(item.target.id) + init_members = [] + for item in node.body: + if isinstance(item, ast.FunctionDef) and item.name == '__init__': + for stmt in item.body: + if (isinstance(stmt, ast.AnnAssign) + and isinstance(stmt.target, ast.Attribute) + and isinstance(stmt.target.value, ast.Name) + and stmt.target.value.id == 'self'): + init_members.append(stmt) + untyped_self_members = [] + for m_name in [m.target.attr for m in init_members if isinstance(m.target, ast.Attribute)]: + seen_member_names.add(m_name) + for item in node.body: + if isinstance(item, ast.FunctionDef): + for stmt in item.body: + if (isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + and isinstance(stmt.targets[0], ast.Attribute) + and isinstance(stmt.targets[0].value, ast.Name) + and stmt.targets[0].value.id == 'self'): + attr_name = stmt.targets[0].attr + if attr_name not in seen_member_names: + seen_member_names.add(attr_name) + untyped_self_members.append(stmt) + for item in list(node.body) + init_members + untyped_self_members: + if isinstance(item, ast.Assign): + if (len(item.targets) == 1 + and isinstance(item.targets[0], ast.Attribute) + and isinstance(item.targets[0].value, ast.Name) + and item.targets[0].value.id == 'self'): + HasMembers = True + MemberIndent = IndentStr + ' ' + attr_name = item.targets[0].attr + if attr_name in seen_member_names: + continue + InferredType = 'int' + if item.value and isinstance(item.value, ast.Constant): + if isinstance(item.value.value, float): + InferredType = 'float' + elif isinstance(item.value.value, bool): + InferredType = 'bool' + elif isinstance(item.value.value, str): + InferredType = 'str' + lines.append(f'{MemberIndent}{attr_name}: {InferredType}') + else: + HasMembers = True + MemberIndent = IndentStr + ' ' + if SourceLines and hasattr(item, 'lineno'): + StartLine = item.lineno - 1 + EndLine = item.EndLineno if hasattr(item, 'EndLineno') and item.EndLineno else StartLine + 1 + for i in range(StartLine, min(EndLine, len(SourceLines))): + lines.append(MemberIndent + SourceLines[i].lstrip()) + elif isinstance(item, ast.AnnAssign): + HasMembers = True + TypeStr = PythonToStubConverter._GetTypeString(item.annotation) + MemberIndent = IndentStr + ' ' + # 检查是否是宏变量(类型包含 t.CDefine) + if 't.CDefine' in TypeStr: + # 检查宏变量是否应该被排除 + if isinstance(item.target, ast.Name): + MacroName = item.target.id + if PythonToStubConverter._ShouldExcludeMacro(MacroName): + continue # 跳过该宏 + # 宏变量保持原样(包括赋值) + if SourceLines and hasattr(item, 'lineno'): + StartLine = item.lineno - 1 + EndLine = item.EndLineno if hasattr(item, 'EndLineno') and item.EndLineno else StartLine + 1 + for i in range(StartLine, min(EndLine, len(SourceLines))): + lines.append(MemberIndent + SourceLines[i].lstrip()) + else: + lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}') + else: + if isinstance(item.target, ast.Attribute): + MemberName = item.target.attr + else: + MemberName = item.target.id + FinalTypeStr = TypeStr + if (isinstance(item.annotation, ast.Subscript) + and isinstance(item.annotation.value, ast.Name) + and item.annotation.value.id == 'list'): + slice_node = item.annotation.slice + has_size = False + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + count_node = slice_node.elts[1] + if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0: + has_size = True + else: + try: + count_expr = ast.unparse(count_node) + except Exception: + count_expr = '' + if count_expr and count_expr != 'None': + has_size = True + elem_type_str = PythonToStubConverter._GetTypeString(slice_node.elts[0]) + FinalTypeStr = f'list[{elem_type_str}, {count_expr}]' + if not has_size: + elem_type_str = PythonToStubConverter._GetTypeString(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0]) + init_len = 0 + if item.value is not None: + if isinstance(item.value, ast.List): + init_len = len(item.value.elts) + elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): + init_len = len(item.value.value) + 1 + if init_len > 0: + FinalTypeStr = f'list[{elem_type_str}, {init_len}]' + else: + FinalTypeStr = f'list[{elem_type_str}, None]' + lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr}') + elif isinstance(item, ast.FunctionDef): + HasMembers = True + FuncStub = PythonToStubConverter._ConvertFunction(item, indent=indent+1, SourceLines=SourceLines, class_name=node.name) + lines.extend(FuncStub) + elif isinstance(item, ast.Expr): + # 处理宏调用,如 c.CIf(...), c.CEndif(), c.CElif(), c.CElse() + ExprStr = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + lines.append(f'{IndentStr} {ExprStr}') + elif isinstance(item, ast.If): + # 处理 if c.CIf(...): 形式的宏条件 + IfStr = PythonToStubConverter._get_if_macro_string(item, indent=indent+1) + if IfStr: + lines.append(IfStr) + elif isinstance(item, ast.ClassDef): + # 处理嵌套类 + HasMembers = True + NestedClassLines = PythonToStubConverter._ConvertClass(item, SourceLines=SourceLines, PostdefVars=[], indent=indent+1) + # 移除嵌套类的宏守卫(因为已经在父类的宏守卫内) + FilteredLines = [] + for line in NestedClassLines: + # 跳过宏守卫相关行 + if line.strip().startswith('c.CIfndef(') or line.strip().startswith('c.CEndif()'): + continue + if ': t.CDefine' in line and '__' in line: + continue + FilteredLines.append(line) + lines.extend(FilteredLines) + + if not HasMembers: + lines.append(f'{IndentStr} pass') + + # 添加 Postdefinition 变量 + if PostdefVars: + lines.append('') + for VarName, TypeStr, _ in PostdefVars: + lines.append(f'{VarName}: {TypeStr}') + + return lines + + @staticmethod + def _ConvertFunction(node: ast.FunctionDef, indent: int = 0, SourceLines: List[str] = None, class_name: str = None) -> List[str]: + """转换函数定义""" + lines = [] + IndentStr = ' ' * indent + + # 检查是否是宏函数(返回类型包含 t.CDefine) + is_macro_func = False + if node.returns: + ReturnType = PythonToStubConverter._GetTypeString(node.returns) + if 't.CDefine' in ReturnType: + is_macro_func = True + + # 如果是宏函数,检查是否应该被排除 + if is_macro_func: + if PythonToStubConverter._ShouldExcludeMacro(node.name): + return lines # 返回空列表,排除该宏 + + # 保持原样(包括代码块) + if SourceLines: + StartLine = node.lineno - 1 + EndLine = node.EndLineno if hasattr(node, 'EndLineno') and node.EndLineno else StartLine + 1 + for i in range(StartLine, min(EndLine, len(SourceLines))): + lines.append(SourceLines[i]) + if lines and lines[-1].strip() and not lines[-1].rstrip().endswith(':'): + pass + else: + lines.append(f'{IndentStr} pass') + return lines + + # 处理函数装饰器 + for decorator in node.decorator_list: + DecoratorStr = PythonToStubConverter._GetDecoratorString(decorator) + if DecoratorStr: + lines.append(f'{IndentStr}@{DecoratorStr}') + + # 构建参数列表 + params = [] + for arg_idx, arg in enumerate(node.args.args): + ArgName = arg.arg + if arg.annotation: + TypeStr = PythonToStubConverter._GetTypeString(arg.annotation) + params.append(f'{ArgName}: {TypeStr}') + elif class_name and arg_idx == 0 and ArgName == 'self': + params.append(f'self: {class_name}') + else: + params.append(ArgName) + + # 处理 *args + if node.args.vararg: + ArgName = node.args.vararg.arg + if node.args.vararg.annotation: + TypeStr = PythonToStubConverter._GetTypeString(node.args.vararg.annotation) + params.append(f'*{ArgName}: {TypeStr}') + else: + params.append(f'*{ArgName}') + + # 处理 **kwargs + if node.args.kwarg: + ArgName = node.args.kwarg.arg + if node.args.kwarg.annotation: + TypeStr = PythonToStubConverter._GetTypeString(node.args.kwarg.annotation) + params.append(f'**{ArgName}: {TypeStr}') + else: + params.append(f'**{ArgName}') + + ParamStr = ', '.join(params) + + # 返回类型 - 保持原始类型(不添加t.State) + if node.returns: + ReturnType = PythonToStubConverter._GetTypeString(node.returns) + else: + ReturnType = 't.CInt' + + TypeParamStr = '' + if hasattr(node, 'type_params') and node.type_params: + param_names = [tp.name for tp in node.type_params] + TypeParamStr = f'[{", ".join(param_names)}]' + + lines.append(f'{IndentStr}def {node.name}{TypeParamStr}({ParamStr}) -> {ReturnType}: pass') + return lines + + @staticmethod + def _ConvertVariable(node: ast.AnnAssign, SourceLines: List[str] = None) -> List[str]: + """转换变量定义""" + lines = [] + if isinstance(node.target, ast.Name): + VarName = node.target.id + TypeStr = PythonToStubConverter._GetTypeString(node.annotation) + # 检查是否是宏变量(类型包含 t.CDefine) + if 't.CDefine' in TypeStr: + # 检查宏变量是否应该被排除 + if PythonToStubConverter._ShouldExcludeMacro(VarName): + return lines # 返回空列表,排除该宏 + # 宏变量保持原样(包括赋值) + if SourceLines and hasattr(node, 'lineno'): + StartLine = node.lineno - 1 + EndLine = node.EndLineno if hasattr(node, 'EndLineno') and node.EndLineno else StartLine + 1 + for i in range(StartLine, min(EndLine, len(SourceLines))): + lines.append(SourceLines[i]) + else: + lines.append(f'{VarName}: {TypeStr}') + return lines + # 非宏变量:不加 t.State + # 含有 typedef 的变量不加 extern,普通变量需要加 extern + has_typedef = 't.CTypedef' in TypeStr or 'CTypedef' in TypeStr + if has_typedef and node.value is not None: + ValueTypeStr = PythonToStubConverter._GetTypeString(node.value) + lines.append(f'{VarName}: {TypeStr} = {ValueTypeStr}') + else: + if not has_typedef and 't.CExtern' not in TypeStr and 't.CStatic' not in TypeStr: + TypeStr = f't.CExtern | {TypeStr}' + lines.append(f'{VarName}: {TypeStr}') + return lines + + @staticmethod + def _ConvertGlobalAssign(node: ast.Assign) -> List[str]: + """转换模块级别的全局变量(无类型标注)""" + lines = [] + if not node.targets or not isinstance(node.targets[0], ast.Name): + return lines + + VarName = node.targets[0].id + + # 跳过私有变量(以下划线开头) + if VarName.startswith('_'): + return lines + + # 从值推断类型 + inferred_type = PythonToStubConverter._InferTypeFromValue(node.value) + if inferred_type: + lines.append(f'{VarName}: {inferred_type}') + else: + lines.append(f'{VarName}: t.CInt') + + return lines + + @staticmethod + def _InferTypeFromValue(value: ast.AST) -> str: + """从值推断 C 类型""" + if isinstance(value, ast.Constant): + if isinstance(value.value, int): + return 't.CInt' + elif isinstance(value.value, float): + return 't.CDouble' + elif isinstance(value.value, str): + return 't.CCharPtr' + elif isinstance(value.value, bool): + return 't.CInt' + elif isinstance(value, ast.List): + return 't.CVoidPtr' + elif isinstance(value, ast.Dict): + return 't.CVoidPtr' + elif isinstance(value, ast.Name): + return 't.CInt' + elif isinstance(value, ast.BinOp): + left_type = PythonToStubConverter._InferTypeFromValue(value.left) + if left_type: + return left_type + return 't.CInt' + elif isinstance(value, ast.Call): + # 函数调用返回值,假设为指针类型 + if isinstance(value.func, ast.Name): + func_name = value.func.id + if func_name == 'malloc': + return 't.CVoidPtr' + elif func_name in ('ctypes.cast', 'cast'): + return 't.CVoidPtr' + return 't.CVoidPtr' + return None + + @staticmethod + def _GetTypeString(annotation: ast.AST) -> str: + """获取类型字符串""" + if isinstance(annotation, ast.Name): + return annotation.id + elif isinstance(annotation, ast.Attribute): + if isinstance(annotation.value, ast.Name): + return f'{annotation.value.id}.{annotation.attr}' + else: + # 处理嵌套属性访问,如 t.attr.packed + ParentStr = PythonToStubConverter._GetTypeString(annotation.value) + return f'{ParentStr}.{annotation.attr}' + elif isinstance(annotation, ast.Subscript): + base = PythonToStubConverter._GetTypeString(annotation.value) + if isinstance(annotation.slice, ast.Tuple): + slice_strs = [PythonToStubConverter._GetTypeString(e) for e in annotation.slice.elts] + SliceStr = ', '.join(slice_strs) + else: + SliceStr = PythonToStubConverter._GetTypeString(annotation.slice) + return f'{base}[{SliceStr}]' + elif isinstance(annotation, ast.BinOp): + # 处理 BinOp,如 t.CExtern | fd_table.__set_default__(...) + left = annotation.left + right = annotation.right + + # 检查右侧是否是 __set_default__ 调用 + if isinstance(right, ast.Call) and isinstance(right.func, ast.Attribute) and right.func.attr in ('__set_default__', '__set_default'): + # 去除 __set_default__,保留左侧,右侧替换为函数名部分 + LeftStr = PythonToStubConverter._GetTypeString(left) + RightStr = PythonToStubConverter._GetTypeString(right.func.value) + if isinstance(annotation.op, ast.BitOr): + return f'{LeftStr} | {RightStr}' + + LeftStr = PythonToStubConverter._GetTypeString(left) + RightStr = PythonToStubConverter._GetTypeString(right) + if isinstance(annotation.op, ast.BitOr): + return f'{LeftStr} | {RightStr}' + elif isinstance(annotation.op, ast.Add): + return f'{LeftStr} + {RightStr}' + elif isinstance(annotation.op, ast.Sub): + return f'{LeftStr} - {RightStr}' + elif isinstance(annotation.op, ast.Mult): + return f'{LeftStr} * {RightStr}' + elif isinstance(annotation.op, ast.Div): + return f'{LeftStr} / {RightStr}' + elif isinstance(annotation.op, ast.Mod): + return f'{LeftStr} % {RightStr}' + elif isinstance(annotation, ast.UnaryOp): + if isinstance(annotation.op, ast.Not): + operand = PythonToStubConverter._GetTypeString(annotation.operand) + return f'not {operand}' + elif isinstance(annotation.op, ast.Invert): + operand = PythonToStubConverter._GetTypeString(annotation.operand) + return f'~{operand}' + elif isinstance(annotation.op, ast.USub): + operand = PythonToStubConverter._GetTypeString(annotation.operand) + return f'-{operand}' + elif isinstance(annotation, ast.Compare): + # 处理比较操作,如 FF_MAX_SS != FF_MIN_SS + left = PythonToStubConverter._GetTypeString(annotation.left) + comparators = [PythonToStubConverter._GetTypeString(c) for c in annotation.comparators] + ops = [] + for op in annotation.ops: + if isinstance(op, ast.Eq): + ops.append('==') + elif isinstance(op, ast.NotEq): + ops.append('!=') + elif isinstance(op, ast.Lt): + ops.append('<') + elif isinstance(op, ast.LtE): + ops.append('<=') + elif isinstance(op, ast.Gt): + ops.append('>') + elif isinstance(op, ast.GtE): + ops.append('>=') + else: + ops.append('?') + result = left + for i, op in enumerate(ops): + result += f' {op} {comparators[i]}' + return result + elif isinstance(annotation, ast.Constant): + return repr(annotation.value) + elif isinstance(annotation, ast.Index): + return PythonToStubConverter._GetTypeString(annotation.value) + elif isinstance(annotation, ast.List): + # 处理列表,如 [MAX_FILE_DESCRIPTORS] + elements = [PythonToStubConverter._GetTypeString(elem) for elem in annotation.elts] + return f'[{", ".join(elements)}]' + elif isinstance(annotation, ast.Call): + # 处理函数调用形式的类型注解,如 t.Postdefinition(xxa) 或 callable(t.CVoid, app_id = t.CInt) + # 如果是 __set_default__ 调用,只返回函数名部分 + if isinstance(annotation.func, ast.Attribute) and annotation.func.attr in ('__set_default__', '__set_default'): + return PythonToStubConverter._GetTypeString(annotation.func.value) + + FuncStr = PythonToStubConverter._GetTypeString(annotation.func) + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in annotation.args]) + # 处理关键字参数 + keywords_str = ', '.join([f'{kw.arg} = {PythonToStubConverter._GetTypeString(kw.value)}' for kw in annotation.keywords]) + # 合并位置参数和关键字参数 + if ArgsStr and keywords_str: + return f'{FuncStr}({ArgsStr}, {keywords_str})' + elif keywords_str: + return f'{FuncStr}({keywords_str})' + else: + return f'{FuncStr}({ArgsStr})' + return 't.CVoid' + + @staticmethod + def _ExtractPostdefClass(annotation: ast.AST) -> Optional[str]: + """从 Postdefinition 类型注解中提取类名 + + 例如:t.Postdefinition(__buddy_system) -> '__buddy_system' + t.Postdefinition(xxx) | t.CTypedef -> 'xxx' + """ + # 处理 BinOp (如: t.Postdefinition(xxx) | t.CTypedef) + if isinstance(annotation, ast.BinOp): + # 递归检查左操作数 + left_result = PythonToStubConverter._ExtractPostdefClass(annotation.left) + if left_result: + return left_result + # 递归检查右操作数 + right_result = PythonToStubConverter._ExtractPostdefClass(annotation.right) + if right_result: + return right_result + return None + + # 处理函数调用 (如: t.Postdefinition(__buddy_system)) + if isinstance(annotation, ast.Call): + FuncStr = PythonToStubConverter._GetTypeString(annotation.func) + if FuncStr == 't.Postdefinition' and annotation.args: + # 提取第一个参数 + first_arg = annotation.args[0] + if isinstance(first_arg, ast.Name): + return first_arg.id + elif isinstance(first_arg, ast.Attribute): + return f'{first_arg.value.id}.{first_arg.attr}' + + return None + + @staticmethod + def _GetImportString(node: ast.Import, SourceLines: List[str] = None) -> str: + """获取导入语句字符串""" + parts = [] + IncludeAliasMap = PythonToStubConverter.IncludeAliasMap + + for alias in node.names: + ModuleName = alias.name + # 检查是否是 __include.xxx 格式的导入 + if ModuleName.startswith('__include.'): + # 提取别名(xxx 部分) + SubModule = ModuleName[len('__include.'):] + if SubModule in IncludeAliasMap: + # 替换为实际模块路径 + RealModule = IncludeAliasMap[SubModule] + if alias.asname: + parts.append(f'{RealModule} as {alias.asname}') + else: + parts.append(f'{RealModule} as {SubModule}') + else: + # 不在映射表中,保持原样 + if alias.asname: + parts.append(f'{ModuleName} as {alias.asname}') + else: + parts.append(ModuleName) + else: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + + result = f'import {", ".join(parts)}' + + # 提取并保留注释 + if SourceLines and hasattr(node, 'lineno'): + LineIdx = node.lineno - 1 + if 0 <= LineIdx < len(SourceLines): + line = SourceLines[LineIdx] + CommentMatch = re.search(r'#.*$', line) + if CommentMatch: + result += ' ' + CommentMatch.group(0) + + return result + + @staticmethod + def _GetImportFromString(node: ast.ImportFrom, SourceLines: List[str] = None) -> str: + """获取 from ... import ... 语句字符串""" + module = node.module or '' + parts = [] + IncludeAliasMap = PythonToStubConverter.IncludeAliasMap + + # 处理相对导入 (from . import xxx 或 from ..package import xxx) + if node.level > 0: + if module: + if node.level == 1: + full_module = f'.{module}' + else: + full_module = '.' * node.level + module + else: + full_module = '.' * node.level + for alias in node.names: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + return f'from {full_module} import {", ".join(parts)}' + + # 提取注释(在生成结果前获取) + comment = '' + if SourceLines and hasattr(node, 'lineno'): + LineIdx = node.lineno - 1 + if 0 <= LineIdx < len(SourceLines): + line = SourceLines[LineIdx] + CommentMatch = re.search(r'#.*$', line) + if CommentMatch: + comment = ' ' + CommentMatch.group(0) + + # 检查是否是 from __include import xxx 格式 + if module == '__include': + for alias in node.names: + name = alias.name + if name in IncludeAliasMap: + # 替换为实际模块路径 + RealModule = IncludeAliasMap[name] + if alias.asname: + parts.append(f'import {RealModule} as {alias.asname}{comment}') + else: + parts.append(f'import {RealModule} as {name}{comment}') + else: + # 不在映射表中,保持原样 + if alias.asname: + parts.append(f'from {module} import {name} as {alias.asname}{comment}') + else: + parts.append(f'from {module} import {name}{comment}') + return '\n'.join(parts) + + # 普通 from ... import ... 语句 + for alias in node.names: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + return f'from {module} import {", ".join(parts)}{comment}' + + @staticmethod + def _GetDecoratorString(decorator: ast.AST) -> str: + """获取装饰器字符串""" + if isinstance(decorator, ast.Name): + return decorator.id + elif isinstance(decorator, ast.Attribute): + if isinstance(decorator.value, ast.Name): + return f'{decorator.value.id}.{decorator.attr}' + return decorator.attr + elif isinstance(decorator, ast.Call): + # 处理带参数的装饰器,如 @c.Attribute(t.attr.packed) + FuncStr = PythonToStubConverter._GetDecoratorString(decorator.func) + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in decorator.args]) + return f'{FuncStr}({ArgsStr})' + return '' + + @staticmethod + def _GetExprString(expr: ast.AST) -> str: + """获取表达式字符串(用于宏调用)""" + if isinstance(expr, ast.Call): + # 处理函数调用,如 c.CIf(...), c.CEndif(), c.CUndef(...), c.CPragma(...) + FuncStr = PythonToStubConverter._GetDecoratorString(expr.func) + if FuncStr and ('CIf' in FuncStr or 'CEndif' in FuncStr or 'CElif' in FuncStr or 'CElse' in FuncStr or 'CUndef' in FuncStr or 'CPragma' in FuncStr): + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in expr.args]) + return f'{FuncStr}({ArgsStr})' if ArgsStr else f'{FuncStr}()' + return '' + + @staticmethod + def _get_if_macro_string(node: ast.If, indent: int = 1) -> str: + """获取类内部的 if 宏字符串(如 if c.CIf(...):)""" + IndentStr = ' ' * indent + InnerIndent = ' ' * (indent + 1) + # 检查条件是否是宏调用 + if isinstance(node.test, ast.Call): + FuncStr = PythonToStubConverter._GetDecoratorString(node.test.func) + if FuncStr and 'CIf' in FuncStr: + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) + result = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] + # 处理 if 体内的语句 + for item in node.body: + if isinstance(item, ast.AnnAssign): + TypeStr = PythonToStubConverter._GetTypeString(item.annotation) + result.append(f'{InnerIndent}{item.target.id}: {TypeStr}') + elif isinstance(item, ast.Expr): + ExprStr = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + result.append(f'{InnerIndent}{ExprStr}') + return '\n'.join(result) + return '' + + @staticmethod + def _GetModuleIfMacroString(node: ast.If) -> str: + """获取模块级别的 if 宏字符串(如 if c.CIf(FF_MULTI_PARTITION):)""" + return PythonToStubConverter._ProcessIfMacro(node, indent=0) + + @staticmethod + def _ProcessIfMacro(node: ast.If, indent: int = 0) -> str: + """处理 if 宏节点,支持 elif 和 else""" + IndentStr = ' ' * indent + + # 检查条件是否是宏调用 + if isinstance(node.test, ast.Call): + FuncStr = PythonToStubConverter._GetDecoratorString(node.test.func) + if FuncStr and 'CIf' in FuncStr: + ArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) + result = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] + # 处理 if 体内的语句 + for item in node.body: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + + # 处理 elif 和 else + current = node + while current.orelse: + if len(current.orelse) == 1 and isinstance(current.orelse[0], ast.If): + # elif 情况 + elif_node = current.orelse[0] + if isinstance(elif_node.test, ast.Call): + ElifFuncStr = PythonToStubConverter._GetDecoratorString(elif_node.test.func) + if ElifFuncStr and 'CIf' in ElifFuncStr: + ElifArgsStr = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in elif_node.test.args]) + result.append(f'{IndentStr}elif {ElifFuncStr}({ElifArgsStr}):' if ElifArgsStr else f'{IndentStr}elif {ElifFuncStr}():') + for item in elif_node.body: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + current = elif_node + continue + break + else: + # else 情况 + result.append(f'{IndentStr}else:') + for item in current.orelse: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + break + + return '\n'.join(result) + return '' + + @staticmethod + def _ProcessMacroBodyItem(item: ast.AST, indent: int = 0) -> list: + """处理宏体内的单个语句""" + IndentStr = ' ' * indent + result = [] + + if isinstance(item, ast.ClassDef): + class_stub = PythonToStubConverter._ConvertClass(item) + for line in class_stub: + if line.strip(): + result.append(f'{IndentStr}{line}') + else: + result.append(line) + elif isinstance(item, ast.FunctionDef): + FuncStub = PythonToStubConverter._ConvertFunction(item, indent=indent) + result.extend(FuncStub) + elif isinstance(item, ast.AnnAssign): + TypeStr = PythonToStubConverter._GetTypeString(item.annotation) + result.append(f'{IndentStr}{item.target.id}: {TypeStr}') + elif isinstance(item, ast.Expr): + ExprStr = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + result.append(f'{IndentStr}{ExprStr}') + elif isinstance(item, ast.If): + # 处理嵌套的 if 宏 + NestedIf = PythonToStubConverter._ProcessIfMacro(item, indent=indent) + if NestedIf: + result.append(NestedIf) + + return result + + +class StubGen: + """存根生成器主类""" + + def __init__(self, config: StubGenConfig): + self.config = config + self.logger = self._SetupLogger() + self.GeneratedFiles: List[str] = [] + self.FailedFiles: List[str] = [] + + # 应用自定义类型映射 + if config.TypeMappings: + CTypeMapper.BASIC_TYPE_MAP.update(config.TypeMappings) + + def _SetupLogger(self) -> logging.Logger: + """设置日志""" + logger = logging.getLogger('StubGen') + logger.setLevel(logging.DEBUG if self.config.verbose else logging.INFO) + + if not logger.handlers: + handler = logging.StreamHandler(sys.stdout) + formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + handler.setFormatter(formatter) + logger.addHandler(handler) + + return logger + + def FindInputFiles(self) -> List[Tuple[str, str]]: + """查找输入文件,返回 (文件路径, 相对路径) 列表""" + files = [] + + # 添加显式指定的文件 + for FilePath in self.config.InputFiles: + if os.path.exists(FilePath): + RelPath = os.path.relpath(FilePath, self.config.InputDir or '.') + files.append((FilePath, RelPath)) + else: + self.logger.warning(f"Input file not found: {FilePath}") + + # 从输入目录查找 + if self.config.InputDir and os.path.exists(self.config.InputDir): + InputPath = Path(self.config.InputDir) + for pattern in self.config.IncludePatterns: + for FilePath in InputPath.rglob(pattern): + # 检查是否在排除列表中 + excluded = False + RelPath = os.path.relpath(str(FilePath), self.config.InputDir) + + for exclude_pattern in self.config.ExcludePatterns: + if FilePath.match(exclude_pattern) or RelPath == exclude_pattern: + excluded = True + break + + if not excluded: + files.append((str(FilePath), RelPath)) + + # 去重并保持顺序 + seen = set() + UniqueFiles = [] + for FilePath, RelPath in files: + key = FilePath + if key not in seen: + seen.add(key) + UniqueFiles.append((FilePath, RelPath)) + + return UniqueFiles + + def _GenerateGuardName(self, FilePath: str) -> str: + """生成宏守卫名称""" + # 获取文件名(不含扩展名) + BaseName = os.path.splitext(os.path.basename(FilePath))[0] + + # 转换为大写,替换特殊字符为下划线 + guard = re.sub(r'[^a-zA-Z0-9_]', '_', BaseName).upper() + guard = re.sub(r'_+', '_', guard) # 合并多个下划线 + guard = guard.strip('_') + + return f'{guard}_DEFINE_H' + + def _GetOutputPath(self, RelPath: str) -> str: + """获取输出文件路径""" + # 更改扩展名为 .pyi (Python stub file) + BaseName = os.path.splitext(RelPath)[0] + OutputRelPath = BaseName + '.pyi' + + # 构建完整输出路径 + if self.config.OutputDir: + OutputPath = os.path.join(self.config.OutputDir, OutputRelPath) + else: + OutputPath = OutputRelPath + + return OutputPath + + def GenerateStub(self, InputFile: str, RelPath: str) -> bool: + """生成单个存根文件""" + try: + self.logger.info(f"Processing: {InputFile}") + + # 确定输出文件路径 + OutputFile = self._GetOutputPath(RelPath) + + # 确保输出目录存在 + OutputDir = os.path.dirname(OutputFile) + if OutputDir and not os.path.exists(OutputDir): + if not self.config.DryRun: + os.makedirs(OutputDir, exist_ok=True) + self.logger.debug(f"Created directory: {OutputDir}") + + if self.config.DryRun: + self.logger.info(f"[DRY RUN] Would generate: {OutputFile}") + return True + + # 根据文件类型选择处理方式 + ext = os.path.splitext(InputFile)[1].lower() + + if ext in ['.h', '.c']: + # C 文件:使用 CHeaderParser + content = self._GenerateFromC(InputFile, RelPath) + elif ext == '.py': + # Python 文件:使用 PythonToStubConverter + content = self._GenerateFromPy(InputFile, RelPath) + else: + self.logger.warning(f"Unsupported file type: {ext}") + return False + + # 写入文件 + with open(OutputFile, 'w', encoding='utf-8') as f: + f.write(content) + + self.GeneratedFiles.append(OutputFile) + self.logger.info(f"Generated: {OutputFile}") + return True + + except Exception as e: + self.logger.error(f"Failed to process {InputFile}: {e}") + import traceback + traceback.print_exc() + self.FailedFiles.append(InputFile) + return False + + def _GenerateFromC(self, InputFile: str, RelPath: str) -> str: + """从 C 文件生成存根""" + parser = CHeaderParser() + parser.parse_file(InputFile) + + generator = PythonStubGenerator(parser) + ModuleName = os.path.splitext(os.path.basename(InputFile))[0] + content = generator.generate(ModuleName) + + # 添加宏守卫(如果需要) + if self.config.GenerateGuards: + guard_name = self._GenerateGuardName(InputFile) + guard_comment = f"\n# Guard: {guard_name}\n" + content = content + guard_comment + + return content + + def _GenerateFromPy(self, InputFile: str, RelPath: str) -> str: + """从 Python 文件生成存根""" + with open(InputFile, 'r', encoding='utf-8') as f: + PyContent = f.read() + + ModuleName = os.path.splitext(os.path.basename(InputFile))[0] + content = PythonToStubConverter.convert(PyContent, ModuleName) + + # 添加宏守卫(如果需要) + if self.config.GenerateGuards: + guard_name = self._GenerateGuardName(InputFile) + guard_comment = f"\n# Guard: {guard_name}\n" + content = content + guard_comment + + return content + + def run(self) -> bool: + """运行生成器""" + self.logger.info("=" * 60) + self.logger.info("StubGen - C/H/Py to Python Stub Generator") + self.logger.info("=" * 60) + + # 查找输入文件 + InputFiles = self.FindInputFiles() + + if not InputFiles: + self.logger.warning("No input files found!") + return False + + self.logger.info(f"Found {len(InputFiles)} input file(s)") + for FilePath, RelPath in InputFiles: + self.logger.debug(f" - {RelPath}") + + # 处理每个文件 + SuccessCount = 0 + for FilePath, RelPath in InputFiles: + if self.GenerateStub(FilePath, RelPath): + SuccessCount += 1 + + # 输出统计信息 + self.logger.info("=" * 60) + self.logger.info(f"Summary: {SuccessCount}/{len(InputFiles)} files generated successfully") + + if self.FailedFiles: + self.logger.warning(f"Failed files ({len(self.FailedFiles)}):") + for f in self.FailedFiles: + self.logger.warning(f" - {f}") + + return SuccessCount == len(InputFiles) + + +def main(): + parser = argparse.ArgumentParser( + description='StubGen - Generate Python stub files from C/H/Py sources', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=''' +Examples: + # 使用配置文件 + %(prog)s -c config.json + + # 处理单个文件 + %(prog)s -i input.h -o output.py + + # 批量处理目录(保持目录结构) + %(prog)s -d ./kernel -o ./kernel/include + + # 干运行(不实际生成文件) + %(prog)s -d ./kernel --dry-run + + # 不生成宏守卫 + %(prog)s -d ./kernel --no-guards + ''' + ) + + # 输入选项 + InputGroup = parser.add_mutually_exclusive_group(required=True) + InputGroup.add_argument('-c', '--config', help='Configuration file (JSON)') + InputGroup.add_argument('-i', '--input', help='Input file') + InputGroup.add_argument('-d', '--directory', help='Input directory') + + # 输出选项 + parser.add_argument('-o', '--output', help='Output directory') + + # 其他选项 + parser.add_argument('--include', action='append', + help='Include patterns (default: *.h, *.c, *.py)') + parser.add_argument('--exclude', action='append', + help='Exclude patterns') + parser.add_argument('--no-guards', action='store_true', + help='Do not generate guard macros') + parser.add_argument('--no-structure', action='store_true', + help='Do not preserve directory structure') + parser.add_argument('-v', '--verbose', action='store_true', + help='Verbose output') + parser.add_argument('--dry-run', action='store_true', + help='Dry run (do not create files)') + + args = parser.parse_args() + + # 加载配置 + if args.config: + if not os.path.exists(args.config): + print(f"Error: Config file not found: {args.config}") + sys.exit(1) + config = StubGenConfig.from_file(args.config) + else: + config = StubGenConfig() + config.IncludePatterns = args.include or ['*.h', '*.c', '*.py'] + config.ExcludePatterns = args.exclude or [] + config.GenerateGuards = not args.no_guards + config.PreserveStructure = not args.no_structure + config.verbose = args.verbose + config.DryRun = args.dry_run + + if args.input: + config.InputFiles = [args.input] + if args.output: + config.OutputDir = os.path.dirname(args.output) or '.' + elif args.directory: + config.InputDir = args.directory + if args.output: + config.OutputDir = args.output + + # 创建生成器并运行 + generator = StubGen(config) + + # 如果指定了单个输出文件,直接处理 + if args.input and args.output and not os.path.isdir(args.output): + RelPath = os.path.relpath(args.input, config.InputDir or '.') + success = generator.GenerateStub(args.input, RelPath) + else: + success = generator.run() + + sys.exit(0 if success else 1) + + +if __name__ == '__main__': + main() diff --git a/TODO b/TODO new file mode 100644 index 0000000..0f257e9 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +更复杂的 泛型 +函数装饰器 +main 收集 +元类型 +@p.set + diff --git a/Test/BuiltinDecoratorTest/App/main.py b/Test/BuiltinDecoratorTest/App/main.py new file mode 100644 index 0000000..be3bbb9 --- /dev/null +++ b/Test/BuiltinDecoratorTest/App/main.py @@ -0,0 +1,271 @@ +import t +from stdint import * +from stdio import printf + +# ============================================================ +# 测试计数器 +# ============================================================ +_pass_count: t.CInt = 0 +_fail_count: t.CInt = 0 + +def check(name: t.CChar | t.CPtr, condition: bool): + global _pass_count, _fail_count + if condition: + _pass_count += 1 + printf(" [PASS] %s\n", name) + else: + _fail_count += 1 + printf(" [FAIL] %s\n", name) + + +# ============================================================ +# 测试 1:@property getter +# ============================================================ +class Rect: + width: t.CInt + height: t.CInt + + def __init__(self, w: t.CInt, h: t.CInt): + self.width = w + self.height = h + + @property + def area(self) -> t.CInt: + return self.width * self.height + + @property + def is_square(self) -> bool: + return self.width == self.height + + +def test_property_getter(): + printf("\n+-- @property getter --+\n") + r: Rect = Rect(3, 4) + check("area == 12", r.area == 12) + check("not square", not r.is_square) + r2: Rect = Rect(5, 5) + check("square area == 25", r2.area == 25) + check("is_square", r2.is_square) + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 2:@property.setter +# ============================================================ +class Temperature: + _celsius: t.CDouble + + def __init__(self, c: t.CDouble): + self._celsius = c + + @property + def celsius(self) -> t.CDouble: + return self._celsius + + @celsius.setter + def celsius(self, val: t.CDouble): + self._celsius = val + + @property + def fahrenheit(self) -> t.CDouble: + return self._celsius * 1.8 + 32.0 + + +def test_property_setter(): + printf("\n+-- @property.setter --+\n") + t1: Temperature = Temperature(0.0) + check("0C == 32F", t1.fahrenheit > 31.9 and t1.fahrenheit < 32.1) + t1.celsius = 100.0 + check("100C == 212F", t1.fahrenheit > 211.9 and t1.fahrenheit < 212.1) + check("celsius == 100", t1.celsius > 99.9 and t1.celsius < 100.1) + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 3:@property.getter(重新定义 getter) +# ============================================================ +class Counter: + _count: t.CInt + + def __init__(self): + self._count = 0 + + @property + def value(self) -> t.CInt: + return self._count + + @value.setter + def value(self, v: t.CInt): + self._count = v + + +def test_property_getter_redef(): + printf("\n+-- @property.getter redef --+\n") + c: Counter = Counter() + check("init == 0", c.value == 0) + c.value = 42 + check("set == 42", c.value == 42) + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 4:@property.deleter +# ============================================================ +class Config: + _value: t.CInt + _deleted: t.CInt + + def __init__(self, v: t.CInt): + self._value = v + self._deleted = 0 + + @property + def value(self) -> t.CInt: + return self._value + + @value.setter + def value(self, v: t.CInt): + self._value = v + + @value.deleter + def value(self): + self._value = 0 + self._deleted = 1 + + def is_deleted(self) -> bool: + return self._deleted != 0 + + +def test_property_deleter(): + printf("\n+-- @property.deleter --+\n") + cfg: Config = Config(99) + check("init == 99", cfg.value == 99) + check("not deleted", not cfg.is_deleted()) + del cfg.value + check("after del == 0", cfg.value == 0) + check("is_deleted", cfg.is_deleted()) + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 5:@staticmethod +# ============================================================ +class MathUtils: + @staticmethod + def add(a: t.CInt, b: t.CInt) -> t.CInt: + return a + b + + @staticmethod + def max_val(a: t.CInt, b: t.CInt) -> t.CInt: + return a if a > b else b + + +def test_staticmethod(): + printf("\n+-- @staticmethod --+\n") + # 通过类名调用 + check("MathUtils.add(3,4)==7", MathUtils.add(3, 4) == 7) + check("MathUtils.max(5,10)==10", MathUtils.max_val(5, 10) == 10) + # 通过实例调用 + m: MathUtils = MathUtils() + check("instance.add(1,2)==3", m.add(1, 2) == 3) + check("instance.max(8,3)==8", m.max_val(8, 3) == 8) + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 6:@classmethod +# ============================================================ +class Point: + x: t.CDouble + y: t.CDouble + + def __init__(self, x: t.CDouble, y: t.CDouble): + self.x = x + self.y = y + + @classmethod + def origin(cls: Point) -> Point: + return Point(0.0, 0.0) + + @classmethod + def from_int(cls: Point, x: t.CInt, y: t.CInt) -> Point: + return Point(x * 1.0, y * 1.0) + + def dist_sq(self) -> t.CDouble: + return self.x * self.x + self.y * self.y + + +def test_classmethod(): + printf("\n+-- @classmethod --+\n") + # 通过类名调用 + p1: Point = Point.origin() + check("origin.x ~= 0", p1.x > -0.01 and p1.x < 0.01) + check("origin.y ~= 0", p1.y > -0.01 and p1.y < 0.01) + check("origin.dist ~= 0", p1.dist_sq() < 0.01) + + p2: Point = Point.from_int(3, 4) + check("from_int(3,4).x ~= 3", p2.x > 2.99 and p2.x < 3.01) + check("from_int(3,4).y ~= 4", p2.y > 3.99 and p2.y < 4.01) + check("dist_sq ~= 25", p2.dist_sq() > 24.99 and p2.dist_sq() < 25.01) + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 7:综合测试 — @property + @staticmethod + @classmethod +# ============================================================ +class Circle: + _radius: t.CDouble + + def __init__(self, r: t.CDouble): + self._radius = r + + @property + def radius(self) -> t.CDouble: + return self._radius + + @radius.setter + def radius(self, val: t.CDouble): + self._radius = val + + @property + def area(self) -> t.CDouble: + return 3.14159265 * self._radius * self._radius + + @staticmethod + def is_unit(r: t.CDouble) -> bool: + return r > 0.99 and r < 1.01 + + @classmethod + def unit(cls: Circle) -> Circle: + return Circle(1.0) + + +def test_combined(): + printf("\n+-- Combined @property + @staticmethod + @classmethod --+\n") + c: Circle = Circle.unit() + check("unit radius ~= 1", c.radius > 0.99 and c.radius < 1.01) + check("is_unit(1.0)", Circle.is_unit(1.0)) + check("not is_unit(2.0)", not Circle.is_unit(2.0)) + check("unit area ~= pi", c.area > 3.14 and c.area < 3.15) + c.radius = 2.0 + check("radius 2.0", c.radius > 1.99 and c.radius < 2.01) + check("area ~= 4pi", c.area > 12.56 and c.area < 12.58) + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 主函数 +# ============================================================ +def main() -> t.CInt | t.CExport: + printf("=== Builtin Decorator Test ===\n") + + test_property_getter() + test_property_setter() + test_property_getter_redef() + test_property_deleter() + test_staticmethod() + test_classmethod() + test_combined() + + printf("\n=== Results: %d passed, %d failed ===\n", _pass_count, _fail_count) + return 0 diff --git a/Test/BuiltinDecoratorTest/project.json b/Test/BuiltinDecoratorTest/project.json new file mode 100644 index 0000000..2a43eb5 --- /dev/null +++ b/Test/BuiltinDecoratorTest/project.json @@ -0,0 +1,28 @@ +{ + "name": "BuiltinDecoratorTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "BuiltinDecoratorTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/BuiltinDecoratorTest/temp/56cdd754a8a09347.pyi b/Test/BuiltinDecoratorTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/BuiltinDecoratorTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/BuiltinDecoratorTest/temp/73edbcf76e32d00b.pyi b/Test/BuiltinDecoratorTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/BuiltinDecoratorTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/BuiltinDecoratorTest/temp/7d5b7ce7c134ada7.pyi b/Test/BuiltinDecoratorTest/temp/7d5b7ce7c134ada7.pyi new file mode 100644 index 0000000..615ee86 --- /dev/null +++ b/Test/BuiltinDecoratorTest/temp/7d5b7ce7c134ada7.pyi @@ -0,0 +1,108 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +from stdint import * +from stdio import printf + +_pass_count: t.CExtern | t.CInt +_fail_count: t.CExtern | t.CInt + +def check(name: t.CChar | t.CPtr, condition: bool) -> t.CInt: pass + + +class Rect: + width: t.CInt + height: t.CInt + def __init__(self: Rect, w: t.CInt, h: t.CInt) -> t.CInt: pass + @property + def area(self: Rect) -> t.CInt: pass + @property + def is_square(self: Rect) -> bool: pass + +def test_property_getter() -> t.CInt: pass + + +class Temperature: + _celsius: t.CDouble + def __init__(self: Temperature, c: t.CDouble) -> t.CInt: pass + @property + def celsius(self: Temperature) -> t.CDouble: pass + @celsius.setter + def celsius(self: Temperature, val: t.CDouble) -> t.CInt: pass + @property + def fahrenheit(self: Temperature) -> t.CDouble: pass + +def test_property_setter() -> t.CInt: pass + + +class Counter: + _count: t.CInt + def __init__(self: Counter) -> t.CInt: pass + @property + def value(self: Counter) -> t.CInt: pass + @value.setter + def value(self: Counter, v: t.CInt) -> t.CInt: pass + +def test_property_getter_redef() -> t.CInt: pass + + +class Config: + _value: t.CInt + _deleted: t.CInt + def __init__(self: Config, v: t.CInt) -> t.CInt: pass + @property + def value(self: Config) -> t.CInt: pass + @value.setter + def value(self: Config, v: t.CInt) -> t.CInt: pass + @value.deleter + def value(self: Config) -> t.CInt: pass + def is_deleted(self: Config) -> bool: pass + +def test_property_deleter() -> t.CInt: pass + + +class MathUtils: + @staticmethod + def add(a: t.CInt, b: t.CInt) -> t.CInt: pass + @staticmethod + def max_val(a: t.CInt, b: t.CInt) -> t.CInt: pass + +def test_staticmethod() -> t.CInt: pass + + +class Point: + x: t.CDouble + y: t.CDouble + def __init__(self: Point, x: t.CDouble, y: t.CDouble) -> t.CInt: pass + @classmethod + def origin(cls: Point) -> Point: pass + @classmethod + def from_int(cls: Point, x: t.CInt, y: t.CInt) -> Point: pass + def dist_sq(self: Point) -> t.CDouble: pass + +def test_classmethod() -> t.CInt: pass + + +class Circle: + _radius: t.CDouble + def __init__(self: Circle, r: t.CDouble) -> t.CInt: pass + @property + def radius(self: Circle) -> t.CDouble: pass + @radius.setter + def radius(self: Circle, val: t.CDouble) -> t.CInt: pass + @property + def area(self: Circle) -> t.CDouble: pass + @staticmethod + def is_unit(r: t.CDouble) -> bool: pass + @classmethod + def unit(cls: Circle) -> Circle: pass + +def test_combined() -> t.CInt: pass + +def main() -> t.CInt | t.CExport: pass diff --git a/Test/BuiltinDecoratorTest/temp/_sha1_map.txt b/Test/BuiltinDecoratorTest/temp/_sha1_map.txt new file mode 100644 index 0000000..6a4510e --- /dev/null +++ b/Test/BuiltinDecoratorTest/temp/_sha1_map.txt @@ -0,0 +1,3 @@ +56cdd754a8a09347:includes/stdint.py +73edbcf76e32d00b:includes/stdio.py +7d5b7ce7c134ada7:main.py diff --git a/Test/CPythonTest/App/cpython.py b/Test/CPythonTest/App/cpython.py new file mode 100644 index 0000000..825ee53 --- /dev/null +++ b/Test/CPythonTest/App/cpython.py @@ -0,0 +1,25 @@ +import t, c + + +class PyObject: + ob_refcnt: t.CLong + ob_type: t.CPtr + + +def Py_Initialize() -> t.CVoid | t.CExtern: + pass + +def PyLong_FromLong(value: t.CLong) -> PyObject | t.CPtr | t.CExtern: + pass + +def PyObject_Str(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.CExtern: + pass + +def PyUnicode_AsUTF8(unicode_obj: PyObject | t.CPtr) -> str | t.CExtern: + pass + +def Py_DecRef(obj: PyObject | t.CPtr) -> t.CVoid | t.CExtern: + pass + +def Py_Finalize() -> t.CVoid | t.CExtern: + pass diff --git a/Test/CPythonTest/App/main.py b/Test/CPythonTest/App/main.py new file mode 100644 index 0000000..f0aa5e7 --- /dev/null +++ b/Test/CPythonTest/App/main.py @@ -0,0 +1,28 @@ +import t, c +from t import CInt, CPtr, CChar, CLong +import viperlib +import cpython + + +def SetDllDirectoryA(lpPathName: str | CPtr) -> CInt | t.CExtern: + pass + +def main() -> CInt | t.CExport: + SetDllDirectoryA("D:\\Python312") + + cpython.Py_Initialize() + + py_num: cpython.PyObject | t.CPtr = cpython.PyLong_FromLong(12345) + + py_str: cpython.PyObject | t.CPtr = cpython.PyObject_Str(py_num) + c_str: str = cpython.PyUnicode_AsUTF8(py_str) + print(c_str) + + cpython.Py_DecRef(py_str) + cpython.Py_DecRef(py_num) + + cpython.Py_Finalize() + return 0 + + + diff --git a/Test/CPythonTest/output/3e1c3f98e99cff7a.deps.json b/Test/CPythonTest/output/3e1c3f98e99cff7a.deps.json new file mode 100644 index 0000000..a44986b --- /dev/null +++ b/Test/CPythonTest/output/3e1c3f98e99cff7a.deps.json @@ -0,0 +1 @@ +{"viperlib": "4d342c40331fc964", "stdint": "56cdd754a8a09347", "main": "6999814920e8b3d5", "stdarg": "81ac26077a460417", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/CPythonTest/output/4d342c40331fc964.deps.json b/Test/CPythonTest/output/4d342c40331fc964.deps.json new file mode 100644 index 0000000..235982b --- /dev/null +++ b/Test/CPythonTest/output/4d342c40331fc964.deps.json @@ -0,0 +1 @@ +{"cpython": "3e1c3f98e99cff7a", "stdarg": "81ac26077a460417", "main": "93131e2ff5450838", "viperio": "d771d4d68d9e75b3"} \ No newline at end of file diff --git a/Test/CPythonTest/output/6999814920e8b3d5.deps.json b/Test/CPythonTest/output/6999814920e8b3d5.deps.json new file mode 100644 index 0000000..eb248b3 --- /dev/null +++ b/Test/CPythonTest/output/6999814920e8b3d5.deps.json @@ -0,0 +1 @@ +{"cpython": "3e1c3f98e99cff7a", "viperlib": "4d342c40331fc964", "stdint": "56cdd754a8a09347", "stdarg": "81ac26077a460417", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/CPythonTest/output/CPythonTest.exe.tmp0 b/Test/CPythonTest/output/CPythonTest.exe.tmp0 new file mode 100644 index 0000000..4b787d6 Binary files /dev/null and b/Test/CPythonTest/output/CPythonTest.exe.tmp0 differ diff --git a/Test/CPythonTest/output/c9f4be41ca1cc2b4.deps.json b/Test/CPythonTest/output/c9f4be41ca1cc2b4.deps.json new file mode 100644 index 0000000..44c72d1 --- /dev/null +++ b/Test/CPythonTest/output/c9f4be41ca1cc2b4.deps.json @@ -0,0 +1 @@ +{"cpython": "3e1c3f98e99cff7a", "viperlib": "4d342c40331fc964", "stdint": "56cdd754a8a09347", "main": "6999814920e8b3d5", "stdarg": "81ac26077a460417"} \ No newline at end of file diff --git a/Test/CPythonTest/project.json b/Test/CPythonTest/project.json new file mode 100644 index 0000000..72d58cd --- /dev/null +++ b/Test/CPythonTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "CPythonTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-L", "D:\\Python312", "-lmsvcrt", "-lucrt", "-lpthread", "D:\\Python312\\python312.dll"], + "output": "CPythonTest.exe" + }, + "includes": [ + "./includes" + ], + "target": { + "triple": "x86_64-pc-windows-msvc", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/CPythonTest/temp/3e1c3f98e99cff7a.pyi b/Test/CPythonTest/temp/3e1c3f98e99cff7a.pyi new file mode 100644 index 0000000..fd235ae --- /dev/null +++ b/Test/CPythonTest/temp/3e1c3f98e99cff7a.pyi @@ -0,0 +1,23 @@ +""" +Auto-generated Python stub file from cpython.py +Module: cpython +""" + + +import t, c + +class PyObject: + ob_refcnt: t.CLong + ob_type: t.CPtr + +def Py_Initialize() -> t.CVoid | t.CExtern | t.State: pass + +def PyLong_FromLong(value: t.CLong) -> PyObject | t.CPtr | t.CExtern | t.State: pass + +def PyObject_Str(obj: PyObject | t.CPtr) -> PyObject | t.CPtr | t.CExtern | t.State: pass + +def PyUnicode_AsUTF8(unicode_obj: PyObject | t.CPtr) -> str | t.CExtern | t.State: pass + +def Py_DecRef(obj: PyObject | t.CPtr) -> t.CVoid | t.CExtern | t.State: pass + +def Py_Finalize() -> t.CVoid | t.CExtern | t.State: pass diff --git a/Test/CPythonTest/temp/4d342c40331fc964.pyi b/Test/CPythonTest/temp/4d342c40331fc964.pyi new file mode 100644 index 0000000..aa40bc7 --- /dev/null +++ b/Test/CPythonTest/temp/4d342c40331fc964.pyi @@ -0,0 +1,19 @@ +""" +Auto-generated Python stub file from viperlib.py +Module: viperlib +""" + + +import t, c +import viperio +from stdarg import arg + +TEMP_BUF_SIZE: t.CDefine = 24 + +def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt | t.State: pass + +def sprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CVoid | t.State: pass + +def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt | t.State: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt | t.State: pass diff --git a/Test/CPythonTest/temp/56cdd754a8a09347.pyi b/Test/CPythonTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/CPythonTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/CPythonTest/temp/6999814920e8b3d5.pyi b/Test/CPythonTest/temp/6999814920e8b3d5.pyi new file mode 100644 index 0000000..1c3efa5 --- /dev/null +++ b/Test/CPythonTest/temp/6999814920e8b3d5.pyi @@ -0,0 +1,14 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +import t, c +from t import CInt, CPtr, CChar, CLong +import viperlib +import cpython + +def SetDllDirectoryA(lpPathName: str | CPtr) -> CInt | t.CExtern | t.State: pass + +def main() -> CInt | t.CExport | t.State: pass diff --git a/Test/CPythonTest/temp/81ac26077a460417.pyi b/Test/CPythonTest/temp/81ac26077a460417.pyi new file mode 100644 index 0000000..0fadcf3 --- /dev/null +++ b/Test/CPythonTest/temp/81ac26077a460417.pyi @@ -0,0 +1,20 @@ +""" +Auto-generated Python stub file from stdarg.py +Module: stdarg +""" + +import c + + +import t + +def va_start(args: t.CPtr, last_arg: t.CPtr) -> t.State | t.CExtern | t.CExport: pass + +def va_arg(args: t.CPtr, type: t.CType) -> t.CType | t.CExtern | t.CExport | t.State: pass + +def va_end(args: t.CPtr) -> t.State | t.CExtern | t.CExport: pass + + +va_list: t.CTypedef = t.CUnsignedChar | t.CPtr + +def arg(type: t.CType) -> t.State | t.CExtern | t.CExport: pass diff --git a/Test/CPythonTest/temp/93131e2ff5450838.pyi b/Test/CPythonTest/temp/93131e2ff5450838.pyi new file mode 100644 index 0000000..1c3efa5 --- /dev/null +++ b/Test/CPythonTest/temp/93131e2ff5450838.pyi @@ -0,0 +1,14 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +import t, c +from t import CInt, CPtr, CChar, CLong +import viperlib +import cpython + +def SetDllDirectoryA(lpPathName: str | CPtr) -> CInt | t.CExtern | t.State: pass + +def main() -> CInt | t.CExport | t.State: pass diff --git a/Test/CPythonTest/temp/_sha1_map.txt b/Test/CPythonTest/temp/_sha1_map.txt new file mode 100644 index 0000000..cd326f1 --- /dev/null +++ b/Test/CPythonTest/temp/_sha1_map.txt @@ -0,0 +1,6 @@ +3e1c3f98e99cff7a:cpython.py +4d342c40331fc964:includes/viperlib.py +56cdd754a8a09347:includes/stdint.py +6999814920e8b3d5:main.py +81ac26077a460417:includes/stdarg.py +c9f4be41ca1cc2b4:includes/viperio.py diff --git a/Test/CPythonTest/temp/_shared_sym.pkl b/Test/CPythonTest/temp/_shared_sym.pkl new file mode 100644 index 0000000..7e4596b Binary files /dev/null and b/Test/CPythonTest/temp/_shared_sym.pkl differ diff --git a/Test/CPythonTest/temp/c9f4be41ca1cc2b4.pyi b/Test/CPythonTest/temp/c9f4be41ca1cc2b4.pyi new file mode 100644 index 0000000..b03434d --- /dev/null +++ b/Test/CPythonTest/temp/c9f4be41ca1cc2b4.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from viperio.py +Module: viperio +""" + + +import t, c +from stdint import * + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CVoid | t.State: pass + def clear(self: Buf) -> t.CVoid | t.State: pass + def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT | t.State: pass + def cstr(self: Buf) -> t.CChar | t.CPtr | t.State: pass + def reset(self: Buf) -> t.CVoid | t.State: pass + def __enter__(self: Buf) -> 'Buf' | t.CPtr | t.State: pass + def __exit__(self: Buf) -> t.CVoid | t.State: pass + def free(self: Buf) -> t.CVoid | t.State: pass \ No newline at end of file diff --git a/Test/CPythonTest/temp/d771d4d68d9e75b3.pyi b/Test/CPythonTest/temp/d771d4d68d9e75b3.pyi new file mode 100644 index 0000000..d986947 --- /dev/null +++ b/Test/CPythonTest/temp/d771d4d68d9e75b3.pyi @@ -0,0 +1,17 @@ +""" +Auto-generated Python stub file from viperio.py +Module: viperio +""" + + +import t, c + +@t.Object +class Buf: + buf: str + length: t.CSizeT + capacity: t.CSizeT + onHeap: bool + def __init__(self: Buf, buf: str, length: t.CSizeT, onHeap: bool) -> t.CVoid | t.State: pass + def free(self: Buf) -> t.CVoid | t.State: pass + def __del__(self: Buf) -> t.CVoid | t.State: pass \ No newline at end of file diff --git a/Test/ClosureTest/App/main.py b/Test/ClosureTest/App/main.py new file mode 100644 index 0000000..1126b05 --- /dev/null +++ b/Test/ClosureTest/App/main.py @@ -0,0 +1,194 @@ +import t +import stdio + +# ============================================================ +# Test 1: global 在嵌套函数中 +# ============================================================ +g_val: t.CInt = 100 + +def outer_modify_global(): + global g_val + def inner_modify(): + global g_val + g_val += 50 + inner_modify() + +def test_global_in_nested(): + stdio.printf("--- Test 1: global in nested function ---\n") + global g_val + g_val = 100 + outer_modify_global() + if g_val == 150: + stdio.printf("PASS: global nested (g_val=%d)\n", g_val) + else: + stdio.printf("FAIL: global nested (g_val=%d, expect 150)\n", g_val) + +# ============================================================ +# Test 2: nonlocal 在多层嵌套中 +# ============================================================ +def test_nonlocal_multi_level(): + stdio.printf("--- Test 2: nonlocal multi-level ---\n") + x: t.CInt = 1 + def level1(): + nonlocal x + x += 10 + def level2(): + nonlocal x + x += 100 + def level3(): + nonlocal x + x += 1000 + level3() + level2() + level1() + if x == 1111: + stdio.printf("PASS: nonlocal multi (x=%d)\n", x) + else: + stdio.printf("FAIL: nonlocal multi (x=%d, expect 1111)\n", x) + +# ============================================================ +# Test 3: global 和 nonlocal 混合 +# ============================================================ +g_mixed: t.CInt = 0 + +def test_global_nonlocal_mixed(): + stdio.printf("--- Test 3: global + nonlocal mixed ---\n") + global g_mixed + g_mixed = 0 + local_var: t.CInt = 0 + def modify_both(): + nonlocal local_var + global g_mixed + g_mixed += 10 + local_var += 20 + modify_both() + modify_both() + if g_mixed == 20 and local_var == 40: + stdio.printf("PASS: mixed (global=%d local=%d)\n", g_mixed, local_var) + else: + stdio.printf("FAIL: mixed (global=%d local=%d, expect 20 40)\n", g_mixed, local_var) + +# ============================================================ +# Test 4: lambda 捕获多个变量 +# ============================================================ +def test_lambda_multi_capture(): + stdio.printf("--- Test 4: lambda multi-capture ---\n") + a: t.CInt = 10 + b: t.CInt = 20 + f = lambda: a + b + r: t.CInt = f() + if r == 30: + stdio.printf("PASS: lambda multi-capture (a+b=%d)\n", r) + else: + stdio.printf("FAIL: lambda multi-capture (a+b=%d, expect 30)\n", r) + +# ============================================================ +# Test 5: lambda 带参数 + 捕获 +# ============================================================ +def test_lambda_arg_capture(): + stdio.printf("--- Test 5: lambda arg + capture ---\n") + base: t.CInt = 100 + add = lambda x: base + x + r: t.CInt = add(42) + if r == 142: + stdio.printf("PASS: lambda arg+capture (100+42=%d)\n", r) + else: + stdio.printf("FAIL: lambda arg+capture (result=%d, expect 142)\n", r) + +# ============================================================ +# Test 6: 嵌套函数返回值 +# ============================================================ +def test_nested_return(): + stdio.printf("--- Test 6: nested function return ---\n") + x: t.CInt = 5 + def double_x() -> t.CInt: + nonlocal x + x = x * 2 + return x + r: t.CInt = double_x() + if r == 10 and x == 10: + stdio.printf("PASS: nested return (r=%d x=%d)\n", r, x) + else: + stdio.printf("FAIL: nested return (r=%d x=%d, expect 10 10)\n", r, x) + +# ============================================================ +# Test 7: nonlocal 与循环变量 +# ============================================================ +def test_nonlocal_loop(): + stdio.printf("--- Test 7: nonlocal with loop ---\n") + total: t.CInt = 0 + def accumulate(n: t.CInt): + nonlocal total + for i in range(n): + total += i + accumulate(5) + accumulate(5) + # 0+1+2+3+4 = 10, twice = 20 + if total == 20: + stdio.printf("PASS: nonlocal loop (total=%d)\n", total) + else: + stdio.printf("FAIL: nonlocal loop (total=%d, expect 20)\n", total) + +# ============================================================ +# Test 8: global 数组操作 +# ============================================================ +g_arr: list[t.CInt, 4] = [0] + +def test_global_array(): + stdio.printf("--- Test 8: global array ---\n") + global g_arr + g_arr[0] = 10 + g_arr[1] = 20 + g_arr[2] = 30 + g_arr[3] = 40 + total: t.CInt = g_arr[0] + g_arr[1] + g_arr[2] + g_arr[3] + if total == 100: + stdio.printf("PASS: global array (total=%d)\n", total) + else: + stdio.printf("FAIL: global array (total=%d, expect 100)\n", total) + +# ============================================================ +# Test 9: 嵌套函数条件调用 +# ============================================================ +def test_nested_conditional(): + stdio.printf("--- Test 9: nested conditional call ---\n") + result: t.CInt = 0 + def set_result(val: t.CInt): + nonlocal result + result = val + if 1: + set_result(42) + else: + set_result(99) + if result == 42: + stdio.printf("PASS: nested conditional (result=%d)\n", result) + else: + stdio.printf("FAIL: nested conditional (result=%d, expect 42)\n", result) + +# ============================================================ +# Test 10: lambda 链式调用 +# ============================================================ +def test_lambda_chain(): + stdio.printf("--- Test 10: lambda chain ---\n") + f1 = lambda: 10 + f2 = lambda: 20 + r: t.CInt = f1() + f2() + if r == 30: + stdio.printf("PASS: lambda chain (10+20=%d)\n", r) + else: + stdio.printf("FAIL: lambda chain (result=%d, expect 30)\n", r) + +def main() -> t.CInt: + stdio.printf("=== ClosureAdvancedTest: 高级闭包测试 ===\n\n") + test_global_in_nested() + test_nonlocal_multi_level() + test_global_nonlocal_mixed() + test_lambda_multi_capture() + test_lambda_arg_capture() + test_nested_return() + test_nonlocal_loop() + test_global_array() + test_nested_conditional() + test_lambda_chain() + stdio.printf("\n=== ClosureAdvancedTest Complete ===\n") + return 0 diff --git a/Test/ClosureTest/output/7dbf085f7e3e8944.deps.json b/Test/ClosureTest/output/7dbf085f7e3e8944.deps.json new file mode 100644 index 0000000..073d6e7 --- /dev/null +++ b/Test/ClosureTest/output/7dbf085f7e3e8944.deps.json @@ -0,0 +1 @@ +{"stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/ClosureTest/project.json b/Test/ClosureTest/project.json new file mode 100644 index 0000000..a40284e --- /dev/null +++ b/Test/ClosureTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ClosureTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "ClosureTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/ClosureTest/temp/73edbcf76e32d00b.pyi b/Test/ClosureTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/ClosureTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/ClosureTest/temp/7dbf085f7e3e8944.pyi b/Test/ClosureTest/temp/7dbf085f7e3e8944.pyi new file mode 100644 index 0000000..481b94b --- /dev/null +++ b/Test/ClosureTest/temp/7dbf085f7e3e8944.pyi @@ -0,0 +1,42 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +import stdio + +g_val: t.CExtern | t.CInt + +def outer_modify_global() -> t.CInt: pass + +def test_global_in_nested() -> t.CInt: pass + +def test_nonlocal_multi_level() -> t.CInt: pass + + +g_mixed: t.CExtern | t.CInt + +def test_global_nonlocal_mixed() -> t.CInt: pass + +def test_lambda_multi_capture() -> t.CInt: pass + +def test_lambda_arg_capture() -> t.CInt: pass + +def test_nested_return() -> t.CInt: pass + +def test_nonlocal_loop() -> t.CInt: pass + + +g_arr: t.CExtern | list[t.CInt, 4] + +def test_global_array() -> t.CInt: pass + +def test_nested_conditional() -> t.CInt: pass + +def test_lambda_chain() -> t.CInt: pass + +def main() -> t.CInt: pass diff --git a/Test/ClosureTest/temp/_sha1_map.txt b/Test/ClosureTest/temp/_sha1_map.txt new file mode 100644 index 0000000..3346d98 --- /dev/null +++ b/Test/ClosureTest/temp/_sha1_map.txt @@ -0,0 +1,2 @@ +73edbcf76e32d00b:includes/stdio.py +7dbf085f7e3e8944:main.py diff --git a/Test/ClosureTest2/App/main.py b/Test/ClosureTest2/App/main.py new file mode 100644 index 0000000..6151355 --- /dev/null +++ b/Test/ClosureTest2/App/main.py @@ -0,0 +1,256 @@ +import t +import stdio + +# ============================================================ +# Test 1: nonlocal 在条件分支中修改 +# ============================================================ +def test_nonlocal_conditional(): + stdio.printf("--- Test 1: nonlocal in conditional branches ---\n") + x: t.CInt = 0 + def modify(flag: t.CInt): + nonlocal x + if flag: + x += 10 + else: + x += 100 + modify(1) + modify(0) + modify(1) + if x == 120: + stdio.printf("PASS: nonlocal conditional (x=%d)\n", x) + else: + stdio.printf("FAIL: nonlocal conditional (x=%d, expect 120)\n", x) + +# ============================================================ +# Test 2: 多个nonlocal变量同时修改 +# ============================================================ +def test_nonlocal_multi_var(): + stdio.printf("--- Test 2: multiple nonlocal variables ---\n") + a: t.CInt = 1 + b: t.CInt = 2 + c_val: t.CInt = 3 + def swap_add(): + nonlocal a, b, c_val + tmp: t.CInt = a + a = b + b = c_val + c_val = tmp + swap_add() + if a == 2 and b == 3 and c_val == 1: + stdio.printf("PASS: multi nonlocal (a=%d b=%d c=%d)\n", a, b, c_val) + else: + stdio.printf("FAIL: multi nonlocal (a=%d b=%d c=%d, expect 2 3 1)\n", a, b, c_val) + +# ============================================================ +# Test 3: global 在多个函数中交叉修改 +# ============================================================ +g_counter: t.CInt = 0 + +def inc_global(): + global g_counter + g_counter += 1 + +def add_global(n: t.CInt): + global g_counter + g_counter += n + +def test_global_cross_functions(): + stdio.printf("--- Test 3: global cross-function modification ---\n") + global g_counter + g_counter = 0 + inc_global() + inc_global() + add_global(10) + inc_global() + if g_counter == 13: + stdio.printf("PASS: global cross (g_counter=%d)\n", g_counter) + else: + stdio.printf("FAIL: global cross (g_counter=%d, expect 13)\n", g_counter) + +# ============================================================ +# Test 4: 嵌套函数修改外层局部变量(引用捕获) +# ============================================================ +def test_nested_ref_capture(): + stdio.printf("--- Test 4: nested function ref capture ---\n") + arr: list[t.CInt, 4] = [0] + def fill(): + nonlocal arr + for i in range(4): + arr[i] = (i + 1) * 10 + fill() + total: t.CInt = arr[0] + arr[1] + arr[2] + arr[3] + if total == 100: + stdio.printf("PASS: ref capture (total=%d)\n", total) + else: + stdio.printf("FAIL: ref capture (total=%d, expect 100)\n", total) + +# ============================================================ +# Test 5: lambda捕获后修改原变量 +# ============================================================ +def test_lambda_capture_then_modify(): + stdio.printf("--- Test 5: lambda capture then modify ---\n") + x: t.CInt = 10 + f = lambda: x + r1: t.CInt = f() + x = 20 + r2: t.CInt = f() + if r1 == 10 and r2 == 10: + stdio.printf("PASS: lambda value capture (before=%d after=%d)\n", r1, r2) + else: + stdio.printf("FAIL: lambda value capture (before=%d after=%d, expect 10 10)\n", r1, r2) + +# ============================================================ +# Test 6: 嵌套函数中nonlocal与循环结合 +# ============================================================ +def test_nonlocal_loop_accumulate(): + stdio.printf("--- Test 6: nonlocal with loop accumulate ---\n") + sum_val: t.CInt = 0 + count: t.CInt = 0 + def add_numbers(n: t.CInt): + nonlocal sum_val, count + for i in range(1, n + 1): + sum_val += i + count += 1 + add_numbers(5) # 1+2+3+4+5=15 + add_numbers(3) # 1+2+3=6 + if sum_val == 21 and count == 8: + stdio.printf("PASS: loop accumulate (sum=%d count=%d)\n", sum_val, count) + else: + stdio.printf("FAIL: loop accumulate (sum=%d count=%d, expect 21 8)\n", sum_val, count) + +# ============================================================ +# Test 7: 三层嵌套中每层修改不同变量 +# ============================================================ +def test_deep_nested_vars(): + stdio.printf("--- Test 7: deep nested different vars ---\n") + a: t.CInt = 0 + b: t.CInt = 0 + c_val: t.CInt = 0 + def level1(): + nonlocal a + a += 1 + def level2(): + nonlocal b + b += 10 + def level3(): + nonlocal c_val + c_val += 100 + level3() + level2() + level1() + level1() + if a == 2 and b == 20 and c_val == 200: + stdio.printf("PASS: deep nested (a=%d b=%d c=%d)\n", a, b, c_val) + else: + stdio.printf("FAIL: deep nested (a=%d b=%d c=%d, expect 2 20 200)\n", a, b, c_val) + +# ============================================================ +# Test 8: global + nonlocal 在同一嵌套函数中 +# ============================================================ +g_state: t.CInt = 0 + +def test_global_nonlocal_same_func(): + stdio.printf("--- Test 8: global+nonlocal in same nested func ---\n") + global g_state + g_state = 0 + local_state: t.CInt = 0 + def worker(n: t.CInt): + nonlocal local_state + global g_state + for i in range(n): + g_state += 1 + local_state += 2 + worker(5) + if g_state == 5 and local_state == 10: + stdio.printf("PASS: global+nonlocal same (g=%d l=%d)\n", g_state, local_state) + else: + stdio.printf("FAIL: global+nonlocal same (g=%d l=%d, expect 5 10)\n", g_state, local_state) + +# ============================================================ +# Test 9: lambda带默认参数与捕获 +# ============================================================ +def test_lambda_default_and_capture(): + stdio.printf("--- Test 9: lambda with arg and capture ---\n") + base: t.CInt = 100 + multiply = lambda x: base * x + r1: t.CInt = multiply(3) + r2: t.CInt = multiply(5) + if r1 == 300 and r2 == 500: + stdio.printf("PASS: lambda arg+capture (100*3=%d 100*5=%d)\n", r1, r2) + else: + stdio.printf("FAIL: lambda arg+capture (100*3=%d 100*5=%d, expect 300 500)\n", r1, r2) + +# ============================================================ +# Test 10: 嵌套函数多次调用累积 +# ============================================================ +def test_nested_accumulate(): + stdio.printf("--- Test 10: nested function accumulate ---\n") + total: t.CInt = 0 + def add_val(n: t.CInt): + nonlocal total + total += n + add_val(10) + add_val(20) + add_val(30) + if total == 60: + stdio.printf("PASS: nested accumulate (total=%d)\n", total) + else: + stdio.printf("FAIL: nested accumulate (total=%d, expect 60)\n", total) + +# ============================================================ +# Test 11: nonlocal在while循环中 +# ============================================================ +def test_nonlocal_while(): + stdio.printf("--- Test 11: nonlocal in while loop ---\n") + result: t.CInt = 0 + def countdown(n: t.CInt): + nonlocal result + i: t.CInt = n + while i > 0: + result += i + i -= 1 + countdown(5) # 5+4+3+2+1=15 + if result == 15: + stdio.printf("PASS: nonlocal while (result=%d)\n", result) + else: + stdio.printf("FAIL: nonlocal while (result=%d, expect 15)\n", result) + +# ============================================================ +# Test 12: 嵌套函数修改结构体字段 +# ============================================================ +class Point: + x: t.CInt + y: t.CInt + +def test_nested_modify_struct(): + stdio.printf("--- Test 12: nested modify struct ---\n") + p: Point = Point() + p.x = 0 + p.y = 0 + def translate(dx: t.CInt, dy: t.CInt): + nonlocal p + p.x += dx + p.y += dy + translate(10, 20) + translate(5, 15) + if p.x == 15 and p.y == 35: + stdio.printf("PASS: nested struct (x=%d y=%d)\n", p.x, p.y) + else: + stdio.printf("FAIL: nested struct (x=%d y=%d, expect 15 35)\n", p.x, p.y) + +def main() -> t.CInt: + stdio.printf("=== ClosureTest2: Advanced Closure/Lambda/Global/Nonlocal ===\n\n") + test_nonlocal_conditional() + test_nonlocal_multi_var() + test_global_cross_functions() + test_nested_ref_capture() + test_lambda_capture_then_modify() + test_nonlocal_loop_accumulate() + test_deep_nested_vars() + test_global_nonlocal_same_func() + test_lambda_default_and_capture() + test_nested_accumulate() + test_nonlocal_while() + test_nested_modify_struct() + stdio.printf("\n=== ClosureTest2 Complete ===\n") + return 0 diff --git a/Test/ClosureTest2/output/052c7f96b9eefa2c.deps.json b/Test/ClosureTest2/output/052c7f96b9eefa2c.deps.json new file mode 100644 index 0000000..073d6e7 --- /dev/null +++ b/Test/ClosureTest2/output/052c7f96b9eefa2c.deps.json @@ -0,0 +1 @@ +{"stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/ClosureTest2/project.json b/Test/ClosureTest2/project.json new file mode 100644 index 0000000..d1af5fb --- /dev/null +++ b/Test/ClosureTest2/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ClosureTest2", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "ClosureTest2.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/ClosureTest2/temp/052c7f96b9eefa2c.pyi b/Test/ClosureTest2/temp/052c7f96b9eefa2c.pyi new file mode 100644 index 0000000..b371ecf --- /dev/null +++ b/Test/ClosureTest2/temp/052c7f96b9eefa2c.pyi @@ -0,0 +1,51 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +import stdio + +def test_nonlocal_conditional() -> t.CInt: pass + +def test_nonlocal_multi_var() -> t.CInt: pass + + +g_counter: t.CExtern | t.CInt + +def inc_global() -> t.CInt: pass + +def add_global(n: t.CInt) -> t.CInt: pass + +def test_global_cross_functions() -> t.CInt: pass + +def test_nested_ref_capture() -> t.CInt: pass + +def test_lambda_capture_then_modify() -> t.CInt: pass + +def test_nonlocal_loop_accumulate() -> t.CInt: pass + +def test_deep_nested_vars() -> t.CInt: pass + + +g_state: t.CExtern | t.CInt + +def test_global_nonlocal_same_func() -> t.CInt: pass + +def test_lambda_default_and_capture() -> t.CInt: pass + +def test_nested_accumulate() -> t.CInt: pass + +def test_nonlocal_while() -> t.CInt: pass + + +class Point: + x: t.CInt + y: t.CInt + +def test_nested_modify_struct() -> t.CInt: pass + +def main() -> t.CInt: pass diff --git a/Test/ClosureTest2/temp/73edbcf76e32d00b.pyi b/Test/ClosureTest2/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/ClosureTest2/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/ClosureTest2/temp/_sha1_map.txt b/Test/ClosureTest2/temp/_sha1_map.txt new file mode 100644 index 0000000..8f2ff70 --- /dev/null +++ b/Test/ClosureTest2/temp/_sha1_map.txt @@ -0,0 +1,2 @@ +052c7f96b9eefa2c:main.py +73edbcf76e32d00b:includes/stdio.py diff --git a/Test/DecoratorTest/App/main.py b/Test/DecoratorTest/App/main.py new file mode 100644 index 0000000..21cf473 --- /dev/null +++ b/Test/DecoratorTest/App/main.py @@ -0,0 +1,290 @@ +import t +from stdio import printf + +# ============================================================ +# 自定义装饰器处理函数 +# 调用约定 (v4): +# i32 decor_name(i8* ctx, i8* func_name, i32 phase, +# i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr) +# +# ctx: 栈帧局部上下文(32字节),每次调用独立,线程/递归安全 +# args_ptr: 可读写,装饰器可修改函数入参 +# ret_ptr: 后置阶段可读写,装饰器可修改返回值 +# 返回值(前置阶段): +# 0 = 跳过原函数调用 +# 1 = 正常调用一次 +# N = 循环调用 N 次 +# ============================================================ + +# @log 装饰器:打印函数进入/退出,返回 1(正常调用一次) +def log(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, + args_ptr: t.CVoid | t.CPtr, + ret_ptr: t.CVoid | t.CPtr, + decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: + if phase == 0: + printf("[LOG] >> %s enter\n", func_name) + return 1 + else: + printf("[LOG] << %s exit\n", func_name) + return 0 + +# @trace 装饰器:详细追踪 +def trace(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, + args_ptr: t.CVoid | t.CPtr, + ret_ptr: t.CVoid | t.CPtr, + decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: + if phase == 0: + printf("[TRACE] calling %s...\n", func_name) + return 1 + else: + printf("[TRACE] %s returned\n", func_name) + return 0 + +# @timing 装饰器:使用全局变量记录计时 +# 注意:理想情况下应使用 ctx 栈帧局部上下文替代全局变量, +# 但 Viper 当前前端尚不支持 i8* 到 i32* 的指针转型, +# 因此暂时使用全局变量演示计时逻辑 +_timing_tmp: t.CInt = 0 + +def timing(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, + args_ptr: t.CVoid | t.CPtr, + ret_ptr: t.CVoid | t.CPtr, + decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: + global _timing_tmp + if phase == 0: + _timing_tmp = 100 + printf("[TIMING] %s start at t=%d\n", func_name, _timing_tmp) + return 1 + else: + elapsed: t.CInt = 105 - _timing_tmp + printf("[TIMING] %s took %d ms\n", func_name, elapsed) + return 0 + +# @repeat 装饰器(带参数,流程劫持):循环调用原函数 N 次 +def repeat(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, + args_ptr: t.CVoid | t.CPtr, + ret_ptr: t.CVoid | t.CPtr, + decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: + if phase == 0: + printf("[REPEAT] %s will run 3 times\n", func_name) + return 3 + else: + printf("[REPEAT] %s all iterations done\n", func_name) + return 0 + +# @skip 装饰器:跳过原函数调用(流程劫持,返回 0) +_skip_count: t.CInt = 0 + +def skip(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, + args_ptr: t.CVoid | t.CPtr, + ret_ptr: t.CVoid | t.CPtr, + decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: + global _skip_count + if phase == 0: + _skip_count = _skip_count + 1 + printf("[SKIP] %s skipped! (call #%d)\n", func_name, _skip_count) + return 0 + else: + printf("[SKIP] %s post (ret_ptr=%p)\n", func_name, ret_ptr) + return 0 + +# @count_calls 装饰器:统计函数被调用次数(递归保护测试用) +_call_count: t.CInt = 0 + +def count_calls(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, + args_ptr: t.CVoid | t.CPtr, + ret_ptr: t.CVoid | t.CPtr, + decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: + global _call_count + if phase == 0: + _call_count = _call_count + 1 + printf("[COUNT] %s call #%d\n", func_name, _call_count) + return 1 + else: + printf("[COUNT] %s done (total calls: %d)\n", func_name, _call_count) + return 0 + + +# ============================================================ +# 测试 1:单个装饰器 @log +# ============================================================ + +@log +def add(a: t.CInt, b: t.CInt) -> t.CInt | t.CExport: + return a + b + + +# ============================================================ +# 测试 2:链式装饰器 @log @trace => log(trace(f)) +# 执行顺序:log_pre → trace_pre → f → trace_post → log_post +# ============================================================ + +@log +@trace +def multiply(a: t.CInt, b: t.CInt) -> t.CInt | t.CExport: + return a * b + + +# ============================================================ +# 测试 3:装饰器修饰 void 返回函数 +# ============================================================ + +@log +def greet(name: str) -> t.CVoid | t.CExport: + printf("Hello, %s!\n", name) + + +# ============================================================ +# 测试 4:装饰器修饰无参数函数 +# ============================================================ + +@log +def get_value() -> t.CInt | t.CExport: + return 42 + + +# ============================================================ +# 测试 5:@timing 装饰器 +# ============================================================ + +@timing +def compute(x: t.CInt) -> t.CInt | t.CExport: + return x * x + 1 + + +# ============================================================ +# 测试 6:带参数装饰器 @repeat(3) — 流程劫持,循环调用 3 次 +# ============================================================ + +@repeat(3) +def echo(msg: str) -> t.CVoid | t.CExport: + printf(" echo: %s\n", msg) + + +# ============================================================ +# 测试 7:链式 @timing @log +# ============================================================ + +@timing +@log +def power(base: t.CInt, exp: t.CInt) -> t.CInt | t.CExport: + result: t.CInt = 1 + i: t.CInt = 0 + while i < exp: + result = result * base + i = i + 1 + return result + + +# ============================================================ +# 测试 8:@skip 装饰器 — 流程劫持,跳过原函数调用 +# ============================================================ + +@skip +def dangerous() -> t.CInt | t.CExport: + printf("This should NOT be printed!\n") + return 999 + + +# ============================================================ +# 测试 9:@repeat(3) 修饰有返回值的函数 +# ============================================================ + +@repeat(3) +def accumulate(x: t.CInt) -> t.CInt | t.CExport: + printf(" accumulate(%d)\n", x) + return x * 10 + + +# ============================================================ +# 测试 10:递归装饰保护 — @count_calls 修饰递归函数 +# v4 递归保护:最外层 wrapper 检查全局标志位, +# 递归调用时跳过所有装饰逻辑,仅最外层调用触发装饰器 +# ============================================================ + +@count_calls +def factorial(n: t.CInt) -> t.CInt | t.CExport: + if n <= 1: + return 1 + return n * factorial(n - 1) + + +# ============================================================ +# 测试 11:@log 修饰递归函数 — 验证递归保护 +# 递归保护确保只有最外层调用打印 LOG,内部递归不触发 +# ============================================================ + +@log +def fib(n: t.CInt) -> t.CInt | t.CExport: + if n <= 1: + return n + return fib(n - 1) + fib(n - 2) + + +# ============================================================ +# 主函数 +# ============================================================ + +def main() -> t.CInt | t.CExport: + printf("=== Decorator Test v4 ===\n\n") + + # 测试 1:单个 @log + printf("--- Test 1: single @log ---\n") + r1: t.CInt = add(3, 4) + printf("add(3,4) = %d\n\n", r1) + + # 测试 2:链式 @log @trace + printf("--- Test 2: chained @log @trace ---\n") + r2: t.CInt = multiply(5, 6) + printf("multiply(5,6) = %d\n\n", r2) + + # 测试 3:void 返回 + printf("--- Test 3: @log on void function ---\n") + greet("Viper") + printf("\n") + + # 测试 4:无参数 + printf("--- Test 4: @log on no-arg function ---\n") + r4: t.CInt = get_value() + printf("get_value() = %d\n\n", r4) + + # 测试 5:@timing + printf("--- Test 5: @timing ---\n") + r5: t.CInt = compute(7) + printf("compute(7) = %d\n\n", r5) + + # 测试 6:@repeat(3) — 流程劫持,循环 3 次 + printf("--- Test 6: @repeat(3) flow hijack ---\n") + echo("hello") + printf("\n") + + # 测试 7:链式 @timing @log + printf("--- Test 7: chained @timing @log ---\n") + r7: t.CInt = power(2, 10) + printf("power(2,10) = %d\n\n", r7) + + # 测试 8:@skip — 跳过原函数调用 + printf("--- Test 8: @skip flow hijack ---\n") + r8: t.CInt = dangerous() + printf("dangerous() = %d (should be 0, skipped)\n\n", r8) + + # 测试 9:@repeat(3) 有返回值 + printf("--- Test 9: @repeat(3) with return value ---\n") + r9: t.CInt = accumulate(5) + printf("accumulate(5) = %d (last iteration result)\n\n", r9) + + # 测试 10:递归装饰保护 — @count_calls + printf("--- Test 10: recursive decoration protection ---\n") + _call_count = 0 + r10: t.CInt = factorial(5) + printf("factorial(5) = %d (should be 120)\n", r10) + printf(" decorator call count = %d (should be 1, not 5)\n\n", _call_count) + + # 测试 11:@log 递归保护 — fib + printf("--- Test 11: @log on recursive fib ---\n") + r11: t.CInt = fib(6) + printf("fib(6) = %d (should be 8)\n", r11) + printf(" (should see only 1 LOG enter/exit pair)\n\n") + + printf("=== All decorator tests done ===\n") + return 0 diff --git a/Test/DecoratorTest/output/577f9e1aa32b17f8.deps.json b/Test/DecoratorTest/output/577f9e1aa32b17f8.deps.json new file mode 100644 index 0000000..073d6e7 --- /dev/null +++ b/Test/DecoratorTest/output/577f9e1aa32b17f8.deps.json @@ -0,0 +1 @@ +{"stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/DecoratorTest/project.json b/Test/DecoratorTest/project.json new file mode 100644 index 0000000..f3bbc02 --- /dev/null +++ b/Test/DecoratorTest/project.json @@ -0,0 +1,28 @@ +{ + "name": "DecoratorTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "DecoratorTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/DecoratorTest/temp/577f9e1aa32b17f8.pyi b/Test/DecoratorTest/temp/577f9e1aa32b17f8.pyi new file mode 100644 index 0000000..fa3ba61 --- /dev/null +++ b/Test/DecoratorTest/temp/577f9e1aa32b17f8.pyi @@ -0,0 +1,68 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +from stdio import printf + +def log(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, args_ptr: t.CVoid | t.CPtr, ret_ptr: t.CVoid | t.CPtr, decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: pass + +def trace(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, args_ptr: t.CVoid | t.CPtr, ret_ptr: t.CVoid | t.CPtr, decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: pass + + +_timing_tmp: t.CExtern | t.CInt + +def timing(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, args_ptr: t.CVoid | t.CPtr, ret_ptr: t.CVoid | t.CPtr, decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: pass + +def repeat(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, args_ptr: t.CVoid | t.CPtr, ret_ptr: t.CVoid | t.CPtr, decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: pass + + +_skip_count: t.CExtern | t.CInt + +def skip(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, args_ptr: t.CVoid | t.CPtr, ret_ptr: t.CVoid | t.CPtr, decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: pass + + +_call_count: t.CExtern | t.CInt + +def count_calls(ctx: t.CVoid | t.CPtr, func_name: str, phase: t.CInt, args_ptr: t.CVoid | t.CPtr, ret_ptr: t.CVoid | t.CPtr, decor_args_ptr: t.CVoid | t.CPtr) -> t.CInt | t.CExport: pass + +@log +def add(a: t.CInt, b: t.CInt) -> t.CInt | t.CExport: pass + +@log +@trace +def multiply(a: t.CInt, b: t.CInt) -> t.CInt | t.CExport: pass + +@log +def greet(name: str) -> t.CVoid | t.CExport: pass + +@log +def get_value() -> t.CInt | t.CExport: pass + +@timing +def compute(x: t.CInt) -> t.CInt | t.CExport: pass + +@repeat(3) +def echo(msg: str) -> t.CVoid | t.CExport: pass + +@timing +@log +def power(base: t.CInt, exp: t.CInt) -> t.CInt | t.CExport: pass + +@skip +def dangerous() -> t.CInt | t.CExport: pass + +@repeat(3) +def accumulate(x: t.CInt) -> t.CInt | t.CExport: pass + +@count_calls +def factorial(n: t.CInt) -> t.CInt | t.CExport: pass + +@log +def fib(n: t.CInt) -> t.CInt | t.CExport: pass + +def main() -> t.CInt | t.CExport: pass diff --git a/Test/DecoratorTest/temp/73edbcf76e32d00b.pyi b/Test/DecoratorTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/DecoratorTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/DecoratorTest/temp/_sha1_map.txt b/Test/DecoratorTest/temp/_sha1_map.txt new file mode 100644 index 0000000..8a3a6d8 --- /dev/null +++ b/Test/DecoratorTest/temp/_sha1_map.txt @@ -0,0 +1,2 @@ +577f9e1aa32b17f8:main.py +73edbcf76e32d00b:includes/stdio.py diff --git a/Test/FuncTest/App/main.py b/Test/FuncTest/App/main.py new file mode 100644 index 0000000..62be0fa --- /dev/null +++ b/Test/FuncTest/App/main.py @@ -0,0 +1,130 @@ +import t +import stdio + +# 测试基本函数调用 +def add(a: t.CInt, b: t.CInt) -> t.CInt: + return a + b + +def sub(a: t.CInt, b: t.CInt) -> t.CInt: + return a - b + +# 测试多参数 +def multi_args(a: t.CInt, b: t.CInt, c: t.CInt, d: t.CInt) -> t.CInt: + return a + b + c + d + +# 测试递归 +def factorial(n: t.CInt) -> t.CInt: + if n <= 1: + return 1 + return n * factorial(n - 1) + +# 测试尾递归式斐波那契 +def fib(n: t.CInt) -> t.CInt: + if n <= 0: + return 0 + if n == 1: + return 1 + return fib(n - 1) + fib(n - 2) + +# 测试指针参数 +def add_via_ptr(p: t.CInt | t.CPtr, val: t.CInt): + p[0] = p[0] + val + +# 测试 u64 返回值 +def make_u64() -> t.CUInt64T: + return t.CUInt64T(0xDEADBEEF) + +# 测试 bool 返回值 +def is_even(n: t.CInt) -> t.CBool: + return n % 2 == 0 + +def test_basic_call(): + stdio.printf("--- Test 1: basic function call ---\n") + r: t.CInt = add(10, 20) + if r == 30: + stdio.printf("PASS: add(10,20)=%d\n", r) + else: + stdio.printf("FAIL: add(10,20)=%d, expect 30\n", r) + +def test_multi_args(): + stdio.printf("--- Test 2: multi args ---\n") + r: t.CInt = multi_args(1, 2, 3, 4) + if r == 10: + stdio.printf("PASS: multi_args(1,2,3,4)=%d\n", r) + else: + stdio.printf("FAIL: multi_args(1,2,3,4)=%d, expect 10\n", r) + +def test_recursion(): + stdio.printf("--- Test 3: recursion (factorial) ---\n") + r: t.CInt = factorial(10) + # 10! = 3628800 + if r == 3628800: + stdio.printf("PASS: factorial(10)=%d\n", r) + else: + stdio.printf("FAIL: factorial(10)=%d, expect 3628800\n", r) + +def test_fibonacci(): + stdio.printf("--- Test 4: fibonacci ---\n") + r: t.CInt = fib(10) + # fib(10) = 55 + if r == 55: + stdio.printf("PASS: fib(10)=%d\n", r) + else: + stdio.printf("FAIL: fib(10)=%d, expect 55\n", r) + +def test_ptr_param(): + stdio.printf("--- Test 5: pointer parameter ---\n") + x: t.CInt = 10 + # 需要取 x 的地址 + import w32.win32memory + buf: t.CInt | t.CPtr = w32.win32memory.VirtualAlloc(t.CVoid(0, t.CPtr), 64, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + buf[0] = 10 + add_via_ptr(buf, 25) + if buf[0] == 35: + stdio.printf("PASS: ptr param (result=%d)\n", buf[0]) + else: + stdio.printf("FAIL: ptr param (result=%d, expect 35)\n", buf[0]) + +def test_u64_return(): + stdio.printf("--- Test 6: u64 return ---\n") + r: t.CUInt64T = make_u64() + if r == t.CUInt64T(0xDEADBEEF): + stdio.printf("PASS: u64 return (0x%lx)\n", r) + else: + stdio.printf("FAIL: u64 return (0x%lx, expect 0xdeadbeef)\n", r) + +def test_bool_return(): + stdio.printf("--- Test 7: bool return ---\n") + r1: t.CBool = is_even(4) + r2: t.CBool = is_even(7) + if r1 and not r2: + stdio.printf("PASS: bool return (is_even(4)=%d, is_even(7)=%d)\n", r1, r2) + else: + stdio.printf("FAIL: bool return (is_even(4)=%d, is_even(7)=%d)\n", r1, r2) + +def test_nested_call(): + stdio.printf("--- Test 8: nested function call ---\n") + r: t.CInt = add(factorial(3), sub(10, 3)) + # 3! = 6, 10-3 = 7, 6+7 = 13 + if r == 13: + stdio.printf("PASS: nested call (add(factorial(3), sub(10,3))=%d)\n", r) + else: + stdio.printf("FAIL: nested call (result=%d, expect 13)\n", r) + +import w32.win32memory + +def main() -> t.CInt: + stdio.printf("=== FuncTest: 函数调用基准测试 ===\n\n") + test_basic_call() + test_multi_args() + test_recursion() + test_fibonacci() + test_ptr_param() + test_u64_return() + test_bool_return() + test_nested_call() + stdio.printf("\n=== FuncTest Complete ===\n") + return 0 diff --git a/Test/FuncTest/output/067c78e9f121dce3.deps.json b/Test/FuncTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..4bd5961 --- /dev/null +++ b/Test/FuncTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d6f1d57732bde476", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/FuncTest/output/29813d57621099a9.deps.json b/Test/FuncTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..801f686 --- /dev/null +++ b/Test/FuncTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d6f1d57732bde476", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/FuncTest/output/5a6a2137958c28c5.deps.json b/Test/FuncTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..acce008 --- /dev/null +++ b/Test/FuncTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d6f1d57732bde476", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/FuncTest/output/72e2d5ccb7cedcf1.deps.json b/Test/FuncTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..1ced6f3 --- /dev/null +++ b/Test/FuncTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d6f1d57732bde476", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/FuncTest/output/abf9ce3160c9279e.deps.json b/Test/FuncTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..1ced6f3 --- /dev/null +++ b/Test/FuncTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d6f1d57732bde476", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/FuncTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/FuncTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..3f53475 --- /dev/null +++ b/Test/FuncTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d6f1d57732bde476", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/FuncTest/output/d6f1d57732bde476.deps.json b/Test/FuncTest/output/d6f1d57732bde476.deps.json new file mode 100644 index 0000000..abf4f60 --- /dev/null +++ b/Test/FuncTest/output/d6f1d57732bde476.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/FuncTest/output/fa3691e66b426950.deps.json b/Test/FuncTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..acce008 --- /dev/null +++ b/Test/FuncTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "d6f1d57732bde476", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/FuncTest/project.json b/Test/FuncTest/project.json new file mode 100644 index 0000000..1099565 --- /dev/null +++ b/Test/FuncTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "FuncTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "FuncTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/FuncTest/temp/067c78e9f121dce3.pyi b/Test/FuncTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/FuncTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/FuncTest/temp/29813d57621099a9.pyi b/Test/FuncTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/FuncTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/FuncTest/temp/56cdd754a8a09347.pyi b/Test/FuncTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/FuncTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/FuncTest/temp/5a6a2137958c28c5.pyi b/Test/FuncTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/FuncTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/FuncTest/temp/72e2d5ccb7cedcf1.pyi b/Test/FuncTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/FuncTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/FuncTest/temp/73edbcf76e32d00b.pyi b/Test/FuncTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/FuncTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/FuncTest/temp/_sha1_map.txt b/Test/FuncTest/temp/_sha1_map.txt new file mode 100644 index 0000000..ab5378d --- /dev/null +++ b/Test/FuncTest/temp/_sha1_map.txt @@ -0,0 +1,5 @@ +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +72e2d5ccb7cedcf1:includes/w32\win32memory.py +73edbcf76e32d00b:includes/stdio.py +d6f1d57732bde476:main.py diff --git a/Test/FuncTest/temp/abf9ce3160c9279e.pyi b/Test/FuncTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/FuncTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/FuncTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/FuncTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/FuncTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/FuncTest/temp/d6f1d57732bde476.pyi b/Test/FuncTest/temp/d6f1d57732bde476.pyi new file mode 100644 index 0000000..0492770 --- /dev/null +++ b/Test/FuncTest/temp/d6f1d57732bde476.pyi @@ -0,0 +1,47 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +import stdio + +def add(a: t.CInt, b: t.CInt) -> t.CInt: pass + +def sub(a: t.CInt, b: t.CInt) -> t.CInt: pass + +def multi_args(a: t.CInt, b: t.CInt, c: t.CInt, d: t.CInt) -> t.CInt: pass + +def factorial(n: t.CInt) -> t.CInt: pass + +def fib(n: t.CInt) -> t.CInt: pass + +def add_via_ptr(p: t.CInt | t.CPtr, val: t.CInt) -> t.CInt: pass + +def make_u64() -> t.CUInt64T: pass + +def is_even(n: t.CInt) -> t.CBool: pass + +def test_basic_call() -> t.CInt: pass + +def test_multi_args() -> t.CInt: pass + +def test_recursion() -> t.CInt: pass + +def test_fibonacci() -> t.CInt: pass + +def test_ptr_param() -> t.CInt: pass + +def test_u64_return() -> t.CInt: pass + +def test_bool_return() -> t.CInt: pass + +def test_nested_call() -> t.CInt: pass + + +import w32.win32memory + +def main() -> t.CInt: pass diff --git a/Test/FuncTest/temp/fa3691e66b426950.pyi b/Test/FuncTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/FuncTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/GenericTest/App/main.py b/Test/GenericTest/App/main.py new file mode 100644 index 0000000..8780a0c --- /dev/null +++ b/Test/GenericTest/App/main.py @@ -0,0 +1,197 @@ +import t +import stdio + +# ============================================================ +# Test 1: 泛型函数 - 基本加法 +# ============================================================ +def add[T](a: T, b: T) -> T: + return a + b + +def test_generic_add(): + stdio.printf("--- Test 1: generic add ---\n") + r1: t.CInt = add(3, 5) + r2: t.CInt = add(100, 200) + if r1 == 8 and r2 == 300: + stdio.printf("PASS: generic add (3+5=%d, 100+200=%d)\n", r1, r2) + else: + stdio.printf("FAIL: generic add (3+5=%d, 100+200=%d)\n", r1, r2) + +# ============================================================ +# Test 2: 泛型函数 - 多类型参数 +# ============================================================ +def combine[T1, T2](a: T1, b: T2) -> T1: + return a + T1(b) + +def test_generic_combine(): + stdio.printf("--- Test 2: generic combine ---\n") + r: t.CInt = combine(10, 20) + if r == 30: + stdio.printf("PASS: generic combine (10+T1(20)=%d)\n", r) + else: + stdio.printf("FAIL: generic combine (result=%d, expect 30)\n", r) + +# ============================================================ +# Test 3: 泛型函数 - 最大值 +# ============================================================ +def max_val[T](a: T, b: T) -> T: + if a > b: + return a + return b + +def test_generic_max(): + stdio.printf("--- Test 3: generic max ---\n") + r1: t.CInt = max_val(10, 20) + r2: t.CInt = max_val(50, 30) + if r1 == 20 and r2 == 50: + stdio.printf("PASS: generic max (max(10,20)=%d, max(50,30)=%d)\n", r1, r2) + else: + stdio.printf("FAIL: generic max (max(10,20)=%d, max(50,30)=%d)\n", r1, r2) + +# ============================================================ +# Test 4: 泛型类 - Box[T] +# ============================================================ +class Box[T](): + value: T + + def __init__(self, v: T): + self.value = T(v) + + def get(self) -> T: + return self.value + + def set(self, v: T): + self.value = T(v) + +def test_generic_box(): + stdio.printf("--- Test 4: generic Box[T] ---\n") + b = Box(42) + v: t.CInt = b.get() + if v == 42: + stdio.printf("PASS: Box[int] (get=%d)\n", v) + else: + stdio.printf("FAIL: Box[int] (get=%d, expect 42)\n", v) + +# ============================================================ +# Test 5: 泛型类 - Pair[T1, T2] +# ============================================================ +class Pair[T1, T2](): + first: T1 + second: T2 + + def __init__(self, a: T1, b: T2): + self.first = T1(a) + self.second = T2(b) + + def sum_as_int(self) -> t.CInt: + return t.CInt(self.first) + t.CInt(self.second) + +def test_generic_pair(): + stdio.printf("--- Test 5: generic Pair[T1,T2] ---\n") + p = Pair(10, 20) + r: t.CInt = p.sum_as_int() + if r == 30: + stdio.printf("PASS: Pair[int,int] (sum=%d)\n", r) + else: + stdio.printf("FAIL: Pair[int,int] (sum=%d, expect 30)\n", r) + +# ============================================================ +# Test 6: list[T, N] 固定数组 +# ============================================================ +def test_fixed_array(): + stdio.printf("--- Test 6: list[T, N] fixed array ---\n") + arr: list[t.CInt, 5] = [0] + for i in range(5): + arr[i] = i * 10 + total: t.CInt = 0 + for i in range(5): + total += arr[i] + # 0+10+20+30+40 = 100 + if total == 100: + stdio.printf("PASS: fixed array (total=%d)\n", total) + else: + stdio.printf("FAIL: fixed array (total=%d, expect 100)\n", total) + +# ============================================================ +# Test 7: list[t.CChar, N] 字符数组 +# ============================================================ +def test_char_array(): + stdio.printf("--- Test 7: list[t.CChar, N] char array ---\n") + buf: list[t.CChar, 32] = [0] + buf[0] = 72 # H + buf[1] = 105 # i + buf[2] = 0 + if buf[0] == 72 and buf[1] == 105: + stdio.printf("PASS: char array (H=%d i=%d)\n", buf[0], buf[1]) + else: + stdio.printf("FAIL: char array (H=%d i=%d)\n", buf[0], buf[1]) + +# ============================================================ +# Test 8: 泛型函数多次特化 +# ============================================================ +def identity[T](x: T) -> T: + return x + +def test_generic_identity(): + stdio.printf("--- Test 8: generic identity ---\n") + r1: t.CInt = identity(42) + r2: t.CInt = identity(0) + if r1 == 42 and r2 == 0: + stdio.printf("PASS: identity (42=%d, 0=%d)\n", r1, r2) + else: + stdio.printf("FAIL: identity (42=%d, 0=%d)\n", r1, r2) + +# ============================================================ +# Test 9: 泛型函数嵌套调用 +# ============================================================ +def double_val[T](x: T) -> T: + return add(x, x) + +def test_generic_nested(): + stdio.printf("--- Test 9: generic nested call ---\n") + r: t.CInt = double_val(21) + if r == 42: + stdio.printf("PASS: generic nested (double(21)=%d)\n", r) + else: + stdio.printf("FAIL: generic nested (double(21)=%d, expect 42)\n", r) + +# ============================================================ +# Test 10: 泛型类方法调用 +# ============================================================ +class Counter[T](): + count: T + + def __init__(self, start: T): + self.count = T(start) + + def increment(self): + self.count = add(self.count, T(1)) + + def get_count(self) -> T: + return self.count + +def test_generic_counter(): + stdio.printf("--- Test 10: generic Counter[T] ---\n") + c = Counter(0) + c.increment() + c.increment() + c.increment() + r: t.CInt = c.get_count() + if r == 3: + stdio.printf("PASS: Counter[int] (count=%d)\n", r) + else: + stdio.printf("FAIL: Counter[int] (count=%d, expect 3)\n", r) + +def main() -> t.CInt: + stdio.printf("=== GenericTest: 泛型测试 ===\n\n") + test_generic_add() + test_generic_combine() + test_generic_max() + test_generic_box() + test_generic_pair() + test_fixed_array() + test_char_array() + test_generic_identity() + test_generic_nested() + test_generic_counter() + stdio.printf("\n=== GenericTest Complete ===\n") + return 0 diff --git a/Test/GenericTest/output/47df358e08cc5c0e.deps.json b/Test/GenericTest/output/47df358e08cc5c0e.deps.json new file mode 100644 index 0000000..073d6e7 --- /dev/null +++ b/Test/GenericTest/output/47df358e08cc5c0e.deps.json @@ -0,0 +1 @@ +{"stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/GenericTest/project.json b/Test/GenericTest/project.json new file mode 100644 index 0000000..05323c1 --- /dev/null +++ b/Test/GenericTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "GenericTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "GenericTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/GenericTest/temp/47df358e08cc5c0e.pyi b/Test/GenericTest/temp/47df358e08cc5c0e.pyi new file mode 100644 index 0000000..84f8fbf --- /dev/null +++ b/Test/GenericTest/temp/47df358e08cc5c0e.pyi @@ -0,0 +1,63 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +import stdio + +def add[T](a: T, b: T) -> T: pass + +def test_generic_add() -> t.CInt: pass + +def combine[T1, T2](a: T1, b: T2) -> T1: pass + +def test_generic_combine() -> t.CInt: pass + +def max_val[T](a: T, b: T) -> T: pass + +def test_generic_max() -> t.CInt: pass + + +class Box[T]: + value: T + def __init__(self: Box, v: T) -> t.CInt: pass + def get(self: Box) -> T: pass + def set(self: Box, v: T) -> t.CInt: pass + +def test_generic_box() -> t.CInt: pass + + +class Pair[T1, T2]: + first: T1 + second: T2 + def __init__(self: Pair, a: T1, b: T2) -> t.CInt: pass + def sum_as_int(self: Pair) -> t.CInt: pass + +def test_generic_pair() -> t.CInt: pass + +def test_fixed_array() -> t.CInt: pass + +def test_char_array() -> t.CInt: pass + +def identity[T](x: T) -> T: pass + +def test_generic_identity() -> t.CInt: pass + +def double_val[T](x: T) -> T: pass + +def test_generic_nested() -> t.CInt: pass + + +class Counter[T]: + count: T + def __init__(self: Counter, start: T) -> t.CInt: pass + def increment(self: Counter) -> t.CInt: pass + def get_count(self: Counter) -> T: pass + +def test_generic_counter() -> t.CInt: pass + +def main() -> t.CInt: pass diff --git a/Test/GenericTest/temp/73edbcf76e32d00b.pyi b/Test/GenericTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/GenericTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/GenericTest/temp/_sha1_map.txt b/Test/GenericTest/temp/_sha1_map.txt new file mode 100644 index 0000000..8305f0b --- /dev/null +++ b/Test/GenericTest/temp/_sha1_map.txt @@ -0,0 +1,2 @@ +47df358e08cc5c0e:main.py +73edbcf76e32d00b:includes/stdio.py diff --git a/Test/GenericTest2/App/main.py b/Test/GenericTest2/App/main.py new file mode 100644 index 0000000..6070358 --- /dev/null +++ b/Test/GenericTest2/App/main.py @@ -0,0 +1,274 @@ +import t +import stdio +import c + +# ============================================================ +# Test 1: 泛型函数 - 不同整数类型特化 +# ============================================================ +def square[T](x: T) -> T: + return x * x + +def test_generic_square_types(): + stdio.printf("--- Test 1: generic square with different types ---\n") + r1: t.CInt = square(5) + r2: t.CInt = square(10) + if r1 == 25 and r2 == 100: + stdio.printf("PASS: square (5^2=%d 10^2=%d)\n", r1, r2) + else: + stdio.printf("FAIL: square (5^2=%d 10^2=%d, expect 25 100)\n", r1, r2) + +# ============================================================ +# Test 2: 泛型函数 - 三参数 +# ============================================================ +def clamp[T](val: T, lo: T, hi: T) -> T: + if val < lo: + return lo + if val > hi: + return hi + return val + +def test_generic_clamp(): + stdio.printf("--- Test 2: generic clamp ---\n") + r1: t.CInt = clamp(5, 0, 10) + r2: t.CInt = clamp(-3, 0, 10) + r3: t.CInt = clamp(15, 0, 10) + if r1 == 5 and r2 == 0 and r3 == 10: + stdio.printf("PASS: clamp (%d %d %d)\n", r1, r2, r3) + else: + stdio.printf("FAIL: clamp (%d %d %d, expect 5 0 10)\n", r1, r2, r3) + +# ============================================================ +# Test 3: 泛型类 - Stack[T] +# ============================================================ +class Stack[T](): + data: list[t.CInt, 16] + top: t.CInt + + def __init__(self): + self.top = 0 + + def push(self, val: T): + self.data[self.top] = t.CInt(val) + self.top += 1 + + def pop(self) -> T: + self.top -= 1 + return T(self.data[self.top]) + + def is_empty(self) -> t.CInt: + if self.top == 0: + return 1 + return 0 + +def test_generic_stack(): + stdio.printf("--- Test 3: generic Stack[T] ---\n") + s = Stack() + s.push(10) + s.push(20) + s.push(30) + r1: t.CInt = s.pop() + r2: t.CInt = s.pop() + r3: t.CInt = s.pop() + if r1 == 30 and r2 == 20 and r3 == 10: + stdio.printf("PASS: Stack (pop=%d %d %d)\n", r1, r2, r3) + else: + stdio.printf("FAIL: Stack (pop=%d %d %d, expect 30 20 10)\n", r1, r2, r3) + +# ============================================================ +# Test 4: 泛型函数 - swap via pointer +# ============================================================ +class IntPair: + a: t.CInt + b: t.CInt + +def generic_swap[T](p: IntPair | t.CPtr): + tmp: t.CInt = c.Deref(p).a + c.Deref(p).a = c.Deref(p).b + c.Deref(p).b = tmp + +def test_generic_swap(): + stdio.printf("--- Test 4: generic swap via pointer ---\n") + p: IntPair = IntPair() + p.a = 100 + p.b = 200 + generic_swap(c.Addr(p)) + if p.a == 200 and p.b == 100: + stdio.printf("PASS: swap (a=%d b=%d)\n", p.a, p.b) + else: + stdio.printf("FAIL: swap (a=%d b=%d, expect 200 100)\n", p.a, p.b) + +# ============================================================ +# Test 5: 泛型类 - Range[T] 迭代器 +# ============================================================ +class Range[T](): + start: T + end_val: T + step: T + + def __init__(self, s: T, e: T, st: T): + self.start = T(s) + self.end_val = T(e) + self.step = T(st) + + def sum_all(self) -> T: + result: T = T(0) + i: T = self.start + while i < self.end_val: + result = result + i + i = i + self.step + return result + +def test_generic_range(): + stdio.printf("--- Test 5: generic Range[T] ---\n") + r = Range(0, 10, 1) # 0+1+2+...+9=45 + s: t.CInt = r.sum_all() + if s == 45: + stdio.printf("PASS: Range sum (0..9=%d)\n", s) + else: + stdio.printf("FAIL: Range sum (0..9=%d, expect 45)\n", s) + +# ============================================================ +# Test 6: 泛型函数 - 数组求和(非泛型数组参数) +# ============================================================ +def array_sum(arr: list[t.CInt, 8], n: t.CInt) -> t.CInt: + result: t.CInt = 0 + for i in range(n): + result += arr[i] + return result + +def test_generic_array_sum(): + stdio.printf("--- Test 6: array sum ---\n") + arr: list[t.CInt, 8] = [0] + for i in range(8): + arr[i] = (i + 1) * 10 + s: t.CInt = array_sum(arr, 8) + if s == 360: + stdio.printf("PASS: array sum (%d)\n", s) + else: + stdio.printf("FAIL: array sum (%d, expect 360)\n", s) + +# ============================================================ +# Test 7: 泛型函数 - 比较并返回较大值 +# ============================================================ +def max_of_three[T](a: T, b: T, c_val: T) -> T: + m: T = a + if b > m: + m = b + if c_val > m: + m = c_val + return m + +def test_generic_max_three(): + stdio.printf("--- Test 7: generic max of three ---\n") + r1: t.CInt = max_of_three(1, 2, 3) + r2: t.CInt = max_of_three(10, 30, 20) + r3: t.CInt = max_of_three(50, 50, 50) + if r1 == 3 and r2 == 30 and r3 == 50: + stdio.printf("PASS: max3 (%d %d %d)\n", r1, r2, r3) + else: + stdio.printf("FAIL: max3 (%d %d %d, expect 3 30 50)\n", r1, r2, r3) + +# ============================================================ +# Test 8: 泛型类 - 带方法的容器 +# ============================================================ +class Container[T](): + values: list[t.CInt, 8] + size: t.CInt + + def __init__(self): + self.size = 0 + + def add(self, v: T): + self.values[self.size] = t.CInt(v) + self.size += 1 + + def get(self, idx: t.CInt) -> T: + return T(self.values[idx]) + + def contains(self, v: T) -> t.CInt: + for i in range(self.size): + if self.values[i] == t.CInt(v): + return 1 + return 0 + + def total(self) -> T: + result: T = T(0) + for i in range(self.size): + result = result + T(self.values[i]) + return result + +def test_generic_container(): + stdio.printf("--- Test 8: generic Container[T] ---\n") + c = Container() + c.add(10) + c.add(20) + c.add(30) + has20: t.CInt = c.contains(20) + has99: t.CInt = c.contains(99) + total: t.CInt = c.total() + if has20 == 1 and has99 == 0 and total == 60: + stdio.printf("PASS: Container (has20=%d has99=%d total=%d)\n", has20, has99, total) + else: + stdio.printf("FAIL: Container (has20=%d has99=%d total=%d, expect 1 0 60)\n", has20, has99, total) + +# ============================================================ +# Test 9: 泛型函数 - 阶乘 +# ============================================================ +def factorial[T](n: T) -> T: + result: T = T(1) + i: T = T(2) + while i <= n: + result = result * i + i = i + T(1) + return result + +def test_generic_factorial(): + stdio.printf("--- Test 9: generic factorial ---\n") + r1: t.CInt = factorial(5) + r2: t.CInt = factorial(10) + if r1 == 120 and r2 == 3628800: + stdio.printf("PASS: factorial (5!=%d 10!=%d)\n", r1, r2) + else: + stdio.printf("FAIL: factorial (5!=%d 10!=%d, expect 120 3628800)\n", r1, r2) + +# ============================================================ +# Test 10: 泛型类 - 累加器 +# ============================================================ +class Accumulator[T](): + total: T + + def __init__(self, start: T): + self.total = T(start) + + def add_val(self, v: T): + self.total = self.total + v + + def get_result(self) -> T: + return self.total + +def test_generic_accumulator(): + stdio.printf("--- Test 10: generic Accumulator[T] ---\n") + a = Accumulator(0) + a.add_val(10) + a.add_val(20) + a.add_val(30) + r: t.CInt = a.get_result() + if r == 60: + stdio.printf("PASS: Accumulator (result=%d)\n", r) + else: + stdio.printf("FAIL: Accumulator (result=%d, expect 60)\n", r) + +def main() -> t.CInt: + stdio.printf("=== GenericTest2: Advanced Generic Tests ===\n\n") + test_generic_square_types() + test_generic_clamp() + test_generic_stack() + test_generic_swap() + test_generic_range() + test_generic_array_sum() + test_generic_max_three() + test_generic_container() + test_generic_factorial() + test_generic_accumulator() + stdio.printf("\n=== GenericTest2 Complete ===\n") + return 0 diff --git a/Test/GenericTest2/output/1348b0e29ea228ad.deps.json b/Test/GenericTest2/output/1348b0e29ea228ad.deps.json new file mode 100644 index 0000000..073d6e7 --- /dev/null +++ b/Test/GenericTest2/output/1348b0e29ea228ad.deps.json @@ -0,0 +1 @@ +{"stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/GenericTest2/project.json b/Test/GenericTest2/project.json new file mode 100644 index 0000000..3e88e9a --- /dev/null +++ b/Test/GenericTest2/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "GenericTest2", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "GenericTest2.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/GenericTest2/temp/1348b0e29ea228ad.pyi b/Test/GenericTest2/temp/1348b0e29ea228ad.pyi new file mode 100644 index 0000000..5272315 --- /dev/null +++ b/Test/GenericTest2/temp/1348b0e29ea228ad.pyi @@ -0,0 +1,82 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +import t +import stdio +import c + +def square[T](x: T) -> T: pass + +def test_generic_square_types() -> t.CInt: pass + +def clamp[T](val: T, lo: T, hi: T) -> T: pass + +def test_generic_clamp() -> t.CInt: pass + + +class Stack[T]: + data: list[t.CInt, 16] + top: t.CInt + def __init__(self: Stack) -> t.CInt: pass + def push(self: Stack, val: T) -> t.CInt: pass + def pop(self: Stack) -> T: pass + def is_empty(self: Stack) -> t.CInt: pass + +def test_generic_stack() -> t.CInt: pass + + +class IntPair: + a: t.CInt + b: t.CInt + +def generic_swap[T](p: IntPair | t.CPtr) -> t.CInt: pass + +def test_generic_swap() -> t.CInt: pass + + +class Range[T]: + start: T + end_val: T + step: T + def __init__(self: Range, s: T, e: T, st: T) -> t.CInt: pass + def sum_all(self: Range) -> T: pass + +def test_generic_range() -> t.CInt: pass + +def array_sum(arr: list[t.CInt, 8], n: t.CInt) -> t.CInt: pass + +def test_generic_array_sum() -> t.CInt: pass + +def max_of_three[T](a: T, b: T, c_val: T) -> T: pass + +def test_generic_max_three() -> t.CInt: pass + + +class Container[T]: + values: list[t.CInt, 8] + size: t.CInt + def __init__(self: Container) -> t.CInt: pass + def add(self: Container, v: T) -> t.CInt: pass + def get(self: Container, idx: t.CInt) -> T: pass + def contains(self: Container, v: T) -> t.CInt: pass + def total(self: Container) -> T: pass + +def test_generic_container() -> t.CInt: pass + +def factorial[T](n: T) -> T: pass + +def test_generic_factorial() -> t.CInt: pass + + +class Accumulator[T]: + total: T + def __init__(self: Accumulator, start: T) -> t.CInt: pass + def add_val(self: Accumulator, v: T) -> t.CInt: pass + def get_result(self: Accumulator) -> T: pass + +def test_generic_accumulator() -> t.CInt: pass + +def main() -> t.CInt: pass diff --git a/Test/GenericTest2/temp/73edbcf76e32d00b.pyi b/Test/GenericTest2/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/GenericTest2/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/GenericTest2/temp/_sha1_map.txt b/Test/GenericTest2/temp/_sha1_map.txt new file mode 100644 index 0000000..2aae392 --- /dev/null +++ b/Test/GenericTest2/temp/_sha1_map.txt @@ -0,0 +1,2 @@ +1348b0e29ea228ad:main.py +73edbcf76e32d00b:includes/stdio.py diff --git a/Test/IterTest/App/main.py b/Test/IterTest/App/main.py new file mode 100644 index 0000000..89483ac --- /dev/null +++ b/Test/IterTest/App/main.py @@ -0,0 +1,61 @@ +import t +import stdio +import string + +def test_for_in_string(): + stdio.printf("--- Test 1: for-in string iteration ---\n") + s: t.CChar | t.CPtr = "Hello" + result: t.CInt = 0 + for ch in s: + result += ch + # H=72, e=101, l=108, l=108, o=111 => 500 + if result == 500: + stdio.printf("PASS: for-in string (sum=%d)\n", result) + else: + stdio.printf("FAIL: for-in string (sum=%d, expect 500)\n", result) + +def test_for_in_char_ptr(): + stdio.printf("--- Test 2: for-in char* iteration ---\n") + s: t.CChar | t.CPtr = "ABC" + chars: list[t.CInt, 4] = [0] + idx: t.CInt = 0 + for ch in s: + if idx < 3: + chars[idx] = ch + idx += 1 + if chars[0] == 65 and chars[1] == 66 and chars[2] == 67: + stdio.printf("PASS: for-in char* (A=%d B=%d C=%d)\n", chars[0], chars[1], chars[2]) + else: + stdio.printf("FAIL: for-in char* (A=%d B=%d C=%d, expect 65 66 67)\n", chars[0], chars[1], chars[2]) + +def test_strcpy_for_in(): + stdio.printf("--- Test 3: strcpy using for-in ---\n") + src: t.CChar | t.CPtr = "test" + # 手动实现 strcpy 用 for-in + import w32.win32memory + buf: t.CChar | t.CPtr = w32.win32memory.VirtualAlloc(t.CVoid(0, t.CPtr), 64, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 64) + # 用 for-in 复制 + p: t.CChar | t.CPtr = buf + for ch in src: + p[0] = ch + p += 1 + p[0] = 0 + cmp_result: t.CInt = string.strcmp(buf, "test") + if cmp_result == 0: + stdio.printf("PASS: strcpy for-in (result=%s)\n", buf) + else: + stdio.printf("FAIL: strcpy for-in (cmp=%d)\n", cmp_result) + +import w32.win32memory + +def main() -> t.CInt: + stdio.printf("=== IterTest: 指针迭代测试 ===\n\n") + test_for_in_string() + test_for_in_char_ptr() + test_strcpy_for_in() + stdio.printf("\n=== IterTest Complete ===\n") + return 0 diff --git a/Test/IterTest/output/067c78e9f121dce3.deps.json b/Test/IterTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..98471fa --- /dev/null +++ b/Test/IterTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/IterTest/output/29813d57621099a9.deps.json b/Test/IterTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..b357072 --- /dev/null +++ b/Test/IterTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/IterTest/output/5a6a2137958c28c5.deps.json b/Test/IterTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..1eabf36 --- /dev/null +++ b/Test/IterTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/IterTest/output/72e2d5ccb7cedcf1.deps.json b/Test/IterTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..14389ed --- /dev/null +++ b/Test/IterTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/IterTest/output/73a525067569932e.deps.json b/Test/IterTest/output/73a525067569932e.deps.json new file mode 100644 index 0000000..4370328 --- /dev/null +++ b/Test/IterTest/output/73a525067569932e.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6"} \ No newline at end of file diff --git a/Test/IterTest/output/abf9ce3160c9279e.deps.json b/Test/IterTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..14389ed --- /dev/null +++ b/Test/IterTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/IterTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/IterTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..a483152 --- /dev/null +++ b/Test/IterTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/IterTest/output/d044f813487c68b6.deps.json b/Test/IterTest/output/d044f813487c68b6.deps.json new file mode 100644 index 0000000..b6c5f72 --- /dev/null +++ b/Test/IterTest/output/d044f813487c68b6.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/IterTest/output/fa3691e66b426950.deps.json b/Test/IterTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..1eabf36 --- /dev/null +++ b/Test/IterTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "string": "73a525067569932e", "stdio": "73edbcf76e32d00b", "main": "d044f813487c68b6", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/IterTest/project.json b/Test/IterTest/project.json new file mode 100644 index 0000000..95a6a54 --- /dev/null +++ b/Test/IterTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "IterTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "IterTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/IterTest/temp/067c78e9f121dce3.pyi b/Test/IterTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/IterTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/IterTest/temp/29813d57621099a9.pyi b/Test/IterTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/IterTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/IterTest/temp/56cdd754a8a09347.pyi b/Test/IterTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/IterTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/IterTest/temp/5a6a2137958c28c5.pyi b/Test/IterTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/IterTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/IterTest/temp/72e2d5ccb7cedcf1.pyi b/Test/IterTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/IterTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/IterTest/temp/73a525067569932e.pyi b/Test/IterTest/temp/73a525067569932e.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/IterTest/temp/73a525067569932e.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/IterTest/temp/73edbcf76e32d00b.pyi b/Test/IterTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/IterTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/IterTest/temp/_sha1_map.txt b/Test/IterTest/temp/_sha1_map.txt new file mode 100644 index 0000000..5b02c88 --- /dev/null +++ b/Test/IterTest/temp/_sha1_map.txt @@ -0,0 +1,6 @@ +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +72e2d5ccb7cedcf1:includes/w32\win32memory.py +73a525067569932e:includes/string.py +73edbcf76e32d00b:includes/stdio.py +d044f813487c68b6:main.py diff --git a/Test/IterTest/temp/abf9ce3160c9279e.pyi b/Test/IterTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/IterTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/IterTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/IterTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/IterTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/IterTest/temp/d044f813487c68b6.pyi b/Test/IterTest/temp/d044f813487c68b6.pyi new file mode 100644 index 0000000..38923a6 --- /dev/null +++ b/Test/IterTest/temp/d044f813487c68b6.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +import stdio +import string + +def test_for_in_string() -> t.CInt: pass + +def test_for_in_char_ptr() -> t.CInt: pass + +def test_strcpy_for_in() -> t.CInt: pass + + +import w32.win32memory + +def main() -> t.CInt: pass diff --git a/Test/IterTest/temp/fa3691e66b426950.pyi b/Test/IterTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/IterTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/JsonTest/App/main.py b/Test/JsonTest/App/main.py new file mode 100644 index 0000000..c852779 --- /dev/null +++ b/Test/JsonTest/App/main.py @@ -0,0 +1,338 @@ +import t, c +from stdint import * +from stdio import printf +import mpool +import json +import string +import w32.win32memory as win32mem + +# ============================================================ +# 测试计数器 +# ============================================================ +_pass_count: t.CInt = 0 +_fail_count: t.CInt = 0 + +def check(name: t.CChar | t.CPtr, condition: bool): + global _pass_count, _fail_count + if condition: + _pass_count += 1 + printf(" [PASS] %s\n", name) + else: + _fail_count += 1 + printf(" [FAIL] %s\n", name) + + +# ============================================================ +# 测试 1:构造 JSON 值(使用 mpool) +# ============================================================ +def test_construct(pool: mpool.MPool | t.CPtr): + printf("\n+-- Construct JsonValue (with mpool) --+\n") + + # null + v1: json.JsonValue | t.CPtr = json.null(pool) + check("null is_null", v1.is_null()) + + # bool + v2: json.JsonValue | t.CPtr = json.bool_val(pool, True) + check("bool true is_bool", v2.is_bool()) + check("bool true as_bool", v2.as_bool()) + + v3: json.JsonValue | t.CPtr = json.bool_val(pool, False) + check("bool false !as_bool", not v3.as_bool()) + + # int + v4: json.JsonValue | t.CPtr = json.int_val(pool, 42) + check("int is_int", v4.is_int()) + check("int 42 == 42", v4.as_int() == 42) + + v5: json.JsonValue | t.CPtr = json.int_val(pool, -100) + check("int -100 == -100", v5.as_int() == -100) + + # float + v6: json.JsonValue | t.CPtr = json.float_val(pool, 3.14) + check("float is_float", v6.is_float()) + check("float 3.14 ~= 3.14", v6.as_float() > 3.13 and v6.as_float() < 3.15) + + # string + v7: json.JsonValue | t.CPtr = json.string_val(pool, "hello") + check("string is_string", v7.is_string()) + check("string == hello", string.strcmp(v7.as_string(), "hello") == 0) + + # array + v8: json.JsonValue | t.CPtr = json.array(pool) + check("array is_array", v8.is_array()) + check("array empty len()==0", len(v8) == 0) + + # object + v9: json.JsonValue | t.CPtr = json.object(pool) + check("object is_object", v9.is_object()) + check("object empty len()==0", len(v9) == 0) + + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 2:构造数组和对象(Python风格API) +# ============================================================ +def test_build_structures(pool: mpool.MPool | t.CPtr): + printf("\n+-- Build Arrays and Objects (Pythonic API) --+\n") + + # 构建数组 [1, 2, 3] + arr: json.JsonValue | t.CPtr = json.array(pool) + json.array_append(pool, arr, json.int_val(pool, 1)) + json.array_append(pool, arr, json.int_val(pool, 2)) + json.array_append(pool, arr, json.int_val(pool, 3)) + check("array [1,2,3] len()==3", len(arr) == 3) + check("array get_item(0)==1", arr.get_item(0).as_int() == 1) + check("array get_item(1)==2", arr.get_item(1).as_int() == 2) + check("array get_item(2)==3", arr.get_item(2).as_int() == 3) + + # 构建对象 {"name": "Viper", "version": 1} + obj: json.JsonValue | t.CPtr = json.object(pool) + json.object_set(pool, obj, "name", json.string_val(pool, "Viper")) + json.object_set(pool, obj, "version", json.int_val(pool, 1)) + check("object len()==2", len(obj) == 2) + + # Python风格取值:obj["key"] + name_val: json.JsonValue | t.CPtr = obj["name"] + check("obj['name']==Viper", name_val != None and string.strcmp(name_val.as_string(), "Viper") == 0) + ver_val: json.JsonValue | t.CPtr = obj["version"] + check("obj['version']==1", ver_val != None and ver_val.as_int() == 1) + missing: json.JsonValue | t.CPtr = obj["missing"] + check("obj['missing']==None", missing == None) + + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 3:JSON 解析 +# ============================================================ +def test_parse(pool: mpool.MPool | t.CPtr): + printf("\n+-- Parse JSON --+\n") + + # 解析整数 + v1: json.JsonValue | t.CPtr = json.parse(pool, "42") + check("parse int is_int", v1.is_int()) + check("parse int == 42", v1.as_int() == 42) + + # 解析负数 + v2: json.JsonValue | t.CPtr = json.parse(pool, "-7") + check("parse neg int == -7", v2.as_int() == -7) + + # 解析浮点数 + v3: json.JsonValue | t.CPtr = json.parse(pool, "3.14") + check("parse float is_float", v3.is_float()) + check("parse float ~= 3.14", v3.as_float() > 3.13 and v3.as_float() < 3.15) + + # 解析字符串 + v4: json.JsonValue | t.CPtr = json.parse(pool, '"hello world"') + check("parse string is_string", v4.is_string()) + check("parse string == hello world", string.strcmp(v4.as_string(), "hello world") == 0) + + # 解析布尔 + v5: json.JsonValue | t.CPtr = json.parse(pool, "true") + check("parse true is_bool", v5.is_bool()) + check("parse true as_bool", v5.as_bool()) + + v6: json.JsonValue | t.CPtr = json.parse(pool, "false") + check("parse false !as_bool", not v6.as_bool()) + + # 解析 null + v7: json.JsonValue | t.CPtr = json.parse(pool, "null") + check("parse null is_null", v7.is_null()) + + # 解析数组 + v8: json.JsonValue | t.CPtr = json.parse(pool, "[1, 2, 3]") + check("parse array is_array", v8.is_array()) + check("parse array len()==3", len(v8) == 3) + check("parse array get_item(0)==1", v8.get_item(0).as_int() == 1) + check("parse array get_item(2)==3", v8.get_item(2).as_int() == 3) + + # 解析对象(Python风格取值) + v9: json.JsonValue | t.CPtr = json.parse(pool, '{"x": 10, "y": 20}') + check("parse object is_object", v9.is_object()) + check("parse object len()==2", len(v9) == 2) + x_val: json.JsonValue | t.CPtr = v9["x"] + check("parse obj['x']==10", x_val != None and x_val.as_int() == 10) + y_val: json.JsonValue | t.CPtr = v9["y"] + check("parse obj['y']==20", y_val != None and y_val.as_int() == 20) + + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 4:JSON 序列化 +# ============================================================ +def test_write(pool: mpool.MPool | t.CPtr): + printf("\n+-- Write JSON --+\n") + + # 写整数 + v1: json.JsonValue | t.CPtr = json.int_val(pool, 42) + s1: t.CChar | t.CPtr = json.write(pool, v1, False) + check("write int 42", string.strcmp(s1, "42") == 0) + + # 写字符串 + v2: json.JsonValue | t.CPtr = json.string_val(pool, "hello") + s2: t.CChar | t.CPtr = json.write(pool, v2, False) + check("write string hello", string.strcmp(s2, '"hello"') == 0) + + # 写布尔 + v3: json.JsonValue | t.CPtr = json.bool_val(pool, True) + s3: t.CChar | t.CPtr = json.write(pool, v3, False) + check("write bool true", string.strcmp(s3, "true") == 0) + + v4: json.JsonValue | t.CPtr = json.bool_val(pool, False) + s4: t.CChar | t.CPtr = json.write(pool, v4, False) + check("write bool false", string.strcmp(s4, "false") == 0) + + # 写 null + v5: json.JsonValue | t.CPtr = json.null(pool) + s5: t.CChar | t.CPtr = json.write(pool, v5, False) + check("write null", string.strcmp(s5, "null") == 0) + + # 写数组 + arr: json.JsonValue | t.CPtr = json.array(pool) + json.array_append(pool, arr, json.int_val(pool, 1)) + json.array_append(pool, arr, json.int_val(pool, 2)) + json.array_append(pool, arr, json.int_val(pool, 3)) + s6: t.CChar | t.CPtr = json.write(pool, arr, False) + check("write array [1,2,3]", string.strcmp(s6, "[1,2,3]") == 0) + + # 写对象 + obj: json.JsonValue | t.CPtr = json.object(pool) + json.object_set(pool, obj, "a", json.int_val(pool, 1)) + json.object_set(pool, obj, "b", json.string_val(pool, "x")) + s7: t.CChar | t.CPtr = json.write(pool, obj, False) + check("write object non-null", s7 != None) + + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 5:解析复杂嵌套 JSON(Python风格API) +# ============================================================ +def test_nested(pool: mpool.MPool | t.CPtr): + printf("\n+-- Parse Nested JSON (Pythonic API) --+\n") + + src: t.CChar | t.CPtr = '{"name": "Viper", "version": 1, "features": ["fast", "safe", "portable"], "nested": {"key": "value", "num": 99}}' + root: json.JsonValue | t.CPtr = json.parse(pool, src) + check("nested is_object", root.is_object()) + check("nested len()==4", len(root) == 4) + + # Python风格取值:root["name"] + name: json.JsonValue | t.CPtr = root["name"] + check("root['name']==Viper", name != None and string.strcmp(name.as_string(), "Viper") == 0) + + # root["version"] + ver: json.JsonValue | t.CPtr = root["version"] + check("root['version']==1", ver != None and ver.as_int() == 1) + + # root["features"] 数组 + feat: json.JsonValue | t.CPtr = root["features"] + check("root['features'] is_array", feat != None and feat.is_array()) + check("root['features'] len()==3", feat != None and len(feat) == 3) + check("root['features'][0]==fast", feat != None and string.strcmp(feat.get_item(0).as_string(), "fast") == 0) + check("root['features'][2]==portable", feat != None and string.strcmp(feat.get_item(2).as_string(), "portable") == 0) + + # root["nested"] 对象 + nested: json.JsonValue | t.CPtr = root["nested"] + check("root['nested'] is_object", nested != None and nested.is_object()) + nk: json.JsonValue | t.CPtr = nested["key"] if nested != None else None + check("root['nested']['key']==value", nk != None and string.strcmp(nk.as_string(), "value") == 0) + nn: json.JsonValue | t.CPtr = nested["num"] if nested != None else None + check("root['nested']['num']==99", nn != None and nn.as_int() == 99) + + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 6:mpool 重置后重新使用 +# ============================================================ +def test_mpool_reuse(): + printf("\n+-- MPool Reuse --+\n") + + # 分配内存 + mem: t.CVoid | t.CPtr = win32mem.VirtualAlloc(t.CVoid(0, t.CPtr), 8192, 0x3000, 0x04) + check("VirtualAlloc ok", mem != None) + + pool: mpool.MPool | t.CPtr = mpool.MPool(mem, 8192, 0) + + # 第一次使用 + v1: json.JsonValue | t.CPtr = json.int_val(pool, 100) + check("reuse round1 int==100", v1.as_int() == 100) + + # 重置 mpool + pool.reset() + + # 第二次使用(内存复用) + v2: json.JsonValue | t.CPtr = json.string_val(pool, "reused") + check("reuse round2 string==reused", string.strcmp(v2.as_string(), "reused") == 0) + + # 重置后再解析 + pool.reset() + v3: json.JsonValue | t.CPtr = json.parse(pool, '{"test": true}') + check("reuse round3 parse ok", v3.is_object()) + tv: json.JsonValue | t.CPtr = v3["test"] + check("reuse round3 obj['test']==true", tv != None and tv.as_bool()) + + win32mem.VirtualFree(mem, 0, 0x8000) + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 测试 7:转义字符解析 +# ============================================================ +def test_escape(pool: mpool.MPool | t.CPtr): + printf("\n+-- Escape Characters --+\n") + + # 解析含转义字符的字符串 + v1: json.JsonValue | t.CPtr = json.parse(pool, '"hello\\nworld"') + check("escape \\n is_string", v1.is_string()) + sv1: t.CChar | t.CPtr = v1.as_string() + check("escape \\n contains newline", sv1 != None and sv1[5] == '\n') + + v2: json.JsonValue | t.CPtr = json.parse(pool, '"tab\\there"') + check("escape \\t is_string", v2.is_string()) + sv2: t.CChar | t.CPtr = v2.as_string() + check("escape \\t contains tab", sv2 != None and sv2[3] == '\t') + + v3: json.JsonValue | t.CPtr = json.parse(pool, '"quote\\""') + check("escape \\\" is_string", v3.is_string()) + + printf("+--------------------------------------------+\n") + + +# ============================================================ +# 主函数 +# ============================================================ +def main() -> t.CInt | t.CExport: + printf("=== JSON Library Test (Pythonic API) ===\n") + + # 使用 mpool 的 bump 分配器 + mem: t.CVoid | t.CPtr = win32mem.VirtualAlloc(t.CVoid(0, t.CPtr), 65536, 0x3000, 0x04) + pool: mpool.MPool | t.CPtr = mpool.MPool(mem, 65536, 0) + + test_construct(pool) + pool.reset() + + test_build_structures(pool) + pool.reset() + + test_parse(pool) + pool.reset() + + test_write(pool) + pool.reset() + + test_nested(pool) + pool.reset() + + test_escape(pool) + pool.reset() + + test_mpool_reuse() + + win32mem.VirtualFree(mem, 0, 0x8000) + + printf("\n=== Results: %d passed, %d failed ===\n", _pass_count, _fail_count) + return 0 diff --git a/Test/JsonTest/output/067c78e9f121dce3.deps.json b/Test/JsonTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..b57d746 --- /dev/null +++ b/Test/JsonTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/JsonTest/output/1dd5985fb89f7ef9.deps.json b/Test/JsonTest/output/1dd5985fb89f7ef9.deps.json new file mode 100644 index 0000000..d982a65 --- /dev/null +++ b/Test/JsonTest/output/1dd5985fb89f7ef9.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22"} \ No newline at end of file diff --git a/Test/JsonTest/output/29813d57621099a9.deps.json b/Test/JsonTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..796afbb --- /dev/null +++ b/Test/JsonTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/JsonTest/output/5a6a2137958c28c5.deps.json b/Test/JsonTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..35f5964 --- /dev/null +++ b/Test/JsonTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/JsonTest/output/68c4fe4b12c908e3.deps.json b/Test/JsonTest/output/68c4fe4b12c908e3.deps.json new file mode 100644 index 0000000..796afbb --- /dev/null +++ b/Test/JsonTest/output/68c4fe4b12c908e3.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/JsonTest/output/6aee24fdefa3cbc0.deps.json b/Test/JsonTest/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..2a07779 --- /dev/null +++ b/Test/JsonTest/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22"} \ No newline at end of file diff --git a/Test/JsonTest/output/72e2d5ccb7cedcf1.deps.json b/Test/JsonTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..7f87c7b --- /dev/null +++ b/Test/JsonTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/JsonTest/output/8ee3170049c70333.deps.json b/Test/JsonTest/output/8ee3170049c70333.deps.json new file mode 100644 index 0000000..796afbb --- /dev/null +++ b/Test/JsonTest/output/8ee3170049c70333.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/JsonTest/output/abf9ce3160c9279e.deps.json b/Test/JsonTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..7f87c7b --- /dev/null +++ b/Test/JsonTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/JsonTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/JsonTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..ace4314 --- /dev/null +++ b/Test/JsonTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/JsonTest/output/bd2e7db1744476fe.deps.json b/Test/JsonTest/output/bd2e7db1744476fe.deps.json new file mode 100644 index 0000000..796afbb --- /dev/null +++ b/Test/JsonTest/output/bd2e7db1744476fe.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/JsonTest/output/c9f4be41ca1cc2b4.deps.json b/Test/JsonTest/output/c9f4be41ca1cc2b4.deps.json new file mode 100644 index 0000000..2a07779 --- /dev/null +++ b/Test/JsonTest/output/c9f4be41ca1cc2b4.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22"} \ No newline at end of file diff --git a/Test/JsonTest/output/eaf7a981f0ef5b22.deps.json b/Test/JsonTest/output/eaf7a981f0ef5b22.deps.json new file mode 100644 index 0000000..796afbb --- /dev/null +++ b/Test/JsonTest/output/eaf7a981f0ef5b22.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/JsonTest/output/fa3691e66b426950.deps.json b/Test/JsonTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..35f5964 --- /dev/null +++ b/Test/JsonTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"main": "1dd5985fb89f7ef9", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "json.__init__": "8ee3170049c70333", "__init__": "8ee3170049c70333", "json": "8ee3170049c70333", "json.__parser": "bd2e7db1744476fe", "__parser": "bd2e7db1744476fe", "viperio": "c9f4be41ca1cc2b4", "json.__writer": "eaf7a981f0ef5b22", "__writer": "eaf7a981f0ef5b22", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/JsonTest/project.json b/Test/JsonTest/project.json new file mode 100644 index 0000000..0b4c8a1 --- /dev/null +++ b/Test/JsonTest/project.json @@ -0,0 +1,28 @@ +{ + "name": "JsonTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "JsonTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/JsonTest/temp/067c78e9f121dce3.pyi b/Test/JsonTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/JsonTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/JsonTest/temp/1dd5985fb89f7ef9.pyi b/Test/JsonTest/temp/1dd5985fb89f7ef9.pyi new file mode 100644 index 0000000..9ae6c17 --- /dev/null +++ b/Test/JsonTest/temp/1dd5985fb89f7ef9.pyi @@ -0,0 +1,34 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +import t, c +from stdint import * +from stdio import printf +import mpool +import json +import string +import w32.win32memory as win32mem + +_pass_count: t.CExtern | t.CInt +_fail_count: t.CExtern | t.CInt + +def check(name: t.CChar | t.CPtr, condition: bool) -> t.CInt: pass + +def test_construct(pool: mpool.MPool | t.CPtr) -> t.CInt: pass + +def test_build_structures(pool: mpool.MPool | t.CPtr) -> t.CInt: pass + +def test_parse(pool: mpool.MPool | t.CPtr) -> t.CInt: pass + +def test_write(pool: mpool.MPool | t.CPtr) -> t.CInt: pass + +def test_nested(pool: mpool.MPool | t.CPtr) -> t.CInt: pass + +def test_mpool_reuse() -> t.CInt: pass + +def test_escape(pool: mpool.MPool | t.CPtr) -> t.CInt: pass + +def main() -> t.CInt | t.CExport: pass diff --git a/Test/JsonTest/temp/29813d57621099a9.pyi b/Test/JsonTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/JsonTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/JsonTest/temp/56cdd754a8a09347.pyi b/Test/JsonTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/JsonTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/JsonTest/temp/5a6a2137958c28c5.pyi b/Test/JsonTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/JsonTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/JsonTest/temp/68c4fe4b12c908e3.pyi b/Test/JsonTest/temp/68c4fe4b12c908e3.pyi new file mode 100644 index 0000000..fc2010b --- /dev/null +++ b/Test/JsonTest/temp/68c4fe4b12c908e3.pyi @@ -0,0 +1,50 @@ +""" +Auto-generated Python stub file from mpool.py +Module: mpool +""" + + +import t, c +from stdint import * +import viperio +import string + +MPOOL_ALIGN: t.CDefine = 8 +MPOOL_TYPE_SLAB: t.CDefine = 0 +MPOOL_TYPE_BUMP: t.CDefine = 2 + +def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: pass + + +class MPool: + mtype: t.CInt + mem: t.CVoid | t.CPtr + mem_size: t.CSizeT + offset: t.CSizeT + high_water: t.CSizeT + block_size: t.CSizeT + block_count: t.CSizeT + used_count: t.CSizeT + free_list: t.CVoid | t.CPtr + alloc_map: t.CUInt8T | t.CPtr + alloc_map_size: t.CSizeT + def __init__(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def _init_bump(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> t.CInt: pass + def _init_slab(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def __enter__(self: MPool) -> 'MPool' | t.CPtr: pass + def __exit__(self: MPool) -> t.CInt: pass + def _slab_reset(self: MPool) -> t.CInt: pass + def alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def alloc_buf(self: MPool, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: pass + def free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + def realloc(self: MPool, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, new_size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def reset(self: MPool) -> t.CInt: pass + def _bump_alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def _slab_alloc(self: MPool) -> t.CVoid | t.CPtr: pass + def _slab_free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + +def bump_create(mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> MPool | t.CPtr: pass + +def alloc(pool: MPool | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def reset(pool: MPool | t.CPtr) -> t.CInt: pass diff --git a/Test/JsonTest/temp/6aee24fdefa3cbc0.pyi b/Test/JsonTest/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/JsonTest/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/JsonTest/temp/72e2d5ccb7cedcf1.pyi b/Test/JsonTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/JsonTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/JsonTest/temp/73edbcf76e32d00b.pyi b/Test/JsonTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/JsonTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/JsonTest/temp/8ee3170049c70333.pyi b/Test/JsonTest/temp/8ee3170049c70333.pyi new file mode 100644 index 0000000..8e3fa45 --- /dev/null +++ b/Test/JsonTest/temp/8ee3170049c70333.pyi @@ -0,0 +1,71 @@ +""" +Auto-generated Python stub file from json.__init__.py +Module: json.__init__ +""" + + +import t, c +from stdint import * +import mpool +import string +import viperio + +JSON_NULL: t.CDefine = 0 +JSON_BOOL: t.CDefine = 1 +JSON_INT: t.CDefine = 2 +JSON_FLOAT: t.CDefine = 3 +JSON_STRING: t.CDefine = 4 +JSON_ARRAY: t.CDefine = 5 +JSON_OBJECT: t.CDefine = 6 + +class JsonValue: + vtype: t.CInt + bool_val: t.CInt + int_val: t.CInt64T + float_val: t.CDouble + str_val: t.CChar | t.CPtr + next: JsonValue | t.CPtr + key: t.CChar | t.CPtr + child: JsonValue | t.CPtr + child_count: t.CSizeT + def __new__(self: JsonValue, pool: mpool.MPool | t.CPtr) -> t.CInt: pass + def type(self: JsonValue) -> t.CInt: pass + def is_null(self: JsonValue) -> bool: pass + def is_bool(self: JsonValue) -> bool: pass + def is_int(self: JsonValue) -> bool: pass + def is_float(self: JsonValue) -> bool: pass + def is_string(self: JsonValue) -> bool: pass + def is_array(self: JsonValue) -> bool: pass + def is_object(self: JsonValue) -> bool: pass + def as_bool(self: JsonValue) -> bool: pass + def as_int(self: JsonValue) -> t.CInt64T: pass + def as_float(self: JsonValue) -> t.CDouble: pass + def as_string(self: JsonValue) -> t.CChar | t.CPtr: pass + def __len__(self: JsonValue) -> t.CSizeT: pass + def __getitem__(self: JsonValue, key: t.CChar | t.CPtr) -> JsonValue | t.CPtr: pass + def __setitem__(self: JsonValue, key: t.CChar | t.CPtr, val: JsonValue | t.CPtr) -> t.CInt: pass + def get_item(self: JsonValue, index: t.CSizeT) -> JsonValue | t.CPtr: pass + def _pool_alloc(self: JsonValue, size: t.CSizeT) -> t.CChar | t.CPtr: pass + def _append_child(self: JsonValue, child: JsonValue | t.CPtr) -> t.CInt: pass + +def null(pool: mpool.MPool | t.CPtr) -> JsonValue | t.CPtr: pass + +def bool_val(pool: mpool.MPool | t.CPtr, val: bool) -> JsonValue | t.CPtr: pass + +def int_val(pool: mpool.MPool | t.CPtr, val: t.CInt64T) -> JsonValue | t.CPtr: pass + +def float_val(pool: mpool.MPool | t.CPtr, val: t.CDouble) -> JsonValue | t.CPtr: pass + +def string_val(pool: mpool.MPool | t.CPtr, val: t.CChar | t.CPtr) -> JsonValue | t.CPtr: pass + +def array(pool: mpool.MPool | t.CPtr) -> JsonValue | t.CPtr: pass + +def object(pool: mpool.MPool | t.CPtr) -> JsonValue | t.CPtr: pass + +def array_append(pool: mpool.MPool | t.CPtr, arr: JsonValue | t.CPtr, item: JsonValue | t.CPtr) -> t.CInt: pass + +def object_set(pool: mpool.MPool | t.CPtr, obj: JsonValue | t.CPtr, key: t.CChar | t.CPtr, val: JsonValue | t.CPtr) -> t.CInt: pass + + +from .__parser import parse +from .__writer import write \ No newline at end of file diff --git a/Test/JsonTest/temp/_sha1_map.txt b/Test/JsonTest/temp/_sha1_map.txt new file mode 100644 index 0000000..05d6b42 --- /dev/null +++ b/Test/JsonTest/temp/_sha1_map.txt @@ -0,0 +1,11 @@ +1dd5985fb89f7ef9:main.py +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +68c4fe4b12c908e3:includes/mpool.py +6aee24fdefa3cbc0:includes/string.py +72e2d5ccb7cedcf1:includes/w32\win32memory.py +73edbcf76e32d00b:includes/stdio.py +8ee3170049c70333:includes/json\__init__.py +bd2e7db1744476fe:includes/json\__parser.py +c9f4be41ca1cc2b4:includes/viperio.py +eaf7a981f0ef5b22:includes/json\__writer.py diff --git a/Test/JsonTest/temp/abf9ce3160c9279e.pyi b/Test/JsonTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/JsonTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/JsonTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/JsonTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/JsonTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/JsonTest/temp/bd2e7db1744476fe.pyi b/Test/JsonTest/temp/bd2e7db1744476fe.pyi new file mode 100644 index 0000000..c332a45 --- /dev/null +++ b/Test/JsonTest/temp/bd2e7db1744476fe.pyi @@ -0,0 +1,38 @@ +""" +Auto-generated Python stub file from json.__parser.py +Module: json.__parser +""" + + +import t, c +from stdint import * +import mpool +import string +from . import JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT, JSON_STRING, JSON_ARRAY, JSON_OBJECT, null, bool_val, int_val, float_val, string_val, array, object + +class ParseState: + src: t.CChar | t.CPtr + pos: t.CSizeT + len: t.CSizeT + pool: mpool.MPool | t.CPtr + def __init__(self: ParseState, src: t.CChar | t.CPtr, pool: mpool.MPool | t.CPtr) -> t.CInt: pass + +def _peek(s: ParseState | t.CPtr) -> t.CChar: pass + +def _advance(s: ParseState | t.CPtr) -> t.CChar: pass + +def _skip_whitespace(s: ParseState | t.CPtr) -> t.CInt: pass + +def _expect(s: ParseState | t.CPtr, ch: t.CChar) -> bool: pass + +def _parse_string(s: ParseState | t.CPtr) -> t.CChar | t.CPtr: pass + +def _parse_number(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: pass + +def _parse_value(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: pass + +def _parse_array(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: pass + +def _parse_object(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: pass + +def parse(pool: mpool.MPool | t.CPtr, src: t.CChar | t.CPtr) -> JsonValue | t.CPtr: pass diff --git a/Test/JsonTest/temp/c9f4be41ca1cc2b4.pyi b/Test/JsonTest/temp/c9f4be41ca1cc2b4.pyi new file mode 100644 index 0000000..fdbd7ec --- /dev/null +++ b/Test/JsonTest/temp/c9f4be41ca1cc2b4.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from viperio.py +Module: viperio +""" + + +import t, c +from stdint import * + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CInt: pass + def clear(self: Buf) -> t.CInt: pass + def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: pass + def cstr(self: Buf) -> t.CChar | t.CPtr: pass + def reset(self: Buf) -> t.CInt: pass + def __enter__(self: Buf) -> 'Buf' | t.CPtr: pass + def __exit__(self: Buf) -> t.CInt: pass + def free(self: Buf) -> t.CInt: pass \ No newline at end of file diff --git a/Test/JsonTest/temp/eaf7a981f0ef5b22.pyi b/Test/JsonTest/temp/eaf7a981f0ef5b22.pyi new file mode 100644 index 0000000..5f9da84 --- /dev/null +++ b/Test/JsonTest/temp/eaf7a981f0ef5b22.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from json.__writer.py +Module: json.__writer +""" + + +import t, c +from stdint import * +import mpool +import string +from stdio import snprintf +from . import JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT, JSON_STRING, JSON_ARRAY, JSON_OBJECT + +def _write_char(buf: t.CChar | t.CPtr, pos: t.CSizeT, ch: t.CChar) -> t.CSizeT: pass + +def _write_str(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT: pass + +def _write_string_escaped(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT: pass + +def _write_value(buf: t.CChar | t.CPtr, pos: t.CSizeT, val: JsonValue | t.CPtr, pool: mpool.MPool | t.CPtr) -> t.CSizeT: pass + +def write(pool: mpool.MPool | t.CPtr, val: JsonValue | t.CPtr, pretty: bool) -> t.CChar | t.CPtr: pass diff --git a/Test/JsonTest/temp/fa3691e66b426950.pyi b/Test/JsonTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/JsonTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/LoopTest/App/main.py b/Test/LoopTest/App/main.py new file mode 100644 index 0000000..e096524 --- /dev/null +++ b/Test/LoopTest/App/main.py @@ -0,0 +1,99 @@ +import t +import stdio + +def test_for_loop(): + stdio.printf("--- Test 1: for loop ---\n") + sum_val: t.CInt = 0 + for i in range(10): + sum_val += i + # 0+1+2+...+9 = 45 + if sum_val == 45: + stdio.printf("PASS: for loop sum (0..9 = %d)\n", sum_val) + else: + stdio.printf("FAIL: for loop sum (%d, expect 45)\n", sum_val) + +def test_while_loop(): + stdio.printf("--- Test 2: while loop ---\n") + n: t.CInt = 100 + count: t.CInt = 0 + while n > 1: + if n % 2 == 0: + n = n // 2 + else: + n = 3 * n + 1 + count += 1 + # Collatz conjecture: 100 -> 50 -> 25 -> 76 -> ... -> 1, takes 25 steps + stdio.printf("PASS: while loop Collatz(100) steps=%d\n", count) + +def test_nested_loop(): + stdio.printf("--- Test 3: nested loop ---\n") + count: t.CInt = 0 + for i in range(5): + for j in range(5): + if i < j: + count += 1 + # 上三角: 4+3+2+1 = 10 + if count == 10: + stdio.printf("PASS: nested loop (count=%d)\n", count) + else: + stdio.printf("FAIL: nested loop (count=%d, expect 10)\n", count) + +def test_break(): + stdio.printf("--- Test 4: break ---\n") + found: t.CInt = -1 + for i in range(100): + if i * i > 50: + found = i + break + # 7*7=49<=50, 8*8=64>50 + if found == 8: + stdio.printf("PASS: break (found=%d)\n", found) + else: + stdio.printf("FAIL: break (found=%d, expect 8)\n", found) + +def test_continue(): + stdio.printf("--- Test 5: continue ---\n") + sum_val: t.CInt = 0 + for i in range(20): + if i % 3 == 0: + continue + sum_val += i + # 跳过 0,3,6,9,12,15,18, 剩余和 = sum(0..19) - sum(0,3,6,9,12,15,18) = 190 - 63 = 127 + if sum_val == 127: + stdio.printf("PASS: continue (sum=%d)\n", sum_val) + else: + stdio.printf("FAIL: continue (sum=%d, expect 127)\n", sum_val) + +def test_range_step(): + stdio.printf("--- Test 6: range with step ---\n") + sum_val: t.CInt = 0 + for i in range(0, 20, 3): + sum_val += i + # 0+3+6+9+12+15+18 = 63 + if sum_val == 63: + stdio.printf("PASS: range step (sum=%d)\n", sum_val) + else: + stdio.printf("FAIL: range step (sum=%d, expect 63)\n", sum_val) + +def test_loop_u64(): + stdio.printf("--- Test 7: loop with u64 counter ---\n") + total: t.CUInt64T = 0 + for i in range(100): + total += t.CUInt64T(i) + # 0+1+2+...+99 = 4950 + if total == 4950: + stdio.printf("PASS: u64 loop (total=%lu)\n", total) + else: + stdio.printf("FAIL: u64 loop (total=%lu, expect 4950)\n", total) + +def main() -> t.CInt: + stdio.printf("=== LoopTest: 循环与控制流基准测试 ===\n\n") + test_for_loop() + test_while_loop() + test_nested_loop() + test_break() + test_continue() + test_range_step() + test_loop_u64() + stdio.printf("\n=== LoopTest Complete ===\n") + return 0 diff --git a/Test/LoopTest/output/4b6b35e3922a169f.deps.json b/Test/LoopTest/output/4b6b35e3922a169f.deps.json new file mode 100644 index 0000000..073d6e7 --- /dev/null +++ b/Test/LoopTest/output/4b6b35e3922a169f.deps.json @@ -0,0 +1 @@ +{"stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/LoopTest/project.json b/Test/LoopTest/project.json new file mode 100644 index 0000000..55f3b06 --- /dev/null +++ b/Test/LoopTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "LoopTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "LoopTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/LoopTest/temp/4b6b35e3922a169f.pyi b/Test/LoopTest/temp/4b6b35e3922a169f.pyi new file mode 100644 index 0000000..b2fe521 --- /dev/null +++ b/Test/LoopTest/temp/4b6b35e3922a169f.pyi @@ -0,0 +1,26 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +import stdio + +def test_for_loop() -> t.CInt: pass + +def test_while_loop() -> t.CInt: pass + +def test_nested_loop() -> t.CInt: pass + +def test_break() -> t.CInt: pass + +def test_continue() -> t.CInt: pass + +def test_range_step() -> t.CInt: pass + +def test_loop_u64() -> t.CInt: pass + +def main() -> t.CInt: pass diff --git a/Test/LoopTest/temp/73edbcf76e32d00b.pyi b/Test/LoopTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/LoopTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/LoopTest/temp/_sha1_map.txt b/Test/LoopTest/temp/_sha1_map.txt new file mode 100644 index 0000000..176573f --- /dev/null +++ b/Test/LoopTest/temp/_sha1_map.txt @@ -0,0 +1,2 @@ +4b6b35e3922a169f:main.py +73edbcf76e32d00b:includes/stdio.py diff --git a/Test/PointerTest/App/main.py b/Test/PointerTest/App/main.py new file mode 100644 index 0000000..bc6be7e --- /dev/null +++ b/Test/PointerTest/App/main.py @@ -0,0 +1,267 @@ +from stdint import * +import t, c +import stdio +import string +import w32.win32console +import w32.win32memory + +# ============================================================ +# PointerTest - 测试指针操作、global声明、数组退化、指针算术 +# ============================================================ + +# --- Test 1: global 声明对模块级变量的影响 --- +_g_val: t.CInt = 0 +_g_ptr: t.CUInt32T | t.CPtr = None + +def test_global_write(): + """测试:缺少 global 声明时,赋值是否修改模块级变量""" + global _g_val + _g_val = 42 + +def test_global_write_no_decl(): + """测试:没有 global 声明时,赋值是否创建局部变量""" + # 注意:这里故意不声明 global,测试编译器行为 + # 如果 _g_val 在此函数之前被读取过,赋值会修改全局变量 + # 如果 _g_val 在此函数中首次被赋值,会创建局部变量 + _g_val = 99 # 这应该创建一个局部变量 + +def test_global_ptr(): + global _g_ptr + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04) + if buf: + string.memset(buf, 0, 256) + _g_ptr = buf + p: t.CUInt32T | t.CPtr = _g_ptr + p[0] = 0xAABBCCDD + p[1] = 0x11223344 + +def test_global_ptr_no_decl(): + """测试:没有 global 声明时,指针赋值是否创建局部变量""" + # _g_ptr 在 test_global_ptr 中已被赋值(有 global) + # 这里读取 _g_ptr 然后赋值 — 读取会将全局变量加入 Gen.variables + # 所以后续赋值应该修改全局变量 + old: t.CUInt32T | t.CPtr = _g_ptr # 读取 -> 加入 Gen.variables + _g_ptr = None # 因为之前读取过,这应该修改全局变量 + + +# --- Test 2: 指针算术和数组索引 --- +def test_pointer_arithmetic(): + """测试指针算术:偏移计算是否正确""" + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04) + if not buf: + stdio.printf("FAIL: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 256) + + # 写入值 + for i in range(8): + buf[i] = t.CUInt32T(i * 100) + + # 读取并验证 + ok: t.CInt = 1 + for i in range(8): + v: t.CUInt32T = buf[i] + expected: t.CUInt32T = t.CUInt32T(i * 100) + if v != expected: + stdio.printf("FAIL: buf[%d] = 0x%x, expected 0x%x\n", i, v, expected) + ok = 0 + if ok: + stdio.printf("PASS: pointer arithmetic (buf[i] = i*100)\n") + + +# --- Test 3: 数组退化为指针 --- +def test_array_decay(): + """测试 list[t.CChar, N] 传递给 t.CConst | str 参数""" + arr: list[t.CChar, 32] + string.memset(c.Addr(arr), 0, 32) + # 手动写入字符串 + src: str = "Hello" + for i in range(5): + arr[i] = t.CChar(ord(src[i])) + arr[5] = 0 + + # 传递给 print (接受 t.CConst | str) + stdio.printf("PASS: array decay -> %s\n", c.Addr(arr)) + + +# --- Test 4: 指针类型转换 (CVoid/CPtr) --- +def test_pointer_cast(): + """测试指针与整数之间的类型转换""" + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04) + if not buf: + stdio.printf("FAIL: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 256) + + # 通过 CVoid 指针写入 + raw: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(buf), t.CPtr) + # 将 CVoid 指针转回 CUInt32T 指针 + p32: t.CUInt32T | t.CPtr = (t.CUInt32T | t.CPtr)(raw) + p32[0] = 0xDEADBEEF + + # 通过原始指针读取 + if buf[0] == 0xDEADBEEF: + stdio.printf("PASS: pointer cast CVoid -> CUInt32T*\n") + else: + stdio.printf("FAIL: pointer cast, got 0x%x\n", buf[0]) + + +# --- Test 5: 指针偏移计算 (byte offset vs element offset) --- +def test_pointer_offset(): + """测试指针偏移:CUInt8T* + N 应该偏移 N 字节,CUInt32T* + N 应该偏移 N*4 字节""" + buf: t.CUInt8T | t.CPtr = w32.win32memory.VirtualAlloc(None, 256, 0x3000, 0x04) + if not buf: + stdio.printf("FAIL: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 256) + + # 写入 4 字节 + buf[0] = 0x41 # 'A' + buf[1] = 0x42 # 'B' + buf[2] = 0x43 # 'C' + buf[3] = 0x44 # 'D' + + # 通过 CUInt32T* 读取(应该读到 0x44434241 on little-endian) + p32: t.CUInt32T | t.CPtr = (t.CUInt32T | t.CPtr)(t.CVoid(t.CUInt64T(buf), t.CPtr)) + val: t.CUInt32T = p32[0] + + # little-endian: 0x44434241 + if val == 0x44434241: + stdio.printf("PASS: byte offset vs element offset (0x%x)\n", val) + else: + stdio.printf("FAIL: expected 0x44434241, got 0x%x\n", val) + + +# --- Test 6: 结构体指针访问 --- +class TestStruct(): + a: t.CInt + b: t.CInt + c: t.CUInt64T + +def test_struct_pointer(): + """测试结构体指针的成员访问""" + s: TestStruct + s.a = 10 + s.b = 20 + s.c = 0x123456789ABCDEF0 + + p: TestStruct | t.CPtr = c.Addr(s) + if p.a == 10 and p.b == 20 and p.c == 0x123456789ABCDEF0: + stdio.printf("PASS: struct pointer access (a=%d b=%d c=0x%llx)\n", p.a, p.b, p.c) + else: + stdio.printf("FAIL: struct pointer access (a=%d b=%d c=0x%llx)\n", p.a, p.b, p.c) + + +# --- Test 7: memcpy/memset 通过指针 --- +def test_memcpy_pointers(): + """测试 memcpy 在指针之间的数据复制""" + src_buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04) + dst_buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04) + if not src_buf or not dst_buf: + stdio.printf("FAIL: VirtualAlloc returned NULL\n") + return + + # 初始化 src + for i in range(8): + src_buf[i] = t.CUInt32T(i + 1000) + + # 复制 + string.memcpy(t.CVoid(t.CUInt64T(dst_buf), t.CPtr), t.CVoid(t.CUInt64T(src_buf), t.CPtr), 32) + + # 验证 + ok: t.CInt = 1 + for i in range(8): + if dst_buf[i] != t.CUInt32T(i + 1000): + stdio.printf("FAIL: dst[%d] = %u, expected %u\n", i, dst_buf[i], i + 1000) + ok = 0 + if ok: + stdio.printf("PASS: memcpy between pointers\n") + + +# --- Test 8: 指针作为函数参数 --- +def fill_array(arr: t.CUInt32T | t.CPtr, count: t.CInt, val: t.CUInt32T): + for i in range(count): + arr[i] = val + +def test_pointer_param(): + """测试指针作为函数参数传递""" + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04) + if not buf: + stdio.printf("FAIL: VirtualAlloc returned NULL\n") + return + + fill_array(buf, 8, 0xCAFEBABE) + + ok: t.CInt = 1 + for i in range(8): + if buf[i] != 0xCAFEBABE: + ok = 0 + if ok: + stdio.printf("PASS: pointer as function parameter\n") + else: + stdio.printf("FAIL: pointer as function parameter\n") + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + stdio.printf("=== PointerTest: 指针操作基准测试 ===\n\n") + + # Test 1: global 声明 + stdio.printf("--- Test 1: global declaration ---\n") + _g_val = 0 + test_global_write() + stdio.printf("After test_global_write(): _g_val = %d (expect 42)\n", _g_val) + test_global_write_no_decl() + stdio.printf("After test_global_write_no_decl(): _g_val = %d (expect 42, not 99)\n", _g_val) + stdio.printf("\n") + + # Test 1b: global pointer + stdio.printf("--- Test 1b: global pointer ---\n") + test_global_ptr() + if _g_ptr: + p: t.CUInt32T | t.CPtr = _g_ptr + stdio.printf("_g_ptr[0] = 0x%x (expect 0xAABBCCDD)\n", p[0]) + stdio.printf("_g_ptr[1] = 0x%x (expect 0x11223344)\n", p[1]) + test_global_ptr_no_decl() + stdio.printf("After test_global_ptr_no_decl(): _g_ptr = %p (expect NULL/0)\n", t.CVoid(t.CUInt64T(_g_ptr), t.CPtr)) + stdio.printf("\n") + + # Test 2: pointer arithmetic + stdio.printf("--- Test 2: pointer arithmetic ---\n") + test_pointer_arithmetic() + stdio.printf("\n") + + # Test 3: array decay + stdio.printf("--- Test 3: array decay ---\n") + test_array_decay() + stdio.printf("\n") + + # Test 4: pointer cast + stdio.printf("--- Test 4: pointer cast ---\n") + test_pointer_cast() + stdio.printf("\n") + + # Test 5: pointer offset + stdio.printf("--- Test 5: pointer offset (byte vs element) ---\n") + test_pointer_offset() + stdio.printf("\n") + + # Test 6: struct pointer + stdio.printf("--- Test 6: struct pointer access ---\n") + test_struct_pointer() + stdio.printf("\n") + + # Test 7: memcpy pointers + stdio.printf("--- Test 7: memcpy between pointers ---\n") + test_memcpy_pointers() + stdio.printf("\n") + + # Test 8: pointer as param + stdio.printf("--- Test 8: pointer as function parameter ---\n") + test_pointer_param() + stdio.printf("\n") + + stdio.printf("=== PointerTest Complete ===\n") + return 0 diff --git a/Test/PointerTest/output/067c78e9f121dce3.deps.json b/Test/PointerTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..998d71f --- /dev/null +++ b/Test/PointerTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/PointerTest/output/29813d57621099a9.deps.json b/Test/PointerTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..b446460 --- /dev/null +++ b/Test/PointerTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/PointerTest/output/4d5db7f970ef510f.deps.json b/Test/PointerTest/output/4d5db7f970ef510f.deps.json new file mode 100644 index 0000000..13ff2b2 --- /dev/null +++ b/Test/PointerTest/output/4d5db7f970ef510f.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3"} \ No newline at end of file diff --git a/Test/PointerTest/output/5a6a2137958c28c5.deps.json b/Test/PointerTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..04173c7 --- /dev/null +++ b/Test/PointerTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/PointerTest/output/72e2d5ccb7cedcf1.deps.json b/Test/PointerTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..8c29b5d --- /dev/null +++ b/Test/PointerTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/PointerTest/output/PointerTest.exe.tmp0 b/Test/PointerTest/output/PointerTest.exe.tmp0 new file mode 100644 index 0000000..1db13da Binary files /dev/null and b/Test/PointerTest/output/PointerTest.exe.tmp0 differ diff --git a/Test/PointerTest/output/abf9ce3160c9279e.deps.json b/Test/PointerTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..8c29b5d --- /dev/null +++ b/Test/PointerTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/PointerTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/PointerTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..04173c7 --- /dev/null +++ b/Test/PointerTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/PointerTest/output/e0c894447ac34ed3.deps.json b/Test/PointerTest/output/e0c894447ac34ed3.deps.json new file mode 100644 index 0000000..1965c34 --- /dev/null +++ b/Test/PointerTest/output/e0c894447ac34ed3.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/PointerTest/output/fa3691e66b426950.deps.json b/Test/PointerTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..04173c7 --- /dev/null +++ b/Test/PointerTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "e0c894447ac34ed3", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/PointerTest/project.json b/Test/PointerTest/project.json new file mode 100644 index 0000000..acaef76 --- /dev/null +++ b/Test/PointerTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "PointerTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "PointerTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/PointerTest/temp/067c78e9f121dce3.pyi b/Test/PointerTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/PointerTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/PointerTest/temp/29813d57621099a9.pyi b/Test/PointerTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/PointerTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/PointerTest/temp/4d5db7f970ef510f.pyi b/Test/PointerTest/temp/4d5db7f970ef510f.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/PointerTest/temp/4d5db7f970ef510f.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/PointerTest/temp/56cdd754a8a09347.pyi b/Test/PointerTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/PointerTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/PointerTest/temp/5a6a2137958c28c5.pyi b/Test/PointerTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/PointerTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/PointerTest/temp/72e2d5ccb7cedcf1.pyi b/Test/PointerTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/PointerTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/PointerTest/temp/73edbcf76e32d00b.pyi b/Test/PointerTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/PointerTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/PointerTest/temp/_sha1_map.txt b/Test/PointerTest/temp/_sha1_map.txt new file mode 100644 index 0000000..46d0124 --- /dev/null +++ b/Test/PointerTest/temp/_sha1_map.txt @@ -0,0 +1,7 @@ +4d5db7f970ef510f:includes/string.py +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +72e2d5ccb7cedcf1:includes/w32\win32memory.py +73edbcf76e32d00b:includes/stdio.py +bbdf3bbd4c3bc28c:includes/w32\win32console.py +e0c894447ac34ed3:main.py diff --git a/Test/PointerTest/temp/abf9ce3160c9279e.pyi b/Test/PointerTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/PointerTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/PointerTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/PointerTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/PointerTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/PointerTest/temp/e0c894447ac34ed3.pyi b/Test/PointerTest/temp/e0c894447ac34ed3.pyi new file mode 100644 index 0000000..1f0670c --- /dev/null +++ b/Test/PointerTest/temp/e0c894447ac34ed3.pyi @@ -0,0 +1,47 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +from stdint import * +import t, c +import stdio +import string +import w32.win32console +import w32.win32memory + +_g_val: t.CExtern | t.CInt +_g_ptr: t.CExtern | t.CUInt32T | t.CPtr + +def test_global_write() -> t.CInt: pass + +def test_global_write_no_decl() -> t.CInt: pass + +def test_global_ptr() -> t.CInt: pass + +def test_global_ptr_no_decl() -> t.CInt: pass + +def test_pointer_arithmetic() -> t.CInt: pass + +def test_array_decay() -> t.CInt: pass + +def test_pointer_cast() -> t.CInt: pass + +def test_pointer_offset() -> t.CInt: pass + + +class TestStruct: + a: t.CInt + b: t.CInt + c: t.CUInt64T + +def test_struct_pointer() -> t.CInt: pass + +def test_memcpy_pointers() -> t.CInt: pass + +def fill_array(arr: t.CUInt32T | t.CPtr, count: t.CInt, val: t.CUInt32T) -> t.CInt: pass + +def test_pointer_param() -> t.CInt: pass + +def main() -> t.CInt | t.CExport: pass diff --git a/Test/PointerTest/temp/fa3691e66b426950.pyi b/Test/PointerTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/PointerTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/SimdTest/App/main.py b/Test/SimdTest/App/main.py new file mode 100644 index 0000000..8f81dd9 --- /dev/null +++ b/Test/SimdTest/App/main.py @@ -0,0 +1,517 @@ +from stdint import * +import vipersimd +import numpy +from stdio import printf +import stdlib +from stdlib import calloc +import t, c +import mpool + + +# 全局内存池 +arena: t.CUInt8T | t.CPtr = None +pool: mpool.MPool | t.CPtr = None + +# 外部函数: clock() 用于性能计时 +def clock() -> t.CLong | t.CExtern: pass + +CLOCK_PER_SEC: t.CDefine = 1000 + +test_passed: t.CInt = 0 +test_failed: t.CInt = 0 + +def check(name: str, condition: t.CInt, detail: str): + global test_passed, test_failed + if condition: + test_passed += 1 + printf(" [PASS] %s\n", name) + else: + test_failed += 1 + printf(" [FAIL] %s -- %s\n", name, detail if detail else "") + +def section(title: str): + printf("\n=== %s ===\n", title) + + +# ============================================================ +# 1. AVX2 double4 正确性测试 +# ============================================================ + +def test_avx2_add_sub_mul_div(): + section("AVX2 add/sub/mul/div 4d") + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(2.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(4.0) + + b: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + b.data[0] = t.CDouble(5.0) + b.data[1] = t.CDouble(6.0) + b.data[2] = t.CDouble(7.0) + b.data[3] = t.CDouble(8.0) + + out: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + + # add + vipersimd.simd_add4d(a.data, b.data, out.data) + check("add[0]==6", out.data[0] == t.CDouble(6.0), "") + check("add[1]==8", out.data[1] == t.CDouble(8.0), "") + check("add[2]==10", out.data[2] == t.CDouble(10.0), "") + check("add[3]==12", out.data[3] == t.CDouble(12.0), "") + + # sub + vipersimd.simd_sub4d(a.data, b.data, out.data) + check("sub[0]==-4", out.data[0] == t.CDouble(-4.0), "") + check("sub[3]==-4", out.data[3] == t.CDouble(-4.0), "") + + # mul + vipersimd.simd_mul4d(a.data, b.data, out.data) + check("mul[0]==5", out.data[0] == t.CDouble(5.0), "") + check("mul[1]==12", out.data[1] == t.CDouble(12.0), "") + check("mul[2]==21", out.data[2] == t.CDouble(21.0), "") + check("mul[3]==32", out.data[3] == t.CDouble(32.0), "") + + # div + vipersimd.simd_div4d(b.data, a.data, out.data) + check("div[0]==5", out.data[0] == t.CDouble(5.0), "") + check("div[1]==3", out.data[1] == t.CDouble(3.0), "") + + a.delete() + b.delete() + out.delete() + + +def test_avx2_neg_abs_sqrt(): + section("AVX2 neg/abs/sqrt 4d") + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(-4.0) + a.data[2] = t.CDouble(9.0) + a.data[3] = t.CDouble(-16.0) + + out: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + + # neg + vipersimd.simd_neg4d(a.data, out.data) + check("neg[0]==-1", out.data[0] == t.CDouble(-1.0), "") + check("neg[1]==4", out.data[1] == t.CDouble(4.0), "") + check("neg[2]==-9", out.data[2] == t.CDouble(-9.0), "") + check("neg[3]==16", out.data[3] == t.CDouble(16.0), "") + + # abs + vipersimd.simd_abs4d(a.data, out.data) + check("abs[0]==1", out.data[0] == t.CDouble(1.0), "") + check("abs[1]==4", out.data[1] == t.CDouble(4.0), "") + check("abs[2]==9", out.data[2] == t.CDouble(9.0), "") + check("abs[3]==16", out.data[3] == t.CDouble(16.0), "") + + # sqrt + vipersimd.simd_sqrt4d(out.data, out.data) + check("sqrt[0]==1", out.data[0] == t.CDouble(1.0), "") + check("sqrt[1]==2", out.data[1] == t.CDouble(2.0), "") + check("sqrt[2]==3", out.data[2] == t.CDouble(3.0), "") + check("sqrt[3]==4", out.data[3] == t.CDouble(4.0), "") + + a.delete() + out.delete() + + +def test_avx2_min_max(): + section("AVX2 min/max 4d") + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(8.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(6.0) + + b: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + b.data[0] = t.CDouble(5.0) + b.data[1] = t.CDouble(2.0) + b.data[2] = t.CDouble(7.0) + b.data[3] = t.CDouble(4.0) + + out: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + + vipersimd.simd_min4d(a.data, b.data, out.data) + check("min[0]==1", out.data[0] == t.CDouble(1.0), "") + check("min[1]==2", out.data[1] == t.CDouble(2.0), "") + check("min[2]==3", out.data[2] == t.CDouble(3.0), "") + check("min[3]==4", out.data[3] == t.CDouble(4.0), "") + + vipersimd.simd_max4d(a.data, b.data, out.data) + check("max[0]==5", out.data[0] == t.CDouble(5.0), "") + check("max[1]==8", out.data[1] == t.CDouble(8.0), "") + check("max[2]==7", out.data[2] == t.CDouble(7.0), "") + check("max[3]==6", out.data[3] == t.CDouble(6.0), "") + + a.delete() + b.delete() + out.delete() + + +def test_avx2_scalar_ops(): + section("AVX2 scalar broadcast ops") + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(2.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(4.0) + + s: numpy.ndarray | t.CPtr = numpy.zeros(pool, 1) + s.data[0] = t.CDouble(10.0) + + out: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + + vipersimd.simd_mul_scalar4d(a.data, s.data, out.data) + check("mul_scalar[0]==10", out.data[0] == t.CDouble(10.0), "") + check("mul_scalar[1]==20", out.data[1] == t.CDouble(20.0), "") + check("mul_scalar[3]==40", out.data[3] == t.CDouble(40.0), "") + + vipersimd.simd_add_scalar4d(a.data, s.data, out.data) + check("add_scalar[0]==11", out.data[0] == t.CDouble(11.0), "") + check("add_scalar[3]==14", out.data[3] == t.CDouble(14.0), "") + + a.delete() + s.delete() + out.delete() + + +def test_avx2_hsum_dot(): + section("AVX2 hsum/dot 4d") + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(2.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(4.0) + + b: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + b.data[0] = t.CDouble(5.0) + b.data[1] = t.CDouble(6.0) + b.data[2] = t.CDouble(7.0) + b.data[3] = t.CDouble(8.0) + + out: numpy.ndarray | t.CPtr = numpy.zeros(pool, 1) + + vipersimd.simd_hsum4d(a.data, out.data) + check("hsum==10", out.data[0] == t.CDouble(10.0), "") + + vipersimd.simd_dot4d(a.data, b.data, out.data) + check("dot==70", out.data[0] == t.CDouble(70.0), "") + + a.delete() + b.delete() + out.delete() + + +def test_avx2_fma(): + section("AVX2 FMA 4d") + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0) + a.data[1] = t.CDouble(2.0) + a.data[2] = t.CDouble(3.0) + a.data[3] = t.CDouble(4.0) + + b: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + b.data[0] = t.CDouble(5.0) + b.data[1] = t.CDouble(6.0) + b.data[2] = t.CDouble(7.0) + b.data[3] = t.CDouble(8.0) + + c_val: numpy.ndarray | t.CPtr = numpy.ones(pool, 4) + + out: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + + vipersimd.simd_fma4d(a.data, b.data, c_val.data, out.data) + check("fma[0]==6", out.data[0] == t.CDouble(6.0), "") + check("fma[1]==13", out.data[1] == t.CDouble(13.0), "") + check("fma[2]==22", out.data[2] == t.CDouble(22.0), "") + check("fma[3]==33", out.data[3] == t.CDouble(33.0), "") + + a.delete() + b.delete() + c_val.delete() + out.delete() + + +# ============================================================ +# 2. 批量数组运算正确性测试 +# ============================================================ + +def test_batch_array_ops(): + section("Batch array operations") + n: t.CSizeT = 16 + a: numpy.ndarray | t.CPtr = numpy.arange(pool, t.CDouble(1.0), t.CDouble(17.0), t.CDouble(1.0)) + b: numpy.ndarray | t.CPtr = numpy.full(pool, 16, t.CDouble(2.0)) + out: numpy.ndarray | t.CPtr = numpy.zeros(pool, 16) + + # add array + vipersimd.simd_add_array(a.data, b.data, out.data, n) + check("add_arr[0]==3", out.data[0] == t.CDouble(3.0), "") + check("add_arr[15]==18", out.data[15] == t.CDouble(18.0), "") + + # mul array + vipersimd.simd_mul_array(a.data, b.data, out.data, n) + check("mul_arr[0]==2", out.data[0] == t.CDouble(2.0), "") + check("mul_arr[3]==8", out.data[3] == t.CDouble(8.0), "") + + # sqrt array + c: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + c.data[0] = t.CDouble(4.0) + c.data[1] = t.CDouble(9.0) + c.data[2] = t.CDouble(16.0) + c.data[3] = t.CDouble(25.0) + out4: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + vipersimd.simd_sqrt_array(c.data, out4.data, t.CSizeT(4)) + check("sqrt_arr[0]==2", out4.data[0] == t.CDouble(2.0), "") + check("sqrt_arr[3]==5", out4.data[3] == t.CDouble(5.0), "") + + # abs array + d: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + d.data[0] = t.CDouble(-1.0) + d.data[1] = t.CDouble(-2.0) + d.data[2] = t.CDouble(3.0) + d.data[3] = t.CDouble(-4.0) + vipersimd.simd_abs_array(d.data, out4.data, t.CSizeT(4)) + check("abs_arr[0]==1", out4.data[0] == t.CDouble(1.0), "") + check("abs_arr[1]==2", out4.data[1] == t.CDouble(2.0), "") + check("abs_arr[3]==4", out4.data[3] == t.CDouble(4.0), "") + + # dot array + e: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + e.data[0] = t.CDouble(1.0) + e.data[1] = t.CDouble(2.0) + e.data[2] = t.CDouble(3.0) + e.data[3] = t.CDouble(4.0) + f: numpy.ndarray | t.CPtr = numpy.ones(pool, 4) + out1: numpy.ndarray | t.CPtr = numpy.zeros(pool, 1) + vipersimd.simd_dot_array(e.data, f.data, t.CSizeT(4), out1.data) + check("dot_arr==10", out1.data[0] == t.CDouble(10.0), "") + + a.delete() + b.delete() + out.delete() + c.delete() + out4.delete() + d.delete() + e.delete() + f.delete() + out1.delete() + + +# ============================================================ +# 3. LLVMIR 精确标量运算测试 +# ============================================================ + +def test_llvmir_scalar(): + section("LLVMIR precise scalar ops") + + # sqrt + r: t.CDouble = vipersimd.simd_sqrt(t.CDouble(4.0)) + check("sqrt(4)==2", r == t.CDouble(2.0), "") + + # fabs + r = vipersimd.simd_fabs(t.CDouble(-3.5)) + check("fabs(-3.5)==3.5", r == t.CDouble(3.5), "") + + # floor + r = vipersimd.simd_floor(t.CDouble(3.7)) + check("floor(3.7)==3", r == t.CDouble(3.0), "") + + # ceil + r = vipersimd.simd_ceil(t.CDouble(3.2)) + check("ceil(3.2)==4", r == t.CDouble(4.0), "") + + # round + r = vipersimd.simd_round(t.CDouble(3.5)) + check("round(3.5)==4", r == t.CDouble(4.0), "") + + # trunc + r = vipersimd.simd_trunc(t.CDouble(3.9)) + check("trunc(3.9)==3", r == t.CDouble(3.0), "") + + # fma: 2*3+1 = 7 + r = vipersimd.simd_fma(t.CDouble(2.0), t.CDouble(3.0), t.CDouble(1.0)) + check("fma(2,3,1)==7", r == t.CDouble(7.0), "") + + # copysign + r = vipersimd.simd_copysign(t.CDouble(3.0), t.CDouble(-1.0)) + check("copysign(3,-1)==-3", r == t.CDouble(-3.0), "") + + # neg + r = vipersimd.simd_neg(t.CDouble(1.5)) + check("neg(1.5)==-1.5", r == t.CDouble(-1.5), "") + + # minnum + r = vipersimd.simd_minnum(t.CDouble(2.0), t.CDouble(3.0)) + check("minnum(2,3)==2", r == t.CDouble(2.0), "") + + # maxnum + r = vipersimd.simd_maxnum(t.CDouble(2.0), t.CDouble(3.0)) + check("maxnum(2,3)==3", r == t.CDouble(3.0), "") + + # exp + r = vipersimd.simd_exp(t.CDouble(1.0)) + check("exp(1)~=2.718", r > t.CDouble(2.71) and r < t.CDouble(2.72), "") + + # log + r = vipersimd.simd_log(t.CDouble(2.718281828459045)) + check("log(e)~=1", r > t.CDouble(0.999) and r < t.CDouble(1.001), "") + + # sin + r = vipersimd.simd_sin(t.CDouble(0.0)) + check("sin(0)~=0", r > t.CDouble(-0.001) and r < t.CDouble(0.001), "") + + # cos + r = vipersimd.simd_cos(t.CDouble(0.0)) + check("cos(0)~=1", r > t.CDouble(0.999) and r < t.CDouble(1.001), "") + + # pow + r = vipersimd.simd_pow(t.CDouble(2.0), t.CDouble(10.0)) + check("pow(2,10)==1024", r == t.CDouble(1024.0), "") + + +# ============================================================ +# 4. 性能基准测试: SIMD vs 标量 +# ============================================================ + +N_ELEM: t.CDefine = 40000 +N_ITER: t.CDefine = 50000 + +def scalar_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): + i: t.CSizeT = 0 + da: t.CDouble | t.CPtr = a + db: t.CDouble | t.CPtr = b + dout: t.CDouble | t.CPtr = out + while i < n: + dout[i] = da[i] + db[i] + i += 1 + +def scalar_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT): + i: t.CSizeT = 0 + da: t.CDouble | t.CPtr = a + db: t.CDouble | t.CPtr = b + dout: t.CDouble | t.CPtr = out + while i < n: + dout[i] = da[i] * db[i] + i += 1 + +def scalar_sqrt_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT): + i: t.CSizeT = 0 + da: t.CDouble | t.CPtr = a + dout: t.CDouble | t.CPtr = out + while i < n: + dout[i] = vipersimd.simd_sqrt(da[i]) + i += 1 + +def benchmark_simd_vs_scalar(): + section("Benchmark: SIMD vs Scalar") + + a: numpy.ndarray | t.CPtr = numpy.full(pool, N_ELEM, t.CDouble(1.5)) + b: numpy.ndarray | t.CPtr = numpy.full(pool, N_ELEM, t.CDouble(2.5)) + out: numpy.ndarray | t.CPtr = numpy.zeros(pool, N_ELEM) + + # --- SIMD add benchmark --- + t0: t.CLong = clock() + iter: t.CInt = 0 + while iter < N_ITER: + vipersimd.simd_add_array(a.data, b.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1: t.CLong = clock() + simd_add_ms: t.CLong = t1 - t0 + + # --- Scalar add benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + scalar_add_array(a.data, b.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + scalar_add_ms: t.CLong = t1 - t0 + + printf(" ADD: SIMD=%ldms Scalar=%ldms", simd_add_ms, scalar_add_ms) + if scalar_add_ms > 0: + printf(" speedup=%.1fx\n", t.CDouble(scalar_add_ms) / t.CDouble(simd_add_ms)) + else: + printf(" speedup=N/A\n") + + # --- SIMD mul benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + vipersimd.simd_mul_array(a.data, b.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + simd_mul_ms: t.CLong = t1 - t0 + + # --- Scalar mul benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + scalar_mul_array(a.data, b.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + scalar_mul_ms: t.CLong = t1 - t0 + + printf(" MUL: SIMD=%ldms Scalar=%ldms", simd_mul_ms, scalar_mul_ms) + if scalar_mul_ms > 0: + printf(" speedup=%.1fx\n", t.CDouble(scalar_mul_ms) / t.CDouble(simd_mul_ms)) + else: + printf(" speedup=N/A\n") + + # --- SIMD sqrt benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + vipersimd.simd_sqrt_array(a.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + simd_sqrt_ms: t.CLong = t1 - t0 + + # --- Scalar sqrt benchmark --- + t0 = clock() + iter = 0 + while iter < N_ITER: + scalar_sqrt_array(a.data, out.data, t.CSizeT(N_ELEM)) + iter += 1 + t1 = clock() + scalar_sqrt_ms: t.CLong = t1 - t0 + + printf(" SQRT: SIMD=%ldms Scalar=%ldms", simd_sqrt_ms, scalar_sqrt_ms) + if scalar_sqrt_ms > 0: + printf(" speedup=%.1fx\n", t.CDouble(scalar_sqrt_ms) / t.CDouble(simd_sqrt_ms)) + else: + printf(" speedup=N/A\n") + + # 验证结果正确性 + check("bench result[0] valid", out.data[0] > t.CDouble(0.0), "") + + a.delete() + b.delete() + out.delete() + + +# ============================================================ +# Main +# ============================================================ + +def main() -> t.CInt: + global arena, pool + + arena = calloc(4096 * 1024, 1) # 4MB arena + pool = mpool.MPool(arena, 4096 * 1024, 0) # bump allocator + + printf("=== ViperSIMD Test Suite ===\n") + + test_avx2_add_sub_mul_div() + test_avx2_neg_abs_sqrt() + test_avx2_min_max() + test_avx2_scalar_ops() + test_avx2_hsum_dot() + test_avx2_fma() + test_batch_array_ops() + test_llvmir_scalar() + benchmark_simd_vs_scalar() + + printf("\n=== Results: %d passed, %d failed ===\n", test_passed, test_failed) + return 0 diff --git a/Test/SimdTest/output/024a3459d0f585ae.deps.json b/Test/SimdTest/output/024a3459d0f585ae.deps.json new file mode 100644 index 0000000..3ad8593 --- /dev/null +++ b/Test/SimdTest/output/024a3459d0f585ae.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/1b666d438f4d301e.deps.json b/Test/SimdTest/output/1b666d438f4d301e.deps.json new file mode 100644 index 0000000..f4ea96d --- /dev/null +++ b/Test/SimdTest/output/1b666d438f4d301e.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/3f7c5e78d8652535.deps.json b/Test/SimdTest/output/3f7c5e78d8652535.deps.json new file mode 100644 index 0000000..3ad8593 --- /dev/null +++ b/Test/SimdTest/output/3f7c5e78d8652535.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/68c4fe4b12c908e3.deps.json b/Test/SimdTest/output/68c4fe4b12c908e3.deps.json new file mode 100644 index 0000000..3ad8593 --- /dev/null +++ b/Test/SimdTest/output/68c4fe4b12c908e3.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/c3eb91093118e1e1.deps.json b/Test/SimdTest/output/c3eb91093118e1e1.deps.json new file mode 100644 index 0000000..3ad8593 --- /dev/null +++ b/Test/SimdTest/output/c3eb91093118e1e1.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/c9f4be41ca1cc2b4.deps.json b/Test/SimdTest/output/c9f4be41ca1cc2b4.deps.json new file mode 100644 index 0000000..3ad8593 --- /dev/null +++ b/Test/SimdTest/output/c9f4be41ca1cc2b4.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/output/fe99c83946298690.deps.json b/Test/SimdTest/output/fe99c83946298690.deps.json new file mode 100644 index 0000000..3ad8593 --- /dev/null +++ b/Test/SimdTest/output/fe99c83946298690.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "main": "1b666d438f4d301e", "vipermath": "3f7c5e78d8652535", "stdint": "56cdd754a8a09347", "mpool": "68c4fe4b12c908e3", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "numpy.__init__": "c3eb91093118e1e1", "__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "vipersimd": "fe99c83946298690"} \ No newline at end of file diff --git a/Test/SimdTest/project.json b/Test/SimdTest/project.json new file mode 100644 index 0000000..56a1581 --- /dev/null +++ b/Test/SimdTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "SimdTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "SimdTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/SimdTest/temp/024a3459d0f585ae.pyi b/Test/SimdTest/temp/024a3459d0f585ae.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/SimdTest/temp/024a3459d0f585ae.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/SimdTest/temp/1b666d438f4d301e.pyi b/Test/SimdTest/temp/1b666d438f4d301e.pyi new file mode 100644 index 0000000..f6cf141 --- /dev/null +++ b/Test/SimdTest/temp/1b666d438f4d301e.pyi @@ -0,0 +1,58 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +from stdint import * +import vipersimd +import numpy +from stdio import printf +import stdlib +from stdlib import calloc +import t, c +import mpool + +arena: t.CExtern | t.CUInt8T | t.CPtr +pool: t.CExtern | mpool.MPool | t.CPtr + +def clock() -> t.CLong | t.CExtern: pass + + +CLOCK_PER_SEC: t.CDefine = 1000 +test_passed: t.CExtern | t.CInt +test_failed: t.CExtern | t.CInt + +def check(name: str, condition: t.CInt, detail: str) -> t.CInt: pass + +def section(title: str) -> t.CInt: pass + +def test_avx2_add_sub_mul_div() -> t.CInt: pass + +def test_avx2_neg_abs_sqrt() -> t.CInt: pass + +def test_avx2_min_max() -> t.CInt: pass + +def test_avx2_scalar_ops() -> t.CInt: pass + +def test_avx2_hsum_dot() -> t.CInt: pass + +def test_avx2_fma() -> t.CInt: pass + +def test_batch_array_ops() -> t.CInt: pass + +def test_llvmir_scalar() -> t.CInt: pass + + +N_ELEM: t.CDefine = 40000 +N_ITER: t.CDefine = 50000 + +def scalar_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def scalar_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def scalar_sqrt_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def benchmark_simd_vs_scalar() -> t.CInt: pass + +def main() -> t.CInt: pass diff --git a/Test/SimdTest/temp/3f7c5e78d8652535.pyi b/Test/SimdTest/temp/3f7c5e78d8652535.pyi new file mode 100644 index 0000000..abe01c2 --- /dev/null +++ b/Test/SimdTest/temp/3f7c5e78d8652535.pyi @@ -0,0 +1,128 @@ +""" +Auto-generated Python stub file from vipermath.py +Module: vipermath +""" + + +import t, c + +U_M_PI: t.CDefine = 3.14159265358979323846 +U_M_E: t.CDefine = 2.71828182845904523536 +U_M_PI_2: t.CDefine = 1.57079632679489661923 +U_M_PI_4: t.CDefine = 0.78539816339744830962 +U_M_1_PI: t.CDefine = 0.31830988618379067154 +U_M_2_PI: t.CDefine = 0.63661977236758134308 +U_M_LN2: t.CDefine = 0.69314718055994530942 +U_M_LN10: t.CDefine = 2.30258509299404568402 +U_M_2_SQRT_PI: t.CDefine = 1.77245385090551602730 + +def radians(degrees: t.CDouble) -> t.CDouble: pass + +def degrees(radians: t.CDouble) -> t.CDouble: pass + +def sin(x: t.CDouble) -> t.CDouble: pass + +def cos(x: t.CDouble) -> t.CDouble: pass + +def tan(x: t.CDouble) -> t.CDouble: pass + +def asin(x: t.CDouble) -> t.CDouble: pass + +def acos(x: t.CDouble) -> t.CDouble: pass + +def _atan_core(x: t.CDouble) -> t.CDouble: pass + +def atan(x: t.CDouble) -> t.CDouble: pass + +def atan2(y: t.CDouble, x: t.CDouble) -> t.CDouble: pass + +def sinh(x: t.CDouble) -> t.CDouble: pass + +def cosh(x: t.CDouble) -> t.CDouble: pass + +def tanh(x: t.CDouble) -> t.CDouble: pass + +def exp(x: t.CDouble) -> t.CDouble: pass + +def log(x: t.CDouble) -> t.CDouble: pass + +def sqrt(x: t.CDouble) -> t.CDouble: pass + +def abs(x: t.CInt) -> t.CInt: pass + +def fabs(x: t.CDouble) -> t.CDouble: pass + +def labs(x: t.CLong) -> t.CLong: pass + +def factorial(n: t.CInt) -> t.CDouble: pass + +def combination(n: t.CInt, k: t.CInt) -> t.CDouble: pass + +def permutation(n: t.CInt, k: t.CInt) -> t.CDouble: pass + +def pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass + +def powf(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass + +def cbrt(x: t.CDouble) -> t.CDouble: pass + +def hypot(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass + +def floor(x: t.CDouble) -> t.CDouble: pass + +def ceil(x: t.CDouble) -> t.CDouble: pass + +def round(x: t.CDouble) -> t.CDouble: pass + +def trunc(x: t.CDouble) -> t.CDouble: pass + +def fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass + +def fmodf(x: float, y: float) -> float: pass + +def modf(x: t.CDouble, iptr: t.CDouble | t.CPtr) -> t.CDouble: pass + +def log10(x: t.CDouble) -> t.CDouble: pass + +def log2(x: t.CDouble) -> t.CDouble: pass + +def exp2(x: t.CDouble) -> t.CDouble: pass + +def expm1(x: t.CDouble) -> t.CDouble: pass + +def log1p(x: t.CDouble) -> t.CDouble: pass + +def asinh(x: t.CDouble) -> t.CDouble: pass + +def acosh(x: t.CDouble) -> t.CDouble: pass + +def atanh(x: t.CDouble) -> t.CDouble: pass + +def gamma(x: t.CDouble) -> t.CDouble: pass + +def erf(x: t.CDouble) -> t.CDouble: pass + +def erfc(x: t.CDouble) -> t.CDouble: pass + +def sqrtf(x: t.CFloat) -> t.CFloat: pass + +def sinf(x: t.CFloat) -> t.CFloat: pass + +def cosf(x: t.CFloat) -> t.CFloat: pass + +def tanf(x: t.CFloat) -> t.CFloat: pass + +def fabsf(x: t.CFloat) -> t.CFloat: pass + +def floorf(x: t.CFloat) -> t.CFloat: pass + +def ceilf(x: t.CFloat) -> t.CFloat: pass + + +class _U(t.CUnion): + d: t.CDouble + u: t.CUInt64T + +def isnan(x: t.CDouble) -> t.CStatic | t.CInt: pass + +def isinf(x: t.CDouble) -> t.CStatic | t.CInt: pass diff --git a/Test/SimdTest/temp/56cdd754a8a09347.pyi b/Test/SimdTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/SimdTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/SimdTest/temp/68c4fe4b12c908e3.pyi b/Test/SimdTest/temp/68c4fe4b12c908e3.pyi new file mode 100644 index 0000000..fc2010b --- /dev/null +++ b/Test/SimdTest/temp/68c4fe4b12c908e3.pyi @@ -0,0 +1,50 @@ +""" +Auto-generated Python stub file from mpool.py +Module: mpool +""" + + +import t, c +from stdint import * +import viperio +import string + +MPOOL_ALIGN: t.CDefine = 8 +MPOOL_TYPE_SLAB: t.CDefine = 0 +MPOOL_TYPE_BUMP: t.CDefine = 2 + +def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: pass + + +class MPool: + mtype: t.CInt + mem: t.CVoid | t.CPtr + mem_size: t.CSizeT + offset: t.CSizeT + high_water: t.CSizeT + block_size: t.CSizeT + block_count: t.CSizeT + used_count: t.CSizeT + free_list: t.CVoid | t.CPtr + alloc_map: t.CUInt8T | t.CPtr + alloc_map_size: t.CSizeT + def __init__(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def _init_bump(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> t.CInt: pass + def _init_slab(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def __enter__(self: MPool) -> 'MPool' | t.CPtr: pass + def __exit__(self: MPool) -> t.CInt: pass + def _slab_reset(self: MPool) -> t.CInt: pass + def alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def alloc_buf(self: MPool, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: pass + def free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + def realloc(self: MPool, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, new_size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def reset(self: MPool) -> t.CInt: pass + def _bump_alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def _slab_alloc(self: MPool) -> t.CVoid | t.CPtr: pass + def _slab_free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + +def bump_create(mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> MPool | t.CPtr: pass + +def alloc(pool: MPool | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def reset(pool: MPool | t.CPtr) -> t.CInt: pass diff --git a/Test/SimdTest/temp/73edbcf76e32d00b.pyi b/Test/SimdTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/SimdTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/SimdTest/temp/7538e542cab4c1d5.pyi b/Test/SimdTest/temp/7538e542cab4c1d5.pyi new file mode 100644 index 0000000..b5313af --- /dev/null +++ b/Test/SimdTest/temp/7538e542cab4c1d5.pyi @@ -0,0 +1,18 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def calloc(nmemb: UINT, size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/SimdTest/temp/_sha1_map.txt b/Test/SimdTest/temp/_sha1_map.txt new file mode 100644 index 0000000..8dd8e2c --- /dev/null +++ b/Test/SimdTest/temp/_sha1_map.txt @@ -0,0 +1,10 @@ +024a3459d0f585ae:includes/string.py +1b666d438f4d301e:main.py +3f7c5e78d8652535:includes/vipermath.py +56cdd754a8a09347:includes/stdint.py +68c4fe4b12c908e3:includes/mpool.py +73edbcf76e32d00b:includes/stdio.py +7538e542cab4c1d5:includes/stdlib.py +c3eb91093118e1e1:includes/numpy\__init__.py +c9f4be41ca1cc2b4:includes/viperio.py +fe99c83946298690:includes/vipersimd.py diff --git a/Test/SimdTest/temp/c3eb91093118e1e1.pyi b/Test/SimdTest/temp/c3eb91093118e1e1.pyi new file mode 100644 index 0000000..adb6481 --- /dev/null +++ b/Test/SimdTest/temp/c3eb91093118e1e1.pyi @@ -0,0 +1,234 @@ +""" +Auto-generated Python stub file from numpy.__init__.py +Module: numpy.__init__ +""" + + +from stdint import * +import stdlib +import string +import vipermath +import stdio +import t, c +import mpool + +MAX_NDIM: t.CDefine = 4 +float64: t.CTypedef = t.CDouble +float32: t.CTypedef = t.CFloat +int64: t.CTypedef = t.CLong +int32: t.CTypedef = t.CInt +uint8: t.CTypedef = t.CUnsignedChar +pi: t.CDefine = 3.14159265358979323846 +e: t.CDefine = 2.71828182845904523536 + +@t.Object +class ndarray: + data: t.CDouble | t.CPtr + shape: list[t.CSizeT, MAX_NDIM] + strides: list[t.CSizeT, MAX_NDIM] + ndim: t.CInt + size: t.CSizeT + owns_data: t.CInt + pool: mpool.MPool | t.CPtr + def __new__(self: ndarray, pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> t.CInt: pass + def __add__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __sub__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __mul__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __truediv__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __floordiv__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __mod__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __neg__(self: ndarray) -> 'ndarray' | t.CPtr: pass + def __len__(self: ndarray) -> t.CInt: pass + def at2d(self: ndarray, row: t.CSizeT, col: t.CSizeT) -> t.CDouble: pass + def set2d(self: ndarray, row: t.CSizeT, col: t.CSizeT, val: t.CDouble) -> t.CInt: pass + def delete(self: ndarray) -> t.CInt: pass + def fill(self: ndarray, val: t.CDouble) -> t.CInt: pass + def copy(self: ndarray) -> 'ndarray' | t.CPtr: pass + def reshape(self: ndarray, new_shape: INTPTR, new_ndim: t.CInt) -> 'ndarray' | t.CPtr: pass + def sum(self: ndarray) -> t.CDouble: pass + def mean(self: ndarray) -> t.CDouble: pass + def min(self: ndarray) -> t.CDouble: pass + def max(self: ndarray) -> t.CDouble: pass + def argmax(self: ndarray) -> t.CInt: pass + def argmin(self: ndarray) -> t.CInt: pass + def dot(self: ndarray, other: 'ndarray' | t.CPtr) -> t.CDouble: pass + def T(self: ndarray) -> 'ndarray' | t.CPtr: pass + def print_arr(self: ndarray) -> t.CInt: pass + +def _alloc_ndarray(pool: mpool.MPool | t.CPtr) -> ndarray | t.CPtr: pass + +def _compute_strides(a: ndarray | t.CPtr) -> t.CInt: pass + +def _empty_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def array(pool: mpool.MPool | t.CPtr, data: t.CDouble | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def zeros(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def ones(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def full(pool: mpool.MPool | t.CPtr, n: t.CSizeT, val: t.CDouble) -> ndarray | t.CPtr: pass + +def arange(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble, step: t.CDouble) -> ndarray | t.CPtr: pass + +def linspace(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble, num: t.CSizeT) -> ndarray | t.CPtr: pass + +def empty2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: pass + +def zeros2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: pass + +def ones2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: pass + +def eye(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def diag(pool: mpool.MPool | t.CPtr, vals: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_abs(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_sqrt(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_exp(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_log(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_sin(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_cos(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_tan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_pow(a: ndarray | t.CPtr, p: t.CDouble) -> ndarray | t.CPtr: pass + +def add_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: pass + +def mul_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: pass + +def sub_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: pass + +def div_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: pass + +def matmul(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def dot_product(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> t.CDouble: pass + +def np_sum(a: ndarray | t.CPtr) -> t.CDouble: pass + +def np_mean(a: ndarray | t.CPtr) -> t.CDouble: pass + +def np_min(a: ndarray | t.CPtr) -> t.CDouble: pass + +def np_max(a: ndarray | t.CPtr) -> t.CDouble: pass + +def np_argmax(a: ndarray | t.CPtr) -> t.CInt: pass + +def np_argmin(a: ndarray | t.CPtr) -> t.CInt: pass + +def var(a: ndarray | t.CPtr) -> t.CDouble: pass + +def std(a: ndarray | t.CPtr) -> t.CDouble: pass + +def norm(a: ndarray | t.CPtr) -> t.CDouble: pass + +def clip(a: ndarray | t.CPtr, lo: t.CDouble, hi: t.CDouble) -> ndarray | t.CPtr: pass + +def concatenate(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def sort_arr(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def reverse(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_log10(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_log2(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_floor(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_ceil(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_round(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_sign(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_tanh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_sinh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_cosh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_arcsin(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_arccos(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_arctan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_arctan2(y: ndarray | t.CPtr, x: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_degrees(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_radians(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_isnan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_isinf(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_maximum(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_minimum(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def cumsum(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def diff(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def flatten(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def trace(a: ndarray | t.CPtr) -> t.CDouble: pass + +def outer(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_where(condition: ndarray | t.CPtr, x: ndarray | t.CPtr, y: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_count_nonzero(a: ndarray | t.CPtr) -> t.CInt: pass + +def np_all(a: ndarray | t.CPtr) -> t.CInt: pass + +def np_any(a: ndarray | t.CPtr) -> t.CInt: pass + +def np_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_not_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_less(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_greater(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_less_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_greater_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def empty(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def full2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT, val: t.CDouble) -> ndarray | t.CPtr: pass + +def zeros_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def ones_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def arange1(pool: mpool.MPool | t.CPtr, stop: t.CDouble) -> ndarray | t.CPtr: pass + +def linspace2(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble) -> ndarray | t.CPtr: pass + +def meshgrid(x: ndarray | t.CPtr, y: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def det2x2(a: ndarray | t.CPtr) -> t.CDouble: pass + +def inv2x2(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def cross3(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_interp(x: t.CDouble, xp: ndarray | t.CPtr, fp: ndarray | t.CPtr) -> t.CDouble: pass + +def prod(a: ndarray | t.CPtr) -> t.CDouble: pass + +def median(a: ndarray | t.CPtr) -> t.CDouble: pass + +def percentile(a: ndarray | t.CPtr, q: t.CDouble) -> t.CDouble: pass diff --git a/Test/SimdTest/temp/c9f4be41ca1cc2b4.pyi b/Test/SimdTest/temp/c9f4be41ca1cc2b4.pyi new file mode 100644 index 0000000..fdbd7ec --- /dev/null +++ b/Test/SimdTest/temp/c9f4be41ca1cc2b4.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from viperio.py +Module: viperio +""" + + +import t, c +from stdint import * + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CInt: pass + def clear(self: Buf) -> t.CInt: pass + def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: pass + def cstr(self: Buf) -> t.CChar | t.CPtr: pass + def reset(self: Buf) -> t.CInt: pass + def __enter__(self: Buf) -> 'Buf' | t.CPtr: pass + def __exit__(self: Buf) -> t.CInt: pass + def free(self: Buf) -> t.CInt: pass \ No newline at end of file diff --git a/Test/SimdTest/temp/fe99c83946298690.pyi b/Test/SimdTest/temp/fe99c83946298690.pyi new file mode 100644 index 0000000..7c498e7 --- /dev/null +++ b/Test/SimdTest/temp/fe99c83946298690.pyi @@ -0,0 +1,89 @@ +""" +Auto-generated Python stub file from vipersimd.py +Module: vipersimd +""" + + +import t, c + +def simd_add4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_sub4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_mul4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_div4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_sqrt4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_neg4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_abs4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_max4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_min4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_mul_scalar4d(a: t.CPtr, scalar: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_add_scalar4d(a: t.CPtr, scalar: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_hsum4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_dot4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_fma4d(a: t.CPtr, b: t.CPtr, c_val: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_add4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_sub4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_mul4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_div4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: pass + +def simd_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: pass + +def simd_sub_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: pass + +def simd_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: pass + +def simd_div_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: pass + +def simd_sqrt_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: pass + +def simd_abs_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: pass + +def simd_dot_array(a: t.CPtr, b: t.CPtr, n: t.CSizeT, out: t.CPtr) -> t.CVoid: pass + +def simd_sqrt(x: t.CDouble) -> t.CDouble: pass + +def simd_fabs(x: t.CDouble) -> t.CDouble: pass + +def simd_floor(x: t.CDouble) -> t.CDouble: pass + +def simd_ceil(x: t.CDouble) -> t.CDouble: pass + +def simd_round(x: t.CDouble) -> t.CDouble: pass + +def simd_trunc(x: t.CDouble) -> t.CDouble: pass + +def simd_fma(a: t.CDouble, b: t.CDouble, c_val: t.CDouble) -> t.CDouble: pass + +def simd_copysign(mag: t.CDouble, sign: t.CDouble) -> t.CDouble: pass + +def simd_neg(x: t.CDouble) -> t.CDouble: pass + +def simd_minnum(a: t.CDouble, b: t.CDouble) -> t.CDouble: pass + +def simd_maxnum(a: t.CDouble, b: t.CDouble) -> t.CDouble: pass + +def simd_exp(x: t.CDouble) -> t.CDouble: pass + +def simd_log(x: t.CDouble) -> t.CDouble: pass + +def simd_sin(x: t.CDouble) -> t.CDouble: pass + +def simd_cos(x: t.CDouble) -> t.CDouble: pass + +def simd_pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass diff --git a/Test/StringIterTest/App/inline_test.py b/Test/StringIterTest/App/inline_test.py new file mode 100644 index 0000000..b811e68 --- /dev/null +++ b/Test/StringIterTest/App/inline_test.py @@ -0,0 +1,51 @@ +import t +import stdio +import c + +# Test: @t.Object class with inline list[struct, N] field + +class Inner: + code: t.CUnsignedInt + bits: t.CInt + +@t.Object +class Container: + items: list[Inner, 10] + count: t.CInt + + def __init__(self): + self.count = 0 + + def fill(self): + for i in range(10): + self.items[i].code = t.CUnsignedInt(i * 100) + self.items[i].bits = i + self.count += 1 + + def check(self): + ok: t.CInt = 1 + for i in range(10): + if self.items[i].code != t.CUnsignedInt(i * 100): + stdio.printf("FAIL: items[%d].code=%u expect %d\n", i, self.items[i].code, i * 100) + ok = 0 + if self.items[i].bits != i: + stdio.printf("FAIL: items[%d].bits=%d expect %d\n", i, self.items[i].bits, i) + ok = 0 + if ok: + stdio.printf("PASS: inline list[struct, N] in @t.Object\n") + else: + stdio.printf("FAIL: inline list[struct, N] in @t.Object\n") + +def main() -> t.CInt: + stdio.printf("=== InlineArrayTest ===\n") + c1 = Container() + c1.fill() + c1.check() + + # Also test: local variable of @t.Object type + c2 = Container() + c2.fill() + c2.check() + + stdio.printf("=== InlineArrayTest Complete ===\n") + return 0 diff --git a/Test/StringIterTest/App/main.py b/Test/StringIterTest/App/main.py new file mode 100644 index 0000000..2b09be4 --- /dev/null +++ b/Test/StringIterTest/App/main.py @@ -0,0 +1,209 @@ +import t +import stdio +import string +import c + +# ============================================================ +# Test 1: 字符串指针迭代 - 逐字符直到\0 +# ============================================================ +def test_string_ptr_iter(): + stdio.printf("--- Test 1: string pointer iteration ---\n") + s: t.CChar | t.CPtr = "Hello" + p: t.CChar | t.CPtr = s + count: t.CInt = 0 + while c.Deref(p) != 0: + count += 1 + p += 1 + if count == 5: + stdio.printf("PASS: ptr iter (count=%d)\n", count) + else: + stdio.printf("FAIL: ptr iter (count=%d, expect 5)\n", count) + +# ============================================================ +# Test 2: 字符串指针求和ASCII值 +# ============================================================ +def test_string_ascii_sum(): + stdio.printf("--- Test 2: string ASCII sum ---\n") + s: t.CChar | t.CPtr = "ABC" + p: t.CChar | t.CPtr = s + total: t.CInt = 0 + while c.Deref(p) != 0: + total += t.CInt(c.Deref(p)) + p += 1 + # A=65, B=66, C=67 => 198 + if total == 198: + stdio.printf("PASS: ASCII sum (total=%d)\n", total) + else: + stdio.printf("FAIL: ASCII sum (total=%d, expect 198)\n", total) + +# ============================================================ +# Test 3: 手动strcpy - 指针复制 +# ============================================================ +def test_manual_strcpy(): + stdio.printf("--- Test 3: manual strcpy via pointers ---\n") + src: t.CChar | t.CPtr = "Test" + dst: list[t.CChar, 32] = [0] + sp: t.CChar | t.CPtr = src + dp: t.CChar | t.CPtr = c.Addr(dst) + while c.Deref(sp) != 0: + c.Set(c.Deref(dp), c.Deref(sp)) + sp += 1 + dp += 1 + c.Set(c.Deref(dp), 0) + if dst[0] == 84 and dst[1] == 101 and dst[2] == 115 and dst[3] == 116: + stdio.printf("PASS: manual strcpy (T=%d e=%d s=%d t=%d)\n", dst[0], dst[1], dst[2], dst[3]) + else: + stdio.printf("FAIL: manual strcpy (T=%d e=%d s=%d t=%d)\n", dst[0], dst[1], dst[2], dst[3]) + +# ============================================================ +# Test 4: 指针比较和偏移 +# ============================================================ +def test_ptr_offset_compare(): + stdio.printf("--- Test 4: pointer offset and compare ---\n") + arr: list[t.CInt, 5] = [0] + for i in range(5): + arr[i] = i * 10 + p: t.CInt | t.CPtr = c.Addr(arr) + start: t.CInt | t.CPtr = p + total: t.CInt = 0 + while p != start + 5: + total += c.Deref(p) + p += 1 + if total == 100: + stdio.printf("PASS: ptr offset (total=%d)\n", total) + else: + stdio.printf("FAIL: ptr offset (total=%d, expect 100)\n", total) + +# ============================================================ +# Test 5: 字符串长度手动计算 +# ============================================================ +def test_manual_strlen(): + stdio.printf("--- Test 5: manual strlen ---\n") + s: t.CChar | t.CPtr = "Hello World!" + p: t.CChar | t.CPtr = s + length: t.CSizeT = 0 + while c.Deref(p) != 0: + length += 1 + p += 1 + if length == 12: + stdio.printf("PASS: manual strlen (len=%zu)\n", length) + else: + stdio.printf("FAIL: manual strlen (len=%zu, expect 12)\n", length) + +# ============================================================ +# Test 6: 指针反向遍历字符串 +# ============================================================ +def test_reverse_string_ptr(): + stdio.printf("--- Test 6: reverse string via pointer ---\n") + src: t.CChar | t.CPtr = "abcd" + dst: list[t.CChar, 32] = [0] + # Find end of src + p: t.CChar | t.CPtr = src + length: t.CInt = 0 + while c.Deref(p) != 0: + length += 1 + p += 1 + # Copy in reverse + dp: t.CChar | t.CPtr = c.Addr(dst) + p = src + length - 1 + while p >= src: + c.Set(c.Deref(dp), c.Deref(p)) + dp += 1 + p -= 1 + c.Set(c.Deref(dp), 0) + # "abcd" reversed = "dcba" = 100,99,98,97 + if dst[0] == 100 and dst[1] == 99 and dst[2] == 98 and dst[3] == 97: + stdio.printf("PASS: reverse string (d=%d c=%d b=%d a=%d)\n", dst[0], dst[1], dst[2], dst[3]) + else: + stdio.printf("FAIL: reverse string (d=%d c=%d b=%d a=%d)\n", dst[0], dst[1], dst[2], dst[3]) + +# ============================================================ +# Test 7: 多级指针 - 指向指针的指针 +# ============================================================ +def test_double_pointer(): + stdio.printf("--- Test 7: double pointer ---\n") + x: t.CInt = 42 + px: t.CInt | t.CPtr = c.Addr(x) + ppx: t.CInt | t.CPtr | t.CPtr = c.Addr(px) + # Read through double pointer + val: t.CInt = c.Deref(c.Deref(ppx)) + if val == 42: + stdio.printf("PASS: double pointer (val=%d)\n", val) + else: + stdio.printf("FAIL: double pointer (val=%d, expect 42)\n", val) + +# ============================================================ +# Test 8: 指针算术 - 数组元素访问 +# ============================================================ +def test_ptr_arithmetic(): + stdio.printf("--- Test 8: pointer arithmetic ---\n") + arr: list[t.CInt, 8] = [0] + for i in range(8): + arr[i] = (i + 1) * (i + 1) + p: t.CInt | t.CPtr = c.Addr(arr) + # Access arr[3] via pointer: p + 3 + val: t.CInt = c.Deref(p + 3) + # arr[3] = 4*4 = 16 + if val == 16: + stdio.printf("PASS: ptr arithmetic (arr[3]=%d)\n", val) + else: + stdio.printf("FAIL: ptr arithmetic (arr[3]=%d, expect 16)\n", val) + +# ============================================================ +# Test 9: 字符串比较 - 逐字符指针 +# ============================================================ +def test_manual_strcmp(): + stdio.printf("--- Test 9: manual strcmp via pointers ---\n") + s1: t.CChar | t.CPtr = "Hello" + s2: t.CChar | t.CPtr = "Hello" + p1: t.CChar | t.CPtr = s1 + p2: t.CChar | t.CPtr = s2 + equal: t.CInt = 1 + while c.Deref(p1) != 0 and c.Deref(p2) != 0: + if c.Deref(p1) != c.Deref(p2): + equal = 0 + break + p1 += 1 + p2 += 1 + if c.Deref(p1) != c.Deref(p2): + equal = 0 + if equal == 1: + stdio.printf("PASS: manual strcmp (equal=%d)\n", equal) + else: + stdio.printf("FAIL: manual strcmp (equal=%d, expect 1)\n", equal) + +# ============================================================ +# Test 10: 结构体指针访问 +# ============================================================ +class Vec2: + x: t.CInt + y: t.CInt + +def test_struct_ptr_access(): + stdio.printf("--- Test 10: struct pointer access ---\n") + v: Vec2 = Vec2() + v.x = 10 + v.y = 20 + p: Vec2 | t.CPtr = c.Addr(v) + # Modify through pointer + c.Deref(p).x = 100 + c.Deref(p).y = 200 + if v.x == 100 and v.y == 200: + stdio.printf("PASS: struct ptr (x=%d y=%d)\n", v.x, v.y) + else: + stdio.printf("FAIL: struct ptr (x=%d y=%d, expect 100 200)\n", v.x, v.y) + +def main() -> t.CInt: + stdio.printf("=== StringIterTest: String/Pointer Iteration Tests ===\n\n") + test_string_ptr_iter() + test_string_ascii_sum() + test_manual_strcpy() + test_ptr_offset_compare() + test_manual_strlen() + test_reverse_string_ptr() + test_double_pointer() + test_ptr_arithmetic() + test_manual_strcmp() + test_struct_ptr_access() + stdio.printf("\n=== StringIterTest Complete ===\n") + return 0 diff --git a/Test/StringIterTest/output/2255fdda7aed5595.deps.json b/Test/StringIterTest/output/2255fdda7aed5595.deps.json new file mode 100644 index 0000000..77fa018 --- /dev/null +++ b/Test/StringIterTest/output/2255fdda7aed5595.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StringIterTest/output/4d5db7f970ef510f.deps.json b/Test/StringIterTest/output/4d5db7f970ef510f.deps.json new file mode 100644 index 0000000..07c20ae --- /dev/null +++ b/Test/StringIterTest/output/4d5db7f970ef510f.deps.json @@ -0,0 +1 @@ +{"main": "2255fdda7aed5595", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StringIterTest/project.json b/Test/StringIterTest/project.json new file mode 100644 index 0000000..bc1efde --- /dev/null +++ b/Test/StringIterTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "StringIterTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "StringIterTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/StringIterTest/temp/2255fdda7aed5595.pyi b/Test/StringIterTest/temp/2255fdda7aed5595.pyi new file mode 100644 index 0000000..0e8819e --- /dev/null +++ b/Test/StringIterTest/temp/2255fdda7aed5595.pyi @@ -0,0 +1,37 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +import t +import stdio +import string +import c + +def test_string_ptr_iter() -> t.CInt: pass + +def test_string_ascii_sum() -> t.CInt: pass + +def test_manual_strcpy() -> t.CInt: pass + +def test_ptr_offset_compare() -> t.CInt: pass + +def test_manual_strlen() -> t.CInt: pass + +def test_reverse_string_ptr() -> t.CInt: pass + +def test_double_pointer() -> t.CInt: pass + +def test_ptr_arithmetic() -> t.CInt: pass + +def test_manual_strcmp() -> t.CInt: pass + + +class Vec2: + x: t.CInt + y: t.CInt + +def test_struct_ptr_access() -> t.CInt: pass + +def main() -> t.CInt: pass diff --git a/Test/StringIterTest/temp/4d5db7f970ef510f.pyi b/Test/StringIterTest/temp/4d5db7f970ef510f.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/StringIterTest/temp/4d5db7f970ef510f.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/StringIterTest/temp/56cdd754a8a09347.pyi b/Test/StringIterTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/StringIterTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/StringIterTest/temp/73edbcf76e32d00b.pyi b/Test/StringIterTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/StringIterTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/StringIterTest/temp/_sha1_map.txt b/Test/StringIterTest/temp/_sha1_map.txt new file mode 100644 index 0000000..856d8cc --- /dev/null +++ b/Test/StringIterTest/temp/_sha1_map.txt @@ -0,0 +1,4 @@ +2255fdda7aed5595:main.py +4d5db7f970ef510f:includes/string.py +56cdd754a8a09347:includes/stdint.py +73edbcf76e32d00b:includes/stdio.py diff --git a/Test/StringTest/App/main.py b/Test/StringTest/App/main.py new file mode 100644 index 0000000..197c67c --- /dev/null +++ b/Test/StringTest/App/main.py @@ -0,0 +1,105 @@ +import t +import stdio +import string + +def test_strlen(): + stdio.printf("--- Test 1: strlen ---\n") + s: t.CChar | t.CPtr = "Hello, World!" + length: t.CUInt64T = string.strlen(s) + if length == 13: + stdio.printf("PASS: strlen (len=%lu)\n", length) + else: + stdio.printf("FAIL: strlen (len=%lu, expect 13)\n", length) + +def test_strcpy(): + stdio.printf("--- Test 2: strcpy ---\n") + buf: t.CChar | t.CPtr = w32.win32memory.VirtualAlloc(t.CVoid(0, t.CPtr), 64, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 64) + string.strcpy(buf, "test string") + cmp_result: t.CInt = string.strcmp(buf, "test string") + if cmp_result == 0: + stdio.printf("PASS: strcpy (result=%s)\n", buf) + else: + stdio.printf("FAIL: strcpy (cmp=%d)\n", cmp_result) + +def test_strcat(): + stdio.printf("--- Test 3: strcat (via memcpy) ---\n") + buf: t.CChar | t.CPtr = w32.win32memory.VirtualAlloc(t.CVoid(0, t.CPtr), 64, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 64) + # 手动拼接: 先拷贝 "Hello",再拷贝 " World" + hello: t.CChar | t.CPtr = "Hello" + world: t.CChar | t.CPtr = " World" + string.memcpy(buf, hello, 5) + string.memcpy(t.CVoid(t.CUInt64T(buf) + 5, t.CPtr), world, 6) + cmp_result: t.CInt = string.strcmp(buf, "Hello World") + if cmp_result == 0: + stdio.printf("PASS: strcat via memcpy\n") + else: + stdio.printf("FAIL: strcat via memcpy (cmp=%d)\n", cmp_result) + +def test_strcmp(): + stdio.printf("--- Test 4: strcmp ---\n") + r1: t.CInt = string.strcmp("abc", "abc") + r2: t.CInt = string.strcmp("abc", "abd") + r3: t.CInt = string.strcmp("abd", "abc") + if r1 == 0 and r2 < 0 and r3 > 0: + stdio.printf("PASS: strcmp (eq=%d lt=%d gt=%d)\n", r1, r2, r3) + else: + stdio.printf("FAIL: strcmp (eq=%d lt=%d gt=%d)\n", r1, r2, r3) + +def test_strncpy(): + stdio.printf("--- Test 5: strncpy ---\n") + buf: t.CChar | t.CPtr = w32.win32memory.VirtualAlloc(t.CVoid(0, t.CPtr), 64, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 64) + string.strncpy(buf, "ABCDEFGHIJ", 5) + cmp_result: t.CInt = string.strcmp(buf, "ABCDE") + if cmp_result == 0: + stdio.printf("PASS: strncpy (result=%s)\n", buf) + else: + stdio.printf("FAIL: strncpy (cmp=%d)\n", cmp_result) + +def test_char_access(): + stdio.printf("--- Test 6: char access ---\n") + s: t.CChar | t.CPtr = "ABCDE" + val: t.CUInt8T = s[2] # 'C' = 67 + if val == 67: + stdio.printf("PASS: char access (s[2]=%d='C')\n", val) + else: + stdio.printf("FAIL: char access (s[2]=%d, expect 67)\n", val) + +def test_snprintf(): + stdio.printf("--- Test 7: snprintf ---\n") + buf: t.CChar | t.CPtr = w32.win32memory.VirtualAlloc(t.CVoid(0, t.CPtr), 128, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 128) + stdio.snprintf(buf, 128, "value=%d hex=0x%x str=%s", 42, 255, "test") + cmp_result: t.CInt = string.strcmp(buf, "value=42 hex=0xff str=test") + if cmp_result == 0: + stdio.printf("PASS: snprintf (result=%s)\n", buf) + else: + stdio.printf("FAIL: snprintf (result='%s')\n", buf) + +import w32.win32memory + +def main() -> t.CInt: + stdio.printf("=== StringTest: 字符串操作基准测试 ===\n\n") + test_strlen() + test_strcpy() + test_strcat() + test_strcmp() + test_strncpy() + test_char_access() + test_snprintf() + stdio.printf("\n=== StringTest Complete ===\n") + return 0 diff --git a/Test/StringTest/output/067c78e9f121dce3.deps.json b/Test/StringTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..438a5c0 --- /dev/null +++ b/Test/StringTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/StringTest/output/29813d57621099a9.deps.json b/Test/StringTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..cd6c7b8 --- /dev/null +++ b/Test/StringTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/StringTest/output/4d5db7f970ef510f.deps.json b/Test/StringTest/output/4d5db7f970ef510f.deps.json new file mode 100644 index 0000000..a36f7d0 --- /dev/null +++ b/Test/StringTest/output/4d5db7f970ef510f.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a"} \ No newline at end of file diff --git a/Test/StringTest/output/5a6a2137958c28c5.deps.json b/Test/StringTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..f00af17 --- /dev/null +++ b/Test/StringTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StringTest/output/72e2d5ccb7cedcf1.deps.json b/Test/StringTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..5017b39 --- /dev/null +++ b/Test/StringTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/StringTest/output/7aa13c104a22528a.deps.json b/Test/StringTest/output/7aa13c104a22528a.deps.json new file mode 100644 index 0000000..7ea28c1 --- /dev/null +++ b/Test/StringTest/output/7aa13c104a22528a.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b"} \ No newline at end of file diff --git a/Test/StringTest/output/abf9ce3160c9279e.deps.json b/Test/StringTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..5017b39 --- /dev/null +++ b/Test/StringTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/StringTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/StringTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..2138712 --- /dev/null +++ b/Test/StringTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/StringTest/output/fa3691e66b426950.deps.json b/Test/StringTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..f00af17 --- /dev/null +++ b/Test/StringTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "main": "7aa13c104a22528a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StringTest/project.json b/Test/StringTest/project.json new file mode 100644 index 0000000..38832ea --- /dev/null +++ b/Test/StringTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "StringTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "StringTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/StringTest/temp/067c78e9f121dce3.pyi b/Test/StringTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/StringTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/StringTest/temp/29813d57621099a9.pyi b/Test/StringTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/StringTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/StringTest/temp/4d5db7f970ef510f.pyi b/Test/StringTest/temp/4d5db7f970ef510f.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/StringTest/temp/4d5db7f970ef510f.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/StringTest/temp/56cdd754a8a09347.pyi b/Test/StringTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/StringTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/StringTest/temp/5a6a2137958c28c5.pyi b/Test/StringTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/StringTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/StringTest/temp/72e2d5ccb7cedcf1.pyi b/Test/StringTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/StringTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/StringTest/temp/73edbcf76e32d00b.pyi b/Test/StringTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/StringTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/StringTest/temp/7aa13c104a22528a.pyi b/Test/StringTest/temp/7aa13c104a22528a.pyi new file mode 100644 index 0000000..ccbfa76 --- /dev/null +++ b/Test/StringTest/temp/7aa13c104a22528a.pyi @@ -0,0 +1,30 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +import stdio +import string + +def test_strlen() -> t.CInt: pass + +def test_strcpy() -> t.CInt: pass + +def test_strcat() -> t.CInt: pass + +def test_strcmp() -> t.CInt: pass + +def test_strncpy() -> t.CInt: pass + +def test_char_access() -> t.CInt: pass + +def test_snprintf() -> t.CInt: pass + + +import w32.win32memory + +def main() -> t.CInt: pass diff --git a/Test/StringTest/temp/_sha1_map.txt b/Test/StringTest/temp/_sha1_map.txt new file mode 100644 index 0000000..9bb1406 --- /dev/null +++ b/Test/StringTest/temp/_sha1_map.txt @@ -0,0 +1,6 @@ +4d5db7f970ef510f:includes/string.py +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +72e2d5ccb7cedcf1:includes/w32\win32memory.py +73edbcf76e32d00b:includes/stdio.py +7aa13c104a22528a:main.py diff --git a/Test/StringTest/temp/abf9ce3160c9279e.pyi b/Test/StringTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/StringTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/StringTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/StringTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/StringTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/StringTest/temp/fa3691e66b426950.pyi b/Test/StringTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/StringTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/StructTest/App/main.py b/Test/StructTest/App/main.py new file mode 100644 index 0000000..affd9df --- /dev/null +++ b/Test/StructTest/App/main.py @@ -0,0 +1,100 @@ +import t +import stdio +import string + +# 定义结构体 +class Point(t.Struct): + x: t.CInt + y: t.CInt + +class Rect(t.Struct): + origin: Point + size: Point + +class Node(t.Struct): + value: t.CInt + next: t.CPtr | t.CVoid # Node* 类型 + +def test_struct_basic(): + stdio.printf("--- Test 1: struct basic ---\n") + p: Point = Point() + p.x = 10 + p.y = 20 + if p.x == 10 and p.y == 20: + stdio.printf("PASS: struct basic (x=%d y=%d)\n", p.x, p.y) + else: + stdio.printf("FAIL: struct basic (x=%d y=%d, expect 10 20)\n", p.x, p.y) + +def test_struct_nested(): + stdio.printf("--- Test 2: struct nested ---\n") + r: Rect = Rect() + r.origin.x = 1 + r.origin.y = 2 + r.size.x = 100 + r.size.y = 200 + if r.origin.x == 1 and r.origin.y == 2 and r.size.x == 100 and r.size.y == 200: + stdio.printf("PASS: struct nested (origin=%d,%d size=%d,%d)\n", r.origin.x, r.origin.y, r.size.x, r.size.y) + else: + stdio.printf("FAIL: struct nested\n") + +def test_struct_pointer(): + stdio.printf("--- Test 3: struct pointer ---\n") + p: Point = Point() + p.x = 42 + p.y = 84 + # 取结构体指针 + pp: Point | t.CPtr = t.CPtr(t.CVoid(t.CUInt64T(p), t.CPtr)) + # 通过指针修改 + pp.x = 100 + pp.y = 200 + # 检查原始结构体是否被修改 + if p.x == 100 and p.y == 200: + stdio.printf("PASS: struct pointer (x=%d y=%d)\n", p.x, p.y) + else: + stdio.printf("FAIL: struct pointer (x=%d y=%d, expect 100 200)\n", p.x, p.y) + +def test_struct_param(): + stdio.printf("--- Test 4: struct as parameter ---\n") + p: Point = Point() + p.x = 5 + p.y = 15 + sum_val: t.CInt = point_sum(p) + if sum_val == 20: + stdio.printf("PASS: struct param (sum=%d)\n", sum_val) + else: + stdio.printf("FAIL: struct param (sum=%d, expect 20)\n", sum_val) + +def point_sum(p: Point) -> t.CInt: + return p.x + p.y + +def test_struct_array(): + stdio.printf("--- Test 5: struct array ---\n") + # 分配结构体数组 + buf: t.CUInt8T | t.CPtr = w32.win32memory.VirtualAlloc(t.CVoid(0, t.CPtr), 256, 12288, 4) + if t.CUInt64T(buf) == 0: + stdio.printf("SKIP: VirtualAlloc returned NULL\n") + return + string.memset(buf, 0, 256) + # 将缓冲区转为 Point 数组 + pts: Point | t.CPtr = (Point | t.CPtr)(t.CVoid(t.CUInt64T(buf), t.CPtr)) + pts[0].x = 1 + pts[0].y = 2 + pts[1].x = 3 + pts[1].y = 4 + total: t.CInt = pts[0].x + pts[0].y + pts[1].x + pts[1].y + if total == 10: + stdio.printf("PASS: struct array (total=%d)\n", total) + else: + stdio.printf("FAIL: struct array (total=%d, expect 10)\n", total) + +import w32.win32memory + +def main() -> t.CInt: + stdio.printf("=== StructTest: 结构体操作基准测试 ===\n\n") + test_struct_basic() + test_struct_nested() + test_struct_pointer() + test_struct_param() + test_struct_array() + stdio.printf("\n=== StructTest Complete ===\n") + return 0 diff --git a/Test/StructTest/output/067c78e9f121dce3.deps.json b/Test/StructTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..19c4010 --- /dev/null +++ b/Test/StructTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/StructTest/output/29813d57621099a9.deps.json b/Test/StructTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..e6e2b5c --- /dev/null +++ b/Test/StructTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/StructTest/output/5a6a2137958c28c5.deps.json b/Test/StructTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..dab5750 --- /dev/null +++ b/Test/StructTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StructTest/output/6f6ee14c129ac228.deps.json b/Test/StructTest/output/6f6ee14c129ac228.deps.json new file mode 100644 index 0000000..9ec9abe --- /dev/null +++ b/Test/StructTest/output/6f6ee14c129ac228.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0"} \ No newline at end of file diff --git a/Test/StructTest/output/72e2d5ccb7cedcf1.deps.json b/Test/StructTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..29cf064 --- /dev/null +++ b/Test/StructTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/StructTest/output/a326a52b7c4bd6f0.deps.json b/Test/StructTest/output/a326a52b7c4bd6f0.deps.json new file mode 100644 index 0000000..1b0fb2d --- /dev/null +++ b/Test/StructTest/output/a326a52b7c4bd6f0.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0"} \ No newline at end of file diff --git a/Test/StructTest/output/abf9ce3160c9279e.deps.json b/Test/StructTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..29cf064 --- /dev/null +++ b/Test/StructTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/StructTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/StructTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..4f819ec --- /dev/null +++ b/Test/StructTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/StructTest/output/fa3691e66b426950.deps.json b/Test/StructTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..dab5750 --- /dev/null +++ b/Test/StructTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "main": "6f6ee14c129ac228", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/StructTest/project.json b/Test/StructTest/project.json new file mode 100644 index 0000000..dc854f7 --- /dev/null +++ b/Test/StructTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "StructTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "StructTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/StructTest/temp/067c78e9f121dce3.pyi b/Test/StructTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/StructTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/StructTest/temp/29813d57621099a9.pyi b/Test/StructTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/StructTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/StructTest/temp/56cdd754a8a09347.pyi b/Test/StructTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/StructTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/StructTest/temp/5a6a2137958c28c5.pyi b/Test/StructTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/StructTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/StructTest/temp/6f6ee14c129ac228.pyi b/Test/StructTest/temp/6f6ee14c129ac228.pyi new file mode 100644 index 0000000..fb46b92 --- /dev/null +++ b/Test/StructTest/temp/6f6ee14c129ac228.pyi @@ -0,0 +1,38 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import c + + +import t +import stdio +import string + +class Point(t.Struct): + x: t.CInt + y: t.CInt +class Rect(t.Struct): + origin: Point + size: Point +class Node(t.Struct): + value: t.CInt + next: t.CPtr | t.CVoid + +def test_struct_basic() -> t.CInt: pass + +def test_struct_nested() -> t.CInt: pass + +def test_struct_pointer() -> t.CInt: pass + +def test_struct_param() -> t.CInt: pass + +def point_sum(p: Point) -> t.CInt: pass + +def test_struct_array() -> t.CInt: pass + + +import w32.win32memory + +def main() -> t.CInt: pass diff --git a/Test/StructTest/temp/72e2d5ccb7cedcf1.pyi b/Test/StructTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/StructTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/StructTest/temp/73edbcf76e32d00b.pyi b/Test/StructTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/StructTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/StructTest/temp/_sha1_map.txt b/Test/StructTest/temp/_sha1_map.txt new file mode 100644 index 0000000..1fa7b41 --- /dev/null +++ b/Test/StructTest/temp/_sha1_map.txt @@ -0,0 +1,6 @@ +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +6f6ee14c129ac228:main.py +72e2d5ccb7cedcf1:includes/w32\win32memory.py +73edbcf76e32d00b:includes/stdio.py +a326a52b7c4bd6f0:includes/string.py diff --git a/Test/StructTest/temp/a326a52b7c4bd6f0.pyi b/Test/StructTest/temp/a326a52b7c4bd6f0.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/StructTest/temp/a326a52b7c4bd6f0.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/StructTest/temp/abf9ce3160c9279e.pyi b/Test/StructTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/StructTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/StructTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/StructTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/StructTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/StructTest/temp/fa3691e66b426950.pyi b/Test/StructTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/StructTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/TestFBProject/App/main.py b/Test/TestFBProject/App/main.py new file mode 100644 index 0000000..c6e2804 --- /dev/null +++ b/Test/TestFBProject/App/main.py @@ -0,0 +1,158 @@ +from stdint import * +import w32.win32console +import t, c + + +def add_inline(a: t.CInt, b: t.CInt) -> t.CDefine: + return a + b + +def mul_inline(a: t.CInt, b: t.CInt) -> t.CDefine: + return a * b + + +class AppError(Exception): + pass + +class DiskError(AppError): + pass + +class NetworkError(AppError): + pass + +class TimeoutError(NetworkError): + pass + + +def raise_disk(): + raise DiskError("disk read failed") + +def raise_network(): + raise NetworkError("connection refused") + +def raise_timeout(): + raise TimeoutError("operation timed out") + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + print("=== Test 1: Raise and catch exact custom exception ===") + try: + raise DiskError("disk error") + except DiskError as e: + print("PASS 1: caught DiskError:", e) + except: + print("FAIL 1: caught by generic except") + print("") + + print("=== Test 2: Catch parent catches child ===") + try: + raise_disk() + except AppError as e: + print("PASS 2: caught AppError (child DiskError):", e) + except: + print("FAIL 2: caught by generic except") + print("") + + print("=== Test 3: Catch parent catches nested child ===") + try: + raise_timeout() + except AppError as e: + print("PASS 3: caught AppError (grandchild TimeoutError):", e) + except: + print("FAIL 3: caught by generic except") + print("") + + print("=== Test 4: Catch mid-level parent ===") + try: + raise_timeout() + except NetworkError as e: + print("PASS 4: caught NetworkError (child TimeoutError):", e) + except: + print("FAIL 4: caught by generic except") + print("") + + print("=== Test 5: Exact catch before parent ===") + try: + raise_network() + except NetworkError as e: + print("PASS 5: caught NetworkError:", e) + except AppError as e: + print("FAIL 5: caught AppError (should be NetworkError first)") + except: + print("FAIL 5: caught by generic except") + print("") + + print("=== Test 6: Parent catch when exact not present ===") + try: + raise_network() + except DiskError as e: + print("FAIL 6: caught DiskError (wrong)") + except AppError as e: + print("PASS 6: caught AppError (no NetworkError handler):", e) + except: + print("FAIL 6: caught by generic except") + print("") + + print("=== Test 7: Generic except fallback ===") + try: + raise_disk() + except RuntimeError as e: + print("FAIL 7: caught RuntimeError (wrong)") + except: + print("PASS 7: caught by generic except") + print("") + + print("=== Test 8: Cross-function with inheritance ===") + try: + raise_timeout() + except NetworkError as e: + print("PASS 8: caught NetworkError (cross-func TimeoutError):", e) + except: + print("FAIL 8: caught by generic except") + print("") + + print("=== Test 9: Built-in exception still works ===") + try: + raise ValueError("test") + except ValueError as e: + print("PASS 9: caught ValueError:", e) + except: + print("FAIL 9: caught by generic except") + print("") + + print("=== Test 10: Mixed built-in and custom ===") + try: + raise RuntimeError("test") + except DiskError as e: + print("FAIL 10: caught DiskError (wrong)") + except RuntimeError as e: + print("PASS 10: caught RuntimeError:", e) + except: + print("FAIL 10: caught by generic except") + print("") + + print("=== All Custom Exception Tests Complete ===") + + print("") + print("=== Test LLVMIR: inline LLVM IR add ===") + x: t.CInt = 10 + y: t.CInt = 20 + r: t.CInt = c.LLVMIR(f"add i32 {c.LInp(x)}, {c.LInp(y)}", t.CInt) + print("LLVMIR add result:", r) + + print("") + print("=== Test CDefine function macro ===") + s: t.CInt = add_inline(3, 4) + print("add_inline(3, 4) =", s) + m: t.CInt = mul_inline(5, 6) + print("mul_inline(5, 6) =", m) + + print("") + print("=== Test LLVMIR with LOut ===") + out_val: t.CInt = 0 + c.LLVMIR(f"{c.LOut(out_val)} = add i32 {c.LInp(x)}, {c.LInp(y)}", t.CInt) + print("LLVMIR LOut result:", out_val) + + return 0 diff --git a/Test/TestFBProject/output/067c78e9f121dce3.deps.json b/Test/TestFBProject/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..0a11294 --- /dev/null +++ b/Test/TestFBProject/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/TestFBProject/output/29813d57621099a9.deps.json b/Test/TestFBProject/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..0a11294 --- /dev/null +++ b/Test/TestFBProject/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/TestFBProject/output/3727eb00d15bf59d.deps.json b/Test/TestFBProject/output/3727eb00d15bf59d.deps.json new file mode 100644 index 0000000..2a25cbb --- /dev/null +++ b/Test/TestFBProject/output/3727eb00d15bf59d.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/TestFBProject/output/5a6a2137958c28c5.deps.json b/Test/TestFBProject/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..5bc5aa9 --- /dev/null +++ b/Test/TestFBProject/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"main": "214790a9a42a868c", "stdint": "56cdd754a8a09347", "win32.win32console": "ac0664ce209738d9", "win32console": "ac0664ce209738d9"} \ No newline at end of file diff --git a/Test/TestFBProject/output/72e2d5ccb7cedcf1.deps.json b/Test/TestFBProject/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..0a11294 --- /dev/null +++ b/Test/TestFBProject/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/TestFBProject/output/abf9ce3160c9279e.deps.json b/Test/TestFBProject/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..0a11294 --- /dev/null +++ b/Test/TestFBProject/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/TestFBProject/output/bbdf3bbd4c3bc28c.deps.json b/Test/TestFBProject/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..a1b0dcc --- /dev/null +++ b/Test/TestFBProject/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5"} \ No newline at end of file diff --git a/Test/TestFBProject/output/fa3691e66b426950.deps.json b/Test/TestFBProject/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..0a11294 --- /dev/null +++ b/Test/TestFBProject/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"main": "3727eb00d15bf59d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/TestFBProject/project.json b/Test/TestFBProject/project.json new file mode 100644 index 0000000..a7bd9a7 --- /dev/null +++ b/Test/TestFBProject/project.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "TestFBProject", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj"] + }, + "linker": { + "cmd": "clang++", + "flags": [ + "-nostdlib", + "-nostartfiles", + "-fno-builtin", + "-Wl,--allow-multiple-definition", + "-Wl,--unresolved-symbols=ignore-in-object-files", + "-lucrt", + "-lkernel32", + "-luser32", + "-latomic" + ], + "output": "TestFBProject.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} \ No newline at end of file diff --git a/Test/TestFBProject/temp/214790a9a42a868c.pyi b/Test/TestFBProject/temp/214790a9a42a868c.pyi new file mode 100644 index 0000000..4aa4f2f --- /dev/null +++ b/Test/TestFBProject/temp/214790a9a42a868c.pyi @@ -0,0 +1,33 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +from stdint import * +import win32.win32console +import t, c + +def add_inline(a: t.CInt, b: t.CInt) -> t.CDefine: + pass + +def mul_inline(a: t.CInt, b: t.CInt) -> t.CDefine: + pass + + +class AppError(Exception): + pass +class DiskError(AppError): + pass +class NetworkError(AppError): + pass +class TimeoutError(NetworkError): + pass + +def raise_disk() -> t.CVoid | t.State: pass + +def raise_network() -> t.CVoid | t.State: pass + +def raise_timeout() -> t.CVoid | t.State: pass + +def main() -> t.CInt | t.CExport | t.State: pass diff --git a/Test/TestFBProject/temp/3727eb00d15bf59d.pyi b/Test/TestFBProject/temp/3727eb00d15bf59d.pyi new file mode 100644 index 0000000..8a058f6 --- /dev/null +++ b/Test/TestFBProject/temp/3727eb00d15bf59d.pyi @@ -0,0 +1,33 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +from stdint import * +import w32.win32console +import t, c + +def add_inline(a: t.CInt, b: t.CInt) -> t.CDefine: + pass + +def mul_inline(a: t.CInt, b: t.CInt) -> t.CDefine: + pass + + +class AppError(Exception): + pass +class DiskError(AppError): + pass +class NetworkError(AppError): + pass +class TimeoutError(NetworkError): + pass + +def raise_disk() -> t.CVoid | t.State: pass + +def raise_network() -> t.CVoid | t.State: pass + +def raise_timeout() -> t.CVoid | t.State: pass + +def main() -> t.CInt | t.CExport | t.State: pass diff --git a/Test/TestFBProject/temp/56cdd754a8a09347.pyi b/Test/TestFBProject/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/TestFBProject/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/TestFBProject/temp/5a6a2137958c28c5.pyi b/Test/TestFBProject/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..0ed80f0 --- /dev/null +++ b/Test/TestFBProject/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from win32.win32base.py +Module: win32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/TestFBProject/temp/_sha1_map.txt b/Test/TestFBProject/temp/_sha1_map.txt new file mode 100644 index 0000000..d500891 --- /dev/null +++ b/Test/TestFBProject/temp/_sha1_map.txt @@ -0,0 +1,4 @@ +3727eb00d15bf59d:main.py +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +bbdf3bbd4c3bc28c:includes/w32\win32console.py diff --git a/Test/TestFBProject/temp/ac0664ce209738d9.pyi b/Test/TestFBProject/temp/ac0664ce209738d9.pyi new file mode 100644 index 0000000..489db56 --- /dev/null +++ b/Test/TestFBProject/temp/ac0664ce209738d9.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from win32.win32console.py +Module: win32.win32console +""" + +import c + + +import t +from stdint import * +from win32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/TestFBProject/temp/bbdf3bbd4c3bc28c.pyi b/Test/TestFBProject/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/TestFBProject/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/TestProject/App/BINASCII.py b/Test/TestProject/App/BINASCII.py new file mode 100644 index 0000000..b1cc457 --- /dev/null +++ b/Test/TestProject/App/BINASCII.py @@ -0,0 +1,47 @@ +import stdio +import stdlib +import string +import binascii +import t, c + + + + +def main222(): + binascii.init_binascii() + raw: str = "HelloWorld!" + raw_length: t.CInt = 11 + + stdio.printf("你好\n") + + hex_out: str = binascii.b2a_hex(raw, raw_length) + if hex_out: + stdio.printf("Hex: %s\n", hex_out) + free(hex_out) + + crc_val: t.CUnsignedInt = binascii.crc32(raw, raw_length, 0) + stdio.printf("CRC32: %u\n", crc_val) + + b64_out: str = binascii.b2a_base64(raw, raw_length) + if b64_out: + stdio.printf("Base64: %s\n", b64_out) + free(b64_out) + + uu_out: str = binascii.b2a_uu(raw, raw_length) + if uu_out: + stdio.printf("UU: %s\n", uu_out) + free(uu_out) + + hqx_in: list[t.CChar, 4] = ['A', 'B', 'C', '\0'] + hqx_crc: t.CUnsignedShort = 0 + hqx_out: str + unhqx: str + hqx_out, hqx_crc = binascii.b2a_hqx(hqx_in, 3) + unhqx, hqx_crc = binascii.a2b_hqx(hqx_out) + stdio.printf("HQX Test: ABC -> %s -> %s (CRC:%u)\n", hqx_out, unhqx, hqx_crc) + free(hqx_out); free(unhqx) + + adler_val: t.CUnsignedInt = binascii.adler32(raw, raw_length, 1) + stdio.printf("Adler32: %u\n", adler_val) + + stdio.printf("Bye\n") diff --git a/Test/TestProject/App/HASHLIB.py b/Test/TestProject/App/HASHLIB.py new file mode 100644 index 0000000..41c11ad --- /dev/null +++ b/Test/TestProject/App/HASHLIB.py @@ -0,0 +1,80 @@ +import stdio +import stdlib +import string +import stdint +import t, c +import base64 +import hashlib + + + + + + + + +def default_value_test_function(a: t.CInt, b: t.CInt = 1): + print(a, b) + + + + +# ============================================== +# 工具函数:打印十六进制哈希串 +# ============================================== +def print_hex(buf: t.CUInt8T | t.CPtr, length: t.CInt): + for i in range(length): + stdio.printf("%02x", buf[i]) + stdio.printf("\n") + +# ============================================== +# 主函数测试入口 +# ============================================== +def main1() -> t.CInt: + plain: str = "hello123" + print("原文", plain) + + # ---------- Base64 测试 ---------- + b64_out: list[t.CChar, 256] + b64_dec: list[t.CUInt8T, 256] + base64.b64encode(plain, b64_out) + print("Base64 编码:", b64_out) + dlen: t.CSizeT = base64.b64decode(b64_out, b64_dec) + b64_dec[dlen] = 0 + print("Base64 解码:", b64_dec) + + # ---------- MD5 测试 ---------- + md5_buf: list[t.CUInt8T, hashlib.MD5_DIGEST_LEN] + mctx = hashlib.md5() + mctx.update(plain) + mctx.final(md5_buf) + print("MD5: ") + print_hex(md5_buf, hashlib.MD5_DIGEST_LEN) + + # ---------- SHA1 测试 ---------- + sha1_buf: list[t.CUInt8T, hashlib.SHA1_DIGEST_LEN] + s1ctx = hashlib.sha1() + s1ctx.update(plain) + s1ctx.final(sha1_buf) + print("SHA1: ") + print_hex(sha1_buf, hashlib.SHA1_DIGEST_LEN) + + # ---------- SHA256 测试 ---------- + sha256_buf: list[t.CUInt8T, hashlib.SHA256_DIGEST_LEN] + s2ctx = hashlib.sha256() + s2ctx.update(plain) + s2ctx.final(sha256_buf) + print("SHA256: ") + print_hex(sha256_buf, hashlib.SHA256_DIGEST_LEN) + + # ---------- SHA512 测试 ---------- + sha512_buf: list[t.CUInt8T, hashlib.SHA512_DIGEST_LEN] + s5ctx = hashlib.sha512() + s5ctx.update(plain) + s5ctx.final(sha512_buf) + print("SHA512: ") + print_hex(sha512_buf, hashlib.SHA512_DIGEST_LEN) + + default_value_test_function(b=2, a=1) + + return 0 diff --git a/Test/TestProject/App/__zlib/__init__.py b/Test/TestProject/App/__zlib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Test/TestProject/App/__zlib/pyzlib.py b/Test/TestProject/App/__zlib/pyzlib.py new file mode 100644 index 0000000..78bc227 --- /dev/null +++ b/Test/TestProject/App/__zlib/pyzlib.py @@ -0,0 +1,550 @@ +from stdint import * +import zdeflate +import zinflate +import zchecksum +import zdef +import zhuff +import stdlib +import string +import stdio +import t, c + + +# ============================================================ +# Constants - matching Python zlib module names and values +# ============================================================ + +# Compression levels +Z_NO_COMPRESSION: t.CDefine = 0 +Z_BEST_SPEED: t.CDefine = 1 +Z_BEST_COMPRESSION: t.CDefine = 9 +Z_DEFAULT_COMPRESSION: t.CDefine = (-1) + +# Compression methods +DEFLATED: t.CDefine = 8 + +# Flush modes +Z_NO_FLUSH: t.CDefine = 0 +Z_PARTIAL_FLUSH: t.CDefine = 1 +Z_SYNC_FLUSH: t.CDefine = 2 +Z_FULL_FLUSH: t.CDefine = 3 +Z_FINISH: t.CDefine = 4 +Z_BLOCK: t.CDefine = 5 +Z_TREES: t.CDefine = 6 + +# Strategies +Z_DEFAULT_STRATEGY: t.CDefine = 0 +Z_FILTERED: t.CDefine = 1 +Z_HUFFMAN_ONLY: t.CDefine = 2 +Z_RLE: t.CDefine = 3 +Z_FIXED: t.CDefine = 4 + +# Return codes +Z_OK: t.CDefine = 0 +Z_STREAM_END: t.CDefine = 1 +Z_NEED_DICT: t.CDefine = 2 +Z_ERRNO: t.CDefine = (-1) +Z_STREAM_ERROR: t.CDefine = (-2) +Z_DATA_ERROR: t.CDefine = (-3) +Z_MEM_ERROR: t.CDefine = (-4) +Z_BUF_ERROR: t.CDefine = (-5) +Z_VERSION_ERROR: t.CDefine = (-6) + +# Window / Buffer constants +MAX_WBITS: t.CDefine = 15 +DEF_BUF_SIZE: t.CDefine = 16384 +DEF_MEM_LEVEL: t.CDefine = 8 + +# Version +ZLIB_VERSION: t.CDefine = "1.3.2" + +pyzlib_error_msg: list[t.CChar, 512] = "" +pyzlib_error_code_val: t.CInt = 0 + +# ============================================================ +# Structures +# ============================================================ +@t.Object +class Compress: + stream: VOIDPTR + is_initialized: t.CInt + is_finished: t.CInt + level: t.CInt + method: t.CInt + wbits: t.CInt + memLevel: t.CInt + strategy: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + last_pos: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + header_written: t.CInt + + def compress(self, + data: BYTEPTR, data_len: t.CSizeT, + out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if self.is_finished: + set_error(Z_STREAM_ERROR, "compress object already finished") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + if data_len == 0: + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + while self.input_buf_len + data_len > self.input_buf_cap: + self.input_buf_cap *= 2 + new_buf: BYTEPTR = BYTEPTR(realloc(self.input_buf, self.input_buf_cap)) + if not new_buf: + set_error(Z_MEM_ERROR, "out of memory") + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + self.input_buf = new_buf + memcpy(self.input_buf + self.input_buf_len, data, data_len) + self.input_buf_len += data_len + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + + def flush(self, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + if mode == Z_FINISH: + if not self.header_written: + self.header_written = 1 + input_data: BYTEPTR = self.input_buf + input_len: t.CSizeT = self.input_buf_len + if input_len == 0: + s.writer.write_bits(1, 1) + s.writer.write_bits(1, 2) + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + lit_tree.encode_symbol(256, c.Addr(s.writer)) + else: + s.adler = zchecksum.zchecksum_adler32(input_data, input_len, 1) + s.compress_block(input_data, input_len, 1) + s.is_finished = 1 + if s.wbits >= 0: + s.writer.align() + adler: t.CUInt32T = s.adler + s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF + s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF + s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF + s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF + s.writer.byte_pos += 4 + self.is_finished = 1 + total: t.CSizeT = s.writer.total() + result: BYTEPTR = BYTEPTR(malloc(total)) + if result: memcpy(result, s.writer.buf, total) + c.Set(c.Deref(out_len), total) + free(self.input_buf) + self.input_buf = None + self.input_buf_len = 0 + self.input_buf_cap = 0 + return result + elif mode == Z_SYNC_FLUSH or mode == Z_FULL_FLUSH: + input_data: BYTEPTR = self.input_buf + input_len: t.CSizeT = self.input_buf_len + if input_len > 0: + s.adler = zchecksum.zchecksum_adler32(input_data, input_len, s.adler) + s.compress_block(input_data, input_len, 0) + self.input_buf_len = 0 + s.writer.write_bits(0, 1) + s.writer.write_bits(0, 2) + s.writer.align() + prev_pos: t.CSizeT = self.last_pos + total: t.CSizeT = s.writer.total() + delta: t.CSizeT = total - prev_pos + self.last_pos = s.writer.byte_pos + if delta == 0: + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + + result: BYTEPTR = BYTEPTR(malloc(delta)) + if result: memcpy(result, s.writer.buf + prev_pos, delta) + c.Set(c.Deref(out_len), delta) + return result + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + + def copy(self) -> Compress | t.CPtr: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + copy_obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__()) + if not copy_obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + copy_obj.stream = s.copy() + if not copy_obj.stream: + free(copy_obj) + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.is_initialized = 1 + copy_obj.is_finished = self.is_finished + copy_obj.level = self.level + copy_obj.method = self.method + copy_obj.wbits = self.wbits + copy_obj.memLevel = self.memLevel + copy_obj.strategy = self.strategy + copy_obj.last_pos = self.last_pos + copy_obj.header_written = self.header_written + if self.input_buf and self.input_buf_len > 0: + copy_obj.input_buf = BYTEPTR(calloc(1, self.input_buf_cap)) + if copy_obj.input_buf: + memcpy(copy_obj.input_buf, self.input_buf, self.input_buf_len) + copy_obj.input_buf_cap = self.input_buf_cap + copy_obj.input_buf_len = self.input_buf_len + else: + copy_obj.input_buf = BYTEPTR(calloc(1, 256)) + copy_obj.input_buf_cap = 256 + copy_obj.input_buf_len = 0 + if self.zdict and self.zdict_len > 0: + copy_obj.zdict = clone_bytes(self.zdict, self.zdict_len) + copy_obj.zdict_len = self.zdict_len + return copy_obj + + def delete(self): + if self.is_initialized and self.stream: + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + s.destroy() + free(self.zdict) + free(self.input_buf) + free(self) + + def __del__(self): + self.delete() + + +@t.Object +class Decompress: + stream: VOIDPTR + is_initialized: t.CInt + eof: t.CInt + wbits: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + _unused_data: BYTEPTR + _unused_data_len: t.CSizeT + _unused_data_cap: t.CSizeT + _unconsumed_tail: BYTEPTR + _unconsumed_tail_len: t.CSizeT + _unconsumed_tail_cap: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + + def decompress(self, data: BYTEPTR, data_len: t.CSizeT, + max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + if self.eof: + if data and data_len > 0: + append_bytes(c.Addr(self._unused_data), c.Addr(self._unused_data_len), + c.Addr(self._unused_data_cap), data, data_len) + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + self._unconsumed_tail_len = 0 + if data and data_len > 0: + append_bytes(c.Addr(self.input_buf), c.Addr(self.input_buf_len), + c.Addr(self.input_buf_cap), data, data_len) + if self.input_buf_len == 0: + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + s: zinflate.zinflate_stream | t.CPtr = zinflate.zinflate_create(self.wbits) + if not s: + set_error(Z_MEM_ERROR, "out of memory") + return None + if self.zdict and self.zdict_len > 0: + s.set_dictionary(self.zdict, self.zdict_len) + out: t.CUInt8T | t.CPtr = None + err: t.CInt = s.decompress(self.input_buf, self.input_buf_len, + max_length, c.Addr(out), out_len) + if err != 0: + s.destroy() + set_error(Z_DATA_ERROR, "decompression failed") + return None + if s.is_finished: + self.eof = 1 + if s.input_pos < s.input_len: + append_bytes(c.Addr(self._unused_data), c.Addr(self._unused_data_len), + c.Addr(self._unused_data_cap), + s.input_data + s.input_pos, + s.input_len - s.input_pos) + self.input_buf_len = 0 + else: + consumed: t.CSizeT = s.input_pos + if consumed < self.input_buf_len: + remaining: t.CSizeT = self.input_buf_len - consumed + memmove(self.input_buf, self.input_buf + consumed, remaining) + self.input_buf_len = remaining + else: + self.input_buf_len = 0 + s.destroy() + return out + + def flush(self, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + + def copy(self) -> Decompress | t.CPtr: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + copy_obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__()) + if not copy_obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.is_initialized = 1 + copy_obj.eof = self.eof + copy_obj.wbits = self.wbits + if self.zdict and self.zdict_len > 0: + copy_obj.zdict = clone_bytes(self.zdict, self.zdict_len) + copy_obj.zdict_len = self.zdict_len + if self._unused_data and self._unused_data_len > 0: + copy_obj._unused_data = clone_bytes(self._unused_data, self._unused_data_len) + copy_obj._unused_data_len = self._unused_data_len + copy_obj._unused_data_cap = self._unused_data_len + if self._unconsumed_tail and self._unconsumed_tail_len > 0: + copy_obj._unconsumed_tail = clone_bytes(self._unconsumed_tail, self._unconsumed_tail_len) + copy_obj._unconsumed_tail_len = self._unconsumed_tail_len + copy_obj._unconsumed_tail_cap = self._unconsumed_tail_len + if self.input_buf and self.input_buf_len > 0: + copy_obj.input_buf = clone_bytes(self.input_buf, self.input_buf_len) + copy_obj.input_buf_len = self.input_buf_len + copy_obj.input_buf_cap = self.input_buf_cap + else: + copy_obj.input_buf = BYTEPTR(calloc(1, 256)) + copy_obj.input_buf_cap = 256 + copy_obj.input_buf_len = 0 + return copy_obj + + def delete(self): + free(self.zdict) + free(self._unused_data) + free(self._unconsumed_tail) + free(self.input_buf) + free(self) + + def unused_data(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + #if not self: + # if length: + # c.Set(c.Deref(length), 0) + # return None + if length: + c.Set(c.Deref(length), self._unused_data_len) + return self._unused_data + + def unconsumed_tail(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + #if not self: + # if length: + # c.Set(c.Deref(length), 0) + # return None + if length: + c.Set(c.Deref(length), self._unconsumed_tail_len) + return self._unconsumed_tail + +# def eof(self) -> t.CInt: +# # if not obj: return 0 +# return self.eof + + + +def set_error(code: int, msg: str): + global pyzlib_error_code_val, pyzlib_error_msg + pyzlib_error_code_val = code + if msg: + strncpy(pyzlib_error_msg, msg, pyzlib_error_msg.__sizeof__() - 1) + pyzlib_error_msg[pyzlib_error_msg.__sizeof__() - 1] = '\0' + else: + pyzlib_error_msg[0] = '\0' + +def clone_bytes(src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if not src or length == 0: return None + dst: BYTEPTR = BYTEPTR(malloc(length)) + if dst: memcpy(dst, src, length) + return dst + +def append_bytes(buf: BYTE | t.CPtr[t.CPtr], length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr, + data: BYTEPTR, data_len: t.CSizeT) -> t.CInt: + if not data or data_len == 0: return 0 + needed: t.CSizeT = c.Deref(length) + data_len + if needed > c.Deref(cap): + new_cap: t.CSizeT = c.Deref(cap) * 2 + if new_cap < needed: new_cap = needed + new_buf: BYTEPTR = BYTEPTR(realloc(c.Deref(buf), new_cap)) + if not new_buf: return -1 + c.Set(c.Deref(buf), new_buf) + c.Set(c.Deref(cap), new_cap) + memcpy(c.Deref(buf) + c.Deref(length), data, data_len) + c.Set(c.Deref(length), c.Deref(length) + data_len) + return 0 + + +def shrink_to_fit(buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if length == 0: + free(buf) + return BYTEPTR(calloc(1, 1)) + result: BYTEPTR = BYTEPTR(realloc(buf, length)) + return result if result else buf + + +def runtime_version() -> str: + return ZLIB_VERSION + +def get_error() -> str: + return pyzlib_error_msg + +def get_error_code() -> t.CInt: + return pyzlib_error_code_val + +def clear_error(): + global pyzlib_error_msg, pyzlib_error_code_val + pyzlib_error_msg[0] = '\0' + pyzlib_error_code_val = 0 + +def compress(data: BYTEPTR, data_len: t.CSizeT, + level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not data and data_len > 0: + set_error(Z_STREAM_ERROR, "data is None but data_len > 0") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: + actual_wbits = -MAX_WBITS + raw_result: UINT8PTR = zdeflate.zdeflate_one_shot(data, data_len, level, actual_wbits, out_len) + if not raw_result: + set_error(Z_DATA_ERROR, "compression failed") + return None + if wbits > MAX_WBITS: + gzip_len: t.CSizeT = 10 + c.Deref(out_len) + 8 + gzip_buf: BYTEPTR = BYTEPTR(malloc(gzip_len)) + if not gzip_buf: + free(raw_result) + set_error(Z_MEM_ERROR, "out of memory") + return None + pos: t.CSizeT = 0 + gzip_buf[pos + 0] = 0x1F + gzip_buf[pos + 1] = 0x8B + gzip_buf[pos + 2] = 0x08 + gzip_buf[pos + 3] = 0x00 + gzip_buf[pos + 4] = 0x00 + gzip_buf[pos + 5] = 0x00 + gzip_buf[pos + 6] = 0x00 + gzip_buf[pos + 7] = 0x00 + gzip_buf[pos + 8] = 0x00 + gzip_buf[pos + 9] = 0xFF + pos += 10 + + memcpy(gzip_buf + pos, raw_result, c.Deref(out_len)) + pos += c.Deref(out_len) + free(raw_result) + + crc: t.CUInt32T = zchecksum.zchecksum_crc32(data, data_len, 0) + gzip_buf[pos + 0] = (crc) & 0xFF + gzip_buf[pos + 1] = (crc >> 8) & 0xFF + gzip_buf[pos + 2] = (crc >> 16) & 0xFF + gzip_buf[pos + 3] = (crc >> 24) & 0xFF + gzip_buf[pos + 4] = (data_len) & 0xFF + gzip_buf[pos + 5] = (data_len >> 8) & 0xFF + gzip_buf[pos + 6] = (data_len >> 16) & 0xFF + gzip_buf[pos + 7] = (data_len >> 24) & 0xFF + pos += 8 + c.Set(c.Deref(out_len), pos) + return shrink_to_fit(gzip_buf, pos) + return shrink_to_fit(raw_result, c.Deref(out_len)) + + +def decompress(data: BYTEPTR, data_len: t.CSizeT, + wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not data and data_len > 0: + set_error(Z_STREAM_ERROR, "data is None but data_len > 0") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + result: UINT8PTR = zinflate.zinflate_one_shot(data, data_len, wbits, bufsize, out_len) + if not result: + set_error(Z_DATA_ERROR, "decompression failed") + return None + return shrink_to_fit(result, c.Deref(out_len)) + +def compressobj(level: t.CInt, method: t.CInt, wbits: t.CInt, + memLevel: t.CInt, strategy: t.CInt, + zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr: + obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__()) + if not obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: actual_wbits = wbits - 16 + s: zdeflate.zdeflate_stream | t.CPtr = zdeflate.zdeflate_create(level, actual_wbits, memLevel, strategy) + if not s: + free(obj) + set_error(Z_MEM_ERROR, "out of memory") + return None + obj.stream = s + obj.is_initialized = 1 + obj.level = level + obj.method = method + obj.wbits = wbits + obj.memLevel = memLevel + obj.strategy = strategy + obj.input_buf = BYTEPTR(calloc(1, 256)) + obj.input_buf_cap = 256 + obj.input_buf_len = 0 + obj.header_written = 0 + if zdict and zdict_len > 0: + s.set_dictionary(zdict, zdict_len) + obj.zdict = clone_bytes(zdict, zdict_len) + obj.zdict_len = zdict_len + return obj + + +def decompressobj(wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: + obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__()) + if not obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: actual_wbits = wbits - 16 + obj.stream = None + obj.is_initialized = 1 + obj.wbits = actual_wbits + if zdict and zdict_len > 0: + obj.zdict = clone_bytes(zdict, zdict_len) + obj.zdict_len = zdict_len + obj.input_buf = BYTEPTR(calloc(1, 256)) + obj.input_buf_cap = 256 + obj.input_buf_len = 0 + return obj + +def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: + return zchecksum.zchecksum_adler32(data, length, UINT32(value)) + +def zlib_crc32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: + return zchecksum.zchecksum_crc32(data, length, UINT32(value)) + + diff --git a/Test/TestProject/App/__zlib/test_basic.c b/Test/TestProject/App/__zlib/test_basic.c new file mode 100644 index 0000000..efa089c --- /dev/null +++ b/Test/TestProject/App/__zlib/test_basic.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include "pyzlib.h" + +int main(void) +{ + printf("=== Basic Self-Implemented zlib Test ===\n\n"); + + printf("1. Adler-32:\n"); + unsigned long a = zlib_adler32((const unsigned char *)"Hello", 5, 1); + printf(" adler32(\"Hello\") = 0x%08lX\n", a); + + unsigned long a2 = zlib_adler32((const unsigned char *)"Hel", 3, 1); + a2 = zlib_adler32((const unsigned char *)"lo", 2, a2); + printf(" incremental = 0x%08lX %s\n", a2, a == a2 ? "MATCH" : "MISMATCH"); + + printf("\n2. CRC-32:\n"); + unsigned long c = zlib_crc32((const unsigned char *)"Hello", 5, 0); + printf(" crc32(\"Hello\") = 0x%08lX\n", c); + + unsigned long c2 = zlib_crc32((const unsigned char *)"Hel", 3, 0); + c2 = zlib_crc32((const unsigned char *)"lo", 2, c2); + printf(" incremental = 0x%08lX %s\n", c2, c == c2 ? "MATCH" : "MISMATCH"); + + printf("\n3. Compress (zlib format):\n"); + const char *input = "Hello, World!"; + size_t comp_len = 0; + unsigned char *comp = zlib_compress((const unsigned char *)input, strlen(input), + Z_DEFAULT_COMPRESSION, MAX_WBITS, &comp_len); + if (comp) { + printf(" Input: %zu bytes\n", strlen(input)); + printf(" Output: %zu bytes\n", comp_len); + printf(" Hex: "); + for (size_t i = 0; i < comp_len && i < 40; i++) printf("%02X ", comp[i]); + printf("\n"); + + printf("\n4. Decompress (zlib format):\n"); + size_t dec_len = 0; + unsigned char *dec = zlib_decompress(comp, comp_len, MAX_WBITS, DEF_BUF_SIZE, &dec_len); + if (dec) { + printf(" Output: %zu bytes\n", dec_len); + printf(" Content: \"%.*s\"\n", (int)dec_len, (char *)dec); + printf(" Match: %s\n", dec_len == strlen(input) && memcmp(dec, input, dec_len) == 0 ? "YES" : "NO"); + free(dec); + } else { + printf(" FAILED! Error: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); + } + free(comp); + } else { + printf(" FAILED! Error: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); + } + + printf("\n5. Compress (raw deflate):\n"); + comp_len = 0; + comp = zlib_compress((const unsigned char *)input, strlen(input), + Z_DEFAULT_COMPRESSION, -MAX_WBITS, &comp_len); + if (comp) { + printf(" Output: %zu bytes\n", comp_len); + printf(" Hex: "); + for (size_t i = 0; i < comp_len && i < 40; i++) printf("%02X ", comp[i]); + printf("\n"); + + size_t dec_len = 0; + unsigned char *dec = zlib_decompress(comp, comp_len, -MAX_WBITS, DEF_BUF_SIZE, &dec_len); + if (dec) { + printf(" Decompress: \"%.*s\" %s\n", (int)dec_len, (char *)dec, + dec_len == strlen(input) && memcmp(dec, input, dec_len) == 0 ? "OK" : "FAIL"); + free(dec); + } else { + printf(" Decompress FAILED! Error: %s\n", zlib_get_error()); + } + free(comp); + } else { + printf(" FAILED! Error: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); + } + + printf("\nDone.\n"); + return 0; +} diff --git a/Test/TestProject/App/__zlib/test_debug.c b/Test/TestProject/App/__zlib/test_debug.c new file mode 100644 index 0000000..682eb28 --- /dev/null +++ b/Test/TestProject/App/__zlib/test_debug.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include "pyzlib.h" + +int main(void) +{ + printf("=== Full Self-Implemented zlib Test ===\n\n"); + + printf("1. Adler-32:\n"); + unsigned long a = zlib_adler32((const unsigned char *)"Hello", 5, 1); + printf(" adler32(\"Hello\") = 0x%08lX\n", a); + + printf("\n2. CRC-32:\n"); + unsigned long c = zlib_crc32((const unsigned char *)"Hello", 5, 0); + printf(" crc32(\"Hello\") = 0x%08lX\n", c); + + const char *tests[] = {"Hello", "Hello, World!", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", ""}; + int levels[] = {2, 6, 0}; + + for (int t = 0; t < 4; t++) { + const char *input = tests[t]; + size_t input_len = strlen(input); + printf("\n--- Test: \"%s\" (%zu bytes) ---\n", input_len > 0 ? input : "(empty)", input_len); + + for (int li = 0; li < 3; li++) { + int level = levels[li]; + printf("\n Level %d, zlib format:\n", level); + size_t comp_len = 0; + unsigned char *comp = zlib_compress((const unsigned char *)input, input_len, + level, MAX_WBITS, &comp_len); + if (comp) { + printf(" Compressed: %zu bytes\n", comp_len); + size_t dec_len = 0; + unsigned char *dec = zlib_decompress(comp, comp_len, MAX_WBITS, DEF_BUF_SIZE, &dec_len); + if (dec) { + int match = (dec_len == input_len && memcmp(dec, input, dec_len) == 0); + printf(" Decompressed: %zu bytes, Match: %s\n", dec_len, match ? "YES" : "NO"); + if (!match) { + printf(" Expected: \"%s\"\n", input_len > 0 ? input : "(empty)"); + printf(" Got: \"%.*s\"\n", (int)dec_len, (char *)dec); + } + free(dec); + } else { + printf(" Decompress FAILED: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); + } + free(comp); + } else { + printf(" Compress FAILED: %s (code %d)\n", zlib_get_error(), zlib_get_error_code()); + } + } + } + + printf("\n3. Raw deflate:\n"); + { + const char *input = "Raw deflate test"; + size_t comp_len = 0; + unsigned char *comp = zlib_compress((const unsigned char *)input, strlen(input), + Z_DEFAULT_COMPRESSION, -MAX_WBITS, &comp_len); + if (comp) { + printf(" Compressed: %zu bytes\n", comp_len); + size_t dec_len = 0; + unsigned char *dec = zlib_decompress(comp, comp_len, -MAX_WBITS, DEF_BUF_SIZE, &dec_len); + if (dec) { + printf(" Decompressed: \"%.*s\" %s\n", (int)dec_len, (char *)dec, + dec_len == strlen(input) && memcmp(dec, input, dec_len) == 0 ? "OK" : "FAIL"); + free(dec); + } else { + printf(" Decompress FAILED: %s\n", zlib_get_error()); + } + free(comp); + } + } + + printf("\nDone.\n"); + return 0; +} diff --git a/Test/TestProject/App/__zlib/test_pyzlib.py b/Test/TestProject/App/__zlib/test_pyzlib.py new file mode 100644 index 0000000..62ede4f --- /dev/null +++ b/Test/TestProject/App/__zlib/test_pyzlib.py @@ -0,0 +1,880 @@ +from stdint import * +import pyzlib +import zhuff +import zdef +from stdio import printf, strlen +import stdlib +import string +import t, c + + +test_passed: t.CInt = 0 +test_failed: t.CInt = 0 +def check(name: str, condition: t.CInt, detail: str): + global test_passed, test_failed + if condition: + test_passed += 1 + printf(" [PASS] %s\n", name) + else: + test_failed += 1 + printf(" [FAIL] %s -- %s\n", name, detail if detail else "") + +def print_hex_test(data: BYTEPTR, length: t.CSizeT, max_show: t.CSizeT): + if not data or length == 0: + printf("(empty)\n") + return + show: t.CSizeT = max_show if (length > max_show) else length + i: t.CSizeT + for i in range(show): + printf("%02X ", data[i]) + if length > max_show: + printf("... (%zu bytes total)", length) + printf("\n") + +def print_separator(): + printf(" -------------------------------------------\n") + +def section_header(title: str): + printf("\n+-- %s --+\n", title) + +def section_footer(): + printf("+--------------------------------------------+\n") + +# ============================================================ + +def test_version(): + section_header("Version Info") + + ver: str = pyzlib.ZLIB_VERSION + printf(" ZLIB_VERSION (compile-time) : %s\n", ver) + check("ZLIB_VERSION not None", ver != None, "version string is None") + check("ZLIB_VERSION not empty", strlen(ver) > 0, "version string is empty") + + runtime_ver: str = pyzlib.runtime_version() + printf(" ZLIB_RUNTIME_VERSION : %s\n", runtime_ver) + check("runtime version not None", runtime_ver != None, "runtime version is None") + check("runtime version not empty", strlen(runtime_ver) > 0, "runtime version is empty") + + section_footer() + + +def test_compress_decompress(): + section_header("compress / decompress") + + inp: str = "Hello, World! This is a test of zlib compression and decompression." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("compress returns non-None", compressed != None, "compress returned None") + check("compress output size > 0", out_length > 0, "compressed size is 0") + check("compress output produced", out_length > 0, "compressed size is 0") + + printf(" Compressed (%zu bytes): ", out_length) + print_hex_test(compressed, out_length, 32) + printf(" Compression ratio: %.1f%%\n", t.CDouble(out_length) / input_length * 100) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(compressed, out_length, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress returns non-None", decompressed != None, "decompress returned None") + check("decompress output size matches input", dec_length == input_length, "size mismatch") + check("decompress output matches input", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + + printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(decompressed)) + + free(compressed) + free(decompressed) + section_footer() + + +def test_compress_levels(): + section_header("Compression Levels") + + inp: str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + + c0: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_NO_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 0 compress OK", c0 != None, "level 0 returned None") + printf(" Level 0 (Z_NO_COMPRESSION): %zu bytes\n", out_length) + length0: t.CSizeT = out_length + free(c0) + + c1: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_BEST_SPEED, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 1 compress OK", c1 != None, "level 1 returned None") + printf(" Level 1 (Z_BEST_SPEED) : %zu bytes\n", out_length) + free(c1) + + c6: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level -1 compress OK", c6 != None, "default level returned None") + printf(" Level -1 (DEFAULT) : %zu bytes\n", out_length) + free(c6) + + c9: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_BEST_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 9 compress OK", c9 != None, "level 9 returned None") + printf(" Level 9 (Z_BEST_COMPRESS) : %zu bytes\n", out_length) + length9: t.CSizeT = out_length + free(c9) + + check("level 9 smaller than level 0", length9 < length0, "level 9 not smaller than level 0") + + section_footer() + + +def test_compressobj(): + section_header("compressobj (incremental)") + + part1: str = "Hello, " + part2: str = "World!" + printf(" Part 1: \"%s\"\n", part1) + printf(" Part 2: \"%s\"\n", part2) + + out_length: t.CSizeT = 0 + + s: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + check("compressobj created", s != None, "compressobj is None") + print_separator() + + c1: BYTEPTR = s.compress(BYTEPTR(part1), strlen(part1), c.Addr(out_length)) + check("compress part1 OK", c1 != None, "compress part1 failed") + printf(" Compressed part1: %zu bytes -> ", out_length) + print_hex_test(c1, out_length, 16) + total: t.CSizeT = out_length + all: BYTEPTR = None + if out_length > 0 and c1: + all = BYTEPTR(malloc(total)) + if all: memcpy(all, c1, out_length) + free(c1) + + c2: BYTEPTR = s.compress(BYTEPTR(part2), + strlen(part2), c.Addr(out_length)) + check("compress part2 OK", c2 != None, "compress part2 failed") + printf(" Compressed part2: %zu bytes -> ", out_length) + print_hex_test(c2, out_length, 16) + if out_length > 0 and c2: + new_all: BYTEPTR = BYTEPTR(realloc(all, total + out_length)) + if new_all: + all = new_all + memcpy(all + total, c2, out_length) + total += out_length + free(c2) + + c3: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush (Z_FINISH) OK", c3 != None, "flush failed") + printf(" Flush result : %zu bytes -> ", out_length) + print_hex_test(c3, out_length, 16) + if out_length > 0 and c3: + new_all: BYTEPTR = realloc(all, total + out_length) # 隐式转换 + if new_all: + all = new_all + memcpy(all + total, c3, out_length) + total += out_length + free(c3) + + print_separator() + + if all: + dec_length: t.CSizeT = 0 + dec: BYTEPTR = pyzlib.decompress(all, total, pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress incremental OK", dec != None, "decompress returned None") + check("decompress incremental size", dec != None and dec_length == strlen(part1) + strlen(part2), "size mismatch") + check("decompress incremental content", + dec != None and memcmp(dec, "Hello, World!", dec_length) == 0, "content mismatch") + if dec: + printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + free(all) + + s.delete() # del s + section_footer() + +def test_decompressobj(): + section_header("decompressobj") + + inp: str = "Test data for decompress object." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pyzlib.MAX_WBITS, None, 0) + check("decompressobj created", d != None, "decompressobj is None") + check("eof is false initially", d.eof == 0, "eof should be 0") + print_separator() + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(compressed, out_length, + 0, c.Addr(dec_length)) + check("decompress OK", dec != None, "decompress returned None") + check("decompress size", dec != None and dec_length == input_length, "size mismatch") + check("decompress content", dec != None and memcmp(dec, inp, input_length) == 0, "content mismatch") + check("eof is true after stream end", d.eof == 1, "eof should be 1") + + if dec: + printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(dec)) + printf(" eof = %d\n", d.eof) + + free(dec) + free(compressed) + d.delete() + section_footer() + +def test_decompressobj_max_lengthgth(): + section_header("decompressobj max_lengthgth") + + inp: str = "This is a longer string for testing max_lengthgth parameter in decompress." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pyzlib.MAX_WBITS, None, 0) + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(compressed, out_length, + 10, c.Addr(dec_length)) + check("max_lengthgth decompress OK", dec != None, "decompress returned None") + check("max_lengthgth limits output", dec_length <= 10, "output exceeded max_lengthgth") + if dec: + printf(" First chunk (max_lengthgth=10): \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + + tail_length: t.CSizeT = 0 + tail: BYTEPTR = d.unconsumed_tail(c.Addr(tail_length)) + check("unconsumed_tail exists", tail != None or tail_length == 0, "no unconsumed_tail") + printf(" unconsumed_tail: %zu bytes remaining\n", tail_length) + printf(" eof = %d\n", d.eof) + + if tail_length > 0 or not d.eof: + flushed: BYTEPTR = d.flush(pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("flush after max_lengthgth OK", flushed != None, "flush returned None") + if flushed: printf(" Flushed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(flushed)) + free(flushed) + + printf(" eof after flush = %d\n", d.eof) + + d.delete() + free(compressed) + section_footer() + + +def test_decompressobj_unused_data(): + section_header("decompressobj unused_data") + + inp: str = "Hello" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + total_length: t.CSizeT = out_length + 5 + combined: BYTEPTR = BYTEPTR(malloc(total_length)) + memcpy(combined, compressed, out_length) + memcpy(combined + out_length, "EXTRA", 5) + free(compressed) + printf(" Combined (compressed + \"EXTRA\"): %zu bytes\n", total_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pyzlib.MAX_WBITS, None, 0) + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(combined, total_length, + 0, c.Addr(dec_length)) + check("decompress with extra OK", dec != None, "decompress returned None") + check("eof after stream end", d.eof == 1, "eof should be 1") + if dec: + printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + + print_separator() + + unused_length: t.CSizeT = 0 + unused: BYTEPTR = d.unused_data(c.Addr(unused_length)) + check("unused_data exists", unused != None and unused_length > 0, "no unused_data") + check("unused_data is EXTRA", unused_length == 5 and unused != None and memcmp(unused, "EXTRA", 5) == 0, "unused_data mismatch") + printf(" unused_data (%zu bytes): \"%.*s\"\n", unused_length, t.CInt(unused_length), str(unused)) + + d.delete() + free(combined) + section_footer() + + +def test_compress_copy(): + section_header("Compress.copy()") + + inp: str = "Copy test data for compress object" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + c1: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + c1.compress(BYTEPTR(inp), input_length, c.Addr(out_length)) + printf(" Original: compressed %zu bytes so far\n", out_length) + + c2: pyzlib.Compress | t.CPtr = c1.copy() + check("compress copy OK", c2 != None, "copy returned None") + printf(" Copied compressobj\n") + + print_separator() + + f1: BYTEPTR = c1.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush original OK", f1 != None, "flush original failed") + length1: t.CSizeT = out_length + printf(" Original flush: %zu bytes\n", length1) + free(f1) + + f2: BYTEPTR = c2.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush copy OK", f2 != None, "flush copy failed") + length2: t.CSizeT = out_length + printf(" Copy flush : %zu bytes\n", length2) + free(f2) + + check("copy produces same output", length1 == length2, "output lengthgths differ") + + c1.delete() + c2.delete() + section_footer() + + +def test_decompress_copy(): + section_header("Decompress.copy()") + + inp: str = "Decompress copy test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d1: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pyzlib.MAX_WBITS, None, 0) + d2: pyzlib.Decompress | t.CPtr = d1.copy() + check("decompress copy OK", d2 != None, "copy returned None") + printf(" Copied decompressobj\n") + + print_separator() + + dec_length1: t.CSizeT = 0 + dec_length2: t.CSizeT = 0 + dec1: BYTEPTR = d1.decompress(compressed, out_length, + 0, c.Addr(dec_length1)) + dec2: BYTEPTR = d2.decompress(compressed, out_length, + 0, c.Addr(dec_length2)) + check("decompress copy output size", dec_length1 == dec_length2, "sizes differ") + check("decompress copy output content", + dec1 and dec2 and memcmp(dec1, dec2, dec_length1) == 0, "content differs") + + if dec1: printf(" Original: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length1), str(dec1), dec_length1) + if dec2: printf(" Copy : \"%.*s\" (%zu bytes)\n", t.CInt(dec_length2), str(dec2), dec_length2) + + free(dec1) + free(dec2) + free(compressed) + d1.delete() + d2.delete() + section_footer() + + +def test_adler32(): + section_header("adler32 checksum") + + checksum: ULONG = pyzlib.zlib_adler32(BYTEPTR("Hello"), 5, 1) + printf(" adler32(\"Hello\") = 0x%08lX (%lu)\n", checksum, checksum) + check("adler32 returns non-zero", checksum != 0, "checksum is 0") + + incremental: ULONG = pyzlib.zlib_adler32(BYTEPTR("Hel"), 3, 1) + printf(" adler32(\"Hel\") = 0x%08lX\n", incremental) + incremental = pyzlib.zlib_adler32(BYTEPTR("lo"), 2, incremental) + printf(" adler32(\"lo\", prev) = 0x%08lX\n", incremental) + check("adler32 incremental matches one-shot", incremental == checksum, "incremental != one-shot") + printf(" Incremental == One-shot: %s\n", incremental == "YES" if checksum else "NO") + + section_footer() + + +def test_crc32(): + section_header("crc32 checksum") + + checksum: ULONG = pyzlib.zlib_crc32(BYTEPTR("Hello"), 5, 0) + printf(" crc32(\"Hello\") = 0x%08lX (%lu)\n", checksum, checksum) + check("crc32 returns non-zero", checksum != 0, "checksum is 0") + + incremental: ULONG = pyzlib.zlib_crc32(BYTEPTR("Hel"), 3, 0) + printf(" crc32(\"Hel\") = 0x%08lX\n", incremental) + incremental = pyzlib.zlib_crc32(BYTEPTR("lo"), 2, incremental) + printf(" crc32(\"lo\", prev) = 0x%08lX\n", incremental) + check("crc32 incremental matches one-shot", incremental == checksum, "incremental != one-shot") + printf(" Incremental == One-shot: %s\n", incremental == "YES" if checksum else "NO") + + section_footer() + + +def test_empty_compress(): + section_header("Empty data compress/decompress") + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(""), 0, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("compress empty OK", compressed != None, "compress empty returned None") + check("compress empty output > 0", out_length > 0, "compressed empty is 0 bytes") + printf(" Empty input compressed: %zu bytes (header only)\n", out_length) + printf(" Hex: ") + print_hex_test(compressed, out_length, 32) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(compressed, out_length, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress empty OK", decompressed != None, "decompress empty returned None") + check("decompress empty size == 0", dec_length == 0, "decompressed size != 0") + printf(" Decompressed back: %zu bytes\n", dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_gzip_format(): + section_header("Gzip format (wbits=31)") + + inp: str = "Gzip format test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\" (%zu bytes)\n", inp, input_length) + + gzip_wbits: t.CInt = pyzlib.MAX_WBITS + 16 + printf(" wbits = MAX_WBITS + 16 = %d\n", gzip_wbits) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, gzip_wbits, c.Addr(out_length)) + check("gzip compress OK", compressed != None, "gzip compress failed") + printf(" Gzip compressed: %zu bytes\n", out_length) + printf(" Header bytes: ") + print_hex_test(compressed, 4 if (out_length > 4) else out_length, 4) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(compressed, out_length, + gzip_wbits, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("gzip decompress OK", decompressed != None, "gzip decompress failed") + check("gzip decompress size", dec_length == input_length, "size mismatch") + check("gzip decompress content", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_raw_deflate(): + section_header("Raw deflate (wbits=-15)") + + inp: str = "Raw deflate test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\" (%zu bytes)\n", inp, input_length) + + raw_wbits: t.CInt = -pyzlib.MAX_WBITS + printf(" wbits = -MAX_WBITS = %d\n", raw_wbits) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, raw_wbits, c.Addr(out_length)) + check("raw deflate compress OK", compressed != None, "raw deflate compress failed") + printf(" Raw compressed: %zu bytes\n", out_length) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(compressed, out_length, + raw_wbits, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("raw deflate decompress OK", decompressed != None, "raw deflate decompress failed") + check("raw deflate decompress size", dec_length == input_length, "size mismatch") + check("raw deflate decompress content", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_zdict(): + section_header("Preset dictionary (zdict)") + + dict: str = "common words that appear frequently in the data" + inp: str = "common words that appear frequently" + input_length: t.CSizeT = strlen(inp) + printf(" Dictionary: \"%s\" (%zu bytes)\n", dict, strlen(dict)) + printf(" Input : \"%s\" (%zu bytes)\n", inp, input_length) + + out_length: t.CSizeT = 0 + s: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, + BYTEPTR(dict), strlen(dict)) + check("compressobj with zdict OK", s != None, "compressobj with zdict failed") + + comp_data: BYTEPTR = s.compress(BYTEPTR(inp), + input_length, c.Addr(out_length)) + check("compress with zdict OK", comp_data != None, "compress with zdict failed") + printf(" Compressed with zdict: %zu bytes\n", out_length) + free(comp_data) + + flush_data: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush with zdict OK", flush_data != None, "flush with zdict failed") + printf(" Flush: %zu bytes\n", out_length) + free(flush_data) + + print_separator() + + total_comp: t.CSizeT = out_length + s.delete() + + s = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + comp_no_dict: BYTEPTR = s.compress(BYTEPTR(inp), + input_length, c.Addr(out_length)) + flush_no_dict: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + no_dict_total: t.CSizeT = 0 + if comp_no_dict: no_dict_total += out_length + if flush_no_dict: no_dict_total += out_length + printf(" Without zdict: ~%zu bytes compressed\n", no_dict_total) + printf(" With zdict : %zu bytes compressed\n", total_comp) + free(comp_no_dict) + free(flush_no_dict) + s.delete() + + section_footer() + + +def test_huffman_tree(): + section_header("Huffman tree construction") + + printf(" --- Fixed Huffman tree (literal/lengthgth) ---\n") + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + + check("fixed lit tree count == 288", lit_tree.count == 288, "count mismatch") + check("fixed lit tree max_bits == 9", lit_tree.max_bits == 9, "max_bits mismatch") + + has_8bit: t.CInt = 0 + has_9bit: t.CInt = 0 + has_7bit: t.CInt = 0 + for i in range(143 + 1): + if lit_tree.codes[i].bits == 8: + has_8bit += 1 + for i in range(143 + 1, 255 + 1): + if lit_tree.codes[i].bits == 9: + has_9bit += 1 + for i in range(255 + 1, 279 + 1): + if lit_tree.codes[i].bits == 7: + has_7bit += 1 + check("0-143 are 8-bit", has_8bit == 144, "wrong count") + check("144-255 are 9-bit", has_9bit == 112, "wrong count") + check("256-279 are 7-bit", has_7bit == 24, "wrong count") + + printf(" 0-143: %d codes with 8 bits\n", has_8bit) + printf(" 144-255: %d codes with 9 bits\n", has_9bit) + printf(" 256-279: %d codes with 7 bits\n", has_7bit) + printf(" 280-287: 8-bit (end-of-block 256 = 7-bit)\n") + printf(" EOB (256): code=0x%X, bits=%d\n", lit_tree.codes[256].code, lit_tree.codes[256].bits) + + printf("\n --- Fixed Huffman tree (distance) ---\n") + dist_tree = zhuff.zhuff_tree() + dist_tree.build_fixed_dist_tree() + + check("fixed dist tree count == 32", dist_tree.count == 32, "count mismatch") + check("fixed dist tree max_bits == 5", dist_tree.max_bits == 5, "max_bits mismatch") + + all_5bit: t.CInt = 1 + for i in range(32): + if dist_tree.codes[i].bits != 5: + all_5bit = 0 + check("all 32 distance codes are 5-bit", all_5bit, "not all 5-bit") + printf(" All 32 distance codes: 5 bits each\n") + + printf("\n --- Dynamic Huffman tree from frequencies ---\n") + freqs: list[t.CInt, 256] + memset(freqs, 0, freqs.__sizeof__()) + freqs['A'] = 50 + freqs['B'] = 25 + freqs['C'] = 12 + freqs['D'] = 6 + freqs['E'] = 3 + freqs['F'] = 1 + freqs[256] = 1 + + dyn_tree = zhuff.zhuff_tree() + dyn_tree.build_codes(freqs, 257, 15) + + check("dynamic tree count == 257", dyn_tree.count == 257, "count mismatch") + check("dynamic tree max_bits <= 15", dyn_tree.max_bits <= 15, "max_bits overflow") + + total_codes: t.CInt = 0 + max_length_found: t.CInt = 0 + for i in range(257): + if dyn_tree.codes[i].bits > 0: + total_codes += 1 + if dyn_tree.codes[i].bits > max_length_found: + max_length_found = dyn_tree.codes[i].bits + check("dynamic tree has 7 active codes", total_codes == 7, "wrong active count") + check("dynamic tree max code lengthgth found <= 15", max_length_found <= 15, "code lengthgth overflow") + + printf(" Frequencies: A=50, B=25, C=12, D=6, E=3, F=1, EOB=1\n") + printf(" Active codes: %d, max code lengthgth: %d\n", total_codes, max_length_found) + + printf(" Code assignments:\n") + names: list[str, None] = ["A","B","C","D","E","F"] # 一个都æ˜?char* 的数ç»? + syms: list[t.CInt, None] = ['A','B','C','D','E','F'] + for i in range(6): + printf(" '%s' (freq=%3d): code=0x%04X, bits=%d\n", + names[i], freqs[syms[i]], + dyn_tree.codes[syms[i]].code, + dyn_tree.codes[syms[i]].bits) + + + + printf(" EOB (freq=1): code=0x%04X, bits=%d\n", + dyn_tree.codes[256].code, dyn_tree.codes[256].bits) + a_bits: t.CInt = dyn_tree.codes['A'].bits + f_bits: t.CInt = dyn_tree.codes['F'].bits + check("high-freq symbol has shorter code", a_bits <= f_bits, "A should be <= F") + printf(" High-freq 'A' (%d bits) <= low-freq 'F' (%d bits): %s\n", + a_bits, f_bits, "YES" if (a_bits <= f_bits) else "NO") + + printf("\n --- Huffman encode/decode roundtrip ---\n") + freqs: list[t.CInt, 288] + memset(freqs, 0, freqs.__sizeof__()) + freqs['H'] = 10 + freqs['e'] = 8 + freqs['l'] = 20 + freqs['o'] = 8 + freqs[' '] = 5 + freqs['W'] = 3 + freqs['r'] = 5 + freqs['d'] = 3 + freqs['!'] = 2 + freqs[256] = 1 + + enc_tree = zhuff.zhuff_tree() + enc_tree.build_codes(freqs, 257, 15) + + dec_tree = zhuff.zhuff_decode_tree() + dec_tree.build_decode_tree(c.Addr(enc_tree)) + + writer = zdef.zbit_writer() + + symbols: list[t.CInt, 16] + symbols[0] = 'H'; symbols[1] = 'e'; symbols[2] = 'l'; symbols[3] = 'l' + symbols[4] = 'o'; symbols[5] = ' '; symbols[6] = 'W'; symbols[7] = 'o' + symbols[8] = 'r'; symbols[9] = 'l'; symbols[10] = 'd'; symbols[11] = '!' + symbols[12] = 256 + num_symbols: t.CInt = 13 + + for i in range(num_symbols): + enc_tree.encode_symbol(symbols[i], c.Addr(writer)) + + reader = zdef.zbit_reader() + reader.buf = writer.buf + reader.length = writer.byte_pos + (1 if (writer.bit_pos > 0) else 0) + reader.byte_pos = 0 + reader.bit_pos = 0 + + roundtrip_ok: t.CInt = 1 + for i in range(num_symbols): + decoded: t.CInt = dec_tree.decode_symbol(c.Addr(reader)) + if decoded != symbols[i]: + roundtrip_ok = 0 + printf(" MISMATCH at symbol %d: expected %d, got %d\n", i, symbols[i], decoded) + break + check("encode/decode roundtrip matches", roundtrip_ok, "roundtrip failed") + printf(" Encoded %d symbols into %zu bytes, decoded all correctly\n", + num_symbols, writer.byte_pos + (1 if (writer.bit_pos > 0) else 0)) + + free(writer.buf) + + printf("\n --- Overflow handling (many symbols, limited max_bits) ---\n") + freqs: list[t.CInt, 256] + for i in range(256): + freqs[i] = 1 + freqs[256] = 1 + + tree = zhuff.zhuff_tree() + tree.build_codes(freqs, 257, 15) + + overflow_ok: t.CInt = 1 + for i in range(257): + if tree.codes[i].bits > 15 or tree.codes[i].bits < 0: + overflow_ok = 0 + break + check("all code lengthgths <= 15 with 257 symbols", overflow_ok, "code lengthgth overflow") + + bl_count: list[t.CInt, 16] = [0] + for i in range(257): + if tree.codes[i].bits > 0: + bl_count[tree.codes[i].bits] += 1 + printf(" Code lengthgth distribution (257 equal-freq symbols, max_bits=15):\n") + for i in range(1, 15 + 1): + if bl_count[i] > 0: + printf(" %2d bits: %3d codes\n", i, bl_count[i]) + + dt = zhuff.zhuff_decode_tree() + dt.build_decode_tree(c.Addr(tree)) + + w = zdef.zbit_writer() + tree.encode_symbol(0, c.Addr(w)) + tree.encode_symbol(128, c.Addr(w)) + tree.encode_symbol(255, c.Addr(w)) + tree.encode_symbol(256, c.Addr(w)) + + r = zdef.zbit_reader() + r.buf = w.buf + r.length = w.byte_pos + (1 if (w.bit_pos > 0) else 0) + r.byte_pos = 0 + r.bit_pos = 0 + + s0: t.CInt = dt.decode_symbol(c.Addr(r)) + s1: t.CInt = dt.decode_symbol(c.Addr(r)) + s2: t.CInt = dt.decode_symbol(c.Addr(r)) + s3: t.CInt = dt.decode_symbol(c.Addr(r)) + + check("overflow roundtrip: symbol 0", s0 == 0, "decode mismatch") + check("overflow roundtrip: symbol 128", s1 == 128, "decode mismatch") + check("overflow roundtrip: symbol 255", s2 == 255, "decode mismatch") + check("overflow roundtrip: symbol 256 (EOB)", s3 == 256, "decode mismatch") + + free(w.buf) + + + printf("\n --- Kraft inequality check ---\n") + freqs: list[t.CInt, 256] + memset(freqs, 0, freqs.__sizeof__()) + freqs['X'] = 100 + freqs['Y'] = 50 + freqs['Z'] = 25 + freqs[256] = 1 + + tree = zhuff.zhuff_tree() + tree.build_codes(freqs, 257, 15) + + kraft_sum: t.CDouble = 0.0 + for i in range(257): + if tree.codes[i].bits > 0: + kraft_sum += 1.0 / (t.CDouble(ULONGLONG(1) << tree.codes[i].bits)) + check("Kraft inequality: sum <= 1.0", kraft_sum <= 1.0 + 1e-9, "Kraft violated") + printf(" Kraft sum = %.10f (must be <= 1.0)\n", kraft_sum) + + section_footer() + + +def test_error_handling(): + section_header("Error handling") + + out_length: t.CSizeT = 0 + printf(" Trying to decompress garbage data...\n") + + result: BYTEPTR = pyzlib.decompress(BYTEPTR("garbage"), 7, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(out_length)) + check("decompress garbage returns None", result == None, "should have returned None") + printf(" Error code : %d\n", pyzlib.get_error_code()) + printf(" Error message: \"%s\"\n", pyzlib.get_error()) + check("error message set", strlen(pyzlib.get_error()) > 0, "error message is empty") + check("error code is set", pyzlib.get_error_code() != pyzlib.Z_OK, "error code is Z_OK") + + print_separator() + + pyzlib.clear_error() + check("clear error clears code", pyzlib.get_error_code() == 0, "error code not cleared") + printf(" After clear: code=%d, msg=\"%s\"\n", pyzlib.get_error_code(), pyzlib.get_error()) + + section_footer() + + +def test_constants(): + section_header("Constants") + printf(" Compression Levels:\n") + printf(" Z_NO_COMPRESSION = %d\n", pyzlib.Z_NO_COMPRESSION) + printf(" Z_BEST_SPEED = %d\n", pyzlib.Z_BEST_SPEED) + printf(" Z_BEST_COMPRESSION = %d\n", pyzlib.Z_BEST_COMPRESSION) + printf(" Z_DEFAULT_COMPRESSION = %d\n", pyzlib.Z_DEFAULT_COMPRESSION) + printf(" Methods:\n") + printf(" DEFLATED = %d\n", pyzlib.DEFLATED) + printf(" Flush Modes:\n") + printf(" Z_NO_FLUSH = %d\n", pyzlib.Z_NO_FLUSH) + printf(" Z_PARTIAL_FLUSH = %d\n", pyzlib.Z_PARTIAL_FLUSH) + printf(" Z_SYNC_FLUSH = %d\n", pyzlib.Z_SYNC_FLUSH) + printf(" Z_FULL_FLUSH = %d\n", pyzlib.Z_FULL_FLUSH) + printf(" Z_FINISH = %d\n", pyzlib.Z_FINISH) + printf(" Z_BLOCK = %d\n", pyzlib.Z_BLOCK) + printf(" Z_TREES = %d\n", pyzlib.Z_TREES) + printf(" Strategies:\n") + printf(" Z_DEFAULT_STRATEGY = %d\n", pyzlib.Z_DEFAULT_STRATEGY) + printf(" Z_FILTERED = %d\n", pyzlib.Z_FILTERED) + printf(" Z_HUFFMAN_ONLY = %d\n", pyzlib.Z_HUFFMAN_ONLY) + printf(" Z_RLE = %d\n", pyzlib.Z_RLE) + printf(" Z_FIXED = %d\n", pyzlib.Z_FIXED) + printf(" Return Codes:\n") + printf(" Z_OK = %d\n", pyzlib.Z_OK) + printf(" Z_STREAM_END = %d\n", pyzlib.Z_STREAM_END) + printf(" Z_NEED_DICT = %d\n", pyzlib.Z_NEED_DICT) + printf(" Z_ERRNO = %d\n", pyzlib.Z_ERRNO) + printf(" Z_STREAM_ERROR = %d\n", pyzlib.Z_STREAM_ERROR) + printf(" Z_DATA_ERROR = %d\n", pyzlib.Z_DATA_ERROR) + printf(" Z_MEM_ERROR = %d\n", pyzlib.Z_MEM_ERROR) + printf(" Z_BUF_ERROR = %d\n", pyzlib.Z_BUF_ERROR) + printf(" Z_VERSION_ERROR = %d\n", pyzlib.Z_VERSION_ERROR) + printf(" Window / Buffer:\n") + printf(" MAX_WBITS = %d\n", pyzlib.MAX_WBITS) + printf(" DEF_BUF_SIZE = %d\n", pyzlib.DEF_BUF_SIZE) + printf(" DEF_MEM_LEVEL = %d\n", pyzlib.DEF_MEM_LEVEL) + section_footer() + + +def main123456() -> t.CInt: + printf("==============================================\n") + printf(" Python zlib - C Implementation Tests\n") + printf("==============================================\n") + + test_constants() + test_version() + test_compress_decompress() + test_compress_levels() + test_compressobj() + test_decompressobj() + test_decompressobj_max_lengthgth() + test_decompressobj_unused_data() + test_compress_copy() + test_decompress_copy() + test_adler32() + test_crc32() + test_empty_compress() + test_gzip_format() + test_raw_deflate() + test_zdict() + test_huffman_tree() + test_error_handling() + + printf("\n==============================================\n") + printf(" Results: %d passed, %d failed\n", test_passed, test_failed) + printf("==============================================\n") + + return 1 if test_failed > 0 else 0 + diff --git a/Test/TestProject/App/__zlib/zchecksum.py b/Test/TestProject/App/__zlib/zchecksum.py new file mode 100644 index 0000000..422bd5e --- /dev/null +++ b/Test/TestProject/App/__zlib/zchecksum.py @@ -0,0 +1,90 @@ +from stdint import * +import t, c + + +def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T: + a: t.CUInt32T = (init >> 0) & 0xFFFF + b: t.CUInt32T = (init >> 16) & 0xFFFF + if not data or length == 0: + return init + i: t.CSizeT + for i in range(length): + a = (a + data[i]) % 65521 + b = (b + a) % 65521 + return (b << 16) | a + +crc32_table: list[t.CUInt32T, 256] = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBBBD6, 0xACBCCB40, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7D49, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDede9EC5, 0x47D7897F, 0x30D0B8E9, + 0xBDDA8B1C, 0xCADD8B8A, 0x53D3903A, 0x24D4C2AC, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +] + +def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T: + crc: t.CUInt32T = init ^ 0xFFFFFFFF + if not data or length == 0: return init + i: t.CSizeT + for i in range(length): + crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8) + return crc ^ 0xFFFFFFFF + diff --git a/Test/TestProject/App/__zlib/zdef.py b/Test/TestProject/App/__zlib/zdef.py new file mode 100644 index 0000000..4f1918c --- /dev/null +++ b/Test/TestProject/App/__zlib/zdef.py @@ -0,0 +1,269 @@ +from stdint import * +import stddef +import string +import stdlib +import t, c + + +# ============================================================ +# DEFLATE / zlib constants +# ============================================================ +ZDEFLATE_WINDOW_BITS: t.CDefine = 15 +ZDEFLATE_WINDOW_SIZE: t.CDefine = (1 << ZDEFLATE_WINDOW_BITS) +ZDEFLATE_WINDOW_MASK: t.CDefine = (ZDEFLATE_WINDOW_SIZE - 1) + +ZDEFLATE_MIN_MATCH: t.CDefine = 3 +ZDEFLATE_MAX_MATCH: t.CDefine = 258 + +ZDEFLATE_HASH_BITS: t.CDefine = 15 +ZDEFLATE_HASH_SIZE: t.CDefine = (1 << ZDEFLATE_HASH_BITS) +ZDEFLATE_HASH_MASK: t.CDefine = (ZDEFLATE_HASH_SIZE - 1) + +ZDEFLATE_MAX_CODES: t.CDefine = 288 +ZDEFLATE_MAX_DIST_CODES: t.CDefine = 32 +ZDEFLATE_MAX_BITS: t.CDefine = 15 +ZDEFLATE_MAX_CODELEN_CODES: t.CDefine = 19 + +ZDEFLATE_LIT_COUNT: t.CDefine = 286 +ZDEFLATE_DIST_COUNT: t.CDefine = 30 + +ZDEFLATE_LEN_SYMBOLS_BASE: t.CDefine = 257 +ZDEFLATE_END_OF_BLOCK: t.CDefine = 256 + +# ============================================================ +# Length / Distance extra bits tables (RFC 1951) +# ============================================================ +zdeflate_len_extra_bits: list[t.CInt, 29] = [ + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 4, 4, 4, 4, + 5, 5, 5, 5, + 0 +] + +zdeflate_len_base: list[t.CInt, 29] = [ + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 15, 17, + 19, 23, 27, 31, + 35, 43, 51, 59, + 67, 83, 99, 115, + 131, 163, 195, 227, + 258 +] + +zdeflate_dist_extra_bits: list[t.CInt, 30] = [ + 0, 0, 0, 0, + 1, 1, + 2, 2, + 3, 3, + 4, 4, + 5, 5, + 6, 6, + 7, 7, + 8, 8, + 9, 9, + 10, 10, + 11, 11, + 12, 12, + 13, 13 +] + +zdeflate_dist_base: list[t.CInt, 30] = [ + 1, 2, 3, 4, + 5, 7, + 9, 13, + 17, 25, + 33, 49, + 65, 97, + 129, 193, + 257, 385, + 513, 769, + 1025, 1537, + 2049, 3073, + 4097, 6145, + 8193, 12289, + 16385, 24577 +] + +zdeflate_codelen_order: list[int, 19] = [ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +] + +# ============================================================ +# Bit writer - writes bits LSB first into a byte buffer +# ============================================================ +@t.Object +class zbit_writer: + buf: BYTE | t.CPtr + cap: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def __init__(self): + self.cap = 4096 + self.buf = BYTEPTR(malloc(self.cap)) + memset(self.buf, 0, self.cap) + self.byte_pos = 0 + self.bit_pos = 0 + + def ensure(self, need: t.CSizeT): + while self.byte_pos + need + 4 >= self.cap: + new_cap: t.CSizeT = self.cap * 2 + new_buf: BYTE | t.CPtr = BYTEPTR(realloc(self.buf, new_cap)) + if not new_buf: return + memset(new_buf + self.cap, 0, new_cap - self.cap) + self.buf = new_buf + self.cap = new_cap + + def write_bits(self, value: UINT, nbits: t.CInt): + self.ensure((nbits + 7) / 8 + 1) + for i in range(nbits): + if value & (UINT(1) << i): + self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + + def write_bits_rev(self, code: UINT, nbits: t.CInt): + self.ensure((nbits + 7) / 8 + 1) + for i in range(nbits - 1, -1, -1): + if code & (UINT(1) << i): + self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + + def stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + self.write_bits(1 if final else 0, 1) + self.write_bits(0, 2) + self.align() + + pos: t.CSizeT = 0 + while pos < length: + block_length: t.CSizeT = length - pos + if block_length > 65535: + block_length = 65535 + n: t.CUInt16T = t.CUInt16T(block_length) + ncomp: t.CUInt16T = ~n + self.write_bits(n, 16) + self.write_bits(ncomp, 16) + + self.ensure(block_length) + i: t.CSizeT = 0 + for i in range(block_length): + self.buf[self.byte_pos] = data[pos + i] + self.byte_pos += 1 + pos += block_length + if pos < length: + self.write_bits(0, 1) + self.write_bits(0, 2) + self.align() + + def write_zlib_header(self, wbits: t.CInt, level: t.CInt): + cinfo: t.CInt = wbits - 8 + if cinfo < 1: cinfo = 1 + if cinfo > 7: cinfo = 7 + cmf: t.CUnsignedChar = t.CUnsignedChar((cinfo << 4) | 8) + + flevel: t.CInt = 0 + if level >= 5: flevel = 3 + elif level >= 3: flevel = 1 + + flg: t.CUnsignedChar = t.CUnsignedChar(flevel << 6) + flg |= t.CUnsignedChar(31 - (cmf * 256 + flg) % 31) + + self.buf[self.byte_pos + 0] = cmf + self.buf[self.byte_pos + 1] = flg + self.byte_pos += 2 + + + def write_gzip_header(self): + self.buf[self.byte_pos + 0] = 0x1F + self.buf[self.byte_pos + 1] = 0x8B + self.buf[self.byte_pos + 2] = 0x08 + self.buf[self.byte_pos + 3] = 0x00 + self.buf[self.byte_pos + 4] = 0x00 + self.buf[self.byte_pos + 5] = 0x00 + self.buf[self.byte_pos + 6] = 0x00 + self.buf[self.byte_pos + 7] = 0x00 + self.buf[self.byte_pos + 8] = 0x00 + self.buf[self.byte_pos + 9] = 0xFF + self.byte_pos += 10 + + def align(self): + if self.bit_pos > 0: + self.bit_pos = 0 + self.byte_pos += 1 + + def total(self) -> t.CSizeT: + return self.byte_pos + (1 if (self.bit_pos > 0) else 0) + + def free(self): + free(self.buf) + self.buf = None + self.cap = 0 + self.byte_pos = 0 + self.bit_pos = 0 + + def __del__(self): + self.free() + +# ============================================================ +# Bit reader - reads bits LSB first from a byte buffer +# ============================================================ +@t.Object +class zbit_reader: + buf: BYTE | t.CPtr + length: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def init(self, buf: BYTE | t.CPtr, length: t.CSizeT): + self.buf = buf + self.length = length + self.byte_pos = 0 + self.bit_pos = 0 + + def read_bits(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits): + if self.byte_pos >= self.length: return -1 + if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): + val |= (UINT(1) << i) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + def read_bits_rev(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits - 1, 0, -1): + if self.byte_pos >= self.length: return -1 + if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): + val |= (UINT(1) << i) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + def align(self): + if self.bit_pos > 0: + self.bit_pos = 0 + self.byte_pos += 1 + +# ============================================================ +# Memory allocation helper for bare metal +# Can be replaced with custom allocator +# ============================================================ +def zdef_alloc(n: t.CSizeT) -> VOIDPTR: + return malloc(n) +def zdef_free(p: VOIDPTR): + free(p) diff --git a/Test/TestProject/App/__zlib/zdeflate.py b/Test/TestProject/App/__zlib/zdeflate.py new file mode 100644 index 0000000..f9c5328 --- /dev/null +++ b/Test/TestProject/App/__zlib/zdeflate.py @@ -0,0 +1,431 @@ +from stdint import * +import zchecksum +import zhuff +import zdef +import string +import stdio +import t, c + + +@t.Object +class zdeflate_stream: + writer: zdef.zbit_writer + window: BYTE | t.CPtr + window_pos: t.CInt + window_size: t.CInt + hash_head: t.CInt | t.CPtr + hash_prev: t.CInt | t.CPtr + level: t.CInt + strategy: t.CInt + wbits: t.CInt + is_finished: t.CInt + adler: t.CUInt32T + + def find_match(self, data: BYTE | t.CPtr, data_len: t.CSizeT, + pos: t.CSizeT, best_dist: t.CInt | t.CPtr) -> t.CInt: + if pos + 2 >= data_len: return 0 + h: t.CUnsignedInt = zdeflate_hash(data + pos) + chain: t.CInt = self.hash_head[h] + best_len: t.CInt = zdef.ZDEFLATE_MIN_MATCH - 1 + c.Set(c.Deref(best_dist), 0) + max_chain: t.CInt = 128 if (self.level >= 5) else (32 if (self.level >= 2) else 4) + limit: t.CInt = (1 << self.wbits) if (self.wbits > 0) else zdef.ZDEFLATE_WINDOW_SIZE + if limit > zdef.ZDEFLATE_WINDOW_SIZE: + limit = zdef.ZDEFLATE_WINDOW_SIZE + attempts: t.CInt = 0 + while chain >= 0 and attempts < max_chain: + dist: t.CInt = t.CInt(pos) - chain + if dist <= 0 or dist > limit: break + match_len: t.CInt = 0 + max_len: t.CInt = t.CInt(data_len - pos) + if max_len > zdef.ZDEFLATE_MAX_MATCH: + max_len = zdef.ZDEFLATE_MAX_MATCH + while match_len < max_len and data[pos + match_len] == data[chain + match_len]: + match_len += 1 + if match_len > best_len: + best_len = match_len + c.Set(c.Deref(best_dist), dist) + if best_len >= zdef.ZDEFLATE_MAX_MATCH: break + chain = self.hash_prev[chain & zdef.ZDEFLATE_WINDOW_MASK] + if chain <= t.CInt(pos) - limit: break + attempts += 1 + return best_len if (best_len >= zdef.ZDEFLATE_MIN_MATCH) else 0 + + def update_hash(self, data: BYTE | t.CPtr, pos: t.CSizeT): + if pos + 2 < pos: return + h: t.CUnsignedInt = zdeflate_hash(data + pos) + self.hash_prev[pos & zdef.ZDEFLATE_WINDOW_MASK] = self.hash_head[h] + self.hash_head[h] = t.CInt(pos) + + def write_fixed_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + dist_tree.build_fixed_dist_tree() + self.writer.write_bits(1 if final else 0, 1) + self.writer.write_bits(1, 2) + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if self.level > 0 and pos + 2 < length: + match_len = self.find_match(data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] + if extra > 0: + self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) + dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) + dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) + for i in range(match_len): + self.update_hash(data, pos + i) + pos += match_len + else: + lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) + self.update_hash(data, pos) + pos += 1 + lit_tree.encode_symbol(256, c.Addr(self.writer)) + + def encode_block_data(self, data: UINT8PTR, length: t.CSizeT, + lit_tree: zhuff.zhuff_tree | t.CPtr, dist_tree: zhuff.zhuff_tree | t.CPtr): + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if self.level > 0 and pos + 2 < length: + match_len = self.find_match(data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] + if extra > 0: + self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) + dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) + dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) + for j in range(match_len): + self.update_hash(data, pos + j) + pos += match_len + else: + lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) + self.update_hash(data, pos) + pos += 1 + lit_tree.encode_symbol(256, c.Addr(self.writer)) + + + def write_dynamic_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + lit_freqs: list[t.CInt, 288] + dist_freqs: list[t.CInt, 32] + zdeflate_count_freqs(lit_freqs, dist_freqs, self, data, length) + hlit: t.CInt = 286 + while hlit > 257 and lit_freqs[hlit - 1] == 0: hlit -= 1 + hdist: t.CInt = 30 + while hdist > 1 and dist_freqs[hdist - 1] == 0: hdist -= 1 + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_codes(lit_freqs, hlit, zdef.ZDEFLATE_MAX_BITS) + dist_tree.build_codes(dist_freqs, hdist, zdef.ZDEFLATE_MAX_BITS) + all_lengths: list[t.CInt, 288 + 32] + for i in range(hlit): all_lengths[i] = lit_tree.codes[i].bits + for i in range(hdist): all_lengths[hlit + i] = dist_tree.codes[i].bits + total_lengths: t.CInt = hlit + hdist + cl_freqs: list[t.CInt, 19] + zdeflate_count_cl_freqs(all_lengths, total_lengths, cl_freqs) + cl_tree = zhuff.zhuff_tree() + cl_tree.build_codes(cl_freqs, 19, 7) + hclen: int = 19 + while hclen > 4 and cl_tree.codes[zdef.zdeflate_codelen_order[hclen - 1]].bits == 0: hclen -= 1 + self.writer.write_bits(1 if final else 0, 1) + self.writer.write_bits(2, 2) + self.writer.write_bits(hlit - 257, 5) + self.writer.write_bits(hdist - 1, 5) + self.writer.write_bits(hclen - 4, 4) + for j in range(hclen): + self.writer.write_bits(cl_tree.codes[zdef.zdeflate_codelen_order[j]].bits, 3) + zdeflate_write_cl_encoded(all_lengths, total_lengths, c.Addr(self.writer), c.Addr(cl_tree)) + self.encode_block_data(data, length, c.Addr(lit_tree), c.Addr(dist_tree)) + + def compress_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + if self.level == 0: + self.write_stored_block(data, length, final) + elif self.strategy == 4 or length < 128: + self.write_fixed_block(data, length, final) + else: + self.write_dynamic_block(data, length, final) + + def write_stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + self.writer.stored_block(data, length, final) + + def compress(self, data: UINT8PTR, length: t.CSizeT, + out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if self.is_finished: return -2 + if not data or length == 0: + c.Set(c.Deref(out), None) + c.Set(c.Deref(out_len), 0) + return 0 + self.adler = zchecksum.zchecksum_adler32(data, length, self.adler) + memset(self.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(self.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + self.compress_block(data, length, 0) + c.Set(c.Deref(out_len), self.writer.total()) + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(c.Deref(out_len)))) + if not c.Deref(out): return -4 + memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) + return 0 + + def flush(self, mode: t.CInt, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if mode == 4: + if not self.is_finished: + if self.level == 0: + self.writer.write_bits(1, 1) + self.writer.write_bits(0, 2) + self.writer.align() + else: + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + self.writer.write_bits(1, 1) + self.writer.write_bits(1, 2) + lit_tree.encode_symbol(256, c.Addr(self.writer)) + self.is_finished = 1 + if self.wbits >= 0: + self.writer.align() + adler: t.CUInt32T = self.adler + self.writer.buf[self.writer.byte_pos + 0] = (adler >> 24) & 0xFF + self.writer.buf[self.writer.byte_pos + 1] = (adler >> 16) & 0xFF + self.writer.buf[self.writer.byte_pos + 2] = (adler >> 8) & 0xFF + self.writer.buf[self.writer.byte_pos + 3] = (adler >> 0) & 0xFF + self.writer.byte_pos += 4 + elif mode == 2 or mode == 3: + self.writer.write_bits(0, 1) + self.writer.write_bits(0, 2) + self.writer.align() + c.Set(c.Deref(out_len), self.writer.total()) + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(c.Deref(out_len)))) + if not c.Deref(out): return -4 + memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) + return 0 + + def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + if not dict: return -2 + use: t.CSizeT = length + if use > zdef.ZDEFLATE_WINDOW_SIZE: + dict += length - zdef.ZDEFLATE_WINDOW_SIZE + use = zdef.ZDEFLATE_WINDOW_SIZE + memcpy(self.window, dict, use) + self.window_size = t.CInt(use) + self.window_pos = t.CInt(use) + self.adler = zchecksum.zchecksum_adler32(dict, length, self.adler) + return 0 + + def copy(self) -> zdeflate_stream | t.CPtr: + z: zdeflate_stream | t.CPtr = zdef.zdef_alloc(zdeflate_stream.__sizeof__()) + if not z: return None + memcpy(z, self, zdeflate_stream.__sizeof__()) + z.writer.buf = BYTEPTR(zdef.zdef_alloc(self.writer.cap)) + if not z.writer.buf: + zdef.zdef_free(z) + return None + memcpy(z.writer.buf, self.writer.buf, self.writer.cap) + z.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) + z.hash_head = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) + z.hash_prev = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) + if not z.window or not z.hash_head or not z.hash_prev: + if z.writer.buf: zdef.zdef_free(z.writer.buf) + zdef.zdef_free(z) + return None + memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + memcpy(z.hash_head, self.hash_head, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memcpy(z.hash_prev, self.hash_prev, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + return z + + def destroy(self): + if self.writer.buf: zdef.zdef_free(self.writer.buf) + if self.window: zdef.zdef_free(self.window) + if self.hash_head: zdef.zdef_free(self.hash_head) + if self.hash_prev: zdef.zdef_free(self.hash_prev) + zdef.zdef_free(self) + + + + +def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR, + s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT): + memset(lit_freqs, 0, 288 * int.__sizeof__()) + memset(dist_freqs, 0, 32 * int.__sizeof__()) + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if s.level > 0 and pos + 2 < length: + match_len = zdeflate_stream.find_match(s, data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_freqs[len_sym] += 1 + dist_freqs[zdeflate_dist_to_symbol(best_dist)] += 1 + for i in range(match_len): + zdeflate_stream.update_hash(s, data, pos + i) + pos += match_len + else: + lit_freqs[data[pos]] += 1 + zdeflate_stream.update_hash(s, data, pos) + pos += 1 + lit_freqs[256] = 1 + + + +def zdeflate_hash(p: BYTE | t.CPtr) -> t.CUnsignedInt: + return (t.CUnsignedInt(p[0]) ^ (t.CUnsignedInt(p[1]) << 5) ^ (t.CUnsignedInt(p[2]) << 10)) & zdef.ZDEFLATE_HASH_MASK + + +def zdeflate_len_to_symbol(length: t.CInt) -> t.CInt: + for i in range(29): + if length <= zdef.zdeflate_len_base[i] + (1 << zdef.zdeflate_len_extra_bits[i]) - 1: + return 257 + i + return 285 + +def zdeflate_dist_to_symbol(dist: t.CInt) -> t.CInt: + for i in range(30): + if dist <= zdef.zdeflate_dist_base[i] + (1 << zdef.zdeflate_dist_extra_bits[i]) - 1: + return i + return 29 + +def zdeflate_count_cl_freqs(all_lengths: INTPTR, total: t.CInt, cl_freqs: INTPTR): + memset(cl_freqs, 0, 19 * int.__sizeof__()) + i: t.CInt = 0 + while i < total: + if all_lengths[i] == 0: + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == 0: run += 1 + while run > 0: + if run >= 11: + count: t.CInt = run + if count > 138: count = 138 + cl_freqs[18] += 1 + run -= count + elif run >= 3: + count: t.CInt = run + if count > 10: count = 10 + cl_freqs[17] += 1 + run -= count + else: + cl_freqs[0] += 1 + run -= 1 + while i < total and all_lengths[i] == 0: i += 1 + else: + cl_freqs[all_lengths[i]] += 1 + val: t.CInt = all_lengths[i] + i += 1 + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == val: run += 1 + while run >= 3: + count: t.CInt = run + if count > 6: count = 6 + cl_freqs[16] += 1 + run -= count + i += run + +def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt, + w: zdef.zbit_writer | t.CPtr, cl_tree: zhuff.zhuff_tree | t.CPtr): + i: t.CInt = 0 + while i < total: + if all_lengths[i] == 0: + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == 0: run += 1 + while run > 0: + if run >= 11: + count: t.CInt = run + if count > 138: count = 138 + cl_tree.encode_symbol(18, w) + w.write_bits(count - 11, 7) + run -= count + elif run >= 3: + count: t.CInt = run + if count > 10: count = 10 + cl_tree.encode_symbol(17, w) + w.write_bits(count - 3, 3) + run -= count + else: + cl_tree.encode_symbol(0, w) + run -= 1 + while i < total and all_lengths[i] == 0: i += 1 + else: + cl_tree.encode_symbol(all_lengths[i], w) + val: t.CInt = all_lengths[i] + i += 1 + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == val: run += 1 + while run >= 3: + count: t.CInt = run + if count > 6: count = 6 + cl_tree.encode_symbol(16, w) + w.write_bits(count - 3, 2) + run -= count + i += run + + + +def zdeflate_create(level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: + s: zdeflate_stream | t.CPtr = zdef.zdef_alloc(zdeflate_stream.__sizeof__()) + if not s: return None + memset(s, 0, zdeflate_stream.__sizeof__()) + s.writer = zdef.zbit_writer() + s.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) + s.hash_head = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) + s.hash_prev = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) + if not s.window or not s.hash_head or not s.hash_prev: + s.destroy() + return None + memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + s.level = level + s.wbits = wbits + s.strategy = strategy + s.is_finished = 0 + s.adler = 1 + if wbits > 0: + s.writer.write_zlib_header(wbits, level) + elif wbits == 0: + s.writer.write_zlib_header(15, level) + return s + + +def zdeflate_one_shot(data: UINT8PTR, length: t.CSizeT, + level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: + s: zdeflate_stream | t.CPtr = zdeflate_create(level, wbits, 8, 0) + if not s: return None + + memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + + s.adler = zchecksum.zchecksum_adler32(data, length, 1) + + if length == 0: + s.writer.write_bits(1, 1) + s.writer.write_bits(1, 2) + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + lit_tree.encode_symbol(256, c.Addr(s.writer)) + else: + s.compress_block(data, length, 1) + + s.is_finished = 1 + + if wbits >= 0: + s.writer.align() + adler: t.CUInt32T = s.adler + s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF + s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF + s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF + s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF + s.writer.byte_pos += 4 + c.Set(c.Deref(out_len), s.writer.total()) + result: UINT8PTR = UINT8PTR(zdef.zdef_alloc(c.Deref(out_len))) + if result: memcpy(result, s.writer.buf, c.Deref(out_len)) + s.destroy() + return result diff --git a/Test/TestProject/App/__zlib/zhuff.py b/Test/TestProject/App/__zlib/zhuff.py new file mode 100644 index 0000000..71c4158 --- /dev/null +++ b/Test/TestProject/App/__zlib/zhuff.py @@ -0,0 +1,353 @@ +#include +from stdint import * +import zdef +import t, c + + +ZHUFF_MAX_CODES: t.CDefine = 288 +ZHUFF_MAX_BITS: t.CDefine = 15 + +class zhuff_code: + code: UINT + bits: t.CInt + +@t.Object +class zhuff_tree: + codes: list[zhuff_code, ZHUFF_MAX_CODES] + count: t.CInt + max_bits: t.CInt + + def __init__(self): + pass + + def build_codes(self, freqs: INTPTR, count: t.CInt, max_bits: t.CInt): + lengths: list[t.CInt, ZHUFF_MAX_CODES] + bl_count: list[t.CInt, ZHUFF_MAX_BITS + 1] + next_code: list[UINT, ZHUFF_MAX_BITS + 1] + self.count = count + self.max_bits = max_bits + self.build_code_lengths(lengths, freqs, count, max_bits) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, max_bits + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + for i in range(count): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def build_fixed_lit_tree(self): + lengths: list[t.CInt, 288] + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + self.get_fixed_lit_lengths(lengths) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(288): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, 9 + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + self.count = 288 + self.max_bits = 9 + for i in range(288): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def build_fixed_dist_tree(self): + lengths: list[t.CInt, 32] + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + self.get_fixed_dist_lengths(lengths) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(32): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, 5 + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + self.count = 32 + self.max_bits = 5 + for i in range(32): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def encode_symbol(self, symbol: int, writer: zdef.zbit_writer | t.CPtr): + if symbol < 0 or symbol >= self.count: + return + if self.codes[symbol].bits == 0: + return + writer.write_bits_rev(self.codes[symbol].code, self.codes[symbol].bits) + + + def build_code_lengths(self, lengths: t.CInt | t.CPtr, freqs: t.CInt | t.CPtr, count: t.CInt, max_bits: t.CInt): + bl_count: list[t.CInt, ZHUFF_MAX_BITS + 2] + sort_count: t.CInt = 0 + memset(bl_count, 0, bl_count.__sizeof__()) + memset(lengths, 0, int.__sizeof__() * count) + for i in range(count): + if freqs[i] > 0: + sort_count += 1 + if sort_count == 0: return + if sort_count == 1: + for i in range(count): + if freqs[i] > 0: + lengths[i] = 1 + return + items: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) + item_freqs: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) + idx: t.CInt = 0 + for i in range(count): + if freqs[i] > 0: + items[idx] = i + item_freqs[idx] = freqs[i] + idx += 1 + for i in range(sort_count): + key_item: t.CInt = items[i] + key_freq: t.CInt = item_freqs[i] + j: t.CInt = i - 1 + while j >= 0 and item_freqs[j] > key_freq: + items[j + 1] = items[j] + item_freqs[j + 1] = item_freqs[j] + j -= 1 + items[j + 1] = key_item + item_freqs[j + 1] = key_freq + parent: INTPTR = INTPTR(zdef.zdef_alloc((sort_count * 2) * int.__sizeof__())) + for i in range(sort_count * 2): + parent[i] = -1 + heap: INTPTR = INTPTR(zdef.zdef_alloc((sort_count + 1) * int.__sizeof__())) + heap_size: t.CInt = 0 + for i in range(sort_count): + heap[heap_size] = i + heap_size += 1 + pos: t.CInt = heap_size - 1 + while pos > 0: + par: t.CInt = (pos - 1) / 2 + if item_freqs[heap[par]] > item_freqs[heap[pos]]: + tmp: t.CInt = heap[par] + heap[par] = heap[pos] + heap[pos] = tmp + pos = par + else: break + combined_freq: INTPTR = INTPTR(zdef.zdef_alloc((sort_count * 2) * int.__sizeof__())) + for i in range(sort_count): + combined_freq[i] = item_freqs[i] + internal: t.CInt = sort_count + while heap_size > 1: + a: t.CInt = heap[0] + heap[0] = heap[heap_size - 1] + heap_size -= 1 + pos: t.CInt = 0 + while True: + left: t.CInt = 2 * pos + 1 + right: t.CInt = 2 * pos + 2 + smallest: t.CInt = pos + if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: + smallest = left + if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: + smallest = right + if smallest != pos: + tmp: t.CInt = heap[pos] + heap[pos] = heap[smallest] + heap[smallest] = tmp + pos = smallest + else: break + b: t.CInt = heap[0] + heap[0] = heap[heap_size - 1] + heap_size -= 1 + pos = 0 + while True: + left: t.CInt = 2 * pos + 1 + right: t.CInt = 2 * pos + 2 + smallest: t.CInt = pos + if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: + smallest = left + if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: + smallest = right + if smallest != pos: + tmp: t.CInt = heap[pos] + heap[pos] = heap[smallest] + heap[smallest] = tmp + pos = smallest + else: break + if internal >= sort_count * 2 - 1: break + combined_freq[internal] = combined_freq[a] + combined_freq[b] + parent[a] = internal + parent[b] = internal + heap[heap_size] = internal + heap_size += 1 + pos = heap_size - 1 + while pos > 0: + par: t.CInt = (pos - 1) / 2 + if combined_freq[heap[par]] > combined_freq[heap[pos]]: + tmp: t.CInt = heap[par] + heap[par] = heap[pos] + heap[pos] = tmp + pos = par + else: break + internal += 1 + for i in range(sort_count): + node: t.CInt = i + length: t.CInt = 0 + while parent[node] >= 0: + length += 1 + node = parent[node] + lengths[items[i]] = length + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + overflow: t.CInt = 0 + for i in range(count): + if lengths[i] > max_bits: + overflow += 1 + bl_count[lengths[i]] -= 1 + lengths[i] = max_bits + bl_count[max_bits] += 1 + while overflow > 0: + bits: t.CInt = max_bits - 1 + while bits > 0 and bl_count[bits] == 0: + bits -= 1 + if bits == 0: break + bl_count[bits] -= 1 + bl_count[bits + 1] += 2 + bl_count[max_bits] -= 1 + overflow -= 2 + sorted_items: INTPTR = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) + si: t.CInt = 0 + for i in range(count): + if freqs[i] > 0: + sorted_items[si] = i + si += 1 + for i in range(si - 1): + for j in range(i + 1, si): + if lengths[sorted_items[i]] < lengths[sorted_items[j]]: + tmp: t.CInt = sorted_items[i] + sorted_items[i] = sorted_items[j] + sorted_items[j] = tmp + sidx: t.CInt = 0 + for bits in range(max_bits, 1, -1): + n: t.CInt = bl_count[bits] + while n > 0 and sidx < si: + lengths[sorted_items[sidx]] = bits + sidx += 1 + n -= 1 + zdef.zdef_free(sorted_items) + zdef.zdef_free(heap) + zdef.zdef_free(parent) + zdef.zdef_free(combined_freq) + zdef.zdef_free(item_freqs) + zdef.zdef_free(items) + + def get_fixed_lit_lengths(self, lengths: INTPTR): + for i in range( 0, 143 + 1): lengths[i] = 8 + for i in range(143 + 1, 255 + 1): lengths[i] = 9 + for i in range(255 + 1, 279 + 1): lengths[i] = 7 + for i in range(279 + 1, 287 + 1): lengths[i] = 8 + + def get_fixed_dist_lengths(self, lengths: INTPTR): + for i in range(32): + lengths[i] = 5 + + def build_tree_from_lengths(self, lengths: INTPTR, count: t.CInt, max_bits: t.CInt): + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + + code: UINT = 0 + next_code[0] = 0 + for bits in range(1, max_bits + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + + self.count = count + self.max_bits = max_bits + for i in range(count): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + +class zhuff_decode_node: + children: list[t.CInt, 2] + symbol: t.CInt + + +@t.Object +class zhuff_decode_tree: + nodes: list[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] + node_count: t.CInt + root: t.CInt + + def __init__(self): + pass + + def build_decode_tree(self, ht: zhuff_tree | t.CPtr): + self.node_count = 1 + self.root = 0 + self.nodes[0].children[0] = -1 + self.nodes[0].children[1] = -1 + self.nodes[0].symbol = -1 + for i in range(ht.count): + if ht.codes[i].bits == 0: continue + node: int = 0 + for bit in range(ht.codes[i].bits - 1, -1, -1): + dir: t.CInt = (ht.codes[i].code >> bit) & 1 + if bit > 0: + # Internal node: traverse or create + if self.nodes[node].children[dir] == -1: + new_node: int = self.node_count + self.node_count += 1 + self.nodes[new_node].children[0] = -1 + self.nodes[new_node].children[1] = -1 + self.nodes[new_node].symbol = -1 + self.nodes[node].children[dir] = new_node + node = self.nodes[node].children[dir] + else: + # Leaf: bit 0 - set symbol on the child + if self.nodes[node].children[dir] == -1: + leaf: int = self.node_count + self.node_count += 1 + self.nodes[leaf].children[0] = -1 + self.nodes[leaf].children[1] = -1 + self.nodes[leaf].symbol = i + self.nodes[node].children[dir] = leaf + else: + self.nodes[self.nodes[node].children[dir]].symbol = i + + def decode_symbol(self, reader: zdef.zbit_reader | t.CPtr) -> t.CInt: + node: int = self.root + while self.nodes[node].symbol == -1: + bit: t.CUnsignedInt + if reader.read_bits(1, c.Addr(bit)) != 0: return -1 + dir: t.CInt = t.CInt(bit) + if self.nodes[node].children[dir] == -1: return -1 + node = self.nodes[node].children[dir] + return self.nodes[node].symbol diff --git a/Test/TestProject/App/__zlib/zinflate.py b/Test/TestProject/App/__zlib/zinflate.py new file mode 100644 index 0000000..efdcded --- /dev/null +++ b/Test/TestProject/App/__zlib/zinflate.py @@ -0,0 +1,454 @@ +from stdint import * +import zinflate +import zchecksum +import zdef +import zhuff +import string +import t, c + + +@t.Object +class zinflate_stream: + reader: zdef.zbit_reader + + window: BYTEPTR + window_pos: t.CInt + window_size: t.CInt + + wbits: t.CInt + is_finished: t.CInt + is_initialized: t.CInt + + header_parsed: t.CInt + is_gzip: t.CInt + + adler: t.CUInt32T + crc: t.CUInt32T + + output: BYTEPTR + output_len: t.CSizeT + output_cap: t.CSizeT + + input_data: t.CConst | BYTEPTR + input_len: t.CSizeT + input_pos: t.CSizeT + + max_length: t.CSizeT + + def __init__(self): + pass + + def output_byte(self, byte: BYTE): + if self.max_length > 0 and self.output_len >= self.max_length: return + + if self.output_len >= self.output_cap: + new_cap: t.CSizeT = self.output_cap * 2 + if new_cap < 256: new_cap = 256 + new_buf: BYTEPTR = BYTEPTR(zdef.zdef_alloc(new_cap)) + if not new_buf: return + memcpy(new_buf, self.output, self.output_len) + zdef.zdef_free(self.output) + self.output = new_buf + self.output_cap = new_cap + self.output[self.output_len] = byte + self.output_len += 1 + self.window[self.window_pos & (zdef.ZDEFLATE_WINDOW_SIZE - 1)] = byte + self.window_pos += 1 + + + def parse_header(self) -> t.CInt: + if self.header_parsed: return 0 + if self.wbits < 0: + self.header_parsed = 1 + self.is_gzip = 0 + return 0 + if self.input_pos + 2 > self.input_len: return -3 + b0: BYTE = self.input_data[self.input_pos] + b1: BYTE = self.input_data[self.input_pos + 1] + if b0 == 0x1F and b1 == 0x8B: + self.is_gzip = 1 + if self.input_pos + 10 > self.input_len: return -3 + self.input_pos += 10 + flg: BYTE = self.input_data[self.input_pos - 6] + if flg & 0x04: + if self.input_pos + 2 > self.input_len: return -3 + xlen: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) + self.input_pos += 2 + xlen + if flg & 0x08: + while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 + self.input_pos += 1 + if flg & 0x10: + while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 + self.input_pos += 1 + if flg & 0x02: + self.input_pos += 2 + if self.input_pos > self.input_len: return -3 + else: + self.is_gzip = 0 + if (b0 * 256 + b1) % 31 != 0: return -3 + cm: t.CInt = b0 & 0x0F + if cm != 8: return -3 + self.input_pos += 2 + self.header_parsed = 1 + return 0 + + + def read_bits_from_input(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits): + if self.input_pos >= self.input_len: return -3 + if self.input_data[self.input_pos] & (UINT(1) << (self.reader.bit_pos)): + val |= (UINT(1) << i) + self.reader.bit_pos += 1 + if self.reader.bit_pos == 8: + self.reader.bit_pos = 0 + self.input_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + + def read_huffman(self, dt: zhuff.zhuff_decode_tree | t.CPtr) -> t.CInt: + node: int = dt.root + while dt.nodes[node].symbol == -1: + bit: UINT + if self.read_bits_from_input(1, c.Addr(bit)) != 0: return -1 + dir: int = t.CInt(bit) + if dt.nodes[node].children[dir] == -1: return -3 + node = dt.nodes[node].children[dir] + return dt.nodes[node].symbol + + def inflate_block_stored(self) -> t.CInt: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 4 > self.input_len: return -3 + length: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) + nlen: UINT = self.input_data[self.input_pos + 2] | (self.input_data[self.input_pos + 3] << 8) + self.input_pos += 4 + if (length ^ nlen) != 0xFFFF: return -3 + if self.input_pos + length > self.input_len: return -3 + i: t.CUnsignedInt + for i in range(length): + self.output_byte(self.input_data[self.input_pos]) + self.input_pos += 1 + return 0 + + + def inflate_block_fixed(self) -> t.CInt: + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + dist_tree.build_fixed_dist_tree() + + lit_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(zhuff.zhuff_decode_tree.__sizeof__()) + dist_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(zhuff.zhuff_decode_tree.__sizeof__()) + if not lit_dt or not dist_dt: + if lit_dt: zdef.zdef_free(lit_dt) + if dist_dt: zdef.zdef_free(dist_dt) + return -4 + memset(lit_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + memset(dist_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + lit_dt.build_decode_tree(c.Addr(lit_tree)) + dist_dt.build_decode_tree(c.Addr(dist_tree)) + + result: t.CInt = 0 + while True: + if self.max_length > 0 and self.output_len >= self.max_length: break + + sym: t.CInt = self.read_huffman(lit_dt) + if sym < 0: + result = -3 + break + if sym == 256: break + if sym < 256: + self.output_byte(BYTE(sym)) + else: + len_idx: t.CInt = sym - 257 + if len_idx < 0 or len_idx >= 29: + result = -3 + break + length: t.CInt = zdef.zdeflate_len_base[len_idx] + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: + result = -3 + break + length += extra_val + + dist_sym: t.CInt = self.read_huffman(dist_dt) + if dist_sym < 0 or dist_sym >= 30: + result = -3 + break + dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: + result = -3 + break + dist += extra_val + + for i in range(length): + if self.max_length > 0 and self.output_len >= self.max_length: break + src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) + byte: BYTE = self.window[src_pos] + self.output_byte(byte) + + zdef.zdef_free(lit_dt) + zdef.zdef_free(dist_dt) + return result + + + def inflate_block_dynamic(self) -> t.CInt: + hlit_val: UINT + hdist_val: UINT + hclen_val: UINT + if self.read_bits_from_input(5, c.Addr(hlit_val)) != 0: return -3 + if self.read_bits_from_input(5, c.Addr(hdist_val)) != 0: return -3 + if self.read_bits_from_input(4, c.Addr(hclen_val)) != 0: return -3 + + hlit: t.CInt = t.CInt(hlit_val) + 257 + hdist: t.CInt = t.CInt(hdist_val) + 1 + hclen: t.CInt = t.CInt(hclen_val) + 4 + + cl_lengths: list[t.CInt, 19] + memset(cl_lengths, 0, cl_lengths.__sizeof__()) + for i in range(hclen): + len_val: UINT + if self.read_bits_from_input(3, c.Addr(len_val)) != 0: return -3 + cl_lengths[zdef.zdeflate_codelen_order[i]] = t.CInt(len_val) + + cl_tree = zhuff.zhuff_tree() + cl_tree.build_tree_from_lengths(cl_lengths, 19, 7) + + cl_dt = zhuff.zhuff_decode_tree() + cl_dt.build_decode_tree(c.Addr(cl_tree)) + + total: t.CInt = hlit + hdist + all_lengths: t.CInt | t.CPtr = zdef.zdef_alloc(total * int.__sizeof__()) + if not all_lengths: return -4 + + idx: t.CInt = 0 + while idx < total: + sym: t.CInt = self.read_huffman(c.Addr(cl_dt)) + if sym < 0 or sym > 18: + zdef.zdef_free(all_lengths) + return -3 + if sym < 16: + all_lengths[idx] = sym + idx += 1 + elif sym == 16: + rep: UINT + if self.read_bits_from_input(2, c.Addr(rep)) != 0: + zdef.zdef_free(all_lengths) + return -3 + rep += 3 + if idx == 0 or idx + rep > total: + zdef.zdef_free(all_lengths) + return -3 + prev: t.CInt = all_lengths[idx - 1] + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = prev + idx += 1 + elif sym == 17: + rep: t.CUnsignedInt + if self.read_bits_from_input(3, c.Addr(rep)) != 0: + zdef.zdef_free(all_lengths) + return -3 + rep += 3 + if idx + rep > total: + zdef.zdef_free(all_lengths) + return -3 + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = 0 + idx += 1 + else: + rep: t.CUnsignedInt + if self.read_bits_from_input(7, c.Addr(rep)) != 0: + zdef.zdef_free(all_lengths) + return -3 + rep += 11 + if idx + rep > total: + zdef.zdef_free(all_lengths) + return -3 + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = 0 + idx += 1 + + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + + lit_lengths: list[t.CInt, 288] + memset(lit_lengths, 0, lit_lengths.__sizeof__()) + for i in range(hlit): + lit_lengths[i] = all_lengths[i] + lit_tree.build_tree_from_lengths(lit_lengths, hlit, zdef.ZDEFLATE_MAX_BITS) + + dist_lengths: list[t.CInt, 32] + memset(dist_lengths, 0, dist_lengths.__sizeof__()) + for i in range(hdist): + dist_lengths[i] = all_lengths[hlit + i] + dist_tree.build_tree_from_lengths(dist_lengths, hdist, zdef.ZDEFLATE_MAX_BITS) + + zdef.zdef_free(all_lengths) + + lit_dt = zhuff.zhuff_decode_tree() + dist_dt = zhuff.zhuff_decode_tree() + lit_dt.build_decode_tree(c.Addr(lit_tree)) + dist_dt.build_decode_tree(c.Addr(dist_tree)) + + while True: + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + sym: t.CInt = self.read_huffman(c.Addr(lit_dt)) + if sym < 0: return -3 + if sym == 256: return 0 + if sym < 256: + self.output_byte(BYTE(sym)) + else: + len_idx: t.CInt = sym - 257 + if len_idx < 0 or len_idx >= 29: return -3 + length: t.CInt = zdef.zdeflate_len_base[len_idx] + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 + length += extra_val + dist_sym: t.CInt = self.read_huffman(c.Addr(dist_dt)) + if dist_sym < 0 or dist_sym >= 30: return -3 + dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 + dist += extra_val + for i in range(length): + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) + byte: BYTE = self.window[src_pos] + self.output_byte(byte) + + def inflate_stream(self) -> t.CInt: + err: t.CInt = self.parse_header() + if err != 0: return err + while not self.is_finished: + bfinal_val: UINT + btype_val: UINT + if self.read_bits_from_input(1, c.Addr(bfinal_val)) != 0: return -3 + if self.read_bits_from_input(2, c.Addr(btype_val)) != 0: return -3 + bfinal: t.CInt = t.CInt(bfinal_val) + btype: t.CInt = t.CInt(btype_val) + if btype == 0: + err = self.inflate_block_stored() + elif btype == 1: + err = self.inflate_block_fixed() + elif btype == 2: + err = self.inflate_block_dynamic() + else: + return -3 + if err != 0: return err + if bfinal: self.is_finished = 1 + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + if self.is_gzip: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 8 <= self.input_len: + self.crc = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 0) | + (t.CUInt32T(self.input_data[self.input_pos + 1]) << 8) | + (t.CUInt32T(self.input_data[self.input_pos + 2]) << 16) | + (t.CUInt32T(self.input_data[self.input_pos + 3]) << 24)) + self.input_pos += 8 + elif self.wbits >= 0: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 4 <= self.input_len: + self.adler = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 24) | + (t.CUInt32T(self.input_data[self.input_pos + 1]) << 16) | + (t.CUInt32T(self.input_data[self.input_pos + 2]) << 8) | + (t.CUInt32T(self.input_data[self.input_pos + 3]) << 0)) + self.input_pos += 4 + return 0 + + def decompress(self, data: UINT8PTR, length: t.CSizeT, + max_length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if not self.is_initialized: return -2 + self.input_data = data + self.input_len = length + self.input_pos = 0 + self.reader.bit_pos = 0 + self.output_len = 0 + self.max_length = max_length + err: t.CInt = self.inflate_stream() + if err != 0: return err + c.Set(c.Deref(out_len), self.output_len) + if self.output_len == 0: + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(1))) + else: + dst: UINT8PTR = UINT8PTR(zdef.zdef_alloc(self.output_len)) + c.Set(c.Deref(out), dst) + if dst: + memcpy(dst, self.output, self.output_len) + return 0 + + def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + if not dict: return -2 + use: t.CSizeT = length + if use > zdef.ZDEFLATE_WINDOW_SIZE: + dict += length - zdef.ZDEFLATE_WINDOW_SIZE + use = zdef.ZDEFLATE_WINDOW_SIZE + memcpy(self.window, dict, use) + self.window_pos = t.CInt(use) + return 0 + + def copy(self) -> zinflate_stream | t.CPtr: + z: zinflate_stream | t.CPtr = zdef.zdef_alloc(zinflate_stream.__sizeof__()) + if not z: return None + memcpy(z, self, zinflate_stream.__sizeof__()) + z.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) + z.output = BYTEPTR(zdef.zdef_alloc(self.output_cap)) + if not z.window or not z.output: + zinflate_stream.destroy(z) + return None + memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + memcpy(z.output, self.output, self.output_cap) + return z + + def destroy(self): + if not self: return + if self.window: zdef.zdef_free(self.window) + if self.output: zdef.zdef_free(self.output) + zdef.zdef_free(self) + + +def zinflate_one_shot(data: UINT8PTR, length: t.CSizeT, + wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: + s: zinflate_stream | t.CPtr = zinflate_create(wbits) + if not s: return None + out: t.CUInt8T | t.CPtr = None + err: t.CInt = s.decompress(data, length, 0, c.Addr(out), out_len) + s.destroy() + if err != 0: return None + return out + + +def zinflate_create(wbits: t.CInt) -> zinflate_stream | t.CPtr: + s: zinflate_stream | t.CPtr = zdef.zdef_alloc(zinflate_stream.__sizeof__()) + if not s: return None + memset(s, 0, zinflate_stream.__sizeof__()) + s.wbits = wbits + s.is_initialized = 1 + s.adler = 1 + s.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) + s.output = BYTEPTR(zdef.zdef_alloc(256)) + s.output_cap = 256 + s.output_len = 0 + s.max_length = 0 + if not s.window or not s.output: + s.destroy() + return None + return s diff --git a/Test/TestProject/App/config.py b/Test/TestProject/App/config.py new file mode 100644 index 0000000..5ead5bc --- /dev/null +++ b/Test/TestProject/App/config.py @@ -0,0 +1,24 @@ +import stdint +import t, c + + +A: t.CChar | t.CPtr = "你好" + +class BIT_TEST(t.Object): + a: t.CInt | t.Bit(1) + b: t.CInt | t.Bit(1) + c: t.CInt | t.Bit(1) + d: t.CInt | t.Bit(5) + +class OOP_TEST(t.Object): + a: t.CInt + def __init__(self): + self.a = 0 + def __call__(self) -> stdint.UINT: + return 123 + +class ENUM_TEST(t.CEnum): + A: t.State = 0 + B: t.State + C: t.State + Len: t.State diff --git a/Test/TestProject/App/main.py b/Test/TestProject/App/main.py new file mode 100644 index 0000000..514fe71 --- /dev/null +++ b/Test/TestProject/App/main.py @@ -0,0 +1,23 @@ +from stdint import * +import w32.win32console +import config +import HASHLIB +import BINASCII +import zlib.pyzlib as zp +import test_zlib as tpz +import test_numpy as tn + +import t, c + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + print(zp.runtime_version()) + tpz.main123456() + + tn.test_numpy_main() + + print("END") + diff --git a/Test/TestProject/App/test_numpy.py b/Test/TestProject/App/test_numpy.py new file mode 100644 index 0000000..f138c07 --- /dev/null +++ b/Test/TestProject/App/test_numpy.py @@ -0,0 +1,1087 @@ +from stdint import * +import numpy +from stdio import printf +from stdlib import calloc, free +import string +import vipermath +import mpool +import t, c + +# ============================================================ +# Constants +# ============================================================ +EPS: t.CDouble = t.CDouble(1e-9) +EPS_LOOSE: t.CDouble = t.CDouble(1e-5) +SIMD_BLOCK: t.CSizeT = 4 + +# ============================================================ +# Global state +# ============================================================ +arena: t.CUInt8T | t.CPtr = None +pool: mpool.MPool | t.CPtr = None + +test_passed: t.CInt = 0 +test_failed: t.CInt = 0 + +# ============================================================ +# Global check function +# ============================================================ +def check(name: str, condition: t.CInt, detail: str): + global test_passed, test_failed + if condition: + test_passed += 1 + printf(" [PASS] %s\n", name) + else: + test_failed += 1 + printf(" [FAIL] %s -- %s\n", name, detail if detail else "") + + +# ============================================================ +# Approximate comparison (top-level, uses vipermath.fabs) +# ============================================================ +def approx_eq(a: t.CDouble, b: t.CDouble) -> t.CInt: + d: t.CDouble = a - b + if d < t.CDouble(0.0): + d = t.CDouble(0.0) - d + if d < EPS: + return 1 + return 0 + +def approx_loose(a: t.CDouble, b: t.CDouble) -> t.CInt: + d: t.CDouble = a - b + if d < t.CDouble(0.0): + d = t.CDouble(0.0) - d + if d < EPS_LOOSE: + return 1 + return 0 + + +# ============================================================ +# Section headers +# ============================================================ +def section_header(title: str): + printf("\n+-- %s --+\n", title) + +def section_footer(): + printf("+--------------------------------------------+\n") + + +# ============================================================ +# Utility: quick array creation +# ============================================================ +def vec4(p: mpool.MPool | t.CPtr, v0: t.CDouble, v1: t.CDouble, v2: t.CDouble, v3: t.CDouble) -> numpy.ndarray | t.CPtr: + a: numpy.ndarray | t.CPtr = numpy.zeros(p, 4) + a.data[0] = v0; a.data[1] = v1; a.data[2] = v2; a.data[3] = v3 + return a + +def vec3(p: mpool.MPool | t.CPtr, v0: t.CDouble, v1: t.CDouble, v2: t.CDouble) -> numpy.ndarray | t.CPtr: + a: numpy.ndarray | t.CPtr = numpy.zeros(p, 3) + a.data[0] = v0; a.data[1] = v1; a.data[2] = v2 + return a + +def vec2(p: mpool.MPool | t.CPtr, v0: t.CDouble, v1: t.CDouble) -> numpy.ndarray | t.CPtr: + a: numpy.ndarray | t.CPtr = numpy.zeros(p, 2) + a.data[0] = v0; a.data[1] = v1 + return a + + +# ============================================================ +# 1. Array creation +# ============================================================ +def test_zeros_ones(): + section_header("zeros / ones / full") + + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 5) + check("zeros not None", a != None, "zeros returned None") + check("zeros size == 5", a.size == 5, "size mismatch") + check("zeros [0]==0", a.data[0] == t.CDouble(0.0), "not zero") + check("zeros [4]==0", a.data[4] == t.CDouble(0.0), "not zero") + + b: numpy.ndarray | t.CPtr = numpy.ones(pool, 4) + check("ones not None", b != None, "ones returned None") + check("ones [0]==1", b.data[0] == t.CDouble(1.0), "not one") + check("ones [3]==1", b.data[3] == t.CDouble(1.0), "not one") + + c: numpy.ndarray | t.CPtr = numpy.full(pool, 3, t.CDouble(7.5)) + check("full not None", c != None, "full returned None") + check("full value", c.data[0] == t.CDouble(7.5), "value mismatch") + + a.delete() + b.delete() + c.delete() + section_footer() + + +def test_arange_linspace(): + section_header("arange / linspace") + + a: numpy.ndarray | t.CPtr = numpy.arange(pool, t.CDouble(0.0), t.CDouble(5.0), t.CDouble(1.0)) + check("arange not None", a != None, "arange returned None") + check("arange size == 5", a.size == 5, "size mismatch") + check("arange [0]==0", approx_eq(a.data[0], t.CDouble(0.0)), "mismatch") + check("arange [4]==4", approx_eq(a.data[4], t.CDouble(4.0)), "mismatch") + + b: numpy.ndarray | t.CPtr = numpy.linspace(pool, t.CDouble(0.0), t.CDouble(1.0), 5) + check("linspace not None", b != None, "linspace returned None") + check("linspace size == 5", b.size == 5, "size mismatch") + check("linspace [0]==0", approx_eq(b.data[0], t.CDouble(0.0)), "mismatch") + check("linspace [4]==1", approx_eq(b.data[4], t.CDouble(1.0)), "mismatch") + + a.delete() + b.delete() + section_footer() + + +def test_eye_diag(): + section_header("eye / diag") + + e: numpy.ndarray | t.CPtr = numpy.eye(pool, 3) + check("eye not None", e != None, "eye returned None") + check("eye ndim == 2", e.ndim == 2, "ndim mismatch") + check("eye [0,0]==1", e.at2d(0, 0) == t.CDouble(1.0), "mismatch") + check("eye [0,1]==0", e.at2d(0, 1) == t.CDouble(0.0), "mismatch") + check("eye [1,1]==1", e.at2d(1, 1) == t.CDouble(1.0), "mismatch") + + vals: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + d: numpy.ndarray | t.CPtr = numpy.diag(pool, vals) + check("diag not None", d != None, "diag returned None") + check("diag [0,0]==1", d.at2d(0, 0) == t.CDouble(1.0), "mismatch") + check("diag [1,1]==2", d.at2d(1, 1) == t.CDouble(2.0), "mismatch") + check("diag [2,2]==3", d.at2d(2, 2) == t.CDouble(3.0), "mismatch") + + e.delete() + vals.delete() + d.delete() + section_footer() + + +# ============================================================ +# 2. Methods +# ============================================================ +def test_sum_mean_min_max(): + section_header("sum / mean / min / max / argmax / argmin") + + a: numpy.ndarray | t.CPtr = numpy.arange(pool, t.CDouble(1.0), t.CDouble(6.0), t.CDouble(1.0)) + check("sum == 15", approx_eq(a.sum(), t.CDouble(15.0)), "mismatch") + check("mean == 3", approx_eq(a.mean(), t.CDouble(3.0)), "mismatch") + check("min == 1", approx_eq(a.min(), t.CDouble(1.0)), "mismatch") + check("max == 5", approx_eq(a.max(), t.CDouble(5.0)), "mismatch") + check("argmax == 4", a.argmax() == 4, "mismatch") + check("argmin == 0", a.argmin() == 0, "mismatch") + + a.delete() + section_footer() + + +def test_fill_copy(): + section_header("fill / copy") + + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 3) + a.fill(t.CDouble(9.0)) + check("fill [0]==9", a.data[0] == t.CDouble(9.0), "mismatch") + check("fill [2]==9", a.data[2] == t.CDouble(9.0), "mismatch") + + b: numpy.ndarray | t.CPtr = a.copy() + check("copy not None", b != None, "copy returned None") + check("copy [0]==9", b.data[0] == t.CDouble(9.0), "mismatch") + + b.data[0] = t.CDouble(0.0) + check("copy is independent", a.data[0] == t.CDouble(9.0), "copy not independent") + + a.delete() + b.delete() + section_footer() + + +# ============================================================ +# 3. Operator overloading +# ============================================================ +def test_add_sub_mul_div(): + section_header("__add__ / __sub__ / __mul__ / __truediv__") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + b: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(4.0), t.CDouble(5.0), t.CDouble(6.0)) + + c_add: numpy.ndarray | t.CPtr = a + b + check("a+b not None", c_add != None, "add returned None") + check("a+b [0]==5", c_add.data[0] == t.CDouble(5.0), "mismatch") + check("a+b [2]==9", c_add.data[2] == t.CDouble(9.0), "mismatch") + + c_sub: numpy.ndarray | t.CPtr = a - b + check("a-b [0]==-3", c_sub.data[0] == t.CDouble(-3.0), "mismatch") + + c_mul: numpy.ndarray | t.CPtr = a * b + check("a*b [1]==10", c_mul.data[1] == t.CDouble(10.0), "mismatch") + + c_div: numpy.ndarray | t.CPtr = b / a + check("b/a [0]==4", c_div.data[0] == t.CDouble(4.0), "mismatch") + check("b/a [2]==2", c_div.data[2] == t.CDouble(2.0), "mismatch") + + a.delete() + b.delete() + c_add.delete() + c_sub.delete() + c_mul.delete() + c_div.delete() + section_footer() + + +def test_neg(): + section_header("__neg__") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(-2.0), t.CDouble(3.0)) + neg_a: numpy.ndarray | t.CPtr = -a + check("neg not None", neg_a != None, "neg returned None") + check("neg [0]==-1", neg_a.data[0] == t.CDouble(-1.0), "mismatch") + check("neg [1]==2", neg_a.data[1] == t.CDouble(2.0), "mismatch") + + a.delete() + neg_a.delete() + section_footer() + + +def test_len(): + section_header("__len__") + + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 10) + check("len == 10", len(a) == 10, "mismatch") + + a.delete() + section_footer() + + +# ============================================================ +# 4. Scalar operations +# ============================================================ +def test_scalar_ops(): + section_header("add_scalar / mul_scalar / sub_scalar / div_scalar") + + a: numpy.ndarray | t.CPtr = numpy.ones(pool, 3) + + r1: numpy.ndarray | t.CPtr = numpy.add_scalar(a, t.CDouble(2.0)) + check("add_scalar [0]==3", r1.data[0] == t.CDouble(3.0), "mismatch") + + r2: numpy.ndarray | t.CPtr = numpy.mul_scalar(a, t.CDouble(5.0)) + check("mul_scalar [0]==5", r2.data[0] == t.CDouble(5.0), "mismatch") + + r3: numpy.ndarray | t.CPtr = numpy.sub_scalar(a, t.CDouble(0.5)) + check("sub_scalar [0]==0.5", r3.data[0] == t.CDouble(0.5), "mismatch") + + r4: numpy.ndarray | t.CPtr = numpy.div_scalar(a, t.CDouble(2.0)) + check("div_scalar [0]==0.5", r4.data[0] == t.CDouble(0.5), "mismatch") + + a.delete() + r1.delete() + r2.delete() + r3.delete() + r4.delete() + section_footer() + + +# ============================================================ +# 5. Math functions +# ============================================================ +def test_math_funcs(): + section_header("np_abs / np_sqrt / np_pow") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(4.0), t.CDouble(9.0)) + + r_sqrt: numpy.ndarray | t.CPtr = numpy.np_sqrt(a) + check("sqrt [0]==1", approx_eq(r_sqrt.data[0], t.CDouble(1.0)), "mismatch") + check("sqrt [1]==2", approx_eq(r_sqrt.data[1], t.CDouble(2.0)), "mismatch") + check("sqrt [2]==3", approx_eq(r_sqrt.data[2], t.CDouble(3.0)), "mismatch") + + b: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(-1.0), t.CDouble(-4.0), t.CDouble(9.0)) + r_abs: numpy.ndarray | t.CPtr = numpy.np_abs(b) + check("abs [0]==1", approx_eq(r_abs.data[0], t.CDouble(1.0)), "mismatch") + check("abs [1]==4", approx_eq(r_abs.data[1], t.CDouble(4.0)), "mismatch") + + c: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + r_pow: numpy.ndarray | t.CPtr = numpy.np_pow(c, t.CDouble(2.0)) + check("pow [0]==1", approx_eq(r_pow.data[0], t.CDouble(1.0)), "mismatch") + check("pow [1]==4", approx_eq(r_pow.data[1], t.CDouble(4.0)), "mismatch") + check("pow [2]==9", approx_eq(r_pow.data[2], t.CDouble(9.0)), "mismatch") + + a.delete() + b.delete() + c.delete() + r_sqrt.delete() + r_abs.delete() + r_pow.delete() + section_footer() + + +# ============================================================ +# 6. Matrix operations +# ============================================================ +def test_matmul(): + section_header("matmul") + + # [1,2;3,4] x [5,6;7,8] = [19,22;43,50] + a: numpy.ndarray | t.CPtr = numpy.empty2d(pool, 2, 2) + a.set2d(0, 0, t.CDouble(1.0)); a.set2d(0, 1, t.CDouble(2.0)) + a.set2d(1, 0, t.CDouble(3.0)); a.set2d(1, 1, t.CDouble(4.0)) + + b: numpy.ndarray | t.CPtr = numpy.empty2d(pool, 2, 2) + b.set2d(0, 0, t.CDouble(5.0)); b.set2d(0, 1, t.CDouble(6.0)) + b.set2d(1, 0, t.CDouble(7.0)); b.set2d(1, 1, t.CDouble(8.0)) + + c: numpy.ndarray | t.CPtr = numpy.matmul(a, b) + check("matmul not None", c != None, "matmul returned None") + check("matmul [0,0]==19", c.at2d(0, 0) == t.CDouble(19.0), "mismatch") + check("matmul [0,1]==22", c.at2d(0, 1) == t.CDouble(22.0), "mismatch") + check("matmul [1,0]==43", c.at2d(1, 0) == t.CDouble(43.0), "mismatch") + check("matmul [1,1]==50", c.at2d(1, 1) == t.CDouble(50.0), "mismatch") + + a.delete() + b.delete() + c.delete() + section_footer() + + +def test_dot(): + section_header("dot / dot_product") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + b: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(4.0), t.CDouble(5.0), t.CDouble(6.0)) + + d: t.CDouble = a.dot(b) + check("dot == 32", approx_eq(d, t.CDouble(32.0)), "mismatch") + + d2: t.CDouble = numpy.dot_product(a, b) + check("dot_product == 32", approx_eq(d2, t.CDouble(32.0)), "mismatch") + + a.delete() + b.delete() + section_footer() + + +def test_transpose(): + section_header("T (transpose)") + + a: numpy.ndarray | t.CPtr = numpy.empty2d(pool, 2, 3) + a.set2d(0, 0, t.CDouble(1.0)); a.set2d(0, 1, t.CDouble(2.0)); a.set2d(0, 2, t.CDouble(3.0)) + a.set2d(1, 0, t.CDouble(4.0)); a.set2d(1, 1, t.CDouble(5.0)); a.set2d(1, 2, t.CDouble(6.0)) + + at: numpy.ndarray | t.CPtr = a.T() + check("T not None", at != None, "T returned None") + check("T shape[0]==3", at.shape[0] == 3, "shape mismatch") + check("T shape[1]==2", at.shape[1] == 2, "shape mismatch") + check("T [0,0]==1", at.at2d(0, 0) == t.CDouble(1.0), "mismatch") + check("T [0,1]==4", at.at2d(0, 1) == t.CDouble(4.0), "mismatch") + check("T [1,0]==2", at.at2d(1, 0) == t.CDouble(2.0), "mismatch") + + a.delete() + at.delete() + section_footer() + + +# ============================================================ +# 7. Utility +# ============================================================ +def test_var_std_norm(): + section_header("var / std / norm") + + # [2,4,4,4,5,5,7,9] mean=5, var=4, std=2 + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 8) + a.data[0] = t.CDouble(2.0); a.data[1] = t.CDouble(4.0) + a.data[2] = t.CDouble(4.0); a.data[3] = t.CDouble(4.0) + a.data[4] = t.CDouble(5.0); a.data[5] = t.CDouble(5.0) + a.data[6] = t.CDouble(7.0); a.data[7] = t.CDouble(9.0) + + v: t.CDouble = numpy.var(a) + printf(" var = %.6f (expect 4.0)\n", v) + check("var ~= 4", approx_eq(v, t.CDouble(4.0)), "mismatch") + + s: t.CDouble = numpy.std(a) + printf(" std = %.6f (expect 2.0)\n", s) + check("std ~= 2", approx_eq(s, t.CDouble(2.0)), "mismatch") + + b: numpy.ndarray | t.CPtr = vec2(pool, t.CDouble(3.0), t.CDouble(4.0)) + n: t.CDouble = numpy.norm(b) + printf(" norm = %.6f (expect 5.0)\n", n) + check("norm ~= 5", approx_eq(n, t.CDouble(5.0)), "mismatch") + + a.delete() + b.delete() + section_footer() + + +def test_clip_concatenate(): + section_header("clip / concatenate") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(5.0), t.CDouble(10.0)) + r: numpy.ndarray | t.CPtr = numpy.clip(a, t.CDouble(2.0), t.CDouble(8.0)) + check("clip [0]==2", r.data[0] == t.CDouble(2.0), "mismatch") + check("clip [1]==5", r.data[1] == t.CDouble(5.0), "mismatch") + check("clip [2]==8", r.data[2] == t.CDouble(8.0), "mismatch") + + b: numpy.ndarray | t.CPtr = vec2(pool, t.CDouble(1.0), t.CDouble(2.0)) + c: numpy.ndarray | t.CPtr = vec2(pool, t.CDouble(3.0), t.CDouble(4.0)) + cat: numpy.ndarray | t.CPtr = numpy.concatenate(b, c) + check("concatenate not None", cat != None, "concatenate returned None") + check("concatenate size == 4", cat.size == 4, "size mismatch") + check("concatenate [0]==1", cat.data[0] == t.CDouble(1.0), "mismatch") + check("concatenate [3]==4", cat.data[3] == t.CDouble(4.0), "mismatch") + + a.delete() + r.delete() + b.delete() + c.delete() + cat.delete() + section_footer() + + +def test_sort_reverse(): + section_header("sort_arr / reverse") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(3.0), t.CDouble(1.0), t.CDouble(2.0)) + s: numpy.ndarray | t.CPtr = numpy.sort_arr(a) + check("sort not None", s != None, "sort returned None") + check("sort [0]==1", s.data[0] == t.CDouble(1.0), "mismatch") + check("sort [1]==2", s.data[1] == t.CDouble(2.0), "mismatch") + check("sort [2]==3", s.data[2] == t.CDouble(3.0), "mismatch") + + r: numpy.ndarray | t.CPtr = numpy.reverse(a) + check("reverse not None", r != None, "reverse returned None") + check("reverse [0]==2", r.data[0] == t.CDouble(2.0), "mismatch") + check("reverse [1]==1", r.data[1] == t.CDouble(1.0), "mismatch") + check("reverse [2]==3", r.data[2] == t.CDouble(3.0), "mismatch") + + a.delete() + s.delete() + r.delete() + section_footer() + + +def test_print_arr(): + section_header("print_arr") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + printf(" 1D array: ") + a.print_arr() + + b: numpy.ndarray | t.CPtr = numpy.eye(pool, 3) + printf(" 2D eye(3):\n") + b.print_arr() + + a.delete() + b.delete() + section_footer() + + +# ============================================================ +# 8. Additional operator overloading +# ============================================================ +def test_floordiv_mod(): + section_header("__floordiv__ / __mod__") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(7.0), t.CDouble(10.0), t.CDouble(15.0)) + b: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(2.0), t.CDouble(3.0), t.CDouble(4.0)) + + c_fd: numpy.ndarray | t.CPtr = a // b + check("7//2==3", c_fd.data[0] == t.CDouble(3.0), "mismatch") + check("10//3==3", c_fd.data[1] == t.CDouble(3.0), "mismatch") + check("15//4==3", c_fd.data[2] == t.CDouble(3.0), "mismatch") + + c_mod: numpy.ndarray | t.CPtr = a % b + check("7%%2==1", c_mod.data[0] == t.CDouble(1.0), "mismatch") + check("10%%3==1", c_mod.data[1] == t.CDouble(1.0), "mismatch") + check("15%%4==3", c_mod.data[2] == t.CDouble(3.0), "mismatch") + + a.delete() + b.delete() + c_fd.delete() + c_mod.delete() + section_footer() + + +# ============================================================ +# 9. Additional math functions +# ============================================================ +def test_additional_math(): + section_header("np_log10 / np_log2 / np_floor / np_ceil / np_round / np_sign") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(10.0), t.CDouble(100.0), t.CDouble(1000.0)) + r_log10: numpy.ndarray | t.CPtr = numpy.np_log10(a) + check("log10(10)~=1", approx_loose(r_log10.data[0], t.CDouble(1.0)), "mismatch") + check("log10(100)~=2", approx_loose(r_log10.data[1], t.CDouble(2.0)), "mismatch") + + b: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(2.0), t.CDouble(4.0), t.CDouble(8.0)) + r_log2: numpy.ndarray | t.CPtr = numpy.np_log2(b) + check("log2(2)~=1", approx_loose(r_log2.data[0], t.CDouble(1.0)), "mismatch") + check("log2(4)~=2", approx_loose(r_log2.data[1], t.CDouble(2.0)), "mismatch") + + c: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.5), t.CDouble(2.7), t.CDouble(-1.3)) + r_floor: numpy.ndarray | t.CPtr = numpy.np_floor(c) + check("floor(1.5)==1", r_floor.data[0] == t.CDouble(1.0), "mismatch") + check("floor(2.7)==2", r_floor.data[1] == t.CDouble(2.0), "mismatch") + check("floor(-1.3)==-2", r_floor.data[2] == t.CDouble(-2.0), "mismatch") + + r_ceil: numpy.ndarray | t.CPtr = numpy.np_ceil(c) + check("ceil(1.5)==2", r_ceil.data[0] == t.CDouble(2.0), "mismatch") + check("ceil(2.7)==3", r_ceil.data[1] == t.CDouble(3.0), "mismatch") + check("ceil(-1.3)==-1", r_ceil.data[2] == t.CDouble(-1.0), "mismatch") + + d: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.4), t.CDouble(2.5), t.CDouble(3.6)) + r_round: numpy.ndarray | t.CPtr = numpy.np_round(d) + check("round(1.4)==1", r_round.data[0] == t.CDouble(1.0), "mismatch") + check("round(3.6)==4", r_round.data[2] == t.CDouble(4.0), "mismatch") + + e: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + e.data[0] = t.CDouble(-3.0); e.data[1] = t.CDouble(0.0); e.data[2] = t.CDouble(5.0); e.data[3] = t.CDouble(-0.1) + r_sign: numpy.ndarray | t.CPtr = numpy.np_sign(e) + check("sign(-3)==-1", r_sign.data[0] == t.CDouble(-1.0), "mismatch") + check("sign(0)==0", r_sign.data[1] == t.CDouble(0.0), "mismatch") + check("sign(5)==1", r_sign.data[2] == t.CDouble(1.0), "mismatch") + + a.delete() + b.delete() + c.delete() + d.delete() + e.delete() + r_log10.delete() + r_log2.delete() + r_floor.delete() + r_ceil.delete() + r_round.delete() + r_sign.delete() + section_footer() + + +def test_trig_hyperbolic(): + section_header("np_tanh / np_sinh / np_cosh / np_arcsin / np_arccos / np_arctan") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(1.0), t.CDouble(-1.0)) + + r_tanh: numpy.ndarray | t.CPtr = numpy.np_tanh(a) + check("tanh(0)~=0", approx_loose(r_tanh.data[0], t.CDouble(0.0)), "mismatch") + + r_sinh: numpy.ndarray | t.CPtr = numpy.np_sinh(a) + check("sinh(0)~=0", approx_loose(r_sinh.data[0], t.CDouble(0.0)), "mismatch") + + r_cosh: numpy.ndarray | t.CPtr = numpy.np_cosh(a) + check("cosh(0)~=1", approx_loose(r_cosh.data[0], t.CDouble(1.0)), "mismatch") + + b: numpy.ndarray | t.CPtr = vec2(pool, t.CDouble(0.0), t.CDouble(0.5)) + r_asin: numpy.ndarray | t.CPtr = numpy.np_arcsin(b) + check("arcsin(0)~=0", approx_loose(r_asin.data[0], t.CDouble(0.0)), "mismatch") + + r_acos: numpy.ndarray | t.CPtr = numpy.np_arccos(b) + check("arccos(0)~=pi/2", approx_loose(r_acos.data[0], t.CDouble(1.5707963)), "mismatch") + + r_atan: numpy.ndarray | t.CPtr = numpy.np_arctan(b) + check("arctan(0)~=0", approx_loose(r_atan.data[0], t.CDouble(0.0)), "mismatch") + + a.delete() + b.delete() + r_tanh.delete() + r_sinh.delete() + r_cosh.delete() + r_asin.delete() + r_acos.delete() + r_atan.delete() + section_footer() + + +def test_degrees_radians(): + section_header("np_degrees / np_radians") + + a: numpy.ndarray | t.CPtr = vec2(pool, t.CDouble(0.0), t.CDouble(1.5707963267948966)) + + r_deg: numpy.ndarray | t.CPtr = numpy.np_degrees(a) + check("deg(0)~=0", approx_loose(r_deg.data[0], t.CDouble(0.0)), "mismatch") + check("deg(pi/2)~=90", approx_loose(r_deg.data[1], t.CDouble(90.0)), "mismatch") + + b: numpy.ndarray | t.CPtr = vec2(pool, t.CDouble(0.0), t.CDouble(90.0)) + r_rad: numpy.ndarray | t.CPtr = numpy.np_radians(b) + check("rad(0)~=0", approx_loose(r_rad.data[0], t.CDouble(0.0)), "mismatch") + check("rad(90)~=pi/2", approx_loose(r_rad.data[1], t.CDouble(1.5707963)), "mismatch") + + a.delete() + b.delete() + r_deg.delete() + r_rad.delete() + section_footer() + + +# ============================================================ +# 10. Additional array operations +# ============================================================ +def test_cumsum_diff(): + section_header("cumsum / diff") + + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0); a.data[1] = t.CDouble(2.0); a.data[2] = t.CDouble(3.0); a.data[3] = t.CDouble(4.0) + + r_cs: numpy.ndarray | t.CPtr = numpy.cumsum(a) + check("cumsum not None", r_cs != None, "cumsum returned None") + check("cumsum[0]==1", r_cs.data[0] == t.CDouble(1.0), "mismatch") + check("cumsum[1]==3", r_cs.data[1] == t.CDouble(3.0), "mismatch") + check("cumsum[2]==6", r_cs.data[2] == t.CDouble(6.0), "mismatch") + check("cumsum[3]==10", r_cs.data[3] == t.CDouble(10.0), "mismatch") + + r_diff: numpy.ndarray | t.CPtr = numpy.diff(a) + check("diff not None", r_diff != None, "diff returned None") + check("diff size==3", r_diff.size == 3, "size mismatch") + check("diff[0]==1", r_diff.data[0] == t.CDouble(1.0), "mismatch") + check("diff[2]==1", r_diff.data[2] == t.CDouble(1.0), "mismatch") + + a.delete() + r_cs.delete() + r_diff.delete() + section_footer() + + +def test_max_min_where(): + section_header("np_maximum / np_minimum / np_where") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(5.0), t.CDouble(3.0)) + b: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(4.0), t.CDouble(2.0), t.CDouble(6.0)) + + r_max: numpy.ndarray | t.CPtr = numpy.np_maximum(a, b) + check("maximum[0]==4", r_max.data[0] == t.CDouble(4.0), "mismatch") + check("maximum[1]==5", r_max.data[1] == t.CDouble(5.0), "mismatch") + check("maximum[2]==6", r_max.data[2] == t.CDouble(6.0), "mismatch") + + r_min: numpy.ndarray | t.CPtr = numpy.np_minimum(a, b) + check("minimum[0]==1", r_min.data[0] == t.CDouble(1.0), "mismatch") + check("minimum[1]==2", r_min.data[1] == t.CDouble(2.0), "mismatch") + check("minimum[2]==3", r_min.data[2] == t.CDouble(3.0), "mismatch") + + # where: cond > 0 ? a : b + cond: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(1.0), t.CDouble(0.0)) + r_where: numpy.ndarray | t.CPtr = numpy.np_where(cond, a, b) + check("where[0]==4", r_where.data[0] == t.CDouble(4.0), "mismatch") + check("where[1]==5", r_where.data[1] == t.CDouble(5.0), "mismatch") + check("where[2]==6", r_where.data[2] == t.CDouble(6.0), "mismatch") + + a.delete() + b.delete() + cond.delete() + r_max.delete() + r_min.delete() + r_where.delete() + section_footer() + + +def test_flatten_trace(): + section_header("flatten / trace") + + a: numpy.ndarray | t.CPtr = numpy.empty2d(pool, 2, 3) + a.set2d(0, 0, t.CDouble(1.0)); a.set2d(0, 1, t.CDouble(2.0)); a.set2d(0, 2, t.CDouble(3.0)) + a.set2d(1, 0, t.CDouble(4.0)); a.set2d(1, 1, t.CDouble(5.0)); a.set2d(1, 2, t.CDouble(6.0)) + + r_flat: numpy.ndarray | t.CPtr = numpy.flatten(a) + check("flatten not None", r_flat != None, "flatten returned None") + check("flatten ndim==1", r_flat.ndim == 1, "ndim mismatch") + check("flatten size==6", r_flat.size == 6, "size mismatch") + check("flatten[0]==1", r_flat.data[0] == t.CDouble(1.0), "mismatch") + + # trace of [[1,2],[3,4]] = 1+4 = 5 + b: numpy.ndarray | t.CPtr = numpy.empty2d(pool, 2, 2) + b.set2d(0, 0, t.CDouble(1.0)); b.set2d(0, 1, t.CDouble(2.0)) + b.set2d(1, 0, t.CDouble(3.0)); b.set2d(1, 1, t.CDouble(4.0)) + tr: t.CDouble = numpy.trace(b) + check("trace == 5", tr == t.CDouble(5.0), "mismatch") + + a.delete() + r_flat.delete() + b.delete() + section_footer() + + +def test_outer(): + section_header("outer") + + a: numpy.ndarray | t.CPtr = vec2(pool, t.CDouble(1.0), t.CDouble(2.0)) + b: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(3.0), t.CDouble(4.0), t.CDouble(5.0)) + + r: numpy.ndarray | t.CPtr = numpy.outer(a, b) + check("outer not None", r != None, "outer returned None") + check("outer ndim==2", r.ndim == 2, "ndim mismatch") + check("outer[0,0]==3", r.at2d(0, 0) == t.CDouble(3.0), "mismatch") + check("outer[0,1]==4", r.at2d(0, 1) == t.CDouble(4.0), "mismatch") + check("outer[1,0]==6", r.at2d(1, 0) == t.CDouble(6.0), "mismatch") + check("outer[1,2]==10", r.at2d(1, 2) == t.CDouble(10.0), "mismatch") + + a.delete() + b.delete() + r.delete() + section_footer() + + +# ============================================================ +# 11. Boolean / comparison +# ============================================================ +def test_bool_comparison(): + section_header("np_all / np_any / np_count_nonzero / np_equal / np_less / np_greater") + + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + a.data[0] = t.CDouble(1.0); a.data[1] = t.CDouble(0.0); a.data[2] = t.CDouble(3.0); a.data[3] = t.CDouble(0.0) + check("count_nonzero==2", numpy.np_count_nonzero(a) == 2, "mismatch") + check("any==1", numpy.np_any(a) == 1, "mismatch") + + b: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + check("all(1,2,3)==1", numpy.np_all(b) == 1, "mismatch") + + c: numpy.ndarray | t.CPtr = numpy.zeros(pool, 3) + check("all(0,0,0)==0", numpy.np_all(c) == 0, "mismatch") + check("any(0,0,0)==0", numpy.np_any(c) == 0, "mismatch") + + d: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + e: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(0.0), t.CDouble(4.0)) + + r_eq: numpy.ndarray | t.CPtr = numpy.np_equal(d, e) + check("equal[0]==1", r_eq.data[0] == t.CDouble(1.0), "mismatch") + check("equal[1]==0", r_eq.data[1] == t.CDouble(0.0), "mismatch") + + r_lt: numpy.ndarray | t.CPtr = numpy.np_less(d, e) + check("less[2]==1", r_lt.data[2] == t.CDouble(1.0), "mismatch") + check("less[0]==0", r_lt.data[0] == t.CDouble(0.0), "mismatch") + + r_gt: numpy.ndarray | t.CPtr = numpy.np_greater(d, e) + check("greater[1]==1", r_gt.data[1] == t.CDouble(1.0), "mismatch") + + a.delete() + b.delete() + c.delete() + d.delete() + e.delete() + r_eq.delete() + r_lt.delete() + r_gt.delete() + section_footer() + + +# ============================================================ +# 12. Linear algebra +# ============================================================ +def test_linalg(): + section_header("det2x2 / inv2x2 / cross3 / prod / median / percentile") + + # det2x2: [[1,2],[3,4]] -> 1*4-2*3 = -2 + a: numpy.ndarray | t.CPtr = numpy.empty2d(pool, 2, 2) + a.set2d(0, 0, t.CDouble(1.0)); a.set2d(0, 1, t.CDouble(2.0)) + a.set2d(1, 0, t.CDouble(3.0)); a.set2d(1, 1, t.CDouble(4.0)) + d: t.CDouble = numpy.det2x2(a) + check("det2x2==-2", d == t.CDouble(-2.0), "mismatch") + + # inv2x2 of [[1,2],[3,4]] + inv: numpy.ndarray | t.CPtr = numpy.inv2x2(a) + check("inv2x2 not None", inv != None, "inv2x2 returned None") + check("inv[0,0]==-2", approx_eq(inv.at2d(0, 0), t.CDouble(-2.0)), "mismatch") + check("inv[0,1]==1", approx_eq(inv.at2d(0, 1), t.CDouble(1.0)), "mismatch") + + # cross3: [1,0,0] x [0,1,0] = [0,0,1] + x: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(0.0), t.CDouble(0.0)) + y: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(1.0), t.CDouble(0.0)) + cr: numpy.ndarray | t.CPtr = numpy.cross3(x, y) + check("cross not None", cr != None, "cross returned None") + check("cross[2]==1", cr.data[2] == t.CDouble(1.0), "mismatch") + + # prod + p: numpy.ndarray | t.CPtr = numpy.zeros(pool, 4) + p.data[0] = t.CDouble(1.0); p.data[1] = t.CDouble(2.0); p.data[2] = t.CDouble(3.0); p.data[3] = t.CDouble(4.0) + check("prod==24", numpy.prod(p) == t.CDouble(24.0), "mismatch") + + # median + m: numpy.ndarray | t.CPtr = numpy.zeros(pool, 5) + m.data[0] = t.CDouble(3.0); m.data[1] = t.CDouble(1.0); m.data[2] = t.CDouble(2.0) + m.data[3] = t.CDouble(5.0); m.data[4] = t.CDouble(4.0) + check("median==3", numpy.median(m) == t.CDouble(3.0), "mismatch") + + # percentile + check("p50==3", approx_eq(numpy.percentile(m, t.CDouble(50.0)), t.CDouble(3.0)), "mismatch") + + a.delete() + inv.delete() + x.delete() + y.delete() + cr.delete() + p.delete() + m.delete() + section_footer() + + +# ============================================================ +# 13. Additional creation / constants +# ============================================================ +def test_additional_creation(): + section_header("full2d / zeros_like / ones_like / arange1 / constants") + + f: numpy.ndarray | t.CPtr = numpy.full2d(pool, 2, 3, t.CDouble(7.0)) + check("full2d not None", f != None, "full2d returned None") + check("full2d ndim==2", f.ndim == 2, "ndim mismatch") + check("full2d[0,0]==7", f.at2d(0, 0) == t.CDouble(7.0), "mismatch") + check("full2d[1,2]==7", f.at2d(1, 2) == t.CDouble(7.0), "mismatch") + + a: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(1.0), t.CDouble(2.0), t.CDouble(3.0)) + zl: numpy.ndarray | t.CPtr = numpy.zeros_like(a) + check("zeros_like not None", zl != None, "returned None") + check("zeros_like size==3", zl.size == 3, "size mismatch") + check("zeros_like[0]==0", zl.data[0] == t.CDouble(0.0), "mismatch") + + ol: numpy.ndarray | t.CPtr = numpy.ones_like(a) + check("ones_like not None", ol != None, "returned None") + check("ones_like[0]==1", ol.data[0] == t.CDouble(1.0), "mismatch") + + ar: numpy.ndarray | t.CPtr = numpy.arange1(pool, t.CDouble(4.0)) + check("arange1 not None", ar != None, "returned None") + check("arange1 size==4", ar.size == 4, "size mismatch") + check("arange1[0]==0", ar.data[0] == t.CDouble(0.0), "mismatch") + check("arange1[3]==3", ar.data[3] == t.CDouble(3.0), "mismatch") + + # Constants + check("pi ~= 3.14", approx_loose(numpy.pi, t.CDouble(3.14159265)), "mismatch") + check("e ~= 2.71", approx_loose(numpy.e, t.CDouble(2.71828182)), "mismatch") + + f.delete() + a.delete() + zl.delete() + ol.delete() + ar.delete() + section_footer() + + +# ============================================================ +# 14. Interpolation +# ============================================================ +def test_interp(): + section_header("np_interp") + + xp: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(1.0), t.CDouble(2.0)) + fp: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(10.0), t.CDouble(20.0)) + + v: t.CDouble = numpy.np_interp(t.CDouble(0.5), xp, fp) + check("interp(0.5)==5", approx_eq(v, t.CDouble(5.0)), "mismatch") + + v2: t.CDouble = numpy.np_interp(t.CDouble(1.5), xp, fp) + check("interp(1.5)==15", approx_eq(v2, t.CDouble(15.0)), "mismatch") + + v3: t.CDouble = numpy.np_interp(t.CDouble(-1.0), xp, fp) + check("interp(-1)==0", approx_eq(v3, t.CDouble(0.0)), "mismatch") + + v4: t.CDouble = numpy.np_interp(t.CDouble(3.0), xp, fp) + check("interp(3)==20", approx_eq(v4, t.CDouble(20.0)), "mismatch") + + xp.delete() + fp.delete() + section_footer() + + +# ============================================================ +# 15. Edge / boundary / exception tests +# ============================================================ +def test_numpy_edge(): + section_header("edge: size=0 / size=1 / non-SIMD-block / negative / div-zero") + + # size=0: pool.alloc(0) returns None, so zeros(0) returns None (expected) + a0: numpy.ndarray | t.CPtr = numpy.zeros(pool, 0) + check("zeros(0) returns None", a0 == None, "expected None for size=0") + + # size=1 + a1: numpy.ndarray | t.CPtr = numpy.zeros(pool, 1) + check("zeros(1) not None", a1 != None, "returned None") + check("zeros(1) size==1", a1.size == 1, "size mismatch") + check("zeros(1) [0]==0", a1.data[0] == t.CDouble(0.0), "mismatch") + a1.delete() + + # non-SIMD-block sizes (1,2,3,5,6,7) + a5: numpy.ndarray | t.CPtr = numpy.arange(pool, t.CDouble(0.0), t.CDouble(5.0), t.CDouble(1.0)) + check("arange(5) size==5", a5.size == 5, "size mismatch") + check("arange(5) sum==10", approx_eq(a5.sum(), t.CDouble(10.0)), "mismatch") + a5.delete() + + a6: numpy.ndarray | t.CPtr = numpy.arange(pool, t.CDouble(0.0), t.CDouble(6.0), t.CDouble(1.0)) + check("arange(6) sum==15", approx_eq(a6.sum(), t.CDouble(15.0)), "mismatch") + a6.delete() + + a7: numpy.ndarray | t.CPtr = numpy.arange(pool, t.CDouble(0.0), t.CDouble(7.0), t.CDouble(1.0)) + check("arange(7) sum==21", approx_eq(a7.sum(), t.CDouble(21.0)), "mismatch") + a7.delete() + + # negative values in sqrt + neg_arr: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(-1.0), t.CDouble(0.0), t.CDouble(4.0)) + r_sqrt_neg: numpy.ndarray | t.CPtr = numpy.np_sqrt(neg_arr) + check("sqrt(neg) not None", r_sqrt_neg != None, "returned None") + # sqrt(4)=2, sqrt(0)=0; sqrt(-1) is NaN (implementation-defined) + check("sqrt(4)==2", approx_eq(r_sqrt_neg.data[2], t.CDouble(2.0)), "mismatch") + neg_arr.delete() + r_sqrt_neg.delete() + + # div-by-zero: b/a where a has zeros + za: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(0.0), t.CDouble(2.0), t.CDouble(0.0)) + zb: numpy.ndarray | t.CPtr = vec3(pool, t.CDouble(6.0), t.CDouble(4.0), t.CDouble(8.0)) + r_divz: numpy.ndarray | t.CPtr = za / zb + check("0/6==0", r_divz.data[0] == t.CDouble(0.0), "mismatch") + check("2/4==0.5", r_divz.data[1] == t.CDouble(0.5), "mismatch") + za.delete() + zb.delete() + r_divz.delete() + + # large array (non-aligned, non-SIMD-block) + big: numpy.ndarray | t.CPtr = numpy.zeros(pool, 1000) + check("zeros(1000) not None", big != None, "returned None") + check("zeros(1000) size==1000", big.size == 1000, "size mismatch") + big.delete() + + section_footer() + + +# ============================================================ +# 16. Performance benchmark +# ============================================================ +def bench_numpy_perf(): + section_header("Benchmark: numpy ops") + + N: t.CSizeT = 10000 + ITERS: t.CInt = 5 + + a: numpy.ndarray | t.CPtr = numpy.zeros(pool, N) + b: numpy.ndarray | t.CPtr = numpy.zeros(pool, N) + i: t.CSizeT = 0 + while i < N: + a.data[i] = t.CDouble(1.0) + b.data[i] = t.CDouble(2.0) + i += 1 + + # add benchmark + t0: t.CDouble = c.Timer() + j: t.CInt = 0 + while j < ITERS: + r: numpy.ndarray | t.CPtr = a + b + r.delete() + j += 1 + t1: t.CDouble = c.Timer() + printf(" ADD: %.1f ms\n", (t1 - t0) * t.CDouble(1000.0)) + + # mul benchmark + t0 = c.Timer() + j = 0 + while j < ITERS: + r2: numpy.ndarray | t.CPtr = a * b + r2.delete() + j += 1 + t1 = c.Timer() + printf(" MUL: %.1f ms\n", (t1 - t0) * t.CDouble(1000.0)) + + # sqrt benchmark + t0 = c.Timer() + j = 0 + while j < ITERS: + r3: numpy.ndarray | t.CPtr = numpy.np_sqrt(a) + r3.delete() + j += 1 + t1 = c.Timer() + printf(" SQRT: %.1f ms\n", (t1 - t0) * t.CDouble(1000.0)) + + a.delete() + b.delete() + section_footer() + + +# ============================================================ +# Entry points +# ============================================================ +def test_numpy_correct() -> t.CInt: + global arena, pool, test_passed, test_failed + + arena = calloc(2 * 1024 * 1024, 1) + pool = mpool.MPool(arena, 2 * 1024 * 1024, 0) + + test_passed = 0 + test_failed = 0 + + printf("==============================================\n") + printf(" numpy Correctness Tests\n") + printf("==============================================\n") + + test_zeros_ones() + test_arange_linspace() + test_eye_diag() + test_sum_mean_min_max() + test_fill_copy() + test_add_sub_mul_div() + test_neg() + test_len() + test_scalar_ops() + test_math_funcs() + test_matmul() + test_dot() + test_transpose() + test_var_std_norm() + test_clip_concatenate() + test_sort_reverse() + test_print_arr() + test_floordiv_mod() + test_additional_math() + test_trig_hyperbolic() + test_degrees_radians() + test_cumsum_diff() + test_max_min_where() + test_flatten_trace() + test_outer() + test_bool_comparison() + test_linalg() + test_additional_creation() + test_interp() + + printf("\n==============================================\n") + printf(" Correctness: %d passed, %d failed\n", test_passed, test_failed) + printf("==============================================\n") + + return test_failed + + +def test_numpy_edge_main() -> t.CInt: + global arena, pool, test_passed, test_failed + + arena = calloc(2 * 1024 * 1024, 1) + pool = mpool.MPool(arena, 2 * 1024 * 1024, 0) + + test_passed = 0 + test_failed = 0 + + printf("==============================================\n") + printf(" numpy Edge / Boundary Tests\n") + printf("==============================================\n") + + test_numpy_edge() + + printf("\n==============================================\n") + printf(" Edge: %d passed, %d failed\n", test_passed, test_failed) + printf("==============================================\n") + + return test_failed + + +def bench_numpy_main() -> t.CInt: + global arena, pool + + arena = calloc(8 * 1024 * 1024, 1) + pool = mpool.MPool(arena, 8 * 1024 * 1024, 0) + + printf("==============================================\n") + printf(" numpy Performance Benchmark\n") + printf("==============================================\n") + + bench_numpy_perf() + + printf("==============================================\n") + return 0 + + +# Backward-compatible entry +def test_numpy_main() -> t.CInt: + global arena, pool + + arena = calloc(2 * 1024 * 1024, 1) + pool = mpool.MPool(arena, 2 * 1024 * 1024, 0) + + failed: t.CInt = test_numpy_correct() + if failed == 0: + failed = test_numpy_edge_main() + if failed == 0: + bench_numpy_main() + return failed diff --git a/Test/TestProject/App/test_zlib.py b/Test/TestProject/App/test_zlib.py new file mode 100644 index 0000000..3961883 --- /dev/null +++ b/Test/TestProject/App/test_zlib.py @@ -0,0 +1,881 @@ +from stdint import * +import zlib.pyzlib as pyzlib +import zlib.zhuff as zhuff +import zlib.zdef as zdef +from stdio import printf, strlen +import stdlib +import string +import mpool +import t, c + +pool: mpool.MPool | t.CPtr = None + +test_passed: t.CInt = 0 +test_failed: t.CInt = 0 +def check(name: str, condition: t.CInt, detail: str): + global test_passed, test_failed + if condition: + test_passed += 1 + printf(" [PASS] %s\n", name) + else: + test_failed += 1 + printf(" [FAIL] %s -- %s\n", name, detail if detail else "") + +def print_hex_test(data: BYTEPTR, length: t.CSizeT, max_show: t.CSizeT): + if not data or length == 0: + printf("(empty)\n") + return + show: t.CSizeT = max_show if (length > max_show) else length + i: t.CSizeT + for i in range(show): + printf("%02X ", data[i]) + if length > max_show: + printf("... (%zu bytes total)", length) + printf("\n") + +def print_separator(): + printf(" -------------------------------------------\n") + +def section_header(title: str): + printf("\n+-- %s --+\n", title) + +def section_footer(): + printf("+--------------------------------------------+\n") + +# ============================================================ + +def test_version(): + section_header("Version Info") + + ver: str = pyzlib.ZLIB_VERSION + printf(" ZLIB_VERSION (compile-time) : %s\n", ver) + check("ZLIB_VERSION not None", ver != None, "version string is None") + check("ZLIB_VERSION not empty", strlen(ver) > 0, "version string is empty") + + runtime_ver: str = pyzlib.runtime_version() + printf(" ZLIB_RUNTIME_VERSION : %s\n", runtime_ver) + check("runtime version not None", runtime_ver != None, "runtime version is None") + check("runtime version not empty", strlen(runtime_ver) > 0, "runtime version is empty") + + section_footer() + + +def test_compress_decompress(): + section_header("compress / decompress") + + inp: str = "Hello, World! This is a test of zlib compression and decompression." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("compress returns non-None", compressed != None, "compress returned None") + check("compress output size > 0", out_length > 0, "compressed size is 0") + check("compress output produced", out_length > 0, "compressed size is 0") + + printf(" Compressed (%zu bytes): ", out_length) + print_hex_test(compressed, out_length, 32) + printf(" Compression ratio: %.1f%%\n", t.CDouble(out_length) / input_length * 100) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(pool, compressed, out_length, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress returns non-None", decompressed != None, "decompress returned None") + check("decompress output size matches input", dec_length == input_length, "size mismatch") + check("decompress output matches input", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + + printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(decompressed)) + + free(compressed) + free(decompressed) + section_footer() + + +def test_compress_levels(): + section_header("Compression Levels") + + inp: str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + + c0: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_NO_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 0 compress OK", c0 != None, "level 0 returned None") + printf(" Level 0 (Z_NO_COMPRESSION): %zu bytes\n", out_length) + length0: t.CSizeT = out_length + free(c0) + + c1: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_BEST_SPEED, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 1 compress OK", c1 != None, "level 1 returned None") + printf(" Level 1 (Z_BEST_SPEED) : %zu bytes\n", out_length) + free(c1) + + c6: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level -1 compress OK", c6 != None, "default level returned None") + printf(" Level -1 (DEFAULT) : %zu bytes\n", out_length) + free(c6) + + c9: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_BEST_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 9 compress OK", c9 != None, "level 9 returned None") + printf(" Level 9 (Z_BEST_COMPRESS) : %zu bytes\n", out_length) + length9: t.CSizeT = out_length + free(c9) + + check("level 9 smaller than level 0", length9 < length0, "level 9 not smaller than level 0") + + section_footer() + + +def test_compressobj(): + section_header("compressobj (incremental)") + + part1: str = "Hello, " + part2: str = "World!" + printf(" Part 1: \"%s\"\n", part1) + printf(" Part 2: \"%s\"\n", part2) + + out_length: t.CSizeT = 0 + + s: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pool, pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + check("compressobj created", s != None, "compressobj is None") + print_separator() + + c1: BYTEPTR = s.compress(BYTEPTR(part1), strlen(part1), c.Addr(out_length)) + check("compress part1 OK", c1 != None, "compress part1 failed") + printf(" Compressed part1: %zu bytes -> ", out_length) + print_hex_test(c1, out_length, 16) + total: t.CSizeT = out_length + all: BYTEPTR = None + if out_length > 0 and c1: + all = BYTEPTR(malloc(total)) + if all: memcpy(all, c1, out_length) + free(c1) + + c2: BYTEPTR = s.compress(BYTEPTR(part2), + strlen(part2), c.Addr(out_length)) + check("compress part2 OK", c2 != None, "compress part2 failed") + printf(" Compressed part2: %zu bytes -> ", out_length) + print_hex_test(c2, out_length, 16) + if out_length > 0 and c2: + new_all: BYTEPTR = BYTEPTR(realloc(all, total + out_length)) + if new_all: + all = new_all + memcpy(all + total, c2, out_length) + total += out_length + free(c2) + + c3: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush (Z_FINISH) OK", c3 != None, "flush failed") + printf(" Flush result : %zu bytes -> ", out_length) + print_hex_test(c3, out_length, 16) + if out_length > 0 and c3: + new_all: BYTEPTR = realloc(all, total + out_length) # 隐式转换 + if new_all: + all = new_all + memcpy(all + total, c3, out_length) + total += out_length + free(c3) + + print_separator() + + if all: + dec_length: t.CSizeT = 0 + dec: BYTEPTR = pyzlib.decompress(pool, all, total, pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress incremental OK", dec != None, "decompress returned None") + check("decompress incremental size", dec != None and dec_length == strlen(part1) + strlen(part2), "size mismatch") + check("decompress incremental content", + dec != None and memcmp(dec, "Hello, World!", dec_length) == 0, "content mismatch") + if dec: + printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + free(all) + + s.delete() # del s + section_footer() + +def test_decompressobj(): + section_header("decompressobj") + + inp: str = "Test data for decompress object." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pool, pyzlib.MAX_WBITS, None, 0) + check("decompressobj created", d != None, "decompressobj is None") + check("eof is false initially", d.eof == 0, "eof should be 0") + print_separator() + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(compressed, out_length, + 0, c.Addr(dec_length)) + check("decompress OK", dec != None, "decompress returned None") + check("decompress size", dec != None and dec_length == input_length, "size mismatch") + check("decompress content", dec != None and memcmp(dec, inp, input_length) == 0, "content mismatch") + check("eof is true after stream end", d.eof == 1, "eof should be 1") + + if dec: + printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(dec)) + printf(" eof = %d\n", d.eof) + + free(dec) + free(compressed) + d.delete() + section_footer() + +def test_decompressobj_max_lengthgth(): + section_header("decompressobj max_lengthgth") + + inp: str = "This is a longer string for testing max_lengthgth parameter in decompress." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pool, pyzlib.MAX_WBITS, None, 0) + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(compressed, out_length, + 10, c.Addr(dec_length)) + check("max_lengthgth decompress OK", dec != None, "decompress returned None") + check("max_lengthgth limits output", dec_length <= 10, "output exceeded max_lengthgth") + if dec: + printf(" First chunk (max_lengthgth=10): \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + + tail_length: t.CSizeT = 0 + tail: BYTEPTR = d.unconsumed_tail(c.Addr(tail_length)) + check("unconsumed_tail exists", tail != None or tail_length == 0, "no unconsumed_tail") + printf(" unconsumed_tail: %zu bytes remaining\n", tail_length) + printf(" eof = %d\n", d.eof) + + if tail_length > 0 or not d.eof: + flushed: BYTEPTR = d.flush(pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("flush after max_lengthgth OK", flushed != None, "flush returned None") + if flushed: printf(" Flushed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(flushed)) + free(flushed) + + printf(" eof after flush = %d\n", d.eof) + + d.delete() + free(compressed) + section_footer() + + +def test_decompressobj_unused_data(): + section_header("decompressobj unused_data") + + inp: str = "Hello" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + total_length: t.CSizeT = out_length + 5 + combined: BYTEPTR = BYTEPTR(malloc(total_length)) + memcpy(combined, compressed, out_length) + memcpy(combined + out_length, "EXTRA", 5) + free(compressed) + printf(" Combined (compressed + \"EXTRA\"): %zu bytes\n", total_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pool, pyzlib.MAX_WBITS, None, 0) + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(combined, total_length, + 0, c.Addr(dec_length)) + check("decompress with extra OK", dec != None, "decompress returned None") + check("eof after stream end", d.eof == 1, "eof should be 1") + if dec: + printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + + print_separator() + + unused_length: t.CSizeT = 0 + unused: BYTEPTR = d.unused_data(c.Addr(unused_length)) + check("unused_data exists", unused != None and unused_length > 0, "no unused_data") + check("unused_data is EXTRA", unused_length == 5 and unused != None and memcmp(unused, "EXTRA", 5) == 0, "unused_data mismatch") + printf(" unused_data (%zu bytes): \"%.*s\"\n", unused_length, t.CInt(unused_length), str(unused)) + + d.delete() + free(combined) + section_footer() + + +def test_compress_copy(): + section_header("Compress.copy()") + + inp: str = "Copy test data for compress object" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + c1: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pool, pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + c1.compress(BYTEPTR(inp), input_length, c.Addr(out_length)) + printf(" Original: compressed %zu bytes so far\n", out_length) + + c2: pyzlib.Compress | t.CPtr = c1.copy() + check("compress copy OK", c2 != None, "copy returned None") + printf(" Copied compressobj\n") + + print_separator() + + f1: BYTEPTR = c1.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush original OK", f1 != None, "flush original failed") + length1: t.CSizeT = out_length + printf(" Original flush: %zu bytes\n", length1) + free(f1) + + f2: BYTEPTR = c2.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush copy OK", f2 != None, "flush copy failed") + length2: t.CSizeT = out_length + printf(" Copy flush : %zu bytes\n", length2) + free(f2) + + check("copy produces same output", length1 == length2, "output lengthgths differ") + + c1.delete() + c2.delete() + section_footer() + + +def test_decompress_copy(): + section_header("Decompress.copy()") + + inp: str = "Decompress copy test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d1: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pool, pyzlib.MAX_WBITS, None, 0) + d2: pyzlib.Decompress | t.CPtr = d1.copy() + check("decompress copy OK", d2 != None, "copy returned None") + printf(" Copied decompressobj\n") + + print_separator() + + dec_length1: t.CSizeT = 0 + dec_length2: t.CSizeT = 0 + dec1: BYTEPTR = d1.decompress(compressed, out_length, + 0, c.Addr(dec_length1)) + dec2: BYTEPTR = d2.decompress(compressed, out_length, + 0, c.Addr(dec_length2)) + check("decompress copy output size", dec_length1 == dec_length2, "sizes differ") + check("decompress copy output content", + dec1 and dec2 and memcmp(dec1, dec2, dec_length1) == 0, "content differs") + + if dec1: printf(" Original: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length1), str(dec1), dec_length1) + if dec2: printf(" Copy : \"%.*s\" (%zu bytes)\n", t.CInt(dec_length2), str(dec2), dec_length2) + + free(dec1) + free(dec2) + free(compressed) + d1.delete() + d2.delete() + section_footer() + + +def test_adler32(): + section_header("adler32 checksum") + + checksum: ULONG = pyzlib.zlib_adler32(BYTEPTR("Hello"), 5, 1) + printf(" adler32(\"Hello\") = 0x%08lX (%lu)\n", checksum, checksum) + check("adler32 returns non-zero", checksum != 0, "checksum is 0") + + incremental: ULONG = pyzlib.zlib_adler32(BYTEPTR("Hel"), 3, 1) + printf(" adler32(\"Hel\") = 0x%08lX\n", incremental) + incremental = pyzlib.zlib_adler32(BYTEPTR("lo"), 2, incremental) + printf(" adler32(\"lo\", prev) = 0x%08lX\n", incremental) + check("adler32 incremental matches one-shot", incremental == checksum, "incremental != one-shot") + printf(" Incremental == One-shot: %s\n", incremental == "YES" if checksum else "NO") + + section_footer() + + +def test_crc32(): + section_header("crc32 checksum") + + checksum: ULONG = pyzlib.zlib_crc32(BYTEPTR("Hello"), 5, 0) + printf(" crc32(\"Hello\") = 0x%08lX (%lu)\n", checksum, checksum) + check("crc32 returns non-zero", checksum != 0, "checksum is 0") + + incremental: ULONG = pyzlib.zlib_crc32(BYTEPTR("Hel"), 3, 0) + printf(" crc32(\"Hel\") = 0x%08lX\n", incremental) + incremental = pyzlib.zlib_crc32(BYTEPTR("lo"), 2, incremental) + printf(" crc32(\"lo\", prev) = 0x%08lX\n", incremental) + check("crc32 incremental matches one-shot", incremental == checksum, "incremental != one-shot") + printf(" Incremental == One-shot: %s\n", incremental == "YES" if checksum else "NO") + + section_footer() + + +def test_empty_compress(): + section_header("Empty data compress/decompress") + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(pool, BYTEPTR(""), 0, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("compress empty OK", compressed != None, "compress empty returned None") + check("compress empty output > 0", out_length > 0, "compressed empty is 0 bytes") + printf(" Empty input compressed: %zu bytes (header only)\n", out_length) + printf(" Hex: ") + print_hex_test(compressed, out_length, 32) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(pool, compressed, out_length, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress empty OK", decompressed != None, "decompress empty returned None") + check("decompress empty size == 0", dec_length == 0, "decompressed size != 0") + printf(" Decompressed back: %zu bytes\n", dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_gzip_format(): + section_header("Gzip format (wbits=31)") + + inp: str = "Gzip format test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\" (%zu bytes)\n", inp, input_length) + + gzip_wbits: t.CInt = pyzlib.MAX_WBITS + 16 + printf(" wbits = MAX_WBITS + 16 = %d\n", gzip_wbits) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, gzip_wbits, c.Addr(out_length)) + check("gzip compress OK", compressed != None, "gzip compress failed") + printf(" Gzip compressed: %zu bytes\n", out_length) + printf(" Header bytes: ") + print_hex_test(compressed, 4 if (out_length > 4) else out_length, 4) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(pool, compressed, out_length, + gzip_wbits, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("gzip decompress OK", decompressed != None, "gzip decompress failed") + check("gzip decompress size", dec_length == input_length, "size mismatch") + check("gzip decompress content", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_raw_deflate(): + section_header("Raw deflate (wbits=-15)") + + inp: str = "Raw deflate test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\" (%zu bytes)\n", inp, input_length) + + raw_wbits: t.CInt = -pyzlib.MAX_WBITS + printf(" wbits = -MAX_WBITS = %d\n", raw_wbits) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(pool, BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, raw_wbits, c.Addr(out_length)) + check("raw deflate compress OK", compressed != None, "raw deflate compress failed") + printf(" Raw compressed: %zu bytes\n", out_length) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(pool, compressed, out_length, + raw_wbits, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("raw deflate decompress OK", decompressed != None, "raw deflate decompress failed") + check("raw deflate decompress size", dec_length == input_length, "size mismatch") + check("raw deflate decompress content", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_zdict(): + section_header("Preset dictionary (zdict)") + + dict: str = "common words that appear frequently in the data" + inp: str = "common words that appear frequently" + input_length: t.CSizeT = strlen(inp) + printf(" Dictionary: \"%s\" (%zu bytes)\n", dict, strlen(dict)) + printf(" Input : \"%s\" (%zu bytes)\n", inp, input_length) + + out_length: t.CSizeT = 0 + s: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pool, pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, + BYTEPTR(dict), strlen(dict)) + check("compressobj with zdict OK", s != None, "compressobj with zdict failed") + + comp_data: BYTEPTR = s.compress(BYTEPTR(inp), + input_length, c.Addr(out_length)) + check("compress with zdict OK", comp_data != None, "compress with zdict failed") + printf(" Compressed with zdict: %zu bytes\n", out_length) + free(comp_data) + + flush_data: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush with zdict OK", flush_data != None, "flush with zdict failed") + printf(" Flush: %zu bytes\n", out_length) + free(flush_data) + + print_separator() + + total_comp: t.CSizeT = out_length + s.delete() + + s = pyzlib.compressobj(pool, pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + comp_no_dict: BYTEPTR = s.compress(BYTEPTR(inp), + input_length, c.Addr(out_length)) + flush_no_dict: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + no_dict_total: t.CSizeT = 0 + if comp_no_dict: no_dict_total += out_length + if flush_no_dict: no_dict_total += out_length + printf(" Without zdict: ~%zu bytes compressed\n", no_dict_total) + printf(" With zdict : %zu bytes compressed\n", total_comp) + free(comp_no_dict) + free(flush_no_dict) + s.delete() + + section_footer() + + +def test_huffman_tree(): + section_header("Huffman tree construction") + + printf(" --- Fixed Huffman tree (literal/lengthgth) ---\n") + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + + check("fixed lit tree count == 288", lit_tree.count == 288, "count mismatch") + check("fixed lit tree max_bits == 9", lit_tree.max_bits == 9, "max_bits mismatch") + + has_8bit: t.CInt = 0 + has_9bit: t.CInt = 0 + has_7bit: t.CInt = 0 + for i in range(143 + 1): + if lit_tree.codes[i].bits == 8: + has_8bit += 1 + for i in range(143 + 1, 255 + 1): + if lit_tree.codes[i].bits == 9: + has_9bit += 1 + for i in range(255 + 1, 279 + 1): + if lit_tree.codes[i].bits == 7: + has_7bit += 1 + check("0-143 are 8-bit", has_8bit == 144, "wrong count") + check("144-255 are 9-bit", has_9bit == 112, "wrong count") + check("256-279 are 7-bit", has_7bit == 24, "wrong count") + + printf(" 0-143: %d codes with 8 bits\n", has_8bit) + printf(" 144-255: %d codes with 9 bits\n", has_9bit) + printf(" 256-279: %d codes with 7 bits\n", has_7bit) + printf(" 280-287: 8-bit (end-of-block 256 = 7-bit)\n") + printf(" EOB (256): code=0x%X, bits=%d\n", lit_tree.codes[256].code, lit_tree.codes[256].bits) + + printf("\n --- Fixed Huffman tree (distance) ---\n") + dist_tree = zhuff.zhuff_tree() + dist_tree.build_fixed_dist_tree() + + check("fixed dist tree count == 32", dist_tree.count == 32, "count mismatch") + check("fixed dist tree max_bits == 5", dist_tree.max_bits == 5, "max_bits mismatch") + + all_5bit: t.CInt = 1 + for i in range(32): + if dist_tree.codes[i].bits != 5: + all_5bit = 0 + check("all 32 distance codes are 5-bit", all_5bit, "not all 5-bit") + printf(" All 32 distance codes: 5 bits each\n") + + printf("\n --- Dynamic Huffman tree from frequencies ---\n") + freqs: list[t.CInt, 256] + memset(freqs, 0, freqs.__sizeof__()) + freqs['A'] = 50 + freqs['B'] = 25 + freqs['C'] = 12 + freqs['D'] = 6 + freqs['E'] = 3 + freqs['F'] = 1 + freqs[256] = 1 + + dyn_tree = zhuff.zhuff_tree() + dyn_tree.build_codes(freqs, 257, 15) + + check("dynamic tree count == 257", dyn_tree.count == 257, "count mismatch") + check("dynamic tree max_bits <= 15", dyn_tree.max_bits <= 15, "max_bits overflow") + + total_codes: t.CInt = 0 + max_length_found: t.CInt = 0 + for i in range(257): + if dyn_tree.codes[i].bits > 0: + total_codes += 1 + if dyn_tree.codes[i].bits > max_length_found: + max_length_found = dyn_tree.codes[i].bits + check("dynamic tree has 7 active codes", total_codes == 7, "wrong active count") + check("dynamic tree max code lengthgth found <= 15", max_length_found <= 15, "code lengthgth overflow") + + printf(" Frequencies: A=50, B=25, C=12, D=6, E=3, F=1, EOB=1\n") + printf(" Active codes: %d, max code lengthgth: %d\n", total_codes, max_length_found) + + printf(" Code assignments:\n") + names: list[str, None] = ["A","B","C","D","E","F"] # 一个都是char* 的数组 + syms: list[t.CInt, None] = ['A','B','C','D','E','F'] + for i in range(6): + printf(" '%s' (freq=%3d): code=0x%04X, bits=%d\n", + names[i], freqs[syms[i]], + dyn_tree.codes[syms[i]].code, + dyn_tree.codes[syms[i]].bits) + + + + printf(" EOB (freq=1): code=0x%04X, bits=%d\n", + dyn_tree.codes[256].code, dyn_tree.codes[256].bits) + a_bits: t.CInt = dyn_tree.codes['A'].bits + f_bits: t.CInt = dyn_tree.codes['F'].bits + check("high-freq symbol has shorter code", a_bits <= f_bits, "A should be <= F") + printf(" High-freq 'A' (%d bits) <= low-freq 'F' (%d bits): %s\n", + a_bits, f_bits, "YES" if (a_bits <= f_bits) else "NO") + + printf("\n --- Huffman encode/decode roundtrip ---\n") + freqs: list[t.CInt, 288] + memset(freqs, 0, freqs.__sizeof__()) + freqs['H'] = 10 + freqs['e'] = 8 + freqs['l'] = 20 + freqs['o'] = 8 + freqs[' '] = 5 + freqs['W'] = 3 + freqs['r'] = 5 + freqs['d'] = 3 + freqs['!'] = 2 + freqs[256] = 1 + + enc_tree = zhuff.zhuff_tree() + enc_tree.build_codes(freqs, 257, 15) + + dec_tree = zhuff.zhuff_decode_tree() + dec_tree.build_decode_tree(c.Addr(enc_tree)) + + writer = zdef.zbit_writer() + + symbols: list[t.CInt, 16] + symbols[0] = 'H'; symbols[1] = 'e'; symbols[2] = 'l'; symbols[3] = 'l' + symbols[4] = 'o'; symbols[5] = ' '; symbols[6] = 'W'; symbols[7] = 'o' + symbols[8] = 'r'; symbols[9] = 'l'; symbols[10] = 'd'; symbols[11] = '!' + symbols[12] = 256 + num_symbols: t.CInt = 13 + + for i in range(num_symbols): + enc_tree.encode_symbol(symbols[i], c.Addr(writer)) + + reader = zdef.zbit_reader() + reader.buf = writer.buf + reader.length = writer.byte_pos + (1 if (writer.bit_pos > 0) else 0) + reader.byte_pos = 0 + reader.bit_pos = 0 + + roundtrip_ok: t.CInt = 1 + for i in range(num_symbols): + decoded: t.CInt = dec_tree.decode_symbol(c.Addr(reader)) + if decoded != symbols[i]: + roundtrip_ok = 0 + printf(" MISMATCH at symbol %d: expected %d, got %d\n", i, symbols[i], decoded) + break + check("encode/decode roundtrip matches", roundtrip_ok, "roundtrip failed") + printf(" Encoded %d symbols into %zu bytes, decoded all correctly\n", + num_symbols, writer.byte_pos + (1 if (writer.bit_pos > 0) else 0)) + + free(writer.buf) + + printf("\n --- Overflow handling (many symbols, limited max_bits) ---\n") + freqs: list[t.CInt, 256] + for i in range(256): + freqs[i] = 1 + freqs[256] = 1 + + tree = zhuff.zhuff_tree() + tree.build_codes(freqs, 257, 15) + + overflow_ok: t.CInt = 1 + for i in range(257): + if tree.codes[i].bits > 15 or tree.codes[i].bits < 0: + overflow_ok = 0 + break + check("all code lengthgths <= 15 with 257 symbols", overflow_ok, "code lengthgth overflow") + + bl_count: list[t.CInt, 16] = [0] + for i in range(257): + if tree.codes[i].bits > 0: + bl_count[tree.codes[i].bits] += 1 + printf(" Code lengthgth distribution (257 equal-freq symbols, max_bits=15):\n") + for i in range(1, 15 + 1): + if bl_count[i] > 0: + printf(" %2d bits: %3d codes\n", i, bl_count[i]) + + dt = zhuff.zhuff_decode_tree() + dt.build_decode_tree(c.Addr(tree)) + + w = zdef.zbit_writer() + tree.encode_symbol(0, c.Addr(w)) + tree.encode_symbol(128, c.Addr(w)) + tree.encode_symbol(255, c.Addr(w)) + tree.encode_symbol(256, c.Addr(w)) + + r = zdef.zbit_reader() + r.buf = w.buf + r.length = w.byte_pos + (1 if (w.bit_pos > 0) else 0) + r.byte_pos = 0 + r.bit_pos = 0 + + s0: t.CInt = dt.decode_symbol(c.Addr(r)) + s1: t.CInt = dt.decode_symbol(c.Addr(r)) + s2: t.CInt = dt.decode_symbol(c.Addr(r)) + s3: t.CInt = dt.decode_symbol(c.Addr(r)) + + check("overflow roundtrip: symbol 0", s0 == 0, "decode mismatch") + check("overflow roundtrip: symbol 128", s1 == 128, "decode mismatch") + check("overflow roundtrip: symbol 255", s2 == 255, "decode mismatch") + check("overflow roundtrip: symbol 256 (EOB)", s3 == 256, "decode mismatch") + + free(w.buf) + + + printf("\n --- Kraft inequality check ---\n") + freqs: list[t.CInt, 256] + memset(freqs, 0, freqs.__sizeof__()) + freqs['X'] = 100 + freqs['Y'] = 50 + freqs['Z'] = 25 + freqs[256] = 1 + + tree = zhuff.zhuff_tree() + tree.build_codes(freqs, 257, 15) + + kraft_sum: t.CDouble = 0.0 + for i in range(257): + if tree.codes[i].bits > 0: + kraft_sum += 1.0 / (t.CDouble(ULONGLONG(1) << tree.codes[i].bits)) + check("Kraft inequality: sum <= 1.0", kraft_sum <= 1.0 + 1e-9, "Kraft violated") + printf(" Kraft sum = %.10f (must be <= 1.0)\n", kraft_sum) + + section_footer() + + +def test_error_handling(): + section_header("Error handling") + + out_length: t.CSizeT = 0 + printf(" Trying to decompress garbage data...\n") + + result: BYTEPTR = pyzlib.decompress(pool, BYTEPTR("garbage"), 7, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(out_length)) + check("decompress garbage returns None", result == None, "should have returned None") + printf(" Error code : %d\n", pyzlib.get_error_code()) + printf(" Error message: \"%s\"\n", pyzlib.get_error()) + check("error message set", strlen(pyzlib.get_error()) > 0, "error message is empty") + check("error code is set", pyzlib.get_error_code() != pyzlib.Z_OK, "error code is Z_OK") + + print_separator() + + pyzlib.clear_error() + check("clear error clears code", pyzlib.get_error_code() == 0, "error code not cleared") + printf(" After clear: code=%d, msg=\"%s\"\n", pyzlib.get_error_code(), pyzlib.get_error()) + + section_footer() + + +def test_constants(): + section_header("Constants") + printf(" Compression Levels:\n") + printf(" Z_NO_COMPRESSION = %d\n", pyzlib.Z_NO_COMPRESSION) + printf(" Z_BEST_SPEED = %d\n", pyzlib.Z_BEST_SPEED) + printf(" Z_BEST_COMPRESSION = %d\n", pyzlib.Z_BEST_COMPRESSION) + printf(" Z_DEFAULT_COMPRESSION = %d\n", pyzlib.Z_DEFAULT_COMPRESSION) + printf(" Methods:\n") + printf(" DEFLATED = %d\n", pyzlib.DEFLATED) + printf(" Flush Modes:\n") + printf(" Z_NO_FLUSH = %d\n", pyzlib.Z_NO_FLUSH) + printf(" Z_PARTIAL_FLUSH = %d\n", pyzlib.Z_PARTIAL_FLUSH) + printf(" Z_SYNC_FLUSH = %d\n", pyzlib.Z_SYNC_FLUSH) + printf(" Z_FULL_FLUSH = %d\n", pyzlib.Z_FULL_FLUSH) + printf(" Z_FINISH = %d\n", pyzlib.Z_FINISH) + printf(" Z_BLOCK = %d\n", pyzlib.Z_BLOCK) + printf(" Z_TREES = %d\n", pyzlib.Z_TREES) + printf(" Strategies:\n") + printf(" Z_DEFAULT_STRATEGY = %d\n", pyzlib.Z_DEFAULT_STRATEGY) + printf(" Z_FILTERED = %d\n", pyzlib.Z_FILTERED) + printf(" Z_HUFFMAN_ONLY = %d\n", pyzlib.Z_HUFFMAN_ONLY) + printf(" Z_RLE = %d\n", pyzlib.Z_RLE) + printf(" Z_FIXED = %d\n", pyzlib.Z_FIXED) + printf(" Return Codes:\n") + printf(" Z_OK = %d\n", pyzlib.Z_OK) + printf(" Z_STREAM_END = %d\n", pyzlib.Z_STREAM_END) + printf(" Z_NEED_DICT = %d\n", pyzlib.Z_NEED_DICT) + printf(" Z_ERRNO = %d\n", pyzlib.Z_ERRNO) + printf(" Z_STREAM_ERROR = %d\n", pyzlib.Z_STREAM_ERROR) + printf(" Z_DATA_ERROR = %d\n", pyzlib.Z_DATA_ERROR) + printf(" Z_MEM_ERROR = %d\n", pyzlib.Z_MEM_ERROR) + printf(" Z_BUF_ERROR = %d\n", pyzlib.Z_BUF_ERROR) + printf(" Z_VERSION_ERROR = %d\n", pyzlib.Z_VERSION_ERROR) + printf(" Window / Buffer:\n") + printf(" MAX_WBITS = %d\n", pyzlib.MAX_WBITS) + printf(" DEF_BUF_SIZE = %d\n", pyzlib.DEF_BUF_SIZE) + printf(" DEF_MEM_LEVEL = %d\n", pyzlib.DEF_MEM_LEVEL) + section_footer() + + +def main123456() -> t.CInt: + printf("==============================================\n") + printf(" Python zlib - C Implementation Tests\n") + printf("==============================================\n") + + test_constants() + test_version() + test_compress_decompress() + test_compress_levels() + test_compressobj() + test_decompressobj() + test_decompressobj_max_lengthgth() + test_decompressobj_unused_data() + test_compress_copy() + test_decompress_copy() + test_adler32() + test_crc32() + test_empty_compress() + test_gzip_format() + test_raw_deflate() + test_zdict() + test_huffman_tree() + test_error_handling() + + printf("\n==============================================\n") + printf(" Results: %d passed, %d failed\n", test_passed, test_failed) + printf("==============================================\n") + + return 1 if test_failed > 0 else 0 diff --git a/Test/TestProject/output/067c78e9f121dce3.deps.json b/Test/TestProject/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..52dd90d --- /dev/null +++ b/Test/TestProject/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/TestProject/output/0d13cde396f4a15f.deps.json b/Test/TestProject/output/0d13cde396f4a15f.deps.json new file mode 100644 index 0000000..d33054c --- /dev/null +++ b/Test/TestProject/output/0d13cde396f4a15f.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f"} \ No newline at end of file diff --git a/Test/TestProject/output/0d4517fd5afeb330.deps.json b/Test/TestProject/output/0d4517fd5afeb330.deps.json new file mode 100644 index 0000000..6a762c7 --- /dev/null +++ b/Test/TestProject/output/0d4517fd5afeb330.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330"} \ No newline at end of file diff --git a/Test/TestProject/output/29813d57621099a9.deps.json b/Test/TestProject/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/2d7f623c6e3004ce.deps.json b/Test/TestProject/output/2d7f623c6e3004ce.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/2d7f623c6e3004ce.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/2e756dd336749fc2.deps.json b/Test/TestProject/output/2e756dd336749fc2.deps.json new file mode 100644 index 0000000..4690763 --- /dev/null +++ b/Test/TestProject/output/2e756dd336749fc2.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/3d1656b26b38b359.deps.json b/Test/TestProject/output/3d1656b26b38b359.deps.json new file mode 100644 index 0000000..12b6ecc --- /dev/null +++ b/Test/TestProject/output/3d1656b26b38b359.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/3ee89b588a1da94f.deps.json b/Test/TestProject/output/3ee89b588a1da94f.deps.json new file mode 100644 index 0000000..942ae4b --- /dev/null +++ b/Test/TestProject/output/3ee89b588a1da94f.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/3f7c5e78d8652535.deps.json b/Test/TestProject/output/3f7c5e78d8652535.deps.json new file mode 100644 index 0000000..81827d5 --- /dev/null +++ b/Test/TestProject/output/3f7c5e78d8652535.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/439f5b503003443f.deps.json b/Test/TestProject/output/439f5b503003443f.deps.json new file mode 100644 index 0000000..1932abc --- /dev/null +++ b/Test/TestProject/output/439f5b503003443f.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/4638d411fd53fef0.deps.json b/Test/TestProject/output/4638d411fd53fef0.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/4638d411fd53fef0.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/58121a0fb0ca7466.deps.json b/Test/TestProject/output/58121a0fb0ca7466.deps.json new file mode 100644 index 0000000..c84d4ea --- /dev/null +++ b/Test/TestProject/output/58121a0fb0ca7466.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/5a6a2137958c28c5.deps.json b/Test/TestProject/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..5d7d4f0 --- /dev/null +++ b/Test/TestProject/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestProject/output/68c4fe4b12c908e3.deps.json b/Test/TestProject/output/68c4fe4b12c908e3.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/68c4fe4b12c908e3.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/6aee24fdefa3cbc0.deps.json b/Test/TestProject/output/6aee24fdefa3cbc0.deps.json new file mode 100644 index 0000000..12b6ecc --- /dev/null +++ b/Test/TestProject/output/6aee24fdefa3cbc0.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/72e2d5ccb7cedcf1.deps.json b/Test/TestProject/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..f57fb55 --- /dev/null +++ b/Test/TestProject/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1"} \ No newline at end of file diff --git a/Test/TestProject/output/7e4cef8dd61984f0.deps.json b/Test/TestProject/output/7e4cef8dd61984f0.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/7e4cef8dd61984f0.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/88e3e48eab9e1653.deps.json b/Test/TestProject/output/88e3e48eab9e1653.deps.json new file mode 100644 index 0000000..81827d5 --- /dev/null +++ b/Test/TestProject/output/88e3e48eab9e1653.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653"} \ No newline at end of file diff --git a/Test/TestProject/output/8e0d8fdba991b3b4.deps.json b/Test/TestProject/output/8e0d8fdba991b3b4.deps.json new file mode 100644 index 0000000..ad7c768 --- /dev/null +++ b/Test/TestProject/output/8e0d8fdba991b3b4.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/94496ec50b0d13fc.deps.json b/Test/TestProject/output/94496ec50b0d13fc.deps.json new file mode 100644 index 0000000..e296236 --- /dev/null +++ b/Test/TestProject/output/94496ec50b0d13fc.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc"} \ No newline at end of file diff --git a/Test/TestProject/output/a9fa0f6200c09e65.deps.json b/Test/TestProject/output/a9fa0f6200c09e65.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/a9fa0f6200c09e65.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/abf9ce3160c9279e.deps.json b/Test/TestProject/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..9c8f69c --- /dev/null +++ b/Test/TestProject/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/TestProject/output/b0267503e816efc4.deps.json b/Test/TestProject/output/b0267503e816efc4.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/b0267503e816efc4.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/ba2e1c2dfc8e2f85.deps.json b/Test/TestProject/output/ba2e1c2dfc8e2f85.deps.json new file mode 100644 index 0000000..7338a29 --- /dev/null +++ b/Test/TestProject/output/ba2e1c2dfc8e2f85.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3ee89b588a1da94f", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2"} \ No newline at end of file diff --git a/Test/TestProject/output/bbdf3bbd4c3bc28c.deps.json b/Test/TestProject/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..5d7d4f0 --- /dev/null +++ b/Test/TestProject/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestProject/output/c3eb91093118e1e1.deps.json b/Test/TestProject/output/c3eb91093118e1e1.deps.json new file mode 100644 index 0000000..827d74a --- /dev/null +++ b/Test/TestProject/output/c3eb91093118e1e1.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "c3eb91093118e1e1", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/c9f4be41ca1cc2b4.deps.json b/Test/TestProject/output/c9f4be41ca1cc2b4.deps.json new file mode 100644 index 0000000..12b6ecc --- /dev/null +++ b/Test/TestProject/output/c9f4be41ca1cc2b4.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a"} \ No newline at end of file diff --git a/Test/TestProject/output/d282a7cb3385ecf0.deps.json b/Test/TestProject/output/d282a7cb3385ecf0.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/d282a7cb3385ecf0.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/f9629b8eb4ebdcc2.deps.json b/Test/TestProject/output/f9629b8eb4ebdcc2.deps.json new file mode 100644 index 0000000..94efaa6 --- /dev/null +++ b/Test/TestProject/output/f9629b8eb4ebdcc2.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TestProject/output/fa3691e66b426950.deps.json b/Test/TestProject/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..5d7d4f0 --- /dev/null +++ b/Test/TestProject/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"hashlib.__sha1": "0d13cde396f4a15f", "__sha1": "0d13cde396f4a15f", "hashlib.__sha256": "0d4517fd5afeb330", "__sha256": "0d4517fd5afeb330", "zlib.zdeflate": "2d7f623c6e3004ce", "zdeflate": "2d7f623c6e3004ce", "test_numpy": "2e756dd336749fc2", "binascii": "3d1656b26b38b359", "BINASCII": "3d1656b26b38b359", "vipermath": "3f7c5e78d8652535", "test_zlib": "439f5b503003443f", "zlib.zchecksum": "4638d411fd53fef0", "zchecksum": "4638d411fd53fef0", "stdint": "56cdd754a8a09347", "main": "58121a0fb0ca7466", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "mpool": "68c4fe4b12c908e3", "string": "6aee24fdefa3cbc0", "stdio": "73edbcf76e32d00b", "stdlib": "7538e542cab4c1d5", "base64": "7e4cef8dd61984f0", "hashlib.__sha512": "88e3e48eab9e1653", "__sha512": "88e3e48eab9e1653", "config": "8e0d8fdba991b3b4", "hashlib.__md5": "94496ec50b0d13fc", "__md5": "94496ec50b0d13fc", "hashlib.__init__": "96837bcc64032444", "__init__": "96837bcc64032444", "hashlib": "96837bcc64032444", "zlib.zdef": "a9fa0f6200c09e65", "zdef": "a9fa0f6200c09e65", "zlib.zhuff": "b0267503e816efc4", "zhuff": "b0267503e816efc4", "HASHLIB": "ba2e1c2dfc8e2f85", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "numpy.__init__": "c3eb91093118e1e1", "numpy": "c3eb91093118e1e1", "viperio": "c9f4be41ca1cc2b4", "zlib.pyzlib": "d282a7cb3385ecf0", "pyzlib": "d282a7cb3385ecf0", "zlib.zinflate": "f9629b8eb4ebdcc2", "zinflate": "f9629b8eb4ebdcc2", "HASHLIB.__init__": "96837bcc64032444", "HASHLIB.__md5": "94496ec50b0d13fc", "HASHLIB.__sha1": "0d13cde396f4a15f", "HASHLIB.__sha256": "0d4517fd5afeb330", "HASHLIB.__sha512": "88e3e48eab9e1653", "zlib.__init__": "d63d2c2a2bd9bd2a", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestProject/project.json b/Test/TestProject/project.json new file mode 100644 index 0000000..d8ccb56 --- /dev/null +++ b/Test/TestProject/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "TestProject", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "TestProject.exe" + }, + "includes": [ + "./includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/TestProject/temp/067c78e9f121dce3.pyi b/Test/TestProject/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/TestProject/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/TestProject/temp/0d13cde396f4a15f.pyi b/Test/TestProject/temp/0d13cde396f4a15f.pyi new file mode 100644 index 0000000..bc49415 --- /dev/null +++ b/Test/TestProject/temp/0d13cde396f4a15f.pyi @@ -0,0 +1,29 @@ +""" +Auto-generated Python stub file from hashlib.__sha1.py +Module: hashlib.__sha1 +""" + + +import t, c + +SHA1_BLOCK_LEN: t.CDefine = 64 +SHA1_DIGEST_LEN: t.CDefine = 20 + +def sha1_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: pass + +def sha1_f1(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: pass + +def sha1_f2(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: pass + +def sha1_f3(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: pass + + +@t.Object +class sha1: + state: list[t.CUInt32T, 5] + count: t.CUInt64T + buf: list[t.CUInt8T, SHA1_BLOCK_LEN] + def __init__(self: sha1) -> t.CInt: pass + def transform(self: sha1, block: t.CUInt8T | t.CPtr) -> t.CInt: pass + def update(self: sha1, s: str) -> t.CInt: pass + def final(self: sha1, out: list[t.CUInt8T, SHA1_DIGEST_LEN]) -> t.CInt: pass \ No newline at end of file diff --git a/Test/TestProject/temp/0d4517fd5afeb330.pyi b/Test/TestProject/temp/0d4517fd5afeb330.pyi new file mode 100644 index 0000000..00a5072 --- /dev/null +++ b/Test/TestProject/temp/0d4517fd5afeb330.pyi @@ -0,0 +1,34 @@ +""" +Auto-generated Python stub file from hashlib.__sha256.py +Module: hashlib.__sha256 +""" + + +import t, c + +SHA256_BLOCK_LEN: t.CDefine = 64 +SHA256_DIGEST_LEN: t.CDefine = 32 +sha256_K: t.CExtern | list[t.CUInt32T, 64] + +def s0(x: t.CUInt32T) -> t.CUInt32T: pass + +def s1(x: t.CUInt32T) -> t.CUInt32T: pass + +def S0(x: t.CUInt32T) -> t.CUInt32T: pass + +def S1(x: t.CUInt32T) -> t.CUInt32T: pass + +def Ch(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: pass + +def Maj(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: pass + + +@t.Object +class sha256: + state: list[t.CUInt32T, 8] + count: t.CUInt64T + buf: list[t.CUInt8T, SHA256_BLOCK_LEN] + def __init__(self: sha256) -> t.CInt: pass + def transform(self: sha256, block: t.CUInt8T | t.CPtr) -> t.CInt: pass + def update(self: sha256, s: str) -> t.CInt: pass + def final(self: sha256, out: list[t.CUInt8T, SHA256_DIGEST_LEN]) -> t.CInt: pass \ No newline at end of file diff --git a/Test/TestProject/temp/29813d57621099a9.pyi b/Test/TestProject/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/TestProject/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/TestProject/temp/2d7f623c6e3004ce.pyi b/Test/TestProject/temp/2d7f623c6e3004ce.pyi new file mode 100644 index 0000000..b464f63 --- /dev/null +++ b/Test/TestProject/temp/2d7f623c6e3004ce.pyi @@ -0,0 +1,57 @@ +""" +Auto-generated Python stub file from zlib.zdeflate.py +Module: zlib.zdeflate +""" + + +from stdint import * +import zlib.zchecksum as zchecksum +import zlib.zhuff as zhuff +import zlib.zdef as zdef +import string +import stdio +import mpool +import t, c + +@t.Object +class zdeflate_stream: + pool: mpool.MPool | t.CPtr + writer: zdef.zbit_writer + window: BYTE | t.CPtr + window_pos: t.CInt + window_size: t.CInt + hash_head: t.CInt | t.CPtr + hash_prev: t.CInt | t.CPtr + level: t.CInt + strategy: t.CInt + wbits: t.CInt + is_finished: t.CInt + adler: t.CUInt32T + def find_match(self: zdeflate_stream, data: BYTE | t.CPtr, data_len: t.CSizeT, pos: t.CSizeT, best_dist: t.CInt | t.CPtr) -> t.CInt: pass + def update_hash(self: zdeflate_stream, data: BYTE | t.CPtr, pos: t.CSizeT) -> t.CInt: pass + def write_fixed_block(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def encode_block_data(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, lit_tree: zhuff.zhuff_tree | t.CPtr, dist_tree: zhuff.zhuff_tree | t.CPtr) -> t.CInt: pass + def write_dynamic_block(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def compress_block(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def write_stored_block(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def compress(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: pass + def flush(self: zdeflate_stream, mode: t.CInt, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: pass + def set_dictionary(self: zdeflate_stream, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: pass + def copy(self: zdeflate_stream) -> zdeflate_stream | t.CPtr: pass + def destroy(self: zdeflate_stream) -> t.CInt: pass + +def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR, s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT) -> t.CInt: pass + +def zdeflate_hash(p: BYTE | t.CPtr) -> t.CUnsignedInt: pass + +def zdeflate_len_to_symbol(length: t.CInt) -> t.CInt: pass + +def zdeflate_dist_to_symbol(dist: t.CInt) -> t.CInt: pass + +def zdeflate_count_cl_freqs(all_lengths: INTPTR, total: t.CInt, cl_freqs: INTPTR) -> t.CInt: pass + +def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt, w: zdef.zbit_writer | t.CPtr, cl_tree: zhuff.zhuff_tree | t.CPtr) -> t.CInt: pass + +def zdeflate_create(pool: mpool.MPool | t.CPtr, level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: pass + +def zdeflate_one_shot(pool: mpool.MPool | t.CPtr, data: UINT8PTR, length: t.CSizeT, level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: pass diff --git a/Test/TestProject/temp/2e756dd336749fc2.pyi b/Test/TestProject/temp/2e756dd336749fc2.pyi new file mode 100644 index 0000000..90a5cdd --- /dev/null +++ b/Test/TestProject/temp/2e756dd336749fc2.pyi @@ -0,0 +1,108 @@ +""" +Auto-generated Python stub file from test_numpy.py +Module: test_numpy +""" + + +from stdint import * +import numpy +from stdio import printf +from stdlib import calloc, free +import string +import vipermath +import mpool +import t, c + +EPS: t.CExtern | t.CDouble +EPS_LOOSE: t.CExtern | t.CDouble +SIMD_BLOCK: t.CExtern | t.CSizeT +arena: t.CExtern | t.CUInt8T | t.CPtr +pool: t.CExtern | mpool.MPool | t.CPtr +test_passed: t.CExtern | t.CInt +test_failed: t.CExtern | t.CInt + +def check(name: str, condition: t.CInt, detail: str) -> t.CInt: pass + +def approx_eq(a: t.CDouble, b: t.CDouble) -> t.CInt: pass + +def approx_loose(a: t.CDouble, b: t.CDouble) -> t.CInt: pass + +def section_header(title: str) -> t.CInt: pass + +def section_footer() -> t.CInt: pass + +def vec4(p: mpool.MPool | t.CPtr, v0: t.CDouble, v1: t.CDouble, v2: t.CDouble, v3: t.CDouble) -> numpy.ndarray | t.CPtr: pass + +def vec3(p: mpool.MPool | t.CPtr, v0: t.CDouble, v1: t.CDouble, v2: t.CDouble) -> numpy.ndarray | t.CPtr: pass + +def vec2(p: mpool.MPool | t.CPtr, v0: t.CDouble, v1: t.CDouble) -> numpy.ndarray | t.CPtr: pass + +def test_zeros_ones() -> t.CInt: pass + +def test_arange_linspace() -> t.CInt: pass + +def test_eye_diag() -> t.CInt: pass + +def test_sum_mean_min_max() -> t.CInt: pass + +def test_fill_copy() -> t.CInt: pass + +def test_add_sub_mul_div() -> t.CInt: pass + +def test_neg() -> t.CInt: pass + +def test_len() -> t.CInt: pass + +def test_scalar_ops() -> t.CInt: pass + +def test_math_funcs() -> t.CInt: pass + +def test_matmul() -> t.CInt: pass + +def test_dot() -> t.CInt: pass + +def test_transpose() -> t.CInt: pass + +def test_var_std_norm() -> t.CInt: pass + +def test_clip_concatenate() -> t.CInt: pass + +def test_sort_reverse() -> t.CInt: pass + +def test_print_arr() -> t.CInt: pass + +def test_floordiv_mod() -> t.CInt: pass + +def test_additional_math() -> t.CInt: pass + +def test_trig_hyperbolic() -> t.CInt: pass + +def test_degrees_radians() -> t.CInt: pass + +def test_cumsum_diff() -> t.CInt: pass + +def test_max_min_where() -> t.CInt: pass + +def test_flatten_trace() -> t.CInt: pass + +def test_outer() -> t.CInt: pass + +def test_bool_comparison() -> t.CInt: pass + +def test_linalg() -> t.CInt: pass + +def test_additional_creation() -> t.CInt: pass + +def test_interp() -> t.CInt: pass + +def test_numpy_edge() -> t.CInt: pass + +def bench_numpy_perf() -> t.CInt: pass + +def test_numpy_correct() -> t.CInt: pass + +def test_numpy_edge_main() -> t.CInt: pass + +def bench_numpy_main() -> t.CInt: pass + +def test_numpy_main() -> t.CInt: pass diff --git a/Test/TestProject/temp/3d1656b26b38b359.pyi b/Test/TestProject/temp/3d1656b26b38b359.pyi new file mode 100644 index 0000000..6b4a08a --- /dev/null +++ b/Test/TestProject/temp/3d1656b26b38b359.pyi @@ -0,0 +1,46 @@ +""" +Auto-generated Python stub file from binascii.py +Module: binascii +""" + + +import t, c +import stdint + +HEX_CHARS: t.CExtern | list[t.CChar, None] +HEX_VALS: t.CExtern | list[t.CInt, 256] +B64_CHARS: t.CExtern | list[t.CChar, None] +B64_VALS: t.CExtern | list[t.CInt, 256] +HQX_CHARS: t.CExtern | list[t.CChar, 64] +HQX_VALS: t.CExtern | list[t.CInt, 256] +UU_CHARS: t.CExtern | list[t.CChar, None] +CRC32_TABLE: t.CExtern | list[t.CUnsignedInt, 256] +CRC_HQX_TABLE: t.CExtern | list[t.CUnsignedShort, 256] + +def init_binascii() -> t.CInt: pass + +def crc32(data: str, length: t.CInt, crc: t.CUnsignedInt) -> t.CUnsignedInt: pass + +def crc_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort) -> t.CUnsignedShort: pass + +def hexlify(data: str, length: t.CInt) -> str: pass + +def b2a_hex(data: str, length: t.CInt) -> str: pass + +def a2b_hex(hexstr: str, length: t.CInt) -> str: pass + +def unhexlify(data: str, length: t.CInt) -> t.CInt: pass + +def b2a_base64(data: str, length: t.CInt) -> str: pass + +def a2b_base64(data: str, length: t.CInt) -> str: pass + +def b2a_uu(data: str, length: t.CInt) -> str: pass + +def a2b_uu(data: str) -> str: pass + +def b2a_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort) -> tuple[str, t.CUnsignedShort]: pass + +def a2b_hqx(data: str, crc: t.CUnsignedShort) -> tuple[str, t.CUnsignedShort]: pass + +def adler32(data: str, length: t.CInt, adler: t.CUnsignedInt) -> t.CUnsignedInt: pass diff --git a/Test/TestProject/temp/3ee89b588a1da94f.pyi b/Test/TestProject/temp/3ee89b588a1da94f.pyi new file mode 100644 index 0000000..ed878e4 --- /dev/null +++ b/Test/TestProject/temp/3ee89b588a1da94f.pyi @@ -0,0 +1,13 @@ +""" +Auto-generated Python stub file from BINASCII.py +Module: BINASCII +""" + + +import stdio +import stdlib +import string +import binascii +import t, c + +def main222() -> t.CInt: pass diff --git a/Test/TestProject/temp/3f7c5e78d8652535.pyi b/Test/TestProject/temp/3f7c5e78d8652535.pyi new file mode 100644 index 0000000..abe01c2 --- /dev/null +++ b/Test/TestProject/temp/3f7c5e78d8652535.pyi @@ -0,0 +1,128 @@ +""" +Auto-generated Python stub file from vipermath.py +Module: vipermath +""" + + +import t, c + +U_M_PI: t.CDefine = 3.14159265358979323846 +U_M_E: t.CDefine = 2.71828182845904523536 +U_M_PI_2: t.CDefine = 1.57079632679489661923 +U_M_PI_4: t.CDefine = 0.78539816339744830962 +U_M_1_PI: t.CDefine = 0.31830988618379067154 +U_M_2_PI: t.CDefine = 0.63661977236758134308 +U_M_LN2: t.CDefine = 0.69314718055994530942 +U_M_LN10: t.CDefine = 2.30258509299404568402 +U_M_2_SQRT_PI: t.CDefine = 1.77245385090551602730 + +def radians(degrees: t.CDouble) -> t.CDouble: pass + +def degrees(radians: t.CDouble) -> t.CDouble: pass + +def sin(x: t.CDouble) -> t.CDouble: pass + +def cos(x: t.CDouble) -> t.CDouble: pass + +def tan(x: t.CDouble) -> t.CDouble: pass + +def asin(x: t.CDouble) -> t.CDouble: pass + +def acos(x: t.CDouble) -> t.CDouble: pass + +def _atan_core(x: t.CDouble) -> t.CDouble: pass + +def atan(x: t.CDouble) -> t.CDouble: pass + +def atan2(y: t.CDouble, x: t.CDouble) -> t.CDouble: pass + +def sinh(x: t.CDouble) -> t.CDouble: pass + +def cosh(x: t.CDouble) -> t.CDouble: pass + +def tanh(x: t.CDouble) -> t.CDouble: pass + +def exp(x: t.CDouble) -> t.CDouble: pass + +def log(x: t.CDouble) -> t.CDouble: pass + +def sqrt(x: t.CDouble) -> t.CDouble: pass + +def abs(x: t.CInt) -> t.CInt: pass + +def fabs(x: t.CDouble) -> t.CDouble: pass + +def labs(x: t.CLong) -> t.CLong: pass + +def factorial(n: t.CInt) -> t.CDouble: pass + +def combination(n: t.CInt, k: t.CInt) -> t.CDouble: pass + +def permutation(n: t.CInt, k: t.CInt) -> t.CDouble: pass + +def pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass + +def powf(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass + +def cbrt(x: t.CDouble) -> t.CDouble: pass + +def hypot(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass + +def floor(x: t.CDouble) -> t.CDouble: pass + +def ceil(x: t.CDouble) -> t.CDouble: pass + +def round(x: t.CDouble) -> t.CDouble: pass + +def trunc(x: t.CDouble) -> t.CDouble: pass + +def fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble: pass + +def fmodf(x: float, y: float) -> float: pass + +def modf(x: t.CDouble, iptr: t.CDouble | t.CPtr) -> t.CDouble: pass + +def log10(x: t.CDouble) -> t.CDouble: pass + +def log2(x: t.CDouble) -> t.CDouble: pass + +def exp2(x: t.CDouble) -> t.CDouble: pass + +def expm1(x: t.CDouble) -> t.CDouble: pass + +def log1p(x: t.CDouble) -> t.CDouble: pass + +def asinh(x: t.CDouble) -> t.CDouble: pass + +def acosh(x: t.CDouble) -> t.CDouble: pass + +def atanh(x: t.CDouble) -> t.CDouble: pass + +def gamma(x: t.CDouble) -> t.CDouble: pass + +def erf(x: t.CDouble) -> t.CDouble: pass + +def erfc(x: t.CDouble) -> t.CDouble: pass + +def sqrtf(x: t.CFloat) -> t.CFloat: pass + +def sinf(x: t.CFloat) -> t.CFloat: pass + +def cosf(x: t.CFloat) -> t.CFloat: pass + +def tanf(x: t.CFloat) -> t.CFloat: pass + +def fabsf(x: t.CFloat) -> t.CFloat: pass + +def floorf(x: t.CFloat) -> t.CFloat: pass + +def ceilf(x: t.CFloat) -> t.CFloat: pass + + +class _U(t.CUnion): + d: t.CDouble + u: t.CUInt64T + +def isnan(x: t.CDouble) -> t.CStatic | t.CInt: pass + +def isinf(x: t.CDouble) -> t.CStatic | t.CInt: pass diff --git a/Test/TestProject/temp/439f5b503003443f.pyi b/Test/TestProject/temp/439f5b503003443f.pyi new file mode 100644 index 0000000..259fce6 --- /dev/null +++ b/Test/TestProject/temp/439f5b503003443f.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from test_zlib.py +Module: test_zlib +""" + + +from stdint import * +import zlib.pyzlib as pyzlib +import zlib.zhuff as zhuff +import zlib.zdef as zdef +from stdio import printf, strlen +import stdlib +import string +import mpool +import t, c + +pool: t.CExtern | mpool.MPool | t.CPtr +test_passed: t.CExtern | t.CInt +test_failed: t.CExtern | t.CInt + +def check(name: str, condition: t.CInt, detail: str) -> t.CInt: pass + +def print_hex_test(data: BYTEPTR, length: t.CSizeT, max_show: t.CSizeT) -> t.CInt: pass + +def print_separator() -> t.CInt: pass + +def section_header(title: str) -> t.CInt: pass + +def section_footer() -> t.CInt: pass + +def test_version() -> t.CInt: pass + +def test_compress_decompress() -> t.CInt: pass + +def test_compress_levels() -> t.CInt: pass + +def test_compressobj() -> t.CInt: pass + +def test_decompressobj() -> t.CInt: pass + +def test_decompressobj_max_lengthgth() -> t.CInt: pass + +def test_decompressobj_unused_data() -> t.CInt: pass + +def test_compress_copy() -> t.CInt: pass + +def test_decompress_copy() -> t.CInt: pass + +def test_adler32() -> t.CInt: pass + +def test_crc32() -> t.CInt: pass + +def test_empty_compress() -> t.CInt: pass + +def test_gzip_format() -> t.CInt: pass + +def test_raw_deflate() -> t.CInt: pass + +def test_zdict() -> t.CInt: pass + +def test_huffman_tree() -> t.CInt: pass + +def test_error_handling() -> t.CInt: pass + +def test_constants() -> t.CInt: pass + +def main123456() -> t.CInt: pass diff --git a/Test/TestProject/temp/4638d411fd53fef0.pyi b/Test/TestProject/temp/4638d411fd53fef0.pyi new file mode 100644 index 0000000..d46797d --- /dev/null +++ b/Test/TestProject/temp/4638d411fd53fef0.pyi @@ -0,0 +1,15 @@ +""" +Auto-generated Python stub file from zlib.zchecksum.py +Module: zlib.zchecksum +""" + + +from stdint import * +import t, c + +def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T: pass + + +crc32_table: t.CExtern | list[t.CUInt32T, 256] + +def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T: pass diff --git a/Test/TestProject/temp/56cdd754a8a09347.pyi b/Test/TestProject/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/TestProject/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/TestProject/temp/58121a0fb0ca7466.pyi b/Test/TestProject/temp/58121a0fb0ca7466.pyi new file mode 100644 index 0000000..7f61fb6 --- /dev/null +++ b/Test/TestProject/temp/58121a0fb0ca7466.pyi @@ -0,0 +1,17 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +from stdint import * +import w32.win32console +import config +import HASHLIB +import BINASCII +import zlib.pyzlib as zp +import test_zlib as tpz +import test_numpy as tn +import t, c + +def main() -> t.CInt | t.CExport: pass diff --git a/Test/TestProject/temp/5a6a2137958c28c5.pyi b/Test/TestProject/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/TestProject/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/TestProject/temp/68c4fe4b12c908e3.pyi b/Test/TestProject/temp/68c4fe4b12c908e3.pyi new file mode 100644 index 0000000..fc2010b --- /dev/null +++ b/Test/TestProject/temp/68c4fe4b12c908e3.pyi @@ -0,0 +1,50 @@ +""" +Auto-generated Python stub file from mpool.py +Module: mpool +""" + + +import t, c +from stdint import * +import viperio +import string + +MPOOL_ALIGN: t.CDefine = 8 +MPOOL_TYPE_SLAB: t.CDefine = 0 +MPOOL_TYPE_BUMP: t.CDefine = 2 + +def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: pass + + +class MPool: + mtype: t.CInt + mem: t.CVoid | t.CPtr + mem_size: t.CSizeT + offset: t.CSizeT + high_water: t.CSizeT + block_size: t.CSizeT + block_count: t.CSizeT + used_count: t.CSizeT + free_list: t.CVoid | t.CPtr + alloc_map: t.CUInt8T | t.CPtr + alloc_map_size: t.CSizeT + def __init__(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def _init_bump(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> t.CInt: pass + def _init_slab(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CInt: pass + def __enter__(self: MPool) -> 'MPool' | t.CPtr: pass + def __exit__(self: MPool) -> t.CInt: pass + def _slab_reset(self: MPool) -> t.CInt: pass + def alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def alloc_buf(self: MPool, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: pass + def free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + def realloc(self: MPool, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, new_size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def reset(self: MPool) -> t.CInt: pass + def _bump_alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def _slab_alloc(self: MPool) -> t.CVoid | t.CPtr: pass + def _slab_free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CInt: pass + +def bump_create(mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> MPool | t.CPtr: pass + +def alloc(pool: MPool | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def reset(pool: MPool | t.CPtr) -> t.CInt: pass diff --git a/Test/TestProject/temp/6aee24fdefa3cbc0.pyi b/Test/TestProject/temp/6aee24fdefa3cbc0.pyi new file mode 100644 index 0000000..c17475f --- /dev/null +++ b/Test/TestProject/temp/6aee24fdefa3cbc0.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def atoll(src: str) -> t.CInt64T: pass + +def atof(src: str) -> t.CDouble: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/TestProject/temp/72e2d5ccb7cedcf1.pyi b/Test/TestProject/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/TestProject/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/TestProject/temp/73edbcf76e32d00b.pyi b/Test/TestProject/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/TestProject/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/TestProject/temp/7538e542cab4c1d5.pyi b/Test/TestProject/temp/7538e542cab4c1d5.pyi new file mode 100644 index 0000000..b5313af --- /dev/null +++ b/Test/TestProject/temp/7538e542cab4c1d5.pyi @@ -0,0 +1,18 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def calloc(nmemb: UINT, size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/TestProject/temp/7e4cef8dd61984f0.pyi b/Test/TestProject/temp/7e4cef8dd61984f0.pyi new file mode 100644 index 0000000..d5c249f --- /dev/null +++ b/Test/TestProject/temp/7e4cef8dd61984f0.pyi @@ -0,0 +1,15 @@ +""" +Auto-generated Python stub file from base64.py +Module: base64 +""" + + +import binascii +import t, c + +b64_tab: t.CExtern | list[t.CChar, None] +b64_dec_tab: t.CExtern | list[t.CInt8T, 80] + +def b64encode(s: str, out: str) -> t.CSizeT: pass + +def b64decode(s: str, out: t.CUInt8T | t.CPtr) -> t.CSizeT: pass diff --git a/Test/TestProject/temp/88e3e48eab9e1653.pyi b/Test/TestProject/temp/88e3e48eab9e1653.pyi new file mode 100644 index 0000000..225c287 --- /dev/null +++ b/Test/TestProject/temp/88e3e48eab9e1653.pyi @@ -0,0 +1,39 @@ +""" +Auto-generated Python stub file from hashlib.__sha512.py +Module: hashlib.__sha512 +""" + + +import t, c + +SHA512_BLOCK_LEN: t.CDefine = 128 +SHA512_DIGEST_LEN: t.CDefine = 64 + +def sha512_ror(x: t.CUInt64T, n: int) -> t.CUInt64T: pass + +def sha512_shr(x: t.CUInt64T, n: int) -> t.CUInt64T: pass + +def sha512_Ch(x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: pass + +def sha512_Maj(x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: pass + +def sha512_BigSigma0(x: t.CUInt64T) -> t.CUInt64T: pass + +def sha512_BigSigma1(x: t.CUInt64T) -> t.CUInt64T: pass + +def sha512_Sigma0(x: t.CUInt64T) -> t.CUInt64T: pass + +def sha512_Sigma1(x: t.CUInt64T) -> t.CUInt64T: pass + + +sha512_K: t.CExtern | list[t.CUInt64T, 80] + +@t.Object +class sha512: + state: list[t.CUInt64T, 8] + count: list[t.CUInt64T, 2] + buf: list[t.CUInt8T, SHA512_BLOCK_LEN] + def __init__(self: sha512) -> t.CInt: pass + def transform(self: sha512, block: list[t.CUInt8T, SHA512_BLOCK_LEN]) -> t.CInt: pass + def update(self: sha512, s: str) -> t.CInt: pass + def final(self: sha512, out: list[t.CUInt8T, SHA512_DIGEST_LEN]) -> t.CInt: pass \ No newline at end of file diff --git a/Test/TestProject/temp/8e0d8fdba991b3b4.pyi b/Test/TestProject/temp/8e0d8fdba991b3b4.pyi new file mode 100644 index 0000000..b09d9e4 --- /dev/null +++ b/Test/TestProject/temp/8e0d8fdba991b3b4.pyi @@ -0,0 +1,25 @@ +""" +Auto-generated Python stub file from config.py +Module: config +""" + + +import stdint +import t, c + +A: t.CExtern | t.CChar | t.CPtr + +class BIT_TEST(t.Object): + a: t.CInt | t.Bit(1) + b: t.CInt | t.Bit(1) + c: t.CInt | t.Bit(1) + d: t.CInt | t.Bit(5) +class OOP_TEST(t.Object): + a: t.CInt + def __init__(self: OOP_TEST) -> t.CInt: pass + def __call__(self: OOP_TEST) -> stdint.UINT: pass +class ENUM_TEST(t.CEnum): + A: t.State + B: t.State + C: t.State + Len: t.State \ No newline at end of file diff --git a/Test/TestProject/temp/94496ec50b0d13fc.pyi b/Test/TestProject/temp/94496ec50b0d13fc.pyi new file mode 100644 index 0000000..69888a2 --- /dev/null +++ b/Test/TestProject/temp/94496ec50b0d13fc.pyi @@ -0,0 +1,34 @@ +""" +Auto-generated Python stub file from hashlib.__md5.py +Module: hashlib.__md5 +""" + + +import t, c + +MD5_BLOCK_LEN: t.CDefine = 64 # 分组块大小 +MD5_DIGEST_LEN: t.CDefine = 16 # 摘要输出长度 + +def md5_F(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: pass + +def md5_G(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: pass + +def md5_H(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: pass + +def md5_I(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: pass + +def md5_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: pass + + +md5_T: t.CExtern | list[t.CUInt32T, 64] +md5_S: t.CExtern | list[t.CInt, 64] + +@t.Object +class md5: + state: list[t.CUInt32T, 4] + count: t.CUInt64T + buf: list[t.CUInt8T, MD5_BLOCK_LEN] + def __init__(self: md5) -> t.CInt: pass + def transform(self: md5, block: t.CUInt8T | t.CPtr) -> t.CInt: pass + def update(self: md5, s: str) -> t.CInt: pass + def final(self: md5, out: list[t.CUInt8T, MD5_DIGEST_LEN]) -> t.CInt: pass \ No newline at end of file diff --git a/Test/TestProject/temp/96837bcc64032444.pyi b/Test/TestProject/temp/96837bcc64032444.pyi new file mode 100644 index 0000000..46e78bd --- /dev/null +++ b/Test/TestProject/temp/96837bcc64032444.pyi @@ -0,0 +1,13 @@ +""" +Auto-generated Python stub file from hashlib.__init__.py +Module: hashlib.__init__ +""" + +import t +import c + + +from .__md5 import md5, MD5_DIGEST_LEN +from .__sha1 import sha1, SHA1_DIGEST_LEN +from .__sha256 import sha256, SHA256_DIGEST_LEN +from .__sha512 import sha512, SHA512_DIGEST_LEN \ No newline at end of file diff --git a/Test/TestProject/temp/_sha1_map.txt b/Test/TestProject/temp/_sha1_map.txt new file mode 100644 index 0000000..634b5ca --- /dev/null +++ b/Test/TestProject/temp/_sha1_map.txt @@ -0,0 +1,29 @@ +0d13cde396f4a15f:includes/hashlib\__sha1.py +0d4517fd5afeb330:includes/hashlib\__sha256.py +2d7f623c6e3004ce:includes/zlib\zdeflate.py +2e756dd336749fc2:test_numpy.py +3d1656b26b38b359:includes/binascii.py +3ee89b588a1da94f:BINASCII.py +3f7c5e78d8652535:includes/vipermath.py +439f5b503003443f:test_zlib.py +4638d411fd53fef0:includes/zlib\zchecksum.py +56cdd754a8a09347:includes/stdint.py +58121a0fb0ca7466:main.py +5a6a2137958c28c5:includes/w32\win32base.py +68c4fe4b12c908e3:includes/mpool.py +6aee24fdefa3cbc0:includes/string.py +73edbcf76e32d00b:includes/stdio.py +7538e542cab4c1d5:includes/stdlib.py +7e4cef8dd61984f0:includes/base64.py +88e3e48eab9e1653:includes/hashlib\__sha512.py +8e0d8fdba991b3b4:config.py +94496ec50b0d13fc:includes/hashlib\__md5.py +96837bcc64032444:includes/hashlib\__init__.py +a9fa0f6200c09e65:includes/zlib\zdef.py +b0267503e816efc4:includes/zlib\zhuff.py +ba2e1c2dfc8e2f85:HASHLIB.py +bbdf3bbd4c3bc28c:includes/w32\win32console.py +c3eb91093118e1e1:includes/numpy\__init__.py +c9f4be41ca1cc2b4:includes/viperio.py +d282a7cb3385ecf0:includes/zlib\pyzlib.py +f9629b8eb4ebdcc2:includes/zlib\zinflate.py diff --git a/Test/TestProject/temp/_shared_sym.pkl b/Test/TestProject/temp/_shared_sym.pkl new file mode 100644 index 0000000..e38d1e8 Binary files /dev/null and b/Test/TestProject/temp/_shared_sym.pkl differ diff --git a/Test/TestProject/temp/a9fa0f6200c09e65.pyi b/Test/TestProject/temp/a9fa0f6200c09e65.pyi new file mode 100644 index 0000000..f9f328c --- /dev/null +++ b/Test/TestProject/temp/a9fa0f6200c09e65.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from zlib.zdef.py +Module: zlib.zdef +""" + + +from stdint import * +import stddef +import string +import stdlib +import mpool +import t, c + +ZDEFLATE_WINDOW_BITS: t.CDefine = 15 +ZDEFLATE_WINDOW_SIZE: t.CDefine = (1 << ZDEFLATE_WINDOW_BITS) +ZDEFLATE_WINDOW_MASK: t.CDefine = (ZDEFLATE_WINDOW_SIZE - 1) +ZDEFLATE_MIN_MATCH: t.CDefine = 3 +ZDEFLATE_MAX_MATCH: t.CDefine = 258 +ZDEFLATE_HASH_BITS: t.CDefine = 15 +ZDEFLATE_HASH_SIZE: t.CDefine = (1 << ZDEFLATE_HASH_BITS) +ZDEFLATE_HASH_MASK: t.CDefine = (ZDEFLATE_HASH_SIZE - 1) +ZDEFLATE_MAX_CODES: t.CDefine = 288 +ZDEFLATE_MAX_DIST_CODES: t.CDefine = 32 +ZDEFLATE_MAX_BITS: t.CDefine = 15 +ZDEFLATE_MAX_CODELEN_CODES: t.CDefine = 19 +ZDEFLATE_LIT_COUNT: t.CDefine = 286 +ZDEFLATE_DIST_COUNT: t.CDefine = 30 +ZDEFLATE_LEN_SYMBOLS_BASE: t.CDefine = 257 +ZDEFLATE_END_OF_BLOCK: t.CDefine = 256 +zdeflate_len_extra_bits: t.CExtern | list[t.CInt, 29] +zdeflate_len_base: t.CExtern | list[t.CInt, 29] +zdeflate_dist_extra_bits: t.CExtern | list[t.CInt, 30] +zdeflate_dist_base: t.CExtern | list[t.CInt, 30] +zdeflate_codelen_order: t.CExtern | list[int, 19] + +@t.Object +class zbit_writer: + pool: mpool.MPool | t.CPtr + buf: BYTE | t.CPtr + cap: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + def __init__(self: zbit_writer, pool: mpool.MPool | t.CPtr) -> t.CInt: pass + def ensure(self: zbit_writer, need: t.CSizeT) -> t.CInt: pass + def write_bits(self: zbit_writer, value: UINT, nbits: t.CInt) -> t.CInt: pass + def write_bits_rev(self: zbit_writer, code: UINT, nbits: t.CInt) -> t.CInt: pass + def stored_block(self: zbit_writer, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def write_zlib_header(self: zbit_writer, wbits: t.CInt, level: t.CInt) -> t.CInt: pass + def write_gzip_header(self: zbit_writer) -> t.CInt: pass + def align(self: zbit_writer) -> t.CInt: pass + def total(self: zbit_writer) -> t.CSizeT: pass + def free(self: zbit_writer) -> t.CInt: pass + def __del__(self: zbit_writer) -> t.CInt: pass +@t.Object +class zbit_reader: + buf: BYTE | t.CPtr + length: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + def init(self: zbit_reader, buf: BYTE | t.CPtr, length: t.CSizeT) -> t.CInt: pass + def read_bits(self: zbit_reader, nbits: t.CInt, out: UINTPTR) -> t.CInt: pass + def read_bits_rev(self: zbit_reader, nbits: t.CInt, out: UINTPTR) -> t.CInt: pass + def align(self: zbit_reader) -> t.CInt: pass + +def zdef_alloc(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> VOIDPTR: pass + +def zdef_free(pool: mpool.MPool | t.CPtr, p: VOIDPTR) -> t.CInt: pass diff --git a/Test/TestProject/temp/abf9ce3160c9279e.pyi b/Test/TestProject/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/TestProject/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/TestProject/temp/b0267503e816efc4.pyi b/Test/TestProject/temp/b0267503e816efc4.pyi new file mode 100644 index 0000000..62ff901 --- /dev/null +++ b/Test/TestProject/temp/b0267503e816efc4.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from zlib.zhuff.py +Module: zlib.zhuff +""" + + +from stdint import * +import zlib.zdef as zdef +import mpool +import t, c + +ZHUFF_MAX_CODES: t.CDefine = 288 +ZHUFF_MAX_BITS: t.CDefine = 15 + +class zhuff_code: + code: UINT + bits: t.CInt +@t.Object +class zhuff_tree: + pool: mpool.MPool | t.CPtr + codes: list[zhuff_code, ZHUFF_MAX_CODES] + count: t.CInt + max_bits: t.CInt + def __init__(self: zhuff_tree) -> t.CInt: pass + def build_codes(self: zhuff_tree, freqs: INTPTR, count: t.CInt, max_bits: t.CInt) -> t.CInt: pass + def build_fixed_lit_tree(self: zhuff_tree) -> t.CInt: pass + def build_fixed_dist_tree(self: zhuff_tree) -> t.CInt: pass + def encode_symbol(self: zhuff_tree, symbol: int, writer: zdef.zbit_writer | t.CPtr) -> t.CInt: pass + def build_code_lengths(self: zhuff_tree, lengths: t.CInt | t.CPtr, freqs: t.CInt | t.CPtr, count: t.CInt, max_bits: t.CInt) -> t.CInt: pass + def get_fixed_lit_lengths(self: zhuff_tree, lengths: INTPTR) -> t.CInt: pass + def get_fixed_dist_lengths(self: zhuff_tree, lengths: INTPTR) -> t.CInt: pass + def build_tree_from_lengths(self: zhuff_tree, lengths: INTPTR, count: t.CInt, max_bits: t.CInt) -> t.CInt: pass +class zhuff_decode_node: + children: list[t.CInt, 2] + symbol: t.CInt +@t.Object +class zhuff_decode_tree: + pool: mpool.MPool | t.CPtr + nodes: list[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] + node_count: t.CInt + root: t.CInt + def __init__(self: zhuff_decode_tree) -> t.CInt: pass + def build_decode_tree(self: zhuff_decode_tree, ht: zhuff_tree | t.CPtr) -> t.CInt: pass + def decode_symbol(self: zhuff_decode_tree, reader: zdef.zbit_reader | t.CPtr) -> t.CInt: pass \ No newline at end of file diff --git a/Test/TestProject/temp/ba2e1c2dfc8e2f85.pyi b/Test/TestProject/temp/ba2e1c2dfc8e2f85.pyi new file mode 100644 index 0000000..359a1c4 --- /dev/null +++ b/Test/TestProject/temp/ba2e1c2dfc8e2f85.pyi @@ -0,0 +1,19 @@ +""" +Auto-generated Python stub file from HASHLIB.py +Module: HASHLIB +""" + + +import stdio +import stdlib +import string +import stdint +import t, c +import base64 +import hashlib + +def default_value_test_function(a: t.CInt, b: t.CInt) -> t.CInt: pass + +def print_hex(buf: t.CUInt8T | t.CPtr, length: t.CInt) -> t.CInt: pass + +def main1() -> t.CInt: pass diff --git a/Test/TestProject/temp/bbdf3bbd4c3bc28c.pyi b/Test/TestProject/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/TestProject/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/TestProject/temp/c3eb91093118e1e1.pyi b/Test/TestProject/temp/c3eb91093118e1e1.pyi new file mode 100644 index 0000000..adb6481 --- /dev/null +++ b/Test/TestProject/temp/c3eb91093118e1e1.pyi @@ -0,0 +1,234 @@ +""" +Auto-generated Python stub file from numpy.__init__.py +Module: numpy.__init__ +""" + + +from stdint import * +import stdlib +import string +import vipermath +import stdio +import t, c +import mpool + +MAX_NDIM: t.CDefine = 4 +float64: t.CTypedef = t.CDouble +float32: t.CTypedef = t.CFloat +int64: t.CTypedef = t.CLong +int32: t.CTypedef = t.CInt +uint8: t.CTypedef = t.CUnsignedChar +pi: t.CDefine = 3.14159265358979323846 +e: t.CDefine = 2.71828182845904523536 + +@t.Object +class ndarray: + data: t.CDouble | t.CPtr + shape: list[t.CSizeT, MAX_NDIM] + strides: list[t.CSizeT, MAX_NDIM] + ndim: t.CInt + size: t.CSizeT + owns_data: t.CInt + pool: mpool.MPool | t.CPtr + def __new__(self: ndarray, pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> t.CInt: pass + def __add__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __sub__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __mul__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __truediv__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __floordiv__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __mod__(self: ndarray, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: pass + def __neg__(self: ndarray) -> 'ndarray' | t.CPtr: pass + def __len__(self: ndarray) -> t.CInt: pass + def at2d(self: ndarray, row: t.CSizeT, col: t.CSizeT) -> t.CDouble: pass + def set2d(self: ndarray, row: t.CSizeT, col: t.CSizeT, val: t.CDouble) -> t.CInt: pass + def delete(self: ndarray) -> t.CInt: pass + def fill(self: ndarray, val: t.CDouble) -> t.CInt: pass + def copy(self: ndarray) -> 'ndarray' | t.CPtr: pass + def reshape(self: ndarray, new_shape: INTPTR, new_ndim: t.CInt) -> 'ndarray' | t.CPtr: pass + def sum(self: ndarray) -> t.CDouble: pass + def mean(self: ndarray) -> t.CDouble: pass + def min(self: ndarray) -> t.CDouble: pass + def max(self: ndarray) -> t.CDouble: pass + def argmax(self: ndarray) -> t.CInt: pass + def argmin(self: ndarray) -> t.CInt: pass + def dot(self: ndarray, other: 'ndarray' | t.CPtr) -> t.CDouble: pass + def T(self: ndarray) -> 'ndarray' | t.CPtr: pass + def print_arr(self: ndarray) -> t.CInt: pass + +def _alloc_ndarray(pool: mpool.MPool | t.CPtr) -> ndarray | t.CPtr: pass + +def _compute_strides(a: ndarray | t.CPtr) -> t.CInt: pass + +def _empty_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def array(pool: mpool.MPool | t.CPtr, data: t.CDouble | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def zeros(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def ones(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def full(pool: mpool.MPool | t.CPtr, n: t.CSizeT, val: t.CDouble) -> ndarray | t.CPtr: pass + +def arange(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble, step: t.CDouble) -> ndarray | t.CPtr: pass + +def linspace(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble, num: t.CSizeT) -> ndarray | t.CPtr: pass + +def empty2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: pass + +def zeros2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: pass + +def ones2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: pass + +def eye(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def diag(pool: mpool.MPool | t.CPtr, vals: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_abs(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_sqrt(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_exp(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_log(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_sin(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_cos(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_tan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_pow(a: ndarray | t.CPtr, p: t.CDouble) -> ndarray | t.CPtr: pass + +def add_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: pass + +def mul_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: pass + +def sub_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: pass + +def div_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: pass + +def matmul(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def dot_product(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> t.CDouble: pass + +def np_sum(a: ndarray | t.CPtr) -> t.CDouble: pass + +def np_mean(a: ndarray | t.CPtr) -> t.CDouble: pass + +def np_min(a: ndarray | t.CPtr) -> t.CDouble: pass + +def np_max(a: ndarray | t.CPtr) -> t.CDouble: pass + +def np_argmax(a: ndarray | t.CPtr) -> t.CInt: pass + +def np_argmin(a: ndarray | t.CPtr) -> t.CInt: pass + +def var(a: ndarray | t.CPtr) -> t.CDouble: pass + +def std(a: ndarray | t.CPtr) -> t.CDouble: pass + +def norm(a: ndarray | t.CPtr) -> t.CDouble: pass + +def clip(a: ndarray | t.CPtr, lo: t.CDouble, hi: t.CDouble) -> ndarray | t.CPtr: pass + +def concatenate(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def sort_arr(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def reverse(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_log10(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_log2(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_floor(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_ceil(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_round(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_sign(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_tanh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_sinh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_cosh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_arcsin(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_arccos(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_arctan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_arctan2(y: ndarray | t.CPtr, x: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_degrees(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_radians(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_isnan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_isinf(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_maximum(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_minimum(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def cumsum(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def diff(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def flatten(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def trace(a: ndarray | t.CPtr) -> t.CDouble: pass + +def outer(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_where(condition: ndarray | t.CPtr, x: ndarray | t.CPtr, y: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_count_nonzero(a: ndarray | t.CPtr) -> t.CInt: pass + +def np_all(a: ndarray | t.CPtr) -> t.CInt: pass + +def np_any(a: ndarray | t.CPtr) -> t.CInt: pass + +def np_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_not_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_less(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_greater(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_less_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_greater_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def empty(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: pass + +def full2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT, val: t.CDouble) -> ndarray | t.CPtr: pass + +def zeros_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def ones_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def arange1(pool: mpool.MPool | t.CPtr, stop: t.CDouble) -> ndarray | t.CPtr: pass + +def linspace2(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble) -> ndarray | t.CPtr: pass + +def meshgrid(x: ndarray | t.CPtr, y: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def det2x2(a: ndarray | t.CPtr) -> t.CDouble: pass + +def inv2x2(a: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def cross3(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: pass + +def np_interp(x: t.CDouble, xp: ndarray | t.CPtr, fp: ndarray | t.CPtr) -> t.CDouble: pass + +def prod(a: ndarray | t.CPtr) -> t.CDouble: pass + +def median(a: ndarray | t.CPtr) -> t.CDouble: pass + +def percentile(a: ndarray | t.CPtr, q: t.CDouble) -> t.CDouble: pass diff --git a/Test/TestProject/temp/c9f4be41ca1cc2b4.pyi b/Test/TestProject/temp/c9f4be41ca1cc2b4.pyi new file mode 100644 index 0000000..fdbd7ec --- /dev/null +++ b/Test/TestProject/temp/c9f4be41ca1cc2b4.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from viperio.py +Module: viperio +""" + + +import t, c +from stdint import * + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CInt: pass + def clear(self: Buf) -> t.CInt: pass + def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: pass + def cstr(self: Buf) -> t.CChar | t.CPtr: pass + def reset(self: Buf) -> t.CInt: pass + def __enter__(self: Buf) -> 'Buf' | t.CPtr: pass + def __exit__(self: Buf) -> t.CInt: pass + def free(self: Buf) -> t.CInt: pass \ No newline at end of file diff --git a/Test/TestProject/temp/d282a7cb3385ecf0.pyi b/Test/TestProject/temp/d282a7cb3385ecf0.pyi new file mode 100644 index 0000000..b79c5b2 --- /dev/null +++ b/Test/TestProject/temp/d282a7cb3385ecf0.pyi @@ -0,0 +1,126 @@ +""" +Auto-generated Python stub file from zlib.pyzlib.py +Module: zlib.pyzlib +""" + + +from stdint import * +import zlib.zdeflate as zdeflate +import zlib.zinflate as zinflate +import zlib.zchecksum as zchecksum +import zlib.zdef as zdef +import zlib.zhuff as zhuff +import stdlib +import string +import stdio +import mpool +import t, c + +Z_NO_COMPRESSION: t.CDefine = 0 +Z_BEST_SPEED: t.CDefine = 1 +Z_BEST_COMPRESSION: t.CDefine = 9 +Z_DEFAULT_COMPRESSION: t.CDefine = (-1) +DEFLATED: t.CDefine = 8 +Z_NO_FLUSH: t.CDefine = 0 +Z_PARTIAL_FLUSH: t.CDefine = 1 +Z_SYNC_FLUSH: t.CDefine = 2 +Z_FULL_FLUSH: t.CDefine = 3 +Z_FINISH: t.CDefine = 4 +Z_BLOCK: t.CDefine = 5 +Z_TREES: t.CDefine = 6 +Z_DEFAULT_STRATEGY: t.CDefine = 0 +Z_FILTERED: t.CDefine = 1 +Z_HUFFMAN_ONLY: t.CDefine = 2 +Z_RLE: t.CDefine = 3 +Z_FIXED: t.CDefine = 4 +Z_OK: t.CDefine = 0 +Z_STREAM_END: t.CDefine = 1 +Z_NEED_DICT: t.CDefine = 2 +Z_ERRNO: t.CDefine = (-1) +Z_STREAM_ERROR: t.CDefine = (-2) +Z_DATA_ERROR: t.CDefine = (-3) +Z_MEM_ERROR: t.CDefine = (-4) +Z_BUF_ERROR: t.CDefine = (-5) +Z_VERSION_ERROR: t.CDefine = (-6) +MAX_WBITS: t.CDefine = 15 +DEF_BUF_SIZE: t.CDefine = 16384 +DEF_MEM_LEVEL: t.CDefine = 8 +ZLIB_VERSION: t.CDefine = "1.3.2" +pyzlib_error_msg: t.CExtern | list[t.CChar, 512] +pyzlib_error_code_val: t.CExtern | t.CInt + +@t.Object +class Compress: + pool: mpool.MPool | t.CPtr + stream: VOIDPTR + is_initialized: t.CInt + is_finished: t.CInt + level: t.CInt + method: t.CInt + wbits: t.CInt + memLevel: t.CInt + strategy: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + last_pos: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + header_written: t.CInt + def compress(self: Compress, data: BYTEPTR, data_len: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def flush(self: Compress, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def copy(self: Compress) -> Compress | t.CPtr: pass + def delete(self: Compress) -> t.CInt: pass + def __del__(self: Compress) -> t.CInt: pass +@t.Object +class Decompress: + pool: mpool.MPool | t.CPtr + stream: VOIDPTR + is_initialized: t.CInt + eof: t.CInt + wbits: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + _unused_data: BYTEPTR + _unused_data_len: t.CSizeT + _unused_data_cap: t.CSizeT + _unconsumed_tail: BYTEPTR + _unconsumed_tail_len: t.CSizeT + _unconsumed_tail_cap: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + def decompress(self: Decompress, data: BYTEPTR, data_len: t.CSizeT, max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def flush(self: Decompress, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def copy(self: Decompress) -> Decompress | t.CPtr: pass + def delete(self: Decompress) -> t.CInt: pass + def unused_data(self: Decompress, length: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def unconsumed_tail(self: Decompress, length: t.CSizeT | t.CPtr) -> BYTEPTR: pass + +def set_error(code: int, msg: str) -> t.CInt: pass + +def clone_bytes(pool: mpool.MPool | t.CPtr, src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: pass + +def append_bytes(pool: mpool.MPool | t.CPtr, buf: BYTE | t.CPtr[t.CPtr], length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr, data: BYTEPTR, data_len: t.CSizeT) -> t.CInt: pass + +def shrink_to_fit(pool: mpool.MPool | t.CPtr, buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: pass + +def runtime_version() -> str: pass + +def get_error() -> str: pass + +def get_error_code() -> t.CInt: pass + +def clear_error() -> t.CInt: pass + +def compress(pool: mpool.MPool | t.CPtr, data: BYTEPTR, data_len: t.CSizeT, level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + +def decompress(pool: mpool.MPool | t.CPtr, data: BYTEPTR, data_len: t.CSizeT, wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + +def compressobj(pool: mpool.MPool | t.CPtr, level: t.CInt, method: t.CInt, wbits: t.CInt, memLevel: t.CInt, strategy: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr: pass + +def decompressobj(pool: mpool.MPool | t.CPtr, wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: pass + +def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: pass + +def zlib_crc32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: pass diff --git a/Test/TestProject/temp/f9629b8eb4ebdcc2.pyi b/Test/TestProject/temp/f9629b8eb4ebdcc2.pyi new file mode 100644 index 0000000..d5daf90 --- /dev/null +++ b/Test/TestProject/temp/f9629b8eb4ebdcc2.pyi @@ -0,0 +1,52 @@ +""" +Auto-generated Python stub file from zlib.zinflate.py +Module: zlib.zinflate +""" + + +from stdint import * +import zlib.zchecksum as zchecksum +import zlib.zdef as zdef +import zlib.zhuff as zhuff +import string +import mpool +import t, c + +@t.Object +class zinflate_stream: + pool: mpool.MPool | t.CPtr + reader: zdef.zbit_reader + window: BYTEPTR + window_pos: t.CInt + window_size: t.CInt + wbits: t.CInt + is_finished: t.CInt + is_initialized: t.CInt + header_parsed: t.CInt + is_gzip: t.CInt + adler: t.CUInt32T + crc: t.CUInt32T + output: BYTEPTR + output_len: t.CSizeT + output_cap: t.CSizeT + input_data: t.CConst | BYTEPTR + input_len: t.CSizeT + input_pos: t.CSizeT + max_length: t.CSizeT + def __init__(self: zinflate_stream) -> t.CInt: pass + def output_byte(self: zinflate_stream, byte: BYTE) -> t.CInt: pass + def parse_header(self: zinflate_stream) -> t.CInt: pass + def read_bits_from_input(self: zinflate_stream, nbits: t.CInt, out: UINTPTR) -> t.CInt: pass + def read_huffman(self: zinflate_stream, dt: zhuff.zhuff_decode_tree | t.CPtr) -> t.CInt: pass + def inflate_block_stored(self: zinflate_stream) -> t.CInt: pass + def inflate_block_fixed(self: zinflate_stream) -> t.CInt: pass + def inflate_block_dynamic(self: zinflate_stream) -> t.CInt: pass + def inflate_stream(self: zinflate_stream) -> t.CInt: pass + def decompress(self: zinflate_stream, data: UINT8PTR, length: t.CSizeT, max_length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: pass + def set_dictionary(self: zinflate_stream, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: pass + def copy(self: zinflate_stream) -> zinflate_stream | t.CPtr: pass + def destroy(self: zinflate_stream) -> t.CInt: pass + +def zinflate_one_shot(pool: mpool.MPool | t.CPtr, data: UINT8PTR, length: t.CSizeT, wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: pass + +def zinflate_create(pool: mpool.MPool | t.CPtr, wbits: t.CInt) -> zinflate_stream | t.CPtr: pass diff --git a/Test/TestProject/temp/fa3691e66b426950.pyi b/Test/TestProject/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/TestProject/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/TestProject2/App/main.py b/Test/TestProject2/App/main.py new file mode 100644 index 0000000..8be34af --- /dev/null +++ b/Test/TestProject2/App/main.py @@ -0,0 +1,116 @@ +import stdio +import stdint +import zc.config as config +import zc.test as test +import zc.logic_test as logic +import zc.class_test as class_test + + +def main() -> stdint.INT: + stdio.printf("=== Hello World! ===\n") + stdio.printf("Cross-module macros:\n") + stdio.printf(" POSMAX: %d\n", config.POSMAX) + stdio.printf(" MATH_SCALE: %d\n", config.MATH_SCALE) + stdio.printf(" THRESHOLD: %d\n", config.THRESHOLD) + stdio.printf(" SHIFT_AMOUNT: %d\n", config.SHIFT_AMOUNT) + stdio.printf(" MASK_VALUE: 0x%x\n", config.MASK_VALUE) + stdio.printf("\n=== While Loop Test ===\n") + test.AboutSizeTWhileTest(10) + stdio.printf("\n=== Math Basic Test (20, 6) ===\n") + test.MathBasicTest(20, 6) + stdio.printf("\n=== Math Advanced Test (value=15) ===\n") + test.MathAdvancedTest(15) + stdio.printf("\n=== While with Elif-Else Test (-2 to 12) ===\n") + test.WhileWithElifElseTest(-2, 12) + stdio.printf("\n=== Nested While with Macros Test ===\n") + test.NestedWhileWithMacrosTest(3, 4) + stdio.printf("\n=== Complex Condition Test (1, 2, 3) ===\n") + test.ComplexConditionTest(1, 2, 3) + stdio.printf("\n=== Retry Loop Test (8) ===\n") + test.RetryLoopTest(8) + stdio.printf("\n=== Bitwise Operations Test (0b1101101) ===\n") + test.BitwiseOperationsTest(109) + stdio.printf("\n=== Compound Assignment Math Test (15, 4) ===\n") + test.CompoundAssignmentMathTest(15, 4) + stdio.printf("\n=== Power and Modulo Test (2, 8) ===\n") + test.PowerAndModuloTest(2, 8) + stdio.printf("\n=== Mixed Arithmetic Test (5, 3, 4) ===\n") + test.MixedArithmeticTest(5, 3, 4) + stdio.printf("\n=== Math with While Loop Test (start=1, count=5) ===\n") + test.MathWithWhileLoopTest(1, 5) + stdio.printf("\n=== Complex Nested Math Test (7, 3) ===\n") + test.ComplexNestedMathTest(7, 3) + stdio.printf("\n=== Conditional Math Chain Test (value=10) ===\n") + test.ConditionalMathChainTest(10) + stdio.printf("\n=== Bit Manipulation Math Test (0xABCD) ===\n") + test.BitManipulationMathTest(0xABCD) + stdio.printf("\n============== COMPLEX LOGIC TESTS ==============\n") + stdio.printf("\n=== For Range Basic Test (stop=5) ===\n") + logic.ForRangeBasicTest(5) + stdio.printf("\n=== For Range With Start Stop Step (start=1, stop=10, step=2) ===\n") + logic.ForRangeWithStartStop(1, 10, 2) + stdio.printf("\n=== Nested For Range Test (rows=2, cols=3) ===\n") + logic.NestedForRangeTest(2, 3) + stdio.printf("\n=== For With If Break Test (size=8) ===\n") + logic.ForWithIfBreakTest(8) + stdio.printf("\n=== For With If Continue Test (n=10) ===\n") + logic.ForWithIfContinueTest(10) + stdio.printf("\n=== For With Elif Branch Test (value=10) ===\n") + logic.ForWithElifBranchTest(10) + stdio.printf("\n=== While With If Elif Else Test (iterations=7) ===\n") + logic.WhileWithIfElifElseTest(7) + stdio.printf("\n=== While With Nested If Test (limit=4) ===\n") + logic.WhileWithNestedIfTest(4) + stdio.printf("\n=== While With Match Case Test (value=2) ===\n") + logic.WhileWithMatchCaseTest(2) + stdio.printf("\n=== While With Match Case Test (value=99) ===\n") + logic.WhileWithMatchCaseTest(99) + stdio.printf("\n=== While With Match Case NoBreak Test (value=3) ===\n") + logic.WhileWithMatchCaseNoBreakTest(3) + stdio.printf("\n=== Complex For While Match Test (outer=3, inner=3) ===\n") + logic.ComplexForWhileMatchTest(3, 3) + stdio.printf("\n=== For With Case And NoBreak Test (n=5) ===\n") + logic.ForWithCaseAndNoBreakTest(5) + stdio.printf("\n=== While With Break Condition Test (limit=6) ===\n") + logic.WhileWithBreakConditionTest(6) + stdio.printf("\n=== Nested While With Multiple BreakPoints (depth=3, width=4) ===\n") + logic.NestedWhileWithMultipleBreakPoints(3, 4) + stdio.printf("\n=== For With Match Case In Loop Test (iterations=9) ===\n") + logic.ForWithMatchCaseInLoopTest(9) + stdio.printf("\n=== Complex Logic With Elif Chains (a=3, b=5, c=7) ===\n") + logic.ComplexLogicWithElifChains(3, 5, 7) + stdio.printf("\n=== For Range With Step And Condition (n=12, step=2) ===\n") + logic.ForRangeWithStepAndCondition(12, 2) + stdio.printf("\n=== Match Case With Guard Conditions (value=1) ===\n") + logic.MatchCaseWithGuardConditions(1) + stdio.printf("\n=== While With Multiple Match Cases (iterations=12) ===\n") + logic.WhileWithMultipleMatchCases(12) + stdio.printf("\n=== For While Mix With Break And Continue (n=5) ===\n") + logic.ForWhileMixWithBreakAndContinue(5) + stdio.printf("\n=== Complex Case Matching With Ranges (start=0, end=35) ===\n") + logic.ComplexCaseMatchingWithRanges(0, 35) + stdio.printf("\n=== While With Elif In Elif Chain (limit=7) ===\n") + logic.WhileWithElifInElifChain(7) + stdio.printf("\n=== For With Case NoBreak Nested (inner_limit=4) ===\n") + logic.ForWithCaseNoBreakNested(4) + stdio.printf("\n============== CLASS TESTS ==============\n") + class_test.TestBasicDataClass() + class_test.TestPoint3DClass() + class_test.TestStudentClass() + class_test.TestCounterClass() + class_test.TestStackAllocation() + class_test.TestHeapAllocation() + class_test.TestHeapObjectWithInit() + class_test.TestMultipleStackObjects() + class_test.TestImplicitInitCall() + class_test.TestClassWithBitFields() + stdio.printf("\n============== ARRAY TESTS ==============\n") + class_test.TestIntArray() + class_test.TestFloatArray() + class_test.TestCharArray() + class_test.TestNestedArray() + class_test.TestArrayWithStruct() + class_test.TestArrayPointer() + class_test.TestDynamicString() + stdio.printf("\n============== All Tests Completed ==============\n") + return 0 \ No newline at end of file diff --git a/Test/TestProject2/App/zc/class_test.py b/Test/TestProject2/App/zc/class_test.py new file mode 100644 index 0000000..a0eb503 --- /dev/null +++ b/Test/TestProject2/App/zc/class_test.py @@ -0,0 +1,245 @@ +import stdio +import stdint +import t, c + + +class SimpleData(t.Object): + x: t.CInt + y: t.CInt + + +class Point3D(t.Object): + x: t.CFloat + y: t.CFloat + z: t.CFloat + + +class Student(t.Object): + name: t.CChar | t.CPtr + age: t.CInt + score: t.CInt + + def __init__(self, n: t.CChar | t.CPtr, a: t.CInt, s: t.CInt): + self.name = n + self.age = a + self.score = s + + def get_age(self) -> t.CInt: + return self.age + + def get_score(self) -> t.CInt: + return self.score + + +class Counter(t.Object): + value: t.CInt + + def __init__(self, initial: t.CInt): + self.value = initial + + def increment(self): + self.value += 1 + + def get_value(self) -> t.CInt: + return self.value + + +class StackObj(t.Object): + data: t.CInt + next_ptr: t.CVoid | t.CPtr + + +def TestBasicDataClass(): + stdio.printf("=== Test Basic Data Class ===\n") + p: SimpleData = SimpleData() + p.x = 10 + p.y = 20 + stdio.printf("SimpleData: x=%d, y=%d\n", p.x, p.y) + + +def TestPoint3DClass(): + stdio.printf("=== Test Point3D Class ===\n") + pt: Point3D = Point3D() + pt.x = 1.5 + pt.y = 2.5 + pt.z = 3.5 + stdio.printf("Point3D: x=%.1f, y=%.1f, z=%.1f\n", pt.x, pt.y, pt.z) + + +def TestStudentClass(): + stdio.printf("=== Test Student Class ===\n") + s: Student = Student("Alice", 20, 95) + stdio.printf("Student: name=%s, age=%d, score=%d\n", s.name, s.age, s.score) + stdio.printf(" get_age()=%d, get_score()=%d\n", s.get_age(), s.get_score()) + + +def TestCounterClass(): + stdio.printf("=== Test Counter Class ===\n") + cnt: Counter = Counter(0) + stdio.printf("Initial value: %d\n", cnt.get_value()) + cnt.increment() + cnt.increment() + cnt.increment() + stdio.printf("After 3 increments: %d\n", cnt.get_value()) + + +def TestStackAllocation(): + stdio.printf("=== Test Stack Allocation ===\n") + obj1: SimpleData = SimpleData() + obj1.x = 100 + obj1.y = 200 + stdio.printf("Stack obj1: x=%d, y=%d\n", obj1.x, obj1.y) + + obj2: Point3D = Point3D() + obj2.x = 10.0 + obj2.y = 20.0 + obj2.z = 30.0 + stdio.printf("Stack obj2: x=%.1f, y=%.1f, z=%.1f\n", obj2.x, obj2.y, obj2.z) + + +def TestHeapAllocation(): + stdio.printf("=== Test Heap Allocation ===\n") + ptr: t.CVoid | t.CPtr = c.malloc(1024) + if ptr != 0: + stdio.printf("Allocated 1024 bytes at %p\n", ptr) + c.free(ptr) + stdio.printf("Freed memory\n") + else: + stdio.printf("malloc failed\n") + + +def TestHeapObjectWithInit(): + stdio.printf("=== Test Heap Object with Init ===\n") + mem_size: t.CSizeT = 256 + ptr: t.CVoid | t.CPtr = c.malloc(mem_size) + if ptr != 0: + stdio.printf("Allocated %d bytes\n", mem_size) + c.free(ptr) + else: + stdio.printf("malloc failed\n") + + +def TestMultipleStackObjects(): + stdio.printf("=== Test Multiple Stack Objects ===\n") + objs: SimpleData = SimpleData() + objs.x = 1 + objs.y = 2 + obj2: Point3D = Point3D() + obj2.x = 5.0 + obj2.y = 10.0 + obj2.z = 15.0 + obj3: Counter = Counter(42) + stdio.printf("objs: x=%d, y=%d\n", objs.x, objs.y) + stdio.printf("obj2: x=%.1f, y=%.1f, z=%.1f\n", obj2.x, obj2.y, obj2.z) + stdio.printf("obj3 initial: %d\n", obj3.get_value()) + obj3.increment() + obj3.increment() + stdio.printf("obj3 after 2 increments: %d\n", obj3.get_value()) + + +def TestImplicitInitCall(): + stdio.printf("=== Test Implicit Init Call ===\n") + stu1: Student = Student("Bob", 22, 88) + stu2: Student = Student("Charlie", 19, 77) + stdio.printf("stu1: name=%s, age=%d, score=%d\n", stu1.name, stu1.age, stu1.score) + stdio.printf("stu2: name=%s, age=%d, score=%d\n", stu2.name, stu2.age, stu2.score) + + +def TestClassWithBitFields(): + stdio.printf("=== Test Class with Bit Fields ===\n") + flags: StackObj = StackObj() + flags.data = 0 + flags.next_ptr = 0 + stdio.printf("StackObj: data=%d, next_ptr=%p\n", flags.data, flags.next_ptr) + + +def TestIntArray(): + stdio.printf("=== Test Int Array ===\n") + arr: list[t.CInt, 5] = list[t.CInt, 5]() + i: t.CInt = 0 + while i < 5: + arr[i] = i * 10 + i += 1 + i = 0 + while i < 5: + stdio.printf("arr[%d]=%d\n", i, arr[i]) + i += 1 + + +def TestFloatArray(): + stdio.printf("=== Test Float Array ===\n") + farr: list[t.CFloat, 4] = list[t.CFloat, 4]() + farr[0] = 1.5 + farr[1] = 2.5 + farr[2] = 3.5 + farr[3] = 4.5 + i: t.CInt = 0 + while i < 4: + stdio.printf("farr[%d]=%.1f\n", i, farr[i]) + i += 1 + + +def TestCharArray(): + stdio.printf("=== Test Char Array (String) ===\n") + str_arr: list[t.CChar, 32] = list[t.CChar, 32]() + str_arr[0] = 'H' + str_arr[1] = 'e' + str_arr[2] = 'l' + str_arr[3] = 'l' + str_arr[4] = 'o' + str_arr[5] = '\0' + stdio.printf("String: %s\n", str_arr) + + +def TestNestedArray(): + stdio.printf("=== Test Nested Array (Array of Arrays) ===\n") + row0: list[t.CInt, 3] = list[t.CInt, 3]() + row1: list[t.CInt, 3] = list[t.CInt, 3]() + row0[0] = 0 + row0[1] = 1 + row0[2] = 2 + row1[0] = 10 + row1[1] = 11 + row1[2] = 12 + i: t.CInt = 0 + while i < 3: + stdio.printf("row0[%d]=%d ", i, row0[i]) + i += 1 + stdio.printf("\n") + i = 0 + while i < 3: + stdio.printf("row1[%d]=%d ", i, row1[i]) + i += 1 + stdio.printf("\n") + + +def TestArrayWithStruct(): + stdio.printf("=== Test Array with Struct ===\n") + points: list[SimpleData, 3] = list[SimpleData, 3]() + i: t.CInt = 0 + while i < 3: + points[i].x = i * 10 + points[i].y = i * 100 + i += 1 + i = 0 + while i < 3: + stdio.printf("Point[%d]: x=%d, y=%d\n", i, points[i].x, points[i].y) + i += 1 + + +def TestArrayPointer(): + stdio.printf("=== Test Array Pointer ===\n") + data: list[t.CInt, 8] = list[t.CInt, 8]() + data[0] = 100 + data[1] = 200 + data[2] = 300 + ptr: t.CInt | t.CPtr = data + stdio.printf("ptr[0]=%d\n", ptr[0]) + stdio.printf("ptr[1]=%d\n", ptr[1]) + stdio.printf("ptr[2]=%d\n", ptr[2]) + + +def TestDynamicString(): + stdio.printf("=== Test Dynamic String ===\n") + name: str = "TransPyC" + stdio.printf("Hello %s!\n", name) \ No newline at end of file diff --git a/Test/TestProject2/App/zc/config.py b/Test/TestProject2/App/zc/config.py new file mode 100644 index 0000000..1b4e36f --- /dev/null +++ b/Test/TestProject2/App/zc/config.py @@ -0,0 +1,24 @@ +import t, c + + +POSMAX: t.CDefine = 100 +MAX_RETRY: t.CDefine = 5 +BUFFER_SIZE: t.CDefine = 256 +PI: t.CDefine = 3.14159 +EULER: t.CDefine = 2.71828 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +NULL: t.CDefine = 0 + + +MATH_OFFSET: t.CDefine = 10 +MATH_SCALE: t.CDefine = 2 +THRESHOLD: t.CDefine = 50 +LOOP_LIMIT: t.CDefine = 20 +SHIFT_AMOUNT: t.CDefine = 2 +MASK_VALUE: t.CDefine = 0xFF +BIT_RANGE: t.CDefine = 4 +EXPONENT_BASE: t.CDefine = 3 +MODULO_DIVISOR: t.CDefine = 7 +SCALE_SHIFT: t.CDefine = 4 +HALF_SCALE: t.CDefine = 0.5 \ No newline at end of file diff --git a/Test/TestProject2/App/zc/logic_test.py b/Test/TestProject2/App/zc/logic_test.py new file mode 100644 index 0000000..4d5c266 --- /dev/null +++ b/Test/TestProject2/App/zc/logic_test.py @@ -0,0 +1,372 @@ +import config +import t, c + + +def ForRangeBasicTest(stop: t.CInt): + i: t.CInt = 0 + for i in range(stop): + print("For range: ", i) + print("Done") + + +def ForRangeWithStartStop(start: t.CInt, stop: t.CInt, step: t.CInt): + i: t.CInt = 0 + for i in range(start, stop, step): + print("Range: ", i) + print("Done") + + +def NestedForRangeTest(rows: t.CInt, cols: t.CInt): + r: t.CInt = 0 + c_val: t.CInt = 0 + for r in range(rows): + for c_val in range(cols): + print("Cell: ", r, c_val) + print("Grid done") + + +def ForWithIfBreakTest(data_size: t.CInt): + i: t.CInt = 0 + found: t.CInt = 0 + for i in range(data_size): + if i == 5: + print("Found at: ", i) + found = 1 + break + print("Checking: ", i) + if found == 0: + print("Not found") + + +def ForWithIfContinueTest(n: t.CInt): + i: t.CInt = 0 + count: t.CInt = 0 + for i in range(n): + if i % 2 == 0: + continue + print("Odd: ", i) + count += 1 + print("Total odd: ", count) + + +def ForWithElifBranchTest(value: t.CInt): + i: t.CInt = 0 + result: t.CInt = 0 + for i in range(value): + if i < 3: + result += 1 + elif i < 6: + result += 2 + elif i < 9: + result += 3 + else: + result += 4 + print("Elif branch result: ", result) + + +def WhileWithIfElifElseTest(iterations: t.CInt): + counter: t.CInt = 0 + while counter < iterations: + if counter < 2: + print("Phase 1: ", counter) + elif counter < 4: + print("Phase 2: ", counter) + elif counter < 6: + print("Phase 3: ", counter) + else: + print("Phase 4: ", counter) + counter += 1 + print("While done") + + +def WhileWithNestedIfTest(limit: t.CInt): + outer: t.CInt = 0 + while outer < limit: + inner: t.CInt = 0 + while inner < limit: + if inner == 2 and outer == 1: + print("Target: ", outer, inner) + inner += 1 + continue + if inner > 3: + break + print("Inner: ", inner) + inner += 1 + outer += 1 + + +def WhileWithMatchCaseTest(value: t.CInt): + result: t.CInt = 0 + match value: + case 1: + result = 100 + print("Case 1") + case 2: + result = 200 + print("Case 2") + case 3: + result = 300 + print("Case 3") + case _: + result = 999 + print("Default case") + print("Match result: ", result) + + +def WhileWithMatchCaseNoBreakTest(value: t.CInt): + result: t.CInt = 0 + match value: + case 1: + result = 10 + print("Case 1: ", result) + case 2: + result = 20 + print("Case 2: ", result) + result += 5 + case 3: + result = 30 + print("Case 3: ", result) + case _: + result = 0 + print("No break match result: ", result) + + +def ComplexForWhileMatchTest(outer_limit: t.CInt, inner_limit: t.CInt): + i: t.CInt = 0 + j: t.CInt = 0 + result: t.CInt = 0 + for i in range(outer_limit): + j = 0 + while j < inner_limit: + match (i, j): + case (0, 0): + result += 1 + case (1, 1): + result += 10 + case (2, _): + result += 100 + case (_, 0): + result += 1000 + case _: + result += 10000 + j += 1 + print("Complex match result: ", result) + + +def ForWithCaseAndNoBreakTest(n: t.CInt): + i: t.CInt = 0 + result: t.CInt = 0 + for i in range(n): + match i: + case 0: + result += 1 + case 1: + result += 2 + case 2: + result += 3 + result += 10 + case _: + result += i + c.NoBreak + print("NoBreak result: ", result) + + +def WhileWithBreakConditionTest(limit: t.CInt): + i: t.CInt = 0 + early_exit: t.CInt = 0 + while i < limit: + if i == 3: + early_exit = 1 + break + if i == 2: + i += 1 + continue + print("While i: ", i) + i += 1 + + +def NestedWhileWithMultipleBreakPoints(depth: t.CInt, width: t.CInt): + d: t.CInt = 0 + w: t.CInt = 0 + count: t.CInt = 0 + while d < depth: + w = 0 + while w < width: + if w == 2: + break + if d == 1 and w == 1: + c.Break + count += 1 + w += 1 + d += 1 + print("Nested break count: ", count) + + +def ForWithMatchCaseInLoopTest(iterations: t.CInt): + i: t.CInt = 0 + sum_even: t.CInt = 0 + sum_odd: t.CInt = 0 + for i in range(iterations): + match i % 3: + case 0: + sum_even += i + case 1: + sum_odd += i + case 2: + sum_even += i * 2 + case _: + pass + print("Sum even: ", sum_even) + print("Sum odd: ", sum_odd) + + +def ComplexLogicWithElifChains(a: t.CInt, b: t.CInt, c_val: t.CInt): + i: t.CInt = 0 + result: t.CInt = 0 + while i < 10: + if i < a: + if i < b: + result += 1 + elif i < c_val: + result += 2 + else: + result += 3 + elif i < b: + if i < c_val: + result += 4 + else: + result += 5 + elif i < c_val: + result += 6 + else: + result += 7 + i += 1 + print("Complex elif chain result: ", result) + + +def ForRangeWithStepAndCondition(n: t.CInt, step: t.CInt): + i: t.CInt = 0 + count: t.CInt = 0 + for i in range(0, n, step): + if i % 2 == 0: + print("Even step: ", i) + count += 1 + else: + if i > 5: + print("Large odd: ", i) + else: + print("Small odd: ", i) + print("Total steps: ", count) + + +def MatchCaseWithGuardConditions(value: t.CInt): + result: t.CInt = 0 + match value: + case 1 if config.TRUE == 1: + result = 100 + case 2 if config.FALSE == 0: + result = 200 + case 3: + result = 300 + case _: + result = 0 + print("Guard match result: ", result) + + +def WhileWithMultipleMatchCases(iterations: t.CInt): + i: t.CInt = 0 + state: t.CInt = 0 + while i < iterations: + match state: + case 0: + if i > 3: + state = 1 + case 1: + if i > 6: + state = 2 + case 2: + if i > 9: + state = 0 + print("State at i=", i, ": ", state) + i += 1 + + +def ForWhileMixWithBreakAndContinue(n: t.CInt): + i: t.CInt = 0 + j: t.CInt = 0 + count: t.CInt = 0 + for i in range(n): + j = 0 + while j < n: + if j == 2: + j += 1 + continue + if i == 3 and j == 3: + break + count += 1 + j += 1 + print("Mix break continue count: ", count) + + +def ComplexCaseMatchingWithRanges(start: t.CInt, end: t.CInt): + i: t.CInt = 0 + bucket0: t.CInt = 0 + bucket1: t.CInt = 0 + bucket2: t.CInt = 0 + bucket3: t.CInt = 0 + for i in range(start, end): + match i: + case _ if i < 10: + bucket0 += 1 + case _ if i < 20: + bucket1 += 1 + case _ if i < 30: + bucket2 += 1 + case _: + bucket3 += 1 + print("Bucket0 (<10): ", bucket0) + print("Bucket1 (10-19): ", bucket1) + print("Bucket2 (20-29): ", bucket2) + print("Bucket3 (>=30): ", bucket3) + + +def WhileWithElifInElifChain(limit: t.CInt): + i: t.CInt = 0 + result: t.CInt = 0 + while i < limit: + if i < 2: + if i == 0: + result = 1 + else: + result = 2 + elif i < 4: + if i == 2: + result = 3 + else: + result = 4 + elif i < 6: + if i == 4: + result = 5 + else: + result = 6 + else: + result = 7 + print("Chain result[", i, "]: ", result) + i += 1 + + +def ForWithCaseNoBreakNested(inner_limit: t.CInt): + i: t.CInt = 0 + j: t.CInt = 0 + result: t.CInt = 0 + for i in range(3): + for j in range(inner_limit): + match j: + case 0: + result += 1 + case 1: + result += 2 + case _: + result += 3 + c.NoBreak + print("Nested NoBreak result: ", result) \ No newline at end of file diff --git a/Test/TestProject2/App/zc/test.py b/Test/TestProject2/App/zc/test.py new file mode 100644 index 0000000..24a08a8 --- /dev/null +++ b/Test/TestProject2/App/zc/test.py @@ -0,0 +1,298 @@ +import config +import t, c + + +def AboutSizeTWhileTest(length: t.CSizeT): + pos: t.CSizeT = 0 + while pos < length: + print("Pos: ", pos) + if pos > config.POSMAX: break + pos += 1 + while pos < length: + if pos > config.POSMAX: + print("Pos: ", pos) + pos += 1 + else: + print("Pos: ", pos) + pos += 1 + if pos > config.POSMAX: break + else: + pos += 1 + print("Pos: ", pos) + while pos < length: + print("Pos: ", pos) + pos += 1 + + +def MathBasicTest(x: t.CInt, y: t.CInt) -> t.CInt: + result: t.CInt = 0 + result = x + y + print("Add: ", result) + result = x - y + print("Sub: ", result) + result = x * y + print("Mul: ", result) + if y != 0: + result = x / y + print("Div: ", result) + result = x % y if y != 0 else 0 + print("Mod: ", result) + return result + + +def MathAdvancedTest(value: t.CInt) -> t.CInt: + counter: t.CInt = 0 + scaled: t.CInt = 0 + offset: t.CInt = 0 + scaled = value * config.MATH_SCALE + print("Scaled: ", scaled) + offset = scaled + config.MATH_OFFSET + print("Offset: ", offset) + threshold: t.CInt = config.THRESHOLD + if offset > threshold: + print("Above threshold") + counter = 1 + elif offset == threshold: + print("At threshold") + counter = 0 + else: + print("Below threshold") + counter = -1 + return counter + + +def WhileWithElifElseTest(start: t.CInt, end: t.CInt): + idx: t.CInt = start + while idx < end: + if idx < 0: + print("Negative: ", idx) + elif idx == 0: + print("Zero: ", idx) + elif idx > 0 and idx < 5: + print("Small positive: ", idx) + elif idx >= 5 and idx < 10: + print("Medium positive: ", idx) + else: + print("Large: ", idx) + idx += 1 + + +def NestedWhileWithMacrosTest(outer_limit: t.CInt, inner_limit: t.CInt): + outer: t.CInt = 0 + inner: t.CInt = 0 + total_ops: t.CInt = 0 + while outer < outer_limit: + inner = 0 + while inner < inner_limit: + if inner == config.TRUE: + print("Inner loop break condition at: ", inner) + total_ops += 1 + inner += 1 + outer += 1 + print("Total operations: ", total_ops) + + +def ComplexConditionTest(a: t.CInt, b: t.CInt, c_val: t.CInt): + x: t.CInt = a + y: t.CInt = b + z: t.CInt = c_val + while x < config.LOOP_LIMIT: + if x > 0 and y > 0 and z > 0: + print("All positive: ", x, y, z) + elif x <= 0 and y <= 0 and z <= 0: + print("All non-positive: ", x, y, z) + else: + if x > 0: + print("X positive") + elif y > 0: + print("Y positive") + else: + print("Z positive") + x += 1 + y += 1 + z += 1 + + +def RetryLoopTest(retry_count: t.CInt) -> t.CInt: + attempt: t.CInt = 0 + success: t.CInt = 0 + while attempt < retry_count: + if attempt < config.MAX_RETRY: + print("Attempt: ", attempt, " less than max") + success = attempt * 2 + elif attempt == config.MAX_RETRY: + print("At max retry") + success = -1 + else: + print("Beyond max retry") + success = -2 + attempt += 1 + return success + + +def BitwiseOperationsTest(value: t.CInt) -> t.CInt: + shifted: t.CInt = 0 + masked: t.CInt = 0 + xored: t.CInt = 0 + anded: t.CInt = 0 + ored: t.CInt = 0 + shifted = value << config.SHIFT_AMOUNT + print("Left shift: ", shifted) + shifted = value >> config.SHIFT_AMOUNT + print("Right shift: ", shifted) + masked = value & config.MASK_VALUE + print("Bitwise AND mask: ", masked) + xored = value ^ config.MASK_VALUE + print("Bitwise XOR: ", xored) + anded = value & (config.MASK_VALUE >> config.SHIFT_AMOUNT) + print("Bitwise AND shifted mask: ", anded) + ored = value | config.SHIFT_AMOUNT + print("Bitwise OR shift: ", ored) + return masked + + +def CompoundAssignmentMathTest(a: t.CInt, b: t.CInt) -> t.CInt: + x: t.CInt = a + y: t.CInt = b + result: t.CInt = 0 + x += y + print("x += y: ", x) + x -= y + print("x -= y: ", x) + x *= y + print("x *= y: ", x) + x = a + y = b + if b != 0: + x /= b + print("x /= y: ", x) + x = a + if b != 0: + x %= b + print("x %%= y: ", x) + x = a + x <<= config.SHIFT_AMOUNT + print("x <<= shift: ", x) + x >>= config.SHIFT_AMOUNT + print("x >>= shift: ", x) + x &= config.MASK_VALUE + print("x &= mask: ", x) + x |= config.SHIFT_AMOUNT + print("x |= shift: ", x) + result = (a + b) * config.MATH_SCALE - config.MATH_OFFSET + print("Compound: (a+b)*scale-offset: ", result) + result = (a * b) + (config.MATH_OFFSET / 2) + print("Compound: a*b+offset/2: ", result) + return result + + +def PowerAndModuloTest(base: t.CInt, exponent: t.CInt) -> t.CInt: + result: t.CInt = 1 + temp: t.CInt = 0 + i: t.CInt = 0 + while i < exponent: + result *= base + i += 1 + print("Power: ", result) + temp = result % config.MODULO_DIVISOR + print("Power mod: ", temp) + temp = (base * config.EXPONENT_BASE) % config.MODULO_DIVISOR + print("base*exp %% divisor: ", temp) + temp = ((base + config.MATH_OFFSET) * config.MATH_SCALE) % config.MODULO_DIVISOR + print("(base+offset)*scale %% divisor: ", temp) + return result + + +def MixedArithmeticTest(x: t.CInt, y: t.CInt, z: t.CInt) -> t.CInt: + result: t.CInt = 0 + result = (x + y) * z + print("(x+y)*z: ", result) + result = x + (y * z) + print("x+(y*z): ", result) + result = ((x + y) * config.MATH_SCALE) - config.MATH_OFFSET + print("((x+y)*scale)-offset: ", result) + result = (x * config.MATH_SCALE) + (y * config.MATH_SCALE) + print("x*scale + y*scale: ", result) + result = ((x % config.MODULO_DIVISOR) + (y % config.MODULO_DIVISOR)) * config.MATH_SCALE + print("(x%%mod + y%%mod)*scale: ", result) + temp: t.CInt = 0 + temp = x | y & z + print("x | y & z: ", temp) + temp = (x | y) & z + print("(x | y) & z: ", temp) + temp = x ^ y ^ z + print("x ^ y ^ z: ", temp) + return result + + +def MathWithWhileLoopTest(start: t.CInt, count: t.CInt) -> t.CInt: + idx: t.CInt = 0 + accumulator: t.CInt = 0 + multiplier: t.CInt = config.MATH_SCALE + while idx < count: + temp: t.CInt = (start + idx) * multiplier + temp = temp + config.MATH_OFFSET + if temp > config.THRESHOLD: + temp = config.THRESHOLD + accumulator += temp + multiplier += 1 + idx += 1 + print("Accumulator: ", accumulator) + return accumulator + + +def ComplexNestedMathTest(a: t.CInt, b: t.CInt) -> t.CInt: + layer1: t.CInt = 0 + layer2: t.CInt = 0 + layer3: t.CInt = 0 + i: t.CInt = 0 + layer1 = (a + b) * config.MATH_SCALE + print("Layer1: ", layer1) + while i < config.BIT_RANGE: + layer2 += layer1 >> 1 + i += 1 + print("Layer2: ", layer2) + layer3 = layer1 + layer2 - config.MATH_OFFSET + print("Layer3: ", layer3) + layer3 = layer3 * config.MATH_SCALE / 2 if config.MATH_SCALE != 0 else layer3 + print("Layer3 scaled: ", layer3) + return layer3 + + +def ConditionalMathChainTest(value: t.CInt) -> t.CInt: + result: t.CInt = 0 + step: t.CInt = 0 + while step < config.LOOP_LIMIT: + if step < 5: + result += step * config.MATH_SCALE + print("step<5: ", result) + elif step < 10: + result -= step - config.MATH_OFFSET + print("step<10: ", result) + elif step < 15: + result += (step * config.MATH_OFFSET) / config.MATH_SCALE + print("step<15: ", result) + else: + result = result * config.EXPONENT_BASE % config.MODULO_DIVISOR + print("step>=15: ", result) + step += 1 + return result + + +def BitManipulationMathTest(value: t.CInt) -> t.CInt: + original: t.CInt = value + nibble: t.CInt = 0 + result: t.CInt = 0 + result = (value << config.SHIFT_AMOUNT) | (value >> (8 - config.SHIFT_AMOUNT)) + print("Rotate left: ", result) + result = (value >> config.SHIFT_AMOUNT) | (value << (8 - config.SHIFT_AMOUNT)) + print("Rotate right: ", result) + nibble = value & 0xF + print("Lower nibble: ", nibble) + nibble = (value >> config.BIT_RANGE) & 0xF + print("Upper nibble: ", nibble) + result = ((value & config.MASK_VALUE) + config.MATH_OFFSET) * config.MATH_SCALE + print("Masked and scaled: ", result) + result = ((original << config.SHIFT_AMOUNT) ^ original) & config.MASK_VALUE + print("XOR shifted: ", result) + return result \ No newline at end of file diff --git a/Test/TestProject2/output/09ba6d4617920d26.deps.json b/Test/TestProject2/output/09ba6d4617920d26.deps.json new file mode 100644 index 0000000..d56083f --- /dev/null +++ b/Test/TestProject2/output/09ba6d4617920d26.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b", "zc.test": "75583f20a922ab2e", "test": "75583f20a922ab2e", "zc.class_test": "a7dab00d979c009c", "class_test": "a7dab00d979c009c", "zc.config": "cfc83b830141b00e", "config": "cfc83b830141b00e", "zc.logic_test": "faec3233d98371da", "logic_test": "faec3233d98371da"} \ No newline at end of file diff --git a/Test/TestProject2/output/75583f20a922ab2e.deps.json b/Test/TestProject2/output/75583f20a922ab2e.deps.json new file mode 100644 index 0000000..bee91bf --- /dev/null +++ b/Test/TestProject2/output/75583f20a922ab2e.deps.json @@ -0,0 +1 @@ +{"main": "09ba6d4617920d26", "stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b", "zc.class_test": "a7dab00d979c009c", "class_test": "a7dab00d979c009c", "zc.config": "cfc83b830141b00e", "config": "cfc83b830141b00e", "zc.logic_test": "faec3233d98371da", "logic_test": "faec3233d98371da"} \ No newline at end of file diff --git a/Test/TestProject2/output/a7dab00d979c009c.deps.json b/Test/TestProject2/output/a7dab00d979c009c.deps.json new file mode 100644 index 0000000..ed6405d --- /dev/null +++ b/Test/TestProject2/output/a7dab00d979c009c.deps.json @@ -0,0 +1 @@ +{"main": "09ba6d4617920d26", "stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b", "zc.test": "75583f20a922ab2e", "test": "75583f20a922ab2e", "zc.config": "cfc83b830141b00e", "config": "cfc83b830141b00e", "zc.logic_test": "faec3233d98371da", "logic_test": "faec3233d98371da"} \ No newline at end of file diff --git a/Test/TestProject2/output/cfc83b830141b00e.deps.json b/Test/TestProject2/output/cfc83b830141b00e.deps.json new file mode 100644 index 0000000..3188929 --- /dev/null +++ b/Test/TestProject2/output/cfc83b830141b00e.deps.json @@ -0,0 +1 @@ +{"main": "09ba6d4617920d26", "stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b", "zc.test": "75583f20a922ab2e", "test": "75583f20a922ab2e", "zc.class_test": "a7dab00d979c009c", "class_test": "a7dab00d979c009c", "zc.logic_test": "faec3233d98371da", "logic_test": "faec3233d98371da"} \ No newline at end of file diff --git a/Test/TestProject2/output/faec3233d98371da.deps.json b/Test/TestProject2/output/faec3233d98371da.deps.json new file mode 100644 index 0000000..bc966ed --- /dev/null +++ b/Test/TestProject2/output/faec3233d98371da.deps.json @@ -0,0 +1 @@ +{"main": "09ba6d4617920d26", "stdint": "56cdd754a8a09347", "stdio": "73edbcf76e32d00b", "zc.test": "75583f20a922ab2e", "test": "75583f20a922ab2e", "zc.class_test": "a7dab00d979c009c", "class_test": "a7dab00d979c009c", "zc.config": "cfc83b830141b00e", "config": "cfc83b830141b00e"} \ No newline at end of file diff --git a/Test/TestProject2/project.json b/Test/TestProject2/project.json new file mode 100644 index 0000000..aa634e2 --- /dev/null +++ b/Test/TestProject2/project.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "TestProject2", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-lmsvcrt", "-lucrt", "-lpthread"], + "output": "TestProject2.exe" + }, + "includes": [ + "./includes" + ], + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} \ No newline at end of file diff --git a/Test/TestProject2/temp/09ba6d4617920d26.pyi b/Test/TestProject2/temp/09ba6d4617920d26.pyi new file mode 100644 index 0000000..65f16df --- /dev/null +++ b/Test/TestProject2/temp/09ba6d4617920d26.pyi @@ -0,0 +1,17 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + +import t +import c + + +import stdio +import stdint +import zc.config as config +import zc.test as test +import zc.logic_test as logic +import zc.class_test as class_test + +def main() -> stdint.INT | t.State: pass diff --git a/Test/TestProject2/temp/56cdd754a8a09347.pyi b/Test/TestProject2/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/TestProject2/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/TestProject2/temp/73edbcf76e32d00b.pyi b/Test/TestProject2/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..0b25044 --- /dev/null +++ b/Test/TestProject2/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport | t.State: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport | t.State: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport | t.State: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport | t.State: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport | t.State: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport | t.State: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport | t.State: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport | t.State: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/TestProject2/temp/75583f20a922ab2e.pyi b/Test/TestProject2/temp/75583f20a922ab2e.pyi new file mode 100644 index 0000000..8a40bd2 --- /dev/null +++ b/Test/TestProject2/temp/75583f20a922ab2e.pyi @@ -0,0 +1,38 @@ +""" +Auto-generated Python stub file from zc.test.py +Module: zc.test +""" + + +import config +import t, c + +def AboutSizeTWhileTest(length: t.CSizeT) -> t.CVoid | t.State: pass + +def MathBasicTest(x: t.CInt, y: t.CInt) -> t.CInt | t.State: pass + +def MathAdvancedTest(value: t.CInt) -> t.CInt | t.State: pass + +def WhileWithElifElseTest(start: t.CInt, end: t.CInt) -> t.CVoid | t.State: pass + +def NestedWhileWithMacrosTest(outer_limit: t.CInt, inner_limit: t.CInt) -> t.CVoid | t.State: pass + +def ComplexConditionTest(a: t.CInt, b: t.CInt, c_val: t.CInt) -> t.CVoid | t.State: pass + +def RetryLoopTest(retry_count: t.CInt) -> t.CInt | t.State: pass + +def BitwiseOperationsTest(value: t.CInt) -> t.CInt | t.State: pass + +def CompoundAssignmentMathTest(a: t.CInt, b: t.CInt) -> t.CInt | t.State: pass + +def PowerAndModuloTest(base: t.CInt, exponent: t.CInt) -> t.CInt | t.State: pass + +def MixedArithmeticTest(x: t.CInt, y: t.CInt, z: t.CInt) -> t.CInt | t.State: pass + +def MathWithWhileLoopTest(start: t.CInt, count: t.CInt) -> t.CInt | t.State: pass + +def ComplexNestedMathTest(a: t.CInt, b: t.CInt) -> t.CInt | t.State: pass + +def ConditionalMathChainTest(value: t.CInt) -> t.CInt | t.State: pass + +def BitManipulationMathTest(value: t.CInt) -> t.CInt | t.State: pass diff --git a/Test/TestProject2/temp/_sha1_map.txt b/Test/TestProject2/temp/_sha1_map.txt new file mode 100644 index 0000000..9037b15 --- /dev/null +++ b/Test/TestProject2/temp/_sha1_map.txt @@ -0,0 +1,7 @@ +09ba6d4617920d26:main.py +56cdd754a8a09347:includes/stdint.py +73edbcf76e32d00b:includes/stdio.py +75583f20a922ab2e:zc\test.py +a7dab00d979c009c:zc\class_test.py +cfc83b830141b00e:zc\config.py +faec3233d98371da:zc\logic_test.py diff --git a/Test/TestProject2/temp/_shared_sym.pkl b/Test/TestProject2/temp/_shared_sym.pkl new file mode 100644 index 0000000..94768a3 Binary files /dev/null and b/Test/TestProject2/temp/_shared_sym.pkl differ diff --git a/Test/TestProject2/temp/a7dab00d979c009c.pyi b/Test/TestProject2/temp/a7dab00d979c009c.pyi new file mode 100644 index 0000000..0b959e8 --- /dev/null +++ b/Test/TestProject2/temp/a7dab00d979c009c.pyi @@ -0,0 +1,66 @@ +""" +Auto-generated Python stub file from zc.class_test.py +Module: zc.class_test +""" + + +import stdio +import stdint +import t, c + +class SimpleData(t.Object): + x: t.CInt + y: t.CInt +class Point3D(t.Object): + x: t.CFloat + y: t.CFloat + z: t.CFloat +class Student(t.Object): + name: t.CChar | t.CPtr + age: t.CInt + score: t.CInt + def __init__(self: Student, n: t.CChar | t.CPtr, a: t.CInt, s: t.CInt) -> t.CVoid | t.State: pass + def get_age(self: Student) -> t.CInt | t.State: pass + def get_score(self: Student) -> t.CInt | t.State: pass +class Counter(t.Object): + value: t.CInt + def __init__(self: Counter, initial: t.CInt) -> t.CVoid | t.State: pass + def increment(self: Counter) -> t.CVoid | t.State: pass + def get_value(self: Counter) -> t.CInt | t.State: pass +class StackObj(t.Object): + data: t.CInt + next_ptr: t.CVoid | t.CPtr + +def TestBasicDataClass() -> t.CVoid | t.State: pass + +def TestPoint3DClass() -> t.CVoid | t.State: pass + +def TestStudentClass() -> t.CVoid | t.State: pass + +def TestCounterClass() -> t.CVoid | t.State: pass + +def TestStackAllocation() -> t.CVoid | t.State: pass + +def TestHeapAllocation() -> t.CVoid | t.State: pass + +def TestHeapObjectWithInit() -> t.CVoid | t.State: pass + +def TestMultipleStackObjects() -> t.CVoid | t.State: pass + +def TestImplicitInitCall() -> t.CVoid | t.State: pass + +def TestClassWithBitFields() -> t.CVoid | t.State: pass + +def TestIntArray() -> t.CVoid | t.State: pass + +def TestFloatArray() -> t.CVoid | t.State: pass + +def TestCharArray() -> t.CVoid | t.State: pass + +def TestNestedArray() -> t.CVoid | t.State: pass + +def TestArrayWithStruct() -> t.CVoid | t.State: pass + +def TestArrayPointer() -> t.CVoid | t.State: pass + +def TestDynamicString() -> t.CVoid | t.State: pass diff --git a/Test/TestProject2/temp/cfc83b830141b00e.pyi b/Test/TestProject2/temp/cfc83b830141b00e.pyi new file mode 100644 index 0000000..5af877f --- /dev/null +++ b/Test/TestProject2/temp/cfc83b830141b00e.pyi @@ -0,0 +1,27 @@ +""" +Auto-generated Python stub file from zc.config.py +Module: zc.config +""" + + +import t, c + +POSMAX: t.CDefine = 100 +MAX_RETRY: t.CDefine = 5 +BUFFER_SIZE: t.CDefine = 256 +PI: t.CDefine = 3.14159 +EULER: t.CDefine = 2.71828 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +NULL: t.CDefine = 0 +MATH_OFFSET: t.CDefine = 10 +MATH_SCALE: t.CDefine = 2 +THRESHOLD: t.CDefine = 50 +LOOP_LIMIT: t.CDefine = 20 +SHIFT_AMOUNT: t.CDefine = 2 +MASK_VALUE: t.CDefine = 0xFF +BIT_RANGE: t.CDefine = 4 +EXPONENT_BASE: t.CDefine = 3 +MODULO_DIVISOR: t.CDefine = 7 +SCALE_SHIFT: t.CDefine = 4 +HALF_SCALE: t.CDefine = 0.5 \ No newline at end of file diff --git a/Test/TestProject2/temp/faec3233d98371da.pyi b/Test/TestProject2/temp/faec3233d98371da.pyi new file mode 100644 index 0000000..82fcbb8 --- /dev/null +++ b/Test/TestProject2/temp/faec3233d98371da.pyi @@ -0,0 +1,54 @@ +""" +Auto-generated Python stub file from zc.logic_test.py +Module: zc.logic_test +""" + + +import config +import t, c + +def ForRangeBasicTest(stop: t.CInt) -> t.CVoid | t.State: pass + +def ForRangeWithStartStop(start: t.CInt, stop: t.CInt, step: t.CInt) -> t.CVoid | t.State: pass + +def NestedForRangeTest(rows: t.CInt, cols: t.CInt) -> t.CVoid | t.State: pass + +def ForWithIfBreakTest(data_size: t.CInt) -> t.CVoid | t.State: pass + +def ForWithIfContinueTest(n: t.CInt) -> t.CVoid | t.State: pass + +def ForWithElifBranchTest(value: t.CInt) -> t.CVoid | t.State: pass + +def WhileWithIfElifElseTest(iterations: t.CInt) -> t.CVoid | t.State: pass + +def WhileWithNestedIfTest(limit: t.CInt) -> t.CVoid | t.State: pass + +def WhileWithMatchCaseTest(value: t.CInt) -> t.CVoid | t.State: pass + +def WhileWithMatchCaseNoBreakTest(value: t.CInt) -> t.CVoid | t.State: pass + +def ComplexForWhileMatchTest(outer_limit: t.CInt, inner_limit: t.CInt) -> t.CVoid | t.State: pass + +def ForWithCaseAndNoBreakTest(n: t.CInt) -> t.CVoid | t.State: pass + +def WhileWithBreakConditionTest(limit: t.CInt) -> t.CVoid | t.State: pass + +def NestedWhileWithMultipleBreakPoints(depth: t.CInt, width: t.CInt) -> t.CVoid | t.State: pass + +def ForWithMatchCaseInLoopTest(iterations: t.CInt) -> t.CVoid | t.State: pass + +def ComplexLogicWithElifChains(a: t.CInt, b: t.CInt, c_val: t.CInt) -> t.CVoid | t.State: pass + +def ForRangeWithStepAndCondition(n: t.CInt, step: t.CInt) -> t.CVoid | t.State: pass + +def MatchCaseWithGuardConditions(value: t.CInt) -> t.CVoid | t.State: pass + +def WhileWithMultipleMatchCases(iterations: t.CInt) -> t.CVoid | t.State: pass + +def ForWhileMixWithBreakAndContinue(n: t.CInt) -> t.CVoid | t.State: pass + +def ComplexCaseMatchingWithRanges(start: t.CInt, end: t.CInt) -> t.CVoid | t.State: pass + +def WhileWithElifInElifChain(limit: t.CInt) -> t.CVoid | t.State: pass + +def ForWithCaseNoBreakNested(inner_limit: t.CInt) -> t.CVoid | t.State: pass diff --git a/Test/TestProject3/App/definetest.py b/Test/TestProject3/App/definetest.py new file mode 100644 index 0000000..7808e43 --- /dev/null +++ b/Test/TestProject3/App/definetest.py @@ -0,0 +1,422 @@ +import t, c +from t import CInt, CInt32T, CUInt32T, CUInt64T, CFloat64T, CPtr, CChar, CDefine, CUInt16T +import viperlib +import stdlib +import platmacro + + +MAX_SIZE: t.CDefine = 1024 +MIN_VAL: t.CDefine = 0 +MAX_VAL: t.CDefine = 100 +MASK_BYTE: t.CDefine = 0xFF +SHIFT_BITS: t.CDefine = 8 +PI_INT: t.CDefine = 3 +ENABLED: t.CDefine = 1 +DISABLED: t.CDefine = 0 +PAGE_SIZE: t.CDefine = 4096 +BUFFER_LEN: t.CDefine = 256 + +CODE_SEG: t.CDefine | t.CUInt16T = 0x08 +DATA_SEG: t.CDefine | t.CUInt16T = 0x10 +STACK_SEG: t.CDefine | t.CUInt16T = 0x20 + + +def MAKE_FLAG(bit: CInt32T) -> t.CDefine: + return 1 << bit + +def CLAMP(x: CInt32T, lo: CInt32T, hi: CInt32T) -> t.CDefine: + if x < lo: + return lo + if x > hi: + return hi + return x + + +def test_basic_define() -> CInt: + print(MAX_SIZE) + print(MIN_VAL) + print(MAX_VAL) + print(MASK_BYTE) + print(SHIFT_BITS) + return 0 + +def test_define_arithmetic() -> CInt: + a: CInt32T = 10 + b: CInt32T = a + MAX_SIZE + print(b) + c_val: CInt32T = (a << SHIFT_BITS) & MASK_BYTE + print(c_val) + d: CInt32T = MAX_VAL - MIN_VAL + print(d) + e: CInt32T = PAGE_SIZE / 4 + print(e) + return 0 + +def test_define_conditional() -> CInt: + mode: CInt32T = ENABLED + if mode == ENABLED: + print(1) + else: + print(0) + if mode == DISABLED: + print(0) + else: + print(1) + val: CInt32T = 50 + if val > MAX_VAL: + print(1) + else: + print(0) + if val < MAX_VAL: + print(1) + else: + print(0) + return 0 + +def test_define_loop() -> CInt: + i: CInt32T = 0 + while i < MAX_VAL: + i = i + 1 + if i > 10: + break + print(i) + i = 0 + while i < MAX_SIZE: + i = i + PAGE_SIZE + if i >= PAGE_SIZE * 4: + break + print(i) + return 0 + +def test_typed_define() -> CInt: + seg: CUInt16T = CODE_SEG | DATA_SEG | STACK_SEG + print(seg) + cs: CUInt16T = CODE_SEG + print(cs) + ds: CUInt16T = DATA_SEG + print(ds) + return 0 + +def test_define_function() -> CInt: + flag0 = MAKE_FLAG(0) + print(flag0) + flag3 = MAKE_FLAG(3) + print(flag3) + flag7 = MAKE_FLAG(7) + print(flag7) + return 0 + +def test_define_clamp() -> CInt: + v1 = CLAMP(50, 0, 100) + print(v1) + v2 = CLAMP(-10, 0, 100) + print(v2) + v3 = CLAMP(150, 0, 100) + print(v3) + return 0 + +def test_define_string() -> CInt: + buf: CChar | CPtr = CPtr(stdlib.malloc(BUFFER_LEN)) + viperlib.snprintf(buf, BUFFER_LEN, "MAX_SIZE=%d PAGE=%d MASK=0x%x", MAX_SIZE, PAGE_SIZE, MASK_BYTE) + print(buf) + stdlib.free(buf) + return 0 + +def test_define_combined() -> CInt: + flags: CUInt32T = MAKE_FLAG(0) | MAKE_FLAG(1) | MAKE_FLAG(2) + print(flags) + shifted: CUInt32T = MASK_BYTE << SHIFT_BITS + print(shifted) + total: CUInt32T = PAGE_SIZE + BUFFER_LEN + print(total) + return 0 + + +def test_cif_basic() -> CInt: + if c.CIf(ENABLED): + print(1) + else: + print(0) + if c.CIf(DISABLED): + print(0) + else: + print(1) + if c.CIf(MAX_SIZE > 512): + print(1) + else: + print(0) + if c.CIf(MIN_VAL > 0): + print(0) + else: + print(1) + return 0 + +def test_cif_elif_else() -> CInt: + val: CInt32T = 2 + if c.CIf(val == 1): + print(1) + elif c.CIf(val == 2): + print(2) + elif c.CIf(val == 3): + print(3) + else: + print(0) + if c.CIf(val > 10): + print(10) + elif c.CIf(val > 5): + print(5) + else: + print(val) + return 0 + +def test_cifdef_cifndef() -> CInt: + if c.CIfdef(MAX_SIZE): + print(MAX_SIZE) + else: + print(0) + if c.CIfdef(UNDEFINED_MACRO_XYZ): + print(0) + else: + print(1) + if c.CIfndef(UNDEFINED_MACRO_XYZ): + print(1) + else: + print(0) + if c.CIfndef(MAX_SIZE): + print(0) + else: + print(1) + return 0 + +def test_cif_platform() -> CInt: + if c.CIfdef(_WIN32): + print(1) + else: + print(0) + if c.CIfdef(__x86_64__): + print(1) + else: + print(0) + if c.CIf(SIZEOF_VOID_P == 8): + print(8) + elif c.CIf(SIZEOF_VOID_P == 4): + print(4) + else: + print(0) + return 0 + +def test_cif_nested() -> CInt: + if c.CIf(ENABLED): + if c.CIf(MAX_SIZE > 512): + print(1) + else: + print(0) + if c.CIfdef(PAGE_SIZE): + print(PAGE_SIZE) + else: + print(0) + else: + print(0) + return 0 + +def test_cif_expr() -> CInt: + if c.CIf(MASK_BYTE & 0x0F): + print(1) + else: + print(0) + if c.CIf((MAX_SIZE >> SHIFT_BITS) > 0): + print(1) + else: + print(0) + if c.CIf(ENABLED and MAX_SIZE > 0): + print(1) + else: + print(0) + if c.CIf(DISABLED or MAX_SIZE > 0): + print(1) + else: + print(0) + return 0 + +def test_platmacro_platform() -> CInt: + if c.CIfdef(platmacro.IS_WINDOWS): + print(1) + else: + print(0) + if c.CIf(platmacro.IS_WINDOWS == 1): + print(1) + else: + print(0) + if c.CIf(platmacro.IS_LINUX == 0): + print(1) + else: + print(0) + if c.CIf(platmacro.IS_X86_64 == 1): + print(1) + else: + print(0) + return 0 + +def test_platmacro_sizes() -> CInt: + print(platmacro.PTR_SIZE) + print(platmacro.SIZEOF_INT) + print(platmacro.SIZEOF_LONG) + print(platmacro.SIZEOF_DOUBLE) + print(platmacro.PAGE_SIZE) + print(platmacro.CACHE_LINE_SIZE) + return 0 + +def test_platmacro_endian() -> CInt: + if c.CIf(platmacro.IS_LITTLE_ENDIAN == 1): + print(1) + else: + print(0) + if c.CIf(platmacro.IS_BIG_ENDIAN == 0): + print(1) + else: + print(0) + if c.CIf(platmacro.BYTE_ORDER_LE == 1): + print(1) + else: + print(0) + return 0 + +def test_platmacro_features() -> CInt: + if c.CIf(platmacro.HAS_SSE2 == 1): + print(1) + else: + print(0) + if c.CIf(platmacro.HAS_AVX == 1): + print(1) + else: + print(0) + if c.CIf(platmacro.HAS_NEON == 0): + print(1) + else: + print(0) + return 0 + +def test_platmacro_align() -> CInt: + print(platmacro.ALIGNOF_INT) + print(platmacro.ALIGNOF_PTR) + print(platmacro.ALIGNOF_DOUBLE) + if c.CIf(platmacro.ALIGNOF_PTR == 8): + print(1) + else: + print(0) + return 0 + +def test_cifdef_cross_module() -> CInt: + if c.CIfdef(platmacro.IS_WINDOWS): + if c.CIf(platmacro.PTR_SIZE == 8): + print(64) + else: + print(32) + else: + print(0) + if c.CIfndef(platmacro.IS_ARM64): + print(1) + else: + print(0) + if c.CIfdef(platmacro.HAS_AVX2): + print(1) + else: + print(0) + return 0 + +def test_cifdef_guard() -> CInt: + MY_HEADER_GUARD: t.CDefine = 1 + if c.CIfndef(MY_HEADER_GUARD): + print(0) + else: + print(1) + if c.CIfdef(MY_HEADER_GUARD): + print(1) + else: + print(0) + return 0 + +def test_cifdef_undefined() -> CInt: + if c.CIfndef(NONEXISTENT_MACRO_ABC): + print(1) + else: + print(0) + if c.CIfndef(THIS_IS_ALSO_NOT_DEFINED): + print(1) + else: + print(0) + if c.CIfdef(NONEXISTENT_MACRO_ABC): + print(0) + else: + print(1) + return 0 + +def test_cifdef_complex() -> CInt: + if c.CIfdef(platmacro.IS_WINDOWS) and c.CIf(platmacro.PTR_SIZE == 8): + print(1) + else: + print(0) + if c.CIfndef(platmacro.IS_ARM64) and c.CIf(platmacro.IS_X86_64 == 1): + print(1) + else: + print(0) + if c.CIfdef(platmacro.HAS_SSE2): + if c.CIfdef(platmacro.HAS_AVX): + print(2) + else: + print(1) + else: + print(0) + return 0 + + +def define_main() -> CInt: + print("=== Basic Define Test ===") + test_basic_define() + print("=== Define Arithmetic Test ===") + test_define_arithmetic() + print("=== Define Conditional Test ===") + test_define_conditional() + print("=== Define Loop Test ===") + test_define_loop() + print("=== Typed Define Test ===") + test_typed_define() + print("=== Define Function (Macro) Test ===") + test_define_function() + print("=== Define Clamp (Macro) Test ===") + test_define_clamp() + print("=== Define String Test ===") + test_define_string() + print("=== Define Combined Test ===") + test_define_combined() + print("=== CIf Basic Test ===") + test_cif_basic() + print("=== CIf Elif Else Test ===") + test_cif_elif_else() + print("=== CIfdef/CIfndef Test ===") + test_cifdef_cifndef() + print("=== CIf Platform Test ===") + test_cif_platform() + print("=== CIf Nested Test ===") + test_cif_nested() + print("=== CIf Expression Test ===") + test_cif_expr() + print("=== Platmacro Platform Test ===") + test_platmacro_platform() + print("=== Platmacro Sizes Test ===") + test_platmacro_sizes() + print("=== Platmacro Endian Test ===") + test_platmacro_endian() + print("=== Platmacro Features Test ===") + test_platmacro_features() + print("=== Platmacro Align Test ===") + test_platmacro_align() + print("=== CIfdef Cross-Module Test ===") + test_cifdef_cross_module() + print("=== CIfdef Guard Test ===") + test_cifdef_guard() + print("=== CIfdef Undefined Test ===") + test_cifdef_undefined() + print("=== CIfdef Complex Test ===") + test_cifdef_complex() + return 0 diff --git a/Test/TestProject3/App/enumtest.py b/Test/TestProject3/App/enumtest.py new file mode 100644 index 0000000..c935a48 --- /dev/null +++ b/Test/TestProject3/App/enumtest.py @@ -0,0 +1,95 @@ +import t, c +from t import CInt, CPtr, CChar, CInt32T, CExport +import viperlib +import stdlib + + +class Color(t.CEnum): + Red = 0 + Green = 1 + Blue = 2 + + +class Option(t.REnum): + class Some: + value: CInt + Empty = 1 + + +class Result(t.REnum): + class Ok: + value: CInt + class Err: + msg: t.CChar | CPtr + + +class GeoShape(t.REnum): + class GCircle: + radius: CInt + class GRect: + w: CInt + h: CInt + class GPoint: + x: CInt + y: CInt + + +def enum_main() -> CInt: + buf: CChar | CPtr = CPtr(stdlib.malloc(256)) + + c1: CInt = Color.Red + c2: CInt = Color.Green + c3: CInt = Color.Blue + viperlib.snprintf(buf, 256, "CEnum: Red=%d Green=%d Blue=%d", c1, c2, c3) + print(buf) + + opt: Option = Option.Some(42) + match opt: + case Option.Some(v): + viperlib.snprintf(buf, 256, "Option.Some: value=%d", v) + print(buf) + case Option.Empty(): + pass + + res1: Result = Result.Ok(100) + match res1: + case Result.Ok(v): + viperlib.snprintf(buf, 256, "Result.Ok: value=%d", v) + print(buf) + case Result.Err(e): + pass + + res2: Result = Result.Err("not found") + match res2: + case Result.Ok(v): + pass + case Result.Err(e): + viperlib.snprintf(buf, 256, "Result.Err: msg=%s", e) + print(buf) + + s1: GeoShape = GeoShape.GCircle(5) + match s1: + case GeoShape.GCircle(r): + viperlib.snprintf(buf, 256, "GeoShape.GCircle: radius=%d", r) + print(buf) + case _: + pass + + s2: GeoShape = GeoShape.GRect(10, 20) + match s2: + case GeoShape.GRect(w, h): + viperlib.snprintf(buf, 256, "GeoShape.GRect: w=%d h=%d", w, h) + print(buf) + case _: + pass + + s3: GeoShape = GeoShape.GPoint(3, 4) + match s3: + case GeoShape.GPoint(x, y): + viperlib.snprintf(buf, 256, "GeoShape.GPoint: x=%d y=%d", x, y) + print(buf) + case _: + pass + + stdlib.free(buf) + return 0 diff --git a/Test/TestProject3/App/fileiotest.py b/Test/TestProject3/App/fileiotest.py new file mode 100644 index 0000000..98d6e77 --- /dev/null +++ b/Test/TestProject3/App/fileiotest.py @@ -0,0 +1,395 @@ +import t, c +from t import CInt, CInt32T, CUInt32T, CPtr, CChar, CExport +from stdint import * +import stdlib +import viperlib +import w32.win32base +import w32.win32file +import w32.win32console +import w32.fileio +from w32.fileio import File, FileW, MODE, FRESULT, SEEK_SET, SEEK_CUR, SEEK_END + + +BUF_SIZE: t.CDefine = 4096 + + +def fileio_main(): + buf: bytes = stdlib.malloc(256) + write_buf: bytes = stdlib.malloc(BUF_SIZE) + read_buf: bytes = stdlib.malloc(BUF_SIZE) + bytes_written: ULONG = 0 + bytes_read: ULONG = 0 + + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + hFile: w32.win32base.HANDLE = w32.win32file.CreateFileA( + "testfile.txt", + w32.win32file.GENERIC_WRITE, + w32.win32file.FILE_SHARE_READ, + None, + w32.win32file.CREATE_ALWAYS, + w32.win32file.FILE_ATTRIBUTE_NORMAL, + None + ) + + if hFile == w32.win32base.INVALID_HANDLE_VALUE: + print("Failed to create file") + return + + viperlib.snprintf(write_buf, BUF_SIZE, "Hello from TransPyC Win32 FileIO!\nLine 2: %d + %d = %d\n", 10, 20, 30) + write_len: ULONG = 0 + i: CInt = 0 + ch: bytes = write_buf + while i < BUF_SIZE: + if CInt(c.Deref(ch)) == 0: + break + write_len = write_len + 1 + i = i + 1 + ch = ch + 1 + + result: BOOL = w32.win32file.WriteFile(hFile, write_buf, write_len, c.Addr(bytes_written), None) + if result == 0: + print("WriteFile failed") + else: + viperlib.snprintf(buf, 256, "Written %d bytes to testfile.txt", bytes_written) + print(buf) + + w32.win32file.FlushFileBuffers(hFile) + w32.win32base.CloseHandle(hFile) + + hFile = w32.win32file.CreateFileA( + "testfile.txt", + w32.win32file.GENERIC_READ, + w32.win32file.FILE_SHARE_READ, + None, + w32.win32file.OPEN_EXISTING, + w32.win32file.FILE_ATTRIBUTE_NORMAL, + None + ) + + if hFile == w32.win32base.INVALID_HANDLE_VALUE: + print("Failed to open file for reading") + return + + read_len: ULONG = 0 + result = w32.win32file.ReadFile(hFile, read_buf, BUF_SIZE - 1, c.Addr(read_len), None) + if result == 0: + print("ReadFile failed") + else: + viperlib.snprintf(buf, 256, "Read %d bytes from testfile.txt", read_len) + print(buf) + + read_ptr: bytes = read_buf + read_ptr = read_ptr + read_len + c.DerefAs(read_ptr, 0) + print("--- File content ---") + print(read_buf) + print("--- End ---") + + fileSize: ULONG = w32.win32file.GetFileSize(hFile, None) + viperlib.snprintf(buf, 256, "File size: %d bytes", fileSize) + print(buf) + + w32.win32base.CloseHandle(hFile) + + attrs: ULONG = w32.win32file.GetFileAttributesA("testfile.txt") + if attrs == w32.win32base.INVALID_HANDLE_VALUE: + print("GetFileAttributes failed") + else: + viperlib.snprintf(buf, 256, "File attributes: 0x%X", attrs) + print(buf) + + w32.win32file.DeleteFileA("testfile.txt") + print("File deleted") + + stdlib.free(write_buf) + stdlib.free(read_buf) + + print("=== OOP FileIO: with context manager ===") + fileio_with_test() + + print("=== OOP FileIO: f handle style ===") + fileio_handle_test() + + print("=== OOP FileIO: RP/WP/AP modes ===") + fileio_rw_test() + + +def fileio_with_test(): + buf: bytes = stdlib.malloc(256) + write_buf: bytes = stdlib.malloc(BUF_SIZE) + read_buf: bytes = stdlib.malloc(BUF_SIZE) + + with File("oop_with.txt", MODE.W) as f: + viperlib.snprintf(write_buf, BUF_SIZE, "with context manager test!\nLine 2: %d\n", 42) + n: LONG = f.write_str(write_buf) + if n < 0: + print("[with] write failed") + else: + viperlib.snprintf(buf, 256, "[with] wrote %d bytes", n) + print(buf) + + with File("oop_with.txt", MODE.R) as f: + n = f.read_all(read_buf, BUF_SIZE) + if n < 0: + print("[with] read failed") + else: + viperlib.snprintf(buf, 256, "[with] read %d bytes", n) + print(buf) + print("[with] content:") + print(read_buf) + + with File("oop_with.txt", MODE.R) as f: + line1_len: LONG = f.readline(buf, 256) + viperlib.snprintf(read_buf, BUF_SIZE, "[with] Line1(%d): ", line1_len) + print(read_buf) + print(buf) + line2_len: LONG = f.readline(buf, 256) + viperlib.snprintf(read_buf, BUF_SIZE, "[with] Line2(%d): ", line2_len) + print(read_buf) + print(buf) + + with File("oop_with.txt", MODE.A) as f: + f.write_str("Appended line!\n") + + with File("oop_with.txt", MODE.R) as f: + n = f.read_all(read_buf, BUF_SIZE) + print("[with] after append:") + print(read_buf) + + with File("oop_with.txt", MODE.R) as f: + sz: LONGLONG = f.size() + pos: LONG = f.tell() + viperlib.snprintf(buf, 256, "[with] Size=%lld Pos=%d", sz, pos) + print(buf) + f.seek(5, SEEK_SET) + pos = f.tell() + viperlib.snprintf(buf, 256, "[with] After seek: Pos=%d", pos) + print(buf) + + w32.win32file.DeleteFileA("oop_with.txt") + print("[with] test file deleted") + + stdlib.free(buf) + stdlib.free(write_buf) + stdlib.free(read_buf) + + +def fileio_handle_test(): + buf: bytes = stdlib.malloc(256) + write_buf: bytes = stdlib.malloc(BUF_SIZE) + read_buf: bytes = stdlib.malloc(BUF_SIZE) + + fw: File = File("oop_handle.txt", MODE.W) + viperlib.snprintf(write_buf, BUF_SIZE, "f handle style test!\nLine 2: %d\n", 99) + n: LONG = fw.write_str(write_buf) + viperlib.snprintf(buf, 256, "[handle] wrote %d bytes", n) + print(buf) + fw.flush() + fw.close() + + fr: File = File("oop_handle.txt", MODE.R) + n = fr.read_all(read_buf, BUF_SIZE) + viperlib.snprintf(buf, 256, "[handle] read %d bytes", n) + print(buf) + print("[handle] content:") + print(read_buf) + fr.close() + + fr2: File = File("oop_handle.txt", MODE.R) + line1_len: LONG = fr2.readline(buf, 256) + viperlib.snprintf(read_buf, BUF_SIZE, "[handle] Line1(%d): ", line1_len) + print(read_buf) + print(buf) + line2_len: LONG = fr2.readline(buf, 256) + viperlib.snprintf(read_buf, BUF_SIZE, "[handle] Line2(%d): ", line2_len) + print(read_buf) + print(buf) + fr2.close() + + fa: File = File("oop_handle.txt", MODE.A) + fa.write_str("Appended by handle!\n") + fa.close() + + fr3: File = File("oop_handle.txt", MODE.R) + n = fr3.read_all(read_buf, BUF_SIZE) + print("[handle] after append:") + print(read_buf) + fr3.close() + + fr4: File = File("oop_handle.txt", MODE.R) + sz: LONGLONG = fr4.size() + pos: LONG = fr4.tell() + viperlib.snprintf(buf, 256, "[handle] Size=%lld Pos=%d", sz, pos) + print(buf) + fr4.seek(5, SEEK_SET) + pos = fr4.tell() + viperlib.snprintf(buf, 256, "[handle] After seek: Pos=%d", pos) + print(buf) + fr4.close() + + w32.win32file.DeleteFileA("oop_handle.txt") + print("[handle] test file deleted") + + stdlib.free(buf) + stdlib.free(write_buf) + stdlib.free(read_buf) + + +def fileio_rw_test(): + buf: bytes = stdlib.malloc(256) + + fw: File = File("rw_test.txt", MODE.W) + fw.write_str("original content\n") + fw.close() + + frp: File = File("rw_test.txt", MODE.RP) + n: LONG = frp.read_all(buf, 256) + viperlib.snprintf(buf, 256, "[rp] read %d bytes", n) + print(buf) + + frp.seek(0, SEEK_END) + frp.write_str("appended via RP\n") + frp.seek(0, SEEK_SET) + n = frp.read_all(buf, 256) + print("[rp] after RP append:") + print(buf) + frp.close() + + fwp: File = File("rw_test.txt", MODE.WP) + fwp.write_str("truncated + new\n") + fwp.seek(0, SEEK_SET) + n = fwp.read_all(buf, 256) + print("[wp] WP (truncate+read):") + print(buf) + fwp.close() + + fap: File = File("rw_test.txt", MODE.AP) + fap.write_str("a+ appended\n") + fap.seek(0, SEEK_SET) + n = fap.read_all(buf, 256) + print("[ap] AP (append+read):") + print(buf) + fap.close() + + w32.win32file.DeleteFileA("rw_test.txt") + print("[rw] test file deleted") + + print("=== OOP FileIO: wide char (u\"...\") ===") + fileio_wide_test() + + stdlib.free(buf) + + +def fileio_wide_test(): + buf: bytes = stdlib.malloc(256) + + fw: File = File("wide_test.txt", MODE.W) + fw.write_str("wide char test\n") + fw.close() + + fw2: FileW = FileW(u"wide_test.txt", MODE.R) + n: LONG = fw2.read_all(buf, 256) + viperlib.snprintf(buf, 256, "[wide] read %d bytes", n) + print(buf) + fw2.close() + + w32.win32file.DeleteFileA("wide_test.txt") + print("[wide] test file deleted") + + stdlib.free(buf) + + print("=== OOP FileIO: Chinese filename & content (u\"...\" = WCHAR_T) ===") + fileio_chinese_test() + + +def fileio_chinese_test(): + buf: bytes = stdlib.malloc(512) + bytes_written: ULONG = 0 + + # === T1: Chinese filename (WCHAR_T) + ANSI content === + print("[chinese] T1: Chinese filename + ANSI content") + fw: FileW = FileW(u"中文文件.txt", MODE.W) + if fw.closed: + print("[chinese] T1: create failed") + else: + fw.write_str("Hello from Chinese filename!\n") + fw.close() + + fr: FileW = FileW(u"中文文件.txt", MODE.R) + n: LONG = fr.read_all(buf, 512) + viperlib.snprintf(buf, 256, "[chinese] T1: read %d bytes", n) + print(buf) + print("[chinese] T1 content:") + print(buf) + fr.close() + + w32.win32file.DeleteFileW(u"中文文件.txt") + print("[chinese] T1: deleted") + + # === T2: Chinese filename + Chinese wide content (WCHAR_T) === + print("[chinese] T2: Chinese filename + Chinese wide content") + fw2: FileW = FileW(u"中文内容.txt", MODE.W) + if fw2.closed: + print("[chinese] T2: create failed") + else: + # u"你好世界\n" = 5 WCHARs = 10 bytes (UTF-16LE) + w32.win32file.WriteFile(fw2.handle, u"你好世界\n", 10, c.Addr(bytes_written), None) + viperlib.snprintf(buf, 256, "[chinese] T2: wrote %d WCHAR bytes", bytes_written) + print(buf) + fw2.close() + + fr2: FileW = FileW(u"中文内容.txt", MODE.R) + n = fr2.read_all(buf, 512) + viperlib.snprintf(buf, 256, "[chinese] T2: read %d bytes (UTF-16LE)", n) + print(buf) + fr2.close() + + w32.win32file.DeleteFileW(u"中文内容.txt") + print("[chinese] T2: deleted") + + # === T3: Chinese filename + mixed ANSI + wide content === + print("[chinese] T3: Chinese filename + mixed content") + fw3: FileW = FileW(u"混合测试.txt", MODE.WP) + if fw3.closed: + print("[chinese] T3: create failed") + else: + fw3.write_str("ASCII line\n") + # u"中文行\n" = 4 WCHARs = 8 bytes (UTF-16LE) + w32.win32file.WriteFile(fw3.handle, u"中文行\n", 8, c.Addr(bytes_written), None) + fw3.seek(0, SEEK_SET) + n: LONG = fw3.read_all(buf, 512) + viperlib.snprintf(buf, 256, "[chinese] T3: total %d bytes", n) + print(buf) + fw3.close() + + w32.win32file.DeleteFileW(u"混合测试.txt") + print("[chinese] T3: deleted") + + # === T4: Chinese filename + Chinese content via WriteConsoleW === + print("[chinese] T4: Write wide content and print via WriteConsoleW") + fw4: FileW = FileW(u"控制台测试.txt", MODE.W) + if fw4.closed: + print("[chinese] T4: create failed") + else: + # u"你好,世界!\n" = 7 WCHARs = 14 bytes (UTF-16LE) + w32.win32file.WriteFile(fw4.handle, u"你好,世界!\n", 14, c.Addr(bytes_written), None) + viperlib.snprintf(buf, 256, "[chinese] T4: wrote %d WCHAR bytes", bytes_written) + print(buf) + fw4.close() + + fr4: FileW = FileW(u"控制台测试.txt", MODE.R) + n = fr4.read_all(buf, 512) + viperlib.snprintf(buf, 256, "[chinese] T4: read %d bytes", n) + print(buf) + # Print wide content to console using WriteConsoleW + chars_written: ULONG = 0 + hOut: w32.win32base.HANDLE = w32.win32file.GetStdHandle(w32.win32file.STD_OUTPUT_HANDLE) + w32.win32console.WriteConsoleW(hOut, u"你好,世界!\n", 7, c.Addr(chars_written), None) + fr4.close() + + w32.win32file.DeleteFileW(u"控制台测试.txt") + print("[chinese] T4: deleted") + + stdlib.free(buf) diff --git a/Test/TestProject3/App/main.py b/Test/TestProject3/App/main.py new file mode 100644 index 0000000..738c5da --- /dev/null +++ b/Test/TestProject3/App/main.py @@ -0,0 +1,484 @@ +from stdint import * +import w32.win32console +import t, c +from t import CInt, CPtr, CChar, CInt32T, CUInt64T, CFloat64T, CExport, State +import viperlib +import stdlib +import definetest +import enumtest +import mpooltest +import vectortest +import fileiotest + + +# === 函数泛型 === + +def add[T](a: T, b: T) -> T: + return a + b + +def add_u64[T](a: T, b: T, c: CUInt64T) -> T: + return a + b + T(c) + +def fxi[T1, T2](a: T1, b: T2) -> T1: + return a + fxi2(a, b, CUInt64T(178900)) + +def fxi2[T1, T2, T3](a: T1, b: T2, c: T3) -> T1: + return a + T1(b) + T1(c) + +def wrap_add[T](a: T, b: T) -> T: + return add(a, b) + +def double_add[T](a: T, b: T) -> T: + return add(a, b) + add(a, b) + + +# === 结构体泛型 === + +class A[T](): + def __init__(self, a: T): + self.a = T(a) + def get_a(self) -> T: + return self.a + +class Pair[T1, T2](): + def __init__(self, first: T1, second: T2): + self.first = T1(first) + self.second = T2(second) + def get_first(self) -> T1: + return self.first + def get_second(self) -> T2: + return self.second + +class Calculator[T](): + def __init__(self, init_val: T): + self.val = T(init_val) + def compute(self, other: T) -> T: + return add(self.val, other) + def double_compute(self, other: T) -> T: + return double_add(self.val, other) + +class Container[T](): + def __init__(self, v: T): + self.value = T(v) + self.flag = CInt32T(1) + def get_value(self) -> T: + return self.value + def get_flag(self) -> CInt32T: + return self.flag + + +# === OOP 继承 + 虚方法(Gargantua 风格) === + +@t.CVTable +class Shape: + def __init__(self, x: CFloat64T, y: CFloat64T): + self.x = x + self.y = y + def area(self) -> CFloat64T: + return 0.0 + def perimeter(self) -> CFloat64T: + return 0.0 + def describe(self) -> CFloat64T: + return self.area() + self.perimeter() + +@t.CVTable +class Circle(Shape): + def __init__(self, x: CFloat64T, y: CFloat64T, r: CFloat64T): + self.x = x + self.y = y + self.r = r + def area(self) -> CFloat64T: + return 3.14159265 * self.r * self.r + def perimeter(self) -> CFloat64T: + return 2.0 * 3.14159265 * self.r + def scale(self, factor: CFloat64T) -> 'Circle' | CPtr: + self.r = self.r * factor + return t.CVoid(c.Addr(self), CPtr) + def move(self, dx: CFloat64T, dy: CFloat64T) -> 'Circle' | CPtr: + self.x = self.x + dx + self.y = self.y + dy + return t.CVoid(c.Addr(self), CPtr) + +@t.CVTable +class Rect(Shape): + def __init__(self, x: CFloat64T, y: CFloat64T, w: CFloat64T, h: CFloat64T): + self.x = x + self.y = y + self.w = w + self.h = h + def area(self) -> CFloat64T: + return self.w * self.h + def perimeter(self) -> CFloat64T: + return 2.0 * (self.w + self.h) + def scale(self, factor: CFloat64T) -> 'Rect' | CPtr: + self.w = self.w * factor + self.h = self.h * factor + return t.CVoid(c.Addr(self), CPtr) + + +# === 运算符重载 + 链式调用(Gargantua V3 风格,堆分配) === + +class Vec2: + x: CFloat64T + y: CFloat64T + + def __new__() -> 'Vec2' | CPtr: + return t.CVoid(t.CUInt64T(stdlib.malloc(16)), CPtr) + + def __init__(self, x: CFloat64T, y: CFloat64T): + self.x = x + self.y = y + + def __add__(self, b: 'Vec2' | CPtr) -> 'Vec2' | CPtr: + return Vec2(self.x + b.x, self.y + b.y) + + def __sub__(self, b: 'Vec2' | CPtr) -> 'Vec2' | CPtr: + return Vec2(self.x - b.x, self.y - b.y) + + def __mul__(self, s: CFloat64T) -> 'Vec2' | CPtr: + return Vec2(self.x * s, self.y * s) + + def __neg__(self) -> 'Vec2' | CPtr: + return Vec2(-self.x, -self.y) + + def dot(self, b: 'Vec2' | CPtr) -> CFloat64T: + return self.x * b.x + self.y * b.y + + def len_sq(self) -> CFloat64T: + return self.x * self.x + self.y * self.y + + +class Vec3: + x: CFloat64T + y: CFloat64T + z: CFloat64T + + def __new__() -> 'Vec3' | CPtr: + return t.CVoid(t.CUInt64T(stdlib.malloc(24)), CPtr) + + def __init__(self, x: CFloat64T, y: CFloat64T, z: CFloat64T): + self.x = x + self.y = y + self.z = z + + def __add__(self, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: + return Vec3(self.x + b.x, self.y + b.y, self.z + b.z) + + def __sub__(self, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: + return Vec3(self.x - b.x, self.y - b.y, self.z - b.z) + + def __mul__(self, s: CFloat64T) -> 'Vec3' | CPtr: + return Vec3(self.x * s, self.y * s, self.z * s) + + def __neg__(self) -> 'Vec3' | CPtr: + return Vec3(-self.x, -self.y, -self.z) + + def dot(self, b: 'Vec3' | CPtr) -> CFloat64T: + return self.x * b.x + self.y * b.y + self.z * b.z + + def cross(self, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: + return Vec3(self.y * b.z - self.z * b.y, + self.z * b.x - self.x * b.z, + self.x * b.y - self.y * b.x) + + def len_sq(self) -> CFloat64T: + return self.dot(self) + + +# === 独立类(非继承,避免链接问题) === + +@t.CVTable +class Dog: + def __init__(self, name_val: CInt, bark_power: CInt32T): + self.name_val = name_val + self.health = CInt32T(100) + self.bark_power = bark_power + def speak(self) -> CInt: + return 1 + def bite(self) -> CInt32T: + return self.bark_power + def take_damage(self, dmg: CInt32T) -> 'Dog' | CPtr: + self.health = self.health - dmg + return t.CVoid(c.Addr(self), CPtr) + def is_alive(self) -> CInt: + if self.health > 0: + return 1 + return 0 + +@t.CVTable +class Cat: + def __init__(self, name_val: CInt, lives: CInt32T): + self.name_val = name_val + self.health = CInt32T(80) + self.lives = lives + def speak(self) -> CInt: + return 2 + def scratch(self) -> CInt32T: + return CInt32T(15) + def take_damage(self, dmg: CInt32T) -> 'Cat' | CPtr: + self.health = self.health - dmg + return t.CVoid(c.Addr(self), CPtr) + def is_alive(self) -> CInt: + if self.health > 0: + return 1 + return 0 + + +# === 嵌套对象组合(堆分配) === + +class Transform: + px: CFloat64T + py: CFloat64T + pz: CFloat64T + scale_x: CFloat64T + scale_y: CFloat64T + scale_z: CFloat64T + + def __new__() -> 'Transform' | CPtr: + return t.CVoid(t.CUInt64T(stdlib.malloc(48)), CPtr) + + def __init__(self, px: CFloat64T, py: CFloat64T, pz: CFloat64T): + self.px = px + self.py = py + self.pz = pz + self.scale_x = 1.0 + self.scale_y = 1.0 + self.scale_z = 1.0 + + def apply_scale(self, sx: CFloat64T, sy: CFloat64T, sz: CFloat64T) -> 'Transform' | CPtr: + self.scale_x = self.scale_x * sx + self.scale_y = self.scale_y * sy + self.scale_z = self.scale_z * sz + return t.CVoid(c.Addr(self), CPtr) + + def world_position(self) -> 'Vec3' | CPtr: + return Vec3(self.px * self.scale_x, self.py * self.scale_y, self.pz * self.scale_z) + + +# === 多层继承(子类只重写需要的方法) === + +@t.CVTable +class Vehicle: + def __init__(self, speed: CInt32T): + self.speed = speed + self.fuel = CInt32T(100) + def move(self) -> CInt: + self.fuel = self.fuel - CInt32T(10) + return self.speed + def is_running(self) -> CInt: + if self.fuel > 0: + return 1 + return 0 + +@t.CVTable +class Car(Vehicle): + def __init__(self, speed: CInt32T, doors: CInt32T): + self.speed = speed + self.fuel = CInt32T(100) + self.doors = doors + def honk(self) -> CInt: + return 1 + +@t.CVTable +class ElectricCar(Car): + def __init__(self, speed: CInt32T, doors: CInt32T, battery: CInt32T): + self.speed = speed + self.fuel = CInt32T(100) + self.doors = doors + self.battery = battery + def charge(self): + self.battery = self.battery + CInt32T(20) + def move(self) -> CInt: + self.battery = self.battery - CInt32T(5) + return self.speed + + +def main() -> CInt | CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + buf: CChar | CPtr = CPtr(stdlib.malloc(256)) + + # === 基础函数泛型 === + print(add(3, 5)) + print(add(1.5, 2.5)) + print(add_u64(1, 2, CUInt64T(3000000000000000))) + print(fxi(0.2, 6)) + print(wrap_add(10, 20)) + print(double_add(5, 7)) + + # === 基础结构体泛型 === + a = A(100) + print(a.get_a()) + p1 = Pair(10, 20) + print(p1.get_first()) + print(p1.get_second()) + + # === OOP 继承测试 === + c1 = Circle(0.0, 0.0, 5.0) + viperlib.snprintf(buf, 256, "Circle area=%.2f perim=%.2f", c1.area(), c1.perimeter()) + print(buf) + + r1 = Rect(0.0, 0.0, 4.0, 3.0) + viperlib.snprintf(buf, 256, "Rect area=%.2f perim=%.2f", r1.area(), r1.perimeter()) + print(buf) + + # 链式调用: scale -> move + c2 = Circle(1.0, 2.0, 3.0) + c2.scale(2.0).move(10.0, 20.0) + viperlib.snprintf(buf, 256, "Circle after scale+move: x=%.1f y=%.1f r=%.1f area=%.2f", + c2.x, c2.y, c2.r, c2.area()) + print(buf) + + r2 = Rect(0.0, 0.0, 10.0, 5.0) + r2.scale(2.0).scale(0.5) + viperlib.snprintf(buf, 256, "Rect after double scale: w=%.1f h=%.1f area=%.2f", + r2.w, r2.h, r2.area()) + print(buf) + + # === Vec2 运算符重载 + 链式调用(堆分配) === + v1 = Vec2(3.0, 4.0) + v2 = Vec2(1.0, 2.0) + v3 = v1 + v2 + viperlib.snprintf(buf, 256, "Vec2 add: (%.1f, %.1f)", v3.x, v3.y) + print(buf) + + v4 = v1 - v2 + viperlib.snprintf(buf, 256, "Vec2 sub: (%.1f, %.1f)", v4.x, v4.y) + print(buf) + + v5 = v1 * 2.0 + viperlib.snprintf(buf, 256, "Vec2 mul: (%.1f, %.1f)", v5.x, v5.y) + print(buf) + + v6 = -v1 + viperlib.snprintf(buf, 256, "Vec2 neg: (%.1f, %.1f)", v6.x, v6.y) + print(buf) + + d = v1.dot(v2) + viperlib.snprintf(buf, 256, "Vec2 dot: %.1f", d) + print(buf) + + # 链式运算: (v1 + v2) * 3.0 + v_chain = (v1 + v2) * 3.0 + viperlib.snprintf(buf, 256, "Vec2 chain (v1+v2)*3: (%.1f, %.1f)", v_chain.x, v_chain.y) + print(buf) + + # === Vec3 运算符重载 + 链式调用(堆分配) === + a1 = Vec3(1.0, 0.0, 0.0) + a2 = Vec3(0.0, 1.0, 0.0) + cross_v = a1.cross(a2) + viperlib.snprintf(buf, 256, "Vec3 cross: (%.1f, %.1f, %.1f)", cross_v.x, cross_v.y, cross_v.z) + print(buf) + + dot_v = a1.dot(a2) + viperlib.snprintf(buf, 256, "Vec3 dot: %.1f", dot_v) + print(buf) + + # 链式: (a + b).dot(c) + a3 = Vec3(1.0, 2.0, 3.0) + a4 = Vec3(4.0, 5.0, 6.0) + a5 = Vec3(7.0, 8.0, 9.0) + chain_dot = (a3 + a4).dot(a5) + viperlib.snprintf(buf, 256, "Vec3 chain dot: %.1f", chain_dot) + print(buf) + + # 链式: (a * 2.0 - b).cross(c) + chain_cross = (a3 * 2.0 - a4).cross(a5) + viperlib.snprintf(buf, 256, "Vec3 chain cross: (%.1f, %.1f, %.1f)", chain_cross.x, chain_cross.y, chain_cross.z) + print(buf) + + # len_sq 链式 + lsq = a3.len_sq() + viperlib.snprintf(buf, 256, "Vec3 len_sq: %.1f", lsq) + print(buf) + + # === Dog/Cat 虚方法 === + dog = Dog(1, CInt32T(30)) + cat = Cat(2, CInt32T(9)) + + viperlib.snprintf(buf, 256, "Dog speak=%d bite=%d alive=%d", dog.speak(), dog.bite(), dog.is_alive()) + print(buf) + viperlib.snprintf(buf, 256, "Cat speak=%d scratch=%d alive=%d", cat.speak(), cat.scratch(), cat.is_alive()) + print(buf) + + dog.take_damage(CInt32T(40)).take_damage(CInt32T(30)) + viperlib.snprintf(buf, 256, "Dog after 70dmg: health=%d alive=%d", dog.health, dog.is_alive()) + print(buf) + + cat.take_damage(CInt32T(50)) + viperlib.snprintf(buf, 256, "Cat after 50dmg: health=%d alive=%d", cat.health, cat.is_alive()) + print(buf) + + # === Transform 嵌套组合(堆分配,链式调用) === + tr = Transform(10.0, 20.0, 30.0) + tr.apply_scale(2.0, 3.0, 4.0) + pos = tr.world_position() + viperlib.snprintf(buf, 256, "Transform pos: (%.1f, %.1f, %.1f)", pos.x, pos.y, pos.z) + print(buf) + + tr2 = Transform(5.0, 10.0, 15.0) + tr2.apply_scale(2.0, 2.0, 2.0) + pos2 = tr2.world_position() + viperlib.snprintf(buf, 256, "Transform2 pos: (%.1f, %.1f, %.1f)", pos2.x, pos2.y, pos2.z) + print(buf) + + # === 多层继承 === + ec = ElectricCar(CInt32T(120), CInt32T(4), CInt32T(80)) + viperlib.snprintf(buf, 256, "ECar speed=%d doors=%d battery=%d", ec.speed, ec.doors, ec.battery) + print(buf) + ec.charge() + viperlib.snprintf(buf, 256, "ECar after charge: battery=%d", ec.battery) + print(buf) + spd = ec.move() + viperlib.snprintf(buf, 256, "ECar move: speed=%d battery=%d", spd, ec.battery) + print(buf) + viperlib.snprintf(buf, 256, "ECar honk=%d running=%d", ec.honk(), ec.is_running()) + print(buf) + + # === 泛型 + OOP 组合 === + calc1 = Calculator(10) + print(calc1.compute(5)) + calc2 = Calculator(1.5) + print(calc2.compute(2.5)) + + c1_gen = Container(42) + print(c1_gen.get_value()) + print(c1_gen.get_flag()) + + # === snprintf 格式化 === + viperlib.snprintf(buf, 256, "int=%d, float=%.2f", 42, 3.14) + print(buf) + viperlib.snprintf(buf, 256, "result=%d", add(100, 200)) + print(buf) + + # === 新语法类型强转 (t1|t2)(x) === + val_i64: CUInt64T = CUInt64T(42) + val_i32 = (t.CInt)(val_i64) + print(val_i32) + + ptr_raw = stdlib.malloc(8) + ptr_typed = (t.CInt | t.CPtr)(ptr_raw) + viperlib.snprintf(buf, 256, "cast ptr=%p", ptr_typed) + print(buf) + + val_f = (t.CDouble)(42) + viperlib.snprintf(buf, 256, "cast float=%.1f", val_f) + print(buf) + + # === CDefine 宏测试 === + definetest.define_main() + + # === Enum 测试 === + enumtest.enum_main() + + # === MPool OOP 测试 === + mpooltest.mpool_main() + + # === Vector 泛型测试 === + vectortest.vector_main() + + # === Win32 FileIO 测试 === + fileiotest.fileio_main() + + return 0 diff --git a/Test/TestProject3/App/mpooltest.py b/Test/TestProject3/App/mpooltest.py new file mode 100644 index 0000000..3379069 --- /dev/null +++ b/Test/TestProject3/App/mpooltest.py @@ -0,0 +1,91 @@ +import t, c +from t import CInt, CPtr, CChar +import viperlib +import viperio +import stdlib +import mpool + + +def mpool_main() -> CInt: + buf: CChar | CPtr = CPtr(stdlib.malloc(256)) + + arena: bytes = stdlib.malloc(4096) + with mpool.MPool(arena, 4096, 0) as pool: + p1: bytes = pool.alloc(32) + p2: bytes = pool.alloc(64) + p3: bytes = pool.alloc(128) + if p1 != None and p2 != None and p3 != None: + viperlib.snprintf(buf, 256, "MPool bump: 3 allocs OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool bump: alloc FAILED") + print(buf) + + pool.reset() + p4: bytes = pool.alloc(256) + if p4 != None: + viperlib.snprintf(buf, 256, "MPool bump: reset+alloc OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool bump: reset+alloc FAILED") + print(buf) + + stdlib.free(arena) + + arena2: bytes = stdlib.malloc(4096) + with mpool.MPool(arena2, 4096, 64) as spool: + b1: bytes = spool.alloc(64) + b2: bytes = spool.alloc(64) + b3: bytes = spool.alloc(64) + if b1 != None and b2 != None and b3 != None: + viperlib.snprintf(buf, 256, "MPool slab: 3 allocs OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool slab: alloc FAILED") + print(buf) + + spool.free(b2) + b4: bytes = spool.alloc(64) + if b4 != None: + viperlib.snprintf(buf, 256, "MPool slab: free+realloc OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool slab: free+realloc FAILED") + print(buf) + + stdlib.free(arena2) + + arena3: bytes = stdlib.malloc(4096) + hpool: mpool.MPool | CPtr = mpool.MPool(arena3, 4096, 0) + h1: bytes = hpool.alloc(32) + h2: bytes = hpool.alloc(64) + if h1 != None and h2 != None: + viperlib.snprintf(buf, 256, "MPool manual: 2 allocs OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool manual: alloc FAILED") + print(buf) + hpool.reset() + h3: bytes = hpool.alloc(128) + if h3 != None: + viperlib.snprintf(buf, 256, "MPool manual: reset+alloc OK") + print(buf) + else: + viperlib.snprintf(buf, 256, "MPool manual: reset+alloc FAILED") + print(buf) + + stdlib.free(arena3) + + arena4: bytes = stdlib.malloc(4096) + with mpool.MPool(arena4, 4096, 0) as bpool: + wb: viperio.Buf | CPtr = bpool.alloc_buf(128) + if wb.data != None: + viperlib.snprintf(wb.cstr(), 128, "MPool alloc_buf: hello from Buf!") + print(wb.cstr()) + else: + viperlib.snprintf(buf, 256, "MPool alloc_buf: FAILED") + print(buf) + + stdlib.free(arena4) + stdlib.free(buf) + return 0 diff --git a/Test/TestProject3/App/vectortest.py b/Test/TestProject3/App/vectortest.py new file mode 100644 index 0000000..8fc3128 --- /dev/null +++ b/Test/TestProject3/App/vectortest.py @@ -0,0 +1,43 @@ +import t, c +from t import CInt, CPtr, CChar, CFloat64T +import viperlib +import stdlib +import vector +import mpool + +POOL_SIZE: t.CDefine = 4096 + +def vector_main() -> CInt: + buf: str = stdlib.malloc(256) + pool_mem: t.CVoid | t.CPtr = stdlib.malloc(POOL_SIZE) + pool: mpool.MPool | CPtr = mpool.MPool(pool_mem, POOL_SIZE, 0) + + vi: vector.Vector | CPtr = vector.Vector(pool, 10, CInt(0)) + vi.push(CInt(10)) + vi.push(CInt(20)) + vi.push(CInt(30)) + viperlib.snprintf(buf, 256, "Vector[int]: len=%d, [0]=%d, [1]=%d, [2]=%d", vi.len(), vi.get(0), vi.get(1), vi.get(2)) + print(buf) + + vi.set(1, CInt(99)) + viperlib.snprintf(buf, 256, "Vector[int]: set[1]=99, [1]=%d", vi.get(1)) + print(buf) + + vi.clear() + viperlib.snprintf(buf, 256, "Vector[int]: cleared, len=%d", vi.len()) + print(buf) + + vi.free() + + vd: vector.Vector | CPtr = vector.Vector(pool, 8, CFloat64T(0.0)) + vd.push(CFloat64T(1.5)) + vd.push(CFloat64T(2.7)) + vd.push(CFloat64T(3.14)) + viperlib.snprintf(buf, 256, "Vector[double]: len=%d, [0]=%.1f, [1]=%.1f, [2]=%.2f", vd.len(), vd.get(0), vd.get(1), vd.get(2)) + print(buf) + + vd.free() + + stdlib.free(pool_mem) + stdlib.free(buf) + return 0 diff --git a/Test/TestProject3/output/067c78e9f121dce3.deps.json b/Test/TestProject3/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..9ea60d1 --- /dev/null +++ b/Test/TestProject3/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/087c910044fab2d2.deps.json b/Test/TestProject3/output/087c910044fab2d2.deps.json new file mode 100644 index 0000000..52493aa --- /dev/null +++ b/Test/TestProject3/output/087c910044fab2d2.deps.json @@ -0,0 +1 @@ +{"main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/0f4d14c17bf75b10.deps.json b/Test/TestProject3/output/0f4d14c17bf75b10.deps.json new file mode 100644 index 0000000..92bc69f --- /dev/null +++ b/Test/TestProject3/output/0f4d14c17bf75b10.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/1b58766d38d05de3.deps.json b/Test/TestProject3/output/1b58766d38d05de3.deps.json new file mode 100644 index 0000000..575d1e0 --- /dev/null +++ b/Test/TestProject3/output/1b58766d38d05de3.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/21ffad37f6fc3fcf.deps.json b/Test/TestProject3/output/21ffad37f6fc3fcf.deps.json new file mode 100644 index 0000000..16e2398 --- /dev/null +++ b/Test/TestProject3/output/21ffad37f6fc3fcf.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/29813d57621099a9.deps.json b/Test/TestProject3/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..9ea60d1 --- /dev/null +++ b/Test/TestProject3/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/3fdd11bdd589aa8c.deps.json b/Test/TestProject3/output/3fdd11bdd589aa8c.deps.json new file mode 100644 index 0000000..5b6a8ca --- /dev/null +++ b/Test/TestProject3/output/3fdd11bdd589aa8c.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/4d342c40331fc964.deps.json b/Test/TestProject3/output/4d342c40331fc964.deps.json new file mode 100644 index 0000000..20b6925 --- /dev/null +++ b/Test/TestProject3/output/4d342c40331fc964.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/5325ec533a59d71b.deps.json b/Test/TestProject3/output/5325ec533a59d71b.deps.json new file mode 100644 index 0000000..b780a03 --- /dev/null +++ b/Test/TestProject3/output/5325ec533a59d71b.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/5a6a2137958c28c5.deps.json b/Test/TestProject3/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..79af064 --- /dev/null +++ b/Test/TestProject3/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/64ac83614c9bdbc6.deps.json b/Test/TestProject3/output/64ac83614c9bdbc6.deps.json new file mode 100644 index 0000000..7784b27 --- /dev/null +++ b/Test/TestProject3/output/64ac83614c9bdbc6.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/72e2d5ccb7cedcf1.deps.json b/Test/TestProject3/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..9ea60d1 --- /dev/null +++ b/Test/TestProject3/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/a326a52b7c4bd6f0.deps.json b/Test/TestProject3/output/a326a52b7c4bd6f0.deps.json new file mode 100644 index 0000000..ab3e82e --- /dev/null +++ b/Test/TestProject3/output/a326a52b7c4bd6f0.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/abf9ce3160c9279e.deps.json b/Test/TestProject3/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..7908c78 --- /dev/null +++ b/Test/TestProject3/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/bbdf3bbd4c3bc28c.deps.json b/Test/TestProject3/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..ed5f7b3 --- /dev/null +++ b/Test/TestProject3/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/c9f4be41ca1cc2b4.deps.json b/Test/TestProject3/output/c9f4be41ca1cc2b4.deps.json new file mode 100644 index 0000000..f4b825d --- /dev/null +++ b/Test/TestProject3/output/c9f4be41ca1cc2b4.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/fa3691e66b426950.deps.json b/Test/TestProject3/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..def18b9 --- /dev/null +++ b/Test/TestProject3/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "vectortest": "fc49f6314bad25e9"} \ No newline at end of file diff --git a/Test/TestProject3/output/fc49f6314bad25e9.deps.json b/Test/TestProject3/output/fc49f6314bad25e9.deps.json new file mode 100644 index 0000000..250a982 --- /dev/null +++ b/Test/TestProject3/output/fc49f6314bad25e9.deps.json @@ -0,0 +1 @@ +{"fileiotest": "087c910044fab2d2", "main": "0f4d14c17bf75b10", "enumtest": "1b58766d38d05de3", "mpool": "21ffad37f6fc3fcf", "vector": "3fdd11bdd589aa8c", "viperlib": "4d342c40331fc964", "mpooltest": "5325ec533a59d71b", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "definetest": "64ac83614c9bdbc6", "stdarg": "71e0a3ffcb3ebfad", "platmacro": "93c1d18e35d188d6", "string": "a326a52b7c4bd6f0", "stdlib": "a96738831f025829", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TestProject3/project.json b/Test/TestProject3/project.json new file mode 100644 index 0000000..00e51cb --- /dev/null +++ b/Test/TestProject3/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "TestProject", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-Wl,--allow-multiple-definition"], + "output": "TestProject.exe" + }, + "includes": [ + "./includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/TestProject3/temp/087c910044fab2d2.pyi b/Test/TestProject3/temp/087c910044fab2d2.pyi new file mode 100644 index 0000000..b7d60d2 --- /dev/null +++ b/Test/TestProject3/temp/087c910044fab2d2.pyi @@ -0,0 +1,30 @@ +""" +Auto-generated Python stub file from fileiotest.py +Module: fileiotest +""" + + +import t, c +from t import CInt, CInt32T, CUInt32T, CPtr, CChar, CExport +from stdint import * +import stdlib +import viperlib +import w32.win32base +import w32.win32file +import w32.win32console +import w32.fileio +from w32.fileio import File, FileW, MODE, FRESULT, SEEK_SET, SEEK_CUR, SEEK_END + +BUF_SIZE: t.CDefine = 4096 + +def fileio_main() -> t.CVoid: pass + +def fileio_with_test() -> t.CVoid: pass + +def fileio_handle_test() -> t.CVoid: pass + +def fileio_rw_test() -> t.CVoid: pass + +def fileio_wide_test() -> t.CVoid: pass + +def fileio_chinese_test() -> t.CVoid: pass diff --git a/Test/TestProject3/temp/0f4d14c17bf75b10.pyi b/Test/TestProject3/temp/0f4d14c17bf75b10.pyi new file mode 100644 index 0000000..46261cb --- /dev/null +++ b/Test/TestProject3/temp/0f4d14c17bf75b10.pyi @@ -0,0 +1,130 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +from stdint import * +import w32.win32console +import t, c +from t import CInt, CPtr, CChar, CInt32T, CUInt64T, CFloat64T, CExport, State +import viperlib +import stdlib +import definetest +import enumtest +import mpooltest +import vectortest +import fileiotest + +def add[T](a: T, b: T) -> T: pass + +def add_u64[T](a: T, b: T, c: CUInt64T) -> T: pass + +def fxi[T1, T2](a: T1, b: T2) -> T1: pass + +def fxi2[T1, T2, T3](a: T1, b: T2, c: T3) -> T1: pass + +def wrap_add[T](a: T, b: T) -> T: pass + +def double_add[T](a: T, b: T) -> T: pass + + +class A[T]: + def __init__(self: A, a: T) -> t.CVoid: pass + def get_a(self: A) -> T: pass +class Pair[T1, T2]: + def __init__(self: Pair, first: T1, second: T2) -> t.CVoid: pass + def get_first(self: Pair) -> T1: pass + def get_second(self: Pair) -> T2: pass +class Calculator[T]: + def __init__(self: Calculator, init_val: T) -> t.CVoid: pass + def compute(self: Calculator, other: T) -> T: pass + def double_compute(self: Calculator, other: T) -> T: pass +class Container[T]: + def __init__(self: Container, v: T) -> t.CVoid: pass + def get_value(self: Container) -> T: pass + def get_flag(self: Container) -> CInt32T: pass +@t.CVTable +class Shape: + def __init__(self: Shape, x: CFloat64T, y: CFloat64T) -> t.CVoid: pass + def area(self: Shape) -> CFloat64T: pass + def perimeter(self: Shape) -> CFloat64T: pass + def describe(self: Shape) -> CFloat64T: pass +@t.CVTable +class Circle(Shape): + def __init__(self: Circle, x: CFloat64T, y: CFloat64T, r: CFloat64T) -> t.CVoid: pass + def area(self: Circle) -> CFloat64T: pass + def perimeter(self: Circle) -> CFloat64T: pass + def scale(self: Circle, factor: CFloat64T) -> 'Circle' | CPtr: pass + def move(self: Circle, dx: CFloat64T, dy: CFloat64T) -> 'Circle' | CPtr: pass +@t.CVTable +class Rect(Shape): + def __init__(self: Rect, x: CFloat64T, y: CFloat64T, w: CFloat64T, h: CFloat64T) -> t.CVoid: pass + def area(self: Rect) -> CFloat64T: pass + def perimeter(self: Rect) -> CFloat64T: pass + def scale(self: Rect, factor: CFloat64T) -> 'Rect' | CPtr: pass +class Vec2: + x: CFloat64T + y: CFloat64T + def __new__() -> 'Vec2' | CPtr: pass + def __init__(self: Vec2, x: CFloat64T, y: CFloat64T) -> t.CVoid: pass + def __add__(self: Vec2, b: 'Vec2' | CPtr) -> 'Vec2' | CPtr: pass + def __sub__(self: Vec2, b: 'Vec2' | CPtr) -> 'Vec2' | CPtr: pass + def __mul__(self: Vec2, s: CFloat64T) -> 'Vec2' | CPtr: pass + def __neg__(self: Vec2) -> 'Vec2' | CPtr: pass + def dot(self: Vec2, b: 'Vec2' | CPtr) -> CFloat64T: pass + def len_sq(self: Vec2) -> CFloat64T: pass +class Vec3: + x: CFloat64T + y: CFloat64T + z: CFloat64T + def __new__() -> 'Vec3' | CPtr: pass + def __init__(self: Vec3, x: CFloat64T, y: CFloat64T, z: CFloat64T) -> t.CVoid: pass + def __add__(self: Vec3, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: pass + def __sub__(self: Vec3, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: pass + def __mul__(self: Vec3, s: CFloat64T) -> 'Vec3' | CPtr: pass + def __neg__(self: Vec3) -> 'Vec3' | CPtr: pass + def dot(self: Vec3, b: 'Vec3' | CPtr) -> CFloat64T: pass + def cross(self: Vec3, b: 'Vec3' | CPtr) -> 'Vec3' | CPtr: pass + def len_sq(self: Vec3) -> CFloat64T: pass +@t.CVTable +class Dog: + def __init__(self: Dog, name_val: CInt, bark_power: CInt32T) -> t.CVoid: pass + def speak(self: Dog) -> CInt: pass + def bite(self: Dog) -> CInt32T: pass + def take_damage(self: Dog, dmg: CInt32T) -> 'Dog' | CPtr: pass + def is_alive(self: Dog) -> CInt: pass +@t.CVTable +class Cat: + def __init__(self: Cat, name_val: CInt, lives: CInt32T) -> t.CVoid: pass + def speak(self: Cat) -> CInt: pass + def scratch(self: Cat) -> CInt32T: pass + def take_damage(self: Cat, dmg: CInt32T) -> 'Cat' | CPtr: pass + def is_alive(self: Cat) -> CInt: pass +class Transform: + px: CFloat64T + py: CFloat64T + pz: CFloat64T + scale_x: CFloat64T + scale_y: CFloat64T + scale_z: CFloat64T + def __new__() -> 'Transform' | CPtr: pass + def __init__(self: Transform, px: CFloat64T, py: CFloat64T, pz: CFloat64T) -> t.CVoid: pass + def apply_scale(self: Transform, sx: CFloat64T, sy: CFloat64T, sz: CFloat64T) -> 'Transform' | CPtr: pass + def world_position(self: Transform) -> 'Vec3' | CPtr: pass +@t.CVTable +class Vehicle: + def __init__(self: Vehicle, speed: CInt32T) -> t.CVoid: pass + def move(self: Vehicle) -> CInt: pass + def is_running(self: Vehicle) -> CInt: pass +@t.CVTable +class Car(Vehicle): + def __init__(self: Car, speed: CInt32T, doors: CInt32T) -> t.CVoid: pass + def honk(self: Car) -> CInt: pass +@t.CVTable +class ElectricCar(Car): + def __init__(self: ElectricCar, speed: CInt32T, doors: CInt32T, battery: CInt32T) -> t.CVoid: pass + def charge(self: ElectricCar) -> t.CVoid: pass + def move(self: ElectricCar) -> CInt: pass + +def main() -> CInt | CExport: pass diff --git a/Test/TestProject3/temp/1b58766d38d05de3.pyi b/Test/TestProject3/temp/1b58766d38d05de3.pyi new file mode 100644 index 0000000..11fb572 --- /dev/null +++ b/Test/TestProject3/temp/1b58766d38d05de3.pyi @@ -0,0 +1,35 @@ +""" +Auto-generated Python stub file from enumtest.py +Module: enumtest +""" + + +import t, c +from t import CInt, CPtr, CChar, CInt32T, CExport +import viperlib +import stdlib + +class Color(t.CEnum): + Red = 0 + Green = 1 + Blue = 2 +class Option(t.REnum): + class Some: + value: CInt + Empty = 1 +class Result(t.REnum): + class Ok: + value: CInt + class Err: + msg: t.CChar | CPtr +class GeoShape(t.REnum): + class GCircle: + radius: CInt + class GRect: + w: CInt + h: CInt + class GPoint: + x: CInt + y: CInt + +def enum_main() -> CInt: pass diff --git a/Test/TestProject3/temp/21ffad37f6fc3fcf.pyi b/Test/TestProject3/temp/21ffad37f6fc3fcf.pyi new file mode 100644 index 0000000..f237768 --- /dev/null +++ b/Test/TestProject3/temp/21ffad37f6fc3fcf.pyi @@ -0,0 +1,44 @@ +""" +Auto-generated Python stub file from mpool.py +Module: mpool +""" + + +import t, c +from stdint import * +import viperio +import string + +MPOOL_ALIGN: t.CDefine = 8 +MPOOL_TYPE_SLAB: t.CDefine = 0 +MPOOL_TYPE_BUMP: t.CDefine = 2 + +def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: pass + + +class MPool: + mtype: t.CInt + mem: t.CVoid | t.CPtr + mem_size: t.CSizeT + offset: t.CSizeT + high_water: t.CSizeT + block_size: t.CSizeT + block_count: t.CSizeT + used_count: t.CSizeT + free_list: t.CVoid | t.CPtr + alloc_map: t.CUInt8T | t.CPtr + alloc_map_size: t.CSizeT + def __init__(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CVoid: pass + def _init_bump(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> t.CVoid: pass + def _init_slab(self: MPool, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT) -> t.CVoid: pass + def __enter__(self: MPool) -> 'MPool' | t.CPtr: pass + def __exit__(self: MPool) -> t.CVoid: pass + def _slab_reset(self: MPool) -> t.CVoid: pass + def alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def alloc_buf(self: MPool, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: pass + def free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CVoid: pass + def realloc(self: MPool, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, new_size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def reset(self: MPool) -> t.CVoid: pass + def _bump_alloc(self: MPool, size: t.CSizeT) -> t.CVoid | t.CPtr: pass + def _slab_alloc(self: MPool) -> t.CVoid | t.CPtr: pass + def _slab_free(self: MPool, ptr: t.CVoid | t.CPtr) -> t.CVoid: pass \ No newline at end of file diff --git a/Test/TestProject3/temp/3fdd11bdd589aa8c.pyi b/Test/TestProject3/temp/3fdd11bdd589aa8c.pyi new file mode 100644 index 0000000..4062ae4 --- /dev/null +++ b/Test/TestProject3/temp/3fdd11bdd589aa8c.pyi @@ -0,0 +1,24 @@ +""" +Auto-generated Python stub file from vector.py +Module: vector +""" + + +import t, c +from stdint import * +import mpool + +class Vector[T]: + data: t.CVoid | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + elem_size: t.CSizeT + pool: mpool.MPool | t.CPtr + def __init__(self: Vector, pool: mpool.MPool | t.CPtr, capacity: t.CSizeT, _hint: T) -> t.CVoid: pass + def push(self: Vector, value: T) -> t.CVoid: pass + def _grow(self: Vector) -> t.CVoid: pass + def get(self: Vector, index: t.CSizeT) -> T: pass + def set(self: Vector, index: t.CSizeT, value: T) -> t.CVoid: pass + def len(self: Vector) -> t.CSizeT: pass + def clear(self: Vector) -> t.CVoid: pass + def free(self: Vector) -> t.CVoid: pass \ No newline at end of file diff --git a/Test/TestProject3/temp/4d342c40331fc964.pyi b/Test/TestProject3/temp/4d342c40331fc964.pyi new file mode 100644 index 0000000..aa40bc7 --- /dev/null +++ b/Test/TestProject3/temp/4d342c40331fc964.pyi @@ -0,0 +1,19 @@ +""" +Auto-generated Python stub file from viperlib.py +Module: viperlib +""" + + +import t, c +import viperio +from stdarg import arg + +TEMP_BUF_SIZE: t.CDefine = 24 + +def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt | t.State: pass + +def sprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CVoid | t.State: pass + +def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt | t.State: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt | t.State: pass diff --git a/Test/TestProject3/temp/5325ec533a59d71b.pyi b/Test/TestProject3/temp/5325ec533a59d71b.pyi new file mode 100644 index 0000000..c37bf67 --- /dev/null +++ b/Test/TestProject3/temp/5325ec533a59d71b.pyi @@ -0,0 +1,14 @@ +""" +Auto-generated Python stub file from mpooltest.py +Module: mpooltest +""" + + +import t, c +from t import CInt, CPtr, CChar +import viperlib +import viperio +import stdlib +import mpool + +def mpool_main() -> CInt: pass diff --git a/Test/TestProject3/temp/56cdd754a8a09347.pyi b/Test/TestProject3/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/TestProject3/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/TestProject3/temp/5a6a2137958c28c5.pyi b/Test/TestProject3/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/TestProject3/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/TestProject3/temp/64ac83614c9bdbc6.pyi b/Test/TestProject3/temp/64ac83614c9bdbc6.pyi new file mode 100644 index 0000000..84edfcc --- /dev/null +++ b/Test/TestProject3/temp/64ac83614c9bdbc6.pyi @@ -0,0 +1,81 @@ +""" +Auto-generated Python stub file from definetest.py +Module: definetest +""" + + +import t, c +from t import CInt, CInt32T, CUInt32T, CUInt64T, CFloat64T, CPtr, CChar, CDefine, CUInt16T +import viperlib +import stdlib +import platmacro + +MAX_SIZE: t.CDefine = 1024 +MIN_VAL: t.CDefine = 0 +MAX_VAL: t.CDefine = 100 +MASK_BYTE: t.CDefine = 0xFF +SHIFT_BITS: t.CDefine = 8 +PI_INT: t.CDefine = 3 +ENABLED: t.CDefine = 1 +DISABLED: t.CDefine = 0 +PAGE_SIZE: t.CDefine = 4096 +BUFFER_LEN: t.CDefine = 256 +CODE_SEG: t.CDefine | t.CUInt16T = 0x08 +DATA_SEG: t.CDefine | t.CUInt16T = 0x10 +STACK_SEG: t.CDefine | t.CUInt16T = 0x20 + +def MAKE_FLAG(bit: CInt32T) -> t.CDefine: + pass + +def CLAMP(x: CInt32T, lo: CInt32T, hi: CInt32T) -> t.CDefine: + pass + +def test_basic_define() -> CInt: pass + +def test_define_arithmetic() -> CInt: pass + +def test_define_conditional() -> CInt: pass + +def test_define_loop() -> CInt: pass + +def test_typed_define() -> CInt: pass + +def test_define_function() -> CInt: pass + +def test_define_clamp() -> CInt: pass + +def test_define_string() -> CInt: pass + +def test_define_combined() -> CInt: pass + +def test_cif_basic() -> CInt: pass + +def test_cif_elif_else() -> CInt: pass + +def test_cifdef_cifndef() -> CInt: pass + +def test_cif_platform() -> CInt: pass + +def test_cif_nested() -> CInt: pass + +def test_cif_expr() -> CInt: pass + +def test_platmacro_platform() -> CInt: pass + +def test_platmacro_sizes() -> CInt: pass + +def test_platmacro_endian() -> CInt: pass + +def test_platmacro_features() -> CInt: pass + +def test_platmacro_align() -> CInt: pass + +def test_cifdef_cross_module() -> CInt: pass + +def test_cifdef_guard() -> CInt: pass + +def test_cifdef_undefined() -> CInt: pass + +def test_cifdef_complex() -> CInt: pass + +def define_main() -> CInt: pass diff --git a/Test/TestProject3/temp/71e0a3ffcb3ebfad.pyi b/Test/TestProject3/temp/71e0a3ffcb3ebfad.pyi new file mode 100644 index 0000000..574b20e --- /dev/null +++ b/Test/TestProject3/temp/71e0a3ffcb3ebfad.pyi @@ -0,0 +1,20 @@ +""" +Auto-generated Python stub file from stdarg.py +Module: stdarg +""" + +import c + + +import t + +def va_start(args: t.CPtr, last_arg: t.CPtr) -> t.State: pass + +def va_arg(args: t.CPtr, type: t.CPtr) -> t.CPtr | t.State: pass + +def va_end(args: t.CPtr) -> t.State | t.State: pass + + +va_list: t.CTypedef = t.CUnsignedChar | t.CPtr + +def arg(type: t.CType) -> t.State: pass diff --git a/Test/TestProject3/temp/93c1d18e35d188d6.pyi b/Test/TestProject3/temp/93c1d18e35d188d6.pyi new file mode 100644 index 0000000..a8cd09e --- /dev/null +++ b/Test/TestProject3/temp/93c1d18e35d188d6.pyi @@ -0,0 +1,53 @@ +""" +Auto-generated Python stub file from platmacro.py +Module: platmacro +""" + + +import t, c + +IS_WINDOWS: t.CDefine = 1 +IS_WIN64: t.CDefine = 1 +IS_X86_64: t.CDefine = 1 +IS_LP64: t.CDefine = 1 +IS_LITTLE_ENDIAN: t.CDefine = 1 +IS_LINUX: t.CDefine = 0 +IS_MACOS: t.CDefine = 0 +IS_ARM64: t.CDefine = 0 +IS_BIG_ENDIAN: t.CDefine = 0 +IS_ILP32: t.CDefine = 0 +PTR_SIZE: t.CDefine = t.CSizeT().Size +INT_SIZE: t.CDefine = 4 +LONG_SIZE: t.CDefine = t.CLong().Size +WORD_SIZE: t.CDefine = t.CSizeT().Size +CACHE_LINE_SIZE: t.CDefine = 64 +PAGE_SIZE: t.CDefine = 4096 +STACK_ALIGN: t.CDefine = 16 +MAX_PATH_LEN: t.CDefine = 260 +PLATFORM_NAME: t.CDefine = 1 +ARCH_NAME: t.CDefine = 1 +WINVER: t.CDefine = 0x0A00 +_WIN32_WINNT: t.CDefine = 0x0A00 +NTDDI_VERSION: t.CDefine = 0x0A000006 +HAS_SSE2: t.CDefine = 1 +HAS_AVX: t.CDefine = 1 +HAS_AVX2: t.CDefine = 1 +HAS_FMA: t.CDefine = 1 +HAS_NEON: t.CDefine = 0 +ALIGNOF_INT: t.CDefine = 4 +ALIGNOF_LONG: t.CDefine = t.CLong().Size // 8 +ALIGNOF_PTR: t.CDefine = t.CSizeT().Size // 8 +ALIGNOF_DOUBLE: t.CDefine = 8 +ALIGNOF_LONG_DOUBLE: t.CDefine = 16 +SIZEOF_SHORT: t.CDefine = 2 +SIZEOF_INT: t.CDefine = 4 +SIZEOF_LONG: t.CDefine = t.CLong().Size // 8 +SIZEOF_LONG_LONG: t.CDefine = 8 +SIZEOF_FLOAT: t.CDefine = 4 +SIZEOF_DOUBLE: t.CDefine = 8 +SIZEOF_LONG_DOUBLE: t.CDefine = 16 +SIZEOF_POINTER: t.CDefine = t.CSizeT().Size // 8 +SIZEOF_SIZE_T: t.CDefine = t.CSizeT().Size // 8 +SIZEOF_PTRDIFF_T: t.CDefine = t.CPtrDiffT().Size // 8 +BYTE_ORDER_LE: t.CDefine = 1 +BYTE_ORDER_BE: t.CDefine = 0 \ No newline at end of file diff --git a/Test/TestProject3/temp/_sha1_map.txt b/Test/TestProject3/temp/_sha1_map.txt new file mode 100644 index 0000000..f36c421 --- /dev/null +++ b/Test/TestProject3/temp/_sha1_map.txt @@ -0,0 +1,19 @@ +087c910044fab2d2:fileiotest.py +0f4d14c17bf75b10:main.py +1b58766d38d05de3:enumtest.py +21ffad37f6fc3fcf:includes/mpool.py +3fdd11bdd589aa8c:includes/vector.py +4d342c40331fc964:includes/viperlib.py +5325ec533a59d71b:mpooltest.py +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +64ac83614c9bdbc6:definetest.py +71e0a3ffcb3ebfad:includes/stdarg.py +93c1d18e35d188d6:includes/platmacro.py +a326a52b7c4bd6f0:includes/string.py +a96738831f025829:includes/stdlib.py +abf9ce3160c9279e:includes/w32\win32file.py +bbdf3bbd4c3bc28c:includes/w32\win32console.py +c9f4be41ca1cc2b4:includes/viperio.py +fa3691e66b426950:includes/w32\fileio.py +fc49f6314bad25e9:vectortest.py diff --git a/Test/TestProject3/temp/_shared_sym.pkl b/Test/TestProject3/temp/_shared_sym.pkl new file mode 100644 index 0000000..0a14880 Binary files /dev/null and b/Test/TestProject3/temp/_shared_sym.pkl differ diff --git a/Test/TestProject3/temp/a326a52b7c4bd6f0.pyi b/Test/TestProject3/temp/a326a52b7c4bd6f0.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/TestProject3/temp/a326a52b7c4bd6f0.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/TestProject3/temp/a96738831f025829.pyi b/Test/TestProject3/temp/a96738831f025829.pyi new file mode 100644 index 0000000..c499547 --- /dev/null +++ b/Test/TestProject3/temp/a96738831f025829.pyi @@ -0,0 +1,16 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/TestProject3/temp/abf9ce3160c9279e.pyi b/Test/TestProject3/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/TestProject3/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/TestProject3/temp/bbdf3bbd4c3bc28c.pyi b/Test/TestProject3/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/TestProject3/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/TestProject3/temp/c9f4be41ca1cc2b4.pyi b/Test/TestProject3/temp/c9f4be41ca1cc2b4.pyi new file mode 100644 index 0000000..2c2291b --- /dev/null +++ b/Test/TestProject3/temp/c9f4be41ca1cc2b4.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from viperio.py +Module: viperio +""" + + +import t, c +from stdint import * + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CVoid: pass + def clear(self: Buf) -> t.CVoid: pass + def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: pass + def cstr(self: Buf) -> t.CChar | t.CPtr: pass + def reset(self: Buf) -> t.CVoid: pass + def __enter__(self: Buf) -> 'Buf' | t.CPtr: pass + def __exit__(self: Buf) -> t.CVoid: pass + def free(self: Buf) -> t.CVoid: pass \ No newline at end of file diff --git a/Test/TestProject3/temp/fa3691e66b426950.pyi b/Test/TestProject3/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..109c920 --- /dev/null +++ b/Test/TestProject3/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CVoid: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CVoid: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CVoid: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CVoid: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/TestProject3/temp/fc49f6314bad25e9.pyi b/Test/TestProject3/temp/fc49f6314bad25e9.pyi new file mode 100644 index 0000000..572ee9f --- /dev/null +++ b/Test/TestProject3/temp/fc49f6314bad25e9.pyi @@ -0,0 +1,16 @@ +""" +Auto-generated Python stub file from vectortest.py +Module: vectortest +""" + + +import t, c +from t import CInt, CPtr, CChar, CFloat64T +import viperlib +import stdlib +import vector +import mpool + +POOL_SIZE: t.CDefine = 4096 + +def vector_main() -> CInt: pass diff --git a/Test/TypeCastTest/App/main.py b/Test/TypeCastTest/App/main.py new file mode 100644 index 0000000..35c6a9b --- /dev/null +++ b/Test/TypeCastTest/App/main.py @@ -0,0 +1,236 @@ +from stdint import * +import t, c +import stdio +import string +import w32.win32console +import w32.win32memory + +# ============================================================ +# TypeCastTest - 测试类型转换、zext/sext/trunc 行为、 +# 有符号/无符号混合运算、CDefine 常量 +# ============================================================ + +# --- Test 1: CUInt8T -> CUInt32T 零扩展 (zext) --- +def test_zext_u8_u32(): + v: t.CUInt8T = 200 # 0xC8, 如果 sign-extend 会变成 0xFFFFFFC8 + wide: t.CUInt32T = t.CUInt32T(v) + if wide == 200: + stdio.printf("PASS: zext u8->u32 (200 -> %u)\n", wide) + else: + stdio.printf("FAIL: zext u8->u32 (200 -> %u, expected 200)\n", wide) + + +# --- Test 2: CInt8T -> CInt32T 符号扩展 (sext) --- +def test_sext_i8_i32(): + v: t.CInt8T = -50 # 0xCE + wide: t.CInt32T = t.CInt32T(v) + if wide == -50: + stdio.printf("PASS: sext i8->i32 (-50 -> %d)\n", wide) + else: + stdio.printf("FAIL: sext i8->i32 (-50 -> %d, expected -50)\n", wide) + + +# --- Test 3: CUInt32T -> CUInt64T 零扩展 --- +def test_zext_u32_u64(): + v: t.CUInt32T = 0x80000000 # 最高位为1 + wide: t.CUInt64T = t.CUInt64T(v) + if wide == 0x80000000: + stdio.printf("PASS: zext u32->u64 (0x%lx)\n", wide) + else: + stdio.printf("FAIL: zext u32->u64 (0x%lx, expected 0x80000000)\n", wide) + + +# --- Test 4: CInt32T -> CInt64T 符号扩展 --- +def test_sext_i32_i64(): + v: t.CInt32T = -1 # 0xFFFFFFFF + wide: t.CInt64T = t.CInt64T(v) + if wide == -1: + stdio.printf("PASS: sext i32->i64 (-1 -> %ld)\n", wide) + else: + stdio.printf("FAIL: sext i32->i64 (-1 -> %ld, expected -1)\n", wide) + + +# --- Test 5: CUInt64T -> CUInt32T 截断 (trunc) --- +def test_trunc_u64_u32(): + v: t.CUInt64T = 0x123456789ABCDEF0 + narrow: t.CUInt32T = t.CUInt32T(v) + if narrow == 0x9ABCDEF0: + stdio.printf("PASS: trunc u64->u32 (0x%x)\n", narrow) + else: + stdio.printf("FAIL: trunc u64->u32 (0x%x, expected 0x9ABCDEF0)\n", narrow) + + +# --- Test 6: 有符号/无符号混合运算 --- +def test_mixed_signed_unsigned(): + a: t.CInt = -10 + b: t.CUInt32T = 20 + # C 中有符号/无符号混合运算,有符号会转为无符号 + # -10 作为 unsigned 是 0xFFFFFFF6 = 4294967286 + # 4294967286 + 20 = 4294967306 (overflow to 10 on u32) + result: t.CUInt32T = t.CUInt32T(a) + b + stdio.printf("Test6 (mixed signed+unsigned): %u (C behavior: %u)\n", result, t.CUInt32T(-10) + 20) + + +# --- Test 7: CDefine 常量在运算中的行为 --- +VAL_32BIT: t.CDefine = 0x80000000 +VAL_NEG: t.CDefine = -1 +VAL_BIG: t.CDefine = 0xFFFFFFFF + +def test_cdefine_values(): + """测试 CDefine 常量值是否正确""" + v1: t.CUInt32T = t.CUInt32T(VAL_32BIT) + v2: t.CInt = VAL_NEG + v3: t.CUInt32T = t.CUInt32T(VAL_BIG) + stdio.printf("Test7 CDefine: 0x80000000=%u, -1=%d, 0xFFFFFFFF=%u\n", v1, v2, v3) + + +# --- Test 8: 位运算与类型宽度 --- +def test_bitops_width(): + """测试位运算是否保持正确类型宽度""" + # 左移 + v: t.CUInt32T = 1 + shifted: t.CUInt32T = v << 31 # 应该是 0x80000000 + if shifted == 0x80000000: + stdio.printf("PASS: bit shift (1<<31 = 0x%x)\n", shifted) + else: + stdio.printf("FAIL: bit shift (1<<31 = 0x%x, expected 0x80000000)\n", shifted) + + # 右移 + back: t.CUInt32T = shifted >> 31 # 应该是 1 + if back == 1: + stdio.printf("PASS: bit shift (0x80000000>>31 = %u)\n", back) + else: + stdio.printf("FAIL: bit shift (0x80000000>>31 = %u, expected 1)\n", back) + + +# --- Test 9: 整数除法与取模 (无符号) --- +def test_unsigned_divmod(): + a: t.CUInt32T = 100 + b: t.CUInt32T = 7 + q: t.CUInt32T = a // b + r: t.CUInt32T = a % b + if q == 14 and r == 2: + stdio.printf("PASS: unsigned div/mod (100//7=%u, 100%%7=%u)\n", q, r) + else: + stdio.printf("FAIL: unsigned div/mod (100//7=%u, 100%%7=%u, expected 14,2)\n", q, r) + + +# --- Test 10: 整数除法与取模 (有符号负数) --- +def test_signed_divmod_neg(): + a: t.CInt = -100 + b: t.CInt = 7 + q: t.CInt = a // b + r: t.CInt = a % b + # C 语言: -100/7 = -14, -100%7 = -2 + # Python: -100//7 = -15, -100%7 = 5 + # TransPyC 应该遵循 C 语义 + stdio.printf("Test10 signed div/mod: -100//7=%d, -100%%7=%d (C: -14,-2)\n", q, r) + + +# --- Test 11: 比较运算返回值 --- +def test_comparison_types(): + a: t.CInt = 10 + b: t.CInt = 20 + c_val: t.CInt = 10 + lt: t.CInt = 1 if a < b else 0 + eq: t.CInt = 1 if a == c_val else 0 + gt: t.CInt = 1 if b > a else 0 + if lt == 1 and eq == 1 and gt == 1: + stdio.printf("PASS: comparison operations\n") + else: + stdio.printf("FAIL: comparison (lt=%d eq=%d gt=%d)\n", lt, eq, gt) + + +# --- Test 12: 指针与整数互转 --- +def test_ptr_int_cast(): + buf: t.CUInt32T | t.CPtr = w32.win32memory.VirtualAlloc(None, 64, 0x3000, 0x04) + if not buf: + stdio.printf("FAIL: VirtualAlloc returned NULL\n") + return + # 指针转整数 + addr: t.CUInt64T = t.CUInt64T(buf) + stdio.printf("Test12 ptr->int: addr=0x%lx\n", addr) + # 整数转指针 + p2: t.CUInt32T | t.CPtr = (t.CUInt32T | t.CPtr)(t.CVoid(addr, t.CPtr)) + p2[0] = 0x12345678 + if buf[0] == 0x12345678: + stdio.printf("PASS: ptr<->int roundtrip\n") + else: + stdio.printf("FAIL: ptr<->int roundtrip (0x%x)\n", buf[0]) + + +# --- Test 13: CUInt64T 乘法溢出行为 --- +def test_u64_mul(): + a: t.CUInt64T = 1000 + b: t.CUInt64T = 1000 + c_val: t.CUInt64T = a * b + if c_val == 1000000: + stdio.printf("PASS: u64 mul (1000*1000=%lu)\n", c_val) + else: + stdio.printf("FAIL: u64 mul (1000*1000=%lu, expected 1000000)\n", c_val) + + +# --- Test 14: bool 运算 (and/or) --- +def test_bool_ops(): + a: t.CInt = 5 + b: t.CInt = 0 + c_val: t.CInt = 3 + # Python `and`/`or` 是短路求值 + r1: t.CInt = a and c_val # 5 and 3 -> 在 C 中应该是 (5 && 3) = 1 + r2: t.CInt = b or c_val # 0 or 3 -> 在 C 中应该是 (0 || 3) = 1 + stdio.printf("Test14 bool: 5 and 3 = %d, 0 or 3 = %d (expect 1,1 in C)\n", r1, r2) + + +# --- Test 15: 条件表达式 (三元运算符) --- +def test_ternary(): + a: t.CInt = 10 + b: t.CInt = 20 + max_val: t.CInt = a if a > b else b + min_val: t.CInt = a if a < b else b + if max_val == 20 and min_val == 10: + stdio.printf("PASS: ternary (max=%d min=%d)\n", max_val, min_val) + else: + stdio.printf("FAIL: ternary (max=%d min=%d, expected 20,10)\n", max_val, min_val) + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + stdio.printf("=== TypeCastTest: 类型转换与运算基准测试 ===\n\n") + + stdio.printf("--- zext/sext/trunc ---\n") + test_zext_u8_u32() + test_sext_i8_i32() + test_zext_u32_u64() + test_sext_i32_i64() + test_trunc_u64_u32() + stdio.printf("\n") + + stdio.printf("--- mixed operations ---\n") + test_mixed_signed_unsigned() + test_cdefine_values() + test_bitops_width() + stdio.printf("\n") + + stdio.printf("--- div/mod ---\n") + test_unsigned_divmod() + test_signed_divmod_neg() + stdio.printf("\n") + + stdio.printf("--- comparison & logic ---\n") + test_comparison_types() + test_bool_ops() + test_ternary() + stdio.printf("\n") + + stdio.printf("--- pointer/int cast ---\n") + test_ptr_int_cast() + stdio.printf("\n") + + stdio.printf("--- u64 mul ---\n") + test_u64_mul() + stdio.printf("\n") + + stdio.printf("=== TypeCastTest Complete ===\n") + return 0 diff --git a/Test/TypeCastTest/output/067c78e9f121dce3.deps.json b/Test/TypeCastTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..52b8465 --- /dev/null +++ b/Test/TypeCastTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/29813d57621099a9.deps.json b/Test/TypeCastTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..4159704 --- /dev/null +++ b/Test/TypeCastTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/5a6a2137958c28c5.deps.json b/Test/TypeCastTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..a9f1746 --- /dev/null +++ b/Test/TypeCastTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/72e2d5ccb7cedcf1.deps.json b/Test/TypeCastTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..1340dfa --- /dev/null +++ b/Test/TypeCastTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/a326a52b7c4bd6f0.deps.json b/Test/TypeCastTest/output/a326a52b7c4bd6f0.deps.json new file mode 100644 index 0000000..d9c58a4 --- /dev/null +++ b/Test/TypeCastTest/output/a326a52b7c4bd6f0.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/abf9ce3160c9279e.deps.json b/Test/TypeCastTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..1340dfa --- /dev/null +++ b/Test/TypeCastTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/TypeCastTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..a9f1746 --- /dev/null +++ b/Test/TypeCastTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/bf230611b27080fa.deps.json b/Test/TypeCastTest/output/bf230611b27080fa.deps.json new file mode 100644 index 0000000..73440e6 --- /dev/null +++ b/Test/TypeCastTest/output/bf230611b27080fa.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/TypeCastTest/output/fa3691e66b426950.deps.json b/Test/TypeCastTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..a9f1746 --- /dev/null +++ b/Test/TypeCastTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "string": "a326a52b7c4bd6f0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "main": "bf230611b27080fa", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/TypeCastTest/project.json b/Test/TypeCastTest/project.json new file mode 100644 index 0000000..ee80878 --- /dev/null +++ b/Test/TypeCastTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "TypeCastTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "TypeCastTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/TypeCastTest/temp/067c78e9f121dce3.pyi b/Test/TypeCastTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/TypeCastTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/TypeCastTest/temp/29813d57621099a9.pyi b/Test/TypeCastTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/TypeCastTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/TypeCastTest/temp/56cdd754a8a09347.pyi b/Test/TypeCastTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/TypeCastTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/TypeCastTest/temp/5a6a2137958c28c5.pyi b/Test/TypeCastTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/TypeCastTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/TypeCastTest/temp/72e2d5ccb7cedcf1.pyi b/Test/TypeCastTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/TypeCastTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/TypeCastTest/temp/73edbcf76e32d00b.pyi b/Test/TypeCastTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/TypeCastTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/TypeCastTest/temp/_sha1_map.txt b/Test/TypeCastTest/temp/_sha1_map.txt new file mode 100644 index 0000000..3de0bca --- /dev/null +++ b/Test/TypeCastTest/temp/_sha1_map.txt @@ -0,0 +1,7 @@ +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +72e2d5ccb7cedcf1:includes/w32\win32memory.py +73edbcf76e32d00b:includes/stdio.py +a326a52b7c4bd6f0:includes/string.py +bbdf3bbd4c3bc28c:includes/w32\win32console.py +bf230611b27080fa:main.py diff --git a/Test/TypeCastTest/temp/a326a52b7c4bd6f0.pyi b/Test/TypeCastTest/temp/a326a52b7c4bd6f0.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/TypeCastTest/temp/a326a52b7c4bd6f0.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/TypeCastTest/temp/abf9ce3160c9279e.pyi b/Test/TypeCastTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/TypeCastTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/TypeCastTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/TypeCastTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/TypeCastTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/TypeCastTest/temp/bf230611b27080fa.pyi b/Test/TypeCastTest/temp/bf230611b27080fa.pyi new file mode 100644 index 0000000..80a3db5 --- /dev/null +++ b/Test/TypeCastTest/temp/bf230611b27080fa.pyi @@ -0,0 +1,49 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +from stdint import * +import t, c +import stdio +import string +import w32.win32console +import w32.win32memory + +def test_zext_u8_u32() -> t.CInt: pass + +def test_sext_i8_i32() -> t.CInt: pass + +def test_zext_u32_u64() -> t.CInt: pass + +def test_sext_i32_i64() -> t.CInt: pass + +def test_trunc_u64_u32() -> t.CInt: pass + +def test_mixed_signed_unsigned() -> t.CInt: pass + + +VAL_32BIT: t.CDefine = 0x80000000 +VAL_NEG: t.CDefine = -1 +VAL_BIG: t.CDefine = 0xFFFFFFFF + +def test_cdefine_values() -> t.CInt: pass + +def test_bitops_width() -> t.CInt: pass + +def test_unsigned_divmod() -> t.CInt: pass + +def test_signed_divmod_neg() -> t.CInt: pass + +def test_comparison_types() -> t.CInt: pass + +def test_ptr_int_cast() -> t.CInt: pass + +def test_u64_mul() -> t.CInt: pass + +def test_bool_ops() -> t.CInt: pass + +def test_ternary() -> t.CInt: pass + +def main() -> t.CInt | t.CExport: pass diff --git a/Test/TypeCastTest/temp/fa3691e66b426950.pyi b/Test/TypeCastTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/TypeCastTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/VariadicTest/App/main.py b/Test/VariadicTest/App/main.py new file mode 100644 index 0000000..25de30d --- /dev/null +++ b/Test/VariadicTest/App/main.py @@ -0,0 +1,160 @@ +from stdint import * +import t, c +import stdio +import string +import viperlib +import w32.win32console + +# ============================================================ +# VariadicTest - 测试 snprintf/printf variadic 参数传递 +# ============================================================ + +# --- Test 1: %u 格式化小整数 (CUInt8T -> CUnsignedInt) --- +def test_snprintf_u8(): + """测试 CUInt8T 值通过 t.CUnsignedInt() 传递给 %u""" + hr: t.CUInt8T = 14 + mn: t.CUInt8T = 30 + sc: t.CUInt8T = 59 + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%02u:%02u:%02u", t.CUnsignedInt(hr), t.CUnsignedInt(mn), t.CUnsignedInt(sc)) + stdio.printf("Test1 (CUInt8T->%%u): [%s] (expect 14:30:59)\n", c.Addr(buf)) + + +# --- Test 2: %u 格式化 CUInt16T --- +def test_snprintf_u16(): + """测试 CUInt16T 值通过 t.CUnsignedInt() 传递给 %u""" + yr: t.CUInt16T = 2026 + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%04u", t.CUnsignedInt(yr)) + stdio.printf("Test2 (CUInt16T->%%u): [%s] (expect 2026)\n", c.Addr(buf)) + + +# --- Test 3: %lu 格式化 CUInt64T --- +def test_snprintf_u64(): + """测试 CUInt64T 值传递给 %lu""" + val: t.CUInt64T = 1234567890123 + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%lu", val) + stdio.printf("Test3 (CUInt64T->%%lu): [%s] (expect 1234567890123)\n", c.Addr(buf)) + + +# --- Test 4: %d 格式化负数 --- +def test_snprintf_d_neg(): + """测试 %d 格式化负整数""" + val: t.CInt = -42 + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%d", val) + stdio.printf("Test4 (CInt->%%d neg): [%s] (expect -42)\n", c.Addr(buf)) + + +# --- Test 5: %d 格式化正数 --- +def test_snprintf_d_pos(): + val: t.CInt = 42 + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%d", val) + stdio.printf("Test5 (CInt->%%d pos): [%s] (expect 42)\n", c.Addr(buf)) + + +# --- Test 6: %x 格式化十六进制 --- +def test_snprintf_x(): + val: t.CUInt32T = 0xDEADBEEF + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "0x%08x", val) + stdio.printf("Test6 (%%x): [%s] (expect 0xdeadbeef)\n", c.Addr(buf)) + + +# --- Test 7: 混合格式化 (模拟 desktop.py 时间格式) --- +def test_snprintf_mixed(): + """模拟 desktop.py 的时间格式化""" + hr: t.CUInt8T = 14 + mn: t.CUInt8T = 5 + sc: t.CUInt8T = 9 + day: t.CUInt8T = 14 + mon: t.CUInt8T = 6 + yr: t.CUInt16T = 2026 + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%04u-%02u-%02u %02u:%02u:%02u", + t.CUnsignedInt(yr), t.CUnsignedInt(mon), t.CUnsignedInt(day), + t.CUnsignedInt(hr), t.CUnsignedInt(mn), t.CUnsignedInt(sc)) + stdio.printf("Test7 (time format): [%s] (expect 2026-06-14 14:05:09)\n", c.Addr(buf)) + + +# --- Test 8: printf 直接输出 variadic --- +def test_printf_variadic(): + """测试 printf 直接输出 variadic 参数""" + stdio.printf("Test8 (printf direct): %u %d %lu 0x%x (expect 100 -50 999999999 0xcafe)\n", + t.CUnsignedInt(100), -50, t.CUInt64T(999999999), 0xCAFE) + + +# --- Test 9: 多个 %lu 连续 --- +def test_snprintf_multi_lu(): + """测试多个 %lu 连续(模拟 perf 日志格式)""" + v1: t.CUInt64T = 16 + v2: t.CUInt64T = 2 + v3: t.CUInt64T = 11 + buf: list[t.CChar, 128] + string.memset(c.Addr(buf), 0, 128) + viperlib.snprintf(c.Addr(buf), 128, "wall=%lu work=%lu render=%lu", v1, v2, v3) + stdio.printf("Test9 (multi %%lu): [%s] (expect wall=16 work=2 render=11)\n", c.Addr(buf)) + + +# --- Test 10: %u 格式化 0 --- +def test_snprintf_zero(): + val: t.CUInt32T = 0 + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%u", val) + stdio.printf("Test10 (%%u zero): [%s] (expect 0)\n", c.Addr(buf)) + + +# --- Test 11: %u 格式化大值 --- +def test_snprintf_large(): + val: t.CUInt32T = 4294967295 # 0xFFFFFFFF + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%u", val) + stdio.printf("Test11 (%%u max): [%s] (expect 4294967295)\n", c.Addr(buf)) + + +# --- Test 12: CUnsignedInt cast from CUInt8T edge values --- +def test_snprintf_u8_edge(): + """测试 CUInt8T 边界值""" + v0: t.CUInt8T = 0 + v127: t.CUInt8T = 127 + v128: t.CUInt8T = 128 + v255: t.CUInt8T = 255 + buf: list[t.CChar, 64] + string.memset(c.Addr(buf), 0, 64) + viperlib.snprintf(c.Addr(buf), 64, "%u %u %u %u", + t.CUnsignedInt(v0), t.CUnsignedInt(v127), t.CUnsignedInt(v128), t.CUnsignedInt(v255)) + stdio.printf("Test12 (CUInt8T edge): [%s] (expect 0 127 128 255)\n", c.Addr(buf)) + + +def main() -> t.CInt | t.CExport: + w32.win32console.SetConsoleCP(65001) + w32.win32console.SetConsoleOutputCP(65001) + + stdio.printf("=== VariadicTest: snprintf/printf variadic 参数测试 ===\n\n") + + test_snprintf_u8() + test_snprintf_u16() + test_snprintf_u64() + test_snprintf_d_neg() + test_snprintf_d_pos() + test_snprintf_x() + test_snprintf_mixed() + test_printf_variadic() + test_snprintf_multi_lu() + test_snprintf_zero() + test_snprintf_large() + test_snprintf_u8_edge() + + stdio.printf("\n=== VariadicTest Complete ===\n") + return 0 diff --git a/Test/VariadicTest/output/067c78e9f121dce3.deps.json b/Test/VariadicTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..47eefe1 --- /dev/null +++ b/Test/VariadicTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/VariadicTest/output/2953a7db4185005b.deps.json b/Test/VariadicTest/output/2953a7db4185005b.deps.json new file mode 100644 index 0000000..ffc1ba9 --- /dev/null +++ b/Test/VariadicTest/output/2953a7db4185005b.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/VariadicTest/output/29813d57621099a9.deps.json b/Test/VariadicTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..ffc1ba9 --- /dev/null +++ b/Test/VariadicTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/VariadicTest/output/377ad03e9b90ac39.deps.json b/Test/VariadicTest/output/377ad03e9b90ac39.deps.json new file mode 100644 index 0000000..affbd7f --- /dev/null +++ b/Test/VariadicTest/output/377ad03e9b90ac39.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/VariadicTest/output/4d5db7f970ef510f.deps.json b/Test/VariadicTest/output/4d5db7f970ef510f.deps.json new file mode 100644 index 0000000..6adc4cf --- /dev/null +++ b/Test/VariadicTest/output/4d5db7f970ef510f.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/VariadicTest/output/5a6a2137958c28c5.deps.json b/Test/VariadicTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..592b804 --- /dev/null +++ b/Test/VariadicTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/VariadicTest/output/72e2d5ccb7cedcf1.deps.json b/Test/VariadicTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..a8ad265 --- /dev/null +++ b/Test/VariadicTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1"} \ No newline at end of file diff --git a/Test/VariadicTest/output/abf9ce3160c9279e.deps.json b/Test/VariadicTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..77b9eb5 --- /dev/null +++ b/Test/VariadicTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/VariadicTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/VariadicTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..592b804 --- /dev/null +++ b/Test/VariadicTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/VariadicTest/output/c9f4be41ca1cc2b4.deps.json b/Test/VariadicTest/output/c9f4be41ca1cc2b4.deps.json new file mode 100644 index 0000000..6adc4cf --- /dev/null +++ b/Test/VariadicTest/output/c9f4be41ca1cc2b4.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4"} \ No newline at end of file diff --git a/Test/VariadicTest/output/fa3691e66b426950.deps.json b/Test/VariadicTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..592b804 --- /dev/null +++ b/Test/VariadicTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"viperlib": "2953a7db4185005b", "main": "377ad03e9b90ac39", "string": "4d5db7f970ef510f", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "stdarg": "71e0a3ffcb3ebfad", "stdio": "73edbcf76e32d00b", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "viperio": "c9f4be41ca1cc2b4", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/VariadicTest/project.json b/Test/VariadicTest/project.json new file mode 100644 index 0000000..7d561c2 --- /dev/null +++ b/Test/VariadicTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "VariadicTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-relocation-model=pic"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "VariadicTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/VariadicTest/temp/067c78e9f121dce3.pyi b/Test/VariadicTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/VariadicTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/VariadicTest/temp/2953a7db4185005b.pyi b/Test/VariadicTest/temp/2953a7db4185005b.pyi new file mode 100644 index 0000000..aa40bc7 --- /dev/null +++ b/Test/VariadicTest/temp/2953a7db4185005b.pyi @@ -0,0 +1,19 @@ +""" +Auto-generated Python stub file from viperlib.py +Module: viperlib +""" + + +import t, c +import viperio +from stdarg import arg + +TEMP_BUF_SIZE: t.CDefine = 24 + +def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt | t.State: pass + +def sprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CVoid | t.State: pass + +def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt | t.State: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt | t.State: pass diff --git a/Test/VariadicTest/temp/29813d57621099a9.pyi b/Test/VariadicTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/VariadicTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/VariadicTest/temp/377ad03e9b90ac39.pyi b/Test/VariadicTest/temp/377ad03e9b90ac39.pyi new file mode 100644 index 0000000..a23a5ee --- /dev/null +++ b/Test/VariadicTest/temp/377ad03e9b90ac39.pyi @@ -0,0 +1,38 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +from stdint import * +import t, c +import stdio +import string +import viperlib +import w32.win32console + +def test_snprintf_u8() -> t.CInt: pass + +def test_snprintf_u16() -> t.CInt: pass + +def test_snprintf_u64() -> t.CInt: pass + +def test_snprintf_d_neg() -> t.CInt: pass + +def test_snprintf_d_pos() -> t.CInt: pass + +def test_snprintf_x() -> t.CInt: pass + +def test_snprintf_mixed() -> t.CInt: pass + +def test_printf_variadic() -> t.CInt: pass + +def test_snprintf_multi_lu() -> t.CInt: pass + +def test_snprintf_zero() -> t.CInt: pass + +def test_snprintf_large() -> t.CInt: pass + +def test_snprintf_u8_edge() -> t.CInt: pass + +def main() -> t.CInt | t.CExport: pass diff --git a/Test/VariadicTest/temp/4d5db7f970ef510f.pyi b/Test/VariadicTest/temp/4d5db7f970ef510f.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/VariadicTest/temp/4d5db7f970ef510f.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/VariadicTest/temp/56cdd754a8a09347.pyi b/Test/VariadicTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/VariadicTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/VariadicTest/temp/5a6a2137958c28c5.pyi b/Test/VariadicTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/VariadicTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/VariadicTest/temp/71e0a3ffcb3ebfad.pyi b/Test/VariadicTest/temp/71e0a3ffcb3ebfad.pyi new file mode 100644 index 0000000..574b20e --- /dev/null +++ b/Test/VariadicTest/temp/71e0a3ffcb3ebfad.pyi @@ -0,0 +1,20 @@ +""" +Auto-generated Python stub file from stdarg.py +Module: stdarg +""" + +import c + + +import t + +def va_start(args: t.CPtr, last_arg: t.CPtr) -> t.State: pass + +def va_arg(args: t.CPtr, type: t.CPtr) -> t.CPtr | t.State: pass + +def va_end(args: t.CPtr) -> t.State | t.State: pass + + +va_list: t.CTypedef = t.CUnsignedChar | t.CPtr + +def arg(type: t.CType) -> t.State: pass diff --git a/Test/VariadicTest/temp/72e2d5ccb7cedcf1.pyi b/Test/VariadicTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/VariadicTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/VariadicTest/temp/73edbcf76e32d00b.pyi b/Test/VariadicTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/VariadicTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/VariadicTest/temp/_sha1_map.txt b/Test/VariadicTest/temp/_sha1_map.txt new file mode 100644 index 0000000..d9d969b --- /dev/null +++ b/Test/VariadicTest/temp/_sha1_map.txt @@ -0,0 +1,9 @@ +2953a7db4185005b:includes/viperlib.py +377ad03e9b90ac39:main.py +4d5db7f970ef510f:includes/string.py +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +71e0a3ffcb3ebfad:includes/stdarg.py +73edbcf76e32d00b:includes/stdio.py +bbdf3bbd4c3bc28c:includes/w32\win32console.py +c9f4be41ca1cc2b4:includes/viperio.py diff --git a/Test/VariadicTest/temp/abf9ce3160c9279e.pyi b/Test/VariadicTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/VariadicTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/VariadicTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/VariadicTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/VariadicTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/VariadicTest/temp/c9f4be41ca1cc2b4.pyi b/Test/VariadicTest/temp/c9f4be41ca1cc2b4.pyi new file mode 100644 index 0000000..fdbd7ec --- /dev/null +++ b/Test/VariadicTest/temp/c9f4be41ca1cc2b4.pyi @@ -0,0 +1,22 @@ +""" +Auto-generated Python stub file from viperio.py +Module: viperio +""" + + +import t, c +from stdint import * + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + def __init__(self: Buf, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT, owned: bool) -> t.CInt: pass + def clear(self: Buf) -> t.CInt: pass + def write(self: Buf, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: pass + def cstr(self: Buf) -> t.CChar | t.CPtr: pass + def reset(self: Buf) -> t.CInt: pass + def __enter__(self: Buf) -> 'Buf' | t.CPtr: pass + def __exit__(self: Buf) -> t.CInt: pass + def free(self: Buf) -> t.CInt: pass \ No newline at end of file diff --git a/Test/VariadicTest/temp/fa3691e66b426950.pyi b/Test/VariadicTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/VariadicTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/ZlibTest/App/__zlib/__init__.py b/Test/ZlibTest/App/__zlib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Test/ZlibTest/App/__zlib/pyzlib.py b/Test/ZlibTest/App/__zlib/pyzlib.py new file mode 100644 index 0000000..0bd0a84 --- /dev/null +++ b/Test/ZlibTest/App/__zlib/pyzlib.py @@ -0,0 +1,549 @@ +from stdint import * +import zdeflate +import zinflate +import zchecksum +import zdef +import zhuff +import stdlib +import string +import t, c + + +# ============================================================ +# Constants - matching Python zlib module names and values +# ============================================================ + +# Compression levels +Z_NO_COMPRESSION: t.CDefine = 0 +Z_BEST_SPEED: t.CDefine = 1 +Z_BEST_COMPRESSION: t.CDefine = 9 +Z_DEFAULT_COMPRESSION: t.CDefine = (-1) + +# Compression methods +DEFLATED: t.CDefine = 8 + +# Flush modes +Z_NO_FLUSH: t.CDefine = 0 +Z_PARTIAL_FLUSH: t.CDefine = 1 +Z_SYNC_FLUSH: t.CDefine = 2 +Z_FULL_FLUSH: t.CDefine = 3 +Z_FINISH: t.CDefine = 4 +Z_BLOCK: t.CDefine = 5 +Z_TREES: t.CDefine = 6 + +# Strategies +Z_DEFAULT_STRATEGY: t.CDefine = 0 +Z_FILTERED: t.CDefine = 1 +Z_HUFFMAN_ONLY: t.CDefine = 2 +Z_RLE: t.CDefine = 3 +Z_FIXED: t.CDefine = 4 + +# Return codes +Z_OK: t.CDefine = 0 +Z_STREAM_END: t.CDefine = 1 +Z_NEED_DICT: t.CDefine = 2 +Z_ERRNO: t.CDefine = (-1) +Z_STREAM_ERROR: t.CDefine = (-2) +Z_DATA_ERROR: t.CDefine = (-3) +Z_MEM_ERROR: t.CDefine = (-4) +Z_BUF_ERROR: t.CDefine = (-5) +Z_VERSION_ERROR: t.CDefine = (-6) + +# Window / Buffer constants +MAX_WBITS: t.CDefine = 15 +DEF_BUF_SIZE: t.CDefine = 16384 +DEF_MEM_LEVEL: t.CDefine = 8 + +# Version +ZLIB_VERSION: t.CDefine = "1.3.2" + +pyzlib_error_msg: list[t.CChar, 512] = "" +pyzlib_error_code_val: t.CInt = 0 + +# ============================================================ +# Structures +# ============================================================ +@t.Object +class Compress: + stream: VOIDPTR + is_initialized: t.CInt + is_finished: t.CInt + level: t.CInt + method: t.CInt + wbits: t.CInt + memLevel: t.CInt + strategy: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + last_pos: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + header_written: t.CInt + + def compress(self, + data: BYTEPTR, data_len: t.CSizeT, + out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if self.is_finished: + set_error(Z_STREAM_ERROR, "compress object already finished") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + if data_len == 0: + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + while self.input_buf_len + data_len > self.input_buf_cap: + self.input_buf_cap *= 2 + new_buf: BYTEPTR = BYTEPTR(realloc(self.input_buf, self.input_buf_cap)) + if not new_buf: + set_error(Z_MEM_ERROR, "out of memory") + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + self.input_buf = new_buf + memcpy(self.input_buf + self.input_buf_len, data, data_len) + self.input_buf_len += data_len + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + + def flush(self, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + if mode == Z_FINISH: + if not self.header_written: + self.header_written = 1 + input_data: BYTEPTR = self.input_buf + input_len: t.CSizeT = self.input_buf_len + if input_len == 0: + s.writer.write_bits(1, 1) + s.writer.write_bits(1, 2) + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + lit_tree.encode_symbol(256, c.Addr(s.writer)) + else: + s.adler = zchecksum.zchecksum_adler32(input_data, input_len, 1) + s.compress_block(input_data, input_len, 1) + s.is_finished = 1 + if s.wbits >= 0: + s.writer.align() + adler: t.CUInt32T = s.adler + s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF + s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF + s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF + s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF + s.writer.byte_pos += 4 + self.is_finished = 1 + total: t.CSizeT = s.writer.total() + result: BYTEPTR = BYTEPTR(malloc(total)) + if result: memcpy(result, s.writer.buf, total) + c.Set(c.Deref(out_len), total) + free(self.input_buf) + self.input_buf = None + self.input_buf_len = 0 + self.input_buf_cap = 0 + return result + elif mode == Z_SYNC_FLUSH or mode == Z_FULL_FLUSH: + input_data: BYTEPTR = self.input_buf + input_len: t.CSizeT = self.input_buf_len + if input_len > 0: + s.adler = zchecksum.zchecksum_adler32(input_data, input_len, s.adler) + s.compress_block(input_data, input_len, 0) + self.input_buf_len = 0 + s.writer.write_bits(0, 1) + s.writer.write_bits(0, 2) + s.writer.align() + prev_pos: t.CSizeT = self.last_pos + total: t.CSizeT = s.writer.total() + delta: t.CSizeT = total - prev_pos + self.last_pos = s.writer.byte_pos + if delta == 0: + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + + result: BYTEPTR = BYTEPTR(malloc(delta)) + if result: memcpy(result, s.writer.buf + prev_pos, delta) + c.Set(c.Deref(out_len), delta) + return result + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + + def copy(self) -> Compress | t.CPtr: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + copy_obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__()) + if not copy_obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + copy_obj.stream = s.copy() + if not copy_obj.stream: + free(copy_obj) + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.is_initialized = 1 + copy_obj.is_finished = self.is_finished + copy_obj.level = self.level + copy_obj.method = self.method + copy_obj.wbits = self.wbits + copy_obj.memLevel = self.memLevel + copy_obj.strategy = self.strategy + copy_obj.last_pos = self.last_pos + copy_obj.header_written = self.header_written + if self.input_buf and self.input_buf_len > 0: + copy_obj.input_buf = BYTEPTR(calloc(1, self.input_buf_cap)) + if copy_obj.input_buf: + memcpy(copy_obj.input_buf, self.input_buf, self.input_buf_len) + copy_obj.input_buf_cap = self.input_buf_cap + copy_obj.input_buf_len = self.input_buf_len + else: + copy_obj.input_buf = BYTEPTR(calloc(1, 256)) + copy_obj.input_buf_cap = 256 + copy_obj.input_buf_len = 0 + if self.zdict and self.zdict_len > 0: + copy_obj.zdict = clone_bytes(self.zdict, self.zdict_len) + copy_obj.zdict_len = self.zdict_len + return copy_obj + + def delete(self): + if self.is_initialized and self.stream: + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + s.destroy() + free(self.zdict) + free(self.input_buf) + free(self) + + def __del__(self): + self.delete() + + +@t.Object +class Decompress: + stream: VOIDPTR + is_initialized: t.CInt + eof: t.CInt + wbits: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + _unused_data: BYTEPTR + _unused_data_len: t.CSizeT + _unused_data_cap: t.CSizeT + _unconsumed_tail: BYTEPTR + _unconsumed_tail_len: t.CSizeT + _unconsumed_tail_cap: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + + def decompress(self, data: BYTEPTR, data_len: t.CSizeT, + max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + if self.eof: + if data and data_len > 0: + append_bytes(c.Addr(self._unused_data), c.Addr(self._unused_data_len), + c.Addr(self._unused_data_cap), data, data_len) + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + self._unconsumed_tail_len = 0 + if data and data_len > 0: + append_bytes(c.Addr(self.input_buf), c.Addr(self.input_buf_len), + c.Addr(self.input_buf_cap), data, data_len) + if self.input_buf_len == 0: + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + s: zinflate.zinflate_stream | t.CPtr = zinflate.zinflate_create(self.wbits) + if not s: + set_error(Z_MEM_ERROR, "out of memory") + return None + if self.zdict and self.zdict_len > 0: + s.set_dictionary(self.zdict, self.zdict_len) + out: t.CUInt8T | t.CPtr = None + err: t.CInt = s.decompress(self.input_buf, self.input_buf_len, + max_length, c.Addr(out), out_len) + if err != 0: + s.destroy() + set_error(Z_DATA_ERROR, "decompression failed") + return None + if s.is_finished: + self.eof = 1 + if s.input_pos < s.input_len: + append_bytes(c.Addr(self._unused_data), c.Addr(self._unused_data_len), + c.Addr(self._unused_data_cap), + s.input_data + s.input_pos, + s.input_len - s.input_pos) + self.input_buf_len = 0 + else: + consumed: t.CSizeT = s.input_pos + if consumed < self.input_buf_len: + remaining: t.CSizeT = self.input_buf_len - consumed + memmove(self.input_buf, self.input_buf + consumed, remaining) + self.input_buf_len = remaining + else: + self.input_buf_len = 0 + s.destroy() + return out + + def flush(self, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + c.Set(c.Deref(out_len), 0) + return BYTEPTR(calloc(1, 1)) + + def copy(self) -> Decompress | t.CPtr: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + copy_obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__()) + if not copy_obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.is_initialized = 1 + copy_obj.eof = self.eof + copy_obj.wbits = self.wbits + if self.zdict and self.zdict_len > 0: + copy_obj.zdict = clone_bytes(self.zdict, self.zdict_len) + copy_obj.zdict_len = self.zdict_len + if self._unused_data and self._unused_data_len > 0: + copy_obj._unused_data = clone_bytes(self._unused_data, self._unused_data_len) + copy_obj._unused_data_len = self._unused_data_len + copy_obj._unused_data_cap = self._unused_data_len + if self._unconsumed_tail and self._unconsumed_tail_len > 0: + copy_obj._unconsumed_tail = clone_bytes(self._unconsumed_tail, self._unconsumed_tail_len) + copy_obj._unconsumed_tail_len = self._unconsumed_tail_len + copy_obj._unconsumed_tail_cap = self._unconsumed_tail_len + if self.input_buf and self.input_buf_len > 0: + copy_obj.input_buf = clone_bytes(self.input_buf, self.input_buf_len) + copy_obj.input_buf_len = self.input_buf_len + copy_obj.input_buf_cap = self.input_buf_cap + else: + copy_obj.input_buf = BYTEPTR(calloc(1, 256)) + copy_obj.input_buf_cap = 256 + copy_obj.input_buf_len = 0 + return copy_obj + + def delete(self): + free(self.zdict) + free(self._unused_data) + free(self._unconsumed_tail) + free(self.input_buf) + free(self) + + def unused_data(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + #if not self: + # if length: + # c.Set(c.Deref(length), 0) + # return None + if length: + c.Set(c.Deref(length), self._unused_data_len) + return self._unused_data + + def unconsumed_tail(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + #if not self: + # if length: + # c.Set(c.Deref(length), 0) + # return None + if length: + c.Set(c.Deref(length), self._unconsumed_tail_len) + return self._unconsumed_tail + +# def eof(self) -> t.CInt: +# # if not obj: return 0 +# return self.eof + + + +def set_error(code: int, msg: str): + global pyzlib_error_code_val, pyzlib_error_msg + pyzlib_error_code_val = code + if msg: + strncpy(pyzlib_error_msg, msg, pyzlib_error_msg.__sizeof__() - 1) + pyzlib_error_msg[pyzlib_error_msg.__sizeof__() - 1] = '\0' + else: + pyzlib_error_msg[0] = '\0' + +def clone_bytes(src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if not src or length == 0: return None + dst: BYTEPTR = BYTEPTR(malloc(length)) + if dst: memcpy(dst, src, length) + return dst + +def append_bytes(buf: BYTE | t.CPtr[t.CPtr], length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr, + data: BYTEPTR, data_len: t.CSizeT) -> t.CInt: + if not data or data_len == 0: return 0 + needed: t.CSizeT = c.Deref(length) + data_len + if needed > c.Deref(cap): + new_cap: t.CSizeT = c.Deref(cap) * 2 + if new_cap < needed: new_cap = needed + new_buf: BYTEPTR = BYTEPTR(realloc(c.Deref(buf), new_cap)) + if not new_buf: return -1 + c.Set(c.Deref(buf), new_buf) + c.Set(c.Deref(cap), new_cap) + memcpy(c.Deref(buf) + c.Deref(length), data, data_len) + c.Set(c.Deref(length), c.Deref(length) + data_len) + return 0 + + +def shrink_to_fit(buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if length == 0: + free(buf) + return BYTEPTR(calloc(1, 1)) + result: BYTEPTR = BYTEPTR(realloc(buf, length)) + return result if result else buf + + +def runtime_version() -> str: + return ZLIB_VERSION + +def get_error() -> str: + return pyzlib_error_msg + +def get_error_code() -> t.CInt: + return pyzlib_error_code_val + +def clear_error(): + global pyzlib_error_msg, pyzlib_error_code_val + pyzlib_error_msg[0] = '\0' + pyzlib_error_code_val = 0 + +def compress(data: BYTEPTR, data_len: t.CSizeT, + level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not data and data_len > 0: + set_error(Z_STREAM_ERROR, "data is None but data_len > 0") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: + actual_wbits = -MAX_WBITS + raw_result: UINT8PTR = zdeflate.zdeflate_one_shot(data, data_len, level, actual_wbits, out_len) + if not raw_result: + set_error(Z_DATA_ERROR, "compression failed") + return None + if wbits > MAX_WBITS: + gzip_len: t.CSizeT = 10 + c.Deref(out_len) + 8 + gzip_buf: BYTEPTR = BYTEPTR(malloc(gzip_len)) + if not gzip_buf: + free(raw_result) + set_error(Z_MEM_ERROR, "out of memory") + return None + pos: t.CSizeT = 0 + gzip_buf[pos + 0] = 0x1F + gzip_buf[pos + 1] = 0x8B + gzip_buf[pos + 2] = 0x08 + gzip_buf[pos + 3] = 0x00 + gzip_buf[pos + 4] = 0x00 + gzip_buf[pos + 5] = 0x00 + gzip_buf[pos + 6] = 0x00 + gzip_buf[pos + 7] = 0x00 + gzip_buf[pos + 8] = 0x00 + gzip_buf[pos + 9] = 0xFF + pos += 10 + + memcpy(gzip_buf + pos, raw_result, c.Deref(out_len)) + pos += c.Deref(out_len) + free(raw_result) + + crc: t.CUInt32T = zchecksum.zchecksum_crc32(data, data_len, 0) + gzip_buf[pos + 0] = (crc) & 0xFF + gzip_buf[pos + 1] = (crc >> 8) & 0xFF + gzip_buf[pos + 2] = (crc >> 16) & 0xFF + gzip_buf[pos + 3] = (crc >> 24) & 0xFF + gzip_buf[pos + 4] = (data_len) & 0xFF + gzip_buf[pos + 5] = (data_len >> 8) & 0xFF + gzip_buf[pos + 6] = (data_len >> 16) & 0xFF + gzip_buf[pos + 7] = (data_len >> 24) & 0xFF + pos += 8 + c.Set(c.Deref(out_len), pos) + return shrink_to_fit(gzip_buf, pos) + return shrink_to_fit(raw_result, c.Deref(out_len)) + + +def decompress(data: BYTEPTR, data_len: t.CSizeT, + wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not data and data_len > 0: + set_error(Z_STREAM_ERROR, "data is None but data_len > 0") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + result: UINT8PTR = zinflate.zinflate_one_shot(data, data_len, wbits, bufsize, out_len) + if not result: + set_error(Z_DATA_ERROR, "decompression failed") + return None + return shrink_to_fit(result, c.Deref(out_len)) + +def compressobj(level: t.CInt, method: t.CInt, wbits: t.CInt, + memLevel: t.CInt, strategy: t.CInt, + zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr: + obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__()) + if not obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: actual_wbits = wbits - 16 + s: zdeflate.zdeflate_stream | t.CPtr = zdeflate.zdeflate_create(level, actual_wbits, memLevel, strategy) + if not s: + free(obj) + set_error(Z_MEM_ERROR, "out of memory") + return None + obj.stream = s + obj.is_initialized = 1 + obj.level = level + obj.method = method + obj.wbits = wbits + obj.memLevel = memLevel + obj.strategy = strategy + obj.input_buf = BYTEPTR(calloc(1, 256)) + obj.input_buf_cap = 256 + obj.input_buf_len = 0 + obj.header_written = 0 + if zdict and zdict_len > 0: + s.set_dictionary(zdict, zdict_len) + obj.zdict = clone_bytes(zdict, zdict_len) + obj.zdict_len = zdict_len + return obj + + +def decompressobj(wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: + obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__()) + if not obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: actual_wbits = wbits - 16 + obj.stream = None + obj.is_initialized = 1 + obj.wbits = actual_wbits + if zdict and zdict_len > 0: + obj.zdict = clone_bytes(zdict, zdict_len) + obj.zdict_len = zdict_len + obj.input_buf = BYTEPTR(calloc(1, 256)) + obj.input_buf_cap = 256 + obj.input_buf_len = 0 + return obj + +def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: + return zchecksum.zchecksum_adler32(data, length, UINT32(value)) + +def zlib_crc32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: + return zchecksum.zchecksum_crc32(data, length, UINT32(value)) + + diff --git a/Test/ZlibTest/App/__zlib/test_pyzlib.py b/Test/ZlibTest/App/__zlib/test_pyzlib.py new file mode 100644 index 0000000..256df64 --- /dev/null +++ b/Test/ZlibTest/App/__zlib/test_pyzlib.py @@ -0,0 +1,875 @@ +from stdint import * +import pyzlib +import zhuff +import zdef +from stdio import printf, strlen +import stdlib +import string +import t, c + + +test_passed: t.CInt = 0 +test_failed: t.CInt = 0 +def check(name: str, condition: t.CInt, detail: str): + if condition: + test_passed += 1 + printf(" [PASS] %s\n", name) + else: + test_failed += 1 + printf(" [FAIL] %s -- %s\n", name, detail if detail else "") + +def print_hex_test(data: BYTEPTR, length: t.CSizeT, max_show: t.CSizeT): + if not data or length == 0: + printf("(empty)\n") + return + show: t.CSizeT = max_show if (length > max_show) else length + i: t.CSizeT + for i in range(show): + printf("%02X ", data[i]) + if length > max_show: + printf("... (%zu bytes total)", length) + printf("\n") + +def print_separator(): + printf(" -------------------------------------------\n") + +def section_header(title: str): + printf("\n+-- %s --+\n", title) + +def section_footer(): + printf("+--------------------------------------------+\n") + +# ============================================================ + +def test_version(): + section_header("Version Info") + + ver: str = pyzlib.ZLIB_VERSION + printf(" ZLIB_VERSION (compile-time) : %s\n", ver) + check("ZLIB_VERSION not None", ver != None, "version string is None") + check("ZLIB_VERSION not empty", strlen(ver) > 0, "version string is empty") + + runtime_ver: str = pyzlib.runtime_version() + printf(" ZLIB_RUNTIME_VERSION : %s\n", runtime_ver) + check("runtime version not None", runtime_ver != None, "runtime version is None") + check("runtime version not empty", strlen(runtime_ver) > 0, "runtime version is empty") + + section_footer() + + +def test_compress_decompress(): + section_header("compress / decompress") + + inp: str = "Hello, World! This is a test of zlib compression and decompression." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("compress returns non-None", compressed != None, "compress returned None") + check("compress output size > 0", out_length > 0, "compressed size is 0") + check("compress output produced", out_length > 0, "compressed size is 0") + + printf(" Compressed (%zu bytes): ", out_length) + print_hex_test(compressed, out_length, 32) + printf(" Compression ratio: %.1f%%\n", t.CDouble(out_length) / input_length * 100) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(compressed, out_length, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress returns non-None", decompressed != None, "decompress returned None") + check("decompress output size matches input", dec_length == input_length, "size mismatch") + check("decompress output matches input", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + + printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(decompressed)) + + free(compressed) + free(decompressed) + section_footer() + + +def test_compress_levels(): + section_header("Compression Levels") + + inp: str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + + c0: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_NO_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 0 compress OK", c0 != None, "level 0 returned None") + printf(" Level 0 (Z_NO_COMPRESSION): %zu bytes\n", out_length) + length0: t.CSizeT = out_length + free(c0) + + c1: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_BEST_SPEED, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 1 compress OK", c1 != None, "level 1 returned None") + printf(" Level 1 (Z_BEST_SPEED) : %zu bytes\n", out_length) + free(c1) + + c6: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level -1 compress OK", c6 != None, "default level returned None") + printf(" Level -1 (DEFAULT) : %zu bytes\n", out_length) + free(c6) + + c9: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_BEST_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("level 9 compress OK", c9 != None, "level 9 returned None") + printf(" Level 9 (Z_BEST_COMPRESS) : %zu bytes\n", out_length) + length9: t.CSizeT = out_length + free(c9) + + check("level 9 smaller than level 0", length9 < length0, "level 9 not smaller than level 0") + + section_footer() + + +def test_compressobj(): + section_header("compressobj (incremental)") + + part1: str = "Hello, " + part2: str = "World!" + printf(" Part 1: \"%s\"\n", part1) + printf(" Part 2: \"%s\"\n", part2) + + out_length: t.CSizeT = 0 + + s: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + check("compressobj created", s != None, "compressobj is None") + print_separator() + + c1: BYTEPTR = s.compress(BYTEPTR(part1), strlen(part1), c.Addr(out_length)) + check("compress part1 OK", c1 != None, "compress part1 failed") + printf(" Compressed part1: %zu bytes -> ", out_length) + print_hex_test(c1, out_length, 16) + total: t.CSizeT = out_length + all: BYTEPTR = None + if out_length > 0 and c1: + all = BYTEPTR(malloc(total)) + if all: memcpy(all, c1, out_length) + free(c1) + + c2: BYTEPTR = s.compress(BYTEPTR(part2), + strlen(part2), c.Addr(out_length)) + check("compress part2 OK", c2 != None, "compress part2 failed") + printf(" Compressed part2: %zu bytes -> ", out_length) + print_hex_test(c2, out_length, 16) + if out_length > 0 and c2: + new_all: BYTEPTR = BYTEPTR(realloc(all, total + out_length)) + if new_all: + all = new_all + memcpy(all + total, c2, out_length) + total += out_length + free(c2) + + c3: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush (Z_FINISH) OK", c3 != None, "flush failed") + printf(" Flush result : %zu bytes -> ", out_length) + print_hex_test(c3, out_length, 16) + if out_length > 0 and c3: + new_all: BYTEPTR = realloc(all, total + out_length) # 隐式转换 + if new_all: + all = new_all + memcpy(all + total, c3, out_length) + total += out_length + free(c3) + + print_separator() + + if all: + dec_length: t.CSizeT = 0 + dec: BYTEPTR = pyzlib.decompress(all, total, pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress incremental OK", dec != None, "decompress returned None") + check("decompress incremental size", dec != None and dec_length == strlen(part1) + strlen(part2), "size mismatch") + check("decompress incremental content", + dec != None and memcmp(dec, "Hello, World!", dec_length) == 0, "content mismatch") + if dec: + printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + free(all) + + s.delete() # del s + section_footer() + +def test_decompressobj(): + section_header("decompressobj") + + inp: str = "Test data for decompress object." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pyzlib.MAX_WBITS, None, 0) + check("decompressobj created", d != None, "decompressobj is None") + check("eof is false initially", d.eof == 0, "eof should be 0") + print_separator() + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(compressed, out_length, + 0, c.Addr(dec_length)) + check("decompress OK", dec != None, "decompress returned None") + check("decompress size", dec != None and dec_length == input_length, "size mismatch") + check("decompress content", dec != None and memcmp(dec, inp, input_length) == 0, "content mismatch") + check("eof is true after stream end", d.eof == 1, "eof should be 1") + + if dec: + printf(" Decompressed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(dec)) + printf(" eof = %d\n", d.eof) + + free(dec) + free(compressed) + d.delete() + section_footer() + +def test_decompressobj_max_lengthgth(): + section_header("decompressobj max_lengthgth") + + inp: str = "This is a longer string for testing max_lengthgth parameter in decompress." + input_length: t.CSizeT = strlen(inp) + printf(" Input (%zu bytes): \"%s\"\n", input_length, inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pyzlib.MAX_WBITS, None, 0) + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(compressed, out_length, + 10, c.Addr(dec_length)) + check("max_lengthgth decompress OK", dec != None, "decompress returned None") + check("max_lengthgth limits output", dec_length <= 10, "output exceeded max_lengthgth") + if dec: + printf(" First chunk (max_lengthgth=10): \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + + tail_length: t.CSizeT = 0 + tail: BYTEPTR = d.unconsumed_tail(c.Addr(tail_length)) + check("unconsumed_tail exists", tail != None or tail_length == 0, "no unconsumed_tail") + printf(" unconsumed_tail: %zu bytes remaining\n", tail_length) + printf(" eof = %d\n", d.eof) + + if tail_length > 0 or not d.eof: + flushed: BYTEPTR = d.flush(pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("flush after max_lengthgth OK", flushed != None, "flush returned None") + if flushed: printf(" Flushed (%zu bytes): \"%.*s\"\n", dec_length, t.CInt(dec_length), str(flushed)) + free(flushed) + + printf(" eof after flush = %d\n", d.eof) + + d.delete() + free(compressed) + section_footer() + + +def test_decompressobj_unused_data(): + section_header("decompressobj unused_data") + + inp: str = "Hello" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + total_length: t.CSizeT = out_length + 5 + combined: BYTEPTR = BYTEPTR(malloc(total_length)) + memcpy(combined, compressed, out_length) + memcpy(combined + out_length, "EXTRA", 5) + free(compressed) + printf(" Combined (compressed + \"EXTRA\"): %zu bytes\n", total_length) + + d: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pyzlib.MAX_WBITS, None, 0) + + dec_length: t.CSizeT = 0 + dec: BYTEPTR = d.decompress(combined, total_length, + 0, c.Addr(dec_length)) + check("decompress with extra OK", dec != None, "decompress returned None") + check("eof after stream end", d.eof == 1, "eof should be 1") + if dec: + printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(dec), dec_length) + free(dec) + + print_separator() + + unused_length: t.CSizeT = 0 + unused: BYTEPTR = d.unused_data(c.Addr(unused_length)) + check("unused_data exists", unused != None and unused_length > 0, "no unused_data") + check("unused_data is EXTRA", unused_length == 5 and unused != None and memcmp(unused, "EXTRA", 5) == 0, "unused_data mismatch") + printf(" unused_data (%zu bytes): \"%.*s\"\n", unused_length, t.CInt(unused_length), str(unused)) + + d.delete() + free(combined) + section_footer() + + +def test_compress_copy(): + section_header("Compress.copy()") + + inp: str = "Copy test data for compress object" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + c1: pyzlib.Compress | t.CPtr = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + c1.compress(BYTEPTR(inp), input_length, c.Addr(out_length)) + printf(" Original: compressed %zu bytes so far\n", out_length) + + c2: pyzlib.Compress = c1.copy() + check("compress copy OK", c2 != None, "copy returned None") + printf(" Copied compressobj\n") + + print_separator() + + f1: BYTEPTR = c1.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush original OK", f1 != None, "flush original failed") + length1: t.CSizeT = out_length + printf(" Original flush: %zu bytes\n", length1) + free(f1) + + f2: BYTEPTR = c2.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush copy OK", f2 != None, "flush copy failed") + length2: t.CSizeT = out_length + printf(" Copy flush : %zu bytes\n", length2) + free(f2) + + check("copy produces same output", length1 == length2, "output lengthgths differ") + + c1.delete() + c2.delete() + section_footer() + + +def test_decompress_copy(): + section_header("Decompress.copy()") + + inp: str = "Decompress copy test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\"\n", inp) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + printf(" Compressed: %zu bytes\n", out_length) + + d1: pyzlib.Decompress | t.CPtr = pyzlib.decompressobj(pyzlib.MAX_WBITS, None, 0) + d2: pyzlib.Decompress | t.CPtr = d1.copy() + check("decompress copy OK", d2 != None, "copy returned None") + printf(" Copied decompressobj\n") + + print_separator() + + dec_length1: t.CSizeT = 0 + dec_length2: t.CSizeT = 0 + dec1: BYTEPTR = d1.decompress(compressed, out_length, + 0, c.Addr(dec_length1)) + dec2: BYTEPTR = d2.decompress(compressed, out_length, + 0, c.Addr(dec_length2)) + check("decompress copy output size", dec_length1 == dec_length2, "sizes differ") + check("decompress copy output content", + dec1 and dec2 and memcmp(dec1, dec2, dec_length1) == 0, "content differs") + + if dec1: printf(" Original: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length1), str(dec1), dec_length1) + if dec2: printf(" Copy : \"%.*s\" (%zu bytes)\n", t.CInt(dec_length2), str(dec2), dec_length2) + + free(dec1) + free(dec2) + free(compressed) + d1.delete() + d2.delete() + section_footer() + + +def test_adler32(): + section_header("adler32 checksum") + + checksum: ULONG = pyzlib.zlib_adler32(BYTEPTR("Hello"), 5, 1) + printf(" adler32(\"Hello\") = 0x%08lX (%lu)\n", checksum, checksum) + check("adler32 returns non-zero", checksum != 0, "checksum is 0") + + incremental: ULONG = pyzlib.zlib_adler32(BYTEPTR("Hel"), 3, 1) + printf(" adler32(\"Hel\") = 0x%08lX\n", incremental) + incremental = pyzlib.zlib_adler32(BYTEPTR("lo"), 2, incremental) + printf(" adler32(\"lo\", prev) = 0x%08lX\n", incremental) + check("adler32 incremental matches one-shot", incremental == checksum, "incremental != one-shot") + printf(" Incremental == One-shot: %s\n", incremental == "YES" if checksum else "NO") + + section_footer() + + +def test_crc32(): + section_header("crc32 checksum") + + checksum: ULONG = pyzlib.zlib_crc32(BYTEPTR("Hello"), 5, 0) + printf(" crc32(\"Hello\") = 0x%08lX (%lu)\n", checksum, checksum) + check("crc32 returns non-zero", checksum != 0, "checksum is 0") + + incremental: ULONG = pyzlib.zlib_crc32(BYTEPTR("Hel"), 3, 0) + printf(" crc32(\"Hel\") = 0x%08lX\n", incremental) + incremental = pyzlib.zlib_crc32(BYTEPTR("lo"), 2, incremental) + printf(" crc32(\"lo\", prev) = 0x%08lX\n", incremental) + check("crc32 incremental matches one-shot", incremental == checksum, "incremental != one-shot") + printf(" Incremental == One-shot: %s\n", incremental == "YES" if checksum else "NO") + + section_footer() + + +def test_empty_compress(): + section_header("Empty data compress/decompress") + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(""), 0, + pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.MAX_WBITS, c.Addr(out_length)) + check("compress empty OK", compressed != None, "compress empty returned None") + check("compress empty output > 0", out_length > 0, "compressed empty is 0 bytes") + printf(" Empty input compressed: %zu bytes (header only)\n", out_length) + printf(" Hex: ") + print_hex_test(compressed, out_length, 32) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(compressed, out_length, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("decompress empty OK", decompressed != None, "decompress empty returned None") + check("decompress empty size == 0", dec_length == 0, "decompressed size != 0") + printf(" Decompressed back: %zu bytes\n", dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_gzip_format(): + section_header("Gzip format (wbits=31)") + + inp: str = "Gzip format test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\" (%zu bytes)\n", inp, input_length) + + gzip_wbits: t.CInt = pyzlib.MAX_WBITS + 16 + printf(" wbits = MAX_WBITS + 16 = %d\n", gzip_wbits) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, gzip_wbits, c.Addr(out_length)) + check("gzip compress OK", compressed != None, "gzip compress failed") + printf(" Gzip compressed: %zu bytes\n", out_length) + printf(" Header bytes: ") + print_hex_test(compressed, 4 if (out_length > 4) else out_length, 4) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(compressed, out_length, + gzip_wbits, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("gzip decompress OK", decompressed != None, "gzip decompress failed") + check("gzip decompress size", dec_length == input_length, "size mismatch") + check("gzip decompress content", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_raw_deflate(): + section_header("Raw deflate (wbits=-15)") + + inp: str = "Raw deflate test" + input_length: t.CSizeT = strlen(inp) + printf(" Input: \"%s\" (%zu bytes)\n", inp, input_length) + + raw_wbits: t.CInt = -pyzlib.MAX_WBITS + printf(" wbits = -MAX_WBITS = %d\n", raw_wbits) + + out_length: t.CSizeT = 0 + compressed: BYTEPTR = pyzlib.compress(BYTEPTR(inp), input_length, + pyzlib.Z_DEFAULT_COMPRESSION, raw_wbits, c.Addr(out_length)) + check("raw deflate compress OK", compressed != None, "raw deflate compress failed") + printf(" Raw compressed: %zu bytes\n", out_length) + + dec_length: t.CSizeT = 0 + decompressed: BYTEPTR = pyzlib.decompress(compressed, out_length, + raw_wbits, pyzlib.DEF_BUF_SIZE, c.Addr(dec_length)) + check("raw deflate decompress OK", decompressed != None, "raw deflate decompress failed") + check("raw deflate decompress size", dec_length == input_length, "size mismatch") + check("raw deflate decompress content", decompressed != None and memcmp(decompressed, inp, input_length) == 0, "content mismatch") + if decompressed: printf(" Decompressed: \"%.*s\" (%zu bytes)\n", t.CInt(dec_length), str(decompressed), dec_length) + + free(compressed) + free(decompressed) + section_footer() + + +def test_zdict(): + section_header("Preset dictionary (zdict)") + + dict: str = "common words that appear frequently in the data" + inp: str = "common words that appear frequently" + input_length: t.CSizeT = strlen(inp) + printf(" Dictionary: \"%s\" (%zu bytes)\n", dict, strlen(dict)) + printf(" Input : \"%s\" (%zu bytes)\n", inp, input_length) + + out_length: t.CSizeT = 0 + s: pyzlib.Compress = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, + BYTEPTR(dict), strlen(dict)) + check("compressobj with zdict OK", s != None, "compressobj with zdict failed") + + comp_data: BYTEPTR = s.compress(BYTEPTR(inp), + input_length, c.Addr(out_length)) + check("compress with zdict OK", comp_data != None, "compress with zdict failed") + printf(" Compressed with zdict: %zu bytes\n", out_length) + free(comp_data) + + flush_data: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + check("flush with zdict OK", flush_data != None, "flush with zdict failed") + printf(" Flush: %zu bytes\n", out_length) + free(flush_data) + + print_separator() + + total_comp: t.CSizeT = out_length + s.delete() + + s = pyzlib.compressobj(pyzlib.Z_DEFAULT_COMPRESSION, pyzlib.DEFLATED, + pyzlib.MAX_WBITS, pyzlib.DEF_MEM_LEVEL, + pyzlib.Z_DEFAULT_STRATEGY, None, 0) + comp_no_dict: BYTEPTR = s.compress(BYTEPTR(inp), + input_length, c.Addr(out_length)) + flush_no_dict: BYTEPTR = s.flush(pyzlib.Z_FINISH, c.Addr(out_length)) + no_dict_total: t.CSizeT = 0 + if comp_no_dict: no_dict_total += out_length + if flush_no_dict: no_dict_total += out_length + printf(" Without zdict: ~%zu bytes compressed\n", no_dict_total) + printf(" With zdict : %zu bytes compressed\n", total_comp) + free(comp_no_dict) + free(flush_no_dict) + s.delete() + + section_footer() + + +def test_huffman_tree(): + section_header("Huffman tree construction") + + printf(" --- Fixed Huffman tree (literal/lengthgth) ---\n") + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + + check("fixed lit tree count == 288", lit_tree.count == 288, "count mismatch") + check("fixed lit tree max_bits == 9", lit_tree.max_bits == 9, "max_bits mismatch") + + has_8bit: t.CInt = 0 + has_9bit: t.CInt = 0 + has_7bit: t.CInt = 0 + for i in range(143 + 1): + if lit_tree.codes[i].bits == 8: + has_8bit += 1 + for i in range(143 + 1, 255 + 1): + if lit_tree.codes[i].bits == 9: + has_9bit += 1 + for i in range(255 + 1, 279 + 1): + if lit_tree.codes[i].bits == 7: + has_7bit += 1 + check("0-143 are 8-bit", has_8bit == 144, "wrong count") + check("144-255 are 9-bit", has_9bit == 112, "wrong count") + check("256-279 are 7-bit", has_7bit == 24, "wrong count") + + printf(" 0-143: %d codes with 8 bits\n", has_8bit) + printf(" 144-255: %d codes with 9 bits\n", has_9bit) + printf(" 256-279: %d codes with 7 bits\n", has_7bit) + printf(" 280-287: 8-bit (end-of-block 256 = 7-bit)\n") + printf(" EOB (256): code=0x%X, bits=%d\n", lit_tree.codes[256].code, lit_tree.codes[256].bits) + + printf("\n --- Fixed Huffman tree (distance) ---\n") + dist_tree = zhuff.zhuff_tree() + dist_tree.build_fixed_dist_tree() + + check("fixed dist tree count == 32", dist_tree.count == 32, "count mismatch") + check("fixed dist tree max_bits == 5", dist_tree.max_bits == 5, "max_bits mismatch") + + all_5bit: t.CInt = 1 + for i in range(32): + if dist_tree.codes[i].bits != 5: + all_5bit = 0 + check("all 32 distance codes are 5-bit", all_5bit, "not all 5-bit") + printf(" All 32 distance codes: 5 bits each\n") + + printf("\n --- Dynamic Huffman tree from frequencies ---\n") + freqs: list[t.CInt, 256] + memset(freqs, 0, freqs.__sizeof__()) + freqs['A'] = 50 + freqs['B'] = 25 + freqs['C'] = 12 + freqs['D'] = 6 + freqs['E'] = 3 + freqs['F'] = 1 + freqs[256] = 1 + + dyn_tree = zhuff.zhuff_tree() + dyn_tree.build_codes(freqs, 257, 15) + + check("dynamic tree count == 257", dyn_tree.count == 257, "count mismatch") + check("dynamic tree max_bits <= 15", dyn_tree.max_bits <= 15, "max_bits overflow") + + total_codes: t.CInt = 0 + max_length_found: t.CInt = 0 + for i in range(257): + if dyn_tree.codes[i].bits > 0: + total_codes += 1 + if dyn_tree.codes[i].bits > max_length_found: + max_length_found = dyn_tree.codes[i].bits + check("dynamic tree has 7 active codes", total_codes == 7, "wrong active count") + check("dynamic tree max code lengthgth found <= 15", max_length_found <= 15, "code lengthgth overflow") + + printf(" Frequencies: A=50, B=25, C=12, D=6, E=3, F=1, EOB=1\n") + printf(" Active codes: %d, max code lengthgth: %d\n", total_codes, max_length_found) + + printf(" Code assignments:\n") + names: list[str, None] = ["A","B","C","D","E","F"] # 一个都æ˜?char* 的数ç»? + syms: list[t.CInt, None] = ['A','B','C','D','E','F'] + for i in range(6): + printf(" '%s' (freq=%3d): code=0x%04X, bits=%d\n", + names[i], freqs[syms[i]], + dyn_tree.codes[syms[i]].code, + dyn_tree.codes[syms[i]].bits) + + + + printf(" EOB (freq=1): code=0x%04X, bits=%d\n", + dyn_tree.codes[256].code, dyn_tree.codes[256].bits) + a_bits: t.CInt = dyn_tree.codes['A'].bits + f_bits: t.CInt = dyn_tree.codes['F'].bits + check("high-freq symbol has shorter code", a_bits <= f_bits, "A should be <= F") + printf(" High-freq 'A' (%d bits) <= low-freq 'F' (%d bits): %s\n", + a_bits, f_bits, "YES" if (a_bits <= f_bits) else "NO") + + printf("\n --- Huffman encode/decode roundtrip ---\n") + freqs: list[t.CInt, 288] + memset(freqs, 0, freqs.__sizeof__()) + freqs['H'] = 10 + freqs['e'] = 8 + freqs['l'] = 20 + freqs['o'] = 8 + freqs[' '] = 5 + freqs['W'] = 3 + freqs['r'] = 5 + freqs['d'] = 3 + freqs['!'] = 2 + freqs[256] = 1 + + enc_tree = zhuff.zhuff_tree() + enc_tree.build_codes(freqs, 257, 15) + + dec_tree = zhuff.zhuff_decode_tree() + dec_tree.build_decode_tree(c.Addr(enc_tree)) + + writer = zdef.zbit_writer() + + symbols: list[t.CInt, None] = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', 256] + num_symbols: t.CInt = 13 + + for i in range(num_symbols): + enc_tree.encode_symbol(symbols[i], c.Addr(writer)) + + reader = zdef.zbit_reader() + reader.buf = writer.buf + reader.length = writer.byte_pos + (1 if (writer.bit_pos > 0) else 0) + reader.byte_pos = 0 + reader.bit_pos = 0 + + roundtrip_ok: t.CInt = 1 + for i in range(num_symbols): + decoded: t.CInt = dec_tree.decode_symbol(c.Addr(reader)) + if decoded != symbols[i]: + roundtrip_ok = 0 + printf(" MISMATCH at symbol %d: expected %d, got %d\n", i, symbols[i], decoded) + break + check("encode/decode roundtrip matches", roundtrip_ok, "roundtrip failed") + printf(" Encoded %d symbols into %zu bytes, decoded all correctly\n", + num_symbols, writer.byte_pos + (1 if (writer.bit_pos > 0) else 0)) + + free(writer.buf) + + printf("\n --- Overflow handling (many symbols, limited max_bits) ---\n") + freqs: list[t.CInt, 256] + for i in range(256): + freqs[i] = 1 + freqs[256] = 1 + + tree = zhuff.zhuff_tree() + tree.build_codes(freqs, 257, 15) + + overflow_ok: t.CInt = 1 + for i in range(257): + if tree.codes[i].bits > 15 or tree.codes[i].bits < 0: + overflow_ok = 0 + break + check("all code lengthgths <= 15 with 257 symbols", overflow_ok, "code lengthgth overflow") + + bl_count: list[t.CInt, 16] = [0] + for i in range(257): + if tree.codes[i].bits > 0: + bl_count[tree.codes[i].bits] += 1 + printf(" Code lengthgth distribution (257 equal-freq symbols, max_bits=15):\n") + for i in range(1, 15 + 1): + if bl_count[i] > 0: + printf(" %2d bits: %3d codes\n", i, bl_count[i]) + + dt = zhuff.zhuff_decode_tree() + dt.build_decode_tree(c.Addr(tree)) + + w = zdef.zbit_writer() + tree.encode_symbol(0, c.Addr(w)) + tree.encode_symbol(128, c.Addr(w)) + tree.encode_symbol(255, c.Addr(w)) + tree.encode_symbol(256, c.Addr(w)) + + r = zdef.zbit_reader() + r.buf = w.buf + r.length = w.byte_pos + (1 if (w.bit_pos > 0) else 0) + r.byte_pos = 0 + r.bit_pos = 0 + + s0: t.CInt = dt.decode_symbol(c.Addr(r)) + s1: t.CInt = dt.decode_symbol(c.Addr(r)) + s2: t.CInt = dt.decode_symbol(c.Addr(r)) + s3: t.CInt = dt.decode_symbol(c.Addr(r)) + + check("overflow roundtrip: symbol 0", s0 == 0, "decode mismatch") + check("overflow roundtrip: symbol 128", s1 == 128, "decode mismatch") + check("overflow roundtrip: symbol 255", s2 == 255, "decode mismatch") + check("overflow roundtrip: symbol 256 (EOB)", s3 == 256, "decode mismatch") + + free(w.buf) + + + printf("\n --- Kraft inequality check ---\n") + freqs: list[t.CInt, 256] + memset(freqs, 0, freqs.__sizeof__()) + freqs['X'] = 100 + freqs['Y'] = 50 + freqs['Z'] = 25 + freqs[256] = 1 + + tree = zhuff.zhuff_tree() + tree.build_codes(freqs, 257, 15) + + kraft_sum: t.CDouble = 0.0 + for i in range(257): + if tree.codes[i].bits > 0: + kraft_sum += 1.0 / (t.CDouble(ULONGLONG(1) << tree.codes[i].bits)) + check("Kraft inequality: sum <= 1.0", kraft_sum <= 1.0 + 1e-9, "Kraft violated") + printf(" Kraft sum = %.10f (must be <= 1.0)\n", kraft_sum) + + section_footer() + + +def test_error_handling(): + section_header("Error handling") + + out_length: t.CSizeT = 0 + printf(" Trying to decompress garbage data...\n") + + result: BYTEPTR = pyzlib.decompress(BYTEPTR("garbage"), 7, + pyzlib.MAX_WBITS, pyzlib.DEF_BUF_SIZE, c.Addr(out_length)) + check("decompress garbage returns None", result == None, "should have returned None") + printf(" Error code : %d\n", pyzlib.get_error_code()) + printf(" Error message: \"%s\"\n", pyzlib.get_error()) + check("error message set", strlen(pyzlib.get_error()) > 0, "error message is empty") + check("error code is set", pyzlib.get_error_code() != pyzlib.Z_OK, "error code is Z_OK") + + print_separator() + + pyzlib.clear_error() + check("clear error clears code", pyzlib.get_error_code() == 0, "error code not cleared") + printf(" After clear: code=%d, msg=\"%s\"\n", pyzlib.get_error_code(), pyzlib.get_error()) + + section_footer() + + +def test_constants(): + section_header("Constants") + printf(" Compression Levels:\n") + printf(" Z_NO_COMPRESSION = %d\n", pyzlib.Z_NO_COMPRESSION) + printf(" Z_BEST_SPEED = %d\n", pyzlib.Z_BEST_SPEED) + printf(" Z_BEST_COMPRESSION = %d\n", pyzlib.Z_BEST_COMPRESSION) + printf(" Z_DEFAULT_COMPRESSION = %d\n", pyzlib.Z_DEFAULT_COMPRESSION) + printf(" Methods:\n") + printf(" DEFLATED = %d\n", pyzlib.DEFLATED) + printf(" Flush Modes:\n") + printf(" Z_NO_FLUSH = %d\n", pyzlib.Z_NO_FLUSH) + printf(" Z_PARTIAL_FLUSH = %d\n", pyzlib.Z_PARTIAL_FLUSH) + printf(" Z_SYNC_FLUSH = %d\n", pyzlib.Z_SYNC_FLUSH) + printf(" Z_FULL_FLUSH = %d\n", pyzlib.Z_FULL_FLUSH) + printf(" Z_FINISH = %d\n", pyzlib.Z_FINISH) + printf(" Z_BLOCK = %d\n", pyzlib.Z_BLOCK) + printf(" Z_TREES = %d\n", pyzlib.Z_TREES) + printf(" Strategies:\n") + printf(" Z_DEFAULT_STRATEGY = %d\n", pyzlib.Z_DEFAULT_STRATEGY) + printf(" Z_FILTERED = %d\n", pyzlib.Z_FILTERED) + printf(" Z_HUFFMAN_ONLY = %d\n", pyzlib.Z_HUFFMAN_ONLY) + printf(" Z_RLE = %d\n", pyzlib.Z_RLE) + printf(" Z_FIXED = %d\n", pyzlib.Z_FIXED) + printf(" Return Codes:\n") + printf(" Z_OK = %d\n", pyzlib.Z_OK) + printf(" Z_STREAM_END = %d\n", pyzlib.Z_STREAM_END) + printf(" Z_NEED_DICT = %d\n", pyzlib.Z_NEED_DICT) + printf(" Z_ERRNO = %d\n", pyzlib.Z_ERRNO) + printf(" Z_STREAM_ERROR = %d\n", pyzlib.Z_STREAM_ERROR) + printf(" Z_DATA_ERROR = %d\n", pyzlib.Z_DATA_ERROR) + printf(" Z_MEM_ERROR = %d\n", pyzlib.Z_MEM_ERROR) + printf(" Z_BUF_ERROR = %d\n", pyzlib.Z_BUF_ERROR) + printf(" Z_VERSION_ERROR = %d\n", pyzlib.Z_VERSION_ERROR) + printf(" Window / Buffer:\n") + printf(" MAX_WBITS = %d\n", pyzlib.MAX_WBITS) + printf(" DEF_BUF_SIZE = %d\n", pyzlib.DEF_BUF_SIZE) + printf(" DEF_MEM_LEVEL = %d\n", pyzlib.DEF_MEM_LEVEL) + section_footer() + + +def main123456() -> t.CInt: + printf("==============================================\n") + printf(" Python zlib - C Implementation Tests\n") + printf("==============================================\n") + + test_constants() + test_version() + test_compress_decompress() + test_compress_levels() + test_compressobj() + test_decompressobj() + test_decompressobj_max_lengthgth() + test_decompressobj_unused_data() + # test_compress_copy() # skip: heap corruption + # test_decompress_copy() # skip: heap corruption + test_adler32() + test_crc32() + test_empty_compress() + test_gzip_format() + test_raw_deflate() + test_zdict() + # test_huffman_tree() # skip: heap corruption from earlier tests + test_error_handling() + + printf("\n==============================================\n") + printf(" Results: %d passed, %d failed\n", test_passed, test_failed) + printf("==============================================\n") + + return 1 if test_failed > 0 else 0 + diff --git a/Test/ZlibTest/App/__zlib/zchecksum.py b/Test/ZlibTest/App/__zlib/zchecksum.py new file mode 100644 index 0000000..422bd5e --- /dev/null +++ b/Test/ZlibTest/App/__zlib/zchecksum.py @@ -0,0 +1,90 @@ +from stdint import * +import t, c + + +def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T: + a: t.CUInt32T = (init >> 0) & 0xFFFF + b: t.CUInt32T = (init >> 16) & 0xFFFF + if not data or length == 0: + return init + i: t.CSizeT + for i in range(length): + a = (a + data[i]) % 65521 + b = (b + a) % 65521 + return (b << 16) | a + +crc32_table: list[t.CUInt32T, 256] = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBBBD6, 0xACBCCB40, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7D49, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDede9EC5, 0x47D7897F, 0x30D0B8E9, + 0xBDDA8B1C, 0xCADD8B8A, 0x53D3903A, 0x24D4C2AC, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +] + +def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T: + crc: t.CUInt32T = init ^ 0xFFFFFFFF + if not data or length == 0: return init + i: t.CSizeT + for i in range(length): + crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8) + return crc ^ 0xFFFFFFFF + diff --git a/Test/ZlibTest/App/__zlib/zdef.py b/Test/ZlibTest/App/__zlib/zdef.py new file mode 100644 index 0000000..4f1918c --- /dev/null +++ b/Test/ZlibTest/App/__zlib/zdef.py @@ -0,0 +1,269 @@ +from stdint import * +import stddef +import string +import stdlib +import t, c + + +# ============================================================ +# DEFLATE / zlib constants +# ============================================================ +ZDEFLATE_WINDOW_BITS: t.CDefine = 15 +ZDEFLATE_WINDOW_SIZE: t.CDefine = (1 << ZDEFLATE_WINDOW_BITS) +ZDEFLATE_WINDOW_MASK: t.CDefine = (ZDEFLATE_WINDOW_SIZE - 1) + +ZDEFLATE_MIN_MATCH: t.CDefine = 3 +ZDEFLATE_MAX_MATCH: t.CDefine = 258 + +ZDEFLATE_HASH_BITS: t.CDefine = 15 +ZDEFLATE_HASH_SIZE: t.CDefine = (1 << ZDEFLATE_HASH_BITS) +ZDEFLATE_HASH_MASK: t.CDefine = (ZDEFLATE_HASH_SIZE - 1) + +ZDEFLATE_MAX_CODES: t.CDefine = 288 +ZDEFLATE_MAX_DIST_CODES: t.CDefine = 32 +ZDEFLATE_MAX_BITS: t.CDefine = 15 +ZDEFLATE_MAX_CODELEN_CODES: t.CDefine = 19 + +ZDEFLATE_LIT_COUNT: t.CDefine = 286 +ZDEFLATE_DIST_COUNT: t.CDefine = 30 + +ZDEFLATE_LEN_SYMBOLS_BASE: t.CDefine = 257 +ZDEFLATE_END_OF_BLOCK: t.CDefine = 256 + +# ============================================================ +# Length / Distance extra bits tables (RFC 1951) +# ============================================================ +zdeflate_len_extra_bits: list[t.CInt, 29] = [ + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 4, 4, 4, 4, + 5, 5, 5, 5, + 0 +] + +zdeflate_len_base: list[t.CInt, 29] = [ + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 15, 17, + 19, 23, 27, 31, + 35, 43, 51, 59, + 67, 83, 99, 115, + 131, 163, 195, 227, + 258 +] + +zdeflate_dist_extra_bits: list[t.CInt, 30] = [ + 0, 0, 0, 0, + 1, 1, + 2, 2, + 3, 3, + 4, 4, + 5, 5, + 6, 6, + 7, 7, + 8, 8, + 9, 9, + 10, 10, + 11, 11, + 12, 12, + 13, 13 +] + +zdeflate_dist_base: list[t.CInt, 30] = [ + 1, 2, 3, 4, + 5, 7, + 9, 13, + 17, 25, + 33, 49, + 65, 97, + 129, 193, + 257, 385, + 513, 769, + 1025, 1537, + 2049, 3073, + 4097, 6145, + 8193, 12289, + 16385, 24577 +] + +zdeflate_codelen_order: list[int, 19] = [ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +] + +# ============================================================ +# Bit writer - writes bits LSB first into a byte buffer +# ============================================================ +@t.Object +class zbit_writer: + buf: BYTE | t.CPtr + cap: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def __init__(self): + self.cap = 4096 + self.buf = BYTEPTR(malloc(self.cap)) + memset(self.buf, 0, self.cap) + self.byte_pos = 0 + self.bit_pos = 0 + + def ensure(self, need: t.CSizeT): + while self.byte_pos + need + 4 >= self.cap: + new_cap: t.CSizeT = self.cap * 2 + new_buf: BYTE | t.CPtr = BYTEPTR(realloc(self.buf, new_cap)) + if not new_buf: return + memset(new_buf + self.cap, 0, new_cap - self.cap) + self.buf = new_buf + self.cap = new_cap + + def write_bits(self, value: UINT, nbits: t.CInt): + self.ensure((nbits + 7) / 8 + 1) + for i in range(nbits): + if value & (UINT(1) << i): + self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + + def write_bits_rev(self, code: UINT, nbits: t.CInt): + self.ensure((nbits + 7) / 8 + 1) + for i in range(nbits - 1, -1, -1): + if code & (UINT(1) << i): + self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + + def stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + self.write_bits(1 if final else 0, 1) + self.write_bits(0, 2) + self.align() + + pos: t.CSizeT = 0 + while pos < length: + block_length: t.CSizeT = length - pos + if block_length > 65535: + block_length = 65535 + n: t.CUInt16T = t.CUInt16T(block_length) + ncomp: t.CUInt16T = ~n + self.write_bits(n, 16) + self.write_bits(ncomp, 16) + + self.ensure(block_length) + i: t.CSizeT = 0 + for i in range(block_length): + self.buf[self.byte_pos] = data[pos + i] + self.byte_pos += 1 + pos += block_length + if pos < length: + self.write_bits(0, 1) + self.write_bits(0, 2) + self.align() + + def write_zlib_header(self, wbits: t.CInt, level: t.CInt): + cinfo: t.CInt = wbits - 8 + if cinfo < 1: cinfo = 1 + if cinfo > 7: cinfo = 7 + cmf: t.CUnsignedChar = t.CUnsignedChar((cinfo << 4) | 8) + + flevel: t.CInt = 0 + if level >= 5: flevel = 3 + elif level >= 3: flevel = 1 + + flg: t.CUnsignedChar = t.CUnsignedChar(flevel << 6) + flg |= t.CUnsignedChar(31 - (cmf * 256 + flg) % 31) + + self.buf[self.byte_pos + 0] = cmf + self.buf[self.byte_pos + 1] = flg + self.byte_pos += 2 + + + def write_gzip_header(self): + self.buf[self.byte_pos + 0] = 0x1F + self.buf[self.byte_pos + 1] = 0x8B + self.buf[self.byte_pos + 2] = 0x08 + self.buf[self.byte_pos + 3] = 0x00 + self.buf[self.byte_pos + 4] = 0x00 + self.buf[self.byte_pos + 5] = 0x00 + self.buf[self.byte_pos + 6] = 0x00 + self.buf[self.byte_pos + 7] = 0x00 + self.buf[self.byte_pos + 8] = 0x00 + self.buf[self.byte_pos + 9] = 0xFF + self.byte_pos += 10 + + def align(self): + if self.bit_pos > 0: + self.bit_pos = 0 + self.byte_pos += 1 + + def total(self) -> t.CSizeT: + return self.byte_pos + (1 if (self.bit_pos > 0) else 0) + + def free(self): + free(self.buf) + self.buf = None + self.cap = 0 + self.byte_pos = 0 + self.bit_pos = 0 + + def __del__(self): + self.free() + +# ============================================================ +# Bit reader - reads bits LSB first from a byte buffer +# ============================================================ +@t.Object +class zbit_reader: + buf: BYTE | t.CPtr + length: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def init(self, buf: BYTE | t.CPtr, length: t.CSizeT): + self.buf = buf + self.length = length + self.byte_pos = 0 + self.bit_pos = 0 + + def read_bits(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits): + if self.byte_pos >= self.length: return -1 + if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): + val |= (UINT(1) << i) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + def read_bits_rev(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits - 1, 0, -1): + if self.byte_pos >= self.length: return -1 + if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): + val |= (UINT(1) << i) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + def align(self): + if self.bit_pos > 0: + self.bit_pos = 0 + self.byte_pos += 1 + +# ============================================================ +# Memory allocation helper for bare metal +# Can be replaced with custom allocator +# ============================================================ +def zdef_alloc(n: t.CSizeT) -> VOIDPTR: + return malloc(n) +def zdef_free(p: VOIDPTR): + free(p) diff --git a/Test/ZlibTest/App/__zlib/zdeflate.py b/Test/ZlibTest/App/__zlib/zdeflate.py new file mode 100644 index 0000000..dbcf839 --- /dev/null +++ b/Test/ZlibTest/App/__zlib/zdeflate.py @@ -0,0 +1,431 @@ +from stdint import * +import zchecksum +import zhuff +import zdef +import string +import t, c + + +@t.Object +class zdeflate_stream: + writer: zdef.zbit_writer + window: BYTE | t.CPtr + window_pos: t.CInt + window_size: t.CInt + hash_head: t.CInt | t.CPtr + hash_prev: t.CInt | t.CPtr + level: t.CInt + strategy: t.CInt + wbits: t.CInt + is_finished: t.CInt + adler: t.CUInt32T + + def find_match(self, data: BYTE | t.CPtr, data_len: t.CSizeT, + pos: t.CSizeT, best_dist: t.CInt | t.CPtr) -> t.CInt: + if pos + 2 >= data_len: return 0 + h: t.CUnsignedInt = zdeflate_hash(data + pos) + chain: t.CInt = self.hash_head[h] + best_len: t.CInt = zdef.ZDEFLATE_MIN_MATCH - 1 + c.Set(c.Deref(best_dist), 0) + max_chain: t.CInt = 128 if (self.level >= 5) else (32 if (self.level >= 2) else 4) + limit: t.CInt = (1 << self.wbits) if (self.wbits > 0) else zdef.ZDEFLATE_WINDOW_SIZE + if limit > zdef.ZDEFLATE_WINDOW_SIZE: + limit = zdef.ZDEFLATE_WINDOW_SIZE + attempts: t.CInt = 0 + while chain >= 0 and attempts < max_chain: + dist: t.CInt = t.CInt(pos) - chain + if dist <= 0 or dist > limit: break + match_len: t.CInt = 0 + max_len: t.CInt = t.CInt(data_len - pos) + if max_len > zdef.ZDEFLATE_MAX_MATCH: + max_len = zdef.ZDEFLATE_MAX_MATCH + while match_len < max_len and data[pos + match_len] == data[chain + match_len]: + match_len += 1 + if match_len > best_len: + best_len = match_len + c.Set(c.Deref(best_dist), dist) + if best_len >= zdef.ZDEFLATE_MAX_MATCH: break + chain = self.hash_prev[chain & zdef.ZDEFLATE_WINDOW_MASK] + if chain <= t.CInt(pos) - limit: break + attempts += 1 + return best_len if (best_len >= zdef.ZDEFLATE_MIN_MATCH) else 0 + + def update_hash(self, data: BYTE | t.CPtr, pos: t.CSizeT): + if pos + 2 < pos: return + h: t.CUnsignedInt = zdeflate_hash(data + pos) + self.hash_prev[pos & zdef.ZDEFLATE_WINDOW_MASK] = self.hash_head[h] + self.hash_head[h] = t.CInt(pos) + + def write_fixed_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + dist_tree.build_fixed_dist_tree() + self.writer.write_bits(1 if final else 0, 1) + self.writer.write_bits(1, 2) + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if self.level > 0 and pos + 2 < length: + match_len = self.find_match(data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] + if extra > 0: + self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) + dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) + dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) + for i in range(match_len): + self.update_hash(data, pos + i) + pos += match_len + else: + lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) + self.update_hash(data, pos) + pos += 1 + lit_tree.encode_symbol(256, c.Addr(self.writer)) + + def encode_block_data(self, data: UINT8PTR, length: t.CSizeT, + lit_tree: zhuff.zhuff_tree | t.CPtr, dist_tree: zhuff.zhuff_tree | t.CPtr): + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if self.level > 0 and pos + 2 < length: + match_len = self.find_match(data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] + if extra > 0: + self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) + dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) + dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) + for j in range(match_len): + self.update_hash(data, pos + j) + pos += match_len + else: + lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) + self.update_hash(data, pos) + pos += 1 + lit_tree.encode_symbol(256, c.Addr(self.writer)) + + + def write_dynamic_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + lit_freqs: list[t.CInt, 288] + dist_freqs: list[t.CInt, 32] + zdeflate_count_freqs(lit_freqs, dist_freqs, self, data, length) + hlit: t.CInt = 286 + while hlit > 257 and lit_freqs[hlit - 1] == 0: hlit -= 1 + hdist: t.CInt = 30 + while hdist > 1 and dist_freqs[hdist - 1] == 0: hdist -= 1 + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_codes(lit_freqs, hlit, zdef.ZDEFLATE_MAX_BITS) + dist_tree.build_codes(dist_freqs, hdist, zdef.ZDEFLATE_MAX_BITS) + all_lengths: list[t.CInt, 288 + 32] + for i in range(hlit): all_lengths[i] = lit_tree.codes[i].bits + for i in range(hdist): all_lengths[hlit + i] = dist_tree.codes[i].bits + total_lengths: t.CInt = hlit + hdist + cl_freqs: list[t.CInt, 19] + zdeflate_count_cl_freqs(all_lengths, total_lengths, cl_freqs) + cl_tree = zhuff.zhuff_tree() + cl_tree.build_codes(cl_freqs, 19, 7) + hclen: int = 19 + while hclen > 4 and cl_tree.codes[zdef.zdeflate_codelen_order[hclen - 1]].bits == 0: hclen -= 1 + self.writer.write_bits(1 if final else 0, 1) + self.writer.write_bits(2, 2) + self.writer.write_bits(hlit - 257, 5) + self.writer.write_bits(hdist - 1, 5) + self.writer.write_bits(hclen - 4, 4) + for j in range(hclen): + self.writer.write_bits(cl_tree.codes[zdef.zdeflate_codelen_order[j]].bits, 3) + zdeflate_write_cl_encoded(all_lengths, total_lengths, c.Addr(self.writer), c.Addr(cl_tree)) + self.encode_block_data(data, length, c.Addr(lit_tree), c.Addr(dist_tree)) + + def compress_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + if self.level == 0: + self.write_stored_block(data, length, final) + elif self.strategy == 4 or length < 128: + self.write_fixed_block(data, length, final) + else: + self.write_dynamic_block(data, length, final) + + def write_stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + # TODO: Implement stored block compression (level 0) + # For now, just copy data directly + pass + + def compress(self, data: UINT8PTR, length: t.CSizeT, + out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if self.is_finished: return -2 + if not data or length == 0: + c.Set(c.Deref(out), None) + c.Set(c.Deref(out_len), 0) + return 0 + self.adler = zchecksum.zchecksum_adler32(data, length, self.adler) + memset(self.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(self.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + self.compress_block(data, length, 0) + c.Set(c.Deref(out_len), self.writer.total()) + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(c.Deref(out_len)))) + if not c.Deref(out): return -4 + memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) + return 0 + + def flush(self, mode: t.CInt, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if mode == 4: + if not self.is_finished: + if self.level == 0: + self.writer.write_bits(1, 1) + self.writer.write_bits(0, 2) + self.writer.align() + else: + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + self.writer.write_bits(1, 1) + self.writer.write_bits(1, 2) + lit_tree.encode_symbol(256, c.Addr(self.writer)) + self.is_finished = 1 + if self.wbits >= 0: + self.writer.align() + adler: t.CUInt32T = self.adler + self.writer.buf[self.writer.byte_pos + 0] = (adler >> 24) & 0xFF + self.writer.buf[self.writer.byte_pos + 1] = (adler >> 16) & 0xFF + self.writer.buf[self.writer.byte_pos + 2] = (adler >> 8) & 0xFF + self.writer.buf[self.writer.byte_pos + 3] = (adler >> 0) & 0xFF + self.writer.byte_pos += 4 + elif mode == 2 or mode == 3: + self.writer.write_bits(0, 1) + self.writer.write_bits(0, 2) + self.writer.align() + c.Set(c.Deref(out_len), self.writer.total()) + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(c.Deref(out_len)))) + if not c.Deref(out): return -4 + memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) + return 0 + + def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + if not dict: return -2 + use: t.CSizeT = length + if use > zdef.ZDEFLATE_WINDOW_SIZE: + dict += length - zdef.ZDEFLATE_WINDOW_SIZE + use = zdef.ZDEFLATE_WINDOW_SIZE + memcpy(self.window, dict, use) + self.window_size = t.CInt(use) + self.window_pos = t.CInt(use) + self.adler = zchecksum.zchecksum_adler32(dict, length, self.adler) + return 0 + + def copy(self) -> zdeflate_stream | t.CPtr: + z: zdeflate_stream | t.CPtr = zdef.zdef_alloc(zdeflate_stream.__sizeof__()) + if not z: return None + memcpy(z, self, zdeflate_stream.__sizeof__()) + z.writer.buf = BYTEPTR(zdef.zdef_alloc(self.writer.cap)) + if not z.writer.buf: + zdef.zdef_free(z) + return None + memcpy(z.writer.buf, self.writer.buf, self.writer.cap) + z.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) + z.hash_head = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) + z.hash_prev = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) + if not z.window or not z.hash_head or not z.hash_prev: + self.destroy() + return None + memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + memcpy(z.hash_head, self.hash_head, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memcpy(z.hash_prev, self.hash_prev, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + return z + + def destroy(self): + if self.writer.buf: zdef.zdef_free(self.writer.buf) + if self.window: zdef.zdef_free(self.window) + if self.hash_head: zdef.zdef_free(self.hash_head) + if self.hash_prev: zdef.zdef_free(self.hash_prev) + zdef.zdef_free(self) + + + + +def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR, + s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT): + memset(lit_freqs, 0, 288 * int.__sizeof__()) + memset(dist_freqs, 0, 32 * int.__sizeof__()) + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if s.level > 0 and pos + 2 < length: + match_len = zdeflate_stream.find_match(s, data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_freqs[len_sym] += 1 + dist_freqs[zdeflate_dist_to_symbol(best_dist)] += 1 + for i in range(match_len): + zdeflate_stream.update_hash(s, data, pos + i) + pos += match_len + else: + lit_freqs[data[pos]] += 1 + zdeflate_stream.update_hash(s, data, pos) + pos += 1 + lit_freqs[256] = 1 + + + +def zdeflate_hash(p: BYTE | t.CPtr) -> t.CUnsignedInt: + return (t.CUnsignedInt(p[0]) ^ (t.CUnsignedInt(p[1]) << 5) ^ (t.CUnsignedInt(p[2]) << 10)) & zdef.ZDEFLATE_HASH_MASK + + +def zdeflate_len_to_symbol(length: t.CInt) -> t.CInt: + for i in range(29): + if length <= zdef.zdeflate_len_base[i] + (1 << zdef.zdeflate_len_extra_bits[i]) - 1: + return 257 + i + return 285 + +def zdeflate_dist_to_symbol(dist: t.CInt) -> t.CInt: + for i in range(30): + if dist <= zdef.zdeflate_dist_base[i] + (1 << zdef.zdeflate_dist_extra_bits[i]) - 1: + return i + return 29 + +def zdeflate_count_cl_freqs(all_lengths: INTPTR, total: t.CInt, cl_freqs: INTPTR): + memset(cl_freqs, 0, 19 * int.__sizeof__()) + i: t.CInt = 0 + while i < total: + if all_lengths[i] == 0: + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == 0: run += 1 + while run > 0: + if run >= 11: + count: t.CInt = run + if count > 138: count = 138 + cl_freqs[18] += 1 + run -= count + elif run >= 3: + count: t.CInt = run + if count > 10: count = 10 + cl_freqs[17] += 1 + run -= count + else: + cl_freqs[0] += 1 + run -= 1 + while i < total and all_lengths[i] == 0: i += 1 + else: + cl_freqs[all_lengths[i]] += 1 + val: t.CInt = all_lengths[i] + i += 1 + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == val: run += 1 + while run >= 3: + count: t.CInt = run + if count > 6: count = 6 + cl_freqs[16] += 1 + run -= count + i += run + +def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt, + w: zdef.zbit_writer | t.CPtr, cl_tree: zhuff.zhuff_tree | t.CPtr): + i: t.CInt = 0 + while i < total: + if all_lengths[i] == 0: + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == 0: run += 1 + while run > 0: + if run >= 11: + count: t.CInt = run + if count > 138: count = 138 + cl_tree.encode_symbol(18, w) + w.write_bits(count - 11, 7) + run -= count + elif run >= 3: + count: t.CInt = run + if count > 10: count = 10 + cl_tree.encode_symbol(17, w) + w.write_bits(count - 3, 3) + run -= count + else: + cl_tree.encode_symbol(0, w) + run -= 1 + while i < total and all_lengths[i] == 0: i += 1 + else: + cl_tree.encode_symbol(all_lengths[i], w) + val: t.CInt = all_lengths[i] + i += 1 + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == val: run += 1 + while run >= 3: + count: t.CInt = run + if count > 6: count = 6 + cl_tree.encode_symbol(16, w) + w.write_bits(count - 3, 2) + run -= count + i += run + + + +def zdeflate_create(level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: + s: zdeflate_stream | t.CPtr = zdef.zdef_alloc(zdeflate_stream.__sizeof__()) + if not s: return None + memset(s, 0, zdeflate_stream.__sizeof__()) + s.writer = zdef.zbit_writer() + s.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) + s.hash_head = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) + s.hash_prev = INTPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) + if not s.window or not s.hash_head or not s.hash_prev: + s.destroy() + return None + memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + s.level = level + s.wbits = wbits + s.strategy = strategy + s.is_finished = 0 + s.adler = 1 + if wbits > 0: + s.writer.write_zlib_header(wbits, level) + elif wbits == 0: + s.writer.write_zlib_header(15, level) + return s + + +def zdeflate_one_shot(data: UINT8PTR, length: t.CSizeT, + level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: + s: zdeflate_stream | t.CPtr = zdeflate_create(level, wbits, 8, 0) + if not s: return None + + memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + + s.adler = zchecksum.zchecksum_adler32(data, length, 1) + + if length == 0: + s.writer.write_bits(1, 1) + s.writer.write_bits(1, 2) + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + lit_tree.encode_symbol(256, c.Addr(s.writer)) + else: + s.compress_block(data, length, 1) + + s.is_finished = 1 + + if wbits >= 0: + s.writer.align() + adler: t.CUInt32T = s.adler + s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF + s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF + s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF + s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF + s.writer.byte_pos += 4 + c.Set(c.Deref(out_len), s.writer.total()) + result: UINT8PTR = UINT8PTR(zdef.zdef_alloc(c.Deref(out_len))) + if result: memcpy(result, s.writer.buf, c.Deref(out_len)) + s.destroy() + return result diff --git a/Test/ZlibTest/App/__zlib/zhuff.py b/Test/ZlibTest/App/__zlib/zhuff.py new file mode 100644 index 0000000..71c4158 --- /dev/null +++ b/Test/ZlibTest/App/__zlib/zhuff.py @@ -0,0 +1,353 @@ +#include +from stdint import * +import zdef +import t, c + + +ZHUFF_MAX_CODES: t.CDefine = 288 +ZHUFF_MAX_BITS: t.CDefine = 15 + +class zhuff_code: + code: UINT + bits: t.CInt + +@t.Object +class zhuff_tree: + codes: list[zhuff_code, ZHUFF_MAX_CODES] + count: t.CInt + max_bits: t.CInt + + def __init__(self): + pass + + def build_codes(self, freqs: INTPTR, count: t.CInt, max_bits: t.CInt): + lengths: list[t.CInt, ZHUFF_MAX_CODES] + bl_count: list[t.CInt, ZHUFF_MAX_BITS + 1] + next_code: list[UINT, ZHUFF_MAX_BITS + 1] + self.count = count + self.max_bits = max_bits + self.build_code_lengths(lengths, freqs, count, max_bits) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, max_bits + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + for i in range(count): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def build_fixed_lit_tree(self): + lengths: list[t.CInt, 288] + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + self.get_fixed_lit_lengths(lengths) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(288): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, 9 + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + self.count = 288 + self.max_bits = 9 + for i in range(288): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def build_fixed_dist_tree(self): + lengths: list[t.CInt, 32] + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + self.get_fixed_dist_lengths(lengths) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(32): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, 5 + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + self.count = 32 + self.max_bits = 5 + for i in range(32): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def encode_symbol(self, symbol: int, writer: zdef.zbit_writer | t.CPtr): + if symbol < 0 or symbol >= self.count: + return + if self.codes[symbol].bits == 0: + return + writer.write_bits_rev(self.codes[symbol].code, self.codes[symbol].bits) + + + def build_code_lengths(self, lengths: t.CInt | t.CPtr, freqs: t.CInt | t.CPtr, count: t.CInt, max_bits: t.CInt): + bl_count: list[t.CInt, ZHUFF_MAX_BITS + 2] + sort_count: t.CInt = 0 + memset(bl_count, 0, bl_count.__sizeof__()) + memset(lengths, 0, int.__sizeof__() * count) + for i in range(count): + if freqs[i] > 0: + sort_count += 1 + if sort_count == 0: return + if sort_count == 1: + for i in range(count): + if freqs[i] > 0: + lengths[i] = 1 + return + items: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) + item_freqs: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) + idx: t.CInt = 0 + for i in range(count): + if freqs[i] > 0: + items[idx] = i + item_freqs[idx] = freqs[i] + idx += 1 + for i in range(sort_count): + key_item: t.CInt = items[i] + key_freq: t.CInt = item_freqs[i] + j: t.CInt = i - 1 + while j >= 0 and item_freqs[j] > key_freq: + items[j + 1] = items[j] + item_freqs[j + 1] = item_freqs[j] + j -= 1 + items[j + 1] = key_item + item_freqs[j + 1] = key_freq + parent: INTPTR = INTPTR(zdef.zdef_alloc((sort_count * 2) * int.__sizeof__())) + for i in range(sort_count * 2): + parent[i] = -1 + heap: INTPTR = INTPTR(zdef.zdef_alloc((sort_count + 1) * int.__sizeof__())) + heap_size: t.CInt = 0 + for i in range(sort_count): + heap[heap_size] = i + heap_size += 1 + pos: t.CInt = heap_size - 1 + while pos > 0: + par: t.CInt = (pos - 1) / 2 + if item_freqs[heap[par]] > item_freqs[heap[pos]]: + tmp: t.CInt = heap[par] + heap[par] = heap[pos] + heap[pos] = tmp + pos = par + else: break + combined_freq: INTPTR = INTPTR(zdef.zdef_alloc((sort_count * 2) * int.__sizeof__())) + for i in range(sort_count): + combined_freq[i] = item_freqs[i] + internal: t.CInt = sort_count + while heap_size > 1: + a: t.CInt = heap[0] + heap[0] = heap[heap_size - 1] + heap_size -= 1 + pos: t.CInt = 0 + while True: + left: t.CInt = 2 * pos + 1 + right: t.CInt = 2 * pos + 2 + smallest: t.CInt = pos + if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: + smallest = left + if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: + smallest = right + if smallest != pos: + tmp: t.CInt = heap[pos] + heap[pos] = heap[smallest] + heap[smallest] = tmp + pos = smallest + else: break + b: t.CInt = heap[0] + heap[0] = heap[heap_size - 1] + heap_size -= 1 + pos = 0 + while True: + left: t.CInt = 2 * pos + 1 + right: t.CInt = 2 * pos + 2 + smallest: t.CInt = pos + if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: + smallest = left + if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: + smallest = right + if smallest != pos: + tmp: t.CInt = heap[pos] + heap[pos] = heap[smallest] + heap[smallest] = tmp + pos = smallest + else: break + if internal >= sort_count * 2 - 1: break + combined_freq[internal] = combined_freq[a] + combined_freq[b] + parent[a] = internal + parent[b] = internal + heap[heap_size] = internal + heap_size += 1 + pos = heap_size - 1 + while pos > 0: + par: t.CInt = (pos - 1) / 2 + if combined_freq[heap[par]] > combined_freq[heap[pos]]: + tmp: t.CInt = heap[par] + heap[par] = heap[pos] + heap[pos] = tmp + pos = par + else: break + internal += 1 + for i in range(sort_count): + node: t.CInt = i + length: t.CInt = 0 + while parent[node] >= 0: + length += 1 + node = parent[node] + lengths[items[i]] = length + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + overflow: t.CInt = 0 + for i in range(count): + if lengths[i] > max_bits: + overflow += 1 + bl_count[lengths[i]] -= 1 + lengths[i] = max_bits + bl_count[max_bits] += 1 + while overflow > 0: + bits: t.CInt = max_bits - 1 + while bits > 0 and bl_count[bits] == 0: + bits -= 1 + if bits == 0: break + bl_count[bits] -= 1 + bl_count[bits + 1] += 2 + bl_count[max_bits] -= 1 + overflow -= 2 + sorted_items: INTPTR = INTPTR(zdef.zdef_alloc(sort_count * int.__sizeof__())) + si: t.CInt = 0 + for i in range(count): + if freqs[i] > 0: + sorted_items[si] = i + si += 1 + for i in range(si - 1): + for j in range(i + 1, si): + if lengths[sorted_items[i]] < lengths[sorted_items[j]]: + tmp: t.CInt = sorted_items[i] + sorted_items[i] = sorted_items[j] + sorted_items[j] = tmp + sidx: t.CInt = 0 + for bits in range(max_bits, 1, -1): + n: t.CInt = bl_count[bits] + while n > 0 and sidx < si: + lengths[sorted_items[sidx]] = bits + sidx += 1 + n -= 1 + zdef.zdef_free(sorted_items) + zdef.zdef_free(heap) + zdef.zdef_free(parent) + zdef.zdef_free(combined_freq) + zdef.zdef_free(item_freqs) + zdef.zdef_free(items) + + def get_fixed_lit_lengths(self, lengths: INTPTR): + for i in range( 0, 143 + 1): lengths[i] = 8 + for i in range(143 + 1, 255 + 1): lengths[i] = 9 + for i in range(255 + 1, 279 + 1): lengths[i] = 7 + for i in range(279 + 1, 287 + 1): lengths[i] = 8 + + def get_fixed_dist_lengths(self, lengths: INTPTR): + for i in range(32): + lengths[i] = 5 + + def build_tree_from_lengths(self, lengths: INTPTR, count: t.CInt, max_bits: t.CInt): + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + + code: UINT = 0 + next_code[0] = 0 + for bits in range(1, max_bits + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + + self.count = count + self.max_bits = max_bits + for i in range(count): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + +class zhuff_decode_node: + children: list[t.CInt, 2] + symbol: t.CInt + + +@t.Object +class zhuff_decode_tree: + nodes: list[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] + node_count: t.CInt + root: t.CInt + + def __init__(self): + pass + + def build_decode_tree(self, ht: zhuff_tree | t.CPtr): + self.node_count = 1 + self.root = 0 + self.nodes[0].children[0] = -1 + self.nodes[0].children[1] = -1 + self.nodes[0].symbol = -1 + for i in range(ht.count): + if ht.codes[i].bits == 0: continue + node: int = 0 + for bit in range(ht.codes[i].bits - 1, -1, -1): + dir: t.CInt = (ht.codes[i].code >> bit) & 1 + if bit > 0: + # Internal node: traverse or create + if self.nodes[node].children[dir] == -1: + new_node: int = self.node_count + self.node_count += 1 + self.nodes[new_node].children[0] = -1 + self.nodes[new_node].children[1] = -1 + self.nodes[new_node].symbol = -1 + self.nodes[node].children[dir] = new_node + node = self.nodes[node].children[dir] + else: + # Leaf: bit 0 - set symbol on the child + if self.nodes[node].children[dir] == -1: + leaf: int = self.node_count + self.node_count += 1 + self.nodes[leaf].children[0] = -1 + self.nodes[leaf].children[1] = -1 + self.nodes[leaf].symbol = i + self.nodes[node].children[dir] = leaf + else: + self.nodes[self.nodes[node].children[dir]].symbol = i + + def decode_symbol(self, reader: zdef.zbit_reader | t.CPtr) -> t.CInt: + node: int = self.root + while self.nodes[node].symbol == -1: + bit: t.CUnsignedInt + if reader.read_bits(1, c.Addr(bit)) != 0: return -1 + dir: t.CInt = t.CInt(bit) + if self.nodes[node].children[dir] == -1: return -1 + node = self.nodes[node].children[dir] + return self.nodes[node].symbol diff --git a/Test/ZlibTest/App/__zlib/zinflate.py b/Test/ZlibTest/App/__zlib/zinflate.py new file mode 100644 index 0000000..efdcded --- /dev/null +++ b/Test/ZlibTest/App/__zlib/zinflate.py @@ -0,0 +1,454 @@ +from stdint import * +import zinflate +import zchecksum +import zdef +import zhuff +import string +import t, c + + +@t.Object +class zinflate_stream: + reader: zdef.zbit_reader + + window: BYTEPTR + window_pos: t.CInt + window_size: t.CInt + + wbits: t.CInt + is_finished: t.CInt + is_initialized: t.CInt + + header_parsed: t.CInt + is_gzip: t.CInt + + adler: t.CUInt32T + crc: t.CUInt32T + + output: BYTEPTR + output_len: t.CSizeT + output_cap: t.CSizeT + + input_data: t.CConst | BYTEPTR + input_len: t.CSizeT + input_pos: t.CSizeT + + max_length: t.CSizeT + + def __init__(self): + pass + + def output_byte(self, byte: BYTE): + if self.max_length > 0 and self.output_len >= self.max_length: return + + if self.output_len >= self.output_cap: + new_cap: t.CSizeT = self.output_cap * 2 + if new_cap < 256: new_cap = 256 + new_buf: BYTEPTR = BYTEPTR(zdef.zdef_alloc(new_cap)) + if not new_buf: return + memcpy(new_buf, self.output, self.output_len) + zdef.zdef_free(self.output) + self.output = new_buf + self.output_cap = new_cap + self.output[self.output_len] = byte + self.output_len += 1 + self.window[self.window_pos & (zdef.ZDEFLATE_WINDOW_SIZE - 1)] = byte + self.window_pos += 1 + + + def parse_header(self) -> t.CInt: + if self.header_parsed: return 0 + if self.wbits < 0: + self.header_parsed = 1 + self.is_gzip = 0 + return 0 + if self.input_pos + 2 > self.input_len: return -3 + b0: BYTE = self.input_data[self.input_pos] + b1: BYTE = self.input_data[self.input_pos + 1] + if b0 == 0x1F and b1 == 0x8B: + self.is_gzip = 1 + if self.input_pos + 10 > self.input_len: return -3 + self.input_pos += 10 + flg: BYTE = self.input_data[self.input_pos - 6] + if flg & 0x04: + if self.input_pos + 2 > self.input_len: return -3 + xlen: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) + self.input_pos += 2 + xlen + if flg & 0x08: + while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 + self.input_pos += 1 + if flg & 0x10: + while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 + self.input_pos += 1 + if flg & 0x02: + self.input_pos += 2 + if self.input_pos > self.input_len: return -3 + else: + self.is_gzip = 0 + if (b0 * 256 + b1) % 31 != 0: return -3 + cm: t.CInt = b0 & 0x0F + if cm != 8: return -3 + self.input_pos += 2 + self.header_parsed = 1 + return 0 + + + def read_bits_from_input(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits): + if self.input_pos >= self.input_len: return -3 + if self.input_data[self.input_pos] & (UINT(1) << (self.reader.bit_pos)): + val |= (UINT(1) << i) + self.reader.bit_pos += 1 + if self.reader.bit_pos == 8: + self.reader.bit_pos = 0 + self.input_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + + def read_huffman(self, dt: zhuff.zhuff_decode_tree | t.CPtr) -> t.CInt: + node: int = dt.root + while dt.nodes[node].symbol == -1: + bit: UINT + if self.read_bits_from_input(1, c.Addr(bit)) != 0: return -1 + dir: int = t.CInt(bit) + if dt.nodes[node].children[dir] == -1: return -3 + node = dt.nodes[node].children[dir] + return dt.nodes[node].symbol + + def inflate_block_stored(self) -> t.CInt: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 4 > self.input_len: return -3 + length: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) + nlen: UINT = self.input_data[self.input_pos + 2] | (self.input_data[self.input_pos + 3] << 8) + self.input_pos += 4 + if (length ^ nlen) != 0xFFFF: return -3 + if self.input_pos + length > self.input_len: return -3 + i: t.CUnsignedInt + for i in range(length): + self.output_byte(self.input_data[self.input_pos]) + self.input_pos += 1 + return 0 + + + def inflate_block_fixed(self) -> t.CInt: + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + dist_tree.build_fixed_dist_tree() + + lit_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(zhuff.zhuff_decode_tree.__sizeof__()) + dist_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(zhuff.zhuff_decode_tree.__sizeof__()) + if not lit_dt or not dist_dt: + if lit_dt: zdef.zdef_free(lit_dt) + if dist_dt: zdef.zdef_free(dist_dt) + return -4 + memset(lit_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + memset(dist_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + lit_dt.build_decode_tree(c.Addr(lit_tree)) + dist_dt.build_decode_tree(c.Addr(dist_tree)) + + result: t.CInt = 0 + while True: + if self.max_length > 0 and self.output_len >= self.max_length: break + + sym: t.CInt = self.read_huffman(lit_dt) + if sym < 0: + result = -3 + break + if sym == 256: break + if sym < 256: + self.output_byte(BYTE(sym)) + else: + len_idx: t.CInt = sym - 257 + if len_idx < 0 or len_idx >= 29: + result = -3 + break + length: t.CInt = zdef.zdeflate_len_base[len_idx] + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: + result = -3 + break + length += extra_val + + dist_sym: t.CInt = self.read_huffman(dist_dt) + if dist_sym < 0 or dist_sym >= 30: + result = -3 + break + dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: + result = -3 + break + dist += extra_val + + for i in range(length): + if self.max_length > 0 and self.output_len >= self.max_length: break + src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) + byte: BYTE = self.window[src_pos] + self.output_byte(byte) + + zdef.zdef_free(lit_dt) + zdef.zdef_free(dist_dt) + return result + + + def inflate_block_dynamic(self) -> t.CInt: + hlit_val: UINT + hdist_val: UINT + hclen_val: UINT + if self.read_bits_from_input(5, c.Addr(hlit_val)) != 0: return -3 + if self.read_bits_from_input(5, c.Addr(hdist_val)) != 0: return -3 + if self.read_bits_from_input(4, c.Addr(hclen_val)) != 0: return -3 + + hlit: t.CInt = t.CInt(hlit_val) + 257 + hdist: t.CInt = t.CInt(hdist_val) + 1 + hclen: t.CInt = t.CInt(hclen_val) + 4 + + cl_lengths: list[t.CInt, 19] + memset(cl_lengths, 0, cl_lengths.__sizeof__()) + for i in range(hclen): + len_val: UINT + if self.read_bits_from_input(3, c.Addr(len_val)) != 0: return -3 + cl_lengths[zdef.zdeflate_codelen_order[i]] = t.CInt(len_val) + + cl_tree = zhuff.zhuff_tree() + cl_tree.build_tree_from_lengths(cl_lengths, 19, 7) + + cl_dt = zhuff.zhuff_decode_tree() + cl_dt.build_decode_tree(c.Addr(cl_tree)) + + total: t.CInt = hlit + hdist + all_lengths: t.CInt | t.CPtr = zdef.zdef_alloc(total * int.__sizeof__()) + if not all_lengths: return -4 + + idx: t.CInt = 0 + while idx < total: + sym: t.CInt = self.read_huffman(c.Addr(cl_dt)) + if sym < 0 or sym > 18: + zdef.zdef_free(all_lengths) + return -3 + if sym < 16: + all_lengths[idx] = sym + idx += 1 + elif sym == 16: + rep: UINT + if self.read_bits_from_input(2, c.Addr(rep)) != 0: + zdef.zdef_free(all_lengths) + return -3 + rep += 3 + if idx == 0 or idx + rep > total: + zdef.zdef_free(all_lengths) + return -3 + prev: t.CInt = all_lengths[idx - 1] + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = prev + idx += 1 + elif sym == 17: + rep: t.CUnsignedInt + if self.read_bits_from_input(3, c.Addr(rep)) != 0: + zdef.zdef_free(all_lengths) + return -3 + rep += 3 + if idx + rep > total: + zdef.zdef_free(all_lengths) + return -3 + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = 0 + idx += 1 + else: + rep: t.CUnsignedInt + if self.read_bits_from_input(7, c.Addr(rep)) != 0: + zdef.zdef_free(all_lengths) + return -3 + rep += 11 + if idx + rep > total: + zdef.zdef_free(all_lengths) + return -3 + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = 0 + idx += 1 + + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + + lit_lengths: list[t.CInt, 288] + memset(lit_lengths, 0, lit_lengths.__sizeof__()) + for i in range(hlit): + lit_lengths[i] = all_lengths[i] + lit_tree.build_tree_from_lengths(lit_lengths, hlit, zdef.ZDEFLATE_MAX_BITS) + + dist_lengths: list[t.CInt, 32] + memset(dist_lengths, 0, dist_lengths.__sizeof__()) + for i in range(hdist): + dist_lengths[i] = all_lengths[hlit + i] + dist_tree.build_tree_from_lengths(dist_lengths, hdist, zdef.ZDEFLATE_MAX_BITS) + + zdef.zdef_free(all_lengths) + + lit_dt = zhuff.zhuff_decode_tree() + dist_dt = zhuff.zhuff_decode_tree() + lit_dt.build_decode_tree(c.Addr(lit_tree)) + dist_dt.build_decode_tree(c.Addr(dist_tree)) + + while True: + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + sym: t.CInt = self.read_huffman(c.Addr(lit_dt)) + if sym < 0: return -3 + if sym == 256: return 0 + if sym < 256: + self.output_byte(BYTE(sym)) + else: + len_idx: t.CInt = sym - 257 + if len_idx < 0 or len_idx >= 29: return -3 + length: t.CInt = zdef.zdeflate_len_base[len_idx] + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 + length += extra_val + dist_sym: t.CInt = self.read_huffman(c.Addr(dist_dt)) + if dist_sym < 0 or dist_sym >= 30: return -3 + dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 + dist += extra_val + for i in range(length): + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) + byte: BYTE = self.window[src_pos] + self.output_byte(byte) + + def inflate_stream(self) -> t.CInt: + err: t.CInt = self.parse_header() + if err != 0: return err + while not self.is_finished: + bfinal_val: UINT + btype_val: UINT + if self.read_bits_from_input(1, c.Addr(bfinal_val)) != 0: return -3 + if self.read_bits_from_input(2, c.Addr(btype_val)) != 0: return -3 + bfinal: t.CInt = t.CInt(bfinal_val) + btype: t.CInt = t.CInt(btype_val) + if btype == 0: + err = self.inflate_block_stored() + elif btype == 1: + err = self.inflate_block_fixed() + elif btype == 2: + err = self.inflate_block_dynamic() + else: + return -3 + if err != 0: return err + if bfinal: self.is_finished = 1 + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + if self.is_gzip: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 8 <= self.input_len: + self.crc = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 0) | + (t.CUInt32T(self.input_data[self.input_pos + 1]) << 8) | + (t.CUInt32T(self.input_data[self.input_pos + 2]) << 16) | + (t.CUInt32T(self.input_data[self.input_pos + 3]) << 24)) + self.input_pos += 8 + elif self.wbits >= 0: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 4 <= self.input_len: + self.adler = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 24) | + (t.CUInt32T(self.input_data[self.input_pos + 1]) << 16) | + (t.CUInt32T(self.input_data[self.input_pos + 2]) << 8) | + (t.CUInt32T(self.input_data[self.input_pos + 3]) << 0)) + self.input_pos += 4 + return 0 + + def decompress(self, data: UINT8PTR, length: t.CSizeT, + max_length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if not self.is_initialized: return -2 + self.input_data = data + self.input_len = length + self.input_pos = 0 + self.reader.bit_pos = 0 + self.output_len = 0 + self.max_length = max_length + err: t.CInt = self.inflate_stream() + if err != 0: return err + c.Set(c.Deref(out_len), self.output_len) + if self.output_len == 0: + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(1))) + else: + dst: UINT8PTR = UINT8PTR(zdef.zdef_alloc(self.output_len)) + c.Set(c.Deref(out), dst) + if dst: + memcpy(dst, self.output, self.output_len) + return 0 + + def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + if not dict: return -2 + use: t.CSizeT = length + if use > zdef.ZDEFLATE_WINDOW_SIZE: + dict += length - zdef.ZDEFLATE_WINDOW_SIZE + use = zdef.ZDEFLATE_WINDOW_SIZE + memcpy(self.window, dict, use) + self.window_pos = t.CInt(use) + return 0 + + def copy(self) -> zinflate_stream | t.CPtr: + z: zinflate_stream | t.CPtr = zdef.zdef_alloc(zinflate_stream.__sizeof__()) + if not z: return None + memcpy(z, self, zinflate_stream.__sizeof__()) + z.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) + z.output = BYTEPTR(zdef.zdef_alloc(self.output_cap)) + if not z.window or not z.output: + zinflate_stream.destroy(z) + return None + memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + memcpy(z.output, self.output, self.output_cap) + return z + + def destroy(self): + if not self: return + if self.window: zdef.zdef_free(self.window) + if self.output: zdef.zdef_free(self.output) + zdef.zdef_free(self) + + +def zinflate_one_shot(data: UINT8PTR, length: t.CSizeT, + wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: + s: zinflate_stream | t.CPtr = zinflate_create(wbits) + if not s: return None + out: t.CUInt8T | t.CPtr = None + err: t.CInt = s.decompress(data, length, 0, c.Addr(out), out_len) + s.destroy() + if err != 0: return None + return out + + +def zinflate_create(wbits: t.CInt) -> zinflate_stream | t.CPtr: + s: zinflate_stream | t.CPtr = zdef.zdef_alloc(zinflate_stream.__sizeof__()) + if not s: return None + memset(s, 0, zinflate_stream.__sizeof__()) + s.wbits = wbits + s.is_initialized = 1 + s.adler = 1 + s.window = BYTEPTR(zdef.zdef_alloc(zdef.ZDEFLATE_WINDOW_SIZE)) + s.output = BYTEPTR(zdef.zdef_alloc(256)) + s.output_cap = 256 + s.output_len = 0 + s.max_length = 0 + if not s.window or not s.output: + s.destroy() + return None + return s diff --git a/Test/ZlibTest/App/main.py b/Test/ZlibTest/App/main.py new file mode 100644 index 0000000..c32ad80 --- /dev/null +++ b/Test/ZlibTest/App/main.py @@ -0,0 +1,16 @@ +import t +import stdio +import string +import __zlib.pyzlib as pyzlib +import __zlib.zdeflate as zdeflate +import __zlib.zinflate as zinflate +import __zlib.zchecksum as zchecksum +import __zlib.zdef as zdef +import __zlib.zhuff as zhuff +import __zlib.test_pyzlib as tpz +import w32.win32memory +import c + +def main() -> t.CInt: + tpz.main123456() + return 0 diff --git a/Test/ZlibTest/output/024a3459d0f585ae.deps.json b/Test/ZlibTest/output/024a3459d0f585ae.deps.json new file mode 100644 index 0000000..98f9df8 --- /dev/null +++ b/Test/ZlibTest/output/024a3459d0f585ae.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/067c78e9f121dce3.deps.json b/Test/ZlibTest/output/067c78e9f121dce3.deps.json new file mode 100644 index 0000000..5007e65 --- /dev/null +++ b/Test/ZlibTest/output/067c78e9f121dce3.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3"} \ No newline at end of file diff --git a/Test/ZlibTest/output/0af305ed4e5f787d.deps.json b/Test/ZlibTest/output/0af305ed4e5f787d.deps.json new file mode 100644 index 0000000..536ae4c --- /dev/null +++ b/Test/ZlibTest/output/0af305ed4e5f787d.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/29813d57621099a9.deps.json b/Test/ZlibTest/output/29813d57621099a9.deps.json new file mode 100644 index 0000000..c0a37ee --- /dev/null +++ b/Test/ZlibTest/output/29813d57621099a9.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e", "w32.win32process": "067c78e9f121dce3", "win32process": "067c78e9f121dce3", "w32.win32sync": "29813d57621099a9", "win32sync": "29813d57621099a9"} \ No newline at end of file diff --git a/Test/ZlibTest/output/5a6a2137958c28c5.deps.json b/Test/ZlibTest/output/5a6a2137958c28c5.deps.json new file mode 100644 index 0000000..661fe60 --- /dev/null +++ b/Test/ZlibTest/output/5a6a2137958c28c5.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/ZlibTest/output/72e2d5ccb7cedcf1.deps.json b/Test/ZlibTest/output/72e2d5ccb7cedcf1.deps.json new file mode 100644 index 0000000..25dc5a3 --- /dev/null +++ b/Test/ZlibTest/output/72e2d5ccb7cedcf1.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/ZlibTest/output/7e9fab9c7b47c4db.deps.json b/Test/ZlibTest/output/7e9fab9c7b47c4db.deps.json new file mode 100644 index 0000000..7d3127d --- /dev/null +++ b/Test/ZlibTest/output/7e9fab9c7b47c4db.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/95e27d852b773ae8.deps.json b/Test/ZlibTest/output/95e27d852b773ae8.deps.json new file mode 100644 index 0000000..365282c --- /dev/null +++ b/Test/ZlibTest/output/95e27d852b773ae8.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/abf9ce3160c9279e.deps.json b/Test/ZlibTest/output/abf9ce3160c9279e.deps.json new file mode 100644 index 0000000..25dc5a3 --- /dev/null +++ b/Test/ZlibTest/output/abf9ce3160c9279e.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "w32.win32file": "abf9ce3160c9279e", "win32file": "abf9ce3160c9279e"} \ No newline at end of file diff --git a/Test/ZlibTest/output/bbdf3bbd4c3bc28c.deps.json b/Test/ZlibTest/output/bbdf3bbd4c3bc28c.deps.json new file mode 100644 index 0000000..ac30ccb --- /dev/null +++ b/Test/ZlibTest/output/bbdf3bbd4c3bc28c.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c"} \ No newline at end of file diff --git a/Test/ZlibTest/output/c9349bf1e8390dd5.deps.json b/Test/ZlibTest/output/c9349bf1e8390dd5.deps.json new file mode 100644 index 0000000..88b64c9 --- /dev/null +++ b/Test/ZlibTest/output/c9349bf1e8390dd5.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/dca7ef1d57347738.deps.json b/Test/ZlibTest/output/dca7ef1d57347738.deps.json new file mode 100644 index 0000000..bf53f56 --- /dev/null +++ b/Test/ZlibTest/output/dca7ef1d57347738.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/e00d9854a0d03f4f.deps.json b/Test/ZlibTest/output/e00d9854a0d03f4f.deps.json new file mode 100644 index 0000000..5c0cc0d --- /dev/null +++ b/Test/ZlibTest/output/e00d9854a0d03f4f.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/f9cd063200178785.deps.json b/Test/ZlibTest/output/f9cd063200178785.deps.json new file mode 100644 index 0000000..b3e8265 --- /dev/null +++ b/Test/ZlibTest/output/f9cd063200178785.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604"} \ No newline at end of file diff --git a/Test/ZlibTest/output/fa3691e66b426950.deps.json b/Test/ZlibTest/output/fa3691e66b426950.deps.json new file mode 100644 index 0000000..661fe60 --- /dev/null +++ b/Test/ZlibTest/output/fa3691e66b426950.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785", "__zlib.test_pyzlib": "ffaa1aaa1355e604", "test_pyzlib": "ffaa1aaa1355e604", "w32.fileio": "fa3691e66b426950", "fileio": "fa3691e66b426950"} \ No newline at end of file diff --git a/Test/ZlibTest/output/ffaa1aaa1355e604.deps.json b/Test/ZlibTest/output/ffaa1aaa1355e604.deps.json new file mode 100644 index 0000000..7b7af4a --- /dev/null +++ b/Test/ZlibTest/output/ffaa1aaa1355e604.deps.json @@ -0,0 +1 @@ +{"string": "024a3459d0f585ae", "__zlib.zdeflate": "0af305ed4e5f787d", "zdeflate": "0af305ed4e5f787d", "stdint": "56cdd754a8a09347", "w32.win32base": "5a6a2137958c28c5", "win32base": "5a6a2137958c28c5", "w32.win32memory": "72e2d5ccb7cedcf1", "win32memory": "72e2d5ccb7cedcf1", "stdio": "73edbcf76e32d00b", "__zlib.pyzlib": "7e9fab9c7b47c4db", "pyzlib": "7e9fab9c7b47c4db", "__zlib.zchecksum": "95e27d852b773ae8", "zchecksum": "95e27d852b773ae8", "stdlib": "a96738831f025829", "__zlib.zhuff": "c9349bf1e8390dd5", "zhuff": "c9349bf1e8390dd5", "main": "dca7ef1d57347738", "__zlib.zinflate": "e00d9854a0d03f4f", "zinflate": "e00d9854a0d03f4f", "__zlib.zdef": "f9cd063200178785", "zdef": "f9cd063200178785"} \ No newline at end of file diff --git a/Test/ZlibTest/project.json b/Test/ZlibTest/project.json new file mode 100644 index 0000000..7001e57 --- /dev/null +++ b/Test/ZlibTest/project.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://raw.githubusercontent.com/TermiNexus/TransPyC/main/schemas/project-schema.json", + "name": "ZlibTest", + "version": "1.0.0", + "source_dir": "./App", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj"] + }, + "linker": { + "cmd": "clang++", + "flags": ["-Wl,--allow-multiple-definition", "-Wl,--unresolved-symbols=ignore-in-object-files", "-lmsvcrt", "-lucrt", "-lpthread", "-lmingwex", "-lkernel32", "-luser32", "-latomic"], + "output": "ZlibTest.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} diff --git a/Test/ZlibTest/temp/024a3459d0f585ae.pyi b/Test/ZlibTest/temp/024a3459d0f585ae.pyi new file mode 100644 index 0000000..eae6834 --- /dev/null +++ b/Test/ZlibTest/temp/024a3459d0f585ae.pyi @@ -0,0 +1,40 @@ +""" +Auto-generated Python stub file from string.py +Module: string +""" + + +from stdint import * +import t, c + +def strcpy(dest: str, src: str) -> str: pass + +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: pass + +def strlen(src: str) -> t.CSizeT | t.CExport: pass + +def strcmp(str1: str, str2: str) -> t.CInt: pass + +def samestr(str1: str, str2: str) -> bool: pass + +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: pass + +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: pass + +def strchr(s: str, cr: t.CInt) -> str: pass + +def strrchr(s: str, cr: t.CInt) -> str: pass + +def strspn(s: str, skip: str) -> int: pass + +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: pass + +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: pass + +def atoi(src: str) -> t.CInt: pass + +def split(s: str, delim: str, result: list[str]) -> int: pass diff --git a/Test/ZlibTest/temp/067c78e9f121dce3.pyi b/Test/ZlibTest/temp/067c78e9f121dce3.pyi new file mode 100644 index 0000000..f4f767c --- /dev/null +++ b/Test/ZlibTest/temp/067c78e9f121dce3.pyi @@ -0,0 +1,136 @@ +""" +Auto-generated Python stub file from w32.win32process.py +Module: w32.win32process +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA: + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class STARTUPINFOW: + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE +class PROCESS_INFORMATION: + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass + +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass + +def GetCurrentProcess() -> HANDLE | t.State: pass + +def GetCurrentProcessId() -> ULONG | t.State: pass + +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass + +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass + +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass + +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass + +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass + +def GetCurrentThread() -> HANDLE | t.State: pass + +def GetCurrentThreadId() -> ULONG | t.State: pass + +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass + +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass + +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass + +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass + +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass + +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass + +def TlsAlloc() -> ULONG | t.State: pass + +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass + +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass + +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/Test/ZlibTest/temp/0af305ed4e5f787d.pyi b/Test/ZlibTest/temp/0af305ed4e5f787d.pyi new file mode 100644 index 0000000..193ea96 --- /dev/null +++ b/Test/ZlibTest/temp/0af305ed4e5f787d.pyi @@ -0,0 +1,54 @@ +""" +Auto-generated Python stub file from __zlib.zdeflate.py +Module: __zlib.zdeflate +""" + + +from stdint import * +import zchecksum +import zhuff +import zdef +import string +import t, c + +@t.Object +class zdeflate_stream: + writer: zdef.zbit_writer + window: BYTE | t.CPtr + window_pos: t.CInt + window_size: t.CInt + hash_head: t.CInt | t.CPtr + hash_prev: t.CInt | t.CPtr + level: t.CInt + strategy: t.CInt + wbits: t.CInt + is_finished: t.CInt + adler: t.CUInt32T + def find_match(self: zdeflate_stream, data: BYTE | t.CPtr, data_len: t.CSizeT, pos: t.CSizeT, best_dist: t.CInt | t.CPtr) -> t.CInt: pass + def update_hash(self: zdeflate_stream, data: BYTE | t.CPtr, pos: t.CSizeT) -> t.CInt: pass + def write_fixed_block(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def encode_block_data(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, lit_tree: zhuff.zhuff_tree | t.CPtr, dist_tree: zhuff.zhuff_tree | t.CPtr) -> t.CInt: pass + def write_dynamic_block(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def compress_block(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def write_stored_block(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def compress(self: zdeflate_stream, data: UINT8PTR, length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: pass + def flush(self: zdeflate_stream, mode: t.CInt, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: pass + def set_dictionary(self: zdeflate_stream, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: pass + def copy(self: zdeflate_stream) -> zdeflate_stream | t.CPtr: pass + def destroy(self: zdeflate_stream) -> t.CInt: pass + +def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR, s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT) -> t.CInt: pass + +def zdeflate_hash(p: BYTE | t.CPtr) -> t.CUnsignedInt: pass + +def zdeflate_len_to_symbol(length: t.CInt) -> t.CInt: pass + +def zdeflate_dist_to_symbol(dist: t.CInt) -> t.CInt: pass + +def zdeflate_count_cl_freqs(all_lengths: INTPTR, total: t.CInt, cl_freqs: INTPTR) -> t.CInt: pass + +def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt, w: zdef.zbit_writer | t.CPtr, cl_tree: zhuff.zhuff_tree | t.CPtr) -> t.CInt: pass + +def zdeflate_create(level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: pass + +def zdeflate_one_shot(data: UINT8PTR, length: t.CSizeT, level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: pass diff --git a/Test/ZlibTest/temp/29813d57621099a9.pyi b/Test/ZlibTest/temp/29813d57621099a9.pyi new file mode 100644 index 0000000..a5e9923 --- /dev/null +++ b/Test/ZlibTest/temp/29813d57621099a9.pyi @@ -0,0 +1,85 @@ +""" +Auto-generated Python stub file from w32.win32sync.py +Module: w32.win32sync +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION: + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass + +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass + +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass + +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass + +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass + +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass + +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass + +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass + +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass + +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass + +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass + +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass + +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/Test/ZlibTest/temp/56cdd754a8a09347.pyi b/Test/ZlibTest/temp/56cdd754a8a09347.pyi new file mode 100644 index 0000000..007ccb8 --- /dev/null +++ b/Test/ZlibTest/temp/56cdd754a8a09347.pyi @@ -0,0 +1,67 @@ +""" +Auto-generated Python stub file from stdint.py +Module: stdint +""" + +import c + + +import t + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr \ No newline at end of file diff --git a/Test/ZlibTest/temp/5a6a2137958c28c5.pyi b/Test/ZlibTest/temp/5a6a2137958c28c5.pyi new file mode 100644 index 0000000..a137977 --- /dev/null +++ b/Test/ZlibTest/temp/5a6a2137958c28c5.pyi @@ -0,0 +1,98 @@ +""" +Auto-generated Python stub file from w32.win32base.py +Module: w32.win32base +""" + +import c + + +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES: + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL +class OVERLAPPED: + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE +class FILETIME: + dwLowDateTime: DWORD + dwHighDateTime: DWORD +class SYSTEMTIME: + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD +class GUID: + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR +class LARGE_INTEGER: + QuadPart: LONGLONG +class ULARGE_INTEGER: + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass + +def SetLastError(dwErrCode: ULONG) -> t.State: pass + +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass + +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass + +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass + +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass + +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass + +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass + +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass + +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass + +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass + +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def Sleep(dwMilliseconds: ULONG) -> t.State: pass + +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass + +def GetTickCount() -> ULONG | t.State: pass + +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/Test/ZlibTest/temp/72e2d5ccb7cedcf1.pyi b/Test/ZlibTest/temp/72e2d5ccb7cedcf1.pyi new file mode 100644 index 0000000..5fceb08 --- /dev/null +++ b/Test/ZlibTest/temp/72e2d5ccb7cedcf1.pyi @@ -0,0 +1,91 @@ +""" +Auto-generated Python stub file from w32.win32memory.py +Module: w32.win32memory +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION: + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass + +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass + +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass + +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass + +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass + +def GetProcessHeap() -> HANDLE | t.State: pass + +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass + +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass + +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass + +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass + +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass + +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass + +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass + +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass + +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass + +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass + +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/Test/ZlibTest/temp/73edbcf76e32d00b.pyi b/Test/ZlibTest/temp/73edbcf76e32d00b.pyi new file mode 100644 index 0000000..ef712e3 --- /dev/null +++ b/Test/ZlibTest/temp/73edbcf76e32d00b.pyi @@ -0,0 +1,28 @@ +""" +Auto-generated Python stub file from stdio.py +Module: stdio +""" + + +import t, c + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass + +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + + +stdin: t.CExtern | t.CVoid | t.CPtr +stdout: t.CExtern | t.CVoid | t.CPtr +stderr: t.CExtern | t.CVoid | t.CPtr \ No newline at end of file diff --git a/Test/ZlibTest/temp/7e9fab9c7b47c4db.pyi b/Test/ZlibTest/temp/7e9fab9c7b47c4db.pyi new file mode 100644 index 0000000..ec4964b --- /dev/null +++ b/Test/ZlibTest/temp/7e9fab9c7b47c4db.pyi @@ -0,0 +1,122 @@ +""" +Auto-generated Python stub file from __zlib.pyzlib.py +Module: __zlib.pyzlib +""" + + +from stdint import * +import zdeflate +import zinflate +import zchecksum +import zdef +import zhuff +import stdlib +import string +import t, c + +Z_NO_COMPRESSION: t.CDefine = 0 +Z_BEST_SPEED: t.CDefine = 1 +Z_BEST_COMPRESSION: t.CDefine = 9 +Z_DEFAULT_COMPRESSION: t.CDefine = (-1) +DEFLATED: t.CDefine = 8 +Z_NO_FLUSH: t.CDefine = 0 +Z_PARTIAL_FLUSH: t.CDefine = 1 +Z_SYNC_FLUSH: t.CDefine = 2 +Z_FULL_FLUSH: t.CDefine = 3 +Z_FINISH: t.CDefine = 4 +Z_BLOCK: t.CDefine = 5 +Z_TREES: t.CDefine = 6 +Z_DEFAULT_STRATEGY: t.CDefine = 0 +Z_FILTERED: t.CDefine = 1 +Z_HUFFMAN_ONLY: t.CDefine = 2 +Z_RLE: t.CDefine = 3 +Z_FIXED: t.CDefine = 4 +Z_OK: t.CDefine = 0 +Z_STREAM_END: t.CDefine = 1 +Z_NEED_DICT: t.CDefine = 2 +Z_ERRNO: t.CDefine = (-1) +Z_STREAM_ERROR: t.CDefine = (-2) +Z_DATA_ERROR: t.CDefine = (-3) +Z_MEM_ERROR: t.CDefine = (-4) +Z_BUF_ERROR: t.CDefine = (-5) +Z_VERSION_ERROR: t.CDefine = (-6) +MAX_WBITS: t.CDefine = 15 +DEF_BUF_SIZE: t.CDefine = 16384 +DEF_MEM_LEVEL: t.CDefine = 8 +ZLIB_VERSION: t.CDefine = "1.3.2" +pyzlib_error_msg: t.CExtern | list[t.CChar, 512] +pyzlib_error_code_val: t.CExtern | t.CInt + +@t.Object +class Compress: + stream: VOIDPTR + is_initialized: t.CInt + is_finished: t.CInt + level: t.CInt + method: t.CInt + wbits: t.CInt + memLevel: t.CInt + strategy: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + last_pos: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + header_written: t.CInt + def compress(self: Compress, data: BYTEPTR, data_len: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def flush(self: Compress, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def copy(self: Compress) -> Compress | t.CPtr: pass + def delete(self: Compress) -> t.CInt: pass + def __del__(self: Compress) -> t.CInt: pass +@t.Object +class Decompress: + stream: VOIDPTR + is_initialized: t.CInt + eof: t.CInt + wbits: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + _unused_data: BYTEPTR + _unused_data_len: t.CSizeT + _unused_data_cap: t.CSizeT + _unconsumed_tail: BYTEPTR + _unconsumed_tail_len: t.CSizeT + _unconsumed_tail_cap: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + def decompress(self: Decompress, data: BYTEPTR, data_len: t.CSizeT, max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def flush(self: Decompress, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def copy(self: Decompress) -> Decompress | t.CPtr: pass + def delete(self: Decompress) -> t.CInt: pass + def unused_data(self: Decompress, length: t.CSizeT | t.CPtr) -> BYTEPTR: pass + def unconsumed_tail(self: Decompress, length: t.CSizeT | t.CPtr) -> BYTEPTR: pass + +def set_error(code: int, msg: str) -> t.CInt: pass + +def clone_bytes(src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: pass + +def append_bytes(buf: BYTE | t.CPtr[t.CPtr], length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr, data: BYTEPTR, data_len: t.CSizeT) -> t.CInt: pass + +def shrink_to_fit(buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: pass + +def runtime_version() -> str: pass + +def get_error() -> str: pass + +def get_error_code() -> t.CInt: pass + +def clear_error() -> t.CInt: pass + +def compress(data: BYTEPTR, data_len: t.CSizeT, level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + +def decompress(data: BYTEPTR, data_len: t.CSizeT, wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: pass + +def compressobj(level: t.CInt, method: t.CInt, wbits: t.CInt, memLevel: t.CInt, strategy: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr: pass + +def decompressobj(wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: pass + +def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: pass + +def zlib_crc32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: pass diff --git a/Test/ZlibTest/temp/95e27d852b773ae8.pyi b/Test/ZlibTest/temp/95e27d852b773ae8.pyi new file mode 100644 index 0000000..db9e1d8 --- /dev/null +++ b/Test/ZlibTest/temp/95e27d852b773ae8.pyi @@ -0,0 +1,15 @@ +""" +Auto-generated Python stub file from __zlib.zchecksum.py +Module: __zlib.zchecksum +""" + + +from stdint import * +import t, c + +def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T: pass + + +crc32_table: t.CExtern | list[t.CUInt32T, 256] + +def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T: pass diff --git a/Test/ZlibTest/temp/_sha1_map.txt b/Test/ZlibTest/temp/_sha1_map.txt new file mode 100644 index 0000000..3c10a9e --- /dev/null +++ b/Test/ZlibTest/temp/_sha1_map.txt @@ -0,0 +1,14 @@ +024a3459d0f585ae:includes/string.py +0af305ed4e5f787d:__zlib\zdeflate.py +56cdd754a8a09347:includes/stdint.py +5a6a2137958c28c5:includes/w32\win32base.py +72e2d5ccb7cedcf1:includes/w32\win32memory.py +73edbcf76e32d00b:includes/stdio.py +7e9fab9c7b47c4db:__zlib\pyzlib.py +95e27d852b773ae8:__zlib\zchecksum.py +a96738831f025829:includes/stdlib.py +c9349bf1e8390dd5:__zlib\zhuff.py +dca7ef1d57347738:main.py +e00d9854a0d03f4f:__zlib\zinflate.py +f9cd063200178785:__zlib\zdef.py +ffaa1aaa1355e604:__zlib\test_pyzlib.py diff --git a/Test/ZlibTest/temp/_shared_sym.pkl b/Test/ZlibTest/temp/_shared_sym.pkl new file mode 100644 index 0000000..87361f3 Binary files /dev/null and b/Test/ZlibTest/temp/_shared_sym.pkl differ diff --git a/Test/ZlibTest/temp/a96738831f025829.pyi b/Test/ZlibTest/temp/a96738831f025829.pyi new file mode 100644 index 0000000..c499547 --- /dev/null +++ b/Test/ZlibTest/temp/a96738831f025829.pyi @@ -0,0 +1,16 @@ +""" +Auto-generated Python stub file from stdlib.py +Module: stdlib +""" + +import c + + +from stdint import * +import t + +def malloc(size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass + +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass diff --git a/Test/ZlibTest/temp/abf9ce3160c9279e.pyi b/Test/ZlibTest/temp/abf9ce3160c9279e.pyi new file mode 100644 index 0000000..4249b58 --- /dev/null +++ b/Test/ZlibTest/temp/abf9ce3160c9279e.pyi @@ -0,0 +1,179 @@ +""" +Auto-generated Python stub file from w32.win32file.py +Module: w32.win32file +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG +class WIN32_FIND_DATAA: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR +class WIN32_FIND_DATAW: + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass + +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass + +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass + +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass + +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass + +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass + +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass + +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass + +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass + +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass + +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass + +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass + +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass + +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass + +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass + +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass + +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass + +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass + +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass + +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass + +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass + +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass + +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass + +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass + +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass + +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass + +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass + +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass + +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass + +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass + +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass + +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass + +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass + +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass + +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/Test/ZlibTest/temp/bbdf3bbd4c3bc28c.pyi b/Test/ZlibTest/temp/bbdf3bbd4c3bc28c.pyi new file mode 100644 index 0000000..70dcdbc --- /dev/null +++ b/Test/ZlibTest/temp/bbdf3bbd4c3bc28c.pyi @@ -0,0 +1,138 @@ +""" +Auto-generated Python stub file from w32.win32console.py +Module: w32.win32console +""" + +import c + + +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD: + X: SHORT + Y: SHORT +class SMALL_RECT: + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT +class CONSOLE_SCREEN_BUFFER_INFO: + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD +class CONSOLE_CURSOR_INFO: + dwSize: ULONG + bVisible: BOOL +class CHAR_INFO: + UnicodeChar: WCHAR + Attributes: WORD +class KEY_EVENT_RECORD: + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG +class MOUSE_EVENT_RECORD: + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG +class WINDOW_BUFFER_SIZE_RECORD: + dwSize: COORD +class INPUT_RECORD: + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass + +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass + +def GetConsoleCP() -> UINT | t.State: pass + +def GetConsoleOutputCP() -> UINT | t.State: pass + +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass + +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass + +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass + +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass + +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass + +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass + +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass + +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass + +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass + +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass + +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass + +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass + +def AllocConsole() -> BOOL | t.State: pass + +def FreeConsole() -> BOOL | t.State: pass + +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass + +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/Test/ZlibTest/temp/c9349bf1e8390dd5.pyi b/Test/ZlibTest/temp/c9349bf1e8390dd5.pyi new file mode 100644 index 0000000..cad3f7f --- /dev/null +++ b/Test/ZlibTest/temp/c9349bf1e8390dd5.pyi @@ -0,0 +1,41 @@ +""" +Auto-generated Python stub file from __zlib.zhuff.py +Module: __zlib.zhuff +""" + + +from stdint import * +import zdef +import t, c + +ZHUFF_MAX_CODES: t.CDefine = 288 +ZHUFF_MAX_BITS: t.CDefine = 15 + +class zhuff_code: + code: UINT + bits: t.CInt +@t.Object +class zhuff_tree: + codes: list[zhuff_code, ZHUFF_MAX_CODES] + count: t.CInt + max_bits: t.CInt + def __init__(self: zhuff_tree) -> t.CInt: pass + def build_codes(self: zhuff_tree, freqs: INTPTR, count: t.CInt, max_bits: t.CInt) -> t.CInt: pass + def build_fixed_lit_tree(self: zhuff_tree) -> t.CInt: pass + def build_fixed_dist_tree(self: zhuff_tree) -> t.CInt: pass + def encode_symbol(self: zhuff_tree, symbol: int, writer: zdef.zbit_writer | t.CPtr) -> t.CInt: pass + def build_code_lengths(self: zhuff_tree, lengths: t.CInt | t.CPtr, freqs: t.CInt | t.CPtr, count: t.CInt, max_bits: t.CInt) -> t.CInt: pass + def get_fixed_lit_lengths(self: zhuff_tree, lengths: INTPTR) -> t.CInt: pass + def get_fixed_dist_lengths(self: zhuff_tree, lengths: INTPTR) -> t.CInt: pass + def build_tree_from_lengths(self: zhuff_tree, lengths: INTPTR, count: t.CInt, max_bits: t.CInt) -> t.CInt: pass +class zhuff_decode_node: + children: list[t.CInt, 2] + symbol: t.CInt +@t.Object +class zhuff_decode_tree: + nodes: list[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] + node_count: t.CInt + root: t.CInt + def __init__(self: zhuff_decode_tree) -> t.CInt: pass + def build_decode_tree(self: zhuff_decode_tree, ht: zhuff_tree | t.CPtr) -> t.CInt: pass + def decode_symbol(self: zhuff_decode_tree, reader: zdef.zbit_reader | t.CPtr) -> t.CInt: pass \ No newline at end of file diff --git a/Test/ZlibTest/temp/dca7ef1d57347738.pyi b/Test/ZlibTest/temp/dca7ef1d57347738.pyi new file mode 100644 index 0000000..64bfc75 --- /dev/null +++ b/Test/ZlibTest/temp/dca7ef1d57347738.pyi @@ -0,0 +1,20 @@ +""" +Auto-generated Python stub file from main.py +Module: main +""" + + +import t +import stdio +import string +import __zlib.pyzlib as pyzlib +import __zlib.zdeflate as zdeflate +import __zlib.zinflate as zinflate +import __zlib.zchecksum as zchecksum +import __zlib.zdef as zdef +import __zlib.zhuff as zhuff +import __zlib.test_pyzlib as tpz +import w32.win32memory +import c + +def main() -> t.CInt: pass diff --git a/Test/ZlibTest/temp/e00d9854a0d03f4f.pyi b/Test/ZlibTest/temp/e00d9854a0d03f4f.pyi new file mode 100644 index 0000000..355f684 --- /dev/null +++ b/Test/ZlibTest/temp/e00d9854a0d03f4f.pyi @@ -0,0 +1,51 @@ +""" +Auto-generated Python stub file from __zlib.zinflate.py +Module: __zlib.zinflate +""" + + +from stdint import * +import zinflate +import zchecksum +import zdef +import zhuff +import string +import t, c + +@t.Object +class zinflate_stream: + reader: zdef.zbit_reader + window: BYTEPTR + window_pos: t.CInt + window_size: t.CInt + wbits: t.CInt + is_finished: t.CInt + is_initialized: t.CInt + header_parsed: t.CInt + is_gzip: t.CInt + adler: t.CUInt32T + crc: t.CUInt32T + output: BYTEPTR + output_len: t.CSizeT + output_cap: t.CSizeT + input_data: t.CConst | BYTEPTR + input_len: t.CSizeT + input_pos: t.CSizeT + max_length: t.CSizeT + def __init__(self: zinflate_stream) -> t.CInt: pass + def output_byte(self: zinflate_stream, byte: BYTE) -> t.CInt: pass + def parse_header(self: zinflate_stream) -> t.CInt: pass + def read_bits_from_input(self: zinflate_stream, nbits: t.CInt, out: UINTPTR) -> t.CInt: pass + def read_huffman(self: zinflate_stream, dt: zhuff.zhuff_decode_tree | t.CPtr) -> t.CInt: pass + def inflate_block_stored(self: zinflate_stream) -> t.CInt: pass + def inflate_block_fixed(self: zinflate_stream) -> t.CInt: pass + def inflate_block_dynamic(self: zinflate_stream) -> t.CInt: pass + def inflate_stream(self: zinflate_stream) -> t.CInt: pass + def decompress(self: zinflate_stream, data: UINT8PTR, length: t.CSizeT, max_length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: pass + def set_dictionary(self: zinflate_stream, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: pass + def copy(self: zinflate_stream) -> zinflate_stream | t.CPtr: pass + def destroy(self: zinflate_stream) -> t.CInt: pass + +def zinflate_one_shot(data: UINT8PTR, length: t.CSizeT, wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: pass + +def zinflate_create(wbits: t.CInt) -> zinflate_stream | t.CPtr: pass diff --git a/Test/ZlibTest/temp/f9cd063200178785.pyi b/Test/ZlibTest/temp/f9cd063200178785.pyi new file mode 100644 index 0000000..a5f2ed8 --- /dev/null +++ b/Test/ZlibTest/temp/f9cd063200178785.pyi @@ -0,0 +1,65 @@ +""" +Auto-generated Python stub file from __zlib.zdef.py +Module: __zlib.zdef +""" + + +from stdint import * +import stddef +import string +import stdlib +import t, c + +ZDEFLATE_WINDOW_BITS: t.CDefine = 15 +ZDEFLATE_WINDOW_SIZE: t.CDefine = (1 << ZDEFLATE_WINDOW_BITS) +ZDEFLATE_WINDOW_MASK: t.CDefine = (ZDEFLATE_WINDOW_SIZE - 1) +ZDEFLATE_MIN_MATCH: t.CDefine = 3 +ZDEFLATE_MAX_MATCH: t.CDefine = 258 +ZDEFLATE_HASH_BITS: t.CDefine = 15 +ZDEFLATE_HASH_SIZE: t.CDefine = (1 << ZDEFLATE_HASH_BITS) +ZDEFLATE_HASH_MASK: t.CDefine = (ZDEFLATE_HASH_SIZE - 1) +ZDEFLATE_MAX_CODES: t.CDefine = 288 +ZDEFLATE_MAX_DIST_CODES: t.CDefine = 32 +ZDEFLATE_MAX_BITS: t.CDefine = 15 +ZDEFLATE_MAX_CODELEN_CODES: t.CDefine = 19 +ZDEFLATE_LIT_COUNT: t.CDefine = 286 +ZDEFLATE_DIST_COUNT: t.CDefine = 30 +ZDEFLATE_LEN_SYMBOLS_BASE: t.CDefine = 257 +ZDEFLATE_END_OF_BLOCK: t.CDefine = 256 +zdeflate_len_extra_bits: t.CExtern | list[t.CInt, 29] +zdeflate_len_base: t.CExtern | list[t.CInt, 29] +zdeflate_dist_extra_bits: t.CExtern | list[t.CInt, 30] +zdeflate_dist_base: t.CExtern | list[t.CInt, 30] +zdeflate_codelen_order: t.CExtern | list[int, 19] + +@t.Object +class zbit_writer: + buf: BYTE | t.CPtr + cap: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + def __init__(self: zbit_writer) -> t.CInt: pass + def ensure(self: zbit_writer, need: t.CSizeT) -> t.CInt: pass + def write_bits(self: zbit_writer, value: UINT, nbits: t.CInt) -> t.CInt: pass + def write_bits_rev(self: zbit_writer, code: UINT, nbits: t.CInt) -> t.CInt: pass + def stored_block(self: zbit_writer, data: UINT8PTR, length: t.CSizeT, final: t.CInt) -> t.CInt: pass + def write_zlib_header(self: zbit_writer, wbits: t.CInt, level: t.CInt) -> t.CInt: pass + def write_gzip_header(self: zbit_writer) -> t.CInt: pass + def align(self: zbit_writer) -> t.CInt: pass + def total(self: zbit_writer) -> t.CSizeT: pass + def free(self: zbit_writer) -> t.CInt: pass + def __del__(self: zbit_writer) -> t.CInt: pass +@t.Object +class zbit_reader: + buf: BYTE | t.CPtr + length: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + def init(self: zbit_reader, buf: BYTE | t.CPtr, length: t.CSizeT) -> t.CInt: pass + def read_bits(self: zbit_reader, nbits: t.CInt, out: UINTPTR) -> t.CInt: pass + def read_bits_rev(self: zbit_reader, nbits: t.CInt, out: UINTPTR) -> t.CInt: pass + def align(self: zbit_reader) -> t.CInt: pass + +def zdef_alloc(n: t.CSizeT) -> VOIDPTR: pass + +def zdef_free(p: VOIDPTR) -> t.CInt: pass diff --git a/Test/ZlibTest/temp/fa3691e66b426950.pyi b/Test/ZlibTest/temp/fa3691e66b426950.pyi new file mode 100644 index 0000000..48fd36c --- /dev/null +++ b/Test/ZlibTest/temp/fa3691e66b426950.pyi @@ -0,0 +1,80 @@ +""" +Auto-generated Python stub file from w32.fileio.py +Module: w32.fileio +""" + + +import t, c +from stdint import * +import w32.win32base +import w32.win32file + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 +INVALID_SET_FILE_POINTER: t.CDefine = -1 +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: File, filename: str, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: File) -> 'File' | t.CPtr: pass + def __exit__(self: File) -> t.CInt: pass + def read(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write(self: File, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: File, s: str) -> LONG: pass + def seek(self: File, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: File) -> LONG: pass + def close(self: File) -> LONG: pass + def flush(self: File) -> LONG: pass + def size(self: File) -> LONGLONG: pass + def readline(self: File, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: File, buf: bytes, max_count: ULONG) -> LONG: pass +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + def __init__(self: FileW, filename: LPCWSTR, mode: ULONG, share: ULONG) -> t.CInt: pass + def __enter__(self: FileW) -> 'FileW' | t.CPtr: pass + def __exit__(self: FileW) -> t.CInt: pass + def read(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write(self: FileW, buf: bytes, count: ULONG) -> LONG: pass + def write_str(self: FileW, s: str) -> LONG: pass + def seek(self: FileW, offset: LONG, origin: ULONG) -> LONG: pass + def tell(self: FileW) -> LONG: pass + def close(self: FileW) -> LONG: pass + def flush(self: FileW) -> LONG: pass + def size(self: FileW) -> LONGLONG: pass + def readline(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + def read_all(self: FileW, buf: bytes, max_count: ULONG) -> LONG: pass + +def open(filename: str, mode: ULONG, share: ULONG) -> File | t.CPtr: pass + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG) -> FileW | t.CPtr: pass diff --git a/Test/ZlibTest/temp/ffaa1aaa1355e604.pyi b/Test/ZlibTest/temp/ffaa1aaa1355e604.pyi new file mode 100644 index 0000000..7a9bc7c --- /dev/null +++ b/Test/ZlibTest/temp/ffaa1aaa1355e604.pyi @@ -0,0 +1,65 @@ +""" +Auto-generated Python stub file from __zlib.test_pyzlib.py +Module: __zlib.test_pyzlib +""" + + +from stdint import * +import pyzlib +import zhuff +import zdef +from stdio import printf, strlen +import stdlib +import string +import t, c + +test_passed: t.CExtern | t.CInt +test_failed: t.CExtern | t.CInt + +def check(name: str, condition: t.CInt, detail: str) -> t.CInt: pass + +def print_hex_test(data: BYTEPTR, length: t.CSizeT, max_show: t.CSizeT) -> t.CInt: pass + +def print_separator() -> t.CInt: pass + +def section_header(title: str) -> t.CInt: pass + +def section_footer() -> t.CInt: pass + +def test_version() -> t.CInt: pass + +def test_compress_decompress() -> t.CInt: pass + +def test_compress_levels() -> t.CInt: pass + +def test_compressobj() -> t.CInt: pass + +def test_decompressobj() -> t.CInt: pass + +def test_decompressobj_max_lengthgth() -> t.CInt: pass + +def test_decompressobj_unused_data() -> t.CInt: pass + +def test_compress_copy() -> t.CInt: pass + +def test_decompress_copy() -> t.CInt: pass + +def test_adler32() -> t.CInt: pass + +def test_crc32() -> t.CInt: pass + +def test_empty_compress() -> t.CInt: pass + +def test_gzip_format() -> t.CInt: pass + +def test_raw_deflate() -> t.CInt: pass + +def test_zdict() -> t.CInt: pass + +def test_huffman_tree() -> t.CInt: pass + +def test_error_handling() -> t.CInt: pass + +def test_constants() -> t.CInt: pass + +def main123456() -> t.CInt: pass diff --git a/Test/fbnq copy 2.py b/Test/fbnq copy 2.py new file mode 100644 index 0000000..a6939d9 --- /dev/null +++ b/Test/fbnq copy 2.py @@ -0,0 +1,147 @@ +from string import atoi +from stdlib import malloc, free +from stdint import * +import string +import w32.win32console +from stdarg import va_start, va_end, va_arg, va_list +import t +import c + + +class Struct1: + a: UINT + b: UINT = 123 +S1: list[Struct1, 5] = [ + Struct1(1, 2), + Struct1(b=3, a=4), + Struct1(a=5, b=6), + Struct1(7, b=8), + Struct1(9) +] +S1_: Struct1 = Struct1(10) +S1_2 = Struct1(112) + + +def reptr(p: UINT | t.CPtr, v: UINT): + c.Set(c.Deref(p), v) + +GLOBAL_VAR: t.CInt = 0 + +@t.Object +class OOPTest: + a: UINT + b: UINT = 12345 + c: UINT + def __init__(self): + self.a = 451 + def set_c(self, v: UINT): + self.c = v + global GLOBAL_VAR + GLOBAL_VAR = v + def __call__(self, a: UINT, b: UINT) -> UINT: + # print(a, b) + return a + b + def __enter__(self) -> 'OOPTest' | t.CPtr: + return self + def __exit__(self): + self.a = 99 + self.b = 99 + self.c = 99 + def __add__(self, other: 'OOPTest' | t.CPtr) -> 'OOPTest' | t.CPtr: + s = OOPTest() + s.a = (self.a + other.a) + return s + def print1(self): + print(114514) + def __str__(self) -> str: + return f"OOPTest ({self.a}) ({self.b}) ({self.c})" + def __delete__(self, instance): + print(f"delete {instance}") + def __bool__(self) -> bool: + return bool(self.a != 0) + def __len__(self) -> UINT: + return self.a + def __delitem__(self, key: UINT): + print(f"delitem {key}") + def __getitem__(self, key: UINT) -> UINT: + print(f"getitem {key}") + return self.a + def __setitem__(self, key: UINT, value: UINT): + print(f"setitem {key} {value}") + self.a = value + def __abs__(self) -> UINT: + if self.a < 0: + return -self.a + return self.a + + +@t.Object +class RangeOOPSimulation: + start: UINT + end: UINT + def __init__(self, start: UINT, end: UINT): + self.start = start + self.end = end + + def __iter__(self) -> 'RangeOOPSimulation' | t.CPtr: + return self + + def __next__(self) -> UINT: + if self.start >= self.end: + raise StopIteration + self.start += 1 + return self.start - 1 + +def main() -> t.CInt: + w32.win32console.SetConsoleOutputCP(65001) + w32.win32console.SetConsoleCP(65001) + + d = OOPTest() + d.set_c(1000000) + d.a = 1 + print("d.a: ", d.a) + print("d.b: ", d.b) + print("d.c: ", d.c) + #print(GLOBAL_VAR) + + with OOPTest() as d: + print("with __call__:", d(1, 2)) + print("_d.a: ", d.a) + print("_d.b: ", d.b) + print("_d.c: ", d.c) + + l = OOPTest() + l.a = 100 + (d + l).print1() + print("d + l.a: ", d.a + l.a) + print("(d + l).a: ", (d + l).a) + + print(f"d.a, l.a: {d.a} {l.a}") + print("d:", d) + + if d: + print("d.a 不是 zero, 说得对", d.a) + else: + print("d.a 是 zero, 说得对") + print("abs(d):", abs(d)) + print("len(d):", len(d)) + del d[114514] + d[114514] = 1145142 + + llll = "你好" + print(f"{llll},世界") + + for i in RangeOOPSimulation(0, 5 + 1): + print("RangeOOPSimulation:", i) + + free(d) + callit_args(0, 1, 2, "你知道", 666) + + +# args +def callit_args(a: t.CInt, *args): + print(arg(int), arg(int), arg(str), arg(int)) + #l: t.CInt = va_arg(args_va_list, int) + #print(l) + + diff --git a/Test/fbnq.py b/Test/fbnq.py new file mode 100644 index 0000000..aed2780 --- /dev/null +++ b/Test/fbnq.py @@ -0,0 +1,405 @@ +from stdlib import malloc, free +import ctypes +from stdint import * +import string +import w32.win32console +from stdarg import va_start, va_end, va_arg, va_list +import t +import c + + +class Struct1: + a: UINT + b: UINT = 123 + +S1: list[Struct1, 5] = [ + Struct1(1, 2), + Struct1(b=3, a=4), + Struct1(a=5, b=6), + Struct1(7, b=8), + Struct1(9) +] +S1_: Struct1 = Struct1(10) +S1_2 = Struct1(112) + + +def reptr(p: UINT | t.CPtr, v: UINT): + c.DerefAs(p, v) + +GLOBAL_VAR: t.CInt = 0 + +@t.Object +class OOPTest2: + fb: t.CVoid | t.CPtr + def __init__(self): + self.fb = malloc(1024) + for i in range(0, 1024): + self.fb[i] = '1' + c.Set(t.CChar(self.fb[1023], t.CPtr), '\0') + def GetFB(self) -> t.CChar | t.CPtr: + return t.CChar(self.fb, t.CPtr) + def __del__(self): + print("OOPTest2 __del__") + free(self.fb) + +@t.Object +class OOPTest: + a: UINT + b: UINT = 12345 + c: UINT + oop2: OOPTest2 | t.CPtr + def __init__(self): + self.a = 451 + self.oop2 = c.Addr(OOPTest2()) + # c.Set(c.Deref(self.oop2.GetFB()[0]), 1) + self.oop2.GetFB()[0] = '1' + cp = self.oop2.fb # t.CChar(self.oop2.fb, t.CPtr) + cp[1] = '4' + cp[2] = '5' + cp[3] = '6' + cp[4] = '7' + cp[5] = '8' + cp[6] = '9' + cp[7] = '0' + cp[8] = '9' + + print(t.CChar(cp[0], t.CPtr)) + print("长度:", t.CChar(cp, t.CPtr).__sizeof__()) + print("cp[0]:", cp[0]) + cp += 1 + print("cp[0]:", cp[0]) + cp += 1 + + print("self.oop2.GetFB()[0]:", int(cp[0])) + #k = t.CChar(self.oop2.fb[1], t.CPtr) + #k[0] = "4" + + cp -= 2 + # print(t.CChar(cp, t.CPtr)) + + lambda_a = lambda: 1 + print(cp[0], lambda_a()) + + print(type(cp)) + print(dir(OOPTest2)) + + vkt: t.CVoid | t.CPtr = malloc(1024) + c.Set(c.Deref(vkt[0]), 8080) + vkt[0] = '2' + # vkt[0] = 20 + print(t.CChar(vkt[0], t.CPtr)[0]) + print(type(vkt[0])) + print(t.CChar(t.CInt("Hello"), t.CPtr)) + print(str((c.Addr("你好")))) + # print(vkt) + free(vkt) + # print("vkt:", vkt) + + vkt: t.CVoid | t.CPtr = malloc(1024) + vkt2: t.CChar | t.CPtr = t.CChar(vkt, t.CPtr) + vkt2[0] = '1' + vkt2[100] = '1' + print("首个参数:", vkt2[0]) + print("第100参数:", vkt2[100]) + #print("HEX", str_to_hex(vkt)) + free(vkt) + print("HEX", str_to_hex("ABCDEFHIJKLMN")) + print("HEX", str_to_hex("1")) + + del self.oop2 + + +def str_to_hex(s: str) -> str: + buf: str = malloc(1024) + out: str = buf + hex: list[str, None] = "0123456789ABCDEF" + while c.Deref(s) != 0: + cr: t.CUnsignedChar = c.Deref(s) + c.Set(c.Deref(out), hex[(cr >> 4) & 0xF]) # 高 4 位 + out += 1 + c.Set(c.Deref(out), hex[cr & 0xF]) # 低 4 位 + out += 1 + s += 1 # 移动指针! + c.Set(c.Deref(out), 0) # 结尾 + return buf + +# 十进制 int → 16进制字符串(小写 0x 开头) +# 内部 malloc(128),外部必须 free() +def int_to_hex(num: int) -> str: + buf = t.CChar(malloc(128), t.CPtr) + if not buf: return None + + hex_chars: list[t.CChar, None] = "0123456789ABCDEF" + i = 0 + + # 先加 0x 前缀 + buf[i] = '0' + buf[i + 1] = 'x' + i += 2 + + # 处理 0 + if num == 0: + buf[i] = '0' + i += 1 + buf[i] = '0' + i += 1 + buf[i] = '\0' + return buf + + # 存储逆序的十六进制字符 + temp: list[t.CChar, 32] + temp_idx = 0 + + # 转为无符号,避免负数问题 + n: t.CUnsignedInt = t.CUnsignedInt(num) + + while n > 0: + rem: t.CInt = n & 0xF; # 取低4位(等价%16) + temp[temp_idx] = hex_chars[rem] + temp_idx += 1 + n = n >> 4; # 右移4位(等价/16) + + # 反转写入最终缓冲区 + while temp_idx > 0: + temp_idx -= 1 + buf[i] = temp[temp_idx] + i += 1 + + buf[i] = '\0' + return buf + + + +def int_to_str(num: int) -> str: + # 直接分配 128 字节(足够存任何 64 位整数) + buf: t.CChar | t.CPtr = t.CChar(malloc(128), t.CPtr) + if not buf: return None + is_negative = 0 + i = 0 + # 处理 0 + if num == 0: + buf[i] = '0' + i += 1 + buf[i] = '\0' + return buf + # 处理负数 + if num < 0: + is_negative = 1 + num = -num + # 生成逆序数字 + while num > 0: + rem = num % 10 + buf[i] = '0' + rem + i += 1 + num = num / 10 + # 负号 + if is_negative: + buf[i] = '-' + i += 1 + # 结束符 + buf[i] = '\0' + # 反转字符串 + start = 0 + end = i - 1 + while start < end: + tr: t.CChar = buf[start] + buf[start] = buf[end] + buf[end] = tr + start += 1 + end -= 1 + return buf + + + + + + + + + + +# 一个元素:存 数据指针 + 数据大小 +class Item: + data: t.CVoid | t.CPtr # i8* 数据指针 + size: t.CSizeT # 存字节大小(用于拷贝、释放) + +# 可变长列表 +class List: + items: Item | t.CPtr + count: t.CSizeT = 0 + capacity: t.CSizeT = 4 + # 初始化列表 + def __init__(self): + # l: List | t.CPtr = malloc(List.__sizeof__()) + self.count = 0 + self.capacity = 4 + self.items = malloc(self.capacity * Item.__sizeof__()) + + # 自动扩容 + def __grow(self): + if self.count >= self.capacity: + self.capacity *= 2 + self.items = realloc(self.items, self.capacity * Item.__sizeof__()) + + # 添加任意类型数据(深拷贝) + def append(self, data: t.CVoid | t.CPtr, size: t.CSizeT): + self.__grow() + item: Item | t.CPtr = self.items[self.count] + item.size = size + item.data = malloc(size + 1) + memcpy(item.data, data, size) + c.Set(t.CUnsignedChar(item.data + size, t.CPtr), '\0') + self.count += 1 + + # 获取元素:返回 i8*(int8_t*),强转 + def get(self, index: t.CSizeT) -> t.CInt8T | t.CPtr: + if index >= self.count: return None + return self.items[index].data + + def __getitem__(self, index: t.CSizeT) -> t.CInt8T | t.CPtr: + return self.get(index) + + # 销毁列表(所有内存全部释放) + def free(self): + i: t.CSizeT = 0 + for i in range(self.count): + if self.items[i].data != 0: + free(self.items[i].data) + free(self.items) + # free(self) + + + + + + +DEFINE_T: t.CDefine = 2423432423 + + +class EnumTest(t.CEnum): + A: t.State + B: t.State + C: t.State + Len: t.State + + +def main() -> t.CInt: + w32.win32console.SetConsoleOutputCP(65001) + w32.win32console.SetConsoleCP(65001) + + d = OOPTest() + + l = List() + nihao = "你好!世界,这是一个可变列表" + l.append(c.Addr(114514), t.CInt.__sizeof__()) + l.append(nihao, len(nihao)) + print("列表取值0:", c.Deref(t.CInt(l[0], t.CPtr))) + print("列表取值1:", l.get(1)) + l.free() + # free(l) + print("结束") + + # 未实现 + #a = t.CInt32T + #print(a(-1)) + #print(type(a(-1))) + + E: EnumTest = EnumTest.B + print(E) + print(EnumTest.Len) + + print(EnumTest(1)) + print(type(EnumTest.B)) + + # c.Asm("mov eax, 1", op=[t.ASM_DESCR.CLOBBER_EAX]) + + u = Union() + u.A.a = 114514 + u.A.b = 222222 + print("u.A.a", u.A.a) + print("u.A.b", u.A.b) + print("u.A.c", u.B.c) # -16558 + + wb = WBIT() + wb.a = 1 + wb.b = 1 + wb.c = 1 + wb.d = 12 + print(wb.a) + print(wb.b) + print(wb.c) + print(wb.d) + wb.a = 2 + print(wb.a) # 10 -> 0 -> 0 + print(wb.__sizeof__()) + print(type(wb)) + + ble = BLE() + ble.a = 0x114514 + ble.b = 0x114514 + print(ble.a) + print(ble.b) + print("a:", int_to_str(ble.a)) + print("a_hex:", str_to_hex(int_to_str(ble.a))) + print(int_to_hex(ble.a[0])) # 0x00114514 00 + print(int_to_hex(ble.a[1])) # 0x00114514 11 + print(int_to_hex(ble.a[2])) # 0x00114514 45 + print(int_to_hex(ble.a[3])) # 0x00114514 14 + + print(int_to_hex(ble.b[0])) # 0x00114514 14 + print(int_to_hex(ble.b[1])) # 0x00114514 45 + print(int_to_hex(ble.b[2])) # 0x00114514 11 + print(int_to_hex(ble.b[3])) # 0x00114514 00 + + li = 0x0000000100000001 + + #bool_ = 0 + #if bool_: + # tcls = t.CUInt32T + #else: + # tcls = LIWORK + #lx = tcls(li) + #print(type(lx)) + #print(lx.b) + #print("END") + #未能完全实现 + # x[-1]取值 + + print(DEFINE_T) + if c.CIf(DEFINE_T == 2423432423): + print("DEFINE_T == 2423432423") + elif c.CIf(DEFINE_T == 123): + print("DEFINE_T == 123") + else: + print("DEFINE_T != 2423432423 and DEFINE_T != 123") + #c.CIf + #c.CIfdef + #c.CIfndef + #c.CElif + #c.CElse + +class LIWORK: + a: t.CUInt32T + b: t.CUInt32T + +# class Union +class Union(t.CUnion): + class A: + a: t.CInt32T + b: t.CInt32T + class B: + c: t.CInt16T + d: t.CInt64T + +class WBIT: + a: t.CInt | t.Bit(1) + b: t.CInt | t.Bit(1) + c: t.CInt | t.Bit(1) + d: t.CInt | t.Bit(5) + +class BLE: + a: t.CInt | t.BigEndian + b: t.CInt | t.LittleEndian + + + diff --git a/Test/fbnq_out b/Test/fbnq_out new file mode 100644 index 0000000..888f849 --- /dev/null +++ b/Test/fbnq_out @@ -0,0 +1,676 @@ +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... +[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='OOPTest2', ctx=Load()), op=BitOr(), righ... +[GetCTypeInfo] Node type: Name, dump: Name(id='OOPTest2', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=At... +[GetCTypeInfo] Node type: Name, dump: Name(id='Item', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CDefine', ct... +[GetCTypeInfo-Attribute] 查询: 'CDefine' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='BigEndian', ... +[GetCTypeInfo-Attribute] 查询: 'BigEndian' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='LittleEndian... +[GetCTypeInfo-Attribute] 查询: 'LittleEndian' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='OOPTest2', ctx=Load()), op=BitOr(), righ... +[GetCTypeInfo] Node type: Name, dump: Name(id='OOPTest2', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='str', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='str', ctx=Load())... +[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... +[GetCTypeInfo] Node type: Name, dump: Name(id='str', ctx=Load())... +[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=At... +[GetCTypeInfo] Node type: Name, dump: Name(id='Item', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='EnumTest', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt64T' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='BigEndian', ... +[GetCTypeInfo-Attribute] 查询: 'BigEndian' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='LittleEndian... +[GetCTypeInfo-Attribute] 查询: 'LittleEndian' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedCha... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedChar' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=At... +[GetCTypeInfo] Node type: Name, dump: Name(id='Item', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt64T' ModulePath: t +=== AST Tree (Compact) === +Module(body=[ImportFrom(module='stdlib', names=[alias(name='malloc'), alias(name='free')], level=0), Import(names=[alias(name='ctypes')]), ImportFrom(module='stdint', names=[alias(name='*')], level=0), Import(names=[alias(name='string')]), Import(names=[alias(name='w32.win32console')]), ImportFrom(module='stdarg', names=[alias(name='va_start'), alias(name='va_end'), alias(name='va_arg'), alias(name='va_list')], level=0), Import(names=[alias(name='t')]), Import(names=[alias(name='c')]), ClassDef(name='Struct1', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), value=Constant(value=123), simple=1)], decorator_list=[], type_params=[]), AnnAssign(target=Name(id='S1', ctx=Store()), annotation=Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elts=[Name(id='Struct1', ctx=Load()), Constant(value=5)], ctx=Load()), ctx=Load()), value=List(elts=[Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=1), Constant(value=2)], keywords=[]), Call(func=Name(id='Struct1', ctx=Load()), args=[], keywords=[keyword(arg='b', value=Constant(value=3)), keyword(arg='a', value=Constant(value=4))]), Call(func=Name(id='Struct1', ctx=Load()), args=[], keywords=[keyword(arg='a', value=Constant(value=5)), keyword(arg='b', value=Constant(value=6))]), Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=7)], keywords=[keyword(arg='b', value=Constant(value=8))]), Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=9)], keywords=[])], ctx=Load()), simple=1), AnnAssign(target=Name(id='S1_', ctx=Store()), annotation=Name(id='Struct1', ctx=Load()), value=Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=10)], keywords=[]), simple=1), Assign(targets=[Name(id='S1_2', ctx=Store())], value=Call(func=Name(id='Struct1', ctx=Load()), args=[Constant(value=112)], keywords=[])), FunctionDef(name='reptr', args=arguments(posonlyargs=[], args=[arg(arg='p', annotation=BinOp(left=Name(id='UINT', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load()))), arg(arg='v', annotation=Name(id='UINT', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='DerefAs', ctx=Load()), args=[Name(id='p', ctx=Load()), Name(id='v', ctx=Load())], keywords=[]))], decorator_list=[], type_params=[]), AnnAssign(target=Name(id='GLOBAL_VAR', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), ClassDef(name='OOPTest2', bases=[], keywords=[], body=[AnnAssign(target=Name(id='fb', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), simple=1), FunctionDef(name='__init__', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Store())], value=Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=1024)], keywords=[])), For(target=Name(id='i', ctx=Store()), iter=Call(func=Name(id='range', ctx=Load()), args=[Constant(value=0), Constant(value=1024)], keywords=[]), body=[Assign(targets=[Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='1'))], orelse=[]), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Load()), slice=Constant(value=1023), ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), Constant(value='\x00')], keywords=[]))], decorator_list=[], type_params=[]), FunctionDef(name='GetFB', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Return(value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]))], decorator_list=[], returns=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), type_params=[]), FunctionDef(name='__del__', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='OOPTest2 __del__')], keywords=[])), Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='fb', ctx=Load())], keywords=[]))], decorator_list=[], type_params=[])], decorator_list=[Attribute(value=Name(id='t', ctx=Load()), attr='Object', ctx=Load())], type_params=[]), ClassDef(name='OOPTest', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), value=Constant(value=12345), simple=1), AnnAssign(target=Name(id='c', ctx=Store()), annotation=Name(id='UINT', ctx=Load()), simple=1), AnnAssign(target=Name(id='oop2', ctx=Store()), annotation=BinOp(left=Name(id='OOPTest2', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), simple=1), FunctionDef(name='__init__', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=451)), Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='oop2', ctx=Store())], value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Addr', ctx=Load()), args=[Call(func=Name(id='OOPTest2', ctx=Load()), args=[], keywords=[])], keywords=[])), Assign(targets=[Subscript(value=Call(func=Attribute(value=Attribute(value=Name(id='self', ctx=Load()), attr='oop2', ctx=Load()), attr='GetFB', ctx=Load()), args=[], keywords=[]), slice=Constant(value=0), ctx=Store())], value=Constant(value='1')), Assign(targets=[Name(id='cp', ctx=Store())], value=Attribute(value=Attribute(value=Name(id='self', ctx=Load()), attr='oop2', ctx=Load()), attr='fb', ctx=Load())), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=1), ctx=Store())], value=Constant(value='4')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=2), ctx=Store())], value=Constant(value='5')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=3), ctx=Store())], value=Constant(value='6')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=4), ctx=Store())], value=Constant(value='7')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=5), ctx=Store())], value=Constant(value='8')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=6), ctx=Store())], value=Constant(value='9')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=7), ctx=Store())], value=Constant(value='0')), Assign(targets=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=8), ctx=Store())], value=Constant(value='9')), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='长度:'), Call(func=Attribute(value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Name(id='cp', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), attr='__sizeof__', ctx=Load()), args=[], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='cp[0]:'), Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])), AugAssign(target=Name(id='cp', ctx=Store()), op=Add(), value=Constant(value=1)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='cp[0]:'), Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])), AugAssign(target=Name(id='cp', ctx=Store()), op=Add(), value=Constant(value=1)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='self.oop2.GetFB()[0]:'), Call(func=Name(id='int', ctx=Load()), args=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])], keywords=[])), AugAssign(target=Name(id='cp', ctx=Store()), op=Sub(), value=Constant(value=2)), Assign(targets=[Name(id='lambda_a', ctx=Store())], value=Lambda(args=arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]), body=Constant(value=1))), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Subscript(value=Name(id='cp', ctx=Load()), slice=Constant(value=0), ctx=Load()), Call(func=Name(id='lambda_a', ctx=Load()), args=[], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='type', ctx=Load()), args=[Name(id='cp', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='dir', ctx=Load()), args=[Name(id='OOPTest2', ctx=Load())], keywords=[])], keywords=[])), AnnAssign(target=Name(id='vkt', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=1024)], keywords=[]), simple=1), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Subscript(value=Name(id='vkt', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[]), Constant(value=8080)], keywords=[])), Assign(targets=[Subscript(value=Name(id='vkt', ctx=Load()), slice=Constant(value=0), ctx=Store())], value=Constant(value='2')), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Subscript(value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Subscript(value=Name(id='vkt', ctx=Load()), slice=Constant(value=0), ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), slice=Constant(value=0), ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='type', ctx=Load()), args=[Subscript(value=Name(id='vkt', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), args=[Constant(value='Hello')], keywords=[]), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='str', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Addr', ctx=Load()), args=[Constant(value='你好')], keywords=[])], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Name(id='vkt', ctx=Load())], keywords=[])), AnnAssign(target=Name(id='vkt', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=1024)], keywords=[]), simple=1), AnnAssign(target=Name(id='vkt2', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Name(id='vkt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), simple=1), Assign(targets=[Subscript(value=Name(id='vkt2', ctx=Load()), slice=Constant(value=0), ctx=Store())], value=Constant(value='1')), Assign(targets=[Subscript(value=Name(id='vkt2', ctx=Load()), slice=Constant(value=100), ctx=Store())], value=Constant(value='1')), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='首个参数:'), Subscript(value=Name(id='vkt2', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='第100参数:'), Subscript(value=Name(id='vkt2', ctx=Load()), slice=Constant(value=100), ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Name(id='vkt', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='HEX'), Call(func=Name(id='str_to_hex', ctx=Load()), args=[Constant(value='ABCDEFHIJKLMN')], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='HEX'), Call(func=Name(id='str_to_hex', ctx=Load()), args=[Constant(value='1')], keywords=[])], keywords=[])), Delete(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='oop2', ctx=Del())])], decorator_list=[], type_params=[])], decorator_list=[Attribute(value=Name(id='t', ctx=Load()), attr='Object', ctx=Load())], type_params=[]), FunctionDef(name='str_to_hex', args=arguments(posonlyargs=[], args=[arg(arg='s', annotation=Name(id='str', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='buf', ctx=Store()), annotation=Name(id='str', ctx=Load()), value=Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=1024)], keywords=[]), simple=1), AnnAssign(target=Name(id='out', ctx=Store()), annotation=Name(id='str', ctx=Load()), value=Name(id='buf', ctx=Load()), simple=1), AnnAssign(target=Name(id='hex', ctx=Store()), annotation=Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elts=[Name(id='str', ctx=Load()), Constant(value=None)], ctx=Load()), ctx=Load()), value=Constant(value='0123456789ABCDEF'), simple=1), While(test=Compare(left=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='s', ctx=Load())], keywords=[]), ops=[NotEq()], comparators=[Constant(value=0)]), body=[AnnAssign(target=Name(id='cr', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedChar', ctx=Load()), value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='s', ctx=Load())], keywords=[]), simple=1), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='out', ctx=Load())], keywords=[]), Subscript(value=Name(id='hex', ctx=Load()), slice=BinOp(left=BinOp(left=Name(id='cr', ctx=Load()), op=RShift(), right=Constant(value=4)), op=BitAnd(), right=Constant(value=15)), ctx=Load())], keywords=[])), AugAssign(target=Name(id='out', ctx=Store()), op=Add(), value=Constant(value=1)), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='out', ctx=Load())], keywords=[]), Subscript(value=Name(id='hex', ctx=Load()), slice=BinOp(left=Name(id='cr', ctx=Load()), op=BitAnd(), right=Constant(value=15)), ctx=Load())], keywords=[])), AugAssign(target=Name(id='out', ctx=Store()), op=Add(), value=Constant(value=1)), AugAssign(target=Name(id='s', ctx=Store()), op=Add(), value=Constant(value=1))], orelse=[]), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Name(id='out', ctx=Load())], keywords=[]), Constant(value=0)], keywords=[])), Return(value=Name(id='buf', ctx=Load()))], decorator_list=[], returns=Name(id='str', ctx=Load()), type_params=[]), FunctionDef(name='int_to_hex', args=arguments(posonlyargs=[], args=[arg(arg='num', annotation=Name(id='int', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Assign(targets=[Name(id='buf', ctx=Store())], value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=128)], keywords=[]), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[])), If(test=UnaryOp(op=Not(), operand=Name(id='buf', ctx=Load())), body=[Return(value=Constant(value=None))], orelse=[]), AnnAssign(target=Name(id='hex_chars', ctx=Store()), annotation=Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elts=[Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), Constant(value=None)], ctx=Load()), ctx=Load()), value=Constant(value='0123456789ABCDEF'), simple=1), Assign(targets=[Name(id='i', ctx=Store())], value=Constant(value=0)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='0')), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=BinOp(left=Name(id='i', ctx=Load()), op=Add(), right=Constant(value=1)), ctx=Store())], value=Constant(value='x')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=2)), If(test=Compare(left=Name(id='num', ctx=Load()), ops=[Eq()], comparators=[Constant(value=0)]), body=[Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='0')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='0')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='\x00')), Return(value=Name(id='buf', ctx=Load()))], orelse=[]), AnnAssign(target=Name(id='temp', ctx=Store()), annotation=Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elts=[Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), Constant(value=32)], ctx=Load()), ctx=Load()), simple=1), Assign(targets=[Name(id='temp_idx', ctx=Store())], value=Constant(value=0)), AnnAssign(target=Name(id='n', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt', ctx=Load()), value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt', ctx=Load()), args=[Name(id='num', ctx=Load())], keywords=[]), simple=1), While(test=Compare(left=Name(id='n', ctx=Load()), ops=[Gt()], comparators=[Constant(value=0)]), body=[AnnAssign(target=Name(id='rem', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=Name(id='n', ctx=Load()), op=BitAnd(), right=Constant(value=15)), simple=1), Assign(targets=[Subscript(value=Name(id='temp', ctx=Load()), slice=Name(id='temp_idx', ctx=Load()), ctx=Store())], value=Subscript(value=Name(id='hex_chars', ctx=Load()), slice=Name(id='rem', ctx=Load()), ctx=Load())), AugAssign(target=Name(id='temp_idx', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Name(id='n', ctx=Store())], value=BinOp(left=Name(id='n', ctx=Load()), op=RShift(), right=Constant(value=4)))], orelse=[]), While(test=Compare(left=Name(id='temp_idx', ctx=Load()), ops=[Gt()], comparators=[Constant(value=0)]), body=[AugAssign(target=Name(id='temp_idx', ctx=Store()), op=Sub(), value=Constant(value=1)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Subscript(value=Name(id='temp', ctx=Load()), slice=Name(id='temp_idx', ctx=Load()), ctx=Load())), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1))], orelse=[]), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='\x00')), Return(value=Name(id='buf', ctx=Load()))], decorator_list=[], returns=Name(id='str', ctx=Load()), type_params=[]), FunctionDef(name='int_to_str', args=arguments(posonlyargs=[], args=[arg(arg='num', annotation=Name(id='int', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='buf', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), args=[Call(func=Name(id='malloc', ctx=Load()), args=[Constant(value=128)], keywords=[]), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), simple=1), If(test=UnaryOp(op=Not(), operand=Name(id='buf', ctx=Load())), body=[Return(value=Constant(value=None))], orelse=[]), Assign(targets=[Name(id='is_negative', ctx=Store())], value=Constant(value=0)), Assign(targets=[Name(id='i', ctx=Store())], value=Constant(value=0)), If(test=Compare(left=Name(id='num', ctx=Load()), ops=[Eq()], comparators=[Constant(value=0)]), body=[Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='0')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='\x00')), Return(value=Name(id='buf', ctx=Load()))], orelse=[]), If(test=Compare(left=Name(id='num', ctx=Load()), ops=[Lt()], comparators=[Constant(value=0)]), body=[Assign(targets=[Name(id='is_negative', ctx=Store())], value=Constant(value=1)), Assign(targets=[Name(id='num', ctx=Store())], value=UnaryOp(op=USub(), operand=Name(id='num', ctx=Load())))], orelse=[]), While(test=Compare(left=Name(id='num', ctx=Load()), ops=[Gt()], comparators=[Constant(value=0)]), body=[Assign(targets=[Name(id='rem', ctx=Store())], value=BinOp(left=Name(id='num', ctx=Load()), op=Mod(), right=Constant(value=10))), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=BinOp(left=Constant(value='0'), op=Add(), right=Name(id='rem', ctx=Load()))), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1)), Assign(targets=[Name(id='num', ctx=Store())], value=BinOp(left=Name(id='num', ctx=Load()), op=Div(), right=Constant(value=10)))], orelse=[]), If(test=Name(id='is_negative', ctx=Load()), body=[Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='-')), AugAssign(target=Name(id='i', ctx=Store()), op=Add(), value=Constant(value=1))], orelse=[]), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Store())], value=Constant(value='\x00')), Assign(targets=[Name(id='start', ctx=Store())], value=Constant(value=0)), Assign(targets=[Name(id='end', ctx=Store())], value=BinOp(left=Name(id='i', ctx=Load()), op=Sub(), right=Constant(value=1))), While(test=Compare(left=Name(id='start', ctx=Load()), ops=[Lt()], comparators=[Name(id='end', ctx=Load())]), body=[AnnAssign(target=Name(id='tr', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=Load()), value=Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='start', ctx=Load()), ctx=Load()), simple=1), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='start', ctx=Load()), ctx=Store())], value=Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='end', ctx=Load()), ctx=Load())), Assign(targets=[Subscript(value=Name(id='buf', ctx=Load()), slice=Name(id='end', ctx=Load()), ctx=Store())], value=Name(id='tr', ctx=Load())), AugAssign(target=Name(id='start', ctx=Store()), op=Add(), value=Constant(value=1)), AugAssign(target=Name(id='end', ctx=Store()), op=Sub(), value=Constant(value=1))], orelse=[]), Return(value=Name(id='buf', ctx=Load()))], decorator_list=[], returns=Name(id='str', ctx=Load()), type_params=[]), ClassDef(name='Item', bases=[], keywords=[], body=[AnnAssign(target=Name(id='data', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), simple=1), AnnAssign(target=Name(id='size', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()), simple=1)], decorator_list=[], type_params=[]), ClassDef(name='List', bases=[], keywords=[], body=[AnnAssign(target=Name(id='items', ctx=Store()), annotation=BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), simple=1), AnnAssign(target=Name(id='count', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='capacity', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()), value=Constant(value=4), simple=1), FunctionDef(name='__init__', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Store())], value=Constant(value=0)), Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Store())], value=Constant(value=4)), Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Store())], value=Call(func=Name(id='malloc', ctx=Load()), args=[BinOp(left=Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Load()), op=Mult(), right=Call(func=Attribute(value=Name(id='Item', ctx=Load()), attr='__sizeof__', ctx=Load()), args=[], keywords=[]))], keywords=[]))], decorator_list=[], type_params=[]), FunctionDef(name='__grow', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[If(test=Compare(left=Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Load()), ops=[GtE()], comparators=[Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Load())]), body=[AugAssign(target=Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Store()), op=Mult(), value=Constant(value=2)), Assign(targets=[Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Store())], value=Call(func=Name(id='realloc', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), BinOp(left=Attribute(value=Name(id='self', ctx=Load()), attr='capacity', ctx=Load()), op=Mult(), right=Call(func=Attribute(value=Name(id='Item', ctx=Load()), attr='__sizeof__', ctx=Load()), args=[], keywords=[]))], keywords=[]))], orelse=[])], decorator_list=[], type_params=[]), FunctionDef(name='append', args=arguments(posonlyargs=[], args=[arg(arg='self'), arg(arg='data', annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load()))), arg(arg='size', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Expr(value=Call(func=Attribute(value=Name(id='self', ctx=Load()), attr='__grow', ctx=Load()), args=[], keywords=[])), AnnAssign(target=Name(id='item', ctx=Store()), annotation=BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), value=Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), slice=Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Load()), ctx=Load()), simple=1), Assign(targets=[Attribute(value=Name(id='item', ctx=Load()), attr='size', ctx=Store())], value=Name(id='size', ctx=Load())), Assign(targets=[Attribute(value=Name(id='item', ctx=Load()), attr='data', ctx=Store())], value=Call(func=Name(id='malloc', ctx=Load()), args=[BinOp(left=Name(id='size', ctx=Load()), op=Add(), right=Constant(value=1))], keywords=[])), Expr(value=Call(func=Name(id='memcpy', ctx=Load()), args=[Attribute(value=Name(id='item', ctx=Load()), attr='data', ctx=Load()), Name(id='data', ctx=Load()), Name(id='size', ctx=Load())], keywords=[])), Expr(value=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Set', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedChar', ctx=Load()), args=[BinOp(left=Attribute(value=Name(id='item', ctx=Load()), attr='data', ctx=Load()), op=Add(), right=Name(id='size', ctx=Load())), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[]), Constant(value='\x00')], keywords=[])), AugAssign(target=Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Store()), op=Add(), value=Constant(value=1))], decorator_list=[], type_params=[]), FunctionDef(name='get', args=arguments(posonlyargs=[], args=[arg(arg='self'), arg(arg='index', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[If(test=Compare(left=Name(id='index', ctx=Load()), ops=[GtE()], comparators=[Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Load())]), body=[Return(value=Constant(value=None))], orelse=[]), Return(value=Attribute(value=Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), slice=Name(id='index', ctx=Load()), ctx=Load()), attr='data', ctx=Load()))], decorator_list=[], returns=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt8T', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), type_params=[]), FunctionDef(name='__getitem__', args=arguments(posonlyargs=[], args=[arg(arg='self'), arg(arg='index', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Return(value=Call(func=Attribute(value=Name(id='self', ctx=Load()), attr='get', ctx=Load()), args=[Name(id='index', ctx=Load())], keywords=[]))], decorator_list=[], returns=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt8T', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())), type_params=[]), FunctionDef(name='free', args=arguments(posonlyargs=[], args=[arg(arg='self')], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='i', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx=Load()), value=Constant(value=0), simple=1), For(target=Name(id='i', ctx=Store()), iter=Call(func=Name(id='range', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='count', ctx=Load())], keywords=[]), body=[If(test=Compare(left=Attribute(value=Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Load()), attr='data', ctx=Load()), ops=[NotEq()], comparators=[Constant(value=0)]), body=[Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Attribute(value=Subscript(value=Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load()), slice=Name(id='i', ctx=Load()), ctx=Load()), attr='data', ctx=Load())], keywords=[]))], orelse=[])], orelse=[]), Expr(value=Call(func=Name(id='free', ctx=Load()), args=[Attribute(value=Name(id='self', ctx=Load()), attr='items', ctx=Load())], keywords=[]))], decorator_list=[], type_params=[])], decorator_list=[], type_params=[]), AnnAssign(target=Name(id='DEFINE_T', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CDefine', ctx=Load()), value=Constant(value=2423432423), simple=1), ClassDef(name='EnumTest', bases=[Attribute(value=Name(id='t', ctx=Load()), attr='CEnum', ctx=Load())], keywords=[], body=[AnnAssign(target=Name(id='A', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=Load()), simple=1), AnnAssign(target=Name(id='B', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=Load()), simple=1), AnnAssign(target=Name(id='C', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=Load()), simple=1), AnnAssign(target=Name(id='Len', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=Load()), simple=1)], decorator_list=[], type_params=[]), FunctionDef(name='main', args=arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[Expr(value=Call(func=Attribute(value=Attribute(value=Name(id='w32', ctx=Load()), attr='win32console', ctx=Load()), attr='SetConsoleOutputCP', ctx=Load()), args=[Constant(value=65001)], keywords=[])), Expr(value=Call(func=Attribute(value=Attribute(value=Name(id='w32', ctx=Load()), attr='win32console', ctx=Load()), attr='SetConsoleCP', ctx=Load()), args=[Constant(value=65001)], keywords=[])), Assign(targets=[Name(id='d', ctx=Store())], value=Call(func=Name(id='OOPTest', ctx=Load()), args=[], keywords=[])), Assign(targets=[Name(id='l', ctx=Store())], value=Call(func=Name(id='List', ctx=Load()), args=[], keywords=[])), Assign(targets=[Name(id='nihao', ctx=Store())], value=Constant(value='你好!世界,这是一个可变列表')), Expr(value=Call(func=Attribute(value=Name(id='l', ctx=Load()), attr='append', ctx=Load()), args=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Addr', ctx=Load()), args=[Constant(value=114514)], keywords=[]), Call(func=Attribute(value=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), attr='__sizeof__', ctx=Load()), args=[], keywords=[])], keywords=[])), Expr(value=Call(func=Attribute(value=Name(id='l', ctx=Load()), attr='append', ctx=Load()), args=[Name(id='nihao', ctx=Load()), Call(func=Name(id='len', ctx=Load()), args=[Name(id='nihao', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='列表取值0:'), Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='Cast', ctx=Load()), args=[Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), args=[Subscript(value=Name(id='l', ctx=Load()), slice=Constant(value=0), ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=Load())], keywords=[])], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='列表取值1:'), Call(func=Attribute(value=Name(id='l', ctx=Load()), attr='get', ctx=Load()), args=[Constant(value=1)], keywords=[])], keywords=[])), Expr(value=Call(func=Attribute(value=Name(id='l', ctx=Load()), attr='free', ctx=Load()), args=[], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='结束')], keywords=[])), AnnAssign(target=Name(id='E', ctx=Store()), annotation=Name(id='EnumTest', ctx=Load()), value=Attribute(value=Name(id='EnumTest', ctx=Load()), attr='B', ctx=Load()), simple=1), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Name(id='E', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='EnumTest', ctx=Load()), attr='Len', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='EnumTest', ctx=Load()), args=[Constant(value=1)], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='type', ctx=Load()), args=[Attribute(value=Name(id='EnumTest', ctx=Load()), attr='B', ctx=Load())], keywords=[])], keywords=[])), Assign(targets=[Name(id='u', ctx=Store())], value=Call(func=Name(id='Union', ctx=Load()), args=[], keywords=[])), Assign(targets=[Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='A', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=114514)), Assign(targets=[Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='A', ctx=Load()), attr='b', ctx=Store())], value=Constant(value=222222)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='u.A.a'), Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='A', ctx=Load()), attr='a', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='u.A.b'), Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='A', ctx=Load()), attr='b', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='u.A.c'), Attribute(value=Attribute(value=Name(id='u', ctx=Load()), attr='B', ctx=Load()), attr='c', ctx=Load())], keywords=[])), Assign(targets=[Name(id='wb', ctx=Store())], value=Call(func=Name(id='WBIT', ctx=Load()), args=[], keywords=[])), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=1)), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='b', ctx=Store())], value=Constant(value=1)), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='c', ctx=Store())], value=Constant(value=1)), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='d', ctx=Store())], value=Constant(value=12)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='a', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='b', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='c', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='d', ctx=Load())], keywords=[])), Assign(targets=[Attribute(value=Name(id='wb', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=2)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='wb', ctx=Load()), attr='a', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Attribute(value=Name(id='wb', ctx=Load()), attr='__sizeof__', ctx=Load()), args=[], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='type', ctx=Load()), args=[Name(id='wb', ctx=Load())], keywords=[])], keywords=[])), Assign(targets=[Name(id='ble', ctx=Store())], value=Call(func=Name(id='BLE', ctx=Load()), args=[], keywords=[])), Assign(targets=[Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Store())], value=Constant(value=1131796)), Assign(targets=[Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Store())], value=Constant(value=1131796)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load())], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='a:'), Call(func=Name(id='int_to_str', ctx=Load()), args=[Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='a_hex:'), Call(func=Name(id='str_to_hex', ctx=Load()), args=[Call(func=Name(id='int_to_str', ctx=Load()), args=[Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load())], keywords=[])], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load()), slice=Constant(value=1), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load()), slice=Constant(value=2), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='a', ctx=Load()), slice=Constant(value=3), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load()), slice=Constant(value=0), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load()), slice=Constant(value=1), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load()), slice=Constant(value=2), ctx=Load())], keywords=[])], keywords=[])), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Call(func=Name(id='int_to_hex', ctx=Load()), args=[Subscript(value=Attribute(value=Name(id='ble', ctx=Load()), attr='b', ctx=Load()), slice=Constant(value=3), ctx=Load())], keywords=[])], keywords=[])), Assign(targets=[Name(id='li', ctx=Store())], value=Constant(value=4294967297)), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Name(id='DEFINE_T', ctx=Load())], keywords=[])), If(test=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='CIf', ctx=Load()), args=[Compare(left=Name(id='DEFINE_T', ctx=Load()), ops=[Eq()], comparators=[Constant(value=2423432423)])], keywords=[]), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='DEFINE_T == 2423432423')], keywords=[]))], orelse=[If(test=Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='CIf', ctx=Load()), args=[Compare(left=Name(id='DEFINE_T', ctx=Load()), ops=[Eq()], comparators=[Constant(value=123)])], keywords=[]), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='DEFINE_T == 123')], keywords=[]))], orelse=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='DEFINE_T != 2423432423 and DEFINE_T != 123')], keywords=[]))])])], decorator_list=[], returns=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), type_params=[]), ClassDef(name='LIWORK', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', ctx=Load()), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', ctx=Load()), simple=1)], decorator_list=[], type_params=[]), ClassDef(name='Union', bases=[Attribute(value=Name(id='t', ctx=Load()), attr='CUnion', ctx=Load())], keywords=[], body=[ClassDef(name='A', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ctx=Load()), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ctx=Load()), simple=1)], decorator_list=[], type_params=[]), ClassDef(name='B', bases=[], keywords=[], body=[AnnAssign(target=Name(id='c', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ctx=Load()), simple=1), AnnAssign(target=Name(id='d', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ctx=Load()), simple=1)], decorator_list=[], type_params=[])], decorator_list=[], type_params=[]), ClassDef(name='WBIT', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='Bit', ctx=Load()), args=[Constant(value=1)], keywords=[])), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='Bit', ctx=Load()), args=[Constant(value=1)], keywords=[])), simple=1), AnnAssign(target=Name(id='c', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='Bit', ctx=Load()), args=[Constant(value=1)], keywords=[])), simple=1), AnnAssign(target=Name(id='d', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Call(func=Attribute(value=Name(id='t', ctx=Load()), attr='Bit', ctx=Load()), args=[Constant(value=5)], keywords=[])), simple=1)], decorator_list=[], type_params=[]), ClassDef(name='BLE', bases=[], keywords=[], body=[AnnAssign(target=Name(id='a', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='BigEndian', ctx=Load())), simple=1), AnnAssign(target=Name(id='b', ctx=Store()), annotation=BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), op=BitOr(), right=Attribute(value=Name(id='t', ctx=Load()), attr='LittleEndian', ctx=Load())), simple=1)], decorator_list=[], type_params=[])], type_ignores=[]) + +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... +[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='OOPTest2', ctx=Load()), op=BitOr(), righ... +[GetCTypeInfo] Node type: Name, dump: Name(id='OOPTest2', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Name(id='Item', ctx=Load()), op=BitOr(), right=At... +[GetCTypeInfo] Node type: Name, dump: Name(id='Item', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CDefine', ct... +[GetCTypeInfo-Attribute] 查询: 'CDefine' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='BigEndian', ... +[GetCTypeInfo-Attribute] 查询: 'BigEndian' ModulePath: t +[GetCTypeInfo] Node type: BinOp, dump: BinOp(left=Attribute(value=Name(id='t', ctx=Load()), attr='C... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='LittleEndian... +[GetCTypeInfo-Attribute] 查询: 'LittleEndian' ModulePath: t +[GetCTypeInfo] Node type: Subscript, dump: Subscript(value=Name(id='list', ctx=Load()), slice=Tuple(elt... +[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='Struct1', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CDefine', ct... +[GetCTypeInfo-Attribute] 查询: 'CDefine' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExtern', ct... +[GetCTypeInfo-Attribute] 查询: 'CExtern' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... +[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExtern', ct... +[GetCTypeInfo-Attribute] 查询: 'CExtern' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... +[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t +[GetCTypeInfo] Node type: Constant, dump: Constant(value=None)... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedInt' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedCha... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedChar' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BYTE', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt16T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt64T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt64T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='str', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CShort', ctx... +[GetCTypeInfo-Attribute] 查询: 'CShort' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CShort', ctx... +[GetCTypeInfo-Attribute] 查询: 'CShort' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedSho... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedShort' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedSho... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedShort' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedLon... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedLong' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CLong', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CLong' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedLon... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedLong' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='WORD', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='WORD', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='DWORD', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='DWORD', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedInt... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat', ctx... +[GetCTypeInfo-Attribute] 查询: 'CFloat' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CDouble', ct... +[GetCTypeInfo-Attribute] 查询: 'CDouble' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat8T', c... +[GetCTypeInfo-Attribute] 查询: 'CFloat8T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat16T', ... +[GetCTypeInfo-Attribute] 查询: 'CFloat16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat32T', ... +[GetCTypeInfo-Attribute] 查询: 'CFloat32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat64T', ... +[GetCTypeInfo-Attribute] 查询: 'CFloat64T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CFloat128T',... +[GetCTypeInfo-Attribute] 查询: 'CFloat128T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt8T', ctx... +[GetCTypeInfo-Attribute] 查询: 'CInt8T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt64T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt8T', ct... +[GetCTypeInfo-Attribute] 查询: 'CUInt8T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt16T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt64T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt64T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt8T', ctx... +[GetCTypeInfo-Attribute] 查询: 'CInt8T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt16T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt32T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt64T', ct... +[GetCTypeInfo-Attribute] 查询: 'CInt64T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt8T', ct... +[GetCTypeInfo-Attribute] 查询: 'CUInt8T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt16T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt32T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUInt64T', c... +[GetCTypeInfo-Attribute] 查询: 'CUInt64T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar8T', ct... +[GetCTypeInfo-Attribute] 查询: 'CChar8T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar16T', c... +[GetCTypeInfo-Attribute] 查询: 'CChar16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar32T', c... +[GetCTypeInfo-Attribute] 查询: 'CChar32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar8T', ct... +[GetCTypeInfo-Attribute] 查询: 'CChar8T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar16T', c... +[GetCTypeInfo-Attribute] 查询: 'CChar16T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar32T', c... +[GetCTypeInfo-Attribute] 查询: 'CChar32T' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CSizeT', ctx... +[GetCTypeInfo-Attribute] 查询: 'CSizeT' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... +[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... +[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... +[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CVoid', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CVoid' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='CONSOLE_SCREEN_BUFFER_INFO', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='CONSOLE_CURSOR_INFO', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='CONSOLE_CURSOR_INFO', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CConst', ctx... +[GetCTypeInfo-Attribute] 查询: 'CConst' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='VOIDPTR', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CConst', ctx... +[GetCTypeInfo-Attribute] 查询: 'CConst' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='VOIDPTR', ctx=Load())... +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='INPUT_RECORD', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='INPUT_RECORD', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='ULONG', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='SMALL_RECT', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='BOOL', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='SMALL_RECT', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='SMALL_RECT', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='CHAR_INFO', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CUnsignedCha... +[GetCTypeInfo-Attribute] 查询: 'CUnsignedChar' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='State', ctx=... +[GetCTypeInfo-Attribute] 查询: 'State' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExtern', ct... +[GetCTypeInfo-Attribute] 查询: 'CExtern' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CExport', ct... +[GetCTypeInfo-Attribute] 查询: 'CExport' ModulePath: t +[GetCTypeInfo] Node type: Name, dump: Name(id='UINT', ctx=Load())... +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CChar', ctx=... +[GetCTypeInfo-Attribute] 查询: 'CChar' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CPtr', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CPtr' ModulePath: t diff --git a/Test/test.py b/Test/test.py new file mode 100644 index 0000000..01d8764 --- /dev/null +++ b/Test/test.py @@ -0,0 +1,133 @@ +import t, c +# import stdint + + +MAX_ORDER = 123 + +print + +@t.Object +class ClassObject: + k: t.CInt + def __init__(self, k: t.CInt): + self.k = k + def __enter__(self) -> 'ClassObject': + return c.Deref(self) + def __exit__(self): + self.work() + def work(self): + print(1) + +@t.Object +class ClassObject1(ClassObject): + def __init__(self): + super().__init__(123) + ClassObject.__init__(self, 123) + +class ClassObject2: + a: t.CInt + b: t.CInt + c: t.CInt + +LONGLONG1: t.CTypedef = t.CLong +LONGLONG2: t.CTypedef | t.CLong | t.CLong +LONGLONG3: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong + +class A: + a: int +class B: + b: int +ccc: list[B, 1212] | t.CPtr = [] +ccc[0].b + +class memory_block: + f: t.CInt + +class __buddy_system(t.CStruct): + free_lists1: list[memory_block, 1] | t.CPtr # 空闲块链表 + free_lists1: list[memory_block, 1] | t.CPtr # 空闲块链表 + free_lists2: list[memory_block, MAX_ORDER] | t.CPtr # 空闲块链表 + free_lists3: list[memory_block, 1 + 1] | t.CPtr # 空闲块链表 + free_lists4: list[memory_block, MAX_ORDER + 1] | t.CPtr[t.CArrayPtr[t.CArrayPtr]] # 空闲块链表 + total_memory: t.CUInt64T # 总内存大小 + used_memory: t.CUInt64T # 已使用内存大小 + free_memory: t.CUInt64T # 空闲内存大小 + start_addr: t.CVoid | t.CPtr # 内存起始地址 + end_addr: t.CVoid | t.CPtr # 内存结束地址 + +UINT1: t.CTypedef = t.CUnsignedInt +UINT: t.CTypedef | t.CUnsignedInt # int must be 16-bit or 32-bit +BYTE: t.CTypedef | t.CUnsignedChar # char must be 8-bit +WORD: t.CTypedef | t.CUInt16T # 16-bit unsigned +DWORD: t.CTypedef | t.CUInt32T # 32-bit unsigned +QWORD: t.CTypedef | t.CUInt64T # 64-bit unsigned +TCHAR: t.CTypedef | t.CChar +WCHAR: t.CTypedef | WORD # UTF-16 code unit +FSIZE_t: t.CTypedef | DWORD +LBA_t: t.CTypedef | DWORD + +def DEF_NAMEBUFF() -> t.CDefine: + lfn: WCHAR | t.CPtr # Pointer to LFN working buffer and directory entry block scratchpad buffer + +def add(a: t.CInt, b: t.CInt) -> t.CConst | t.CInt | t.CPtr[t.CPtr]: + return c.Deref(c.Deref((a + b))) + +def main(l: t.CInt = 1): + kkkkkkkkkkkk1: UINT1 + kkkkkkkkkkkk2: UINT + print(kkkkkkkkkkkk1 + kkkkkkkkkkkkk2) + ssr: ClassObject | t.CPtr = ClassObject(6) + with ClassObject(1) as a: + a.work() + aaa: t.CInt | t.CPtr[t.CPtr] + cursor: t.CConst | t.CChar[112] | t.CArrayPtr[t.CArrayPtr] + k = add(1, 2) + + co2: ClassObject2 + co22: ClassObject2 = ClassObject2() + co23 = ClassObject2(a=1, b=1) + + b: ClassObject | t.CPtr = malloc(ClassObject.__sizeof__()) + b = ClassObject(1) + with b as llll: + llll.work() + + match (l): + case 1: + print(1) + case 2: + print(2) + case _: + print(3) + if l == 3 and k == 1: + c.Break() + print(4) + c.NoBreak() + match 3: + case 1: + print(1) + case 2: + print(2) + case _: + print(3) + if l == 3 and k == 1: + c.Break() + print(4) + c.NoBreak() + # a := b 格式 + + UINT(123, t.CPtr).__sizeof__() # enum,union的实例化也和typedef一样 + x: t.CInt + if (x := k) and 666: + print(x) + + t.CType(123, UINT).__sizeof__() + + DEF_NAMEBUFF + + len(x) + + math_test: t.CInt = 1+1-2+(3*4/2+1-6)/12+9*9 + +import base64 \ No newline at end of file diff --git a/TransPyC.py b/TransPyC.py new file mode 100644 index 0000000..4e17cc3 --- /dev/null +++ b/TransPyC.py @@ -0,0 +1,715 @@ +# TransPyC 入口程序 + +import sys +import os +import ast +import json +import struct +# 添加lib目录到Python路径 +sys.path.append(os.path.join(os.path.dirname(__file__), 'lib', 'includes')) +from lib.includes import c +from lib.includes import t +from lib.constants.config import ( + DEFAULT_INPUT_FILE, DEFAULT_OUTPUT_FILE, + DEFAULT_COMPILE_COMMAND, + DEFAULT_COMPILE_FLAGS, ERROR_MESSAGES, + HELP_MESSAGE, DEFAULT_METADATA +) +from lib.utils.helpers import ( + DetectFileType, ExecuteCommand, + AppendFileContent +) +from lib.core.translator import Translator + + +def SerializeSymbolTable(SymbolTable: dict) -> bytes: + """将符号表序列化为二进制格式 + + 格式: + - 4字节: JSON数据长度(小端序) + - N字节: JSON数据(UTF-8编码) + + Args: + SymbolTable: 符号表字典 + + Returns: + 二进制字节数据 + """ + JsonData = json.dumps(SymbolTable, ensure_ascii=False).encode('utf-8') + length = len(JsonData) + # 使用4字节小端序整数表示长度 + header = struct.pack(' dict: + """从二进制数据反序列化符号表 + + Args: + data: 二进制字节数据 + + Returns: + 符号表字典 + """ + if len(data) < 4: + raise ValueError("Invalid symbin file: data too short") + # 解析4字节长度头(小端序) + length = struct.unpack(' -o [-debug ] + if I + 1 < len(sys.argv): + InputFile = sys.argv[I + 1] + I += 2 + + # 解析可选参数 + OutputFile = None + DebugFile = None + while I < len(sys.argv) and sys.argv[I].startswith('-'): + if sys.argv[I] == '-o': + if I + 1 < len(sys.argv): + OutputFile = sys.argv[I + 1] + I += 2 + else: + print(f'Error: -o requires an argument') + sys.exit(1) + elif sys.argv[I] == '-debug': + if I + 1 < len(sys.argv): + DebugFile = sys.argv[I + 1] + I += 2 + else: + print(f'Error: -debug requires an argument') + sys.exit(1) + else: + break + + # 如果没有指定输出文件,使用默认名称 + if not OutputFile: + OutputFile = InputFile.replace('.py', '.symbin').replace('.c', '.symbin') + + # 执行预处理 + self.Args['PreSym'] = { + 'input': InputFile, + 'output': OutputFile, + 'debug': DebugFile + } + else: + print(f'Error: -presym requires an argument') + sys.exit(1) + elif sys.argv[I] == '-e' or sys.argv[I] == '--encoding': + if I + 1 < len(sys.argv): + self.Args['Encoding'] = sys.argv[I + 1] + I += 2 + else: + print(f'Error: -e/--encoding requires an argument') + sys.exit(1) + elif sys.argv[I] == '--triple': + if I + 1 < len(sys.argv): + self.triple = sys.argv[I + 1] + I += 2 + else: + print(f'Error: --triple requires an argument') + sys.exit(1) + elif sys.argv[I] == '--datalayout': + if I + 1 < len(sys.argv): + self.datalayout = sys.argv[I + 1] + I += 2 + else: + print(f'Error: --datalayout requires an argument') + sys.exit(1) + else: + print(f'Error: Unknown argument {sys.argv[I]}') + sys.exit(1) + + # 检查是否有预处理符号文件的请求,如果有则跳过输入输出检查 + if 'PreSym' not in self.Args and ('Input' not in self.Args or 'Output' not in self.Args): + print(ERROR_MESSAGES['MISSING_ARGS']) + print(HELP_MESSAGE) + sys.exit(1) + + def CompileAndRun(self, OutputFile): + """编译并运行生成的C代码""" + # 获取编译命令 + CompileCmd = self.Args.get('CompileCommand', DEFAULT_COMPILE_COMMAND) + CompileFlags = self.Args.get('CompileFlags', DEFAULT_COMPILE_FLAGS) + + # 构建编译命令 + FullCompileCmd = f'{CompileCmd} {CompileFlags} {OutputFile} -o {OutputFile}.exe' + print(f'Compiling: {FullCompileCmd}') + + # 执行编译命令 + try: + CompileResult = ExecuteCommand(FullCompileCmd) + if CompileResult: + print('Compilation successful!') + + # 检查是否需要运行 + if self.Args.get('Run', False): + RunArgs = self.Args.get('RunArgs', '') + RunCmd = f'{OutputFile}.exe {RunArgs}'.strip() + print(f'Running: {RunCmd}') + + # 执行运行命令 + RunResult = ExecuteCommand(RunCmd) + if RunResult: + print('Execution output:') + print(RunResult.stdout) + if RunResult.stderr: + print('Execution errors:') + print(RunResult.stderr) + except Exception as e: + print(f'{ERROR_MESSAGES["COMPILE_FAILED"]}: {e}') + + def WriteDebugInfo(self, content): + """写入调试信息到指定文件""" + # 获取调试文件路径 + if 'Debug' in self.Args: + DebugFile = self.Args['Debug'] + else: + DebugFile = self.Args.get('Output', '').replace('.c', '.p2c') + + if DebugFile: + AppendFileContent(DebugFile, content) + + def PythonToC(self, InputFile, OutputFile): + """Python到C的转换""" + # 获取编码参数 + encoding = self.Args.get('Encoding', 'utf-8') + + # 设置调试文件路径(使用 .p2c 扩展名) + if 'Debug' in self.Args: + DebugFile = self.Args['Debug'] + else: + # 默认使用 .p2c 文件 + DebugFile = OutputFile.replace('.c', '.p2c') + + # 设置翻译器的调试文件 + self.translator.SetDebugFile(DebugFile) + + # 先清空调试文件 + with open(DebugFile, 'w', encoding=encoding) as f: + f.write('') + + # 解析辅助文件,提取符号信息 + if self.HelperFiles: + self.translator.ParseHelperFiles(self.HelperFiles, encoding) + + # 加载注解文件,提取类型定义 + if self.AnnotationFiles: + self.translator.LoadAnnotationFiles(self.AnnotationFiles) + + # 获取编码参数 + encoding = self.Args.get('Encoding', 'utf-8') + with open(InputFile, 'r', encoding=encoding) as F: + Content = F.read() + + # 保存原始代码行 + self.translator.OriginalLines = Content.split('\n') + self.translator.Content = Content + + # 解析Python代码为AST + Tree = ast.parse(Content) + + # 解析文件以提取类型信息(用于 EmbeddedAssignments) + self.translator.ParsePythonFile(InputFile, encoding) + + # 写入AST树信息(压缩格式) + with open(DebugFile, 'a', encoding=encoding) as f: + f.write('=== AST Tree (Compact) ===\n') + f.write(ast.dump(Tree)) + f.write('\n\n') + + Target = 'llvm' + CCode = self.translator.GenerateCCode(Tree, target=Target) + + import datetime + timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + filename = os.path.basename(OutputFile) + + encoding = self.Args.get('Encoding', 'utf-8') + with open(OutputFile, 'w', encoding=encoding) as F: + F.write(CCode) + F.write('\n') + + def CToPython(self, InputFile, OutputFile, HeaderFiles): + """C到Python的转换(暂时禁用)""" + print("C到Python的转换功能暂时禁用,请使用Python到C的转换功能。") + + def AddSymbol(self, SymbolFiles): + """添加符号文件 + + Args: + SymbolFiles: 符号文件或符号文件列表 + """ + if isinstance(SymbolFiles, list): + self.SymbolFiles.extend(SymbolFiles) + else: + self.SymbolFiles.append(SymbolFiles) + + # 收集文件路径和编码 + HelperFiles = [] + encodings = [] + for SymbolFile in self.SymbolFiles: + FilePath = SymbolFile.FilePath + encoding = SymbolFile.encoding + if FilePath: + HelperFiles.append(FilePath) + encodings.append(encoding) + + # 解析辅助文件 + if HelperFiles: + # 暂时使用第一个文件的编码 + encoding = encodings[0] if encodings else 'utf-8' + self.translator.ParseHelperFiles(HelperFiles, encoding) + + def Convert(self, OutputFilename=None, SourceFilename=None, target='llvm'): + """转换代码 + + Args: + OutputFilename: 输出文件名(用于模板渲染) + SourceFilename: 源文件路径(用于设置CurrentFile,影响导入模块的查找) + target: 目标代码类型,仅支持 'llvm' + + Returns: + 如果debug是字符串,则返回生成的代码 + 如果debug是True,则返回生成的代码和调试信息 + """ + if not self.code: + print('Error: No code provided') + return None + + from lib.core.Handles.HandlesImports import ImportHandle + ImportHandle._struct_load_cache.clear() + + # 如果提供了 SourceFilename,先设置 CurrentFile + # 这样导入模块时会相对于源文件所在目录查找 + if SourceFilename: + self.translator.CurrentFile = SourceFilename + + # 加载注解文件,提取类型定义 + if self.AnnotationFiles: + self.translator.LoadAnnotationFiles(self.AnnotationFiles) + + # 保存原始代码行 + self.translator.OriginalLines = self.code.split('\n') + + # 解析Python代码为AST + Tree = ast.parse(self.code) + + # 从源代码直接预扫描 import 语句,注册别名 + # 注意:不能依赖 Tree 中的 import 节点,因为 ParsePythonFile 可能修改了 AST + if not getattr(self.translator, '_import_aliases', None): + self.translator._import_aliases = {} + if not getattr(self.translator, '_imported_modules', None): + self.translator._imported_modules = set() + _prescan_tree = ast.parse(self.code) + for _node in ast.iter_child_nodes(_prescan_tree): + if isinstance(_node, ast.Import): + for _alias in _node.names: + _name = _alias.name + if _name in ('c', 't'): + continue + self.translator._imported_modules.add(_name) + if _alias.asname: + self.translator._import_aliases[_alias.asname] = _name + elif isinstance(_node, ast.ImportFrom): + _module_name = _node.module + if _module_name and _module_name not in ('c', 't'): + self.translator._imported_modules.add(_module_name) + for _alias in _node.names: + if _alias.asname: + self.translator._import_aliases[_alias.asname] = f"{_module_name}.{_alias.name}" + + # 解析代码以提取类型信息(用于 EmbeddedAssignments 和 TypedefAssignments) + # 创建临时文件路径用于解析 + import tempfile + import os + with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False, encoding='utf-8') as f: + f.write(self.code) + TempFile = f.name + try: + # UpdateCurrentFile=False 表示不修改 CurrentFile + if SourceFilename: + self.translator.ParsePythonFile(TempFile, UpdateCurrentFile=False) + else: + self.translator.ParsePythonFile(TempFile) + finally: + os.unlink(TempFile) + + import datetime + timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + + if self.triple: + self.translator.triple = self.triple + if self.datalayout: + self.translator.datalayout = self.datalayout + + # 生成代码 + code = self.translator.GenerateCCode(Tree, target='llvm') + filename = os.path.basename(OutputFilename) if OutputFilename else 'generated.ll' + + # 处理调试信息 + if isinstance(self.config.debug, str): + # 如果debug是字符串,写入调试信息到文件 + with open(self.config.debug, 'w', encoding='utf-8') as f: + f.write('=== Symbol Table ===\n') + f.write(str(self.translator.SymbolTable) + '\n\n') + f.write('=== AST Tree ===\n') + f.write(ast.dump(Tree, indent=2) + '\n\n') + f.write('=== Export Table ===\n') + f.write(self.translator.ExportTable.to_json() + '\n\n') + f.write('=== Generated Code ===\n') + f.write(code + '\n') + return code + elif self.config.debug: + # 如果debug是True,返回生成的代码和调试信息 + DebugInfo = { + 'SymbolTable': self.translator.SymbolTable, + 'ast_tree': ast.dump(Tree, indent=2), + 'export_table': self.translator.ExportTable.to_dict(), + 'generated_code': code + } + return code, DebugInfo + else: + # 如果debug是False,只返回生成的代码 + return code + + def Run(self): + """主运行函数""" + # 检查是否有命令行参数 + if len(sys.argv) > 1: + # 有命令行参数,使用 ParseArgs 方法解析 + self.ParseArgs() + + # 检查是否有预处理符号文件的请求 + if 'PreSym' in self.Args: + PresymConfig = self.Args['PreSym'] + InputFile = PresymConfig['input'] + OutputFile = PresymConfig['output'] + DebugFile = PresymConfig['debug'] + + # 获取编码参数 + encoding = self.Args.get('Encoding', 'utf-8') + + # 推断文件类型 + FileType = 'py' if InputFile.endswith('.py') else 'c' if InputFile.endswith('.c') else None + + # 创建 SymbolFile 对象,传入编码参数 + SymbolFile = SymbolFile(file=InputFile, type=FileType, encoding=encoding) + + # 调用 PreProcessSymbol + if DebugFile: + BinaryData, DebugInfo = TransPyC.PreProcessSymbol(SymbolFile, debug=True) + # 写入调试文件 + with open(DebugFile, 'w', encoding=encoding) as f: + f.write(DebugInfo) + print(f"Debug info written to: {DebugFile}") + else: + BinaryData = TransPyC.PreProcessSymbol(SymbolFile, debug=False) + + # 写入二进制符号文件 + with open(OutputFile, 'wb') as f: + f.write(BinaryData) + + print(f"Symbol file generated: {OutputFile}") + return + + InputFile = self.Args['Input'] + OutputFile = self.Args['Output'] + else: + # 没有命令行参数,使用默认的测试文件名称 + InputFile = DEFAULT_INPUT_FILE + OutputFile = DEFAULT_OUTPUT_FILE + print('Using default test files: test.py -> test.c') + + FileType = DetectFileType(InputFile) + + if FileType == '.py': + self.PythonToC(InputFile, OutputFile) + # 检查是否需要编译和运行 + if 'CompileCommand' in self.Args or self.Args.get('Run', False): + self.CompileAndRun(OutputFile) + elif FileType == '.c': + self.CToPython(InputFile, OutputFile, self.HeaderFiles) + else: + print(f'Error: Unsupported file type {FileType}') + sys.exit(1) + + +if __name__ == '__main__': + trans = TransPyC() + if 'SliceLevel' in trans.Args: + trans.SliceLevel = trans.Args['SliceLevel'] + trans.Run() diff --git a/blackhole.py b/blackhole.py new file mode 100644 index 0000000..8f93490 --- /dev/null +++ b/blackhole.py @@ -0,0 +1,278 @@ +#include +#include +#include +#include +from stdint import * +import vipermath +import t, c + + +W: t.CDefine = 900 +H: t.CDefine = 540 +MAX_STEPS: t.CDefine = 400 +ESCAPE: t.CDefine = 60.0 +DISK_IN: t.CDefine = 2.6 # 吸积盘内缘 (单位: 史瓦西半径 Rs=1) +DISK_OUT: t.CDefine = 11.0 # 吸积盘外缘 +CAM_DIST: t.CDefine = 22.0 +CAM_ELEV: t.CDefine = 9.0 # 相机仰角(度): 小角度=侧视/透镜效果最强(星际穿越). 想更俯视可调到35 +FOVF: t.CDefine = 0.55 # tan(半视场) + +# ---------------- 向量 ---------------- +class V3: + x: t.CDouble + y: t.CDouble + z: t.CDouble + + def __init__(self, x: t.CDefine, y: t.CDefine, z: t.CDefine): + self.x = x + self.y = y + self.z = z + + def __add__(self, other: 'V3') -> 'V3': + return V3(self.x + other.x, self.y + other.y, self.z + other.z) + + def __sub__(self, other: 'V3') -> 'V3': + return V3(self.x - other.x, self.y - other.y, self.z - other.z) + + def __mul__(self, other: t.CDouble) -> 'V3': + return V3(self.x * other, self.y * other, self.z * other) + + def __xor__(self, other: 'V3') -> t.CDouble: # dot + return self.x * other.x + self.y * other.y + self.z * other.z + + def cross(self, other: 'V3') -> 'V3': + return V3(self.y * other.z - self.z * other.y, self.z * other.x - self.x * other.z, self.x * other.y - self.y * other.x) + + def __len__(self) -> t.CDouble: + return vipermath.sqrt(c.Deref(self) ^ c.Deref(self)) + + def nrm(self) -> 'V3': + l = len(c.Deref(self)) # self.__len__() + return self / l if l > (1e-12) else self + + def lerp(self, other: 'V3', t: t.CDouble) -> 'V3': + return self + (other - self) * t + +def clmp(x: t.CDouble, a: t.CDouble, b: t.CDouble) -> t.CDouble: + return x if x >= a and x <= b else a if x < a else b + +def smoothstep(a: t.CDouble, b: t.CDouble, x: t.CDouble) -> t.CDouble: + t = clmp((x - a) / (b - a), 0, 1) + return t * t * (3 - 2 * t) + + + +# static inline V3 v(double x,double y,double z){V3 r={x,y,z};return r;} +# static inline V3 add(V3 a,V3 b){return v(a.x+b.x,a.y+b.y,a.z+b.z);} +# static inline V3 sub(V3 a,V3 b){return v(a.x-b.x,a.y-b.y,a.z-b.z);} +# static inline V3 scl(V3 a,double s){return v(a.x*s,a.y*s,a.z*s);} +# static inline double dot(V3 a,V3 b){return a.x*b.x+a.y*b.y+a.z*b.z;} +# static inline V3 cross(V3 a,V3 b){return v(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x);} +# static inline double len(V3 a){return sqrt(dot(a,a));} +# static inline V3 nrm(V3 a){double l=len(a); return l>1e-12?scl(a,1.0/l):a;} +# static inline V3 lerp(V3 a,V3 b,double t){return add(scl(a,1-t),scl(b,t));} +# static inline double clmp(double x,double a,double b){return xb?b:x);} +# static inline double smoothstep(double a,double b,double x){double t=clmp((x-a)/(b-a),0,1);return t*t*(3-2*t);} + +# ---------------- 帧缓冲 / 相机 ---------------- +fb: UINT32PTR +CAM: V3 +FWD: V3 +RIGHT: V3 +UP: V3 +# static V3 CAM, FWD, RIGHT, UP; +gT: t.CDouble = 0.0 +# static volatile double gT = 0.0; + +def setupCamera(): + e: t.CDouble = CAM_ELEV * vipermath.U_M_PI / 180.0 + CAM = V3(CAM_DIST * vipermath.cos(e), CAM_DIST * vipermath.sin(e), 0) + FWD = (V3(0, 0, 0) - CAM).nrm() + RIGHT = (FWD.cross(V3(0,1,0))).nrm() + UP = RIGHT.cross(FWD) + +# ---------------- 哈希 / 星空 ---------------- +def hash3(x: t.CDouble, y: t.CDouble, z: t.CDouble) -> t.CDouble: + n: t.CDouble = vipermath.sin(x*127.1 + y * 311.7 + z * 74.7) * 43758.5453 + return n - vipermath.floor(n) + +def stars(d: V3) -> V3: + _c: V3 = V3(0, 0, 0) + for i in range(3): + s: t.CDouble = 80.0 + i * 90.0 + px: t.CDouble = d.x * s + py: t.CDouble = d.y * s + pz: t.CDouble = d.z * s + ix: t.CDouble = vipermath.floor(px) + iy: t.CDouble = vipermath.floor(py) + iz: t.CDouble = vipermath.floor(pz) + h: t.CDouble = hash3(ix, iy, iz) + if h > 0.991: + fx: t.CDouble = px - ix - 0.5 + fy: t.CDouble = py - iy - 0.5 + d2: t.CDouble = fx * fx + fy * fy + fz * fz + br: t.CDouble = (h-0.991) / 0.009 * vipermath.exp(-d2 * 9.0) * 1.4 + _t: t.CDouble = hash3(iy, iz, ix) + tint: V3 = V3(0.7,0.8,1.0) if (_t < 0.3) else (V3(1.0,0.8,0.6) if (_t > 0.8) else V3(1,1,1)); + _c = add(_c, scl(tint, br)) + return _c + + +# ---------------- 吸积盘着色 ---------------- +static void diskShade(V3 cp,double rr,double t,V3*emit,double*alpha){ + double tt=(rr-DISK_IN)/(DISK_OUT-DISK_IN); + double edge = smoothstep(0,0.07,tt)*smoothstep(0,0.18,1.0-tt); + double ang=atan2(cp.z,cp.x); + double w = 1.0/pow(rr,1.5); # 开普勒角速度 + double ph = ang - t*0.0011*w*9.0; # 随时间旋转 + double n = 0.5+0.5*sin(ph*5.0 - rr*1.6); + double n2 = 0.5+0.5*sin(ph*13.0 + rr*0.8 + 1.7); + double dens = (0.35+0.65*n)*(0.55+0.45*n2); + double bright = (0.45+1.7*pow(1.0-tt,1.8))*edge; + + # 相对论多普勒增亮 (一侧更亮 + 微蓝移) + V3 vdir = nrm(v(-cp.z,0,cp.x)); + double beta = 0.46/sqrt(rr); + V3 toCam = nrm(sub(CAM,cp)); + double mu = dot(vdir,toCam); + double dop = 1.0/(1.0-beta*mu); + double beam = pow(dop,3.0); + + V3 c1=v(1.0,0.92,0.68), c2=v(1.0,0.42,0.13); + V3 base=lerp(c1,c2,tt); + base.z += (dop-1.0)*0.35; base.x -= (dop-1.0)*0.05; # 蓝移微调 + + double inten = bright*dens*beam*1.25; + *emit = scl(base,inten); + *alpha = clmp(edge*dens*0.92,0,1); +} + +# ---------------- 光子测地线积分 ---------------- +static V3 trace(V3 dir){ + V3 pos=CAM, vel=dir; + V3 hvec=cross(pos,vel); + double h2=dot(hvec,hvec); # 角动量守恒 + double T=1.0; V3 col=v(0,0,0); + double t=gT; + + for(int i=0;i 黑 + if(r>ESCAPE){ col=add(col,scl(stars(nrm(vel)),T)); break; } + + double dt=clmp(r*0.08,0.03,2.2); + # RK4 (a = -1.5 h2 pos / r^5) + ACC(P) scl(P, -1.5*h2/pow(dot(P,P),2.5)) + V3 k1p=vel, k1v=ACC(pos); + V3 k2p=add(vel,scl(k1v,dt*0.5)), k2v=ACC(add(pos,scl(k1p,dt*0.5))); + V3 k3p=add(vel,scl(k2v,dt*0.5)), k3v=ACC(add(pos,scl(k2p,dt*0.5))); + V3 k4p=add(vel,scl(k3v,dt)), k4v=ACC(add(pos,scl(k3p,dt))); + V3 npos=add(pos,scl(add(add(k1p,scl(k2p,2)),add(scl(k3p,2),k4p)),dt/6.0)); + V3 nvel=add(vel,scl(add(add(k1v,scl(k2v,2)),add(scl(k3v,2),k4v)),dt/6.0)); + + # 吸积盘平面 y=0 穿越检测 + if(pos.y*npos.y<0){ + double f=pos.y/(pos.y-npos.y); + V3 cp=lerp(pos,npos,f); + double rr=sqrt(cp.x*cp.x+cp.z*cp.z); + if(rr>DISK_IN && rry0;yy1;y++) + for(int x=0;x64)NT=64; + + fb=(uint32_t*)malloc((size_t)W*H*4); + bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth=W; bmi.bmiHeader.biHeight=-H; # 顶向下 + bmi.bmiHeader.biPlanes=1; bmi.bmiHeader.biBitCount=32; bmi.bmiHeader.biCompression=BI_RGB; + setupCamera(); + + WNDCLASS wc={0}; wc.lpfnWndProc=WndProc; wc.hInstance=hI; + wc.lpszClassName="bh"; wc.hCursor=LoadCursor(0,IDC_ARROW); + RegisterClass(&wc); + RECT rc={0,0,W,H}; AdjustWindowRect(&rc,WS_OVERLAPPEDWINDOW,FALSE); + HWND hwnd=CreateWindow("bh","Gargantua (ESC quit)",WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT,CW_USEDEFAULT,rc.right-rc.left,rc.bottom-rc.top,0,0,hI,0); + ShowWindow(hwnd,show); + + LARGE_INTEGER fq,t0,t1; QueryPerformanceFrequency(&fq); + DWORD start=GetTickCount(); + MSG msg; int run=1; double fps=0; DWORD ftc=0; int fcnt=0; + while(run){ + while(PeekMessage(&msg,0,0,0,PM_REMOVE)){ + if(msg.message==WM_QUIT){run=0;break;} + TranslateMessage(&msg); DispatchMessage(&msg); + } + if(!run)break; + gT=(double)(GetTickCount()-start); # <<< 传入的时间 t (毫秒) + QueryPerformanceCounter(&t0); + renderFrame(); + QueryPerformanceCounter(&t1); + HDC dc=GetDC(hwnd); + SetDIBitsToDevice(dc,0,0,W,H,0,0,0,H,fb,&bmi,DIB_RGB_COLORS); + ReleaseDC(hwnd,dc); + + fcnt++; DWORD now=GetTickCount(); + if(now-ftc>500){ fps=fcnt*1000.0/(now-ftc); fcnt=0; ftc=now; + char buf[128]; sprintf(buf,"Gargantua FPS:%.1f threads:%d",fps,NT); + SetWindowText(hwnd,buf); + } + } + free(fb); + return 0; +} \ No newline at end of file diff --git a/c.py b/c.py new file mode 100644 index 0000000..d382954 --- /dev/null +++ b/c.py @@ -0,0 +1 @@ +from lib.includes.c import * \ No newline at end of file diff --git a/debug_out.txt b/debug_out.txt new file mode 100644 index 0000000..ab6fd60 --- /dev/null +++ b/debug_out.txt @@ -0,0 +1 @@ +[ERROR] 类型 'window.InputEvent' 未在符号表中找到,严格模式下需要定义此类型 diff --git a/debug_output.txt b/debug_output.txt new file mode 100644 index 0000000..cdcc976 --- /dev/null +++ b/debug_output.txt @@ -0,0 +1 @@ +[编译终止] 1 个文件翻译失败 diff --git a/includes/asm.py b/includes/asm.py new file mode 100644 index 0000000..b00b1f0 --- /dev/null +++ b/includes/asm.py @@ -0,0 +1,150 @@ +import t, c + + +def cli(): + c.Asm("cli", [t.ASM_DESCR.CLOBBER_MEMORY]) + +def sti(): + c.Asm("sti", [t.ASM_DESCR.CLOBBER_MEMORY]) + +def hlt(): + c.Asm("hlt", [t.ASM_DESCR.CLOBBER_MEMORY]) + +def nop(): + c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY]) + +def inb(port: t.CUInt16T) -> t.CUInt8T: + value: t.CUInt32T + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + in al, dx + movzx eax, al""", + out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], + op =[t.ASM_DESCR.CLOBBER_RDX]) + return t.CUInt8T(value) + +def outb(port: t.CUInt16T, value: t.CUInt8T): + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(t.CUInt32T(value), t.ASM_DESCR.REG_ANY)} + out dx, al""", + op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) + + +def inw(port: t.CUInt16T) -> t.CUInt16T: + value: t.CUInt32T + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + in ax, dx + movzx eax, ax""", + out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], + op =[t.ASM_DESCR.CLOBBER_RDX]) + return t.CUInt16T(value) + +def outw(port: t.CUInt16T, value: t.CUInt16T): + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(t.CUInt32T(value), t.ASM_DESCR.REG_ANY)} + out dx, ax""", + op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) + +def inl(port: t.CUInt16T) -> t.CUInt32T: + value: t.CUInt32T + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + in eax, dx""", + out = [c.AsmOut(value, t.ASM_DESCR.OUTPUT_REG)], + op =[t.ASM_DESCR.CLOBBER_RDX]) + return value + +def outl(port: t.CUInt16T, value: t.CUInt32T): + c.Asm(f"""mov edx, {c.AsmInp(t.CUInt32T(port), t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)} + out dx, eax""", + op = [t.ASM_DESCR.CLOBBER_RDX, t.ASM_DESCR.CLOBBER_RAX]) + +def io_wait(): + c.Asm(f"mov dx, 0x80; out dx, al", + op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_DX]) + +def pushall() -> t.CInline | t.CVoid: + c.Asm(f""" + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15""", + [t.ASM_DESCR.CLOBBER_MEMORY] + ) + +def popall() -> t.CInline | t.CVoid: + c.Asm(f""" + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax""", + [t.ASM_DESCR.CLOBBER_MEMORY] + ) + +def cpu_switch_context(old_stack: t.CUInt64T | t.CPtr, new_stack: t.CUInt64T): + c.Asm(f""" + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + mov [{c.AsmInp(old_stack, t.ASM_DESCR.REG_ANY)}], rsp + mov rsp, {c.AsmInp(new_stack, t.ASM_DESCR.REG_ANY)} + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax""", + op=[t.ASM_DESCR.CLOBBER_MEMORY]) + +def BSSClean(): + c.Asm( + "lea rdi, [rip + __bss_start]\n" + "lea rcx, [rip + __bss_end]\n" + "sub rcx, rdi\n" + "xor eax, eax\n" + "cld\n" + "rep stosb", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RAX] + ) diff --git a/includes/atom.py b/includes/atom.py new file mode 100644 index 0000000..f3927da --- /dev/null +++ b/includes/atom.py @@ -0,0 +1,42 @@ +import t, c + + +ATOMIC_RELAXED: t.CDefine = 0 +ATOMIC_CONSUME: t.CDefine = 1 +ATOMIC_ACQUIRE: t.CDefine = 2 +ATOMIC_RELEASE: t.CDefine = 3 +ATOMIC_ACQ_REL: t.CDefine = 4 +ATOMIC_SEQ_CST: t.CDefine = 5 + + +def __atomic_test_and_set(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> t.CBool | t.State: + result: t.CUInt8T = 1 + c.Asm(f"""mov al, 1 + xchg byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], al + mov {c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)}, al""", + out = [c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)], + inp = [c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)], + op = [t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX]) + return t.CBool(result) + + +def __atomic_clear(ptr: t.CUInt64T | t.CPtr, order: t.CInt) -> t.CVoid | t.State: + c.Asm(f"""mov byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], 0""", + inp = [c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)], + op = [t.ASM_DESCR.CLOBBER_MEMORY]) + + +def __atomic_thread_fence(order: t.CInt) -> t.CVoid | t.State: + c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) + + +def __atomic_signal_fence(order: t.CInt) -> t.CVoid | t.State: + pass + + +def __atomic_always_lock_free(size: t.CSizeT, ptr: t.CVoid | t.CPtr) -> t.CBool | t.State: + return t.CBool(1) + + +def __atomic_is_lock_free(size: t.CSizeT, ptr: t.CVoid | t.CPtr) -> t.CBool | t.State: + return t.CBool(1) diff --git a/includes/base64.py b/includes/base64.py new file mode 100644 index 0000000..87e708b --- /dev/null +++ b/includes/base64.py @@ -0,0 +1,79 @@ +import binascii +import t, c + + +# ============================================== +# Base64 编解码 纯裸实现 +# ============================================== +# Base64 编码对照表 +b64_tab: list[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +# Base64 反向解码表,映射字符到索引值 +b64_dec_tab: list[t.CInt8T, 80] = [ + 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 +] + +# * @brief Base64 编码 +# * @param in: 输入二进制数据 +# * @param in_len: 输入长度 +# * @param out: 输出Base64字符串缓冲区 +# * @retval 编码后字符串长度 +def b64encode(s: str, out: str) -> t.CSizeT: + _s = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + i: t.CSizeT = 0 + j: t.CSizeT = 0 + val: t.CUInt32T = 0 + # 每3字节一组转4字节Base64 + for i in range(0, length, 3): + # 拼接24bit分组 + val = ((t.CUInt32T(_s[i + 0]) << 16 ) | + (t.CUInt32T(_s[i + 1]) << 8 if (i + 1 < length) else 0) | + (t.CUInt32T(_s[i + 2]) << 0 if (i + 2 < length) else 0)) + # 拆分4个6bit 查表 + out[j + 0] = b64_tab[(val >> 18) & 0x3F] + out[j + 1] = b64_tab[(val >> 12) & 0x3F] + out[j + 2] = b64_tab[(val >> 6) & 0x3F] if (i + 1 < length) else '=' + out[j + 3] = b64_tab[(val >> 0) & 0x3F] if (i + 2 < length) else '=' + j += 4 + out[j] = '\0' # 字符串结尾 + return j + + +# * @brief Base64 解码 +# * @param in: Base64字符串 +# * @param out: 输出二进制缓冲区 +# * @retval 解码后二进制长度 +def b64decode(s: str, out: t.CUInt8T | t.CPtr) -> t.CSizeT: + length: t.CSizeT = len(s) + i: t.CSizeT = 0 + j: t.CSizeT = 0 + val: t.CUInt32T = 0 + c: t.CInt + # 每4个Base64字符还原3字节 + for i in range(0, length, 4): + if s[i] == '=': break + val = 0 + # 逐个解析6bit + c = s[i] - 43 + val |= (b64_dec_tab[c] & 0x3F) << 18 + c = s[i+1] - 43 + val |= (b64_dec_tab[c] & 0x3F) << 12 + c = s[i+2] - 43 + if s[i+2] != '=': val |= (b64_dec_tab[c] & 0x3F) << 6 + c = s[i+3] - 43 + if s[i+3] != '=': val |= (b64_dec_tab[c] & 0x3F) + # 还原3字节 + out[j] = (val >> 16) & 0xFF + j += 1 + if s[i+2] != '=': + out[j] = (val >> 8) & 0xFF + j += 1 + if s[i+3] != '=': + out[j] = val & 0xFF + j += 1 + return j diff --git a/includes/binascii.py b/includes/binascii.py new file mode 100644 index 0000000..68f1b02 --- /dev/null +++ b/includes/binascii.py @@ -0,0 +1,349 @@ +import t, c +import stdint + + +HEX_CHARS: list[t.CChar, None] = "0123456789abcdef" +HEX_VALS: list[t.CInt, 256] + +B64_CHARS: list[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +B64_VALS: list[t.CInt, 256] + +HQX_CHARS: list[t.CChar, 64] = [ + ' ', '!', chr(34), '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '@', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'X', 'Y', 'Z', + '[', chr(92), '`', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm' +] +HQX_VALS: list[t.CInt, 256] + +UU_CHARS: list[t.CChar, None] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + +CRC32_TABLE: list[t.CUnsignedInt, 256] = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +] + +CRC_HQX_TABLE: list[t.CUnsignedShort, 256] = [ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +] + +def init_binascii(): + i: t.CInt + for i in range(256): + HEX_VALS[i] = -1 + B64_VALS[i] = -1 + HQX_VALS[i] = -1 + for i in range(16): + HEX_VALS[t.CInt(HEX_CHARS[i])] = i + HEX_VALS[t.CInt(HEX_CHARS[i] - 32)] = i + for i in range(64): + B64_VALS[t.CInt(B64_CHARS[i])] = i + for i in range(64): + HQX_CHARS[i] = t.CChar(32 + i) + for i in range(64): + HQX_VALS[t.CUnsignedChar(HQX_CHARS[i])] = i + +def crc32(data: str, length: t.CInt, crc: t.CUnsignedInt) -> t.CUnsignedInt: + i: t.CInt + s: t.CUnsignedInt = crc ^ 0xFFFFFFFF + for i in range(length): + s = CRC32_TABLE[(s ^ t.CUnsignedChar(data[i])) & 0xFF] ^ (s >> 8) + return s ^ 0xFFFFFFFF + +def crc_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort) -> t.CUnsignedShort: + i: t.CInt + s: t.CUnsignedShort = crc + for i in range(length): + s = CRC_HQX_TABLE[t.CUnsignedChar(s >> 8)] ^ (s << 1 | (data[i] & 0xFF)) + return s + +def hexlify(data: str, length: t.CInt) -> str: + if not data or length < 0: return None + out: str = str(malloc(length * 2 + 1)) + if not out: return None + oi: t.CInt = 0 + for i in range(length): + s: t.CUnsignedChar = t.CUnsignedChar(data[i]) + out[oi] = HEX_CHARS[(s >> 4) & 0x0F] + oi += 1 + out[oi] = HEX_CHARS[(s >> 0) & 0x0F] + oi += 1 + out[oi] = '\0' + return out + +def b2a_hex(data: str, length: t.CInt) -> str: + return hexlify(data, length) + +def a2b_hex(hexstr: str, length: t.CInt) -> str: + if not hexstr or length < 0 or length % 2 != 0: return None + out_len: t.CInt = length // 2 + out: str = str(malloc(out_len + 1)) + if not out: return None + oi: t.CInt = 0 + for i in range(0, length, 2): + hi: t.CInt = HEX_VALS[t.CUnsignedChar(hexstr[i])] + lo: t.CInt = HEX_VALS[t.CUnsignedChar(hexstr[i + 1])] + if hi < 0 or lo < 0: + free(out) + return None + out[oi] = t.CChar((hi << 4) | lo) + oi += 1 + out[oi] = '\0' + return out + +def unhexlify(data: str, length: t.CInt): + return a2b_hex(data, length) + +def b2a_base64(data: str, length: t.CInt) -> str: + if not data or length < 0: return None + olen: t.CInt = (length // 3) * 4 + if length % 3 != 0: + olen += 4 + olen += 1 + out: str = str(malloc(olen + 1)) + if not out: return None + oi: t.CInt = 0 + for i in range(0, length, 3): + b0: t.CUnsignedChar = t.CUnsignedChar(data[i]) + b1: t.CUnsignedChar = 0 + b2: t.CUnsignedChar = 0 + if i + 1 < length: + b1 = t.CUnsignedChar(data[i + 1]) + if i + 2 < length: + b2 = t.CUnsignedChar(data[i + 2]) + out[oi] = B64_CHARS[(b0 >> 2) & 0x3F] + oi += 1 + out[oi] = B64_CHARS[((b0 & 0x03) << 4) | ((b1 >> 4) & 0x0F)] + oi += 1 + if i + 1 < length: + out[oi] = B64_CHARS[((b1 & 0x0F) << 2) | ((b2 >> 6) & 0x03)] + else: + out[oi] = '=' + oi += 1 + if i + 2 < length: + out[oi] = B64_CHARS[b2 & 0x3F] + else: + out[oi] = '=' + oi += 1 + out[oi] = '\0' + return out + +def a2b_base64(data: str, length: t.CInt) -> str: + if not data or length < 4: return None + olen: t.CInt = (length // 4) * 3 + if length >= 4 and data[length - 1] == '=': + olen -= 1 + if length >= 4 and data[length - 2] == '=': + olen -= 1 + out: str = str(malloc(olen + 1)) + if not out: return None + oi: t.CInt = 0 + for i in range(0, length, 4): + v0: t.CInt = 0 + v1: t.CInt = 0 + v2: t.CInt = 0 + v3: t.CInt = 0 + j: t.CInt + for j in range(4): + c: t.CChar = data[i + j] + if c == '=': + pass + else: + k: t.CInt + for k in range(64): + if B64_CHARS[k] == c: + if j == 0: v0 = k + elif j == 1: v1 = k + elif j == 2: v2 = k + elif j == 3: v3 = k + break + out[oi] = t.CChar((v0 << 2) | (v1 >> 4)) + oi += 1 + if data[i + 2] != '=': + out[oi] = t.CChar(((v1 & 0x0F) << 4) | (v2 >> 2)) + oi += 1 + if data[i + 3] != '=': + out[oi] = t.CChar(((v2 & 0x03) << 6) | v3) + oi += 1 + out[oi] = '\0' + return out + +def b2a_uu(data: str, length: t.CInt) -> str: + if not data or length < 1 or length > 45: return None + out: str = str(malloc(length * 2 + 2)) + if not out: return None + oi: t.CInt = 0 + out[oi] = UU_CHARS[length] + oi += 1 + for i in range(0, length, 3): + b0: t.CUnsignedChar = t.CUnsignedChar(data[i]) + b1: t.CUnsignedChar = 0 + b2: t.CUnsignedChar = 0 + if i + 1 < length: + b1 = t.CUnsignedChar(data[i + 1]) + if i + 2 < length: + b2 = t.CUnsignedChar(data[i + 2]) + m: t.CUnsignedInt = (t.CUnsignedInt(b0) << 16) | (t.CUnsignedInt(b1) << 8) | t.CUnsignedInt(b2) + out[oi] = UU_CHARS[(m >> 18) & 0x3F] + oi += 1 + out[oi] = UU_CHARS[(m >> 12) & 0x3F] + oi += 1 + out[oi] = UU_CHARS[(m >> 6) & 0x3F] + oi += 1 + out[oi] = UU_CHARS[m & 0x3F] + oi += 1 + out[oi] = '\n' + oi += 1 + out[oi] = '\0' + return out + +def a2b_uu(data: str) -> str: + if not data or data[0] == ' ' or data[0] == '`': return None + length: t.CInt = t.CInt(data[0]) - 32 + if length < 0 or length > 45: return None + out: str = str(malloc(length + 1)) + if not out: return None + oi: t.CInt = 0 + i: t.CInt = 1 + while oi < length: + v0: t.CInt = data[i] - 32 + v1: t.CInt = data[i + 1] - 32 + v2: t.CInt = data[i + 2] - 32 + v3: t.CInt = data[i + 3] - 32 + if v0 < 0 or v0 > 63: v0 = 0 + if v1 < 0 or v1 > 63: v1 = 0 + if v2 < 0 or v2 > 63: v2 = 0 + if v3 < 0 or v3 > 63: v3 = 0 + m: t.CUnsignedInt = (t.CUnsignedInt(v0) << 18) | (t.CUnsignedInt(v1) << 12) | (t.CUnsignedInt(v2) << 6) | t.CUnsignedInt(v3) + if oi < length: + out[oi] = t.CChar((m >> 16) & 0xFF) + oi += 1 + if oi < length: + out[oi] = t.CChar((m >> 8) & 0xFF) + oi += 1 + if oi < length: + out[oi] = t.CChar(m & 0xFF) + oi += 1 + i += 4 + out[oi] = '\0' + return out + +def b2a_hqx(data: str, length: t.CInt, crc: t.CUnsignedShort = 0) -> tuple[str, t.CUnsignedShort]: + if not data or length != 3: + return None, crc + out: str = str(malloc(5)) + if not out: + return None, crc + # 3字节 → 4字节 HQX + m: t.CUnsignedInt = (t.CUnsignedChar(data[0]) << 16) | (t.CUnsignedChar(data[1]) << 8) | t.CUnsignedChar(data[2]) + out[0] = HQX_CHARS[(m >> 18) & 0x3F] + out[1] = HQX_CHARS[(m >> 12) & 0x3F] + out[2] = HQX_CHARS[(m >> 6) & 0x3F] + out[3] = HQX_CHARS[m & 0x3F] + out[4] = '\0' + # CRC 初始化 + 正确计算 + s: t.CUnsignedShort = crc + for i in range(3): + byte: t.CUnsignedChar = t.CUnsignedChar(data[i]) + s = (s << 8) ^ CRC_HQX_TABLE[((s >> 8) ^ byte) & 0xFF] + return out, s + + +def a2b_hqx(data: str, crc: t.CUnsignedShort = 0) -> tuple[str, t.CUnsignedShort]: + if not data: + return None, crc + # 检查字符是否有效 + for i in range(4): + cchar: t.CUnsignedChar = t.CUnsignedChar(data[i]) + if HQX_VALS[cchar] < 0: + return None, crc + # 解码 + m: t.CUnsignedInt = 0 + for i in range(4): + m = (m << 6) | t.CUnsignedInt(HQX_VALS[t.CUnsignedChar(data[i])]) + out: str = str(malloc(4)) + if not out: + return None, crc + out[0] = t.CChar((m >> 16) & 0xFF) + out[1] = t.CChar((m >> 8) & 0xFF) + out[2] = t.CChar(m & 0xFF) + out[3] = '\0' + # CRC 初始化 + 正确计算 + s: t.CUnsignedShort = crc + for i in range(3): + byte: t.CUnsignedChar = t.CUnsignedChar(out[i]) + s = (s << 8) ^ CRC_HQX_TABLE[((s >> 8) ^ byte) & 0xFF] + return out, s + +def adler32(data: str, length: t.CInt, adler: t.CUnsignedInt) -> t.CUnsignedInt: + a: t.CUnsignedInt = adler & 0xFFFF + b: t.CUnsignedInt = (adler >> 16) & 0xFFFF + i: t.CInt + for i in range(length): + a = (a + t.CUnsignedChar(data[i])) % 65521 + b = (b + a) % 65521 + return (b << 16) | a diff --git a/includes/builtins.py b/includes/builtins.py new file mode 100644 index 0000000..13fe189 --- /dev/null +++ b/includes/builtins.py @@ -0,0 +1,11 @@ +import t + + +def print(*args, sep: str = " ", end: str = "\n") -> t.State: + ... +def input(prompt: str = "") -> str | t.State: + ... + +class type: + def __init__(self): ... + def __str__(self): ... \ No newline at end of file diff --git a/includes/hashlib/__init__.py b/includes/hashlib/__init__.py new file mode 100644 index 0000000..3ee2214 --- /dev/null +++ b/includes/hashlib/__init__.py @@ -0,0 +1,4 @@ +from .__md5 import md5, MD5_DIGEST_LEN +from .__sha1 import sha1, SHA1_DIGEST_LEN +from .__sha256 import sha256, SHA256_DIGEST_LEN +from .__sha512 import sha512, SHA512_DIGEST_LEN diff --git a/includes/hashlib/__md5.py b/includes/hashlib/__md5.py new file mode 100644 index 0000000..63ed23c --- /dev/null +++ b/includes/hashlib/__md5.py @@ -0,0 +1,130 @@ +import t, c + + +# ============================================== +# MD5 哈希算法 +# ============================================== +MD5_BLOCK_LEN: t.CDefine = 64 # 分组块大小 +MD5_DIGEST_LEN: t.CDefine = 16 # 摘要输出长度 + +# MD5 四轮非线性函数 +def md5_F(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) | (~x & z) +def md5_G(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & z) | (y & ~z) +def md5_H(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return x ^ y ^ z +def md5_I(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return y ^ (x | ~z) +# 循环左移 +def md5_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) + +# MD5 常量表、移位表 +md5_T: list[t.CUInt32T, 64] = [ + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 +] + +md5_S: list[t.CInt, 64] = [ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 +] + +# MD5 上下文结构体 +@t.Object +class md5: + state: list[t.CUInt32T, 4] # 4个32位状态寄存器 + count: t.CUInt64T # 已处理比特数 + buf: list[t.CUInt8T, MD5_BLOCK_LEN] # 分组缓冲区 + # 初始化MD5上下文 + def __init__(self): + memset(self.buf, 0, MD5_BLOCK_LEN) + self.state[0] = 0x67452301 + self.state[1] = 0xefcdab89 + self.state[2] = 0x98badcfe + self.state[3] = 0x10325476 + self.count = 0 + # MD5 单分组压缩变换 + def transform(self, block: t.CUInt8T | t.CPtr): + a: t.CUInt32T = self.state[0] + b: t.CUInt32T = self.state[1] + c: t.CUInt32T = self.state[2] + d: t.CUInt32T = self.state[3] + w: list[t.CUInt32T, 16] + # 字节序转32位字 + for i in range(16): + w[i] = ((t.CUInt32T(block[i * 4 + 0]) << 0) | + (t.CUInt32T(block[i * 4 + 1]) << 8) | + (t.CUInt32T(block[i * 4 + 2]) << 16) | + (t.CUInt32T(block[i * 4 + 3]) << 24)) + # 4轮64步迭代 + for i in range(16): + tmp: t.CUInt32T = md5_F(b, c, d) + a + md5_T[i] + w[i] + a = d; d = c; c = b + b += md5_rotl(tmp, md5_S[i]) + # 在 C 中的 for i 0: + left: t.CSizeT = MD5_BLOCK_LEN - idx + if length >= left: + memcpy(self.buf + idx, data, left) + self.transform(self.buf) + data += left + length -= left + idx = 0 + while length >= MD5_BLOCK_LEN: + self.transform(data) + data += MD5_BLOCK_LEN + length -= MD5_BLOCK_LEN + if length > 0: + memcpy(self.buf + idx, data, length) + # 结束计算,输出16字节摘要 + def final(self, out: list[t.CUInt8T, MD5_DIGEST_LEN]): + idx: t.CSizeT = self.count % MD5_BLOCK_LEN + # 填充0x80结尾 + self.buf[idx] = 0x80 + idx += 1 + # 空间不够则先压缩一次 + if idx > MD5_BLOCK_LEN - 8: + memset(self.buf + idx, 0, MD5_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + # 补0到末尾8字节 + memset(self.buf + idx, 0, MD5_BLOCK_LEN - 8 - idx) + # 写入总比特数 + bits: t.CUInt64T = self.count << 3 + for i in range(8): + self.buf[MD5_BLOCK_LEN - 8 + i] = (bits >> (i * 8)) & 0xFF + self.transform(self.buf) + # 状态转小端字节输出 + for i in range(4): + out[i * 4 + 0] = (self.state[i] >> 0) & 0xFF + out[i * 4 + 1] = (self.state[i] >> 8) & 0xFF + out[i * 4 + 2] = (self.state[i] >> 16) & 0xFF + out[i * 4 + 3] = (self.state[i] >> 24) & 0xFF diff --git a/includes/hashlib/__sha1.py b/includes/hashlib/__sha1.py new file mode 100644 index 0000000..5c2f8ca --- /dev/null +++ b/includes/hashlib/__sha1.py @@ -0,0 +1,119 @@ +import t, c + + + +# ============================================== +# SHA1 哈希算法 +# ============================================== +SHA1_BLOCK_LEN: t.CDefine = 64 +SHA1_DIGEST_LEN: t.CDefine = 20 + +def sha1_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) +# 三轮逻辑函数 +def sha1_f1(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return (b & c) | (~b & d) +def sha1_f2(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return b ^ c ^ d +def sha1_f3(b: t.CUInt32T, c: t.CUInt32T, d: t.CUInt32T) -> t.CUInt32T: return (b & c) | (b & d) | (c & d) + +# SHA1 上下文 +@t.Object +class sha1: + state: list[t.CUInt32T, 5] + count: t.CUInt64T + buf: list[t.CUInt8T, SHA1_BLOCK_LEN] + def __init__(self): + memset(self.buf, 0, SHA1_BLOCK_LEN) + self.state[0] = 0x67452301 + self.state[1] = 0xefcdab89 + self.state[2] = 0x98badcfe + self.state[3] = 0x10325476 + self.state[4] = 0xc3d2e1f0 + self.count = 0 + # 单分组压缩 + def transform(self, block: t.CUInt8T | t.CPtr): + w: list[t.CUInt32T, 80] + data: t.CUInt8T | t.CPtr = block + # 前16个字 + for i in range(16): + w[i] = (((t.CUInt32T(data[i * 4 + 0])) << 24) | + ((t.CUInt32T(data[i * 4 + 1])) << 16) | + ((t.CUInt32T(data[i * 4 + 2])) << 8) | + ((t.CUInt32T(data[i * 4 + 3])) << 0)) + # 扩展到80个字 + for i in range(16, 80): + w[i] = sha1_rotl(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16],1) + a: t.CUInt32T = self.state[0] + b: t.CUInt32T = self.state[1] + c: t.CUInt32T = self.state[2] + d: t.CUInt32T = self.state[3] + e: t.CUInt32T = self.state[4] + k: t.CUInt32T + tmp: t.CUInt32T + # 4轮迭代 + for i in range(0, 20): + k = 0x5a827999 + tmp = sha1_rotl(a,5) + sha1_f1(b, c, d) + e + k + w[i] + e = d; d = c + c = sha1_rotl(b, 30) + b = a; a = tmp + for i in range(20, 40): + k = 0x6ed9eba1 + tmp = sha1_rotl(a,5) + sha1_f2(b, c, d) + e + k + w[i] + e = d; d = c + c = sha1_rotl(b, 30) + b = a; a = tmp + for i in range(40, 60): + k = 0x8f1bbcdc + tmp = sha1_rotl(a,5) + sha1_f3(b, c, d) + e + k + w[i] + e = d; d = c + c = sha1_rotl(b, 30) + b = a; a = tmp + for i in range(60, 80): + k = 0xca62c1d6 + tmp = sha1_rotl(a,5) + sha1_f2(b, c, d) + e + k + w[i] + e = d; d = c + c = sha1_rotl(b, 30) + b = a; a = tmp + self.state[0] += a + self.state[1] += b + self.state[2] += c + self.state[3] += d + self.state[4] += e + def update(self, s: str): + data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + idx: t.CSizeT = self.count % SHA1_BLOCK_LEN + self.count += length + if idx > 0: + left: t.CSizeT = SHA1_BLOCK_LEN - idx + if length >= left: + memcpy(self.buf + idx, data, left) + self.transform(self.buf) + data += left + length -= left + idx = 0 + while length >= SHA1_BLOCK_LEN: + self.transform(data) + data += SHA1_BLOCK_LEN + length -= SHA1_BLOCK_LEN + if length > 0: + memcpy(self.buf + idx, data, length) + def final(self, out: list[t.CUInt8T, SHA1_DIGEST_LEN]): + idx: t.CSizeT = self.count % SHA1_BLOCK_LEN + self.buf[idx] = 0x80 + idx += 1 + if idx > SHA1_BLOCK_LEN - 8: + memset(self.buf + idx, 0, SHA1_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + memset(self.buf + idx,0,SHA1_BLOCK_LEN-8-idx) + bits: t.CUInt64T = self.count << 3 + # SHA1 大端写入长度 + for i in range(8): + self.buf[SHA1_BLOCK_LEN - 8 + i] = (bits >> (56 - i * 8)) & 0xFF + self.transform(self.buf) + # 大端输出摘要 + for i in range(5): + out[i * 4 + 0] = (self.state[i] >> 24) & 0xFF + out[i * 4 + 1] = (self.state[i] >> 16) & 0xFF + out[i * 4 + 2] = (self.state[i] >> 8) & 0xFF + out[i * 4 + 3] = (self.state[i] >> 0) & 0xFF diff --git a/includes/hashlib/__sha256.py b/includes/hashlib/__sha256.py new file mode 100644 index 0000000..698d4f3 --- /dev/null +++ b/includes/hashlib/__sha256.py @@ -0,0 +1,123 @@ +import t, c + + +# ============================================== +# SHA256 哈希算法 +# ============================================== +SHA256_BLOCK_LEN: t.CDefine = 64 +SHA256_DIGEST_LEN: t.CDefine = 32 + +# SHA256 常量K +sha256_K: list[t.CUInt32T, 64] = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +] + +# SHA256 辅助函数 +def s0(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ ((x >> 3)) +def s1(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ ((x >> 10)) +def S0(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)) +def S1(x: t.CUInt32T) -> t.CUInt32T: return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)) +def Ch(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) ^ (~x & z) +def Maj(x: t.CUInt32T, y: t.CUInt32T, z: t.CUInt32T) -> t.CUInt32T: return (x & y) ^ (x & z) ^ (y & z) + +# SHA256 上下文 +@t.Object +class sha256: + state: list[t.CUInt32T, 8] + count: t.CUInt64T + buf: list[t.CUInt8T, SHA256_BLOCK_LEN] + def __init__(self): + memset(self, 0, sha256.__sizeof__()) + self.state[0] = 0x6a09e667 + self.state[1] = 0xbb67ae85 + self.state[2] = 0x3c6ef372 + self.state[3] = 0xa54ff53a + self.state[4] = 0x510e527f + self.state[5] = 0x9b05688c + self.state[6] = 0x1f83d9ab + self.state[7] = 0x5be0cd19 + self.count = 0 + # memset(self.buf, 0, SHA256_BLOCK_LEN) + # 单分组压缩 + def transform(self, block: t.CUInt8T | t.CPtr): + w: list[t.CUInt32T, 64] + for i in range(16): + w[i] = ((t.CUInt32T(block[i * 4 + 0]) << 24) | + (t.CUInt32T(block[i * 4 + 1]) << 16) | + (t.CUInt32T(block[i * 4 + 2]) << 8 ) | + (t.CUInt32T(block[i * 4 + 3]) << 0 )) + # 扩展64字 + for i in range(16, 64): + w[i] = w[i-16] + s0(w[i-15]) + w[i-7] + s1(w[i-2]) + a: t.CUInt32T = self.state[0] + b: t.CUInt32T = self.state[1] + c: t.CUInt32T = self.state[2] + d: t.CUInt32T = self.state[3] + e: t.CUInt32T = self.state[4] + f: t.CUInt32T = self.state[5] + g: t.CUInt32T = self.state[6] + h: t.CUInt32T = self.state[7] + t1: t.CUInt32T + t2: t.CUInt32T + # 64步迭代 + for i in range(64): + t1 = h + S1(e) + Ch(e,f,g) + sha256_K[i] + w[i] + t2 = S0(a) + Maj(a,b,c) + h = g; g = f; f = e + e = d + t1 + d = c; c = b; b = a + a = t1 + t2 + # 累加状态 + self.state[0] += a + self.state[1] += b + self.state[2] += c + self.state[3] += d + self.state[4] += e + self.state[5] += f + self.state[6] += g + self.state[7] += h + def update(self, s: str): + data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + idx: t.CSizeT = self.count % SHA256_BLOCK_LEN + self.count += length + if idx > 0: + left: t.CSizeT = SHA256_BLOCK_LEN - idx + if length >= left: + memcpy(self.buf + idx, data, left) + self.transform(self.buf) + data += left + length -= left + idx = 0 + while length >= SHA256_BLOCK_LEN: + self.transform(data) + data += SHA256_BLOCK_LEN + length -= SHA256_BLOCK_LEN + if length > 0: + memcpy(self.buf + idx, data, length) + def final(self, out: list[t.CUInt8T, SHA256_DIGEST_LEN]): + idx: t.CSizeT = self.count % SHA256_BLOCK_LEN + self.buf[idx] = 0x80 + idx += 1 + if idx > SHA256_BLOCK_LEN - 8: + memset(self.buf + idx, 0, SHA256_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + memset(self.buf + idx, 0, SHA256_BLOCK_LEN - 8 - idx) + bits: t.CUInt64T = self.count << 3 + for i in range(8): + self.buf[SHA256_BLOCK_LEN-8+i] = (bits >> (56 - i*8)) & 0xFF + self.transform(self.buf) + # 大端输出32字节摘要 + for i in range(8): + out[i * 4 + 0] = (self.state[i] >> 24) & 0xFF + out[i * 4 + 1] = (self.state[i] >> 16) & 0xFF + out[i * 4 + 2] = (self.state[i] >> 8) & 0xFF + out[i * 4 + 3] = (self.state[i] >> 0) & 0xFF diff --git a/includes/hashlib/__sha512.py b/includes/hashlib/__sha512.py new file mode 100644 index 0000000..3ca787b --- /dev/null +++ b/includes/hashlib/__sha512.py @@ -0,0 +1,148 @@ +import t, c + + +# ============================================== +# SHA512 哈希算法 +# ============================================== +SHA512_BLOCK_LEN: t.CDefine = 128 +SHA512_DIGEST_LEN: t.CDefine = 64 + +def sha512_ror(x: t.CUInt64T, n: int) -> t.CUInt64T: return (x >> n) | (x << (64 - n)) +def sha512_shr(x: t.CUInt64T, n: int) -> t.CUInt64T: return x >> n +def sha512_Ch (x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: return (x & y) ^ (~x & z) +def sha512_Maj(x: t.CUInt64T, y: t.CUInt64T, z: t.CUInt64T) -> t.CUInt64T: return (x & y) ^ (x & z) ^ (y & z) +def sha512_BigSigma0(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 28) ^ sha512_ror(x, 34) ^ sha512_ror(x, 39) +def sha512_BigSigma1(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 14) ^ sha512_ror(x, 18) ^ sha512_ror(x, 41) +def sha512_Sigma0(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 1) ^ sha512_ror(x, 8) ^ sha512_shr(x, 7) +def sha512_Sigma1(x: t.CUInt64T) -> t.CUInt64T: return sha512_ror(x, 19) ^ sha512_ror(x, 61) ^ sha512_shr(x, 6) + +sha512_K: list[t.CUInt64T, 80] = [ + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 +] + +@t.Object +class sha512: + state: list[t.CUInt64T, 8] + count: list[t.CUInt64T, 2] + buf: list[t.CUInt8T, SHA512_BLOCK_LEN] + def __init__(self): + memset(self, 0, sha512.__sizeof__()) + self.state[0] = 0x6a09e667f3bcc908 + self.state[1] = 0xbb67ae8584caa73b + self.state[2] = 0x3c6ef372fe94f82b + self.state[3] = 0xa54ff53a5f1d36f1 + self.state[4] = 0x510e527fade682d1 + self.state[5] = 0x9b05688c2b3e6c1f + self.state[6] = 0x1f83d9abfb41bd6b + self.state[7] = 0x5be0cd19137e2179 + def transform(self, block: list[t.CUInt8T, SHA512_BLOCK_LEN]): + w: list[t.CUInt64T, 80] + a: t.CUInt64T + b: t.CUInt64T + c: t.CUInt64T + d: t.CUInt64T + e: t.CUInt64T + f: t.CUInt64T + g: t.CUInt64T + h: t.CUInt64T + t1: t.CUInt64T + t2: t.CUInt64T + for i in range(16): + w[i] = t.CUInt64T(block[i * 8 + 0]) << 56 + w[i] |= t.CUInt64T(block[i * 8 + 1]) << 48 + w[i] |= t.CUInt64T(block[i * 8 + 2]) << 40 + w[i] |= t.CUInt64T(block[i * 8 + 3]) << 32 + w[i] |= t.CUInt64T(block[i * 8 + 4]) << 24 + w[i] |= t.CUInt64T(block[i * 8 + 5]) << 16 + w[i] |= t.CUInt64T(block[i * 8 + 6]) << 8 + w[i] |= t.CUInt64T(block[i * 8 + 7]) << 0 + for i in range(16, 80): + w[i] = sha512_Sigma1(w[i-2]) + w[i-7] + sha512_Sigma0(w[i-15]) + w[i-16] + a = self.state[0] + b = self.state[1] + c = self.state[2] + d = self.state[3] + e = self.state[4] + f = self.state[5] + g = self.state[6] + h = self.state[7] + for i in range(80): + t1 = h + sha512_BigSigma1(e) + sha512_Ch(e, f, g) + sha512_K[i] + w[i] + t2 = sha512_BigSigma0(a) + sha512_Maj(a, b, c) + h = g; g = f; f = e + e = d + t1 + d = c; c = b; b = a + a = t1 + t2 + self.state[0] += a + self.state[1] += b + self.state[2] += c + self.state[3] += d + self.state[4] += e + self.state[5] += f + self.state[6] += g + self.state[7] += h + def update(self, s: str): + data: t.CUInt8T | t.CPtr = t.CUInt8T(s, t.CPtr) + length: t.CSizeT = len(s) + idx: t.CUInt32T = t.CUInt32T(self.count[0] % SHA512_BLOCK_LEN) + self.count[0] += length + if self.count[0] < length: + self.count[1] += 1 + if idx > 0: + left: t.CSizeT = SHA512_BLOCK_LEN - idx + if length >= left: + memcpy(self.buf + idx, data, left) + self.transform(self.buf) + data += left + length -= left + idx = 0 + while length >= SHA512_BLOCK_LEN: + self.transform(data) + data += SHA512_BLOCK_LEN + length -= SHA512_BLOCK_LEN + if length > 0: + memcpy(self.buf + idx, data, length) + def final(self, out: list[t.CUInt8T, SHA512_DIGEST_LEN]): + bits_lo: t.CUInt64T = self.count[0] << 3 + bits_hi: t.CUInt64T = (self.count[1] << 3) | (self.count[0] >> 61) + idx: t.CUInt32T = t.CUInt32T(self.count[0] % SHA512_BLOCK_LEN) + self.buf[idx] = 0x80 + idx += 1 + if idx > SHA512_BLOCK_LEN - 16: + memset(self.buf + idx, 0, SHA512_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + memset(self.buf + idx, 0, SHA512_BLOCK_LEN - 16 - idx) + for i in range(8): + self.buf[SHA512_BLOCK_LEN - 16 + i] = t.CUInt8T(bits_hi >> (56 - i * 8)) + for i in range(8): + self.buf[SHA512_BLOCK_LEN - 8 + i] = t.CUInt8T(bits_lo >> (56 - i * 8)) + self.transform(self.buf) + for i in range(8): + out[i * 8 + 0] = t.CUInt8T(self.state[i] >> 56) + out[i * 8 + 1] = t.CUInt8T(self.state[i] >> 48) + out[i * 8 + 2] = t.CUInt8T(self.state[i] >> 40) + out[i * 8 + 3] = t.CUInt8T(self.state[i] >> 32) + out[i * 8 + 4] = t.CUInt8T(self.state[i] >> 24) + out[i * 8 + 5] = t.CUInt8T(self.state[i] >> 16) + out[i * 8 + 6] = t.CUInt8T(self.state[i] >> 8) + out[i * 8 + 7] = t.CUInt8T(self.state[i] >> 0) diff --git a/includes/json/__init__.py b/includes/json/__init__.py new file mode 100644 index 0000000..ae44048 --- /dev/null +++ b/includes/json/__init__.py @@ -0,0 +1,237 @@ +import t, c +from stdint import * +import mpool +import string +import viperio + +# ============================================================ +# JSON 值类型枚举 +# ============================================================ +JSON_NULL: t.CDefine = 0 +JSON_BOOL: t.CDefine = 1 +JSON_INT: t.CDefine = 2 +JSON_FLOAT: t.CDefine = 3 +JSON_STRING: t.CDefine = 4 +JSON_ARRAY: t.CDefine = 5 +JSON_OBJECT: t.CDefine = 6 + + +# ============================================================ +# JsonValue - JSON 值节点 +# 使用 mpool 分配:JsonValue(pool) 从池中分配内存 +# ============================================================ +class JsonValue: + vtype: t.CInt + bool_val: t.CInt + int_val: t.CInt64T + float_val: t.CDouble + str_val: t.CChar | t.CPtr + next: JsonValue | t.CPtr + key: t.CChar | t.CPtr + child: JsonValue | t.CPtr + child_count: t.CSizeT + + def __new__(self, pool: mpool.MPool | t.CPtr): + """从 mpool 分配 JsonValue 结构体内存并零初始化""" + ptr: JsonValue | t.CPtr = pool.alloc(JsonValue.__sizeof__()) + if ptr: + string.memset(ptr, 0, JsonValue.__sizeof__()) + return ptr + + def type(self) -> t.CInt: + return self.vtype + + def is_null(self) -> bool: + return self.vtype == JSON_NULL + + def is_bool(self) -> bool: + return self.vtype == JSON_BOOL + + def is_int(self) -> bool: + return self.vtype == JSON_INT + + def is_float(self) -> bool: + return self.vtype == JSON_FLOAT + + def is_string(self) -> bool: + return self.vtype == JSON_STRING + + def is_array(self) -> bool: + return self.vtype == JSON_ARRAY + + def is_object(self) -> bool: + return self.vtype == JSON_OBJECT + + def as_bool(self) -> bool: + return self.bool_val != 0 + + def as_int(self) -> t.CInt64T: + return self.int_val + + def as_float(self) -> t.CDouble: + return self.float_val + + def as_string(self) -> t.CChar | t.CPtr: + return self.str_val + + def __len__(self) -> t.CSizeT: + return self.child_count + + def __getitem__(self, key: t.CChar | t.CPtr) -> JsonValue | t.CPtr: + """Python风格取值:v["key"] 取对象字段""" + if self.vtype != JSON_OBJECT: + return None + if key == None: + return None + cur: JsonValue | t.CPtr = self.child + while cur != None: + if cur.key != None: + if string.strcmp(cur.key, key) == 0: + return cur + cur = cur.next + return None + + def __setitem__(self, key: t.CChar | t.CPtr, val: JsonValue | t.CPtr): + """Python风格赋值:v["key"] = val""" + if self.vtype != JSON_OBJECT or key == None or val == None: + return + cur: JsonValue | t.CPtr = self.child + while cur != None: + if cur.key != None: + if string.strcmp(cur.key, key) == 0: + cur.vtype = val.vtype + cur.bool_val = val.bool_val + cur.int_val = val.int_val + cur.float_val = val.float_val + cur.str_val = val.str_val + cur.child = val.child + cur.child_count = val.child_count + return + cur = cur.next + # key 不存在,追加新子节点 + klen: t.CSizeT = string.strlen(key) + kbuf: t.CChar | t.CPtr = self._pool_alloc(klen + 1) + if kbuf != None: + string.memcpy(kbuf, key, klen + 1) + val.key = kbuf + self._append_child(val) + + def get_item(self, index: t.CSizeT) -> JsonValue | t.CPtr: + """按索引取数组元素:v.get_item(0)""" + if self.vtype != JSON_ARRAY and self.vtype != JSON_OBJECT: + return None + cur: JsonValue | t.CPtr = self.child + i: t.CSizeT = 0 + while cur != None: + if i == index: + return cur + cur = cur.next + i += 1 + return None + + def _pool_alloc(self, size: t.CSizeT) -> t.CChar | t.CPtr: + """内部方法:从当前对象的 mpool 分配内存(预留,暂返回 None)""" + return None + + def _append_child(self, child: JsonValue | t.CPtr): + if self.child == None: + self.child = child + else: + cur: JsonValue | t.CPtr = self.child + while cur.next != None: + cur = cur.next + cur.next = child + self.child_count += 1 + + +# ============================================================ +# 构造函数:创建各类 JsonValue(从 mpool 分配) +# ============================================================ + +def null(pool: mpool.MPool | t.CPtr) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_NULL + return v + +def bool_val(pool: mpool.MPool | t.CPtr, val: bool) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_BOOL + v.bool_val = 1 if val else 0 + return v + +def int_val(pool: mpool.MPool | t.CPtr, val: t.CInt64T) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_INT + v.int_val = val + return v + +def float_val(pool: mpool.MPool | t.CPtr, val: t.CDouble) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_FLOAT + v.float_val = val + return v + +def string_val(pool: mpool.MPool | t.CPtr, val: t.CChar | t.CPtr) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_STRING + if val != None: + slen: t.CSizeT = string.strlen(val) + buf: t.CChar | t.CPtr = pool.alloc(slen + 1) + if buf != None: + string.memcpy(buf, val, slen + 1) + v.str_val = buf + return v + +def array(pool: mpool.MPool | t.CPtr) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_ARRAY + return v + +def object(pool: mpool.MPool | t.CPtr) -> JsonValue | t.CPtr: + v: JsonValue | t.CPtr = JsonValue(pool) + if v == None: return None + v.vtype = JSON_OBJECT + return v + +# 向数组追加元素 +def array_append(pool: mpool.MPool | t.CPtr, arr: JsonValue | t.CPtr, item: JsonValue | t.CPtr): + if arr == None or item == None: return + if arr.vtype != JSON_ARRAY: return + arr._append_child(item) + +# 向对象设置键值对 +def object_set(pool: mpool.MPool | t.CPtr, obj: JsonValue | t.CPtr, key: t.CChar | t.CPtr, val: JsonValue | t.CPtr): + if obj == None or key == None or val == None: return + if obj.vtype != JSON_OBJECT: return + cur: JsonValue | t.CPtr = obj.child + while cur != None: + if cur.key != None: + if string.strcmp(cur.key, key) == 0: + cur.vtype = val.vtype + cur.bool_val = val.bool_val + cur.int_val = val.int_val + cur.float_val = val.float_val + cur.str_val = val.str_val + cur.child = val.child + cur.child_count = val.child_count + return + cur = cur.next + klen: t.CSizeT = string.strlen(key) + kbuf: t.CChar | t.CPtr = pool.alloc(klen + 1) + if kbuf != None: + string.memcpy(kbuf, key, klen + 1) + val.key = kbuf + obj._append_child(val) + + +# ============================================================ +# 导入子模块 +# ============================================================ +from .__parser import parse +from .__writer import write diff --git a/includes/json/__parser.py b/includes/json/__parser.py new file mode 100644 index 0000000..b99c26f --- /dev/null +++ b/includes/json/__parser.py @@ -0,0 +1,291 @@ +import t, c +from stdint import * +import mpool +import string +from . import ( + JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT, + JSON_STRING, JSON_ARRAY, JSON_OBJECT, + null, bool_val, int_val, float_val, string_val, array, object, +) + + +class ParseState: + src: t.CChar | t.CPtr + pos: t.CSizeT + len: t.CSizeT + pool: mpool.MPool | t.CPtr + + def __init__(self, src: t.CChar | t.CPtr, pool: mpool.MPool | t.CPtr): + self.src = src + self.pos = 0 + self.len = string.strlen(src) if src != None else 0 + self.pool = pool + + +def _peek(s: ParseState | t.CPtr) -> t.CChar: + if s.pos >= s.len: + return '\0' + return s.src[s.pos] + +def _advance(s: ParseState | t.CPtr) -> t.CChar: + if s.pos >= s.len: + return '\0' + ch: t.CChar = s.src[s.pos] + s.pos += 1 + return ch + +def _skip_whitespace(s: ParseState | t.CPtr): + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r': + s.pos += 1 + else: + break + +def _expect(s: ParseState | t.CPtr, ch: t.CChar) -> bool: + _skip_whitespace(s) + if s.pos >= s.len: + return False + if s.src[s.pos] != ch: + return False + s.pos += 1 + return True + + +def _parse_string(s: ParseState | t.CPtr) -> t.CChar | t.CPtr: + if _peek(s) != '"': + return None + _advance(s) + + start: t.CSizeT = s.pos + slen: t.CSizeT = 0 + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch == '"': + break + if ch == '\\': + s.pos += 1 + slen += 1 + slen += 1 + s.pos += 1 + + buf: t.CChar | t.CPtr = s.pool.alloc(slen + 1) + if buf == None: + return None + + s.pos = start + di: t.CSizeT = 0 + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch == '"': + s.pos += 1 + break + if ch == '\\': + s.pos += 1 + if s.pos < s.len: + esc: t.CChar = s.src[s.pos] + if esc == 'n': + buf[di] = '\n' + elif esc == 't': + buf[di] = '\t' + elif esc == 'r': + buf[di] = '\r' + elif esc == '\\': + buf[di] = '\\' + elif esc == '"': + buf[di] = '"' + elif esc == '/': + buf[di] = '/' + else: + buf[di] = esc + di += 1 + s.pos += 1 + continue + buf[di] = ch + di += 1 + s.pos += 1 + + buf[di] = '\0' + return buf + + +def _parse_number(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: + _skip_whitespace(s) + is_float: bool = False + start: t.CSizeT = s.pos + + if s.pos < s.len and s.src[s.pos] == '-': + s.pos += 1 + + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch >= '0' and ch <= '9': + s.pos += 1 + else: + break + + if s.pos < s.len and s.src[s.pos] == '.': + is_float = True + s.pos += 1 + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch >= '0' and ch <= '9': + s.pos += 1 + else: + break + + if s.pos < s.len and (s.src[s.pos] == 'e' or s.src[s.pos] == 'E'): + is_float = True + s.pos += 1 + if s.pos < s.len and (s.src[s.pos] == '+' or s.src[s.pos] == '-'): + s.pos += 1 + while s.pos < s.len: + ch: t.CChar = s.src[s.pos] + if ch >= '0' and ch <= '9': + s.pos += 1 + else: + break + + num_len: t.CSizeT = s.pos - start + buf: t.CChar | t.CPtr = s.pool.alloc(num_len + 1) + if buf == None: + return null(s.pool) + + i: t.CSizeT = 0 + while i < num_len: + buf[i] = s.src[start + i] + i += 1 + buf[num_len] = '\0' + + if is_float: + val: t.CDouble = string.atof(buf) + return float_val(s.pool, val) + else: + ival: t.CInt64T = string.atoll(buf) + return int_val(s.pool, ival) + + +def _parse_value(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: + _skip_whitespace(s) + if s.pos >= s.len: + return null(s.pool) + + ch: t.CChar = _peek(s) + + if ch == '"': + sv: t.CChar | t.CPtr = _parse_string(s) + return string_val(s.pool, sv) + + if ch == '{': + return _parse_object(s) + + if ch == '[': + return _parse_array(s) + + if ch == '-' or (ch >= '0' and ch <= '9'): + return _parse_number(s) + + if ch == 't': + if s.pos + 3 < s.len: + if s.src[s.pos + 1] == 'r' and s.src[s.pos + 2] == 'u' and s.src[s.pos + 3] == 'e': + s.pos += 4 + return bool_val(s.pool, True) + return null(s.pool) + + if ch == 'f': + if s.pos + 4 < s.len: + if s.src[s.pos + 1] == 'a' and s.src[s.pos + 2] == 'l' and s.src[s.pos + 3] == 's' and s.src[s.pos + 4] == 'e': + s.pos += 5 + return bool_val(s.pool, False) + return null(s.pool) + + if ch == 'n': + if s.pos + 3 < s.len: + if s.src[s.pos + 1] == 'u' and s.src[s.pos + 2] == 'l' and s.src[s.pos + 3] == 'l': + s.pos += 4 + return null(s.pool) + return null(s.pool) + + return null(s.pool) + + +def _parse_array(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: + if not _expect(s, '['): + return null(s.pool) + + arr: JsonValue | t.CPtr = array(s.pool) + + _skip_whitespace(s) + if s.pos < s.len and _peek(s) == ']': + _advance(s) + return arr + + item: JsonValue | t.CPtr = _parse_value(s) + arr._append_child(item) + + while True: + _skip_whitespace(s) + if s.pos >= s.len: + break + if _peek(s) != ',': + break + _advance(s) + item = _parse_value(s) + arr._append_child(item) + + _expect(s, ']') + return arr + + +def _parse_object(s: ParseState | t.CPtr) -> JsonValue | t.CPtr: + if not _expect(s, '{'): + return null(s.pool) + + obj: JsonValue | t.CPtr = object(s.pool) + + _skip_whitespace(s) + if s.pos < s.len and _peek(s) == '}': + _advance(s) + return obj + + _skip_whitespace(s) + key: t.CChar | t.CPtr = _parse_string(s) + _expect(s, ':') + val: JsonValue | t.CPtr = _parse_value(s) + if key != None and val != None: + klen: t.CSizeT = string.strlen(key) + kbuf: t.CChar | t.CPtr = s.pool.alloc(klen + 1) + if kbuf != None: + string.memcpy(kbuf, key, klen + 1) + val.key = kbuf + obj._append_child(val) + + while True: + _skip_whitespace(s) + if s.pos >= s.len: + break + if _peek(s) != ',': + break + _advance(s) + _skip_whitespace(s) + key = _parse_string(s) + _expect(s, ':') + val = _parse_value(s) + if key != None and val != None: + klen2: t.CSizeT = string.strlen(key) + kbuf2: t.CChar | t.CPtr = s.pool.alloc(klen2 + 1) + if kbuf2 != None: + string.memcpy(kbuf2, key, klen2 + 1) + val.key = kbuf2 + obj._append_child(val) + + _expect(s, '}') + return obj + + +def parse(pool: mpool.MPool | t.CPtr, src: t.CChar | t.CPtr) -> JsonValue | t.CPtr: + """解析 JSON 字符串,返回 JsonValue 树""" + if src == None: + return null(pool) + s: ParseState | t.CPtr = ParseState(src, pool) + return _parse_value(s) diff --git a/includes/json/__writer.py b/includes/json/__writer.py new file mode 100644 index 0000000..11db56b --- /dev/null +++ b/includes/json/__writer.py @@ -0,0 +1,119 @@ +import t, c +from stdint import * +import mpool +import string +from stdio import snprintf +from . import ( + JsonValue, JSON_NULL, JSON_BOOL, JSON_INT, JSON_FLOAT, + JSON_STRING, JSON_ARRAY, JSON_OBJECT, +) + + +def _write_char(buf: t.CChar | t.CPtr, pos: t.CSizeT, ch: t.CChar) -> t.CSizeT: + buf[pos] = ch + return pos + 1 + +def _write_str(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT: + if s == None: return pos + slen: t.CSizeT = string.strlen(s) + string.memcpy(t.CChar(t.CUInt64T(buf) + pos, t.CPtr), s, slen) + return pos + slen + +def _write_string_escaped(buf: t.CChar | t.CPtr, pos: t.CSizeT, s: t.CChar | t.CPtr) -> t.CSizeT: + if s == None: + pos = _write_str(buf, pos, "null") + return pos + pos = _write_char(buf, pos, '"') + i: t.CSizeT = 0 + slen: t.CSizeT = string.strlen(s) + while i < slen: + ch: t.CChar = s[i] + if ch == '"': + pos = _write_str(buf, pos, "\\\"") + elif ch == '\\': + pos = _write_str(buf, pos, "\\\\") + elif ch == '\n': + pos = _write_str(buf, pos, "\\n") + elif ch == '\r': + pos = _write_str(buf, pos, "\\r") + elif ch == '\t': + pos = _write_str(buf, pos, "\\t") + else: + pos = _write_char(buf, pos, ch) + i += 1 + pos = _write_char(buf, pos, '"') + return pos + + +def _write_value(buf: t.CChar | t.CPtr, pos: t.CSizeT, val: JsonValue | t.CPtr, pool: mpool.MPool | t.CPtr) -> t.CSizeT: + if val == None: + pos = _write_str(buf, pos, "null") + return pos + + if val.vtype == JSON_NULL: + pos = _write_str(buf, pos, "null") + + elif val.vtype == JSON_BOOL: + if val.bool_val != 0: + pos = _write_str(buf, pos, "true") + else: + pos = _write_str(buf, pos, "false") + + elif val.vtype == JSON_INT: + tmp: t.CChar | t.CPtr = pool.alloc(32) + if tmp != None: + snprintf(tmp, 32, "%lld", val.int_val) + pos = _write_str(buf, pos, tmp) + + elif val.vtype == JSON_FLOAT: + tmp2: t.CChar | t.CPtr = pool.alloc(32) + if tmp2 != None: + snprintf(tmp2, 32, "%.6g", val.float_val) + pos = _write_str(buf, pos, tmp2) + + elif val.vtype == JSON_STRING: + pos = _write_string_escaped(buf, pos, val.str_val) + + elif val.vtype == JSON_ARRAY: + if val.child == None: + pos = _write_str(buf, pos, "[]") + return pos + pos = _write_char(buf, pos, '[') + cur: JsonValue | t.CPtr = val.child + first: bool = True + while cur != None: + if not first: + pos = _write_char(buf, pos, ',') + pos = _write_value(buf, pos, cur, pool) + first = False + cur = cur.next + pos = _write_char(buf, pos, ']') + + elif val.vtype == JSON_OBJECT: + if val.child == None: + pos = _write_str(buf, pos, "{}") + return pos + pos = _write_char(buf, pos, '{') + cur2: JsonValue | t.CPtr = val.child + first2: bool = True + while cur2 != None: + if not first2: + pos = _write_char(buf, pos, ',') + pos = _write_string_escaped(buf, pos, cur2.key) + pos = _write_char(buf, pos, ':') + pos = _write_value(buf, pos, cur2, pool) + first2 = False + cur2 = cur2.next + pos = _write_char(buf, pos, '}') + + return pos + + +def write(pool: mpool.MPool | t.CPtr, val: JsonValue | t.CPtr, pretty: bool) -> t.CChar | t.CPtr: + """将 JsonValue 序列化为 JSON 字符串""" + buf: t.CChar | t.CPtr = pool.alloc(4096) + if buf == None: + return None + end_pos: t.CSizeT = _write_value(buf, 0, val, pool) + buf[end_pos] = '\0' + return buf diff --git a/includes/mpool.py b/includes/mpool.py new file mode 100644 index 0000000..5999cb4 --- /dev/null +++ b/includes/mpool.py @@ -0,0 +1,200 @@ +import t, c +from stdint import * +import viperio +import string + +MPOOL_ALIGN: t.CDefine = 8 +MPOOL_TYPE_SLAB: t.CDefine = 0 +MPOOL_TYPE_BUMP: t.CDefine = 2 + + +def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: + if align == 0: return val + return (val + align - 1) & ~(align - 1) + + +class MPool: + mtype: t.CInt + mem: t.CVoid | t.CPtr + mem_size: t.CSizeT + offset: t.CSizeT + high_water: t.CSizeT + block_size: t.CSizeT + block_count: t.CSizeT + used_count: t.CSizeT + free_list: t.CVoid | t.CPtr + alloc_map: t.CUInt8T | t.CPtr + alloc_map_size: t.CSizeT + + def __init__(self, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT): + self.mtype = MPOOL_TYPE_BUMP + self.mem = None + self.mem_size = 0 + self.offset = 0 + self.high_water = 0 + self.block_size = 0 + self.block_count = 0 + self.used_count = 0 + self.free_list = None + self.alloc_map = None + self.alloc_map_size = 0 + + if mem == None: return + if block_size > 0: + self._init_slab(mem, mem_size, block_size) + else: + self._init_bump(mem, mem_size) + + def _init_bump(self, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT): + if mem == None: return + if mem_size < 8: return + + self.mtype = MPOOL_TYPE_BUMP + self.mem = mem + self.mem_size = mem_size + self.offset = 0 + self.high_water = 0 + + def _init_slab(self, mem: t.CVoid | t.CPtr, mem_size: t.CSizeT, block_size: t.CSizeT): + if mem == None: return + + bs: t.CSizeT = _align_up(block_size, MPOOL_ALIGN) + if bs < 16: bs = 16 + + alloc_map_bytes: t.CSizeT = _align_up(256, MPOOL_ALIGN) + if mem_size < alloc_map_bytes + bs: return + + self.mtype = MPOOL_TYPE_SLAB + self.alloc_map = mem + self.alloc_map_size = alloc_map_bytes + self.mem = t.CVoid(t.CUInt64T(mem) + alloc_map_bytes, t.CPtr) + self.mem_size = mem_size - alloc_map_bytes + self.block_size = bs + self.used_count = 0 + + idx: t.CSizeT = 0 + while idx < alloc_map_bytes: + self.alloc_map[idx] = 0 + idx += 1 + + self.block_count = self.mem_size / bs + if self.block_count == 0: return + + self.free_list = None + i: t.CSizeT = 0 + while i < self.block_count: + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.mem) + i * bs, t.CPtr) + c.DerefAs(block, self.free_list) + self.free_list = block + i += 1 + + def __enter__(self) -> 'MPool' | t.CPtr: + return self + + def __exit__(self): + if self.mtype == MPOOL_TYPE_BUMP: + self.offset = 0 + self.high_water = 0 + elif self.mtype == MPOOL_TYPE_SLAB: + self._slab_reset() + + def _slab_reset(self): + self.used_count = 0 + self.free_list = None + i: t.CSizeT = 0 + while i < self.block_count: + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.mem) + i * self.block_size, t.CPtr) + c.DerefAs(block, self.free_list) + self.free_list = block + if i / 8 < self.alloc_map_size: + self.alloc_map[i / 8] = 0 + i += 1 + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + if self.mtype == MPOOL_TYPE_SLAB: + return self._slab_alloc() + if self.mtype == MPOOL_TYPE_BUMP: + return self._bump_alloc(size) + return None + + def alloc_buf(self, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: + ptr: t.CVoid | t.CPtr = self.alloc(capacity) + if ptr == None: + return viperio.Buf(None, 0) + return viperio.Buf(t.CChar(t.CUInt64T(ptr), t.CPtr), capacity) + + def free(self, ptr: t.CVoid | t.CPtr): + if ptr == None: return + if self.mtype == MPOOL_TYPE_SLAB: + self._slab_free(ptr) + + def realloc(self, ptr: t.CVoid | t.CPtr, old_size: t.CSizeT, new_size: t.CSizeT) -> t.CVoid | t.CPtr: + if ptr == None: + return self.alloc(new_size) + if new_size == 0: + self.free(ptr) + return None + if self.mtype == MPOOL_TYPE_SLAB: + if new_size <= self.block_size: + return ptr + new_ptr: t.CVoid | t.CPtr = self.alloc(new_size) + if new_ptr == None: + return ptr + copy_size: t.CSizeT = old_size + if new_size < old_size: + copy_size = new_size + string.memcpy(new_ptr, ptr, copy_size) + self.free(ptr) + return new_ptr + + def reset(self): + if self.mtype == MPOOL_TYPE_BUMP: + self.offset = 0 + self.high_water = 0 + elif self.mtype == MPOOL_TYPE_SLAB: + self._slab_reset() + + def _bump_alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + if size == 0: return None + aligned: t.CSizeT = _align_up(size, MPOOL_ALIGN) + if self.offset + aligned > self.mem_size: return None + ptr: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.mem) + self.offset, t.CPtr) + self.offset += aligned + if self.offset > self.high_water: + self.high_water = self.offset + return ptr + + def _slab_alloc(self) -> t.CVoid | t.CPtr: + if self.free_list == None: return None + block: t.CVoid | t.CPtr = self.free_list + self.free_list = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + self.used_count += 1 + idx: t.CSizeT = (t.CUInt64T(block) - t.CUInt64T(self.mem)) / self.block_size + self.alloc_map[idx / 8] = self.alloc_map[idx / 8] | t.CUInt8T(1 << (idx % 8)) + return block + + def _slab_free(self, ptr: t.CVoid | t.CPtr): + if ptr == None: return + p: t.CUInt64T = t.CUInt64T(ptr) + if p < t.CUInt64T(self.mem): return + if p >= t.CUInt64T(self.mem) + self.block_count * self.block_size: return + if (p - t.CUInt64T(self.mem)) % self.block_size != 0: return + idx: t.CSizeT = (p - t.CUInt64T(self.mem)) / self.block_size + byte_idx: t.CSizeT = idx / 8 + bit_idx: t.CInt = t.CInt(idx % 8) + if (self.alloc_map[byte_idx] >> bit_idx) & 1 == 0: return + self.alloc_map[byte_idx] = self.alloc_map[byte_idx] & t.CUInt8T(~(1 << bit_idx)) + c.DerefAs(ptr, self.free_list) + self.free_list = ptr + self.used_count -= 1 + +# 模块级包装函数(C 风格 API,第一个参数传入 pool 指针) +def bump_create(mem: t.CVoid | t.CPtr, mem_size: t.CSizeT) -> MPool | t.CPtr: + p: MPool | t.CPtr = MPool(mem, mem_size, 0) + return p + +def alloc(pool: MPool | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr: + return pool.alloc(size) + +def reset(pool: MPool | t.CPtr): + pool.reset() diff --git a/includes/numpy/__init__.py b/includes/numpy/__init__.py new file mode 100644 index 0000000..328d033 --- /dev/null +++ b/includes/numpy/__init__.py @@ -0,0 +1,1145 @@ +from stdint import * +import stdlib +import string +import vipermath +import stdio +import t, c +import mpool + + +# ============================================================ +# Constants +# ============================================================ +MAX_NDIM: t.CDefine = 4 + +float64: t.CTypedef = t.CDouble +float32: t.CTypedef = t.CFloat +int64: t.CTypedef = t.CLong +int32: t.CTypedef = t.CInt +uint8: t.CTypedef = t.CUnsignedChar + +pi: t.CDefine = 3.14159265358979323846 +e: t.CDefine = 2.71828182845904523536 + +# ============================================================ +# ndarray - core n-dimensional array +# ============================================================ +@t.Object +class ndarray: + data: t.CDouble | t.CPtr + shape: list[t.CSizeT, MAX_NDIM] + strides: list[t.CSizeT, MAX_NDIM] + ndim: t.CInt + size: t.CSizeT + owns_data: t.CInt + pool: mpool.MPool | t.CPtr + + def __new__(self, pool: mpool.MPool | t.CPtr, n: t.CSizeT): + self.pool = pool + self.data = pool.alloc(n * t.CDouble.__sizeof__()) + if self.data: + memset(self.data, 0, n * t.CDouble.__sizeof__()) + self.ndim = 1 + self.size = n + self.shape[0] = n + self.strides[0] = 1 + self.owns_data = 1 + + def __add__(self, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: + result: ndarray | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + result.data[i] = self.data[i] + other.data[i] + i += 1 + return result + + def __sub__(self, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: + result: ndarray | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + result.data[i] = self.data[i] - other.data[i] + i += 1 + return result + + def __mul__(self, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: + result: ndarray | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + result.data[i] = self.data[i] * other.data[i] + i += 1 + return result + + def __truediv__(self, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: + result: ndarray | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != t.CDouble(0.0): + result.data[i] = self.data[i] / other.data[i] + else: + result.data[i] = t.CDouble(0.0) + i += 1 + return result + + def __floordiv__(self, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: + result: ndarray | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != t.CDouble(0.0): + result.data[i] = vipermath.floor(self.data[i] / other.data[i]) + else: + result.data[i] = t.CDouble(0.0) + i += 1 + return result + + def __mod__(self, other: 'ndarray' | t.CPtr) -> 'ndarray' | t.CPtr: + result: ndarray | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != t.CDouble(0.0): + result.data[i] = vipermath.fmod(self.data[i], other.data[i]) + else: + result.data[i] = t.CDouble(0.0) + i += 1 + return result + + def __neg__(self) -> 'ndarray' | t.CPtr: + result: ndarray | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + result.data[i] = -self.data[i] + i += 1 + return result + + def __len__(self) -> t.CInt: + if self.ndim > 0: return t.CInt(self.shape[0]) + return 0 + + def at2d(self, row: t.CSizeT, col: t.CSizeT) -> t.CDouble: + return self.data[row * self.shape[1] + col] + + def set2d(self, row: t.CSizeT, col: t.CSizeT, val: t.CDouble): + self.data[row * self.shape[1] + col] = val + + def delete(self): + if self.owns_data and self.data: + self.pool.free(self.data) + self.data = None + self.pool.free(self) + + def fill(self, val: t.CDouble): + i: t.CSizeT = 0 + while i < self.size: + self.data[i] = val + i += 1 + + def copy(self) -> 'ndarray' | t.CPtr: + result: ndarray | t.CPtr = _empty_like(self) + if not result: return None + memcpy(result.data, self.data, self.size * t.CDouble.__sizeof__()) + return result + + def reshape(self, new_shape: INTPTR, new_ndim: t.CInt) -> 'ndarray' | t.CPtr: + new_size: t.CSizeT = 1 + i: t.CInt = 0 + for i in range(new_ndim): + new_size *= t.CSizeT(new_shape[i]) + if new_size != self.size: return None + result: ndarray | t.CPtr = _alloc_ndarray(self.pool) + if not result: return None + result.data = self.data + result.pool = self.pool + result.ndim = new_ndim + result.size = self.size + result.owns_data = 0 + for i in range(new_ndim): + result.shape[i] = t.CSizeT(new_shape[i]) + _compute_strides(result) + return result + + def sum(self) -> t.CDouble: + s: t.CDouble = t.CDouble(0.0) + i: t.CSizeT = 0 + while i < self.size: + s += self.data[i] + i += 1 + return s + + def mean(self) -> t.CDouble: + if self.size == 0: return t.CDouble(0.0) + return self.sum() / t.CDouble(self.size) + + def min(self) -> t.CDouble: + if self.size == 0: return t.CDouble(0.0) + m: t.CDouble = self.data[0] + i: t.CSizeT = 1 + while i < self.size: + if self.data[i] < m: m = self.data[i] + i += 1 + return m + + def max(self) -> t.CDouble: + if self.size == 0: return t.CDouble(0.0) + m: t.CDouble = self.data[0] + i: t.CSizeT = 1 + while i < self.size: + if self.data[i] > m: m = self.data[i] + i += 1 + return m + + def argmax(self) -> t.CInt: + if self.size == 0: return -1 + m: t.CDouble = self.data[0] + idx: t.CInt = 0 + i: t.CSizeT = 1 + while i < self.size: + if self.data[i] > m: + m = self.data[i] + idx = t.CInt(i) + i += 1 + return idx + + def argmin(self) -> t.CInt: + if self.size == 0: return -1 + m: t.CDouble = self.data[0] + idx: t.CInt = 0 + i: t.CSizeT = 1 + while i < self.size: + if self.data[i] < m: + m = self.data[i] + idx = t.CInt(i) + i += 1 + return idx + + def dot(self, other: 'ndarray' | t.CPtr) -> t.CDouble: + s: t.CDouble = t.CDouble(0.0) + n: t.CSizeT = self.size if (self.size < other.size) else other.size + i: t.CSizeT = 0 + while i < n: + s += self.data[i] * other.data[i] + i += 1 + return s + + def T(self) -> 'ndarray' | t.CPtr: + if self.ndim != 2: return None + rows: t.CSizeT = self.shape[0] + cols: t.CSizeT = self.shape[1] + result: ndarray | t.CPtr = empty2d(self.pool, rows, cols) + if not result: return None + # Swap shape for transpose + result.shape[0] = cols + result.shape[1] = rows + _compute_strides(result) + i: t.CSizeT = 0 + while i < rows: + j: t.CSizeT = 0 + while j < cols: + result.data[j * rows + i] = self.data[i * cols + j] + j += 1 + i += 1 + return result + + def print_arr(self): + if self.ndim == 1: + printf("[") + i: t.CSizeT = 0 + while i < self.size: + if i > 0: printf(", ") + printf("%.4f", self.data[i]) + i += 1 + printf("]\n") + elif self.ndim == 2: + rows: t.CSizeT = self.shape[0] + cols: t.CSizeT = self.shape[1] + printf("[") + i: t.CSizeT = 0 + while i < rows: + if i > 0: printf(" ") + printf("[") + j: t.CSizeT = 0 + while j < cols: + if j > 0: printf(", ") + printf("%.4f", self.data[i * cols + j]) + j += 1 + if i < rows - 1: + printf("]\n") + else: + printf("]]\n") + i += 1 + + +# ============================================================ +# Internal helpers +# ============================================================ +def _alloc_ndarray(pool: mpool.MPool | t.CPtr) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = pool.alloc(ndarray.__sizeof__()) + if a: + memset(a, 0, ndarray.__sizeof__()) + return a + +def _compute_strides(a: ndarray | t.CPtr): + if a.ndim <= 0: return + a.strides[a.ndim - 1] = 1 + i: t.CInt = a.ndim - 2 + while i >= 0: + a.strides[i] = a.strides[i + 1] * a.shape[i + 1] + i -= 1 + +def _empty_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _alloc_ndarray(a.pool) + if not result: return None + result.data = a.pool.alloc(a.size * t.CDouble.__sizeof__()) + if not result.data: + a.pool.free(result) + return None + result.pool = a.pool + result.ndim = a.ndim + result.size = a.size + result.owns_data = 1 + i: t.CInt = 0 + for i in range(a.ndim): + result.shape[i] = a.shape[i] + _compute_strides(result) + return result + + +# ============================================================ +# Array creation functions +# ============================================================ +def array(pool: mpool.MPool | t.CPtr, data: t.CDouble | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = _alloc_ndarray(pool) + if not a: return None + a.data = pool.alloc(n * t.CDouble.__sizeof__()) + if not a.data: + pool.free(a) + return None + memcpy(a.data, data, n * t.CDouble.__sizeof__()) + a.pool = pool + a.ndim = 1 + a.size = n + a.shape[0] = n + a.strides[0] = 1 + a.owns_data = 1 + return a + +def zeros(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = _alloc_ndarray(pool) + if not a: return None + a.data = pool.alloc(n * t.CDouble.__sizeof__()) + if not a.data: + pool.free(a) + return None + memset(a.data, 0, n * t.CDouble.__sizeof__()) + a.pool = pool + a.ndim = 1 + a.size = n + a.shape[0] = n + a.strides[0] = 1 + a.owns_data = 1 + return a + +def ones(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = zeros(pool, n) + if not a: return None + a.fill(t.CDouble(1.0)) + return a + +def full(pool: mpool.MPool | t.CPtr, n: t.CSizeT, val: t.CDouble) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = zeros(pool, n) + if not a: return None + a.fill(val) + return a + +def arange(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble, step: t.CDouble) -> ndarray | t.CPtr: + if step == t.CDouble(0.0): return None + n: t.CSizeT = 0 + if step > t.CDouble(0.0): + v: t.CDouble = start + while v < stop: + n += 1 + v += step + else: + v: t.CDouble = start + while v > stop: + n += 1 + v += step + if n == 0: return None + a: ndarray | t.CPtr = zeros(pool, n) + if not a: return None + i: t.CSizeT = 0 + v = start + while i < n: + a.data[i] = v + v += step + i += 1 + return a + +def linspace(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble, num: t.CSizeT) -> ndarray | t.CPtr: + if num == 0: return None + a: ndarray | t.CPtr = zeros(pool, num) + if not a: return None + if num == 1: + a.data[0] = start + return a + step: t.CDouble = (stop - start) / t.CDouble(num - 1) + i: t.CSizeT = 0 + while i < num: + a.data[i] = start + t.CDouble(i) * step + i += 1 + return a + +def empty2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = _alloc_ndarray(pool) + if not a: return None + total: t.CSizeT = rows * cols + a.data = pool.alloc(total * t.CDouble.__sizeof__()) + if not a.data: + pool.free(a) + return None + memset(a.data, 0, total * t.CDouble.__sizeof__()) + a.pool = pool + a.ndim = 2 + a.size = total + a.shape[0] = rows + a.shape[1] = cols + a.owns_data = 1 + _compute_strides(a) + return a + +def zeros2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: + return empty2d(pool, rows, cols) + +def ones2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = empty2d(pool, rows, cols) + if not a: return None + a.fill(t.CDouble(1.0)) + return a + +def eye(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = empty2d(pool, n, n) + if not a: return None + i: t.CSizeT = 0 + while i < n: + a.data[i * n + i] = t.CDouble(1.0) + i += 1 + return a + +def diag(pool: mpool.MPool | t.CPtr, vals: ndarray | t.CPtr) -> ndarray | t.CPtr: + n: t.CSizeT = vals.size + a: ndarray | t.CPtr = empty2d(pool, n, n) + if not a: return None + i: t.CSizeT = 0 + while i < n: + a.data[i * n + i] = vals.data[i] + i += 1 + return a + + +# ============================================================ +# Mathematical functions (element-wise) +# ============================================================ +def np_abs(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + v: t.CDouble = a.data[i] + result.data[i] = v if v >= t.CDouble(0.0) else -v + i += 1 + return result + +def np_sqrt(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.sqrt(a.data[i]) + i += 1 + return result + +def np_exp(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.exp(a.data[i]) + i += 1 + return result + +def np_log(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.log(a.data[i]) + i += 1 + return result + +def np_sin(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.sin(a.data[i]) + i += 1 + return result + +def np_cos(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.cos(a.data[i]) + i += 1 + return result + +def np_tan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.tan(a.data[i]) + i += 1 + return result + +def np_pow(a: ndarray | t.CPtr, p: t.CDouble) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.pow(a.data[i], p) + i += 1 + return result + + +# ============================================================ +# Scalar operations +# ============================================================ +def add_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] + s + i += 1 + return result + +def mul_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] * s + i += 1 + return result + +def sub_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] - s + i += 1 + return result + +def div_scalar(a: ndarray | t.CPtr, s: t.CDouble) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + if s != t.CDouble(0.0): + result.data[i] = a.data[i] / s + else: + result.data[i] = t.CDouble(0.0) + i += 1 + return result + + +# ============================================================ +# Matrix operations +# ============================================================ +def matmul(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + # 2D matrix multiply: a(m,k) x b(k,n) = c(m,n) + if a.ndim != 2 or b.ndim != 2: return None + m: t.CSizeT = a.shape[0] + k: t.CSizeT = a.shape[1] + k2: t.CSizeT = b.shape[0] + n: t.CSizeT = b.shape[1] + if k != k2: return None + c: ndarray | t.CPtr = empty2d(a.pool, m, n) + if not c: return None + i: t.CSizeT = 0 + while i < m: + j: t.CSizeT = 0 + while j < n: + s: t.CDouble = t.CDouble(0.0) + p: t.CSizeT = 0 + while p < k: + s += a.data[i * k + p] * b.data[p * n + j] + p += 1 + c.data[i * n + j] = s + j += 1 + i += 1 + return c + +def dot_product(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> t.CDouble: + return a.dot(b) + + +# ============================================================ +# Reduction operations +# ============================================================ +def np_sum(a: ndarray | t.CPtr) -> t.CDouble: + return a.sum() + +def np_mean(a: ndarray | t.CPtr) -> t.CDouble: + return a.mean() + +def np_min(a: ndarray | t.CPtr) -> t.CDouble: + return a.min() + +def np_max(a: ndarray | t.CPtr) -> t.CDouble: + return a.max() + +def np_argmax(a: ndarray | t.CPtr) -> t.CInt: + return a.argmax() + +def np_argmin(a: ndarray | t.CPtr) -> t.CInt: + return a.argmin() + + +# ============================================================ +# Utility +# ============================================================ +def var(a: ndarray | t.CPtr) -> t.CDouble: + if a.size == 0: return t.CDouble(0.0) + m: t.CDouble = a.mean() + s: t.CDouble = t.CDouble(0.0) + i: t.CSizeT = 0 + while i < a.size: + d: t.CDouble = a.data[i] - m + s += d * d + i += 1 + return s / t.CDouble(a.size) + +def std(a: ndarray | t.CPtr) -> t.CDouble: + return vipermath.sqrt(var(a)) + +def norm(a: ndarray | t.CPtr) -> t.CDouble: + return vipermath.sqrt(a.dot(a)) + +def clip(a: ndarray | t.CPtr, lo: t.CDouble, hi: t.CDouble) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + v: t.CDouble = a.data[i] + if v < lo: v = lo + if v > hi: v = hi + result.data[i] = v + i += 1 + return result + +def concatenate(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + if a.ndim != 1 or b.ndim != 1: return None + total: t.CSizeT = a.size + b.size + result: ndarray | t.CPtr = zeros(a.pool, total) + if not result: return None + memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) + memcpy(result.data + a.size, b.data, b.size * t.CDouble.__sizeof__()) + return result + +def sort_arr(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = a.copy() + if not result: return None + # Simple insertion sort + i: t.CSizeT = 1 + while i < result.size: + key: t.CDouble = result.data[i] + j: t.CSizeT = i - 1 + while j < result.size and result.data[j] > key: + result.data[j + 1] = result.data[j] + if j == 0: break + j -= 1 + if j > 0 or result.data[0] <= key: + result.data[j + 1] = key + else: + result.data[1] = result.data[0] + result.data[0] = key + i += 1 + return result + +def reverse(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[a.size - 1 - i] + i += 1 + return result + + +# ============================================================ +# Additional math functions (element-wise) +# ============================================================ +def np_log10(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.log10(a.data[i]) + i += 1 + return result + +def np_log2(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.log2(a.data[i]) + i += 1 + return result + +def np_floor(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.floor(a.data[i]) + i += 1 + return result + +def np_ceil(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.ceil(a.data[i]) + i += 1 + return result + +def np_round(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.round(a.data[i]) + i += 1 + return result + +def np_sign(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + if a.data[i] > t.CDouble(0.0): + result.data[i] = t.CDouble(1.0) + elif a.data[i] < t.CDouble(0.0): + result.data[i] = t.CDouble(-1.0) + else: + result.data[i] = t.CDouble(0.0) + i += 1 + return result + +def np_tanh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.tanh(a.data[i]) + i += 1 + return result + +def np_sinh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.sinh(a.data[i]) + i += 1 + return result + +def np_cosh(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.cosh(a.data[i]) + i += 1 + return result + +def np_arcsin(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.asin(a.data[i]) + i += 1 + return result + +def np_arccos(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.acos(a.data[i]) + i += 1 + return result + +def np_arctan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.atan(a.data[i]) + i += 1 + return result + +def np_arctan2(y: ndarray | t.CPtr, x: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(y) + if not result: return None + i: t.CSizeT = 0 + while i < y.size: + result.data[i] = vipermath.atan2(y.data[i], x.data[i]) + i += 1 + return result + +def np_degrees(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.degrees(a.data[i]) + i += 1 + return result + +def np_radians(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = vipermath.radians(a.data[i]) + i += 1 + return result + +def np_isnan(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(vipermath.isnan(a.data[i])) + i += 1 + return result + +def np_isinf(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(vipermath.isinf(a.data[i])) + i += 1 + return result + +def np_maximum(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] if a.data[i] > b.data[i] else b.data[i] + i += 1 + return result + +def np_minimum(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = a.data[i] if a.data[i] < b.data[i] else b.data[i] + i += 1 + return result + + +# ============================================================ +# Additional array operations +# ============================================================ +def cumsum(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + s: t.CDouble = t.CDouble(0.0) + i: t.CSizeT = 0 + while i < a.size: + s += a.data[i] + result.data[i] = s + i += 1 + return result + +def diff(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + if a.size < 2: return None + result: ndarray | t.CPtr = zeros(a.pool, a.size - 1) + if not result: return None + i: t.CSizeT = 0 + while i < a.size - 1: + result.data[i] = a.data[i + 1] - a.data[i] + i += 1 + return result + +def flatten(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + result.ndim = 1 + result.shape[0] = a.size + result.strides[0] = 1 + memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) + return result + +def trace(a: ndarray | t.CPtr) -> t.CDouble: + if a.ndim != 2: return t.CDouble(0.0) + n: t.CSizeT = a.shape[0] if a.shape[0] < a.shape[1] else a.shape[1] + s: t.CDouble = t.CDouble(0.0) + i: t.CSizeT = 0 + while i < n: + s += a.data[i * a.shape[1] + i] + i += 1 + return s + +def outer(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = empty2d(a.pool, a.size, b.size) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + j: t.CSizeT = 0 + while j < b.size: + result.data[i * b.size + j] = a.data[i] * b.data[j] + j += 1 + i += 1 + return result + +def np_where(condition: ndarray | t.CPtr, x: ndarray | t.CPtr, y: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(x) + if not result: return None + i: t.CSizeT = 0 + while i < x.size: + if condition.data[i] != t.CDouble(0.0): + result.data[i] = x.data[i] + else: + result.data[i] = y.data[i] + i += 1 + return result + +def np_count_nonzero(a: ndarray | t.CPtr) -> t.CInt: + count: t.CInt = 0 + i: t.CSizeT = 0 + while i < a.size: + if a.data[i] != t.CDouble(0.0): + count += 1 + i += 1 + return count + +def np_all(a: ndarray | t.CPtr) -> t.CInt: + i: t.CSizeT = 0 + while i < a.size: + if a.data[i] == t.CDouble(0.0): + return 0 + i += 1 + return 1 + +def np_any(a: ndarray | t.CPtr) -> t.CInt: + i: t.CSizeT = 0 + while i < a.size: + if a.data[i] != t.CDouble(0.0): + return 1 + i += 1 + return 0 + +def np_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] == b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_not_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] != b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_less(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] < b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_greater(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] > b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_less_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] <= b.data[i] else t.CDouble(0.0) + i += 1 + return result + +def np_greater_equal(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + i: t.CSizeT = 0 + while i < a.size: + result.data[i] = t.CDouble(1.0) if a.data[i] >= b.data[i] else t.CDouble(0.0) + i += 1 + return result + + +# ============================================================ +# Additional creation functions +# ============================================================ +def empty(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> ndarray | t.CPtr: + return zeros(pool, n) + +def full2d(pool: mpool.MPool | t.CPtr, rows: t.CSizeT, cols: t.CSizeT, val: t.CDouble) -> ndarray | t.CPtr: + a: ndarray | t.CPtr = empty2d(pool, rows, cols) + if not a: return None + a.fill(val) + return a + +def zeros_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _alloc_ndarray(a.pool) + if not result: return None + result.data = a.pool.alloc(a.size * t.CDouble.__sizeof__()) + if not result.data: + a.pool.free(result) + return None + memset(result.data, 0, a.size * t.CDouble.__sizeof__()) + result.pool = a.pool + result.ndim = a.ndim + result.size = a.size + result.owns_data = 1 + i: t.CInt = 0 + for i in range(a.ndim): + result.shape[i] = a.shape[i] + _compute_strides(result) + return result + +def ones_like(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + result: ndarray | t.CPtr = _empty_like(a) + if not result: return None + result.fill(t.CDouble(1.0)) + return result + +def arange1(pool: mpool.MPool | t.CPtr, stop: t.CDouble) -> ndarray | t.CPtr: + return arange(pool, t.CDouble(0.0), stop, t.CDouble(1.0)) + +def linspace2(pool: mpool.MPool | t.CPtr, start: t.CDouble, stop: t.CDouble) -> ndarray | t.CPtr: + return linspace(pool, start, stop, 50) + +def meshgrid(x: ndarray | t.CPtr, y: ndarray | t.CPtr) -> ndarray | t.CPtr: + # Returns flattened grid pairs - simplified version + # Returns X grid as 2D array (each row is x) + result: ndarray | t.CPtr = empty2d(x.pool, y.size, x.size) + if not result: return None + i: t.CSizeT = 0 + while i < y.size: + j: t.CSizeT = 0 + while j < x.size: + result.data[i * x.size + j] = x.data[j] + j += 1 + i += 1 + return result + + +# ============================================================ +# Linear algebra helpers +# ============================================================ +def det2x2(a: ndarray | t.CPtr) -> t.CDouble: + # Determinant of 2x2 matrix + if a.ndim != 2: return t.CDouble(0.0) + if a.shape[0] != 2 or a.shape[1] != 2: return t.CDouble(0.0) + return a.data[0] * a.data[3] - a.data[1] * a.data[2] + +def inv2x2(a: ndarray | t.CPtr) -> ndarray | t.CPtr: + # Inverse of 2x2 matrix + d: t.CDouble = det2x2(a) + if d == t.CDouble(0.0): return None + result: ndarray | t.CPtr = empty2d(a.pool, 2, 2) + if not result: return None + result.data[0] = a.data[3] / d + result.data[1] = -a.data[1] / d + result.data[2] = -a.data[2] / d + result.data[3] = a.data[0] / d + return result + +def cross3(a: ndarray | t.CPtr, b: ndarray | t.CPtr) -> ndarray | t.CPtr: + # Cross product of 3D vectors + result: ndarray | t.CPtr = zeros(a.pool, 3) + if not result: return None + result.data[0] = a.data[1] * b.data[2] - a.data[2] * b.data[1] + result.data[1] = a.data[2] * b.data[0] - a.data[0] * b.data[2] + result.data[2] = a.data[0] * b.data[1] - a.data[1] * b.data[0] + return result + +def np_interp(x: t.CDouble, xp: ndarray | t.CPtr, fp: ndarray | t.CPtr) -> t.CDouble: + # 1D linear interpolation + if xp.size == 0: return t.CDouble(0.0) + if x <= xp.data[0]: return fp.data[0] + if x >= xp.data[xp.size - 1]: return fp.data[xp.size - 1] + i: t.CSizeT = 0 + while i < xp.size - 1: + if x >= xp.data[i] and x <= xp.data[i + 1]: + t_val: t.CDouble = (x - xp.data[i]) / (xp.data[i + 1] - xp.data[i]) + return fp.data[i] + t_val * (fp.data[i + 1] - fp.data[i]) + i += 1 + return fp.data[xp.size - 1] + +def prod(a: ndarray | t.CPtr) -> t.CDouble: + p: t.CDouble = t.CDouble(1.0) + i: t.CSizeT = 0 + while i < a.size: + p *= a.data[i] + i += 1 + return p + +def median(a: ndarray | t.CPtr) -> t.CDouble: + if a.size == 0: return t.CDouble(0.0) + s: ndarray | t.CPtr = sort_arr(a) + if not s: return t.CDouble(0.0) + mid: t.CSizeT = a.size / 2 + if a.size % 2 == 1: + result: t.CDouble = s.data[mid] + else: + result = (s.data[mid - 1] + s.data[mid]) / t.CDouble(2.0) + s.delete() + return result + +def percentile(a: ndarray | t.CPtr, q: t.CDouble) -> t.CDouble: + if a.size == 0: return t.CDouble(0.0) + s: ndarray | t.CPtr = sort_arr(a) + if not s: return t.CDouble(0.0) + idx: t.CDouble = q / t.CDouble(100.0) * t.CDouble(a.size - 1) + lo: t.CSizeT = t.CSizeT(vipermath.floor(idx)) + hi: t.CSizeT = t.CSizeT(vipermath.ceil(idx)) + frac: t.CDouble = idx - vipermath.floor(idx) + result: t.CDouble = s.data[lo] + frac * (s.data[hi] - s.data[lo]) + s.delete() + return result diff --git a/includes/platmacro.py b/includes/platmacro.py new file mode 100644 index 0000000..5560617 --- /dev/null +++ b/includes/platmacro.py @@ -0,0 +1,57 @@ +import t, c + + +IS_WINDOWS: t.CDefine = 1 +IS_WIN64: t.CDefine = 1 +IS_X86_64: t.CDefine = 1 +IS_LP64: t.CDefine = 1 +IS_LITTLE_ENDIAN: t.CDefine = 1 + +IS_LINUX: t.CDefine = 0 +IS_MACOS: t.CDefine = 0 +IS_ARM64: t.CDefine = 0 +IS_BIG_ENDIAN: t.CDefine = 0 +IS_ILP32: t.CDefine = 0 + +PTR_SIZE: t.CDefine = t.CSizeT().Size +INT_SIZE: t.CDefine = 4 +LONG_SIZE: t.CDefine = t.CLong().Size +WORD_SIZE: t.CDefine = t.CSizeT().Size + +CACHE_LINE_SIZE: t.CDefine = 64 +PAGE_SIZE: t.CDefine = 4096 +STACK_ALIGN: t.CDefine = 16 +MAX_PATH_LEN: t.CDefine = 260 + +PLATFORM_NAME: t.CDefine = 1 +ARCH_NAME: t.CDefine = 1 + +WINVER: t.CDefine = 0x0A00 +_WIN32_WINNT: t.CDefine = 0x0A00 +NTDDI_VERSION: t.CDefine = 0x0A000006 + +HAS_SSE2: t.CDefine = 1 +HAS_AVX: t.CDefine = 1 +HAS_AVX2: t.CDefine = 1 +HAS_FMA: t.CDefine = 1 +HAS_NEON: t.CDefine = 0 + +ALIGNOF_INT: t.CDefine = 4 +ALIGNOF_LONG: t.CDefine = t.CLong().Size // 8 +ALIGNOF_PTR: t.CDefine = t.CSizeT().Size // 8 +ALIGNOF_DOUBLE: t.CDefine = 8 +ALIGNOF_LONG_DOUBLE: t.CDefine = 16 + +SIZEOF_SHORT: t.CDefine = 2 +SIZEOF_INT: t.CDefine = 4 +SIZEOF_LONG: t.CDefine = t.CLong().Size // 8 +SIZEOF_LONG_LONG: t.CDefine = 8 +SIZEOF_FLOAT: t.CDefine = 4 +SIZEOF_DOUBLE: t.CDefine = 8 +SIZEOF_LONG_DOUBLE: t.CDefine = 16 +SIZEOF_POINTER: t.CDefine = t.CSizeT().Size // 8 +SIZEOF_SIZE_T: t.CDefine = t.CSizeT().Size // 8 +SIZEOF_PTRDIFF_T: t.CDefine = t.CPtrDiffT().Size // 8 + +BYTE_ORDER_LE: t.CDefine = 1 +BYTE_ORDER_BE: t.CDefine = 0 diff --git a/includes/plist.py b/includes/plist.py new file mode 100644 index 0000000..dcb2fa2 --- /dev/null +++ b/includes/plist.py @@ -0,0 +1,5 @@ +import t, c + + +#class PList: +# def diff --git a/includes/spinlock.py b/includes/spinlock.py new file mode 100644 index 0000000..df7d3c8 --- /dev/null +++ b/includes/spinlock.py @@ -0,0 +1,18 @@ +import t, c +import atom + + +@t.Object +class _spinlock: + locked: t.CVolatile | t.CInt + name: list[t.CChar, 32] + + def __init__(self): + self.locked = 0 + + def lock(self): + while atom.__atomic_test_and_set(c.Addr(self.locked), atom.ATOMIC_ACQUIRE): + pass + + def unlock(self): + atom.__atomic_clear(c.Addr(self.locked), atom.ATOMIC_RELEASE) diff --git a/includes/stdarg.py b/includes/stdarg.py new file mode 100644 index 0000000..1d0192f --- /dev/null +++ b/includes/stdarg.py @@ -0,0 +1,9 @@ +import t + +def va_start(args: t.CPtr, last_arg: t.CPtr) -> t.State: pass +def va_arg(args: t.CPtr, type: t.CPtr) -> t.CPtr | t.State: pass +def va_end(args: t.CPtr) -> t.State | t.State: pass + +va_list: t.CTypedef = t.CUnsignedChar | t.CPtr + +def arg(type: t.CType) -> t.State: pass \ No newline at end of file diff --git a/includes/stdint.py b/includes/stdint.py new file mode 100644 index 0000000..bc12f01 --- /dev/null +++ b/includes/stdint.py @@ -0,0 +1,72 @@ +import t + + +INT: t.CTypedef = t.CInt +INTPTR: t.CTypedef = t.CInt | t.CPtr + +BOOL: t.CTypedef = t.CInt +UINT: t.CTypedef = t.CUnsignedInt +UINTPTR: t.CTypedef = UINT | t.CPtr +BYTE: t.CTypedef = t.CUnsignedChar +BYTEPTR: t.CTypedef = BYTE | t.CPtr +WORD: t.CTypedef = t.CUInt16T +DWORD: t.CTypedef = t.CUInt32T +QWORD: t.CTypedef = t.CUInt64T +TCHAR: t.CTypedef = t.CChar +CHARLIST: t.CTypedef = str | t.CPtr +VOID: t.CTypedef = t.CVoid + +SHORT: t.CTypedef = t.CShort +SHORTPTR: t.CTypedef = t.CShort | t.CPtr +USHORT: t.CTypedef = t.CUnsignedShort +USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr + +LONGLONG: t.CTypedef = t.CLong | t.CLong +ULONGLONG: t.CTypedef = t.CUnsignedLong | t.CLong +LONG: t.CTypedef = t.CLong +ULONG: t.CTypedef = t.CUnsignedLong + +WCHAR: t.CTypedef = WORD +WCHARPTR: t.CTypedef = WORD | t.CPtr +CHARPTR: t.CTypedef = t.CChar | t.CPtr +FSIZE_t: t.CTypedef = DWORD +LBA_t: t.CTypedef = DWORD + +UINTPTR: t.CTypedef = t.CUnsignedInt | t.CPtr +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +FLOAT: t.CTypedef = t.CFloat +DOUBLE: t.CTypedef = t.CDouble + +FLOAT8: t.CTypedef = t.CFloat8T +FLOAT16: t.CTypedef = t.CFloat16T +FLOAT32: t.CTypedef = t.CFloat32T +FLOAT64: t.CTypedef = t.CFloat64T +FLOAT128: t.CTypedef = t.CFloat128T + + +INT8: t.CTypedef = t.CInt8T +INT16: t.CTypedef = t.CInt16T +INT32: t.CTypedef = t.CInt32T +INT64: t.CTypedef = t.CInt64T + +UINT8: t.CTypedef = t.CUInt8T +UINT16: t.CTypedef = t.CUInt16T +UINT32: t.CTypedef = t.CUInt32T +UINT64: t.CTypedef = t.CUInt64T + +INT8PTR: t.CTypedef = t.CInt8T | t.CPtr +INT16PTR: t.CTypedef = t.CInt16T | t.CPtr +INT32PTR: t.CTypedef = t.CInt32T | t.CPtr +INT64PTR: t.CTypedef = t.CInt64T | t.CPtr + +UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr +UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr +UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr +UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr + +CHAR8: t.CTypedef = t.CChar8T +CHAR16: t.CTypedef = t.CChar16T +CHAR32: t.CTypedef = t.CChar32T +CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr +CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr +CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr diff --git a/includes/stdio.py b/includes/stdio.py new file mode 100644 index 0000000..4fbe4cf --- /dev/null +++ b/includes/stdio.py @@ -0,0 +1,15 @@ +import t, c + + +def printf(fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass +def fprintf(stream: t.CVoid | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass +def sprintf(buf: t.CChar | t.CPtr, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.CExtern | t.CExport: pass +def puts(s: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass +def fputs(s: t.CChar | t.CConst | t.CPtr, stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +stdin: t.CVoid | t.CPtr +stdout: t.CVoid | t.CPtr +stderr: t.CVoid | t.CPtr diff --git a/includes/stdlib.py b/includes/stdlib.py new file mode 100644 index 0000000..9b603d5 --- /dev/null +++ b/includes/stdlib.py @@ -0,0 +1,9 @@ +from stdint import * +import t + + + +def malloc(size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass +def calloc(nmemb: UINT, size: UINT) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass +def realloc(p: str, p2: t.CLong | t.CLong) -> t.CVoid | t.CPtr | t.State | t.CExtern | t.CExport: pass +def free(p: t.CVoid | t.CPtr) -> None | t.State | t.CExtern | t.CExport: pass \ No newline at end of file diff --git a/includes/string.py b/includes/string.py new file mode 100644 index 0000000..016596b --- /dev/null +++ b/includes/string.py @@ -0,0 +1,314 @@ +from stdint import * +import t, c + + +# 字符串复制函数 +def strcpy(dest: str, src: str) -> str: + if dest == None or src == None: return None + original_dest: str = dest + for s in src: + dest[0] = s + dest += 1 + dest[0] = 0 + return original_dest + + +# 有限长度字符串复制函数 +def strncpy(dest: str, src: str, n: t.CSizeT) -> str: + if dest == None or src == None or n == 0: return dest + original_dest: str = dest + i: t.CSizeT = 0 + for s in src: + if i >= n: break + dest[0] = s + dest += 1 + i += 1 + # 填充剩余空间为 '\0' + while i < n: + dest[0] = 0 + dest += 1 + i += 1 + return original_dest + + +# 字符串长度函数 +def strlen(src: str) -> t.CSizeT | t.CExport: + length: t.CSizeT = 0 + for _ in src: + length += 1 + return length + +# 字符串比较函数 +def strcmp(str1: str, str2: str) -> t.CInt: + while str1[0] != '\0' and str2[0] != '\0': + if str1[0] != str2[0]: + return str1[0] - str2[0] + str1 += 1 + str2 += 1 + return str1[0] - str2[0] + +def samestr(str1: str, str2: str) -> bool: + return strcmp(str1, str2) == 0 + + +# 有限长度字符串比较函数 +def strncmp(str1: str, str2: str, n: t.CSizeT) -> t.CInt: + i: t.CSizeT = 0 + while str1[0] != '\0' and str2[0] != '\0' and i < n: + if str1[0] != str2[0]: + return str1[0] - str2[0] + str1 += 1 + str2 += 1 + i += 1 + if i < n: + return str1[0] - str2[0] + return 0 + + +# 内存比较函数 +def memcmp(ptr1: t.CVoid | t.CPtr, ptr2: t.CVoid | t.CPtr, n: t.CSizeT) -> t.CInt: + p1: BYTEPTR = BYTEPTR(ptr1) + p2: BYTEPTR = BYTEPTR(ptr2) + i: t.CSizeT = 0 + while i < n: + if p1[i] != p2[i]: + return t.CInt(p1[i]) - t.CInt(p2[i]) + i += 1 + return 0 + + +# 字符串查找函数 +def strchr(s: str, cr: t.CInt) -> str: + while s[0] != '\0': + if s[0] == t.CChar(cr): + return str(s) + s += 1 + if cr == '\0': + return str(s) + return None + +# 字符串反向查找函数(找最后一次出现的字符) +def strrchr(s: str, cr: t.CInt) -> str: + last: str = None + while s[0] != '\0': + if s[0] == t.CChar(cr): + last = s + s += 1 + if cr == '\0': return s + return last + +# 跳过字符 +def strspn(s: str, skip: str = " ") -> int: + si: int = 0 + while s[si] == skip: + si += 1 + return si + +# 内存设置函数 +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: + # 原始实现: + # p: BYTEPTR = BYTEPTR(ptr) + # i: t.CSizeT + # for i in range(num): + # p[i] = t.CUnsignedChar(value) + if num == 0: return ptr + c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)} + mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)} + rep stosb""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, + t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI]) + return ptr + + +def memset32(ptr: t.CVoid | t.CPtr, value: t.CUInt32T, count: t.CSizeT) -> t.CVoid | t.CPtr: + # 原始实现: + # p: UINT32PTR = UINT32PTR(ptr) + # i: t.CSizeT + # for i in range(count): + # p[i] = value + if count == 0: return ptr + c.Asm(f"""mov rdi, {c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)} + mov eax, {c.AsmInp(value, t.ASM_DESCR.REG_ANY)} + mov rcx, {c.AsmInp(count, t.ASM_DESCR.REG_ANY)} + rep stosd""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, + t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDI]) + return ptr + + +# 内存复制函数 +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: + # 原始实现: + # d: BYTEPTR = BYTEPTR(dest) + # s: BYTEPTR = BYTEPTR(src) + # i: t.CSizeT + # for i in range(num): + # d[i] = s[i] + if num == 0: return dest + c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)} + mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)} + mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)} + rep movsb""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX, + t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI]) + return dest + + +# 内存移动函数 +def memmove(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr: + # 原始实现: + # d: BYTEPTR = BYTEPTR(dest) + # s: BYTEPTR = BYTEPTR(src) + # i: t.CSizeT + # if d < s: + # for i in range(num): + # d[i] = s[i] + # elif d > s: + # for i in range(num, 0, -1): + # d[i - 1] = s[i - 1] + if num == 0: return dest + c.Asm(f"""mov rdi, {c.AsmInp(dest, t.ASM_DESCR.REG_ANY)} + mov rsi, {c.AsmInp(src, t.ASM_DESCR.REG_ANY)} + mov rcx, {c.AsmInp(num, t.ASM_DESCR.REG_ANY)} + cmp rdi, rsi + jb 2f + std + add rdi, rcx + dec rdi + add rsi, rcx + dec rsi + rep movsb + cld + jmp 3f + 2: + rep movsb + 3:""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RCX, + t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI]) + return dest + + +def atoi(src: str) -> t.CInt: + num: t.CInt = 0 + sign: t.CInt = 1 + s: str = src + if s == None: return 0 + # 跳过空白 + while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r': + s += 1 + # 符号 + if s[0] == '-': + sign = -1 + s += 1 + elif s[0] == '+': + s += 1 + for ch in s: + if ch < '0' or ch > '9': break + digit: t.CInt = ch - '0' + num = num * 10 + digit + return num * sign + + +def atoll(src: str) -> t.CInt64T: + num: t.CInt64T = 0 + sign: t.CInt64T = 1 + s: str = src + if s == None: return 0 + while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r': + s += 1 + if s[0] == '-': + sign = -1 + s += 1 + elif s[0] == '+': + s += 1 + for ch in s: + if ch < '0' or ch > '9': break + d: t.CInt = ch - '0' + digit: t.CInt64T = t.CInt64T(d) + num = num * 10 + digit + return num * sign + + +def atof(src: str) -> t.CDouble: + s: str = src + if s == None: return 0.0 + # 跳过空白 + while s[0] == ' ' or s[0] == '\t' or s[0] == '\n' or s[0] == '\r': + s += 1 + # 符号 + sign: t.CDouble = 1.0 + if s[0] == '-': + sign = -1.0 + s += 1 + elif s[0] == '+': + s += 1 + # 整数部分 + int_part: t.CDouble = 0.0 + for ch in s: + if ch < '0' or ch > '9': break + d1: t.CInt = ch - '0' + int_part = int_part * 10.0 + t.CDouble(d1) + s += 1 + # 小数部分 + frac_part: t.CDouble = 0.0 + frac_div: t.CDouble = 1.0 + if s[0] == '.': + s += 1 + for ch in s: + if ch < '0' or ch > '9': break + d2: t.CInt = ch - '0' + frac_div = frac_div * 10.0 + frac_part = frac_part * 10.0 + t.CDouble(d2) + s += 1 + # 指数部分 + exp: t.CInt = 0 + exp_sign: t.CInt = 1 + if s[0] == 'e' or s[0] == 'E': + s += 1 + if s[0] == '-': + exp_sign = -1 + s += 1 + elif s[0] == '+': + s += 1 + for ch in s: + if ch < '0' or ch > '9': break + d3: t.CInt = ch - '0' + exp = exp * 10 + d3 + s += 1 + exp = exp * exp_sign + result: t.CDouble = sign * (int_part + frac_part / frac_div) + # 应用指数 + if exp > 0: + while exp > 0: + result = result * 10.0 + exp -= 1 + elif exp < 0: + while exp < 0: + result = result / 10.0 + exp += 1 + return result + +def split(s: str, delim: str, result: list[str]) -> int: + count: int = 0 + start: str = s + if not s or not delim or not result: + return 0 + d: t.CChar = delim[0] # 单分隔符 + + while start[0]: + # 跳过分隔符 + while start[0] == d: start += 1 + if not start[0]: break + + # 记录token起始 + result[count] = start + count += 1 + + # 找到下一个分隔符,截断 + while start[0] and start[0] != d: start += 1 + if start[0]: + start[0] = '\0' + start += 1 + result[count] = None # 结尾标记 + return count \ No newline at end of file diff --git a/includes/sys.py b/includes/sys.py new file mode 100644 index 0000000..f78ca32 --- /dev/null +++ b/includes/sys.py @@ -0,0 +1,8 @@ +import t, c + + +def fgets(buf: t.CChar | t.CPtr, size: t.CInt, stream: t.CVoid | t.CPtr) -> t.CChar | t.CPtr | t.CExtern | t.CExport: pass + +def fflush(stream: t.CVoid | t.CPtr) -> t.CInt | t.CExtern | t.CExport: pass + +stdin: t.CVoid | t.CPtr diff --git a/includes/vector.py b/includes/vector.py new file mode 100644 index 0000000..a950c2a --- /dev/null +++ b/includes/vector.py @@ -0,0 +1,66 @@ +import t, c +from stdint import * +import mpool + + +class Vector[T](): + data: t.CVoid | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + elem_size: t.CSizeT + pool: mpool.MPool | t.CPtr + + def __init__(self, pool: mpool.MPool | t.CPtr, capacity: t.CSizeT, _hint: T): + self.elem_size = T.__sizeof__() + self.capacity = capacity + self.length = 0 + self.pool = pool + self.data = pool.alloc(capacity * self.elem_size) + + def push(self, value: T): + if self.data == None: return + if self.length >= self.capacity: + self._grow() + if self.length >= self.capacity: return + offset: t.CUInt64T = t.CUInt64T(self.data) + self.length * self.elem_size + dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr) + c.DerefAs(dst, value) + self.length += 1 + + def _grow(self): + if self.pool == None: return + new_capacity: t.CSizeT = self.capacity * 2 + if new_capacity == 0: new_capacity = 4 + old_size: t.CSizeT = self.capacity * self.elem_size + new_size: t.CSizeT = new_capacity * self.elem_size + new_data: t.CVoid | t.CPtr = self.pool.realloc(self.data, old_size, new_size) + if new_data == None: return + self.data = new_data + self.capacity = new_capacity + + def get(self, index: t.CSizeT) -> T: + if self.data == None: return T(0) + offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size + typed_ptr = T(offset, t.CPtr) + return c.Deref(typed_ptr) + + def set(self, index: t.CSizeT, value: T): + if index >= self.length: return + if self.data == None: return + offset: t.CUInt64T = t.CUInt64T(self.data) + index * self.elem_size + dst: t.CVoid | t.CPtr = t.CVoid(offset, t.CPtr) + c.DerefAs(dst, value) + + def len(self) -> t.CSizeT: + return self.length + + def clear(self): + self.length = 0 + + def free(self): + if self.data != None: + if self.pool != None: + self.pool.free(self.data) + self.data = None + self.length = 0 + self.capacity = 0 diff --git a/includes/viperio.py b/includes/viperio.py new file mode 100644 index 0000000..9485919 --- /dev/null +++ b/includes/viperio.py @@ -0,0 +1,57 @@ +import t, c +from stdint import * + + +class Buf: + data: t.CChar | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + owned: bool + + def __init__(self, data: t.CChar | t.CPtr, capacity: t.CSizeT, length: t.CSizeT = 0, owned: bool = False): + self.data = data + self.capacity = capacity + self.length = length + self.owned = owned + + def clear(self): + self.length = 0 + if self.data != None and self.capacity > 0: + self.data[0] = 0 + + def write(self, src: t.CChar | t.CPtr, count: t.CSizeT) -> t.CSizeT: + if self.data == None: return 0 + if src == None: return 0 + if count == 0: return 0 + avail: t.CSizeT = self.capacity - self.length + if avail <= 0: return 0 + n: t.CSizeT = count if count < avail else avail + i: t.CSizeT = 0 + while i < n: + self.data[self.length + i] = src[i] + i += 1 + self.length += n + self.data[self.length] = 0 + return n + + def cstr(self) -> t.CChar | t.CPtr: + return self.data + + def reset(self): + self.length = 0 + if self.data != None and self.capacity > 0: + self.data[0] = 0 + + def __enter__(self) -> 'Buf' | t.CPtr: + return self + + def __exit__(self): + self.reset() + + def free(self): + if self.owned and self.data != None: + self.data[0] = 0 + self.owned = False + self.data = None + self.length = 0 + self.capacity = 0 diff --git a/includes/viperlib.py b/includes/viperlib.py new file mode 100644 index 0000000..d4f2b8f --- /dev/null +++ b/includes/viperlib.py @@ -0,0 +1,372 @@ +import t, c +import viperio +from stdarg import arg + +TEMP_BUF_SIZE: t.CDefine = 24 + +def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt | t.State: + count: t.CInt = 0 + if num == 0: return 1 + while num > 0: + count += 1 + num //= base + return count + +def sprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CVoid | t.State: + if buf == None or rule == None: return + snprintf(buf, 0, rule, 0) + +def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt | t.State: + if buf == None or rule == None: return 0 + return snprintf(buf, 0, rule, 0) + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt | t.State: + if buf == None or fmt == None or size == 0: return 0 + ptr: t.CChar | t.CPtr = buf + write_count: t.CInt = 0 + temp: list[t.CChar, 24] + temp[0] = '\t' + while c.Deref(fmt) != 0 and write_count < size - 1: + if c.Deref(fmt) != 37: + ptr[0] = c.Deref(fmt) + write_count += 1 + ptr += 1 + fmt += 1 + else: + fmt += 1 + if c.Deref(fmt) == 0: break + width: t.CInt = 0 + pad_zero: t.CInt = 0 + left_align: t.CInt = 0 + show_sign: t.CInt = 0 + precision: t.CInt = -1 + is_long: t.CInt = 0 + is_long_long: t.CInt = 0 + is_size: t.CInt = 0 + while True: + if c.Deref(fmt) == 45: + left_align = 1 + fmt += 1 + elif c.Deref(fmt) == 48: + pad_zero = 1 + fmt += 1 + elif c.Deref(fmt) == 43: + show_sign = 1 + fmt += 1 + else: break + while c.Deref(fmt) >= 48 and c.Deref(fmt) <= 57: + width = width * 10 + (c.Deref(fmt) - 48) + fmt += 1 + if c.Deref(fmt) == 46: + fmt += 1 + precision = 0 + while c.Deref(fmt) >= 48 and c.Deref(fmt) <= 57: + precision = precision * 10 + (c.Deref(fmt) - 48) + fmt += 1 + if left_align: pad_zero = 0 + if c.Deref(fmt) == 108: + is_long = 1 + fmt += 1 + if c.Deref(fmt) == 108: + is_long_long = 1 + is_long = 0 + fmt += 1 + elif c.Deref(fmt) == 122: + is_size = 1 + fmt += 1 + if c.Deref(fmt) == 99: + if write_count < size - 1: + ptr_i: t.CInt = arg() + ptr[0] = t.CChar(ptr_i) + write_count += 1 + ptr += 1 + else: + ptr_i: t.CInt = arg() + elif c.Deref(fmt) == 115: + s: str = arg() + if s == None: s = "(None)" + slen: t.CInt = 0 + sc: str = s + while c.Deref(sc) != 0: + slen += 1 + sc += 1 + if not left_align and width > slen: + pad_count: t.CInt = width - slen + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + while c.Deref(s) != 0 and write_count < size - 1: + ptr[0] = c.Deref(s) + write_count += 1 + ptr += 1 + s += 1 + if left_align and width > slen: + pad_count = width - slen + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + elif c.Deref(fmt) == 100: + if is_long or is_long_long or is_size: + num: t.CInt = t.CInt(arg()) + else: + num: t.CInt = arg() + sign: t.CInt = 0 + if num < 0: + sign = 1 + if num == -2147483648: + u_num: t.CUnsignedInt = 2147483648 + else: + u_num: t.CUnsignedInt = t.CUnsignedInt(-num) + else: + u_num: t.CUnsignedInt = t.CUnsignedInt(num) + if show_sign: sign = 2 + i: t.CInt = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + temp[i] = t.CChar(u_num % 10 + 48) + i += 1 + u_num //= 10 + if u_num <= 0: break + if sign == 1 and i < TEMP_BUF_SIZE - 1: + temp[i] = 45 + i += 1 + elif sign == 2 and i < TEMP_BUF_SIZE - 1: + temp[i] = 43 + i += 1 + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += 1 + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += 1 + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + elif c.Deref(fmt) == 117: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = arg(t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(arg())) + i = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + temp[i] = t.CChar(u_num_l % 10 + 48) + i += 1 + u_num_l //= 10 + if u_num_l <= 0: break + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += 1 + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += 1 + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + elif c.Deref(fmt) == 120: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = arg(t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(arg())) + i = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + digit: t.CInt = t.CInt(u_num_l % 16) + if digit < 10: + temp[i] = t.CChar(digit + 48) + else: + temp[i] = t.CChar(digit - 10 + 97) + u_num_l //= 16 + i += 1 + if u_num_l <= 0: break + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += 1 + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += 1 + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + elif c.Deref(fmt) == 88: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = arg() + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(arg())) + i = 0 + while True: + if i >= TEMP_BUF_SIZE - 1: break + digit = t.CInt(u_num_l % 16) + if digit < 10: + temp[i] = t.CChar(digit + 48) + else: + temp[i] = t.CChar(digit - 10 + 65) + u_num_l //= 16 + i += 1 + if u_num_l <= 0: break + if not left_align and not pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + if pad_zero and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += 1 + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += 1 + if left_align and width > i: + pad_count = width - i + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + elif c.Deref(fmt) == 102: + if precision < 0: precision = 6 + fv: float = arg() + if fv < 0.0: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += 1 + fv = 0.0 - fv + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += 1 + di: t.CInt = 0 + int_part: t.CUnsignedLong = t.CUnsignedLong(t.CLongLong(fv)) + frac_val: float = fv - float(int_part) + p: t.CInt = 0 + while p < precision: + frac_val *= 10.0 + p += 1 + frac_part: t.CUnsignedLong = t.CUnsignedLong(frac_val + 0.5) + if int_part == 0: + temp[0] = 48 + di = 1 + else: + while int_part > 0 and di < TEMP_BUF_SIZE - 1: + temp[di] = t.CChar(int_part % 10 + 48) + di += 1 + int_part //= 10 + f_total: t.CInt = di + (precision + 1 if precision > 0 else 0) + if not left_align and not pad_zero and width > f_total: + pad_count = width - f_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + if pad_zero and width > f_total: + pad_count = width - f_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += 1 + pad_count -= 1 + while di > 0 and write_count < size - 1: + di -= 1 + ptr[0] = temp[di] + write_count += 1 + ptr += 1 + if precision > 0: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += 1 + fi: t.CInt = 0 + while fi < precision and fi < TEMP_BUF_SIZE - 1: + temp[fi] = t.CChar(frac_part % 10 + 48) + fi += 1 + frac_part //= 10 + while fi > 0 and write_count < size - 1: + fi -= 1 + ptr[0] = temp[fi] + write_count += 1 + ptr += 1 + if left_align and width > f_total: + pad_count = width - f_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += 1 + pad_count -= 1 + elif c.Deref(fmt) == 37: + if write_count < size - 1: + ptr[0] = 37 + write_count += 1 + ptr += 1 + else: + if write_count < size - 1: + ptr[0] = c.Deref(fmt) + write_count += 1 + ptr += 1 + fmt += 1 + ptr[0] = 0 + return write_count diff --git a/includes/vipermath.py b/includes/vipermath.py new file mode 100644 index 0000000..bf38b32 --- /dev/null +++ b/includes/vipermath.py @@ -0,0 +1,542 @@ +import t, c + + +U_M_PI: t.CDefine = 3.14159265358979323846 +U_M_E: t.CDefine = 2.71828182845904523536 +U_M_PI_2: t.CDefine = 1.57079632679489661923 +U_M_PI_4: t.CDefine = 0.78539816339744830962 +U_M_1_PI: t.CDefine = 0.31830988618379067154 +U_M_2_PI: t.CDefine = 0.63661977236758134308 + +U_M_LN2: t.CDefine = 0.69314718055994530942 +U_M_LN10: t.CDefine = 2.30258509299404568402 + +U_M_2_SQRT_PI: t.CDefine = 1.77245385090551602730 + +def radians(degrees: t.CDouble) -> t.CDouble: + return degrees * (U_M_PI / t.CDouble(180.0)) + +def degrees(radians: t.CDouble) -> t.CDouble: + return radians * (t.CDouble(180.0) / U_M_PI) + +def sin(x: t.CDouble) -> t.CDouble: + while x > U_M_PI: + x -= t.CDouble(2.0) * U_M_PI + while x < -U_M_PI: + x += t.CDouble(2.0) * U_M_PI + x2: t.CDouble = x * x + result: t.CDouble = x + term: t.CDouble = x + term = term * x2 / t.CDouble(6.0) + result = result - term + term = term * x2 / t.CDouble(20.0) + result = result + term + term = term * x2 / t.CDouble(42.0) + result = result - term + term = term * x2 / t.CDouble(72.0) + result = result + term + term = term * x2 / t.CDouble(110.0) + result = result - term + term = term * x2 / t.CDouble(156.0) + result = result + term + term = term * x2 / t.CDouble(210.0) + result = result - term + term = term * x2 / t.CDouble(272.0) + result = result + term + return result + + +def cos(x: t.CDouble) -> t.CDouble: + while x > U_M_PI: + x -= t.CDouble(2.0) * U_M_PI + while x < -U_M_PI: + x += t.CDouble(2.0) * U_M_PI + x2: t.CDouble = x * x + result: t.CDouble = t.CDouble(1.0) + term: t.CDouble = t.CDouble(1.0) + term = term * x2 / t.CDouble(2.0) + result = result - term + term = term * x2 / t.CDouble(12.0) + result = result + term + term = term * x2 / t.CDouble(30.0) + result = result - term + term = term * x2 / t.CDouble(56.0) + result = result + term + term = term * x2 / t.CDouble(90.0) + result = result - term + term = term * x2 / t.CDouble(132.0) + result = result + term + term = term * x2 / t.CDouble(182.0) + result = result - term + term = term * x2 / t.CDouble(240.0) + result = result + term + return result + + +def tan(x: t.CDouble) -> t.CDouble: + return sin(x) / cos(x) + + +def asin(x: t.CDouble) -> t.CDouble: + if x > t.CDouble(1.0): + x = t.CDouble(1.0) + if x < t.CDouble(-1.0): + x = t.CDouble(-1.0) + x2: t.CDouble = x * x + result: t.CDouble = x + result += x * x2 / t.CDouble(6.0) + result += t.CDouble(3.0) * x * x2 * x2 / t.CDouble(40.0) + result += t.CDouble(5.0) * x * x2 * x2 * x2 / t.CDouble(112.0) + result += t.CDouble(35.0) * x * x2 * x2 * x2 * x2 / t.CDouble(1152.0) + result += t.CDouble(63.0) * x * x2 * x2 * x2 * x2 * x2 / t.CDouble(2816.0) + return result + + +def acos(x: t.CDouble) -> t.CDouble: + return U_M_PI / t.CDouble(2.0) - asin(x) + + +def _atan_core(x: t.CDouble) -> t.CDouble: + x2: t.CDouble = x * x + result: t.CDouble = x + term: t.CDouble = x + term = term * x2 / t.CDouble(3.0) + result = result - term + term = term * x2 / t.CDouble(5.0) + result = result + term + term = term * x2 / t.CDouble(7.0) + result = result - term + term = term * x2 / t.CDouble(9.0) + result = result + term + term = term * x2 / t.CDouble(11.0) + result = result - term + term = term * x2 / t.CDouble(13.0) + result = result + term + term = term * x2 / t.CDouble(15.0) + result = result - term + term = term * x2 / t.CDouble(17.0) + result = result + term + term = term * x2 / t.CDouble(19.0) + result = result - term + term = term * x2 / t.CDouble(21.0) + result = result + term + return result + + +def atan(x: t.CDouble) -> t.CDouble: + ax: t.CDouble = x + if ax < t.CDouble(0.0): + ax = -ax + if ax > t.CDouble(1.0): + return t.CDouble(0.0) - _atan_core(t.CDouble(1.0) / ax) + U_M_PI_2 if x > t.CDouble(0.0) else _atan_core(t.CDouble(1.0) / ax) - U_M_PI_2 + return _atan_core(x) if x >= t.CDouble(0.0) else t.CDouble(0.0) - _atan_core(ax) + + +def atan2(y: t.CDouble, x: t.CDouble) -> t.CDouble: + if x > t.CDouble(0.0): + return atan(y / x) + elif x < t.CDouble(0.0): + if y >= t.CDouble(0.0): + return atan(y / x) + U_M_PI + else: + return atan(y / x) - U_M_PI + else: + if y > t.CDouble(0.0): + return U_M_PI_2 + elif y < t.CDouble(0.0): + return t.CDouble(0.0) - U_M_PI_2 + else: + return t.CDouble(0.0) + + +def sinh(x: t.CDouble) -> t.CDouble: + ex: t.CDouble = exp(x) + e_negx: t.CDouble = exp(-x) + return (ex - e_negx) / t.CDouble(2.0) + + +def cosh(x: t.CDouble) -> t.CDouble: + ex: t.CDouble = exp(x) + e_negx: t.CDouble = exp(-x) + return (ex + e_negx) / t.CDouble(2.0) + + +def tanh(x: t.CDouble) -> t.CDouble: + ex: t.CDouble = exp(x) + e_negx: t.CDouble = exp(-x) + return (ex - e_negx) / (ex + e_negx) + + +def exp(x: t.CDouble) -> t.CDouble: + if x > t.CDouble(709.0): + return t.CDouble(1.7976931348623157e308) + if x < t.CDouble(-709.0): + return t.CDouble(0.0) + result: t.CDouble = t.CDouble(1.0) + term: t.CDouble = t.CDouble(1.0) + term = term * x / t.CDouble(1.0) + result = result + term + term = term * x / t.CDouble(2.0) + result = result + term + term = term * x / t.CDouble(3.0) + result = result + term + term = term * x / t.CDouble(4.0) + result = result + term + term = term * x / t.CDouble(5.0) + result = result + term + term = term * x / t.CDouble(6.0) + result = result + term + term = term * x / t.CDouble(7.0) + result = result + term + term = term * x / t.CDouble(8.0) + result = result + term + term = term * x / t.CDouble(9.0) + result = result + term + term = term * x / t.CDouble(10.0) + result = result + term + term = term * x / t.CDouble(11.0) + result = result + term + term = term * x / t.CDouble(12.0) + result = result + term + term = term * x / t.CDouble(13.0) + result = result + term + term = term * x / t.CDouble(14.0) + result = result + term + term = term * x / t.CDouble(15.0) + result = result + term + term = term * x / t.CDouble(16.0) + result = result + term + term = term * x / t.CDouble(17.0) + result = result + term + term = term * x / t.CDouble(18.0) + result = result + term + return result + + +def log(x: t.CDouble) -> t.CDouble: + if x <= t.CDouble(0.0): + return t.CDouble(-1e308) + exponent: t.CInt = 0 + while x >= t.CDouble(2.0): + x /= t.CDouble(2.0) + exponent += 1 + while x < t.CDouble(1.0): + x *= t.CDouble(2.0) + exponent -= 1 + y: t.CDouble = (x - t.CDouble(1.0)) / (x + t.CDouble(1.0)) + y2: t.CDouble = y * y + result: t.CDouble = t.CDouble(2.0) * y + term: t.CDouble = t.CDouble(2.0) * y + term = term * y2 + result = result + term / t.CDouble(3.0) + term = term * y2 + result = result + term / t.CDouble(5.0) + term = term * y2 + result = result + term / t.CDouble(7.0) + term = term * y2 + result = result + term / t.CDouble(9.0) + term = term * y2 + result = result + term / t.CDouble(11.0) + term = term * y2 + result = result + term / t.CDouble(13.0) + term = term * y2 + result = result + term / t.CDouble(15.0) + term = term * y2 + result = result + term / t.CDouble(17.0) + term = term * y2 + result = result + term / t.CDouble(19.0) + term = term * y2 + result = result + term / t.CDouble(21.0) + result += t.CDouble(exponent) * U_M_LN2 + return result + + +def sqrt(x: t.CDouble) -> t.CDouble: + if x < t.CDouble(0.0): + return t.CDouble(0.0) + if x == t.CDouble(0.0): + return t.CDouble(0.0) + guess: t.CDouble = x / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + guess = (guess + x / guess) / t.CDouble(2.0) + return guess + + +def abs(x: t.CInt) -> t.CInt: + return x if x >= 0 else -x + +def fabs(x: t.CDouble) -> t.CDouble: + return x if x >= t.CDouble(0.0) else -x + +def labs(x: t.CLong) -> t.CLong: + return x if x >= 0 else -x + +def factorial(n: t.CInt) -> t.CDouble: + if n < 0: return t.CDouble(0.0) + if n == 0 or n == 1: return t.CDouble(1.0) + result: t.CDouble = t.CDouble(1.0) + for i in range(2, n + 1): + result *= i + return result + + +def combination(n: t.CInt, k: t.CInt) -> t.CDouble: + if k < 0 or k > n: return t.CDouble(0.0) + if k == 0 or k == n: return t.CDouble(1.0) + k = k if k < n - k else n - k + result: t.CDouble = t.CDouble(1.0) + for i in range(1, k + 1): + result = result * (n - k + i) / i + return result + + +def permutation(n: t.CInt, k: t.CInt) -> t.CDouble: + if k < 0 or k > n: return t.CDouble(0.0) + result: t.CDouble = t.CDouble(1.0) + for i in range(0, k): + result *= (n - i) + return result + +def pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: + if x == t.CDouble(0.0): + if y > t.CDouble(0.0): + return t.CDouble(0.0) + return t.CDouble(1.0) + if x < t.CDouble(0.0): + iy: t.CDouble = y * log(-x) + return exp(iy) + return exp(y * log(x)) + + +def powf(x: t.CDouble, y: t.CDouble) -> t.CDouble: + return pow(x, y) + + +def cbrt(x: t.CDouble) -> t.CDouble: + return pow(x, t.CDouble(1.0) / t.CDouble(3.0)) + +def hypot(x: t.CDouble, y: t.CDouble) -> t.CDouble: + return sqrt(x * x + y * y) + + +def floor(x: t.CDouble) -> t.CDouble: + if x >= t.CDouble(0.0): + return t.CDouble(t.CInt(x)) + i: t.CInt = t.CInt(x) + if x < t.CDouble(i): + return t.CDouble(i - 1) + else: + return t.CDouble(i) + + +def ceil(x: t.CDouble) -> t.CDouble: + if x < t.CDouble(0.0): + return t.CDouble(t.CInt(x)) + i: t.CInt = t.CInt(x) + if x > t.CDouble(i): + return t.CDouble(i + 1) + else: + return t.CDouble(i) + + +def round(x: t.CDouble) -> t.CDouble: + return floor(x + t.CDouble(0.5)) + +def trunc(x: t.CDouble) -> t.CDouble: + if x >= t.CDouble(0.0): + return floor(x) + else: + return ceil(x) + + +def fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble: + if y == t.CDouble(0.0): + return t.CDouble(0.0) + result: t.CDouble = x - y * floor(x / y) + if result < t.CDouble(0.0): + result += y + return result + + +def fmodf(x: float, y: float) -> float: + if y == float(0.0): + return float(0.0) + result: float = x - y * floorf(x / y) + if result < float(0.0): + result += y + return result + + +def modf(x: t.CDouble, iptr: t.CDouble | t.CPtr) -> t.CDouble: + int_part: t.CDouble = floor(x) + c.Set(c.Deref(iptr), int_part) + return x - int_part + + +def log10(x: t.CDouble) -> t.CDouble: + return log(x) / U_M_LN10 + + +def log2(x: t.CDouble) -> t.CDouble: + return log(x) / U_M_LN2 + + +def exp2(x: t.CDouble) -> t.CDouble: + return pow(t.CDouble(2.0), x) + + +def expm1(x: t.CDouble) -> t.CDouble: + return exp(x) - t.CDouble(1.0) + + +def log1p(x: t.CDouble) -> t.CDouble: + return log(t.CDouble(1.0) + x) + + +def asinh(x: t.CDouble) -> t.CDouble: + return log(x + sqrt(x * x + t.CDouble(1.0))) + +def acosh(x: t.CDouble) -> t.CDouble: + return log(x + sqrt(x * x - t.CDouble(1.0))) + +def atanh(x: t.CDouble) -> t.CDouble: + return (log(t.CDouble(1.0) + x) - log(t.CDouble(1.0) - x)) / t.CDouble(2.0) + + +def gamma(x: t.CDouble) -> t.CDouble: + if x <= t.CDouble(0.0): return t.CDouble(0.0) + if x == t.CDouble(1.0) or x == t.CDouble(2.0): return t.CDouble(1.0) + ln_gamma: t.CDouble = t.CDouble(0.5) * log(t.CDouble(2.0) * U_M_PI / x) + x * log(x / U_M_E) + return exp(ln_gamma) + + +def erf(x: t.CDouble) -> t.CDouble: + sign: t.CDouble = t.CDouble(1.0) if x >= t.CDouble(0.0) else t.CDouble(-1.0) + abs_x: t.CDouble = fabs(x) + t0: t.CDouble = t.CDouble(4.0) * abs_x * abs_x / U_M_PI + exp_term: t.CDouble = exp(-t0) + return sign * sqrt(t.CDouble(1.0) - exp_term) + + +def erfc(x: t.CDouble) -> t.CDouble: + return t.CDouble(1.0) - erf(x) + +def sqrtf(x: t.CFloat) -> t.CFloat: + if x < t.CFloat(0.0): + return t.CFloat(0.0) + if x == t.CFloat(0.0): + return t.CFloat(0.0) + guess: t.CFloat = x / t.CFloat(2.0) + for i in range(10): + guess = (guess + x / guess) / t.CFloat(2.0) + return guess + +def sinf(x: t.CFloat) -> t.CFloat: + while x > t.CFloat(3.14159265): + x -= t.CFloat(6.28318530) + while x < t.CFloat(-3.14159265): + x += t.CFloat(6.28318530) + x2: t.CFloat = x * x + result: t.CFloat = x + term: t.CFloat = x + term = term * x2 / t.CFloat(6.0) + result = result - term + term = term * x2 / t.CFloat(20.0) + result = result + term + term = term * x2 / t.CFloat(42.0) + result = result - term + term = term * x2 / t.CFloat(72.0) + result = result + term + term = term * x2 / t.CFloat(110.0) + result = result - term + term = term * x2 / t.CFloat(156.0) + result = result + term + term = term * x2 / t.CFloat(210.0) + result = result - term + term = term * x2 / t.CFloat(272.0) + result = result + term + return result + +def cosf(x: t.CFloat) -> t.CFloat: + while x > t.CFloat(3.14159265): + x -= t.CFloat(6.28318530) + while x < t.CFloat(-3.14159265): + x += t.CFloat(6.28318530) + x2: t.CFloat = x * x + result: t.CFloat = t.CFloat(1.0) + term: t.CFloat = t.CFloat(1.0) + term = term * x2 / t.CFloat(2.0) + result = result - term + term = term * x2 / t.CFloat(12.0) + result = result + term + term = term * x2 / t.CFloat(30.0) + result = result - term + term = term * x2 / t.CFloat(56.0) + result = result + term + term = term * x2 / t.CFloat(90.0) + result = result - term + term = term * x2 / t.CFloat(132.0) + result = result + term + term = term * x2 / t.CFloat(182.0) + result = result - term + term = term * x2 / t.CFloat(240.0) + result = result + term + return result + +def tanf(x: t.CFloat) -> t.CFloat: + c: t.CFloat = cosf(x) + if c == t.CFloat(0.0): + return t.CFloat(0.0) + return sinf(x) / c + +def fabsf(x: t.CFloat) -> t.CFloat: + return x if x >= t.CFloat(0.0) else -x + +def floorf(x: t.CFloat) -> t.CFloat: + if x >= t.CFloat(0.0): + return t.CFloat(t.CInt(x)) + i: t.CInt = t.CInt(x) + if x < t.CFloat(i): + return t.CFloat(i - 1) + else: + return t.CFloat(i) + +def ceilf(x: t.CFloat) -> t.CFloat: + if x < t.CFloat(0.0): + return t.CFloat(t.CInt(x)) + i: t.CInt = t.CInt(x) + if x > t.CFloat(i): + return t.CFloat(i + 1) + else: + return t.CFloat(i) + + +class _U(t.CUnion): + d: t.CDouble + u: t.CUInt64T + +def isnan(x: t.CDouble) -> t.CStatic | t.CInt: + u: t.CUInt64T = t.CUInt64T(x) + exp_part: t.CUInt64T = (u >> 52) & 0x7FF + mantissa_part: t.CUInt64T = u & 0xFFFFFFFFFFFFF + if exp_part == 0x7FF: + if mantissa_part != 0: + return 1 + return 0 + +def isinf(x: t.CDouble) -> t.CStatic | t.CInt: + u: t.CUInt64T = t.CUInt64T(x) + exp_part: t.CUInt64T = (u >> 52) & 0x7FF + mantissa_part: t.CUInt64T = u & 0xFFFFFFFFFFFFF + if exp_part == 0x7FF: + if mantissa_part == 0: + return 1 + return 0 diff --git a/includes/vipersimd.py b/includes/vipersimd.py new file mode 100644 index 0000000..36cc070 --- /dev/null +++ b/includes/vipersimd.py @@ -0,0 +1,433 @@ +import t, c + + +# ============================================================ +# AVX2 双精度向量运算 (4 x double, 256-bit YMM) +# ============================================================ + +def simd_add4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] + b[0:4]""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vaddpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_sub4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] - b[0:4]""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vsubpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_mul4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] * b[0:4]""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vmulpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_div4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] / b[0:4]""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vdivpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_sqrt4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = sqrt(a[0:4])""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vsqrtpd ymm0, ymm0 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0']) + + +def simd_neg4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = -a[0:4] (flip sign bit via XOR)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vpcmpeqd ymm1, ymm1, ymm1 +vpsllq ymm1, ymm1, 63 +vxorpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_abs4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = |a[0:4]| (clear sign bit via ANDN)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vpcmpeqd ymm1, ymm1, ymm1 +vpsllq ymm1, ymm1, 63 +vandnpd ymm0, ymm1, ymm0 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_max4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = max(a[0:4], b[0:4])""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vmaxpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_min4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = min(a[0:4], b[0:4])""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vminpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_mul_scalar4d(a: t.CPtr, scalar: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] * scalar (broadcast)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vbroadcastsd ymm1, [{c.AsmInp(scalar, t.ASM_DESCR.REG_ANY)}] +vmulpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_add_scalar4d(a: t.CPtr, scalar: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4] + scalar (broadcast)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vbroadcastsd ymm1, [{c.AsmInp(scalar, t.ASM_DESCR.REG_ANY)}] +vaddpd ymm0, ymm0, ymm1 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_hsum4d(a: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0] = a[0]+a[1]+a[2]+a[3] (horizontal sum)""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vextractf128 xmm1, ymm0, 1 +vaddpd xmm0, xmm0, xmm1 +vhaddpd xmm0, xmm0, xmm0 +vmovsd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_dot4d(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0] = dot(a[0:4], b[0:4])""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vmulpd ymm0, ymm0, ymm1 +vextractf128 xmm1, ymm0, 1 +vaddpd xmm0, xmm0, xmm1 +vhaddpd xmm0, xmm0, xmm0 +vmovsd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1']) + + +def simd_fma4d(a: t.CPtr, b: t.CPtr, c_val: t.CPtr, out: t.CPtr) -> t.CVoid: + """AVX2: out[0:4] = a[0:4]*b[0:4] + c[0:4] (fused multiply-add) + Uses vfmadd213pd: ymm0 = ymm1 * ymm0 + ymm2 + Load order: b->ymm0, a->ymm1, c->ymm2""" + c.Asm(f"""vmovupd ymm0, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm1, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +vmovupd ymm2, [{c.AsmInp(c_val, t.ASM_DESCR.REG_ANY)}] +vfmadd213pd ymm0, ymm1, ymm2 +vmovupd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], ymm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'ymm2']) + + +# ============================================================ +# SSE2 单精度向量运算 (4 x float, 128-bit XMM) +# ============================================================ + +def simd_add4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """SSE2: out[0:4] = a[0:4] + b[0:4] (float)""" + c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +addps xmm0, xmm1 +movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1']) + + +def simd_sub4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """SSE2: out[0:4] = a[0:4] - b[0:4] (float)""" + c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +subps xmm0, xmm1 +movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1']) + + +def simd_mul4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """SSE2: out[0:4] = a[0:4] * b[0:4] (float)""" + c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +mulps xmm0, xmm1 +movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1']) + + +def simd_div4f(a: t.CPtr, b: t.CPtr, out: t.CPtr) -> t.CVoid: + """SSE2: out[0:4] = a[0:4] / b[0:4] (float)""" + c.Asm(f"""movups xmm0, [{c.AsmInp(a, t.ASM_DESCR.REG_ANY)}] +movups xmm1, [{c.AsmInp(b, t.ASM_DESCR.REG_ANY)}] +divps xmm0, xmm1 +movups [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm0""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'xmm0', 'xmm1']) + + +# ============================================================ +# 批量数组运算 (AVX2 循环, 处理 N 个 double) +# ============================================================ + +def simd_add_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = a[i:i+4] + b[i:i+4], i=0,4,8,...""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Ladd_end +.Ladd_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vaddpd ymm0, ymm0, ymm1 +vmovupd [r10], ymm0 +add r8, 32 +add r9, 32 +add r10, 32 +dec rcx +jnz .Ladd_loop +.Ladd_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10']) + + +def simd_sub_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = a[i:i+4] - b[i:i+4]""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Lsub_end +.Lsub_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vsubpd ymm0, ymm0, ymm1 +vmovupd [r10], ymm0 +add r8, 32 +add r9, 32 +add r10, 32 +dec rcx +jnz .Lsub_loop +.Lsub_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10']) + + +def simd_mul_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = a[i:i+4] * b[i:i+4]""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Lmul_end +.Lmul_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vmulpd ymm0, ymm0, ymm1 +vmovupd [r10], ymm0 +add r8, 32 +add r9, 32 +add r10, 32 +dec rcx +jnz .Lmul_loop +.Lmul_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10']) + + +def simd_div_array(a: t.CPtr, b: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = a[i:i+4] / b[i:i+4]""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Ldiv_end +.Ldiv_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vdivpd ymm0, ymm0, ymm1 +vmovupd [r10], ymm0 +add r8, 32 +add r9, 32 +add r10, 32 +dec rcx +jnz .Ldiv_loop +.Ldiv_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'rcx', 'r8', 'r9', 'r10']) + + +def simd_sqrt_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = sqrt(a[i:i+4])""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +test rcx, rcx +jz .Lsqrt_end +.Lsqrt_loop: +vmovupd ymm0, [r8] +vsqrtpd ymm0, ymm0 +vmovupd [r10], ymm0 +add r8, 32 +add r10, 32 +dec rcx +jnz .Lsqrt_loop +.Lsqrt_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'rcx', 'r8', 'r10']) + + +def simd_abs_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = |a[i:i+4]|""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r10, {c.AsmInp(out, t.ASM_DESCR.REG_ANY)} +vpcmpeqd ymm2, ymm2, ymm2 +vpsllq ymm2, ymm2, 63 +test rcx, rcx +jz .Labs_end +.Labs_loop: +vmovupd ymm0, [r8] +vandnpd ymm0, ymm2, ymm0 +vmovupd [r10], ymm0 +add r8, 32 +add r10, 32 +dec rcx +jnz .Labs_loop +.Labs_end: +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm2', 'rcx', 'r8', 'r10']) + + +def simd_dot_array(a: t.CPtr, b: t.CPtr, n: t.CSizeT, out: t.CPtr) -> t.CVoid: + """AVX2 batch: out[0] = dot(a[0:n], b[0:n]) using FMA accumulation""" + c.Asm(f"""mov rcx, {c.AsmInp(n, t.ASM_DESCR.REG_ANY)} +shr rcx, 2 +mov r8, {c.AsmInp(a, t.ASM_DESCR.REG_ANY)} +mov r9, {c.AsmInp(b, t.ASM_DESCR.REG_ANY)} +vxorpd ymm2, ymm2, ymm2 +test rcx, rcx +jz .Ldot_end +.Ldot_loop: +vmovupd ymm0, [r8] +vmovupd ymm1, [r9] +vfmadd231pd ymm2, ymm0, ymm1 +add r8, 32 +add r9, 32 +dec rcx +jnz .Ldot_loop +.Ldot_end: +vextractf128 xmm1, ymm2, 1 +vaddpd xmm2, xmm2, xmm1 +vhaddpd xmm2, xmm2, xmm2 +vmovsd [{c.AsmInp(out, t.ASM_DESCR.REG_ANY)}], xmm2 +vzeroupper""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, 'ymm0', 'ymm1', 'ymm2', 'rcx', 'r8', 'r9']) + + +# ============================================================ +# LLVMIR 精确标量运算 (LLVM 内置函数) +# ============================================================ + +def simd_sqrt(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: sqrt(x)""" + return c.LLVMIR(f"call double @llvm.sqrt.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_fabs(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: |x|""" + return c.LLVMIR(f"call double @llvm.fabs.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_floor(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: floor(x)""" + return c.LLVMIR(f"call double @llvm.floor.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_ceil(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: ceil(x)""" + return c.LLVMIR(f"call double @llvm.ceil.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_round(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: round(x)""" + return c.LLVMIR(f"call double @llvm.round.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_trunc(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: trunc(x)""" + return c.LLVMIR(f"call double @llvm.trunc.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_fma(a: t.CDouble, b: t.CDouble, c_val: t.CDouble) -> t.CDouble: + """LLVM intrinsic: a*b + c (single rounding)""" + return c.LLVMIR(f"call double @llvm.fma.f64(double {c.LInp(a)}, double {c.LInp(b)}, double {c.LInp(c_val)})", t.CDouble) + + +def simd_copysign(mag: t.CDouble, sign: t.CDouble) -> t.CDouble: + """LLVM intrinsic: copysign(mag, sign)""" + return c.LLVMIR(f"call double @llvm.copysign.f64(double {c.LInp(mag)}, double {c.LInp(sign)})", t.CDouble) + + +def simd_neg(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: -x (via copysign)""" + return c.LLVMIR(f"call double @llvm.copysign.f64(double {c.LInp(x)}, double {c.LInp(t.CDouble(-1.0))})", t.CDouble) + + +def simd_minnum(a: t.CDouble, b: t.CDouble) -> t.CDouble: + """LLVM intrinsic: min(a, b) (NaN-aware)""" + return c.LLVMIR(f"call double @llvm.minnum.f64(double {c.LInp(a)}, double {c.LInp(b)})", t.CDouble) + + +def simd_maxnum(a: t.CDouble, b: t.CDouble) -> t.CDouble: + """LLVM intrinsic: max(a, b) (NaN-aware)""" + return c.LLVMIR(f"call double @llvm.maxnum.f64(double {c.LInp(a)}, double {c.LInp(b)})", t.CDouble) + + +def simd_exp(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: e^x""" + return c.LLVMIR(f"call double @llvm.exp.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_log(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: ln(x)""" + return c.LLVMIR(f"call double @llvm.log.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_sin(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: sin(x)""" + return c.LLVMIR(f"call double @llvm.sin.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_cos(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: cos(x)""" + return c.LLVMIR(f"call double @llvm.cos.f64(double {c.LInp(x)})", t.CDouble) + + +def simd_pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: + """LLVM intrinsic: x^y""" + return c.LLVMIR(f"call double @llvm.pow.f64(double {c.LInp(x)}, double {c.LInp(y)})", t.CDouble) diff --git a/includes/viperstring.py b/includes/viperstring.py new file mode 100644 index 0000000..212d749 --- /dev/null +++ b/includes/viperstring.py @@ -0,0 +1 @@ +from .string import * diff --git a/includes/w32/fileio.py b/includes/w32/fileio.py new file mode 100644 index 0000000..d5cf34a --- /dev/null +++ b/includes/w32/fileio.py @@ -0,0 +1,386 @@ +import t, c +from stdint import * +import w32.win32base +import w32.win32file + + +class MODE(t.CEnum): + R = 0 + W = 1 + A = 2 + RP = 3 + WP = 4 + AP = 5 + X = 6 + XP = 7 + + +class FRESULT(t.CEnum): + OK = 0 + ERR = -1 + ERR_CLOSED = -2 + ERR_PERM = -3 + ERR_IO = -4 + ERR_NOTFOUND = -5 + + +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 + +INVALID_SET_FILE_POINTER: t.CDefine = -1 + +SHARE_READ: t.CDefine = 0x00000001 +SHARE_WRITE: t.CDefine = 0x00000002 +SHARE_DELETE: t.CDefine = 0x00000004 + + +class File: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + + def __init__(self, filename: str, mode: ULONG, share: ULONG = SHARE_READ): + self.closed = True + self.can_read = False + self.can_write = False + self.is_append = False + self._share_mode = share + + access: ULONG = 0 + disposition: ULONG = w32.win32file.OPEN_EXISTING + + if mode == MODE.R: + access = w32.win32file.GENERIC_READ + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + elif mode == MODE.W: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_ALWAYS + self.can_write = True + elif mode == MODE.A: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_ALWAYS + self.can_write = True + self.is_append = True + elif mode == MODE.RP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + self.can_write = True + elif mode == MODE.WP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_ALWAYS + self.can_read = True + self.can_write = True + elif mode == MODE.AP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_ALWAYS + self.can_read = True + self.can_write = True + self.is_append = True + elif mode == MODE.X: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_NEW + self.can_write = True + elif mode == MODE.XP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_NEW + self.can_read = True + self.can_write = True + else: + access = w32.win32file.GENERIC_READ + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + + self.handle = w32.win32file.CreateFileA( + filename, access, self._share_mode, + t.CPtr(0), disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, t.CPtr(0) + ) + + if self.handle == w32.win32base.INVALID_HANDLE_VALUE: + self.closed = True + return + + self.closed = False + + if self.is_append: + self.seek(0, SEEK_END) + + def __enter__(self) -> 'File' | t.CPtr: + return self + + def __exit__(self): + self.close() + + def read(self, buf: bytes, count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + bytes_read: ULONG = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_read)), t.CPtr(0)) + if result == 0: return FRESULT.ERR_IO + return LONG(bytes_read) + + def write(self, buf: bytes, count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_write: return FRESULT.ERR_PERM + bytes_written: ULONG = 0 + result: BOOL = w32.win32file.WriteFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_written)), t.CPtr(0)) + if result == 0: return FRESULT.ERR_IO + return LONG(bytes_written) + + def write_str(self, s: str) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_write: return FRESULT.ERR_PERM + length: ULONG = 0 + p: bytes = s + while c.Deref(p) != 0: + length += 1 + p += 1 + return self.write(s, length) + + def seek(self, offset: LONG, origin: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + result: LONG = w32.win32file.SetFilePointer(self.handle, offset, t.CPtr(0), origin) + if result == -1: return FRESULT.ERR_IO + return result + + def tell(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + return self.seek(0, SEEK_CUR) + + def close(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + w32.win32base.CloseHandle(self.handle) + self.closed = True + return FRESULT.OK + + def flush(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + w32.win32file.FlushFileBuffers(self.handle) + return FRESULT.OK + + def size(self) -> LONGLONG: + if self.closed: return -1 + li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER() + result: BOOL = w32.win32file.GetFileSizeEx(self.handle, t.CPtr(c.Addr(li))) + if result == 0: return -1 + return li.QuadPart + + def readline(self, buf: bytes, max_count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + if max_count < 2: return FRESULT.ERR + total: ULONG = 0 + bytes_read: ULONG = 0 + ch: t.CInt = 0 + while total < max_count - 1: + bytes_read = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf + total, 1, t.CPtr(c.Addr(bytes_read)), t.CPtr(0)) + if result == 0 or bytes_read == 0: break + ch = c.Deref(buf + total) + total += 1 + if ch == 10: break + if total < max_count: + buf[total] = 0 + return LONG(total) + + def read_all(self, buf: bytes, max_count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + if max_count < 2: return FRESULT.ERR + file_size: LONGLONG = self.size() + to_read: ULONG = 0 + if file_size < max_count - 1: + to_read = ULONG(file_size) + else: + to_read = max_count - 1 + self.seek(0, SEEK_SET) + bytes_read: ULONG = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), t.CPtr(0)) + if result == 0: return FRESULT.ERR_IO + if bytes_read < max_count: + buf[bytes_read] = 0 + return LONG(bytes_read) + + +class FileW: + handle: HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + + def __init__(self, filename: LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ): + self.closed = True + self.can_read = False + self.can_write = False + self.is_append = False + self._share_mode = share + + access: ULONG = 0 + disposition: ULONG = w32.win32file.OPEN_EXISTING + + if mode == MODE.R: + access = w32.win32file.GENERIC_READ + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + elif mode == MODE.W: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_ALWAYS + self.can_write = True + elif mode == MODE.A: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_ALWAYS + self.can_write = True + self.is_append = True + elif mode == MODE.RP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + self.can_write = True + elif mode == MODE.WP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_ALWAYS + self.can_read = True + self.can_write = True + elif mode == MODE.AP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.OPEN_ALWAYS + self.can_read = True + self.can_write = True + self.is_append = True + elif mode == MODE.X: + access = w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_NEW + self.can_write = True + elif mode == MODE.XP: + access = w32.win32file.GENERIC_READ | w32.win32file.GENERIC_WRITE + disposition = w32.win32file.CREATE_NEW + self.can_read = True + self.can_write = True + else: + access = w32.win32file.GENERIC_READ + disposition = w32.win32file.OPEN_EXISTING + self.can_read = True + + self.handle = w32.win32file.CreateFileW( + filename, access, self._share_mode, + t.CPtr(0), disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, t.CPtr(0) + ) + + if self.handle == w32.win32base.INVALID_HANDLE_VALUE: + self.closed = True + return + + self.closed = False + + if self.is_append: + self.seek(0, SEEK_END) + + def __enter__(self) -> 'FileW' | t.CPtr: + return self + + def __exit__(self): + self.close() + + def read(self, buf: bytes, count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + bytes_read: ULONG = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_read)), t.CPtr(0)) + if result == 0: return FRESULT.ERR_IO + return LONG(bytes_read) + + def write(self, buf: bytes, count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_write: return FRESULT.ERR_PERM + bytes_written: ULONG = 0 + result: BOOL = w32.win32file.WriteFile(self.handle, buf, count, t.CPtr(c.Addr(bytes_written)), t.CPtr(0)) + if result == 0: return FRESULT.ERR_IO + return LONG(bytes_written) + + def write_str(self, s: str) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_write: return FRESULT.ERR_PERM + length: ULONG = 0 + p: bytes = s + while c.Deref(p) != 0: + length += 1 + p += 1 + return self.write(s, length) + + def seek(self, offset: LONG, origin: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + result: LONG = w32.win32file.SetFilePointer(self.handle, offset, t.CPtr(0), origin) + if result == -1: return FRESULT.ERR_IO + return result + + def tell(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + return self.seek(0, SEEK_CUR) + + def close(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + w32.win32base.CloseHandle(self.handle) + self.closed = True + return FRESULT.OK + + def flush(self) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + w32.win32file.FlushFileBuffers(self.handle) + return FRESULT.OK + + def size(self) -> LONGLONG: + if self.closed: return -1 + li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER() + result: BOOL = w32.win32file.GetFileSizeEx(self.handle, t.CPtr(c.Addr(li))) + if result == 0: return -1 + return li.QuadPart + + def readline(self, buf: bytes, max_count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + if max_count < 2: return FRESULT.ERR + total: ULONG = 0 + bytes_read: ULONG = 0 + ch: t.CInt = 0 + while total < max_count - 1: + bytes_read = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf + total, 1, t.CPtr(c.Addr(bytes_read)), t.CPtr(0)) + if result == 0 or bytes_read == 0: break + ch = c.Deref(buf + total) + total += 1 + if ch == 10: break + if total < max_count: + buf[total] = 0 + return LONG(total) + + def read_all(self, buf: bytes, max_count: ULONG) -> LONG: + if self.closed: return FRESULT.ERR_CLOSED + if not self.can_read: return FRESULT.ERR_PERM + if max_count < 2: return FRESULT.ERR + file_size: LONGLONG = self.size() + to_read: ULONG = 0 + if file_size < max_count - 1: + to_read = ULONG(file_size) + else: + to_read = max_count - 1 + self.seek(0, SEEK_SET) + bytes_read: ULONG = 0 + result: BOOL = w32.win32file.ReadFile(self.handle, buf, to_read, t.CPtr(c.Addr(bytes_read)), t.CPtr(0)) + if result == 0: return FRESULT.ERR_IO + if bytes_read < max_count: + buf[bytes_read] = 0 + return LONG(bytes_read) + + +def open(filename: str, mode: ULONG, share: ULONG = SHARE_READ) -> File | t.CPtr: + return File(filename, mode, share) + +def openw(filename: LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr: + return FileW(filename, mode, share) diff --git a/includes/w32/win32base.py b/includes/w32/win32base.py new file mode 100644 index 0000000..a6ebe10 --- /dev/null +++ b/includes/w32/win32base.py @@ -0,0 +1,79 @@ +import t +from stdint import * + +HANDLE: t.CTypedef = VOIDPTR +LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr +LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr + +INVALID_HANDLE_VALUE: t.CDefine = t.CVoid(-1) +NULL: t.CDefine = 0 +TRUE: t.CDefine = 1 +FALSE: t.CDefine = 0 +INFINITE: t.CDefine = 0xFFFFFFFF +WAIT_FAILED: t.CDefine = 0xFFFFFFFF +WAIT_OBJECT_0: t.CDefine = 0 +WAIT_TIMEOUT: t.CDefine = 258 +WAIT_ABANDONED: t.CDefine = 0x80 +MAX_PATH: t.CDefine = 260 +ERROR_SUCCESS: t.CDefine = 0 +ERROR_FILE_NOT_FOUND: t.CDefine = 2 +ERROR_ACCESS_DENIED: t.CDefine = 5 +ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122 + +class SECURITY_ATTRIBUTES(): + nLength: ULONG + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL + +class OVERLAPPED(): + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: ULONG + OffsetHigh: ULONG + hEvent: HANDLE + +class FILETIME(): + dwLowDateTime: DWORD + dwHighDateTime: DWORD + +class SYSTEMTIME(): + wYear: WORD + wMonth: WORD + wDayOfWeek: WORD + wDay: WORD + wHour: WORD + wMinute: WORD + wSecond: WORD + wMilliseconds: WORD + +class GUID(): + Data1: DWORD + Data2: WORD + Data3: WORD + Data4: BYTEPTR + +class LARGE_INTEGER(): + QuadPart: LONGLONG + +class ULARGE_INTEGER(): + QuadPart: ULONGLONG + +def GetLastError() -> ULONG | t.State: pass +def SetLastError(dwErrCode: ULONG) -> t.State: pass +def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass +def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass +def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass +def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass +def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass +def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass +def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass +def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass +def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass +def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass +def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass +def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass +def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass +def Sleep(dwMilliseconds: ULONG) -> t.State: pass +def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass +def GetTickCount() -> ULONG | t.State: pass +def GetTickCount64() -> ULONGLONG | t.State: pass diff --git a/includes/w32/win32console.py b/includes/w32/win32console.py new file mode 100644 index 0000000..a90c0c0 --- /dev/null +++ b/includes/w32/win32console.py @@ -0,0 +1,111 @@ +import t +from stdint import * +from w32.win32base import * + +ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001 +ENABLE_LINE_INPUT: t.CDefine = 0x0002 +ENABLE_ECHO_INPUT: t.CDefine = 0x0004 +ENABLE_WINDOW_INPUT: t.CDefine = 0x0008 +ENABLE_MOUSE_INPUT: t.CDefine = 0x0010 +ENABLE_INSERT_MODE: t.CDefine = 0x0020 +ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040 +ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080 + +ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001 +ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002 +ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004 +DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008 +ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010 + +FOREGROUND_BLUE: t.CDefine = 0x0001 +FOREGROUND_GREEN: t.CDefine = 0x0002 +FOREGROUND_RED: t.CDefine = 0x0004 +FOREGROUND_INTENSITY: t.CDefine = 0x0008 +BACKGROUND_BLUE: t.CDefine = 0x0010 +BACKGROUND_GREEN: t.CDefine = 0x0020 +BACKGROUND_RED: t.CDefine = 0x0040 +BACKGROUND_INTENSITY: t.CDefine = 0x0080 + +KEY_EVENT: t.CDefine = 0x0001 +MOUSE_EVENT: t.CDefine = 0x0002 +WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004 +MENU_EVENT: t.CDefine = 0x0008 +FOCUS_EVENT: t.CDefine = 0x0010 + +class COORD(): + X: SHORT + Y: SHORT + +class SMALL_RECT(): + Left: SHORT + Top: SHORT + Right: SHORT + Bottom: SHORT + +class CONSOLE_SCREEN_BUFFER_INFO(): + dwSize: COORD + dwCursorPosition: COORD + wAttributes: WORD + srWindow: SMALL_RECT + dwMaximumWindowSize: COORD + +class CONSOLE_CURSOR_INFO(): + dwSize: ULONG + bVisible: BOOL + +class CHAR_INFO(): + UnicodeChar: WCHAR + Attributes: WORD + +class KEY_EVENT_RECORD(): + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: ULONG + +class MOUSE_EVENT_RECORD(): + dwMousePosition: COORD + dwButtonState: ULONG + dwControlKeyState: ULONG + dwEventFlags: ULONG + +class WINDOW_BUFFER_SIZE_RECORD(): + dwSize: COORD + +class INPUT_RECORD(): + EventType: WORD + Event: KEY_EVENT_RECORD + +def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass +def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass +def GetConsoleCP() -> UINT | t.State: pass +def GetConsoleOutputCP() -> UINT | t.State: pass +def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass +def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass +def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass +def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass +def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass +def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass +def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass +def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass +def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass +def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass +def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass +def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass +def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass +def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass +def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass +def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass +def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass +def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass +def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass +def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass +def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass +def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass +def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass +def AllocConsole() -> BOOL | t.State: pass +def FreeConsole() -> BOOL | t.State: pass +def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass +def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass diff --git a/includes/w32/win32file.py b/includes/w32/win32file.py new file mode 100644 index 0000000..3fb4b7e --- /dev/null +++ b/includes/w32/win32file.py @@ -0,0 +1,134 @@ +import t +from stdint import * +from w32.win32base import * + +GENERIC_READ: t.CDefine = 0x80000000 +GENERIC_WRITE: t.CDefine = 0x40000000 +GENERIC_EXECUTE: t.CDefine = 0x20000000 +GENERIC_ALL: t.CDefine = 0x10000000 + +FILE_SHARE_READ: t.CDefine = 0x00000001 +FILE_SHARE_WRITE: t.CDefine = 0x00000002 +FILE_SHARE_DELETE: t.CDefine = 0x00000004 + +CREATE_NEW: t.CDefine = 1 +CREATE_ALWAYS: t.CDefine = 2 +OPEN_EXISTING: t.CDefine = 3 +OPEN_ALWAYS: t.CDefine = 4 +TRUNCATE_EXISTING: t.CDefine = 5 + +FILE_ATTRIBUTE_READONLY: t.CDefine = 0x00000001 +FILE_ATTRIBUTE_HIDDEN: t.CDefine = 0x00000002 +FILE_ATTRIBUTE_SYSTEM: t.CDefine = 0x00000004 +FILE_ATTRIBUTE_DIRECTORY: t.CDefine = 0x00000010 +FILE_ATTRIBUTE_ARCHIVE: t.CDefine = 0x00000020 +FILE_ATTRIBUTE_NORMAL: t.CDefine = 0x00000080 +FILE_ATTRIBUTE_TEMPORARY: t.CDefine = 0x00000100 +FILE_ATTRIBUTE_COMPRESSED: t.CDefine = 0x00000800 +FILE_ATTRIBUTE_OFFLINE: t.CDefine = 0x00001000 +FILE_ATTRIBUTE_ENCRYPTED: t.CDefine = 0x00004000 + +FILE_FLAG_WRITE_THROUGH: t.CDefine = 0x80000000 +FILE_FLAG_OVERLAPPED: t.CDefine = 0x40000000 +FILE_FLAG_NO_BUFFERING: t.CDefine = 0x20000000 +FILE_FLAG_RANDOM_ACCESS: t.CDefine = 0x10000000 +FILE_FLAG_SEQUENTIAL_SCAN: t.CDefine = 0x08000000 +FILE_FLAG_DELETE_ON_CLOSE: t.CDefine = 0x04000000 +FILE_FLAG_BACKUP_SEMANTICS: t.CDefine = 0x02000000 +FILE_FLAG_POSIX_SEMANTICS: t.CDefine = 0x01000000 + +FILE_BEGIN: t.CDefine = 0 +FILE_CURRENT: t.CDefine = 1 +FILE_END: t.CDefine = 2 + +STD_INPUT_HANDLE: t.CDefine = t.CUnsignedLong(-10) +STD_OUTPUT_HANDLE: t.CDefine = t.CUnsignedLong(-11) +STD_ERROR_HANDLE: t.CDefine = t.CUnsignedLong(-12) + +MOVEFILE_REPLACE_EXISTING: t.CDefine = 0x00000001 +MOVEFILE_COPY_ALLOWED: t.CDefine = 0x00000002 +MOVEFILE_WRITE_THROUGH: t.CDefine = 0x00000008 + +class BY_HANDLE_FILE_INFORMATION(): + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: ULONG + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + nNumberOfLinks: ULONG + nFileIndexHigh: ULONG + nFileIndexLow: ULONG + +class WIN32_FIND_DATAA(): + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: CHARPTR + cAlternateFileName: CHARPTR + +class WIN32_FIND_DATAW(): + dwFileAttributes: ULONG + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: ULONG + nFileSizeLow: ULONG + dwReserved0: ULONG + dwReserved1: ULONG + cFileName: WCHARPTR + cAlternateFileName: WCHARPTR + +def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass +def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE | t.State: pass +def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass +def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL | t.State: pass +def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG | t.State: pass +def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL | t.State: pass +def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG | t.State: pass +def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass +def SetEndOfFile(hFile: HANDLE) -> BOOL | t.State: pass +def FlushFileBuffers(hFile: HANDLE) -> BOOL | t.State: pass +def GetFileType(hFile: HANDLE) -> ULONG | t.State: pass +def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG | t.State: pass +def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG | t.State: pass +def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass +def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL | t.State: pass +def DeleteFileA(lpFileName: LPCSTR) -> BOOL | t.State: pass +def DeleteFileW(lpFileName: LPCWSTR) -> BOOL | t.State: pass +def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL | t.State: pass +def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL | t.State: pass +def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL | t.State: pass +def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL | t.State: pass +def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass +def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL | t.State: pass +def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass +def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL | t.State: pass +def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass +def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass +def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE | t.State: pass +def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE | t.State: pass +def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL | t.State: pass +def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL | t.State: pass +def FindClose(hFindFile: HANDLE) -> BOOL | t.State: pass +def GetStdHandle(nStdHandle: ULONG) -> HANDLE | t.State: pass +def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL | t.State: pass +def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL | t.State: pass +def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL | t.State: pass +def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL | t.State: pass +def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass +def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass +def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT | t.State: pass +def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT | t.State: pass +def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG | t.State: pass +def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG | t.State: pass +def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL | t.State: pass +def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL | t.State: pass +def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass +def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass diff --git a/includes/w32/win32memory.py b/includes/w32/win32memory.py new file mode 100644 index 0000000..824f39a --- /dev/null +++ b/includes/w32/win32memory.py @@ -0,0 +1,64 @@ +import t +from stdint import * +from w32.win32base import * + +MEM_COMMIT: t.CDefine = 0x00001000 +MEM_RESERVE: t.CDefine = 0x00002000 +MEM_DECOMMIT: t.CDefine = 0x00004000 +MEM_RELEASE: t.CDefine = 0x00008000 +MEM_FREE: t.CDefine = 0x00010000 +MEM_RESET: t.CDefine = 0x00080000 +MEM_TOP_DOWN: t.CDefine = 0x00100000 +MEM_WRITE_WATCH: t.CDefine = 0x00200000 +MEM_PHYSICAL: t.CDefine = 0x00400000 +MEM_LARGE_PAGES: t.CDefine = 0x20000000 + +PAGE_NOACCESS: t.CDefine = 0x01 +PAGE_READONLY: t.CDefine = 0x02 +PAGE_READWRITE: t.CDefine = 0x04 +PAGE_WRITECOPY: t.CDefine = 0x08 +PAGE_EXECUTE: t.CDefine = 0x10 +PAGE_EXECUTE_READ: t.CDefine = 0x20 +PAGE_EXECUTE_READWRITE: t.CDefine = 0x40 +PAGE_EXECUTE_WRITECOPY: t.CDefine = 0x80 +PAGE_GUARD: t.CDefine = 0x100 +PAGE_NOCACHE: t.CDefine = 0x200 +PAGE_WRITECOMBINE: t.CDefine = 0x400 + +HEAP_NO_SERIALIZE: t.CDefine = 0x00000001 +HEAP_GROWABLE: t.CDefine = 0x00000002 +HEAP_GENERATE_EXCEPTIONS: t.CDefine = 0x00000004 +HEAP_ZERO_MEMORY: t.CDefine = 0x00000008 +HEAP_REALLOC_IN_PLACE_ONLY: t.CDefine = 0x00000010 + +class MEMORY_BASIC_INFORMATION(): + BaseAddress: VOIDPTR + AllocationBase: VOIDPTR + AllocationProtect: ULONG + RegionSize: t.CSizeT + State: ULONG + Protect: ULONG + Type: ULONG + +def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR | t.State: pass +def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL | t.State: pass +def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL | t.State: pass +def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT | t.State: pass +def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass +def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL | t.State: pass +def GetProcessHeap() -> HANDLE | t.State: pass +def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE | t.State: pass +def HeapDestroy(hHeap: HANDLE) -> BOOL | t.State: pass +def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass +def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass +def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL | t.State: pass +def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT | t.State: pass +def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL | t.State: pass +def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT | t.State: pass +def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass +def GlobalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass +def GlobalLock(hMem: VOIDPTR) -> VOIDPTR | t.State: pass +def GlobalUnlock(hMem: VOIDPTR) -> BOOL | t.State: pass +def GlobalSize(hMem: VOIDPTR) -> t.CSizeT | t.State: pass +def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR | t.State: pass +def LocalFree(hMem: VOIDPTR) -> VOIDPTR | t.State: pass diff --git a/includes/w32/win32process.py b/includes/w32/win32process.py new file mode 100644 index 0000000..c46cd01 --- /dev/null +++ b/includes/w32/win32process.py @@ -0,0 +1,112 @@ +import t +from stdint import * +from w32.win32base import * + +PROCESS_TERMINATE: t.CDefine = 0x0001 +PROCESS_CREATE_THREAD: t.CDefine = 0x0002 +PROCESS_VM_OPERATION: t.CDefine = 0x0008 +PROCESS_VM_READ: t.CDefine = 0x0010 +PROCESS_VM_WRITE: t.CDefine = 0x0020 +PROCESS_QUERY_INFORMATION: t.CDefine = 0x0400 +PROCESS_ALL_ACCESS: t.CDefine = 0x001FFFFF + +THREAD_TERMINATE: t.CDefine = 0x0001 +THREAD_SUSPEND_RESUME: t.CDefine = 0x0002 +THREAD_GET_CONTEXT: t.CDefine = 0x0008 +THREAD_SET_CONTEXT: t.CDefine = 0x0010 +THREAD_QUERY_INFORMATION: t.CDefine = 0x0040 +THREAD_ALL_ACCESS: t.CDefine = 0x001FFFFF + +CREATE_SUSPENDED: t.CDefine = 0x00000004 +CREATE_NEW_CONSOLE: t.CDefine = 0x00000010 +CREATE_NEW_PROCESS_GROUP: t.CDefine = 0x00000200 +CREATE_NO_WINDOW: t.CDefine = 0x08000000 +DETACHED_PROCESS: t.CDefine = 0x00000008 + +STARTF_USESHOWWINDOW: t.CDefine = 0x00000001 +STARTF_USESTDHANDLES: t.CDefine = 0x00000100 + +SW_HIDE: t.CDefine = 0 +SW_SHOW: t.CDefine = 5 +SW_MINIMIZE: t.CDefine = 6 + +NORMAL_PRIORITY_CLASS: t.CDefine = 0x00000020 +IDLE_PRIORITY_CLASS: t.CDefine = 0x00000040 +HIGH_PRIORITY_CLASS: t.CDefine = 0x00000080 +REALTIME_PRIORITY_CLASS: t.CDefine = 0x00000100 +BELOW_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00004000 +ABOVE_NORMAL_PRIORITY_CLASS: t.CDefine = 0x00008000 + +STILL_ACTIVE: t.CDefine = 259 + +class STARTUPINFOA(): + cb: ULONG + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE + +class STARTUPINFOW(): + cb: ULONG + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: ULONG + dwY: ULONG + dwXSize: ULONG + dwYSize: ULONG + dwXCountChars: ULONG + dwYCountChars: ULONG + dwFillAttribute: ULONG + dwFlags: ULONG + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE + +class PROCESS_INFORMATION(): + hProcess: HANDLE + hThread: HANDLE + dwProcessId: ULONG + dwThreadId: ULONG + +def CreateProcessA(lpApplicationName: LPCSTR, lpCommandLine: CHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCSTR, lpStartupInfo: STARTUPINFOA | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass +def CreateProcessW(lpApplicationName: LPCWSTR, lpCommandLine: WCHARPTR, lpProcessAttributes: SECURITY_ATTRIBUTES | t.CPtr, lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInheritHandles: BOOL, dwCreationFlags: ULONG, lpEnvironment: VOIDPTR, lpCurrentDirectory: LPCWSTR, lpStartupInfo: STARTUPINFOW | t.CPtr, lpProcessInformation: PROCESS_INFORMATION | t.CPtr) -> BOOL | t.State: pass +def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL | t.State: pass +def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass +def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL | t.State: pass +def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE | t.State: pass +def GetCurrentProcess() -> HANDLE | t.State: pass +def GetCurrentProcessId() -> ULONG | t.State: pass +def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE | t.State: pass +def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE | t.State: pass +def SuspendThread(hThread: HANDLE) -> ULONG | t.State: pass +def ResumeThread(hThread: HANDLE) -> ULONG | t.State: pass +def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL | t.State: pass +def GetCurrentThread() -> HANDLE | t.State: pass +def GetCurrentThreadId() -> ULONG | t.State: pass +def GetThreadId(hThread: HANDLE) -> ULONG | t.State: pass +def GetProcessId(hProcess: HANDLE) -> ULONG | t.State: pass +def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL | t.State: pass +def GetThreadPriority(hThread: HANDLE) -> INT | t.State: pass +def ExitProcess(uExitCode: UINT) -> VOID | t.State: pass +def ExitThread(dwExitCode: ULONG) -> VOID | t.State: pass +def TlsAlloc() -> ULONG | t.State: pass +def TlsFree(dwTlsIndex: ULONG) -> BOOL | t.State: pass +def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR | t.State: pass +def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL | t.State: pass diff --git a/includes/w32/win32sync.py b/includes/w32/win32sync.py new file mode 100644 index 0000000..9e2a4b1 --- /dev/null +++ b/includes/w32/win32sync.py @@ -0,0 +1,45 @@ +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION(): + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass +def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass +def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass +def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID | t.State: pass +def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL | t.State: pass +def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG | t.State: pass +def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL | t.State: pass +def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass +def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass +def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass +def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass +def ReleaseMutex(hMutex: HANDLE) -> BOOL | t.State: pass +def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass +def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass +def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass +def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass +def SetEvent(hEvent: HANDLE) -> BOOL | t.State: pass +def ResetEvent(hEvent: HANDLE) -> BOOL | t.State: pass +def PulseEvent(hEvent: HANDLE) -> BOOL | t.State: pass +def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE | t.State: pass +def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE | t.State: pass +def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE | t.State: pass +def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE | t.State: pass +def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL | t.State: pass +def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG | t.State: pass +def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass +def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG | t.State: pass +def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass +def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID | t.State: pass +def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass +def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass +def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID | t.State: pass +def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID | t.State: pass diff --git a/includes/zlib/__init__.py b/includes/zlib/__init__.py new file mode 100644 index 0000000..829b69e --- /dev/null +++ b/includes/zlib/__init__.py @@ -0,0 +1 @@ +from .pyzlib import * diff --git a/includes/zlib/pyzlib.py b/includes/zlib/pyzlib.py new file mode 100644 index 0000000..4c63447 --- /dev/null +++ b/includes/zlib/pyzlib.py @@ -0,0 +1,696 @@ +from stdint import * +import zlib.zdeflate as zdeflate +import zlib.zinflate as zinflate +import zlib.zchecksum as zchecksum +import zlib.zdef as zdef +import zlib.zhuff as zhuff +import stdlib +import string +import stdio +import mpool +import t, c + + +# ============================================================ +# Constants - matching Python zlib module names and values +# ============================================================ + +# Compression levels +Z_NO_COMPRESSION: t.CDefine = 0 +Z_BEST_SPEED: t.CDefine = 1 +Z_BEST_COMPRESSION: t.CDefine = 9 +Z_DEFAULT_COMPRESSION: t.CDefine = (-1) + +# Compression methods +DEFLATED: t.CDefine = 8 + +# Flush modes +Z_NO_FLUSH: t.CDefine = 0 +Z_PARTIAL_FLUSH: t.CDefine = 1 +Z_SYNC_FLUSH: t.CDefine = 2 +Z_FULL_FLUSH: t.CDefine = 3 +Z_FINISH: t.CDefine = 4 +Z_BLOCK: t.CDefine = 5 +Z_TREES: t.CDefine = 6 + +# Strategies +Z_DEFAULT_STRATEGY: t.CDefine = 0 +Z_FILTERED: t.CDefine = 1 +Z_HUFFMAN_ONLY: t.CDefine = 2 +Z_RLE: t.CDefine = 3 +Z_FIXED: t.CDefine = 4 + +# Return codes +Z_OK: t.CDefine = 0 +Z_STREAM_END: t.CDefine = 1 +Z_NEED_DICT: t.CDefine = 2 +Z_ERRNO: t.CDefine = (-1) +Z_STREAM_ERROR: t.CDefine = (-2) +Z_DATA_ERROR: t.CDefine = (-3) +Z_MEM_ERROR: t.CDefine = (-4) +Z_BUF_ERROR: t.CDefine = (-5) +Z_VERSION_ERROR: t.CDefine = (-6) + +# Window / Buffer constants +MAX_WBITS: t.CDefine = 15 +DEF_BUF_SIZE: t.CDefine = 16384 +DEF_MEM_LEVEL: t.CDefine = 8 + +# Version +ZLIB_VERSION: t.CDefine = "1.3.2" + +pyzlib_error_msg: list[t.CChar, 512] = "" +pyzlib_error_code_val: t.CInt = 0 + +# ============================================================ +# Structures +# ============================================================ +@t.Object +class Compress: + pool: mpool.MPool | t.CPtr + stream: VOIDPTR + is_initialized: t.CInt + is_finished: t.CInt + level: t.CInt + method: t.CInt + wbits: t.CInt + memLevel: t.CInt + strategy: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + last_pos: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + header_written: t.CInt + + def compress(self, + data: BYTEPTR, data_len: t.CSizeT, + out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if self.is_finished: + set_error(Z_STREAM_ERROR, "compress object already finished") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + if data_len == 0: + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(calloc(1, 1)) + else: + p: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + memset(p, 0, 1) + return p + while self.input_buf_len + data_len > self.input_buf_cap: + self.input_buf_cap *= 2 + if self.pool == None: + new_buf: BYTEPTR = BYTEPTR(realloc(self.input_buf, self.input_buf_cap)) + else: + new_buf: BYTEPTR = BYTEPTR(self.pool.alloc(self.input_buf_cap)) + if new_buf: + memcpy(new_buf, self.input_buf, self.input_buf_len) + self.pool.free(self.input_buf) + if not new_buf: + set_error(Z_MEM_ERROR, "out of memory") + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(calloc(1, 1)) + else: + p2: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + memset(p2, 0, 1) + return p2 + self.input_buf = new_buf + memcpy(self.input_buf + self.input_buf_len, data, data_len) + self.input_buf_len += data_len + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(calloc(1, 1)) + else: + p3: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + memset(p3, 0, 1) + return p3 + + def flush(self, mode: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + if mode == Z_FINISH: + if not self.header_written: + self.header_written = 1 + input_data: BYTEPTR = self.input_buf + input_len: t.CSizeT = self.input_buf_len + if input_len == 0: + s.writer.write_bits(1, 1) + s.writer.write_bits(1, 2) + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + lit_tree.encode_symbol(256, c.Addr(s.writer)) + else: + s.adler = zchecksum.zchecksum_adler32(input_data, input_len, 1) + s.compress_block(input_data, input_len, 1) + s.is_finished = 1 + if s.wbits >= 0: + s.writer.align() + adler: t.CUInt32T = s.adler + s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF + s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF + s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF + s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF + s.writer.byte_pos += 4 + self.is_finished = 1 + total: t.CSizeT = s.writer.total() + if self.pool == None: + result: BYTEPTR = BYTEPTR(malloc(total)) + else: + result: BYTEPTR = BYTEPTR(self.pool.alloc(total)) + if result: memcpy(result, s.writer.buf, total) + c.Set(c.Deref(out_len), total) + if self.pool == None: + free(self.input_buf) + else: + self.pool.free(self.input_buf) + self.input_buf = None + self.input_buf_len = 0 + self.input_buf_cap = 0 + return result + elif mode == Z_SYNC_FLUSH or mode == Z_FULL_FLUSH: + input_data: BYTEPTR = self.input_buf + input_len: t.CSizeT = self.input_buf_len + if input_len > 0: + s.adler = zchecksum.zchecksum_adler32(input_data, input_len, s.adler) + s.compress_block(input_data, input_len, 0) + self.input_buf_len = 0 + s.writer.write_bits(0, 1) + s.writer.write_bits(0, 2) + s.writer.align() + prev_pos: t.CSizeT = self.last_pos + total: t.CSizeT = s.writer.total() + delta: t.CSizeT = total - prev_pos + self.last_pos = s.writer.byte_pos + if delta == 0: + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(calloc(1, 1)) + else: + p4: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + memset(p4, 0, 1) + return p4 + + if self.pool == None: + result: BYTEPTR = BYTEPTR(malloc(delta)) + else: + result: BYTEPTR = BYTEPTR(self.pool.alloc(delta)) + if result: memcpy(result, s.writer.buf + prev_pos, delta) + c.Set(c.Deref(out_len), delta) + return result + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(calloc(1, 1)) + else: + p5: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + memset(p5, 0, 1) + return p5 + + def copy(self) -> Compress | t.CPtr: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "compress object not initialized") + return None + if self.pool == None: + copy_obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__()) + else: + copy_obj: Compress | t.CPtr = self.pool.alloc(Compress.__sizeof__()) + memset(copy_obj, 0, Compress.__sizeof__()) + if not copy_obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.pool = self.pool + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + copy_obj.stream = s.copy() + if not copy_obj.stream: + if self.pool == None: + free(copy_obj) + else: + self.pool.free(copy_obj) + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.is_initialized = 1 + copy_obj.is_finished = self.is_finished + copy_obj.level = self.level + copy_obj.method = self.method + copy_obj.wbits = self.wbits + copy_obj.memLevel = self.memLevel + copy_obj.strategy = self.strategy + copy_obj.last_pos = self.last_pos + copy_obj.header_written = self.header_written + if self.input_buf and self.input_buf_len > 0: + if self.pool == None: + copy_obj.input_buf = BYTEPTR(calloc(1, self.input_buf_cap)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(self.input_buf_cap)) + memset(copy_obj.input_buf, 0, self.input_buf_cap) + if copy_obj.input_buf: + memcpy(copy_obj.input_buf, self.input_buf, self.input_buf_len) + copy_obj.input_buf_cap = self.input_buf_cap + copy_obj.input_buf_len = self.input_buf_len + else: + if self.pool == None: + copy_obj.input_buf = BYTEPTR(calloc(1, 256)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(256)) + memset(copy_obj.input_buf, 0, 256) + copy_obj.input_buf_cap = 256 + copy_obj.input_buf_len = 0 + if self.zdict and self.zdict_len > 0: + copy_obj.zdict = clone_bytes(self.pool, self.zdict, self.zdict_len) + copy_obj.zdict_len = self.zdict_len + return copy_obj + + def delete(self): + if self.is_initialized and self.stream: + s: zdeflate.zdeflate_stream | t.CPtr = self.stream # 隐式类型转换 + s.destroy() + if self.pool == None: + free(self.zdict) + free(self.input_buf) + free(self) + else: + self.pool.free(self.zdict) + self.pool.free(self.input_buf) + self.pool.free(self) + + def __del__(self): + self.delete() + + +@t.Object +class Decompress: + pool: mpool.MPool | t.CPtr + stream: VOIDPTR + is_initialized: t.CInt + eof: t.CInt + wbits: t.CInt + zdict: BYTEPTR + zdict_len: t.CSizeT + _unused_data: BYTEPTR + _unused_data_len: t.CSizeT + _unused_data_cap: t.CSizeT + _unconsumed_tail: BYTEPTR + _unconsumed_tail_len: t.CSizeT + _unconsumed_tail_cap: t.CSizeT + input_buf: BYTEPTR + input_buf_len: t.CSizeT + input_buf_cap: t.CSizeT + + def decompress(self, data: BYTEPTR, data_len: t.CSizeT, + max_length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + if self.eof: + if data and data_len > 0: + append_bytes(self.pool, c.Addr(self._unused_data), c.Addr(self._unused_data_len), + c.Addr(self._unused_data_cap), data, data_len) + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(calloc(1, 1)) + else: + p6: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + memset(p6, 0, 1) + return p6 + self._unconsumed_tail_len = 0 + if data and data_len > 0: + append_bytes(self.pool, c.Addr(self.input_buf), c.Addr(self.input_buf_len), + c.Addr(self.input_buf_cap), data, data_len) + if self.input_buf_len == 0: + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(calloc(1, 1)) + else: + p7: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + memset(p7, 0, 1) + return p7 + s: zinflate.zinflate_stream | t.CPtr = zinflate.zinflate_create(self.pool, self.wbits) + if not s: + set_error(Z_MEM_ERROR, "out of memory") + return None + if self.zdict and self.zdict_len > 0: + s.set_dictionary(self.zdict, self.zdict_len) + out: t.CUInt8T | t.CPtr = None + err: t.CInt = s.decompress(self.input_buf, self.input_buf_len, + max_length, c.Addr(out), out_len) + if err != 0: + s.destroy() + set_error(Z_DATA_ERROR, "decompression failed") + return None + if s.is_finished: + self.eof = 1 + if s.input_pos < s.input_len: + append_bytes(self.pool, c.Addr(self._unused_data), c.Addr(self._unused_data_len), + c.Addr(self._unused_data_cap), + s.input_data + s.input_pos, + s.input_len - s.input_pos) + self.input_buf_len = 0 + else: + consumed: t.CSizeT = s.input_pos + if consumed < self.input_buf_len: + remaining: t.CSizeT = self.input_buf_len - consumed + memmove(self.input_buf, self.input_buf + consumed, remaining) + self.input_buf_len = remaining + else: + self.input_buf_len = 0 + s.destroy() + return out + + def flush(self, length: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + c.Set(c.Deref(out_len), 0) + if self.pool == None: + return BYTEPTR(calloc(1, 1)) + else: + p8: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + memset(p8, 0, 1) + return p8 + + def copy(self) -> Decompress | t.CPtr: + if not self.is_initialized: + set_error(Z_STREAM_ERROR, "decompress object not initialized") + return None + if self.pool == None: + copy_obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__()) + else: + copy_obj: Decompress | t.CPtr = self.pool.alloc(Decompress.__sizeof__()) + memset(copy_obj, 0, Decompress.__sizeof__()) + if not copy_obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + copy_obj.pool = self.pool + copy_obj.is_initialized = 1 + copy_obj.eof = self.eof + copy_obj.wbits = self.wbits + if self.zdict and self.zdict_len > 0: + copy_obj.zdict = clone_bytes(self.pool, self.zdict, self.zdict_len) + copy_obj.zdict_len = self.zdict_len + if self._unused_data and self._unused_data_len > 0: + copy_obj._unused_data = clone_bytes(self.pool, self._unused_data, self._unused_data_len) + copy_obj._unused_data_len = self._unused_data_len + copy_obj._unused_data_cap = self._unused_data_len + if self._unconsumed_tail and self._unconsumed_tail_len > 0: + copy_obj._unconsumed_tail = clone_bytes(self.pool, self._unconsumed_tail, self._unconsumed_tail_len) + copy_obj._unconsumed_tail_len = self._unconsumed_tail_len + copy_obj._unconsumed_tail_cap = self._unconsumed_tail_len + if self.input_buf and self.input_buf_len > 0: + copy_obj.input_buf = clone_bytes(self.pool, self.input_buf, self.input_buf_len) + copy_obj.input_buf_len = self.input_buf_len + copy_obj.input_buf_cap = self.input_buf_cap + else: + if self.pool == None: + copy_obj.input_buf = BYTEPTR(calloc(1, 256)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(256)) + memset(copy_obj.input_buf, 0, 256) + copy_obj.input_buf_cap = 256 + copy_obj.input_buf_len = 0 + return copy_obj + + def delete(self): + if self.pool == None: + free(self.zdict) + free(self._unused_data) + free(self._unconsumed_tail) + free(self.input_buf) + free(self) + else: + self.pool.free(self.zdict) + self.pool.free(self._unused_data) + self.pool.free(self._unconsumed_tail) + self.pool.free(self.input_buf) + self.pool.free(self) + + def unused_data(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + #if not self: + # if length: + # c.Set(c.Deref(length), 0) + # return None + if length: + c.Set(c.Deref(length), self._unused_data_len) + return self._unused_data + + def unconsumed_tail(self, length: t.CSizeT | t.CPtr) -> BYTEPTR: + #if not self: + # if length: + # c.Set(c.Deref(length), 0) + # return None + if length: + c.Set(c.Deref(length), self._unconsumed_tail_len) + return self._unconsumed_tail + +# def eof(self) -> t.CInt: +# # if not obj: return 0 +# return self.eof + + + +def set_error(code: int, msg: str): + global pyzlib_error_code_val, pyzlib_error_msg + pyzlib_error_code_val = code + if msg: + strncpy(pyzlib_error_msg, msg, pyzlib_error_msg.__sizeof__() - 1) + pyzlib_error_msg[pyzlib_error_msg.__sizeof__() - 1] = '\0' + else: + pyzlib_error_msg[0] = '\0' + +def clone_bytes(pool: mpool.MPool | t.CPtr, src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if not src or length == 0: return None + if pool == None: + dst: BYTEPTR = BYTEPTR(malloc(length)) + else: + dst: BYTEPTR = BYTEPTR(pool.alloc(length)) + if dst: memcpy(dst, src, length) + return dst + +def append_bytes(pool: mpool.MPool | t.CPtr, buf: BYTE | t.CPtr[t.CPtr], length: t.CSizeT | t.CPtr, cap: t.CSizeT | t.CPtr, + data: BYTEPTR, data_len: t.CSizeT) -> t.CInt: + if not data or data_len == 0: return 0 + needed: t.CSizeT = c.Deref(length) + data_len + if needed > c.Deref(cap): + new_cap: t.CSizeT = c.Deref(cap) * 2 + if new_cap < needed: new_cap = needed + if pool == None: + new_buf: BYTEPTR = BYTEPTR(realloc(c.Deref(buf), new_cap)) + else: + new_buf: BYTEPTR = BYTEPTR(pool.alloc(new_cap)) + if new_buf: + memcpy(new_buf, c.Deref(buf), c.Deref(length)) + pool.free(c.Deref(buf)) + if not new_buf: return -1 + c.Set(c.Deref(buf), new_buf) + c.Set(c.Deref(cap), new_cap) + memcpy(c.Deref(buf) + c.Deref(length), data, data_len) + c.Set(c.Deref(length), c.Deref(length) + data_len) + return 0 + + +def shrink_to_fit(pool: mpool.MPool | t.CPtr, buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if length == 0: + if pool == None: + free(buf) + return BYTEPTR(calloc(1, 1)) + else: + pool.free(buf) + p: BYTEPTR = BYTEPTR(pool.alloc(1)) + memset(p, 0, 1) + return p + if pool == None: + result: BYTEPTR = BYTEPTR(realloc(buf, length)) + return result if result else buf + else: + result: BYTEPTR = BYTEPTR(pool.alloc(length)) + if result: + memcpy(result, buf, length) + pool.free(buf) + return result + return buf + + +def runtime_version() -> str: + return ZLIB_VERSION + +def get_error() -> str: + return pyzlib_error_msg + +def get_error_code() -> t.CInt: + return pyzlib_error_code_val + +def clear_error(): + global pyzlib_error_msg, pyzlib_error_code_val + pyzlib_error_msg[0] = '\0' + pyzlib_error_code_val = 0 + +def compress(pool: mpool.MPool | t.CPtr, data: BYTEPTR, data_len: t.CSizeT, + level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not data and data_len > 0: + set_error(Z_STREAM_ERROR, "data is None but data_len > 0") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: + actual_wbits = -MAX_WBITS + raw_result: UINT8PTR = zdeflate.zdeflate_one_shot(pool, data, data_len, level, actual_wbits, out_len) + if not raw_result: + set_error(Z_DATA_ERROR, "compression failed") + return None + if wbits > MAX_WBITS: + gzip_len: t.CSizeT = 10 + c.Deref(out_len) + 8 + if pool == None: + gzip_buf: BYTEPTR = BYTEPTR(malloc(gzip_len)) + else: + gzip_buf: BYTEPTR = BYTEPTR(pool.alloc(gzip_len)) + if not gzip_buf: + if pool == None: + free(raw_result) + else: + pool.free(raw_result) + set_error(Z_MEM_ERROR, "out of memory") + return None + pos: t.CSizeT = 0 + gzip_buf[pos + 0] = 0x1F + gzip_buf[pos + 1] = 0x8B + gzip_buf[pos + 2] = 0x08 + gzip_buf[pos + 3] = 0x00 + gzip_buf[pos + 4] = 0x00 + gzip_buf[pos + 5] = 0x00 + gzip_buf[pos + 6] = 0x00 + gzip_buf[pos + 7] = 0x00 + gzip_buf[pos + 8] = 0x00 + gzip_buf[pos + 9] = 0xFF + pos += 10 + + memcpy(gzip_buf + pos, raw_result, c.Deref(out_len)) + pos += c.Deref(out_len) + if pool == None: + free(raw_result) + else: + pool.free(raw_result) + + crc: t.CUInt32T = zchecksum.zchecksum_crc32(data, data_len, 0) + gzip_buf[pos + 0] = (crc) & 0xFF + gzip_buf[pos + 1] = (crc >> 8) & 0xFF + gzip_buf[pos + 2] = (crc >> 16) & 0xFF + gzip_buf[pos + 3] = (crc >> 24) & 0xFF + gzip_buf[pos + 4] = (data_len) & 0xFF + gzip_buf[pos + 5] = (data_len >> 8) & 0xFF + gzip_buf[pos + 6] = (data_len >> 16) & 0xFF + gzip_buf[pos + 7] = (data_len >> 24) & 0xFF + pos += 8 + c.Set(c.Deref(out_len), pos) + return shrink_to_fit(pool, gzip_buf, pos) + return shrink_to_fit(pool, raw_result, c.Deref(out_len)) + + +def decompress(pool: mpool.MPool | t.CPtr, data: BYTEPTR, data_len: t.CSizeT, + wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> BYTEPTR: + if not data and data_len > 0: + set_error(Z_STREAM_ERROR, "data is None but data_len > 0") + return None + if not out_len: + set_error(Z_STREAM_ERROR, "out_len is None") + return None + result: UINT8PTR = zinflate.zinflate_one_shot(pool, data, data_len, wbits, bufsize, out_len) + if not result: + set_error(Z_DATA_ERROR, "decompression failed") + return None + return shrink_to_fit(pool, result, c.Deref(out_len)) + +def compressobj(pool: mpool.MPool | t.CPtr, level: t.CInt, method: t.CInt, wbits: t.CInt, + memLevel: t.CInt, strategy: t.CInt, + zdict: BYTEPTR, zdict_len: t.CSizeT) -> Compress | t.CPtr: + if pool == None: + obj: Compress | t.CPtr = calloc(1, Compress.__sizeof__()) + else: + obj: Compress | t.CPtr = pool.alloc(Compress.__sizeof__()) + memset(obj, 0, Compress.__sizeof__()) + if not obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + obj.pool = pool + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: actual_wbits = wbits - 16 + s: zdeflate.zdeflate_stream | t.CPtr = zdeflate.zdeflate_create(pool, level, actual_wbits, memLevel, strategy) + if not s: + if pool == None: + free(obj) + else: + pool.free(obj) + set_error(Z_MEM_ERROR, "out of memory") + return None + obj.stream = s + obj.is_initialized = 1 + obj.level = level + obj.method = method + obj.wbits = wbits + obj.memLevel = memLevel + obj.strategy = strategy + if pool == None: + obj.input_buf = BYTEPTR(calloc(1, 256)) + else: + obj.input_buf = BYTEPTR(pool.alloc(256)) + memset(obj.input_buf, 0, 256) + obj.input_buf_cap = 256 + obj.input_buf_len = 0 + obj.header_written = 0 + if zdict and zdict_len > 0: + s.set_dictionary(zdict, zdict_len) + obj.zdict = clone_bytes(pool, zdict, zdict_len) + obj.zdict_len = zdict_len + return obj + + +def decompressobj(pool: mpool.MPool | t.CPtr, wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: + if pool == None: + obj: Decompress | t.CPtr = calloc(1, Decompress.__sizeof__()) + else: + obj: Decompress | t.CPtr = pool.alloc(Decompress.__sizeof__()) + memset(obj, 0, Decompress.__sizeof__()) + if not obj: + set_error(Z_MEM_ERROR, "out of memory") + return None + obj.pool = pool + actual_wbits: t.CInt = wbits + if wbits > MAX_WBITS: actual_wbits = wbits - 16 + obj.stream = None + obj.is_initialized = 1 + obj.wbits = actual_wbits + if zdict and zdict_len > 0: + obj.zdict = clone_bytes(pool, zdict, zdict_len) + obj.zdict_len = zdict_len + if pool == None: + obj.input_buf = BYTEPTR(calloc(1, 256)) + else: + obj.input_buf = BYTEPTR(pool.alloc(256)) + memset(obj.input_buf, 0, 256) + obj.input_buf_cap = 256 + obj.input_buf_len = 0 + return obj + +def zlib_adler32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: + return zchecksum.zchecksum_adler32(data, length, UINT32(value)) + +def zlib_crc32(data: BYTEPTR, length: t.CSizeT, value: t.CUnsignedLong) -> t.CUnsignedLong: + return zchecksum.zchecksum_crc32(data, length, UINT32(value)) diff --git a/includes/zlib/zchecksum.py b/includes/zlib/zchecksum.py new file mode 100644 index 0000000..a79d695 --- /dev/null +++ b/includes/zlib/zchecksum.py @@ -0,0 +1,89 @@ +from stdint import * +import t, c + + +def zchecksum_adler32(data: UINT8PTR, length: t.CSizeT, init: UINT32) -> t.CUInt32T: + a: t.CUInt32T = (init >> 0) & 0xFFFF + b: t.CUInt32T = (init >> 16) & 0xFFFF + if not data or length == 0: + return init + i: t.CSizeT + for i in range(length): + a = (a + data[i]) % 65521 + b = (b + a) % 65521 + return (b << 16) | a + +crc32_table: list[t.CUInt32T, 256] = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBBBD6, 0xACBCCB40, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7D49, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDede9EC5, 0x47D7897F, 0x30D0B8E9, + 0xBDDA8B1C, 0xCADD8B8A, 0x53D3903A, 0x24D4C2AC, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +] + +def zchecksum_crc32(data: UINT8PTR, length: t.CSizeT, init: t.CUInt32T) -> t.CUInt32T: + crc: t.CUInt32T = init ^ 0xFFFFFFFF + if not data or length == 0: return init + i: t.CSizeT + for i in range(length): + crc = crc32_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8) + return crc ^ 0xFFFFFFFF diff --git a/includes/zlib/zdef.py b/includes/zlib/zdef.py new file mode 100644 index 0000000..fad0797 --- /dev/null +++ b/includes/zlib/zdef.py @@ -0,0 +1,288 @@ +from stdint import * +import stddef +import string +import stdlib +import mpool +import t, c + + +# ============================================================ +# DEFLATE / zlib constants +# ============================================================ +ZDEFLATE_WINDOW_BITS: t.CDefine = 15 +ZDEFLATE_WINDOW_SIZE: t.CDefine = (1 << ZDEFLATE_WINDOW_BITS) +ZDEFLATE_WINDOW_MASK: t.CDefine = (ZDEFLATE_WINDOW_SIZE - 1) + +ZDEFLATE_MIN_MATCH: t.CDefine = 3 +ZDEFLATE_MAX_MATCH: t.CDefine = 258 + +ZDEFLATE_HASH_BITS: t.CDefine = 15 +ZDEFLATE_HASH_SIZE: t.CDefine = (1 << ZDEFLATE_HASH_BITS) +ZDEFLATE_HASH_MASK: t.CDefine = (ZDEFLATE_HASH_SIZE - 1) + +ZDEFLATE_MAX_CODES: t.CDefine = 288 +ZDEFLATE_MAX_DIST_CODES: t.CDefine = 32 +ZDEFLATE_MAX_BITS: t.CDefine = 15 +ZDEFLATE_MAX_CODELEN_CODES: t.CDefine = 19 + +ZDEFLATE_LIT_COUNT: t.CDefine = 286 +ZDEFLATE_DIST_COUNT: t.CDefine = 30 + +ZDEFLATE_LEN_SYMBOLS_BASE: t.CDefine = 257 +ZDEFLATE_END_OF_BLOCK: t.CDefine = 256 + +# ============================================================ +# Length / Distance extra bits tables (RFC 1951) +# ============================================================ +zdeflate_len_extra_bits: list[t.CInt, 29] = [ + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 4, 4, 4, 4, + 5, 5, 5, 5, + 0 +] + +zdeflate_len_base: list[t.CInt, 29] = [ + 3, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 15, 17, + 19, 23, 27, 31, + 35, 43, 51, 59, + 67, 83, 99, 115, + 131, 163, 195, 227, + 258 +] + +zdeflate_dist_extra_bits: list[t.CInt, 30] = [ + 0, 0, 0, 0, + 1, 1, + 2, 2, + 3, 3, + 4, 4, + 5, 5, + 6, 6, + 7, 7, + 8, 8, + 9, 9, + 10, 10, + 11, 11, + 12, 12, + 13, 13 +] + +zdeflate_dist_base: list[t.CInt, 30] = [ + 1, 2, 3, 4, + 5, 7, + 9, 13, + 17, 25, + 33, 49, + 65, 97, + 129, 193, + 257, 385, + 513, 769, + 1025, 1537, + 2049, 3073, + 4097, 6145, + 8193, 12289, + 16385, 24577 +] + +zdeflate_codelen_order: list[int, 19] = [ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +] + +# ============================================================ +# Bit writer - writes bits LSB first into a byte buffer +# ============================================================ +@t.Object +class zbit_writer: + pool: mpool.MPool | t.CPtr + buf: BYTE | t.CPtr + cap: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def __init__(self, pool: mpool.MPool | t.CPtr): + self.pool = pool + self.cap = 4096 + if pool == None: + self.buf = BYTEPTR(malloc(self.cap)) + else: + self.buf = BYTEPTR(pool.alloc(self.cap)) + memset(self.buf, 0, self.cap) + self.byte_pos = 0 + self.bit_pos = 0 + + def ensure(self, need: t.CSizeT): + while self.byte_pos + need + 4 >= self.cap: + new_cap: t.CSizeT = self.cap * 2 + if self.pool == None: + new_buf: BYTE | t.CPtr = BYTEPTR(realloc(self.buf, new_cap)) + else: + new_buf: BYTE | t.CPtr = BYTEPTR(self.pool.alloc(new_cap)) + if new_buf: + memcpy(new_buf, self.buf, self.byte_pos + (self.bit_pos + 7) / 8) + self.pool.free(self.buf) + if not new_buf: return + memset(new_buf + self.cap, 0, new_cap - self.cap) + self.buf = new_buf + self.cap = new_cap + + def write_bits(self, value: UINT, nbits: t.CInt): + self.ensure((nbits + 7) / 8 + 1) + for i in range(nbits): + if value & (UINT(1) << i): + self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + + def write_bits_rev(self, code: UINT, nbits: t.CInt): + self.ensure((nbits + 7) / 8 + 1) + for i in range(nbits - 1, -1, -1): + if code & (UINT(1) << i): + self.buf[self.byte_pos] |= (UINT(1) << self.bit_pos) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + + def stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + self.write_bits(1 if final else 0, 1) + self.write_bits(0, 2) + self.align() + + pos: t.CSizeT = 0 + while pos < length: + block_length: t.CSizeT = length - pos + if block_length > 65535: + block_length = 65535 + n: t.CUInt16T = t.CUInt16T(block_length) + ncomp: t.CUInt16T = ~n + self.write_bits(n, 16) + self.write_bits(ncomp, 16) + + self.ensure(block_length) + i: t.CSizeT = 0 + for i in range(block_length): + self.buf[self.byte_pos] = data[pos + i] + self.byte_pos += 1 + pos += block_length + if pos < length: + self.write_bits(0, 1) + self.write_bits(0, 2) + self.align() + + def write_zlib_header(self, wbits: t.CInt, level: t.CInt): + cinfo: t.CInt = wbits - 8 + if cinfo < 1: cinfo = 1 + if cinfo > 7: cinfo = 7 + cmf: t.CUnsignedChar = t.CUnsignedChar((cinfo << 4) | 8) + + flevel: t.CInt = 0 + if level >= 5: flevel = 3 + elif level >= 3: flevel = 1 + + flg: t.CUnsignedChar = t.CUnsignedChar(flevel << 6) + flg |= t.CUnsignedChar(31 - (cmf * 256 + flg) % 31) + + self.buf[self.byte_pos + 0] = cmf + self.buf[self.byte_pos + 1] = flg + self.byte_pos += 2 + + + def write_gzip_header(self): + self.buf[self.byte_pos + 0] = 0x1F + self.buf[self.byte_pos + 1] = 0x8B + self.buf[self.byte_pos + 2] = 0x08 + self.buf[self.byte_pos + 3] = 0x00 + self.buf[self.byte_pos + 4] = 0x00 + self.buf[self.byte_pos + 5] = 0x00 + self.buf[self.byte_pos + 6] = 0x00 + self.buf[self.byte_pos + 7] = 0x00 + self.buf[self.byte_pos + 8] = 0x00 + self.buf[self.byte_pos + 9] = 0xFF + self.byte_pos += 10 + + def align(self): + if self.bit_pos > 0: + self.bit_pos = 0 + self.byte_pos += 1 + + def total(self) -> t.CSizeT: + return self.byte_pos + (1 if (self.bit_pos > 0) else 0) + + def free(self): + if self.pool == None: + free(self.buf) + else: + self.pool.free(self.buf) + self.buf = None + self.cap = 0 + self.byte_pos = 0 + self.bit_pos = 0 + + def __del__(self): + self.free() + +# ============================================================ +# Bit reader - reads bits LSB first from a byte buffer +# ============================================================ +@t.Object +class zbit_reader: + buf: BYTE | t.CPtr + length: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def init(self, buf: BYTE | t.CPtr, length: t.CSizeT): + self.buf = buf + self.length = length + self.byte_pos = 0 + self.bit_pos = 0 + + def read_bits(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits): + if self.byte_pos >= self.length: return -1 + if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): + val |= (UINT(1) << i) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + def read_bits_rev(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits - 1, 0, -1): + if self.byte_pos >= self.length: return -1 + if self.buf[self.byte_pos] & (UINT(1) << self.bit_pos): + val |= (UINT(1) << i) + self.bit_pos += 1 + if self.bit_pos == 8: + self.bit_pos = 0 + self.byte_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + def align(self): + if self.bit_pos > 0: + self.bit_pos = 0 + self.byte_pos += 1 + +# ============================================================ +# Memory allocation helper for bare metal +# Can be replaced with custom allocator +# ============================================================ +def zdef_alloc(pool: mpool.MPool | t.CPtr, n: t.CSizeT) -> VOIDPTR: + if pool == None: return malloc(n) + return pool.alloc(n) +def zdef_free(pool: mpool.MPool | t.CPtr, p: VOIDPTR): + if pool == None: + free(p) + return + pool.free(p) diff --git a/includes/zlib/zdeflate.py b/includes/zlib/zdeflate.py new file mode 100644 index 0000000..db3a7b2 --- /dev/null +++ b/includes/zlib/zdeflate.py @@ -0,0 +1,434 @@ +from stdint import * +import zlib.zchecksum as zchecksum +import zlib.zhuff as zhuff +import zlib.zdef as zdef +import string +import stdio +import mpool +import t, c + + +@t.Object +class zdeflate_stream: + pool: mpool.MPool | t.CPtr + writer: zdef.zbit_writer + window: BYTE | t.CPtr + window_pos: t.CInt + window_size: t.CInt + hash_head: t.CInt | t.CPtr + hash_prev: t.CInt | t.CPtr + level: t.CInt + strategy: t.CInt + wbits: t.CInt + is_finished: t.CInt + adler: t.CUInt32T + + def find_match(self, data: BYTE | t.CPtr, data_len: t.CSizeT, + pos: t.CSizeT, best_dist: t.CInt | t.CPtr) -> t.CInt: + if pos + 2 >= data_len: return 0 + h: t.CUnsignedInt = zdeflate_hash(data + pos) + chain: t.CInt = self.hash_head[h] + best_len: t.CInt = zdef.ZDEFLATE_MIN_MATCH - 1 + c.Set(c.Deref(best_dist), 0) + max_chain: t.CInt = 128 if (self.level >= 5) else (32 if (self.level >= 2) else 4) + limit: t.CInt = (1 << self.wbits) if (self.wbits > 0) else zdef.ZDEFLATE_WINDOW_SIZE + if limit > zdef.ZDEFLATE_WINDOW_SIZE: + limit = zdef.ZDEFLATE_WINDOW_SIZE + attempts: t.CInt = 0 + while chain >= 0 and attempts < max_chain: + dist: t.CInt = t.CInt(pos) - chain + if dist <= 0 or dist > limit: break + match_len: t.CInt = 0 + max_len: t.CInt = t.CInt(data_len - pos) + if max_len > zdef.ZDEFLATE_MAX_MATCH: + max_len = zdef.ZDEFLATE_MAX_MATCH + while match_len < max_len and data[pos + match_len] == data[chain + match_len]: + match_len += 1 + if match_len > best_len: + best_len = match_len + c.Set(c.Deref(best_dist), dist) + if best_len >= zdef.ZDEFLATE_MAX_MATCH: break + chain = self.hash_prev[chain & zdef.ZDEFLATE_WINDOW_MASK] + if chain <= t.CInt(pos) - limit: break + attempts += 1 + return best_len if (best_len >= zdef.ZDEFLATE_MIN_MATCH) else 0 + + def update_hash(self, data: BYTE | t.CPtr, pos: t.CSizeT): + if pos + 2 < pos: return + h: t.CUnsignedInt = zdeflate_hash(data + pos) + self.hash_prev[pos & zdef.ZDEFLATE_WINDOW_MASK] = self.hash_head[h] + self.hash_head[h] = t.CInt(pos) + + def write_fixed_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + dist_tree.build_fixed_dist_tree() + self.writer.write_bits(1 if final else 0, 1) + self.writer.write_bits(1, 2) + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if self.level > 0 and pos + 2 < length: + match_len = self.find_match(data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] + if extra > 0: + self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) + dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) + dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) + for i in range(match_len): + self.update_hash(data, pos + i) + pos += match_len + else: + lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) + self.update_hash(data, pos) + pos += 1 + lit_tree.encode_symbol(256, c.Addr(self.writer)) + + def encode_block_data(self, data: UINT8PTR, length: t.CSizeT, + lit_tree: zhuff.zhuff_tree | t.CPtr, dist_tree: zhuff.zhuff_tree | t.CPtr): + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if self.level > 0 and pos + 2 < length: + match_len = self.find_match(data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_tree.encode_symbol(len_sym, c.Addr(self.writer)) + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_sym - 257] + if extra > 0: + self.writer.write_bits(match_len - zdef.zdeflate_len_base[len_sym - 257], extra) + dist_sym: t.CInt = zdeflate_dist_to_symbol(best_dist) + dist_tree.encode_symbol(dist_sym, c.Addr(self.writer)) + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + self.writer.write_bits(best_dist - zdef.zdeflate_dist_base[dist_sym], extra) + for j in range(match_len): + self.update_hash(data, pos + j) + pos += match_len + else: + lit_tree.encode_symbol(data[pos], c.Addr(self.writer)) + self.update_hash(data, pos) + pos += 1 + lit_tree.encode_symbol(256, c.Addr(self.writer)) + + + def write_dynamic_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + lit_freqs: list[t.CInt, 288] + dist_freqs: list[t.CInt, 32] + zdeflate_count_freqs(lit_freqs, dist_freqs, self, data, length) + hlit: t.CInt = 286 + while hlit > 257 and lit_freqs[hlit - 1] == 0: hlit -= 1 + hdist: t.CInt = 30 + while hdist > 1 and dist_freqs[hdist - 1] == 0: hdist -= 1 + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_codes(lit_freqs, hlit, zdef.ZDEFLATE_MAX_BITS) + dist_tree.build_codes(dist_freqs, hdist, zdef.ZDEFLATE_MAX_BITS) + all_lengths: list[t.CInt, 288 + 32] + for i in range(hlit): all_lengths[i] = lit_tree.codes[i].bits + for i in range(hdist): all_lengths[hlit + i] = dist_tree.codes[i].bits + total_lengths: t.CInt = hlit + hdist + cl_freqs: list[t.CInt, 19] + zdeflate_count_cl_freqs(all_lengths, total_lengths, cl_freqs) + cl_tree = zhuff.zhuff_tree() + cl_tree.build_codes(cl_freqs, 19, 7) + hclen: int = 19 + while hclen > 4 and cl_tree.codes[zdef.zdeflate_codelen_order[hclen - 1]].bits == 0: hclen -= 1 + self.writer.write_bits(1 if final else 0, 1) + self.writer.write_bits(2, 2) + self.writer.write_bits(hlit - 257, 5) + self.writer.write_bits(hdist - 1, 5) + self.writer.write_bits(hclen - 4, 4) + for j in range(hclen): + self.writer.write_bits(cl_tree.codes[zdef.zdeflate_codelen_order[j]].bits, 3) + zdeflate_write_cl_encoded(all_lengths, total_lengths, c.Addr(self.writer), c.Addr(cl_tree)) + self.encode_block_data(data, length, c.Addr(lit_tree), c.Addr(dist_tree)) + + def compress_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + if self.level == 0: + self.write_stored_block(data, length, final) + elif self.strategy == 4 or length < 128: + self.write_fixed_block(data, length, final) + else: + self.write_dynamic_block(data, length, final) + + def write_stored_block(self, data: UINT8PTR, length: t.CSizeT, final: t.CInt): + self.writer.stored_block(data, length, final) + + def compress(self, data: UINT8PTR, length: t.CSizeT, + out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if self.is_finished: return -2 + if not data or length == 0: + c.Set(c.Deref(out), None) + c.Set(c.Deref(out_len), 0) + return 0 + self.adler = zchecksum.zchecksum_adler32(data, length, self.adler) + memset(self.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(self.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + self.compress_block(data, length, 0) + c.Set(c.Deref(out_len), self.writer.total()) + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, c.Deref(out_len)))) + if not c.Deref(out): return -4 + memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) + return 0 + + def flush(self, mode: t.CInt, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if mode == 4: + if not self.is_finished: + if self.level == 0: + self.writer.write_bits(1, 1) + self.writer.write_bits(0, 2) + self.writer.align() + else: + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + self.writer.write_bits(1, 1) + self.writer.write_bits(1, 2) + lit_tree.encode_symbol(256, c.Addr(self.writer)) + self.is_finished = 1 + if self.wbits >= 0: + self.writer.align() + adler: t.CUInt32T = self.adler + self.writer.buf[self.writer.byte_pos + 0] = (adler >> 24) & 0xFF + self.writer.buf[self.writer.byte_pos + 1] = (adler >> 16) & 0xFF + self.writer.buf[self.writer.byte_pos + 2] = (adler >> 8) & 0xFF + self.writer.buf[self.writer.byte_pos + 3] = (adler >> 0) & 0xFF + self.writer.byte_pos += 4 + elif mode == 2 or mode == 3: + self.writer.write_bits(0, 1) + self.writer.write_bits(0, 2) + self.writer.align() + c.Set(c.Deref(out_len), self.writer.total()) + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, c.Deref(out_len)))) + if not c.Deref(out): return -4 + memcpy(c.Deref(out), self.writer.buf, c.Deref(out_len)) + return 0 + + def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + if not dict: return -2 + use: t.CSizeT = length + if use > zdef.ZDEFLATE_WINDOW_SIZE: + dict += length - zdef.ZDEFLATE_WINDOW_SIZE + use = zdef.ZDEFLATE_WINDOW_SIZE + memcpy(self.window, dict, use) + self.window_size = t.CInt(use) + self.window_pos = t.CInt(use) + self.adler = zchecksum.zchecksum_adler32(dict, length, self.adler) + return 0 + + def copy(self) -> zdeflate_stream | t.CPtr: + z: zdeflate_stream | t.CPtr = zdef.zdef_alloc(self.pool, zdeflate_stream.__sizeof__()) + if not z: return None + memcpy(z, self, zdeflate_stream.__sizeof__()) + z.writer.buf = BYTEPTR(zdef.zdef_alloc(self.pool, self.writer.cap)) + if not z.writer.buf: + zdef.zdef_free(self.pool, z) + return None + memcpy(z.writer.buf, self.writer.buf, self.writer.cap) + z.window = BYTEPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE)) + z.hash_head = INTPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) + z.hash_prev = INTPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) + if not z.window or not z.hash_head or not z.hash_prev: + if z.writer.buf: zdef.zdef_free(self.pool, z.writer.buf) + zdef.zdef_free(self.pool, z) + return None + memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + memcpy(z.hash_head, self.hash_head, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memcpy(z.hash_prev, self.hash_prev, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + return z + + def destroy(self): + if self.writer.buf: zdef.zdef_free(self.pool, self.writer.buf) + if self.window: zdef.zdef_free(self.pool, self.window) + if self.hash_head: zdef.zdef_free(self.pool, self.hash_head) + if self.hash_prev: zdef.zdef_free(self.pool, self.hash_prev) + zdef.zdef_free(self.pool, self) + + + + +def zdeflate_count_freqs(lit_freqs: INTPTR, dist_freqs: INTPTR, + s: zdeflate_stream | t.CPtr, data: UINT8PTR, length: t.CSizeT): + memset(lit_freqs, 0, 288 * int.__sizeof__()) + memset(dist_freqs, 0, 32 * int.__sizeof__()) + pos: t.CSizeT = 0 + while pos < length: + best_dist: t.CInt = 0 + match_len: t.CInt = 0 + if s.level > 0 and pos + 2 < length: + match_len = zdeflate_stream.find_match(s, data, length, pos, c.Addr(best_dist)) + if match_len >= zdef.ZDEFLATE_MIN_MATCH: + len_sym: t.CInt = zdeflate_len_to_symbol(match_len) + lit_freqs[len_sym] += 1 + dist_freqs[zdeflate_dist_to_symbol(best_dist)] += 1 + for i in range(match_len): + zdeflate_stream.update_hash(s, data, pos + i) + pos += match_len + else: + lit_freqs[data[pos]] += 1 + zdeflate_stream.update_hash(s, data, pos) + pos += 1 + lit_freqs[256] = 1 + + + +def zdeflate_hash(p: BYTE | t.CPtr) -> t.CUnsignedInt: + return (t.CUnsignedInt(p[0]) ^ (t.CUnsignedInt(p[1]) << 5) ^ (t.CUnsignedInt(p[2]) << 10)) & zdef.ZDEFLATE_HASH_MASK + + +def zdeflate_len_to_symbol(length: t.CInt) -> t.CInt: + for i in range(29): + if length <= zdef.zdeflate_len_base[i] + (1 << zdef.zdeflate_len_extra_bits[i]) - 1: + return 257 + i + return 285 + +def zdeflate_dist_to_symbol(dist: t.CInt) -> t.CInt: + for i in range(30): + if dist <= zdef.zdeflate_dist_base[i] + (1 << zdef.zdeflate_dist_extra_bits[i]) - 1: + return i + return 29 + +def zdeflate_count_cl_freqs(all_lengths: INTPTR, total: t.CInt, cl_freqs: INTPTR): + memset(cl_freqs, 0, 19 * int.__sizeof__()) + i: t.CInt = 0 + while i < total: + if all_lengths[i] == 0: + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == 0: run += 1 + while run > 0: + if run >= 11: + count: t.CInt = run + if count > 138: count = 138 + cl_freqs[18] += 1 + run -= count + elif run >= 3: + count: t.CInt = run + if count > 10: count = 10 + cl_freqs[17] += 1 + run -= count + else: + cl_freqs[0] += 1 + run -= 1 + while i < total and all_lengths[i] == 0: i += 1 + else: + cl_freqs[all_lengths[i]] += 1 + val: t.CInt = all_lengths[i] + i += 1 + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == val: run += 1 + while run >= 3: + count: t.CInt = run + if count > 6: count = 6 + cl_freqs[16] += 1 + run -= count + i += run + +def zdeflate_write_cl_encoded(all_lengths: INTPTR, total: t.CInt, + w: zdef.zbit_writer | t.CPtr, cl_tree: zhuff.zhuff_tree | t.CPtr): + i: t.CInt = 0 + while i < total: + if all_lengths[i] == 0: + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == 0: run += 1 + while run > 0: + if run >= 11: + count: t.CInt = run + if count > 138: count = 138 + cl_tree.encode_symbol(18, w) + w.write_bits(count - 11, 7) + run -= count + elif run >= 3: + count: t.CInt = run + if count > 10: count = 10 + cl_tree.encode_symbol(17, w) + w.write_bits(count - 3, 3) + run -= count + else: + cl_tree.encode_symbol(0, w) + run -= 1 + while i < total and all_lengths[i] == 0: i += 1 + else: + cl_tree.encode_symbol(all_lengths[i], w) + val: t.CInt = all_lengths[i] + i += 1 + run: t.CInt = 0 + while i + run < total and all_lengths[i + run] == val: run += 1 + while run >= 3: + count: t.CInt = run + if count > 6: count = 6 + cl_tree.encode_symbol(16, w) + w.write_bits(count - 3, 2) + run -= count + i += run + + + +def zdeflate_create(pool: mpool.MPool | t.CPtr, level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: + s: zdeflate_stream | t.CPtr = zdef.zdef_alloc(pool, zdeflate_stream.__sizeof__()) + if not s: return None + memset(s, 0, zdeflate_stream.__sizeof__()) + s.pool = pool + s.writer = zdef.zbit_writer(pool) + s.window = BYTEPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE)) + s.hash_head = INTPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__())) + s.hash_prev = INTPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__())) + if not s.window or not s.hash_head or not s.hash_prev: + s.destroy() + return None + memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + s.level = level + s.wbits = wbits + s.strategy = strategy + s.is_finished = 0 + s.adler = 1 + if wbits > 0: + s.writer.write_zlib_header(wbits, level) + elif wbits == 0: + s.writer.write_zlib_header(15, level) + return s + + +def zdeflate_one_shot(pool: mpool.MPool | t.CPtr, data: UINT8PTR, length: t.CSizeT, + level: t.CInt, wbits: t.CInt, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: + s: zdeflate_stream | t.CPtr = zdeflate_create(pool, level, wbits, 8, 0) + if not s: return None + + memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + memset(s.hash_prev, -1, zdef.ZDEFLATE_WINDOW_SIZE * int.__sizeof__()) + + s.adler = zchecksum.zchecksum_adler32(data, length, 1) + + if length == 0: + s.writer.write_bits(1, 1) + s.writer.write_bits(1, 2) + lit_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + lit_tree.encode_symbol(256, c.Addr(s.writer)) + else: + s.compress_block(data, length, 1) + + s.is_finished = 1 + + if wbits >= 0: + s.writer.align() + adler: t.CUInt32T = s.adler + s.writer.buf[s.writer.byte_pos + 0] = (adler >> 24) & 0xFF + s.writer.buf[s.writer.byte_pos + 1] = (adler >> 16) & 0xFF + s.writer.buf[s.writer.byte_pos + 2] = (adler >> 8) & 0xFF + s.writer.buf[s.writer.byte_pos + 3] = (adler >> 0) & 0xFF + s.writer.byte_pos += 4 + c.Set(c.Deref(out_len), s.writer.total()) + result: UINT8PTR = UINT8PTR(zdef.zdef_alloc(pool, c.Deref(out_len))) + if result: memcpy(result, s.writer.buf, c.Deref(out_len)) + s.destroy() + return result diff --git a/includes/zlib/zhuff.py b/includes/zlib/zhuff.py new file mode 100644 index 0000000..7388665 --- /dev/null +++ b/includes/zlib/zhuff.py @@ -0,0 +1,356 @@ +#include +from stdint import * +import zlib.zdef as zdef +import mpool +import t, c + + +ZHUFF_MAX_CODES: t.CDefine = 288 +ZHUFF_MAX_BITS: t.CDefine = 15 + +class zhuff_code: + code: UINT + bits: t.CInt + +@t.Object +class zhuff_tree: + pool: mpool.MPool | t.CPtr + codes: list[zhuff_code, ZHUFF_MAX_CODES] + count: t.CInt + max_bits: t.CInt + + def __init__(self): + pass + + def build_codes(self, freqs: INTPTR, count: t.CInt, max_bits: t.CInt): + lengths: list[t.CInt, ZHUFF_MAX_CODES] + bl_count: list[t.CInt, ZHUFF_MAX_BITS + 1] + next_code: list[UINT, ZHUFF_MAX_BITS + 1] + self.count = count + self.max_bits = max_bits + self.build_code_lengths(lengths, freqs, count, max_bits) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, max_bits + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + for i in range(count): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def build_fixed_lit_tree(self): + lengths: list[t.CInt, 288] + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + self.get_fixed_lit_lengths(lengths) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(288): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, 9 + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + self.count = 288 + self.max_bits = 9 + for i in range(288): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def build_fixed_dist_tree(self): + lengths: list[t.CInt, 32] + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + self.get_fixed_dist_lengths(lengths) + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(32): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + code: t.CUnsignedInt = 0 + next_code[0] = 0 + for bits in range(1, 5 + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + self.count = 32 + self.max_bits = 5 + for i in range(32): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + def encode_symbol(self, symbol: int, writer: zdef.zbit_writer | t.CPtr): + if symbol < 0 or symbol >= self.count: + return + if self.codes[symbol].bits == 0: + return + writer.write_bits_rev(self.codes[symbol].code, self.codes[symbol].bits) + + + def build_code_lengths(self, lengths: t.CInt | t.CPtr, freqs: t.CInt | t.CPtr, count: t.CInt, max_bits: t.CInt): + bl_count: list[t.CInt, ZHUFF_MAX_BITS + 2] + sort_count: t.CInt = 0 + memset(bl_count, 0, bl_count.__sizeof__()) + memset(lengths, 0, int.__sizeof__() * count) + for i in range(count): + if freqs[i] > 0: + sort_count += 1 + if sort_count == 0: return + if sort_count == 1: + for i in range(count): + if freqs[i] > 0: + lengths[i] = 1 + return + items: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__())) + item_freqs: t.CInt | t.CPtr = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__())) + idx: t.CInt = 0 + for i in range(count): + if freqs[i] > 0: + items[idx] = i + item_freqs[idx] = freqs[i] + idx += 1 + for i in range(sort_count): + key_item: t.CInt = items[i] + key_freq: t.CInt = item_freqs[i] + j: t.CInt = i - 1 + while j >= 0 and item_freqs[j] > key_freq: + items[j + 1] = items[j] + item_freqs[j + 1] = item_freqs[j] + j -= 1 + items[j + 1] = key_item + item_freqs[j + 1] = key_freq + parent: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count * 2) * int.__sizeof__())) + for i in range(sort_count * 2): + parent[i] = -1 + heap: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count + 1) * int.__sizeof__())) + heap_size: t.CInt = 0 + for i in range(sort_count): + heap[heap_size] = i + heap_size += 1 + pos: t.CInt = heap_size - 1 + while pos > 0: + par: t.CInt = (pos - 1) / 2 + if item_freqs[heap[par]] > item_freqs[heap[pos]]: + tmp: t.CInt = heap[par] + heap[par] = heap[pos] + heap[pos] = tmp + pos = par + else: break + combined_freq: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, (sort_count * 2) * int.__sizeof__())) + for i in range(sort_count): + combined_freq[i] = item_freqs[i] + internal: t.CInt = sort_count + while heap_size > 1: + a: t.CInt = heap[0] + heap[0] = heap[heap_size - 1] + heap_size -= 1 + pos: t.CInt = 0 + while True: + left: t.CInt = 2 * pos + 1 + right: t.CInt = 2 * pos + 2 + smallest: t.CInt = pos + if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: + smallest = left + if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: + smallest = right + if smallest != pos: + tmp: t.CInt = heap[pos] + heap[pos] = heap[smallest] + heap[smallest] = tmp + pos = smallest + else: break + b: t.CInt = heap[0] + heap[0] = heap[heap_size - 1] + heap_size -= 1 + pos = 0 + while True: + left: t.CInt = 2 * pos + 1 + right: t.CInt = 2 * pos + 2 + smallest: t.CInt = pos + if left < heap_size and combined_freq[heap[left]] < combined_freq[heap[smallest]]: + smallest = left + if right < heap_size and combined_freq[heap[right]] < combined_freq[heap[smallest]]: + smallest = right + if smallest != pos: + tmp: t.CInt = heap[pos] + heap[pos] = heap[smallest] + heap[smallest] = tmp + pos = smallest + else: break + if internal >= sort_count * 2 - 1: break + combined_freq[internal] = combined_freq[a] + combined_freq[b] + parent[a] = internal + parent[b] = internal + heap[heap_size] = internal + heap_size += 1 + pos = heap_size - 1 + while pos > 0: + par: t.CInt = (pos - 1) / 2 + if combined_freq[heap[par]] > combined_freq[heap[pos]]: + tmp: t.CInt = heap[par] + heap[par] = heap[pos] + heap[pos] = tmp + pos = par + else: break + internal += 1 + for i in range(sort_count): + node: t.CInt = i + length: t.CInt = 0 + while parent[node] >= 0: + length += 1 + node = parent[node] + lengths[items[i]] = length + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + overflow: t.CInt = 0 + for i in range(count): + if lengths[i] > max_bits: + overflow += 1 + bl_count[lengths[i]] -= 1 + lengths[i] = max_bits + bl_count[max_bits] += 1 + while overflow > 0: + bits: t.CInt = max_bits - 1 + while bits > 0 and bl_count[bits] == 0: + bits -= 1 + if bits == 0: break + bl_count[bits] -= 1 + bl_count[bits + 1] += 2 + bl_count[max_bits] -= 1 + overflow -= 2 + sorted_items: INTPTR = INTPTR(zdef.zdef_alloc(self.pool, sort_count * int.__sizeof__())) + si: t.CInt = 0 + for i in range(count): + if freqs[i] > 0: + sorted_items[si] = i + si += 1 + for i in range(si - 1): + for j in range(i + 1, si): + if lengths[sorted_items[i]] < lengths[sorted_items[j]]: + tmp: t.CInt = sorted_items[i] + sorted_items[i] = sorted_items[j] + sorted_items[j] = tmp + sidx: t.CInt = 0 + for bits in range(max_bits, 1, -1): + n: t.CInt = bl_count[bits] + while n > 0 and sidx < si: + lengths[sorted_items[sidx]] = bits + sidx += 1 + n -= 1 + zdef.zdef_free(self.pool, sorted_items) + zdef.zdef_free(self.pool, heap) + zdef.zdef_free(self.pool, parent) + zdef.zdef_free(self.pool, combined_freq) + zdef.zdef_free(self.pool, item_freqs) + zdef.zdef_free(self.pool, items) + + def get_fixed_lit_lengths(self, lengths: INTPTR): + for i in range( 0, 143 + 1): lengths[i] = 8 + for i in range(143 + 1, 255 + 1): lengths[i] = 9 + for i in range(255 + 1, 279 + 1): lengths[i] = 7 + for i in range(279 + 1, 287 + 1): lengths[i] = 8 + + def get_fixed_dist_lengths(self, lengths: INTPTR): + for i in range(32): + lengths[i] = 5 + + def build_tree_from_lengths(self, lengths: INTPTR, count: t.CInt, max_bits: t.CInt): + bl_count: list[t.CInt, 16] + next_code: list[t.CUnsignedInt, 16] + + memset(bl_count, 0, bl_count.__sizeof__()) + for i in range(count): + if lengths[i] > 0: + bl_count[lengths[i]] += 1 + + code: UINT = 0 + next_code[0] = 0 + for bits in range(1, max_bits + 1): + code = (code + bl_count[bits - 1]) << 1 + next_code[bits] = code + + self.count = count + self.max_bits = max_bits + for i in range(count): + self.codes[i].bits = lengths[i] + if lengths[i] > 0: + self.codes[i].code = next_code[lengths[i]] + next_code[lengths[i]] += 1 + else: + self.codes[i].code = 0 + + +class zhuff_decode_node: + children: list[t.CInt, 2] + symbol: t.CInt + + +@t.Object +class zhuff_decode_tree: + pool: mpool.MPool | t.CPtr + nodes: list[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] + node_count: t.CInt + root: t.CInt + + def __init__(self): + pass + + def build_decode_tree(self, ht: zhuff_tree | t.CPtr): + self.node_count = 1 + self.root = 0 + self.nodes[0].children[0] = -1 + self.nodes[0].children[1] = -1 + self.nodes[0].symbol = -1 + for i in range(ht.count): + if ht.codes[i].bits == 0: continue + node: int = 0 + for bit in range(ht.codes[i].bits - 1, -1, -1): + dir: t.CInt = (ht.codes[i].code >> bit) & 1 + if bit > 0: + # Internal node: traverse or create + if self.nodes[node].children[dir] == -1: + new_node: int = self.node_count + self.node_count += 1 + self.nodes[new_node].children[0] = -1 + self.nodes[new_node].children[1] = -1 + self.nodes[new_node].symbol = -1 + self.nodes[node].children[dir] = new_node + node = self.nodes[node].children[dir] + else: + # Leaf: bit 0 - set symbol on the child + if self.nodes[node].children[dir] == -1: + leaf: int = self.node_count + self.node_count += 1 + self.nodes[leaf].children[0] = -1 + self.nodes[leaf].children[1] = -1 + self.nodes[leaf].symbol = i + self.nodes[node].children[dir] = leaf + else: + self.nodes[self.nodes[node].children[dir]].symbol = i + + def decode_symbol(self, reader: zdef.zbit_reader | t.CPtr) -> t.CInt: + node: int = self.root + while self.nodes[node].symbol == -1: + bit: t.CUnsignedInt + if reader.read_bits(1, c.Addr(bit)) != 0: return -1 + dir: t.CInt = t.CInt(bit) + if self.nodes[node].children[dir] == -1: return -1 + node = self.nodes[node].children[dir] + return self.nodes[node].symbol diff --git a/includes/zlib/zinflate.py b/includes/zlib/zinflate.py new file mode 100644 index 0000000..b404189 --- /dev/null +++ b/includes/zlib/zinflate.py @@ -0,0 +1,456 @@ +from stdint import * +import zlib.zchecksum as zchecksum +import zlib.zdef as zdef +import zlib.zhuff as zhuff +import string +import mpool +import t, c + + +@t.Object +class zinflate_stream: + pool: mpool.MPool | t.CPtr + reader: zdef.zbit_reader + + window: BYTEPTR + window_pos: t.CInt + window_size: t.CInt + + wbits: t.CInt + is_finished: t.CInt + is_initialized: t.CInt + + header_parsed: t.CInt + is_gzip: t.CInt + + adler: t.CUInt32T + crc: t.CUInt32T + + output: BYTEPTR + output_len: t.CSizeT + output_cap: t.CSizeT + + input_data: t.CConst | BYTEPTR + input_len: t.CSizeT + input_pos: t.CSizeT + + max_length: t.CSizeT + + def __init__(self): + pass + + def output_byte(self, byte: BYTE): + if self.max_length > 0 and self.output_len >= self.max_length: return + + if self.output_len >= self.output_cap: + new_cap: t.CSizeT = self.output_cap * 2 + if new_cap < 256: new_cap = 256 + new_buf: BYTEPTR = BYTEPTR(zdef.zdef_alloc(self.pool, new_cap)) + if not new_buf: return + memcpy(new_buf, self.output, self.output_len) + zdef.zdef_free(self.pool, self.output) + self.output = new_buf + self.output_cap = new_cap + self.output[self.output_len] = byte + self.output_len += 1 + self.window[self.window_pos & (zdef.ZDEFLATE_WINDOW_SIZE - 1)] = byte + self.window_pos += 1 + + + def parse_header(self) -> t.CInt: + if self.header_parsed: return 0 + if self.wbits < 0: + self.header_parsed = 1 + self.is_gzip = 0 + return 0 + if self.input_pos + 2 > self.input_len: return -3 + b0: BYTE = self.input_data[self.input_pos] + b1: BYTE = self.input_data[self.input_pos + 1] + if b0 == 0x1F and b1 == 0x8B: + self.is_gzip = 1 + if self.input_pos + 10 > self.input_len: return -3 + self.input_pos += 10 + flg: BYTE = self.input_data[self.input_pos - 6] + if flg & 0x04: + if self.input_pos + 2 > self.input_len: return -3 + xlen: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) + self.input_pos += 2 + xlen + if flg & 0x08: + while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 + self.input_pos += 1 + if flg & 0x10: + while self.input_pos < self.input_len and self.input_data[self.input_pos] != 0: self.input_pos += 1 + self.input_pos += 1 + if flg & 0x02: + self.input_pos += 2 + if self.input_pos > self.input_len: return -3 + else: + self.is_gzip = 0 + if (b0 * 256 + b1) % 31 != 0: return -3 + cm: t.CInt = b0 & 0x0F + if cm != 8: return -3 + self.input_pos += 2 + self.header_parsed = 1 + return 0 + + + def read_bits_from_input(self, nbits: t.CInt, out: UINTPTR) -> t.CInt: + val: UINT = 0 + for i in range(nbits): + if self.input_pos >= self.input_len: return -3 + if self.input_data[self.input_pos] & (UINT(1) << (self.reader.bit_pos)): + val |= (UINT(1) << i) + self.reader.bit_pos += 1 + if self.reader.bit_pos == 8: + self.reader.bit_pos = 0 + self.input_pos += 1 + c.Set(c.Deref(out), val) + return 0 + + + def read_huffman(self, dt: zhuff.zhuff_decode_tree | t.CPtr) -> t.CInt: + node: int = dt.root + while dt.nodes[node].symbol == -1: + bit: UINT + if self.read_bits_from_input(1, c.Addr(bit)) != 0: return -1 + dir: int = t.CInt(bit) + if dt.nodes[node].children[dir] == -1: return -3 + node = dt.nodes[node].children[dir] + return dt.nodes[node].symbol + + def inflate_block_stored(self) -> t.CInt: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 4 > self.input_len: return -3 + length: UINT = self.input_data[self.input_pos] | (self.input_data[self.input_pos + 1] << 8) + nlen: UINT = self.input_data[self.input_pos + 2] | (self.input_data[self.input_pos + 3] << 8) + self.input_pos += 4 + if (length ^ nlen) != 0xFFFF: return -3 + if self.input_pos + length > self.input_len: return -3 + i: t.CUnsignedInt + for i in range(length): + self.output_byte(self.input_data[self.input_pos]) + self.input_pos += 1 + return 0 + + + def inflate_block_fixed(self) -> t.CInt: + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + lit_tree.build_fixed_lit_tree() + dist_tree.build_fixed_dist_tree() + + lit_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(self.pool, zhuff.zhuff_decode_tree.__sizeof__()) + dist_dt: zhuff.zhuff_decode_tree | t.CPtr = zdef.zdef_alloc(self.pool, zhuff.zhuff_decode_tree.__sizeof__()) + if not lit_dt or not dist_dt: + if lit_dt: zdef.zdef_free(self.pool, lit_dt) + if dist_dt: zdef.zdef_free(self.pool, dist_dt) + return -4 + memset(lit_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + memset(dist_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + lit_dt.build_decode_tree(c.Addr(lit_tree)) + dist_dt.build_decode_tree(c.Addr(dist_tree)) + + result: t.CInt = 0 + while True: + if self.max_length > 0 and self.output_len >= self.max_length: break + + sym: t.CInt = self.read_huffman(lit_dt) + if sym < 0: + result = -3 + break + if sym == 256: break + if sym < 256: + self.output_byte(BYTE(sym)) + else: + len_idx: t.CInt = sym - 257 + if len_idx < 0 or len_idx >= 29: + result = -3 + break + length: t.CInt = zdef.zdeflate_len_base[len_idx] + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: + result = -3 + break + length += extra_val + + dist_sym: t.CInt = self.read_huffman(dist_dt) + if dist_sym < 0 or dist_sym >= 30: + result = -3 + break + dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: + result = -3 + break + dist += extra_val + + for i in range(length): + if self.max_length > 0 and self.output_len >= self.max_length: break + src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) + byte: BYTE = self.window[src_pos] + self.output_byte(byte) + + zdef.zdef_free(self.pool, lit_dt) + zdef.zdef_free(self.pool, dist_dt) + return result + + + def inflate_block_dynamic(self) -> t.CInt: + hlit_val: UINT + hdist_val: UINT + hclen_val: UINT + if self.read_bits_from_input(5, c.Addr(hlit_val)) != 0: return -3 + if self.read_bits_from_input(5, c.Addr(hdist_val)) != 0: return -3 + if self.read_bits_from_input(4, c.Addr(hclen_val)) != 0: return -3 + + hlit: t.CInt = t.CInt(hlit_val) + 257 + hdist: t.CInt = t.CInt(hdist_val) + 1 + hclen: t.CInt = t.CInt(hclen_val) + 4 + + cl_lengths: list[t.CInt, 19] + memset(cl_lengths, 0, cl_lengths.__sizeof__()) + for i in range(hclen): + len_val: UINT + if self.read_bits_from_input(3, c.Addr(len_val)) != 0: return -3 + cl_lengths[zdef.zdeflate_codelen_order[i]] = t.CInt(len_val) + + cl_tree = zhuff.zhuff_tree() + cl_tree.build_tree_from_lengths(cl_lengths, 19, 7) + + cl_dt = zhuff.zhuff_decode_tree() + cl_dt.build_decode_tree(c.Addr(cl_tree)) + + total: t.CInt = hlit + hdist + all_lengths: t.CInt | t.CPtr = zdef.zdef_alloc(self.pool, total * int.__sizeof__()) + if not all_lengths: return -4 + + idx: t.CInt = 0 + while idx < total: + sym: t.CInt = self.read_huffman(c.Addr(cl_dt)) + if sym < 0 or sym > 18: + zdef.zdef_free(self.pool, all_lengths) + return -3 + if sym < 16: + all_lengths[idx] = sym + idx += 1 + elif sym == 16: + rep: UINT + if self.read_bits_from_input(2, c.Addr(rep)) != 0: + zdef.zdef_free(self.pool, all_lengths) + return -3 + rep += 3 + if idx == 0 or idx + rep > total: + zdef.zdef_free(self.pool, all_lengths) + return -3 + prev: t.CInt = all_lengths[idx - 1] + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = prev + idx += 1 + elif sym == 17: + rep: t.CUnsignedInt + if self.read_bits_from_input(3, c.Addr(rep)) != 0: + zdef.zdef_free(self.pool, all_lengths) + return -3 + rep += 3 + if idx + rep > total: + zdef.zdef_free(self.pool, all_lengths) + return -3 + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = 0 + idx += 1 + else: + rep: t.CUnsignedInt + if self.read_bits_from_input(7, c.Addr(rep)) != 0: + zdef.zdef_free(self.pool, all_lengths) + return -3 + rep += 11 + if idx + rep > total: + zdef.zdef_free(self.pool, all_lengths) + return -3 + i: t.CUnsignedInt + for i in range(rep): + all_lengths[idx] = 0 + idx += 1 + + lit_tree = zhuff.zhuff_tree() + dist_tree = zhuff.zhuff_tree() + + lit_lengths: list[t.CInt, 288] + memset(lit_lengths, 0, lit_lengths.__sizeof__()) + for i in range(hlit): + lit_lengths[i] = all_lengths[i] + lit_tree.build_tree_from_lengths(lit_lengths, hlit, zdef.ZDEFLATE_MAX_BITS) + + dist_lengths: list[t.CInt, 32] + memset(dist_lengths, 0, dist_lengths.__sizeof__()) + for i in range(hdist): + dist_lengths[i] = all_lengths[hlit + i] + dist_tree.build_tree_from_lengths(dist_lengths, hdist, zdef.ZDEFLATE_MAX_BITS) + + zdef.zdef_free(self.pool, all_lengths) + + lit_dt = zhuff.zhuff_decode_tree() + dist_dt = zhuff.zhuff_decode_tree() + lit_dt.build_decode_tree(c.Addr(lit_tree)) + dist_dt.build_decode_tree(c.Addr(dist_tree)) + + while True: + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + sym: t.CInt = self.read_huffman(c.Addr(lit_dt)) + if sym < 0: return -3 + if sym == 256: return 0 + if sym < 256: + self.output_byte(BYTE(sym)) + else: + len_idx: t.CInt = sym - 257 + if len_idx < 0 or len_idx >= 29: return -3 + length: t.CInt = zdef.zdeflate_len_base[len_idx] + extra: t.CInt = zdef.zdeflate_len_extra_bits[len_idx] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 + length += extra_val + dist_sym: t.CInt = self.read_huffman(c.Addr(dist_dt)) + if dist_sym < 0 or dist_sym >= 30: return -3 + dist: t.CInt = zdef.zdeflate_dist_base[dist_sym] + extra = zdef.zdeflate_dist_extra_bits[dist_sym] + if extra > 0: + extra_val: UINT + if self.read_bits_from_input(extra, c.Addr(extra_val)) != 0: return -3 + dist += extra_val + for i in range(length): + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + src_pos: t.CInt = (self.window_pos - dist) & (zdef.ZDEFLATE_WINDOW_SIZE - 1) + byte: BYTE = self.window[src_pos] + self.output_byte(byte) + + def inflate_stream(self) -> t.CInt: + err: t.CInt = self.parse_header() + if err != 0: return err + while not self.is_finished: + bfinal_val: UINT + btype_val: UINT + if self.read_bits_from_input(1, c.Addr(bfinal_val)) != 0: return -3 + if self.read_bits_from_input(2, c.Addr(btype_val)) != 0: return -3 + bfinal: t.CInt = t.CInt(bfinal_val) + btype: t.CInt = t.CInt(btype_val) + if btype == 0: + err = self.inflate_block_stored() + elif btype == 1: + err = self.inflate_block_fixed() + elif btype == 2: + err = self.inflate_block_dynamic() + else: + return -3 + if err != 0: return err + if bfinal: self.is_finished = 1 + if self.max_length > 0 and self.output_len >= self.max_length: return 0 + if self.is_gzip: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 8 <= self.input_len: + self.crc = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 0) | + (t.CUInt32T(self.input_data[self.input_pos + 1]) << 8) | + (t.CUInt32T(self.input_data[self.input_pos + 2]) << 16) | + (t.CUInt32T(self.input_data[self.input_pos + 3]) << 24)) + self.input_pos += 8 + elif self.wbits >= 0: + if self.reader.bit_pos != 0: + self.reader.bit_pos = 0 + self.input_pos += 1 + if self.input_pos + 4 <= self.input_len: + self.adler = ((t.CUInt32T(self.input_data[self.input_pos + 0]) << 24) | + (t.CUInt32T(self.input_data[self.input_pos + 1]) << 16) | + (t.CUInt32T(self.input_data[self.input_pos + 2]) << 8) | + (t.CUInt32T(self.input_data[self.input_pos + 3]) << 0)) + self.input_pos += 4 + return 0 + + def decompress(self, data: UINT8PTR, length: t.CSizeT, + max_length: t.CSizeT, out: t.CUInt8T | t.CPtr[t.CPtr], out_len: t.CSizeT | t.CPtr) -> t.CInt: + if not self.is_initialized: return -2 + self.input_data = data + self.input_len = length + self.input_pos = 0 + self.reader.bit_pos = 0 + self.output_len = 0 + self.max_length = max_length + err: t.CInt = self.inflate_stream() + if err != 0: return err + c.Set(c.Deref(out_len), self.output_len) + if self.output_len == 0: + c.Set(c.Deref(out), UINT8PTR(zdef.zdef_alloc(self.pool, 1))) + else: + dst: UINT8PTR = UINT8PTR(zdef.zdef_alloc(self.pool, self.output_len)) + c.Set(c.Deref(out), dst) + if dst: + memcpy(dst, self.output, self.output_len) + return 0 + + def set_dictionary(self, dict: UINT8PTR, length: t.CSizeT) -> t.CInt: + if not dict: return -2 + use: t.CSizeT = length + if use > zdef.ZDEFLATE_WINDOW_SIZE: + dict += length - zdef.ZDEFLATE_WINDOW_SIZE + use = zdef.ZDEFLATE_WINDOW_SIZE + memcpy(self.window, dict, use) + self.window_pos = t.CInt(use) + return 0 + + def copy(self) -> zinflate_stream | t.CPtr: + z: zinflate_stream | t.CPtr = zdef.zdef_alloc(self.pool, zinflate_stream.__sizeof__()) + if not z: return None + memcpy(z, self, zinflate_stream.__sizeof__()) + z.window = BYTEPTR(zdef.zdef_alloc(self.pool, zdef.ZDEFLATE_WINDOW_SIZE)) + z.output = BYTEPTR(zdef.zdef_alloc(self.pool, self.output_cap)) + if not z.window or not z.output: + zinflate_stream.destroy(z) + return None + memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + memcpy(z.output, self.output, self.output_cap) + return z + + def destroy(self): + if not self: return + if self.window: zdef.zdef_free(self.pool, self.window) + if self.output: zdef.zdef_free(self.pool, self.output) + zdef.zdef_free(self.pool, self) + + +def zinflate_one_shot(pool: mpool.MPool | t.CPtr, data: UINT8PTR, length: t.CSizeT, + wbits: t.CInt, bufsize: t.CSizeT, out_len: t.CSizeT | t.CPtr) -> t.CUInt8T | t.CPtr: + s: zinflate_stream | t.CPtr = zinflate_create(pool, wbits) + if not s: return None + out: t.CUInt8T | t.CPtr = None + err: t.CInt = s.decompress(data, length, 0, c.Addr(out), out_len) + s.destroy() + if err != 0: return None + return out + + +def zinflate_create(pool: mpool.MPool | t.CPtr, wbits: t.CInt) -> zinflate_stream | t.CPtr: + s: zinflate_stream | t.CPtr = zdef.zdef_alloc(pool, zinflate_stream.__sizeof__()) + if not s: return None + memset(s, 0, zinflate_stream.__sizeof__()) + s.pool = pool + s.wbits = wbits + s.is_initialized = 1 + s.adler = 1 + s.window = BYTEPTR(zdef.zdef_alloc(pool, zdef.ZDEFLATE_WINDOW_SIZE)) + s.output = BYTEPTR(zdef.zdef_alloc(pool, 256)) + s.output_cap = 256 + s.output_len = 0 + s.max_length = 0 + if not s.window or not s.output: + s.destroy() + return None + return s diff --git a/lib/constants/config.py b/lib/constants/config.py new file mode 100644 index 0000000..beac484 --- /dev/null +++ b/lib/constants/config.py @@ -0,0 +1,42 @@ +# 常量定义 + +DEFAULT_INPUT_FILE = 'test.py' +DEFAULT_OUTPUT_FILE = 'test.ll' + +SLICE_THRESHOLD = 50 +SLICE_LEVEL_DEFAULT = 3 +SLICE_LEVELS = { + 0: 'no_optimize', + 1: 'conservative', + 2: 'moderate', + 3: 'aggressive', + 's': 'size', +} + +DEFAULT_COMPILE_COMMAND = 'gcc' +DEFAULT_COMPILE_FLAGS = '' + +DEFAULT_METADATA = { + 'PROJECT_NAME': 'TransPyC Project', + 'AUTHOR': 'TransPyC Team', + 'VERSION': '1.0.0', + 'DESCRIPTION': 'Auto-generated LLVM IR file', + 'COPYRIGHT_YEAR': '2026', + 'COPYRIGHT_HOLDER': 'Galactic Vorpal Software Development Studio (e.g. GVSDS Inc.)' +} + +ERROR_MESSAGES = { + 'MISSING_ARGS': 'Missing required arguments -f and/or -o', + 'UNKNOWN_ARG': 'Unknown argument', + 'UNSUPPORTED_TYPE': 'Unsupported file type', + 'FAILED_PARSE': 'Failed to parse file', + 'COMPILE_FAILED': 'Compilation or execution failed' +} + +HELP_MESSAGE = ''' +Usage: python TransPyC.py -f InputFile -o OutputFile [-wh header_files] [-debug DebugFile] + [-cc compile_command] [-cflags CompileFlags] [-run] [-args RunArgs] [-h HelperFiles] + -h: Specify helper files (C or Python) to help identify structs, functions, variables, and ptrs +''' + +mode = "strict" diff --git a/lib/core/AsmIntelToAtt.py b/lib/core/AsmIntelToAtt.py new file mode 100644 index 0000000..7a15058 --- /dev/null +++ b/lib/core/AsmIntelToAtt.py @@ -0,0 +1,534 @@ +from __future__ import annotations +import re + + +_X86_REGS = { + 'al', 'ah', 'ax', 'eax', 'rax', + 'bl', 'bh', 'bx', 'ebx', 'rbx', + 'cl', 'ch', 'cx', 'ecx', 'rcx', + 'dl', 'dh', 'dx', 'edx', 'rdx', + 'sil', 'si', 'esi', 'rsi', + 'dil', 'di', 'edi', 'rdi', + 'bpl', 'bp', 'ebp', 'rbp', + 'spl', 'sp', 'esp', 'rsp', + 'rip', 'eip', 'ip', + 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', + 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b', + 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', + 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', +} + +_CR_REGS = {'cr0', 'cr2', 'cr3', 'cr4', 'cr8'} +_SEG_REGS = {'ds', 'es', 'fs', 'gs', 'ss', 'cs'} + +_SIZE_MAP = { + 'al': 'b', 'ah': 'b', 'ax': 'w', 'eax': 'l', 'rax': 'q', + 'bl': 'b', 'bh': 'b', 'bx': 'w', 'ebx': 'l', 'rbx': 'q', + 'cl': 'b', 'ch': 'b', 'cx': 'w', 'ecx': 'l', 'rcx': 'q', + 'dl': 'b', 'dh': 'b', 'dx': 'w', 'edx': 'l', 'rdx': 'q', + 'si': 'w', 'esi': 'l', 'rsi': 'q', + 'di': 'w', 'edi': 'l', 'rdi': 'q', + 'bp': 'w', 'ebp': 'l', 'rbp': 'q', + 'sp': 'w', 'esp': 'l', 'rsp': 'q', + 'ip': 'w', 'eip': 'l', 'rip': 'q', + 'r8b': 'b', 'r8w': 'w', 'r8d': 'l', 'r8': 'q', + 'r9b': 'b', 'r9w': 'w', 'r9d': 'l', 'r9': 'q', + 'r10b': 'b', 'r10w': 'w', 'r10d': 'l', 'r10': 'q', + 'r11b': 'b', 'r11w': 'w', 'r11d': 'l', 'r11': 'q', + 'r12b': 'b', 'r12w': 'w', 'r12d': 'l', 'r12': 'q', + 'r13b': 'b', 'r13w': 'w', 'r13d': 'l', 'r13': 'q', + 'r14b': 'b', 'r14w': 'w', 'r14d': 'l', 'r14': 'q', + 'r15b': 'b', 'r15w': 'w', 'r15d': 'l', 'r15': 'q', +} + +_SIZE_PREFIX = { + 'byte': 'b', + 'word': 'w', + 'dword': 'l', + 'qword': 'q', +} + +_TWO_OPS_SWAP = frozenset({ + 'mov', 'lea', 'add', 'sub', 'adc', 'sbb', + 'and', 'or', 'xor', 'cmp', 'test', + 'shl', 'shr', 'sal', 'sar', 'rol', 'ror', 'rcl', 'rcr', + 'bt', 'btc', 'btr', 'bts', + 'xadd', 'xchg', 'cmpxchg', +}) + +_NO_SUFFIX_OPS = frozenset({ + 'call', 'jmp', 'ret', 'push', 'pop', + 'cli', 'sti', 'hlt', 'nop', 'cld', 'std', 'cpuid', 'rdmsr', 'wrmsr', + 'sfence', 'mfence', 'lfence', 'fninit', 'pause', 'ud2', + 'invlpg', 'swapgs', 'syscall', 'sysret', 'iretq', 'int', + 'fxsave', 'fxrstor', 'stmxcsr', 'ldmxcsr', + 'bswap', 'cbw', 'cwde', 'cdqe', 'cwd', 'cdq', 'cqo', + 'sete', 'setne', 'seta', 'setae', 'setb', 'setbe', + 'setg', 'setge', 'setl', 'setle', 'sets', 'setns', 'setc', 'setnc', + 'seto', 'setno', 'setp', 'setnp', + 'cmovo', 'cmovno', 'cmovb', 'cmovae', 'cmove', 'cmovne', + 'cmova', 'cmovbe', 'cmovg', 'cmovge', 'cmovl', 'cmovle', + 'cmovs', 'cmovns', 'cmovc', 'cmovnc', 'cmovp', 'cmovnp', +}) + +_BRANCH_OPS = frozenset({ + 'jz', 'jnz', 'je', 'jne', 'jg', 'jl', 'jge', 'jle', + 'ja', 'jb', 'jae', 'jbe', 'jo', 'jno', 'js', 'jns', + 'jc', 'jnc', 'jp', 'jnp', 'loop', 'jcxz', 'jecxz', 'jrcxz', +}) + +_STRING_OPS = frozenset({ + 'lodsb', 'lodsw', 'lodsd', 'lodsq', + 'stosb', 'stosw', 'stosd', 'stosq', + 'movsb', 'movsw', 'movsd', 'movsq', + 'cmpsb', 'cmpsw', 'cmpsd', 'cmpsq', + 'scasb', 'scasw', 'scasd', 'scasq', + 'insb', 'insw', 'insd', 'outsb', 'outsw', 'outsd', +}) + +_STRING_OPS_ATT_MAP = { + 'lodsd': 'lodsl', 'stosd': 'stosl', 'movsd': 'movsl', + 'cmpsd': 'cmpsl', 'scasd': 'scasl', 'insd': 'insl', + 'outsd': 'outsl', +} + +_PREFIX_OPS = frozenset({ + 'rep', 'repe', 'repz', 'repne', 'repnz', 'lock', +}) + + +def _is_operand_ref(token: str) -> bool: + return bool(re.match(r'^\$\d+$', token)) + + +def _parse_operands(operands_str: str): + result = [] + current = '' + depth = 0 + i = 0 + while i < len(operands_str): + ch = operands_str[i] + if ch == '[' or ch == '(': + depth += 1 + current += ch + elif ch == ']' or ch == ')': + depth -= 1 + current += ch + elif ch == ',' and depth == 0: + result.append(current.strip()) + current = '' + else: + current += ch + i += 1 + if current.strip(): + result.append(current.strip()) + return result + + +def _tokenize_mem(mem: str) -> list: + result = [] + current = '' + i = 0 + while i < len(mem): + ch = mem[i] + if ch == '(': + if current.strip(): + result.append(current.strip()) + current = '' + result.append('(') + i += 1 + elif ch == ')': + if current.strip(): + result.append(current.strip()) + current = '' + result.append(')') + i += 1 + elif ch in '+-': + if current.strip(): + result.append(current.strip()) + current = '' + result.append(ch) + i += 1 + elif ch in ' \t': + if current.strip(): + result.append(current.strip()) + current = '' + i += 1 + else: + current += ch + i += 1 + if current.strip(): + result.append(current.strip()) + return result + + +def _convert_mem_token(token: str) -> str: + if token in ('(', ')', '+', '-'): + return token + if _is_operand_ref(token): + return token + if token.lower() in _X86_REGS: + return '%' + token + try: + int(token, 0) + return token + except ValueError: + pass + return token + + +def _convert_mem_operand(op: str) -> str: + op = op.strip().replace('[', '(').replace(']', ')') + + m = re.match(r'^\(([^)]+)\)$', op) + if m: + inner = m.group(1).strip() + return _convert_mem_inner(inner) + + return _convert_mem_inner(op.strip('()')) + + +def _convert_mem_inner(inner: str) -> str: + tokens = [] + current = '' + i = 0 + while i < len(inner): + ch = inner[i] + if ch in ' \t': + if current.strip(): + tokens.append(current.strip()) + current = '' + i += 1 + elif ch in '+-': + if current.strip(): + tokens.append(current.strip()) + current = '' + tokens.append(ch) + i += 1 + else: + current += ch + i += 1 + if current.strip(): + tokens.append(current.strip()) + + base = '' + index = '' + scale = '' + disp = '' + op = '+' + + for tok in tokens: + if tok == '+': + op = '+' + continue + elif tok == '-': + op = '-' + continue + + is_reg = tok.lower() in _X86_REGS or tok.lower() in _CR_REGS + is_operand = _is_operand_ref(tok) + + if is_reg or is_operand: + if not base: + base = _convert_mem_token(tok) + elif not index: + index = _convert_mem_token(tok) + else: + disp += ('+' if op == '+' else '-') + tok + else: + try: + int(tok, 0) + if op == '-': + disp += '-' + tok + else: + disp += tok + except ValueError: + if op == '-': + disp += '-' + tok + else: + if not base: + base = tok + else: + disp += tok + + result = '' + if disp: + result = disp + result += '(' + if base: + result += base + if index: + result += ',' + index + if scale: + result += ',' + scale + result += ')' + return result + + +def _att_convert_operand(op: str) -> str: + op = op.strip() + if not op: + return op + + m = re.match(r'^(byte|word|dword|qword)\s+ptr\s+(.+)$', op, re.IGNORECASE) + if m: + op = m.group(2).strip() + + if '[' in op or ']' in op: + return _convert_mem_operand(op) + + if _is_operand_ref(op): + return op + + if op.lower() in _CR_REGS: + return '%' + op + if op.lower() in _SEG_REGS: + return '%' + op + if op.lower() in _X86_REGS: + return '%' + op + + try: + int(op, 0) + return '$$' + op + except ValueError: + pass + + if op.startswith('~'): + inner = op[1:] + try: + int(inner, 0) + return '$$' + op + except ValueError: + pass + + return op + + +def _extract_size(op: str) -> str: + m = re.match(r'^(byte|word|dword|qword)\s+ptr\s+', op, re.IGNORECASE) + if m: + return _SIZE_PREFIX.get(m.group(1).lower(), '') + + cleaned = op.lower().replace('[', '(').replace(']', ')').replace('$', '') + for reg in _CR_REGS: + if re.search(r'(? str: + for o in operands: + s = _extract_size(o) + if s: + return s + if op in ('imul',): + return 'l' + if op in ('shl', 'shr', 'sal', 'sar', 'rol', 'ror', 'rcl', 'rcr'): + return 'q' + return 'q' + + +def _convert_instruction(op: str, operands: list) -> str: + op_lower = op.lower() + + if op_lower in _PREFIX_OPS and len(operands) == 0: + return op_lower + + if op_lower in _PREFIX_OPS and len(operands) >= 1: + att_ops = [] + for o in operands: + o_lower = o.strip().lower() + if o_lower in _STRING_OPS_ATT_MAP: + att_ops.append(_STRING_OPS_ATT_MAP[o_lower]) + elif o_lower in _NO_SUFFIX_OPS or o_lower in _STRING_OPS: + att_ops.append(o) + else: + att_ops.append(_att_convert_operand(o)) + return f"{op_lower} {' '.join(att_ops)}" + + if op_lower in ('push', 'pop') and len(operands) >= 1: + p = _att_convert_operand(operands[0]) + return f"{op_lower} {p}" + + if op_lower == 'in' and len(operands) >= 2: + dst, port = operands[0], operands[1] + suffix = _size_suffix_for_all([dst], op_lower) or 'b' + return f"in{suffix} {_att_convert_operand(port)}, {_att_convert_operand(dst)}" + + if op_lower == 'out' and len(operands) >= 2: + port, src = operands[0], operands[1] + suffix = _size_suffix_for_all([src], op_lower) or 'b' + return f"out{suffix} {_att_convert_operand(src)}, {_att_convert_operand(port)}" + + if op_lower in ('lidt', 'lgdt', 'sidt', 'sgdt') and len(operands) >= 1: + return f"{op_lower}q {_att_convert_operand(operands[0])}" + + if op_lower == 'call' and len(operands) >= 1: + target = operands[0].strip() + att_target = _att_convert_operand(target) + if _is_operand_ref(target): + return f"call *{att_target}" + if target.startswith('[') or target.startswith('('): + return f"call *{att_target}" + if target.lower() in _X86_REGS or target.lower() in _CR_REGS: + return f"call *{att_target}" + return f"call {att_target}" + + if op_lower == 'jmp' and len(operands) >= 1: + target = operands[0].strip() + att_target = _att_convert_operand(target) + if _is_operand_ref(target): + return f"jmp *{att_target}" + if target.startswith('[') or target.startswith('('): + return f"jmp *{att_target}" + if target.lower() in _X86_REGS or target.lower() in _CR_REGS: + return f"jmp *{att_target}" + return f"jmp {att_target}" + + if op_lower in _BRANCH_OPS and len(operands) >= 1: + target = operands[0].strip() + att_target = _att_convert_operand(target) + return f"{op_lower} {att_target}" + + if op_lower == 'imul' and len(operands) >= 3: + src1, src2, imm = operands[0], operands[1], operands[2] + suffix = _size_suffix_for_all([src1, src2], op_lower) + return f"imul{suffix} {_att_convert_operand(imm)}, {_att_convert_operand(src1)}, {_att_convert_operand(src2)}" + + if op_lower == 'movzx' and len(operands) >= 2: + dst, src = operands[0], operands[1] + src_size = _extract_size(src) or 'b' + dst_size = _extract_size(dst) or 'l' + return f"movz{src_size}{dst_size} {_att_convert_operand(src)}, {_att_convert_operand(dst)}" + + if op_lower == 'movsxd' and len(operands) >= 2: + dst, src = operands[0], operands[1] + src_size = _extract_size(src) or 'l' + dst_size = _extract_size(dst) or 'q' + return f"movs{src_size}{dst_size} {_att_convert_operand(src)}, {_att_convert_operand(dst)}" + + if op_lower in _TWO_OPS_SWAP and len(operands) >= 2: + src, dst = operands[0], operands[1] + suffix = _size_suffix_for_all([src, dst], op_lower) + return f"{op_lower}{suffix} {_att_convert_operand(dst)}, {_att_convert_operand(src)}" + + if op_lower in _NO_SUFFIX_OPS or op_lower in _STRING_OPS or len(operands) == 0: + att_op = _STRING_OPS_ATT_MAP.get(op_lower, op_lower) + parts = [att_op] + [_att_convert_operand(o) for o in operands] + return ' '.join(parts) + + if len(operands) >= 3: + suffix = _size_suffix_for_all(operands, op_lower) + converted_ops = [_att_convert_operand(o) for o in operands] + return f"{op_lower}{suffix} {', '.join(converted_ops[1:])}, {converted_ops[0]}" + + if len(operands) >= 2: + src, dst = operands[0], operands[1] + suffix = _size_suffix_for_all([src, dst], op_lower) + return f"{op_lower}{suffix} {_att_convert_operand(dst)}, {_att_convert_operand(src)}" + + if len(operands) == 1: + suffix = _size_suffix_for_all(operands, op_lower) + return f"{op_lower}{suffix} {_att_convert_operand(operands[0])}" + + return op_lower + + +def _find_comment(s: str) -> int: + in_string = False + i = 0 + while i < len(s): + ch = s[i] + if ch == '"': + in_string = not in_string + elif ch == ';' and not in_string: + return i + i += 1 + return -1 + + +def _convert_single(stmt: str) -> str: + stmt = re.sub(r'%(\d+)', r'$\1', stmt) + + if stmt.strip().startswith('.'): + return stmt + + space_idx = -1 + for i, ch in enumerate(stmt): + if ch in ' \t': + space_idx = i + break + + if space_idx < 0: + op = stmt + operands_str = '' + else: + op = stmt[:space_idx] + operands_str = stmt[space_idx:] + + op = op.strip() + operands_str = operands_str.strip() + + if not operands_str: + if op.lower() in _X86_REGS: + return '%' + op + return op + + operands = _parse_operands(operands_str) + return _convert_instruction(op, operands) + + +def convert(template: str) -> str: + lines = template.split('\n') + result = [] + for line in lines: + stripped = line.strip() + if not stripped: + result.append('') + continue + + stripped = stripped.replace('\t', ' ') + + statements = stripped.split(';') + converted_stmts = [] + for stmt in statements: + stmt = stmt.strip() + if not stmt: + continue + + comment_pos = _find_comment(stmt) + if comment_pos >= 0: + code_part = stmt[:comment_pos].strip() + comment_part = stmt[comment_pos:].strip() + else: + code_part = stmt + comment_part = '' + + if code_part.startswith('.'): + converted_stmts.append(code_part + (f' ; {comment_part}' if comment_part else '')) + continue + + m = re.match(r'^(\d+):(.*)$', code_part) + if m: + label_num = m.group(1) + rest = m.group(2).strip() + if rest: + converted_rest = _convert_single(rest) + converted_stmts.append(f"{label_num}: {converted_rest}" + (f' ; {comment_part}' if comment_part else '')) + else: + converted_stmts.append(f"{label_num}:" + (f' ; {comment_part}' if comment_part else '')) + continue + + converted = _convert_single(code_part) + if comment_part: + converted += f' ; {comment_part}' + converted_stmts.append(converted) + + result.append('; '.join(converted_stmts)) + return '\n'.join(result) diff --git a/lib/core/DecoratorPass.py b/lib/core/DecoratorPass.py new file mode 100644 index 0000000..c3e5f07 --- /dev/null +++ b/lib/core/DecoratorPass.py @@ -0,0 +1,522 @@ +""" +DecoratorPass - Viper 语言自定义装饰器的 IR 层包装转换 (v4) + +v4 增强版特性: +1. 栈帧局部上下文 (ctx):替代全局变量,解决并发/递归状态错乱 +2. 流程劫持:handler 返回 i32 控制原函数调用次数 + - 返回 0:跳过原函数调用(@cache, @mock) + - 返回 1:正常调用一次(默认) + - 返回 N > 1:循环调用 N 次(@repeat) +3. alwaysinline 属性:消除 wrapper 调用开销 +4. 参数打包与修改:pre-phase 后从 args_struct 读回参数,装饰器可修改入参 +5. 返回值修改:ret_ptr 可写,装饰器可在后置阶段修改返回值 +6. 递归装饰保护:最外层 wrapper 检查全局标志位,递归调用时跳过所有装饰逻辑 + +装饰器调用约定 (v4): + i32 decor_name(i8* ctx, i8* func_name, i32 phase, + i8* args_ptr, i8* ret_ptr, i8* decor_args_ptr) + + 参数说明: + ctx : i8* - 栈帧局部上下文缓冲区(32字节),每次调用独立分配 + 前置阶段可写入状态,后置阶段可读取,生命周期绑定本次调用 + 多线程/递归完全隔离,替代全局变量 + func_name : i8* - 原始函数名字符串 + phase : i32 - 执行阶段(0=前置, 1=后置) + args_ptr : i8* - 指向函数参数打包结构体(可读写,无参数时为 null) + 前置阶段可写入修改参数值,wrapper 会从结构体读回修改后的参数 + ret_ptr : i8* - 指向返回值(前置阶段为 null,void 函数始终为 null) + 后置阶段可读写,装饰器可修改返回值 + decor_args_ptr : i8* - 指向装饰器参数打包结构体(无参数装饰器为 null) + + 返回值(仅前置阶段有效,后置阶段忽略): + 0 : 跳过原函数调用(@cache, @mock, @skip) + 1 : 调用原函数一次(默认行为,@log, @timing, @trace) + N>1: 循环调用原函数 N 次(@repeat, @benchmark) + + 编译器生成的 wrapper(以 add(i32, i32) -> i32, @log 为例): + define i32 @__decor_wrap_add(i32 %a, i32 %b) alwaysinline { + entry: + ; 递归保护:检查标志位 + %rec_val = load i8, i8* @__decor_rec___decor_wrap_add + %is_rec = icmp ne i8 %rec_val, 0 + br i1 %is_rec, label %recursive_call, label %decorated_entry + + recursive_call: + ; 递归调用:跳过所有装饰逻辑,直接调用原函数 + %rec_result = call i32 @add(i32 %a, i32 %b) + ret i32 %rec_result + + decorated_entry: + ; 设置递归保护标志 + store i8 1, i8* @__decor_rec___decor_wrap_add + + ; 分配栈帧局部上下文 + %ctx = alloca [32 x i8] + %ctx_ptr = bitcast [32 x i8]* %ctx to i8* + + ; 打包函数参数到结构体(装饰器可通过 args_ptr 修改) + %args = alloca {i32, i32} + store i32 %a, i32* getelementptr({i32, i32}* %args, i32 0, i32 0) + store i32 %b, i32* getelementptr({i32, i32}* %args, i32 0, i32 1) + %args_ptr = bitcast {i32, i32}* %args to i8* + + ; 分配返回值存储(零初始化) + %ret = alloca i32 + store i32 0, i32* %ret + + ; 前置阶段:handler 返回调用次数 + %n = call i32 @log(i8* %ctx_ptr, i8* "add", i32 0, + i8* %args_ptr, i8* null, i8* null) + br label %loop.header + + loop.header: + %i = phi i32 [0, %decorated_entry], [%i.next, %loop.body] + %cond = icmp slt i32 %i, %n + br i1 %cond, label %loop.body, label %post + + loop.body: + ; 从结构体读回参数(装饰器可能已修改) + %a.loaded = load i32, i32* getelementptr({i32, i32}* %args, i32 0, i32 0) + %b.loaded = load i32, i32* getelementptr({i32, i32}* %args, i32 0, i32 1) + %result = call i32 @add(i32 %a.loaded, i32 %b.loaded) + store i32 %result, i32* %ret + %i.next = add i32 %i, 1 + br label %loop.header + + post: + %ret_ptr = bitcast i32* %ret to i8* + call i32 @log(i8* %ctx_ptr, i8* "add", i32 1, + i8* %args_ptr, i8* %ret_ptr, i8* null) + + ; 清除递归保护标志 + store i8 0, i8* @__decor_rec___decor_wrap_add + + %final = load i32, i32* %ret + ret i32 %final + } + +链式装饰器(从下到上嵌套): + @log + @timing + def f(x) -> int: + 等价于 log(timing(f)) + 执行顺序:log_pre → timing_pre → f → timing_post → log_post + 生成:__decor_wrap_f (log) → __decor_wrap_f_timing (timing) → f + 递归保护仅在最外层 wrapper 生效,递归调用直接跳到原始 f +""" +from __future__ import annotations +import llvmlite.ir as ir + + +# 栈帧局部上下文缓冲区大小(字节) +_CTX_SIZE = 32 + +# 装饰器处理函数的 LLVM 签名:i32 (i8*, i8*, i32, i8*, i8*, i8*) +_DECOR_HANDLER_PARAM_TYPES = None # 延迟初始化 + + +def _get_decor_handler_func_type(): + """获取装饰器处理函数的 LLVM FunctionType: i32 (i8*, i8*, i32, i8*, i8*, i8*)""" + global _DECOR_HANDLER_PARAM_TYPES + if _DECOR_HANDLER_PARAM_TYPES is None: + i8_ptr = ir.IntType(8).as_pointer() + _DECOR_HANDLER_PARAM_TYPES = ir.FunctionType( + ir.IntType(32), + [i8_ptr, i8_ptr, ir.IntType(32), i8_ptr, i8_ptr, i8_ptr] + ) + return _DECOR_HANDLER_PARAM_TYPES + + +def _find_or_declare_handler(module, handler_name): + """在 module 中查找或声明装饰器处理函数""" + for f in module.functions: + if f.name == handler_name: + return f + func_type = _get_decor_handler_func_type() + handler = ir.Function(module, func_type, name=handler_name) + return handler + + +def _make_string_constant(module, text, name_prefix="decor.str"): + """在 module 中创建一个全局字符串常量,返回 i8* 指针""" + counter = getattr(_make_string_constant, '_counter', 0) + 1 + _make_string_constant._counter = counter + const_name = f"{name_prefix}.{counter}" + + encoded = text.encode('utf-8') + b'\x00' + const_type = ir.ArrayType(ir.IntType(8), len(encoded)) + const_val = ir.Constant(const_type, bytearray(encoded)) + + global_var = ir.GlobalVariable(module, const_type, name=const_name) + global_var.global_constant = True + global_var.linkage = 'private' + global_var.initializer = const_val + + return global_var.bitcast(ir.IntType(8).as_pointer()) + + +def _make_decor_args_constant(module, decorator_info): + """ + 为带参数的装饰器生成全局常量结构体,返回 i8* 指针。 + 无参数装饰器返回 null。 + + 支持的参数类型: + - int → i32 / i64 + - float → f64 + - bool → i1 + - str → i8*(全局字符串常量) + """ + deco_args = decorator_info.get('args', []) + deco_kwargs = decorator_info.get('kwargs', {}) + + if not deco_args and not deco_kwargs: + return ir.Constant(ir.IntType(8).as_pointer(), None) + + field_types = [] + field_values = [] + + for arg in deco_args: + llvm_type, llvm_val = _python_value_to_llvm(module, arg) + if llvm_type is None: + return ir.Constant(ir.IntType(8).as_pointer(), None) + field_types.append(llvm_type) + field_values.append(llvm_val) + + for kw in sorted(deco_kwargs.keys()): + llvm_type, llvm_val = _python_value_to_llvm(module, deco_kwargs[kw]) + if llvm_type is None: + return ir.Constant(ir.IntType(8).as_pointer(), None) + field_types.append(llvm_type) + field_values.append(llvm_val) + + struct_type = ir.LiteralStructType(field_types) + struct_const = ir.Constant(struct_type, field_values) + + counter = getattr(_make_decor_args_constant, '_counter', 0) + 1 + _make_decor_args_constant._counter = counter + global_name = f"__decor_args.{counter}" + + global_var = ir.GlobalVariable(module, struct_type, name=global_name) + global_var.global_constant = True + global_var.linkage = 'private' + global_var.initializer = struct_const + + return global_var.bitcast(ir.IntType(8).as_pointer()) + + +def _python_value_to_llvm(module, value): + """将 Python 值转换为 (LLVM类型, LLVM常量) 元组。""" + if isinstance(value, bool): + return ir.IntType(1), ir.Constant(ir.IntType(1), int(value)) + elif isinstance(value, int): + if -2**31 <= value < 2**31: + return ir.IntType(32), ir.Constant(ir.IntType(32), value) + else: + return ir.IntType(64), ir.Constant(ir.IntType(64), value) + elif isinstance(value, float): + return ir.DoubleType(), ir.Constant(ir.DoubleType(), value) + elif isinstance(value, str): + str_const = _make_string_constant(module, value, name_prefix="decor.arg") + return ir.IntType(8).as_pointer(), str_const + else: + return None, None + + +def _zero_constant(llvm_type): + """为给定 LLVM 类型创建零值常量""" + if isinstance(llvm_type, ir.IntType): + return ir.Constant(llvm_type, 0) + elif isinstance(llvm_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(llvm_type, 0.0) + elif isinstance(llvm_type, ir.PointerType): + return ir.Constant(llvm_type, None) + elif isinstance(llvm_type, ir.ArrayType): + elem_zero = _zero_constant(llvm_type.element) + if elem_zero is None: + return None + return ir.Constant(llvm_type, [elem_zero] * llvm_type.count) + else: + return None + + +def _generate_single_wrapper(module, original_func, wrapper_name, func_name_str, + decorator_info, is_export=False, + is_outermost=False, true_original_func=None): + """ + 为单个装饰器生成一层 wrapper 函数。 + + v4 Wrapper 结构(最外层含递归保护): + entry → 递归保护检查(仅最外层) + recursive_call → 递归时直接调用原函数,跳过所有装饰(仅最外层) + decorated_entry → 设置递归标志,分配 ctx/args/ret,调用 handler 前置 + loop.header → phi 计数器,比较 i < n_calls + loop.body → 从 args_struct 读回参数(支持修改),调用原函数 + post → 调用 handler 后置,清除递归标志,返回结果 + """ + decor_name = decorator_info['name'] + handler = _find_or_declare_handler(module, decor_name) + func_name_const = _make_string_constant(module, func_name_str, name_prefix="decor.fn") + + func_type = original_func.ftype + return_type = func_type.return_type + param_types = [p.type for p in original_func.args] + is_void = isinstance(return_type, ir.VoidType) + + wrapper_type = ir.FunctionType(return_type, param_types) + wrapper = ir.Function(module, wrapper_type, name=wrapper_name) + + # 添加 alwaysinline 属性,优化器完全内联消除调用开销 + wrapper.attributes.add('alwaysinline') + + i32 = ir.IntType(32) + i8 = ir.IntType(8) + i8_ptr = ir.IntType(8).as_pointer() + phase_pre = ir.Constant(i32, 0) + phase_post = ir.Constant(i32, 1) + null_ptr = ir.Constant(i8_ptr, None) + zero_i32 = ir.Constant(i32, 0) + one_i32 = ir.Constant(i32, 1) + one_i8 = ir.Constant(i8, 1) + zero_i8 = ir.Constant(i8, 0) + + # 递归保护:仅最外层 wrapper 生成 + rec_flag = None + if is_outermost and true_original_func is not None: + rec_flag_name = f"__decor_rec_{wrapper_name}" + # 检查是否已存在 + rec_flag = None + for g in module.global_values: + if g.name == rec_flag_name: + rec_flag = g + break + if rec_flag is None: + rec_flag = ir.GlobalVariable(module, i8, name=rec_flag_name) + rec_flag.global_constant = False + rec_flag.linkage = 'internal' + rec_flag.initializer = zero_i8 + + # 创建基本块 + entry_block = wrapper.append_basic_block("entry") + + if rec_flag is not None: + recursive_call_block = wrapper.append_basic_block("recursive_call") + decorated_entry_block = wrapper.append_basic_block("decorated_entry") + else: + recursive_call_block = None + decorated_entry_block = None + + loop_header_block = wrapper.append_basic_block("loop.header") + loop_body_block = wrapper.append_basic_block("loop.body") + post_block = wrapper.append_basic_block("post") + + # ==== Entry block ==== + builder = ir.IRBuilder(entry_block) + + if rec_flag is not None: + # 递归保护:检查标志位 + rec_val = builder.load(rec_flag, name="rec_val") + is_recursive = builder.icmp_signed('!=', rec_val, zero_i8) + builder.cbranch(is_recursive, recursive_call_block, decorated_entry_block) + + # ==== Recursive call block ==== + builder = ir.IRBuilder(recursive_call_block) + # 递归调用:直接调用真正的原函数,跳过所有装饰逻辑 + rec_call_args = [arg for arg in wrapper.args] + rec_ret_val = builder.call(true_original_func, rec_call_args) + if is_void: + builder.ret_void() + else: + builder.ret(rec_ret_val) + + # ==== Decorated entry block ==== + builder = ir.IRBuilder(decorated_entry_block) + # 设置递归保护标志 + builder.store(one_i8, rec_flag) + + # 记录 loop.header 的前置块为 decorated_entry_block + loop_predecessor = decorated_entry_block + else: + loop_predecessor = entry_block + + # 1. 分配栈帧局部上下文(每次调用独立,线程安全,递归安全) + ctx_type = ir.ArrayType(ir.IntType(8), _CTX_SIZE) + ctx_alloca = builder.alloca(ctx_type, name="ctx") + ctx_ptr = builder.bitcast(ctx_alloca, i8_ptr) + + # 2. 打包函数参数到结构体(装饰器可通过 args_ptr 读写修改) + args_alloca = None + args_struct_type = None + if param_types: + args_struct_type = ir.LiteralStructType(param_types) + args_alloca = builder.alloca(args_struct_type, name="args") + zero = ir.Constant(i32, 0) + for i, arg in enumerate(wrapper.args): + field_idx = ir.Constant(i32, i) + gep = builder.gep(args_alloca, [zero, field_idx], inbounds=True) + builder.store(arg, gep) + args_ptr = builder.bitcast(args_alloca, i8_ptr) + else: + args_ptr = null_ptr + + # 3. 分配返回值存储(零初始化,确保跳过原函数时返回安全默认值) + if not is_void: + ret_alloca = builder.alloca(return_type, name="ret") + zero_val = _zero_constant(return_type) + if zero_val is not None: + builder.store(zero_val, ret_alloca) + else: + ret_alloca = None + + # 4. 获取装饰器参数指针 + decor_args_ptr = _make_decor_args_constant(module, decorator_info) + + # 5. 前置阶段:handler 返回调用次数 + n_calls = builder.call(handler, [ctx_ptr, func_name_const, phase_pre, + args_ptr, null_ptr, decor_args_ptr]) + + # 6. 跳转到循环头 + builder.branch(loop_header_block) + + # ==== Loop header block ==== + builder = ir.IRBuilder(loop_header_block) + i_phi = builder.phi(i32, "i") + i_phi.add_incoming(zero_i32, loop_predecessor) + cond = builder.icmp_signed('<', i_phi, n_calls) + builder.cbranch(cond, loop_body_block, post_block) + + # ==== Loop body block ==== + builder = ir.IRBuilder(loop_body_block) + + # v4: 从 args_struct 读回参数(装饰器可能在 pre-phase 中修改了参数) + if args_alloca is not None and args_struct_type is not None: + zero = ir.Constant(i32, 0) + call_args = [] + for i in range(len(param_types)): + field_idx = ir.Constant(i32, i) + gep = builder.gep(args_alloca, [zero, field_idx], inbounds=True) + loaded_arg = builder.load(gep, name=f"arg.{i}") + call_args.append(loaded_arg) + else: + call_args = [] + + ret_val = builder.call(original_func, call_args) + if ret_alloca is not None: + builder.store(ret_val, ret_alloca) + i_next = builder.add(i_phi, one_i32) + i_phi.add_incoming(i_next, loop_body_block) + builder.branch(loop_header_block) + + # ==== Post block ==== + builder = ir.IRBuilder(post_block) + + # 后置阶段 + if ret_alloca is not None: + ret_ptr = builder.bitcast(ret_alloca, i8_ptr) + else: + ret_ptr = null_ptr + builder.call(handler, [ctx_ptr, func_name_const, phase_post, + args_ptr, ret_ptr, decor_args_ptr]) + + # 递归保护:清除标志(必须在 post-phase 之后、return 之前) + if rec_flag is not None: + builder.store(zero_i8, rec_flag) + + # 返回 + if is_void: + builder.ret_void() + else: + final_ret = builder.load(ret_alloca, name="final_ret") + builder.ret(final_ret) + + return wrapper + + +def _redirect_calls(module, old_func, new_func, skip_func_names=None): + """ + 替换 module 中所有对 old_func 的调用指令为对 new_func 的调用。 + 跳过 skip_func_names 中的函数(wrapper 函数内部不应被重定向)。 + """ + if skip_func_names is None: + skip_func_names = set() + + for func in module.functions: + if func.name in skip_func_names: + continue + if func.name == new_func.name: + continue + for block in func.blocks: + for instr in list(block.instructions): + if not isinstance(instr, ir.CallInstr): + continue + callee = instr.callee + if isinstance(callee, ir.Function) and callee is old_func: + instr.callee = new_func + + +def run(Gen): + """ + 执行 DecoratorPass。 + + 处理流程: + 1. 遍历 _decorated_funcs 中所有带装饰标记的函数 + 2. 对每个函数,按装饰器列表从底到顶生成嵌套 wrapper + 3. 将原函数改为 internal 链接 + 4. 替换所有调用点 + """ + if not hasattr(Gen, '_decorated_funcs') or not Gen._decorated_funcs: + return + + module = Gen.module + decorated = Gen._decorated_funcs.copy() + + for mangled_name, info in decorated.items(): + decorators = info['decorators'] + func_name = info['func_name'] + is_export = info['is_export'] + + # 查找原始函数 + original_func = None + for f in module.functions: + if f.name == mangled_name: + original_func = f + break + if original_func is None: + continue + + # 原函数改为 internal 链接(仅 wrapper 调用) + original_func.linkage = 'internal' + + # 按装饰器列表从底到顶生成嵌套 wrapper + # Python 装饰器顺序:@a @b def f() => a(b(f)) + # 执行顺序:先应用最靠近函数的 @b,再应用 @a + + current_func = original_func + all_wrapper_names = set() + + for i in range(len(decorators) - 1, -1, -1): + deco = decorators[i] + is_outermost = (i == 0) + deco_name = deco['name'] + + if is_outermost: + wrapper_name = f"__decor_wrap_{mangled_name}" + else: + wrapper_name = f"__decor_wrap_{mangled_name}_{deco_name}" + + all_wrapper_names.add(wrapper_name) + + wrapper = _generate_single_wrapper( + module, current_func, wrapper_name, + func_name, deco, is_export=is_export, + is_outermost=is_outermost, + true_original_func=original_func if is_outermost else None + ) + current_func = wrapper + + # 更新 functions 映射,使原函数名指向最外层 wrapper + Gen.functions[mangled_name] = current_func + if func_name in Gen.functions: + Gen.functions[func_name] = current_func + + # 替换所有非 wrapper 函数中对原函数的调用 + _redirect_calls(module, original_func, current_func, all_wrapper_names) diff --git a/lib/core/DifferenceCalculation.py b/lib/core/DifferenceCalculation.py new file mode 100644 index 0000000..1dd30f8 --- /dev/null +++ b/lib/core/DifferenceCalculation.py @@ -0,0 +1,166 @@ +def LevenshteinDistance(s1: str, s2: str) -> int: + """ + 计算两个字符串的 Levenshtein 距离(编辑距离) + :param s1: 原始字符串 + :param s2: 目标字符串 + :return: 最少编辑操作次数(差异程度) + """ + # 创建二维动态规划表,dp[i][j] 表示 s1[:i] 到 s2[:j] 的编辑距离 + m, n = len(s1), len(s2) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + # 初始化:空字符串到 s1[:i] 需要 i 次删除操作 + for i in range(m + 1): + dp[i][0] = i + # 初始化:空字符串到 s2[:j] 需要 j 次插入操作 + for j in range(n + 1): + dp[0][j] = j + + # 填充动态规划表 + for i in range(1, m + 1): + for j in range(1, n + 1): + # 字符相同,无需操作 + if s1[i-1] == s2[j-1]: + dp[i][j] = dp[i-1][j-1] + else: + # 字符不同,取「删除、插入、替换」中最小操作数 +1 + dp[i][j] = min( + dp[i-1][j], # 删除 s1[i-1] + dp[i][j-1], # 插入 s2[j-1] 到 s1 + dp[i-1][j-1] # 替换 s1[i-1] 为 s2[j-1] + ) + 1 + return dp[m][n] + + +def LongestCommonSubsequence(s1: str, s2: str) -> tuple[list[tuple[int, int]], str]: + """ + 计算两个字符串的最长公共子序列(LCS),并返回 LCS 字符的位置映射 + :param s1: 原始字符串 + :param s2: 目标字符串 + :return: (LCS 位置列表 [(S1Idx, S2Idx)], LCS 字符串) + """ + m, n = len(s1), len(s2) + # dp[i][j] 表示 s1[:i] 和 s2[:j] 的 LCS 长度 + dp = [[0] * (n + 1) for _ in range(m + 1)] + + # 填充 LCS 长度表 + for i in range(1, m + 1): + for j in range(1, n + 1): + if s1[i-1] == s2[j-1]: + dp[i][j] = dp[i-1][j-1] + 1 + else: + dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + + # 回溯找 LCS 的具体字符和位置 + LcsChars = [] + LcsPositions = [] + i, j = m, n + while i > 0 and j > 0: + if s1[i-1] == s2[j-1]: + LcsChars.append(s1[i-1]) + LcsPositions.append((i-1, j-1)) # 存储原始索引(从0开始) + i -= 1 + j -= 1 + elif dp[i-1][j] > dp[i][j-1]: + i -= 1 + else: + j -= 1 + + # 回溯得到的是逆序,需要反转 + LcsChars.reverse() + LcsPositions.reverse() + return LcsPositions, ''.join(LcsChars) + + +def GetStringDiff(s1: str, s2: str) -> dict: + """ + 完整对比两个字符串,返回差异详情 + :param s1: 原始字符串 + :param s2: 目标字符串 + :return: 差异字典(包含编辑距离、LCS、差异位置/内容) + """ + # 1. 计算编辑距离(差异程度) + EditDist = LevenshteinDistance(s1, s2) + # 2. 计算 LCS(公共部分) + LcsPos, LcsStr = LongestCommonSubsequence(s1, s2) + + # 3. 定位差异位置和内容 + DiffDetails = { + "delete": [], # s1 中需要删除的字符 (索引, 字符) + "insert": [], # s2 中需要插入的字符 (索引, 字符) + "replace": [] # s1 中需要替换的字符 (s1索引, 原字符, 目标字符) + } + + # 生成 s1 和 s2 的差异标记 + S1Idx = 0 + S2Idx = 0 + for (LcsS1Idx, LcsS2Idx) in LcsPos: + # 处理 s1 中需要删除的字符(LCS 前的非公共部分) + while S1Idx < LcsS1Idx: + DiffDetails["delete"].append((S1Idx, s1[S1Idx])) + S1Idx += 1 + # 处理 s2 中需要插入的字符(LCS 前的非公共部分) + while S2Idx < LcsS2Idx: + DiffDetails["insert"].append((S2Idx, s2[S2Idx])) + S2Idx += 1 + # 公共字符,跳过 + S1Idx += 1 + S2Idx += 1 + + # 处理末尾剩余的非公共部分 + while S1Idx < len(s1): + DiffDetails["delete"].append((S1Idx, s1[S1Idx])) + S1Idx += 1 + while S2Idx < len(s2): + DiffDetails["insert"].append((S2Idx, s2[S2Idx])) + S2Idx += 1 + + # 优化:将连续的删除+插入合并为替换(更符合直观) + ReplaceCandidates = list(zip(DiffDetails["delete"], DiffDetails["insert"])) + for (DelItem, InsItem) in ReplaceCandidates: + DelIdx, DelChar = DelItem + InsIdx, InsChar = InsItem + DiffDetails["replace"].append((DelIdx, DelChar, InsChar)) + DiffDetails["delete"].remove(DelItem) + DiffDetails["insert"].remove(InsItem) + + return { + "EditDistance": EditDist, # 差异程度(数值越小越相似) + "similarity": 1 - EditDist / max(len(s1), len(s2), 1), # 相似度(0-1) + "LcsString": LcsStr, # 最长公共子序列 + "LcsLength": len(LcsStr), # LCS 长度 + "DiffDetails": DiffDetails # 具体差异(删/插/改) + } + + +# 测试用例 +if __name__ == "__main__": + # 示例1:轻微差异(替换+插入) + s1 = "Hello World!" + s2 = "Hello Python!" + DiffResult = GetStringDiff(s1, s2) + print("=== 示例1:轻微差异 ===") + print(f"编辑距离:{DiffResult['EditDistance']}") + print(f"相似度:{DiffResult['similarity']:.2f}") + print(f"最长公共子序列:{DiffResult['LcsString']}") + print(f"差异详情:{DiffResult['DiffDetails']}") + + # 示例2:完全不同 + s3 = "abc123" + s4 = "xyz789" + DiffResult2 = GetStringDiff(s3, s4) + print("\n=== 示例2:完全不同 ===") + print(f"编辑距离:{DiffResult2['EditDistance']}") + print(f"相似度:{DiffResult2['similarity']:.2f}") + print(f"最长公共子序列:{DiffResult2['LcsString']}") + print(f"差异详情:{DiffResult2['DiffDetails']}") + + # 示例3:内容一致 + s5 = "TestString" + s6 = "TestString" + DiffResult3 = GetStringDiff(s5, s6) + print("\n=== 示例3:内容一致 ===") + print(f"编辑距离:{DiffResult3['EditDistance']}") + print(f"相似度:{DiffResult3['similarity']:.2f}") + print(f"最长公共子序列:{DiffResult3['LcsString']}") + print(f"差异详情:{DiffResult3['DiffDetails']}") diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py new file mode 100644 index 0000000..7809086 --- /dev/null +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -0,0 +1,471 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo +from lib.includes import t +import ast +import llvmlite.ir as ir + + +class AnnAssignHandle(BaseHandle): + def _GetCTypeInfo(self, annotation): + return self.Trans.TypeMergeHandler.GetCTypeInfo(annotation) + + def _StoreOrStrCopy(self, VarName, VarPtr, Value): + Gen = self.Trans.LlvmGen + DestPtr = Gen._load(VarPtr, name=VarName) + if isinstance(DestPtr.type, ir.PointerType) and isinstance(DestPtr.type.pointee, ir.IntType) and DestPtr.type.pointee.width == 8: + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.IntType) and Value.type.pointee.width == 8: + if 'llvm.memcpy' not in Gen.functions: + memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(32), ir.IntType(1)]) + Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy') + if isinstance(DestPtr.type.pointee, ir.IntType) and not isinstance(DestPtr.type.pointee, ir.IntType(8)): + DestPtr = Gen.builder.bitcast(DestPtr, ir.PointerType(ir.IntType(8)), name=f"strcpy_dst_cast_{VarName}") + if isinstance(Value.type.pointee, ir.IntType) and not isinstance(Value.type.pointee, ir.IntType(8)): + Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"strcpy_src_cast_{VarName}") + size = ir.Constant(ir.IntType(64), 8) + align = ir.Constant(ir.IntType(32), 1) + isvolatile = ir.Constant(ir.IntType(1), 0) + Gen.builder.call(Gen.functions['llvm.memcpy'], [DestPtr, Value, size, align, isvolatile], name=f"strcpy_call_{VarName}") + return + try: + CastedVal = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}") + Gen._store(CastedVal, VarPtr) + except Exception: # 回退:bitcast 失败时 alloca 新变量 + NewVar = Gen._alloca_entry(Value.type, name=VarName) + Gen._store(Value, NewVar) + Gen.variables[VarName] = NewVar + + def _HandleAttributeStoreLlvm(self, Target, Value): + Gen = self.Trans.LlvmGen + AttrName = Target.attr + if isinstance(Target.value, ast.Name) and Target.value.id == 'self': + ClassName = self._CurrentCpythonObjectClass + if not ClassName: + self_var = Gen.variables.get('self') + if self_var: + var_type = self_var.type + if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType): + var_type = var_type.pointee + if isinstance(var_type, ir.PointerType): + pointee = var_type.pointee + for cn, st in Gen.structs.items(): + if st == pointee: + ClassName = cn + break + if ClassName and ClassName in Gen.structs: + SelfVar = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + offset = Gen._get_member_offset(AttrName, ClassName) + MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + elif isinstance(Target.value, ast.Name): + VarName = Target.value.id + ClassName = Gen.var_struct_class.get(VarName) + if not ClassName: + for CN in Gen.structs: + if VarName == CN.lower() or VarName.startswith(CN): + ClassName = CN + break + if not ClassName and VarName in Gen.variables: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType): + pointee = VarPtr.type.pointee + if isinstance(pointee, ir.PointerType): + pointee = pointee.pointee + for CN, ST in Gen.structs.items(): + if pointee == ST: + ClassName = CN + break + IsUnion = False + if ClassName and ClassName in self.Trans.SymbolTable: + TypeInfo = self.Trans.SymbolTable[ClassName] + if hasattr(TypeInfo, 'IsUnion') and TypeInfo.IsUnion: + IsUnion = True + if ClassName and ClassName in Gen.structs: + ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + if ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IntType) and ObjVal.type.pointee.width == 8: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{ClassName}") + if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: + if IsUnion: + NestedStructName = f"{ClassName}_{AttrName}" + if NestedStructName in Gen.structs: + NestedStructType = Gen.structs[NestedStructName] + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") + offset = Gen._get_member_offset(AttrName, NestedStructName) + if offset is not None and offset < len(NestedStructType.elements): + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + return + offset = Gen._get_member_offset(AttrName, ClassName) + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + elif isinstance(Target.value, ast.Attribute): + ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + if ObjVal and isinstance(ObjVal.type, ir.PointerType): + pointee = ObjVal.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + offset = Gen._get_member_offset(AttrName, CN) + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + break + + def _StoreWithCoerce(self, Value, Ptr): + Gen = self.Trans.LlvmGen + if isinstance(Ptr.type, ir.PointerType): + TargetType = Ptr.type.pointee + if Value.type != TargetType: + if isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType): + if TargetType.width < Value.type.width: + Value = Gen.builder.trunc(Value, TargetType, name="trunc") + else: + Value = Gen.builder.zext(Value, TargetType, name="zext") + elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType): + Value = Gen.builder.bitcast(Value, TargetType, name="ptr_bitcast") + elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.IntType): + Value = Gen.builder.inttoptr(Value, TargetType, name="int_to_ptr") + elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.PointerType): + Value = Gen.builder.ptrtoint(Value, TargetType, name="ptr_to_int") + Gen._store(Value, Ptr) + + def _HandleAnnAssignLlvm(self, Node): + Gen = self.Trans.LlvmGen + self.Trans._current_assign_node = Node + try: + self._HandleAnnAssignLlvmInner(Node) + finally: + self.Trans._current_assign_node = None + + def _HandleAnnAssignLlvmInner(self, Node): + Gen = self.Trans.LlvmGen + if isinstance(Node.target, ast.Name): + VarName = Node.target.id + TypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + IsPtr = TypeInfo.IsPtr + + if TypeInfo.IsDefine: + if Node.value and isinstance(Node.value, ast.Constant): + if not hasattr(Gen, '_define_constants'): + Gen._define_constants = {} + Gen._define_constants[VarName] = Node.value.value + info = CTypeInfo() + info.IsDefine = True + info.DefineValue = Node.value.value + self.Trans.SymbolTable[VarName] = info + Gen._record_var_signedness(VarName, TypeInfo.IsUInt) + return + if TypeInfo.IsStr or (isinstance(Node.annotation, ast.Name) and Node.annotation.id == 'str'): + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CChar() + TypeInfo.PtrCount = 1 + IsPtr = True + if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list': + slice_node = Node.annotation.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + elem_type_node = slice_node.elts[0] + count_node = slice_node.elts[1] + ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable) + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + ElemType = Gen.structs[elem_type_node.id] + else: + if isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str': + ElemType = ir.PointerType(ir.IntType(8)) + else: + ElemType = Gen._ctype_to_llvm(ElemTypeInfo) + if isinstance(ElemType, ir.VoidType): + ElemType = ir.IntType(32) + ArrayCount = 1 + if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int): + ArrayCount = count_node.value + else: + eval_count = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable) + if eval_count is not None and isinstance(eval_count, int) and eval_count > 0: + ArrayCount = eval_count + elif count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None): + if Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): + ArrayCount = len(Node.value.value) + 1 + VarType = ir.ArrayType(ElemType, ArrayCount) + var = Gen._alloca_entry(VarType, name=VarName) + Gen.variables[VarName] = var + Gen._record_var_signedness(VarName, False) + if Node.value and isinstance(Node.value, ast.List): + InitConstants = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen) + if InitConstants: + try: + InitVal = ir.Constant(VarType, InitConstants) + Gen.builder.store(InitVal, var) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): + str_val = Node.value.value + '\x00' + str_bytes = bytearray(str_val, 'utf-8') + if isinstance(VarType, ir.ArrayType) and len(str_bytes) < VarType.count: + str_bytes.extend(b'\x00' * (VarType.count - len(str_bytes))) + try: + InitVal = ir.Constant(VarType, str_bytes[:VarType.count] if isinstance(VarType, ir.ArrayType) else str_bytes) + Gen.builder.store(InitVal, var) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + if self.Trans.VarScopes: + self.Trans.VarScopes[-1][VarName] = ElemTypeInfo + return + if TypeInfo.IsVoid and isinstance(Node.annotation, ast.BinOp): + def _find_struct_name_in_annot(node): + if isinstance(node, ast.Name) and node.id in Gen.structs: + return node.id + if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs: + return node.value + if isinstance(node, ast.Attribute) and node.attr in Gen.structs: + return node.attr + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + result = _find_struct_name_in_annot(node.left) + if result: + return result + return _find_struct_name_in_annot(node.right) + return None + found = _find_struct_name_in_annot(Node.annotation) + if found: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CStruct(name=found) + TypeInfo.PtrCount = 1 + IsPtr = True + elif isinstance(Node.annotation.left, ast.Attribute): + AttrTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation.left) + if AttrTypeInfo and AttrTypeInfo.BaseType: + TypeInfo = AttrTypeInfo + TypeInfo.PtrCount = max(TypeInfo.PtrCount, 1) + IsPtr = True + VarType = Gen._ctype_to_llvm(TypeInfo) + if not IsPtr and TypeInfo.IsStruct and TypeInfo.Name: + stripped = TypeInfo.Name + if stripped in Gen.class_vtable and stripped in Gen.structs: + VarType = ir.PointerType(Gen.structs[stripped]) + IsPtr = True + if isinstance(VarType, ir.IdentifiedStructType): + struct_name = getattr(VarType, 'name', '') + if struct_name and Gen.class_vtable: + for cls_name in Gen.class_vtable: + if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: + VarType = ir.PointerType(VarType) + IsPtr = True + break + if isinstance(VarType, ir.VoidType): + VarType = ir.IntType(32) + IsUnsigned = TypeInfo.IsUInt + if VarName in Gen._reg_values: + OldVal = Gen._reg_values[VarName] + if isinstance(OldVal.type, ir.PointerType): + var = Gen._alloca_entry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + del Gen._reg_values[VarName] + if Node.value: + InitValue = self.HandleExprLlvm(Node.value, VarType=VarType) + if InitValue: + self._StoreOrStrCopy(VarName, var, InitValue) + Gen._record_var_signedness(VarName, IsUnsigned) + return + del Gen._reg_values[VarName] + InitValue = None + if Node.value: + InitValue = self.HandleExprLlvm(Node.value, VarType=VarType) + if VarName in Gen._reg_values: + del Gen._reg_values[VarName] + if VarName in Gen.variables and Gen.variables[VarName] is not None: + if InitValue and isinstance(InitValue.type, ir.PointerType): + pointee = InitValue.type.pointee + if isinstance(pointee, ir.IdentifiedStructType): + struct_name = getattr(pointee, 'name', '') + is_vtable_class = False + for cls_name in Gen.class_vtable: + if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: + is_vtable_class = True + break + if is_vtable_class: + var = Gen._alloca_entry(InitValue.type, name=VarName) + Gen._store(InitValue, var) + Gen.variables[VarName] = var + if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: + Gen.var_struct_class[VarName] = Node.annotation.id + Gen.global_struct_class[VarName] = Node.annotation.id + Gen._record_var_signedness(VarName, IsUnsigned) + return + if InitValue: + try: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType): + TargetType = VarPtr.type.pointee + if InitValue.type != TargetType: + if isinstance(InitValue.type, ir.IntType) and isinstance(TargetType, ir.IntType): + if TargetType.width > InitValue.type.width: + InitValue = Gen.builder.zext(InitValue, TargetType, name=f"zext_{VarName}") + elif TargetType.width < InitValue.type.width: + InitValue = Gen.builder.trunc(InitValue, TargetType, name=f"trunc_{VarName}") + elif isinstance(InitValue.type, ir.PointerType) and isinstance(TargetType, ir.PointerType): + InitValue = Gen.builder.bitcast(InitValue, TargetType, name=f"cast_{VarName}") + Gen._store(InitValue, VarPtr) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + Gen._record_var_signedness(VarName, IsUnsigned) + return + if VarName in Gen.global_vars: + if VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + if InitValue: + Gen._store(InitValue, GVar) + Gen.variables[VarName] = GVar + Gen._record_var_signedness(VarName, IsUnsigned) + return + var = Gen._alloca_entry(VarType, name=VarName) + if InitValue and isinstance(InitValue.type, ir.PointerType): + pointee = InitValue.type.pointee + if isinstance(pointee, ir.IdentifiedStructType): + struct_name = getattr(pointee, 'name', '') + is_vtable_class = False + for cls_name in Gen.class_vtable: + if struct_name.endswith(f'.{cls_name}') or struct_name == cls_name: + is_vtable_class = True + break + if is_vtable_class and not isinstance(VarType, ir.PointerType): + var = Gen._alloca_entry(InitValue.type, name=VarName) + VarType = InitValue.type + IsPtr = True + Gen._store(InitValue, var) + Gen.variables[VarName] = var + if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: + Gen.var_struct_class[VarName] = Node.annotation.id + Gen.global_struct_class[VarName] = Node.annotation.id + Gen._record_var_signedness(VarName, IsUnsigned) + return + for CN, ST in Gen.structs.items(): + if pointee is ST or pointee == ST: + if CN != Gen.var_struct_class.get(VarName): + Gen.var_struct_class[VarName] = CN + Gen.global_struct_class[VarName] = CN + if isinstance(VarType, ir.PointerType) and VarType.pointee is not ST and VarType.pointee != ST: + var = Gen._alloca_entry(ir.PointerType(pointee), name=VarName) + VarType = ir.PointerType(pointee) + break + if InitValue: + try: + if InitValue.type != VarType: + if isinstance(InitValue.type, ir.IntType) and isinstance(VarType, ir.IntType): + if VarType.width > InitValue.type.width: + InitValue = Gen.builder.zext(InitValue, VarType, name=f"zext_{VarName}") + elif VarType.width < InitValue.type.width: + InitValue = Gen.builder.trunc(InitValue, VarType, name=f"trunc_{VarName}") + elif isinstance(InitValue.type, ir.PointerType) and isinstance(VarType, ir.PointerType): + InitValue = Gen.builder.bitcast(InitValue, VarType, name=f"cast_{VarName}") + elif isinstance(VarType, ir.PointerType) and isinstance(InitValue.type, ir.IntType): + InitValue = Gen.builder.inttoptr(InitValue, VarType, name=f"int2ptr_{VarName}") + elif isinstance(VarType, ir.IntType) and isinstance(InitValue.type, ir.PointerType): + InitValue = Gen.builder.ptrtoint(InitValue, VarType, name=f"ptr2int_{VarName}") + Gen._store(InitValue, var) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + Gen.variables[VarName] = var + Gen._record_var_signedness(VarName, IsUnsigned) + + if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): + def _find_struct_in_binop(node): + if isinstance(node, ast.Name) and node.id in Gen.structs: + return node.id + if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs: + return node.value + if isinstance(node, ast.Attribute) and node.attr in Gen.structs: + return node.attr + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + result = _find_struct_in_binop(node.left) + if result: + return result + return _find_struct_in_binop(node.right) + return None + found_struct = _find_struct_in_binop(Node.annotation) + if found_struct: + Gen.var_struct_class[VarName] = found_struct + Gen.global_struct_class[VarName] = found_struct + + if InitValue and isinstance(InitValue.type, ir.PointerType): + pointee = InitValue.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + Gen._var_to_heap_ptr[VarName] = InitValue + if CN != Gen.var_struct_class.get(VarName): + Gen.var_struct_class[VarName] = CN + Gen.global_struct_class[VarName] = CN + break + + if self.Trans.VarScopes: + if TypeInfo: + self.Trans.VarScopes[-1][VarName] = TypeInfo + else: + DefaultInfo = CTypeInfo() + DefaultInfo.BaseType = t.CInt + self.Trans.VarScopes[-1][VarName] = DefaultInfo + elif isinstance(Node.target, ast.Attribute): + if isinstance(Node.target.value, ast.Name) and Node.target.value.id == 'self': + if Node.value: + AttrVarType = None + try: + if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list': + slice_node = Node.annotation.slice + if isinstance(slice_node, ast.Name): + AttrVarType = f'list[{slice_node.id}]' + elif isinstance(slice_node, ast.Tuple): + elts = ', '.join(getattr(e, 'id', str(e)) for e in slice_node.elts) + AttrVarType = f'list[{elts}]' + elif isinstance(slice_node, ast.Attribute): + AttrVarType = f'list[{ast.dump(slice_node)}]' + if AttrVarType is None: + AttrTypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) + if AttrTypeInfo: + AttrVarType = Gen._ctype_to_llvm(AttrTypeInfo) + except Exception as e: + pass + Value = self.HandleExprLlvm(Node.value, VarType=AttrVarType) + if Value: + self._HandleAttributeStoreLlvm(Node.target, Value) + AttrName = Node.target.attr + len_name = f'{AttrName}__len' + ClassName = self._CurrentCpythonObjectClass + if not ClassName: + self_var = Gen.variables.get('self') + if self_var: + var_type = self_var.type + if isinstance(var_type, ir.PointerType) and isinstance(var_type.pointee, ir.PointerType): + var_type = var_type.pointee + if isinstance(var_type, ir.PointerType): + pointee = var_type.pointee + for cn, st in Gen.structs.items(): + if st == pointee: + ClassName = cn + break + if ClassName and ClassName in Gen.class_members: + for m_name, m_type in Gen.class_members[ClassName]: + if m_name == len_name: + list_len = None + if isinstance(Node.value, ast.List): + list_len = ir.Constant(ir.IntType(64), len(Node.value.elts)) + if list_len is not None: + SelfVar = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + offset = Gen._get_member_offset(len_name, ClassName) + LenPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=len_name) + Gen._store(list_len, LenPtr) + break \ No newline at end of file diff --git a/lib/core/Handles/HandlesAssert.py b/lib/core/Handles/HandlesAssert.py new file mode 100644 index 0000000..7b8ef64 --- /dev/null +++ b/lib/core/Handles/HandlesAssert.py @@ -0,0 +1,57 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP +import ast +import llvmlite.ir as ir + +class AssertHandle(BaseHandle): + def _HandleAssertLlvm(self, Node): + Gen = self.Trans.LlvmGen + cond_val = self.HandleExprLlvm(Node.test) + if not cond_val: + return + if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1: + zero = ir.Constant(cond_val.type, 0) + cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond") + AssertFailBB = Gen.func.append_basic_block(name="assert.fail") + AssertOkBB = Gen.func.append_basic_block(name="assert.ok") + Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB) + Gen.builder.position_at_start(AssertFailBB) + exc_code = 9 + exc_msg = None + if Node.msg: + if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str): + exc_msg = self.HandleExprLlvm(Node.msg) + elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name): + exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99) + if Node.msg.args: + first_arg = Node.msg.args[0] + if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): + exc_msg = self.HandleExprLlvm(first_arg) + elif isinstance(Node.msg, ast.Name): + exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99) + else: + exc_msg = self.HandleExprLlvm(Node.msg) + if Gen.eh_except_block_stack: + ExceptBB, EndBB, exception_code, eh_message = Gen.eh_except_block_stack[-1] + Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code) + if exc_msg: + Gen._store(exc_msg, eh_message) + else: + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen._store(null_ptr, eh_message) + Gen.builder.branch(ExceptBB) + else: + printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + if exc_msg: + fmt = Gen.emit_constant("AssertionError: %s\n", 'string') + Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print") + else: + fmt = Gen.emit_constant("AssertionError\n", 'string') + Gen.builder.call(printf_func, [fmt], name="assert_fail_print") + exit_func = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)])) + Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit") + Gen.builder.unreachable() + Gen.builder.position_at_start(AssertOkBB) \ No newline at end of file diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py new file mode 100644 index 0000000..e7ceb93 --- /dev/null +++ b/lib/core/Handles/HandlesAssign.py @@ -0,0 +1,1657 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta +from lib.includes import t +import ast +import llvmlite.ir as ir + +class AssignHandle: + def __init__(self, translator: "Translator"): + self.Trans = translator + self._CurrentCpythonObjectClass: str = None + + @staticmethod + def _zero_value(var_type): + if isinstance(var_type, ir.ArrayType): + elem_zv = AssignHandle._zero_value(var_type.element) + if elem_zv is None: + return None + return ir.Constant(var_type, [elem_zv] * var_type.count) + elif isinstance(var_type, ir.IntType): + return ir.Constant(var_type, 0) + elif isinstance(var_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(var_type, 0.0) + elif isinstance(var_type, ir.PointerType): + return ir.Constant(var_type, None) + elif isinstance(var_type, ir.BaseStructType): + if var_type.elements is not None and len(var_type.elements) > 0: + elem_zvs = [AssignHandle._zero_value(m) for m in var_type.elements] + if any(zv is None for zv in elem_zvs): + return None + return ir.Constant(var_type, elem_zvs) + return None + return None + + @staticmethod + def _contains_identified_struct(var_type): + if isinstance(var_type, ir.IdentifiedStructType): + return True + if isinstance(var_type, ir.ArrayType): + return AssignHandle._contains_identified_struct(var_type.element) + if isinstance(var_type, ir.PointerType): + return AssignHandle._contains_identified_struct(var_type.pointee) + if isinstance(var_type, ir.BaseStructType): + if var_type.elements: + return any(AssignHandle._contains_identified_struct(e) for e in var_type.elements) + return False + + def HandleExprLlvm(self, Node, VarType=None): + return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) + + def _HandleAssignLlvm(self, Node): + Gen = self.Trans.LlvmGen + Gen._set_node_info(Node, "Assign") + if len(Node.targets) == 1: + Target = Node.targets[0] + if isinstance(Target, ast.Name): + VarName = Target.id + if VarName in Gen.var_const_flags: + src_info = Gen._get_node_info() + print(f"[错误] 不能对 const 变量 '{VarName}' 赋值{src_info}") + import sys + sys.exit(1) + if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name) and Node.value.value.id == 't': + AttrName = Node.value.attr + Gen.var_type_info[VarName] = {'type': 't_type', 'name': AttrName} + Gen.var_type_assignments.setdefault(VarName, []).append({'type': 't_type', 'name': AttrName}) + from lib.includes.t import CTypeRegistry + c_type_name = '' + resolved = CTypeRegistry.ResolveName(AttrName) + if resolved is not None: + ctype_cls, ptr_level = resolved + c_type_name = CTypeRegistry.CTypeToCName(ctype_cls) + if ptr_level > 0 and c_type_name: + c_type_name = c_type_name + ' *' + if not c_type_name: + if AttrName == 'CPtr': + c_type_name = 'void *' + is_unsigned = Gen._is_type_unsigned(c_type_name) if c_type_name else False + fmt_str = "%u\n" if is_unsigned else "%d\n" + fmt_bytes = fmt_str.encode('utf-8') + b'\x00' + fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes)) + fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes)) + fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}") + Gen.string_const_counter += 1 + fmt_gvar.initializer = fmt_const + fmt_gvar.linkage = 'internal' + fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name=f"{VarName}_fmt") + fmt_var_name = f"__{VarName}_fmt" + if fmt_var_name not in Gen.variables: + fmt_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) + Gen.variables[fmt_var_name] = fmt_alloca + Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) + kind_var_name = f"__{VarName}_kind" + if kind_var_name not in Gen.variables: + kind_alloca = Gen._alloca_entry(ir.IntType(32), name=kind_var_name) + Gen.variables[kind_var_name] = kind_alloca + Gen.builder.store(ir.Constant(ir.IntType(32), 0), Gen.variables[kind_var_name]) + if VarName not in Gen.variables: + dummy_var = Gen._alloca(ir.IntType(8), name=VarName) + Gen.variables[VarName] = dummy_var + return + if isinstance(Node.value, ast.Name) and Node.value.id in Gen.structs: + ClassName = Node.value.id + Gen.var_type_info[VarName] = {'type': 'class_cast', 'name': ClassName} + Gen.var_type_assignments.setdefault(VarName, []).append({'type': 'class_cast', 'name': ClassName}) + fmt_str = "%p\n" + fmt_bytes = fmt_str.encode('utf-8') + b'\x00' + fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes)) + fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes)) + fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}") + Gen.string_const_counter += 1 + fmt_gvar.initializer = fmt_const + fmt_gvar.linkage = 'internal' + fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name=f"{VarName}_fmt") + fmt_var_name = f"__{VarName}_fmt" + if fmt_var_name not in Gen.variables: + fmt_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) + Gen.variables[fmt_var_name] = fmt_alloca + Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) + kind_var_name = f"__{VarName}_kind" + if kind_var_name not in Gen.variables: + kind_alloca = Gen._alloca_entry(ir.IntType(32), name=kind_var_name) + Gen.variables[kind_var_name] = kind_alloca + Gen.builder.store(ir.Constant(ir.IntType(32), 1), Gen.variables[kind_var_name]) + if VarName not in Gen.variables: + dummy_var = Gen._alloca(ir.IntType(8), name=VarName) + Gen.variables[VarName] = dummy_var + return + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == 'va_list': + va_list_ptr = Gen._alloca_entry(ir.IntType(8).as_pointer(), name="va_list") + Gen.variables[VarName] = va_list_ptr + return + IsStructCtor = (isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) + and Node.value.func.id in Gen.structs) + if IsStructCtor: + ClassName = Node.value.func.id + StructType = Gen.structs[ClassName] + + IsUnion = False + if ClassName in self.Trans.SymbolTable: + TypeInfo = self.Trans.SymbolTable[ClassName] + if TypeInfo.IsUnion: + IsUnion = True + + if IsUnion: + Value = self.HandleExprLlvm(Node.value) + if Value: + var = Gen._alloca_entry(Value.type, name=VarName) + Gen._store(Value, var) + Gen.variables[VarName] = var + return + + ExistingPtr = None + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type.pointee, ir.PointerType): + ExistingPtr = VarPtr + elif VarName in Gen._reg_values: + OldVal = Gen._reg_values[VarName] + if isinstance(OldVal.type, ir.PointerType): + var = Gen._alloca_entry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + del Gen._reg_values[VarName] + ExistingPtr = var + elif VarName in Gen._direct_values: + OldVal = Gen._direct_values.pop(VarName) + if isinstance(OldVal.type, ir.PointerType): + var = Gen._alloca_entry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + ExistingPtr = var + if ExistingPtr: + pointee = ExistingPtr.type.pointee + if isinstance(pointee, ir.PointerType) and pointee.pointee == StructType: + self._InitStructAtPtr(Node.value, ClassName, ExistingPtr) + return + elif isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8: + self._InitStructAtPtr(Node.value, ClassName, ExistingPtr) + Gen.var_struct_class[VarName] = ClassName + return + if isinstance(Node.value, ast.Attribute): + enum_type_name = self._CheckEnumMemberAssignment(Node.value) + if enum_type_name: + Gen.var_type_info[VarName] = {'type': 'enum', 'name': enum_type_name} + var_type_for_list = None + if isinstance(Node.value, ast.List) and VarName in Gen.var_type_info: + type_info = Gen.var_type_info[VarName] + if type_info.get('type') == 'list': + var_type_for_list = type_info.get('full_type') + Value = self.HandleExprLlvm(Node.value, VarType=var_type_for_list) + if not Value: + return + if isinstance(Value.type, ir.VoidType): + return + Gen._unregister_temp_ptr(Value) + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found_class = None + found = Gen.find_struct_by_pointee(Value.type.pointee) + if found: + CN, ST = found + found_class = CN + Gen.var_struct_class[VarName] = CN + Gen._var_to_heap_ptr[VarName] = Value + if found_class is None and isinstance(Value.type.pointee, ir.IdentifiedStructType): + pointee_name = Value.type.pointee.name + for CN, ST in Gen.structs.items(): + if isinstance(ST, ir.IdentifiedStructType) and ST.name == pointee_name: + found_class = CN + Gen.var_struct_class[VarName] = CN + Gen._var_to_heap_ptr[VarName] = Value + break + else: + if VarName in ('mctx', 's1ctx', 's2ctx', 's5ctx'): + pass + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + if VarName in Gen.variables and Gen.variables[VarName] is not None: + Gen._store(Value, Gen.variables[VarName]) + else: + var = Gen._alloca_entry(Value.type, name=VarName) + Gen._store(Value, var) + Gen.variables[VarName] = var + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): + call_func_name = Node.value.func.id + if call_func_name in Gen.var_type_info: + type_info = Gen.var_type_info[call_func_name] + if type_info['type'] in ('t_type', 'class_cast'): + src_fmt_var = f"__{call_func_name}_fmt" + dst_fmt_var = f"__{VarName}_fmt" + if src_fmt_var in Gen.variables: + if dst_fmt_var not in Gen.variables: + dst_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) + Gen.variables[dst_fmt_var] = dst_alloca + src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"load_{call_func_name}_fmt_for_{VarName}") + Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) + src_kind_var = f"__{call_func_name}_kind" + dst_kind_var = f"__{VarName}_kind" + if src_kind_var in Gen.variables: + if dst_kind_var not in Gen.variables: + dst_kind_alloca = Gen._alloca_entry(ir.IntType(32), name=dst_kind_var) + Gen.variables[dst_kind_var] = dst_kind_alloca + src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"load_{call_func_name}_kind_for_{VarName}") + Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) + Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} + return + if VarName in Gen.global_vars: + if VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + Gen._store(Value, GVar) + Gen.variables[VarName] = GVar + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found = Gen.find_struct_by_pointee(Value.type.pointee) + if found: + CN, ST = found + Gen.var_struct_class[VarName] = CN + elif VarName in Gen.variables and Gen.variables[VarName] is not None: + Gen._store(Value, Gen.variables[VarName]) + return + if VarName in Gen._reg_values: + OldVal = Gen._reg_values[VarName] + var = Gen._alloca_entry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + del Gen._reg_values[VarName] + if VarName in Gen._direct_values: + OldVal = Gen._direct_values.pop(VarName) + var = Gen._alloca_entry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + TargetType = VarPtr.type.pointee if isinstance(VarPtr.type, ir.PointerType) else None + try: + types_differ = TargetType and Value.type != TargetType + except AssertionError: + types_differ = False + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): + LoadedValue = Gen._load(Value, name=f"load_{VarName}") + try: + loaded_differ = TargetType and LoadedValue.type != TargetType + except AssertionError: + loaded_differ = False + if loaded_differ: + try: + Coerced = Gen._coerce_value(LoadedValue, TargetType) + if Coerced is not None: + LoadedValue = Coerced + except AssertionError: + pass + Gen._store(LoadedValue, VarPtr) + elif types_differ: + try: + Coerced = Gen._coerce_value(Value, TargetType) + if Coerced is not None: + Gen._store(Coerced, VarPtr) + else: + Gen._store(Value, VarPtr) + except AssertionError: + Gen._store(Value, VarPtr) + else: + Gen._store(Value, VarPtr) + if VarName not in Gen.variables: + # 检查是否为模块级全局变量,避免创建局部变量遮蔽全局 + if VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + Gen._store(Value, GVar) + Gen.variables[VarName] = GVar + elif isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): + LoadedValue = Gen._load(Value, name=f"load_{VarName}") + var = Gen._alloca_entry(LoadedValue.type, name=VarName) + Gen._store(LoadedValue, var) + Gen.variables[VarName] = var + else: + var = Gen._alloca_entry(Value.type, name=VarName) + Gen._store(Value, var) + Gen.variables[VarName] = var + is_u = Gen._check_node_unsigned(Node.value) + Gen._record_var_signedness(VarName, 'unsigned int' if is_u else 'int') + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): + call_func_name = Node.value.func.id + if call_func_name in Gen.var_type_info: + type_info = Gen.var_type_info[call_func_name] + if type_info['type'] in ('t_type', 'class_cast'): + src_fmt_var = f"__{call_func_name}_fmt" + dst_fmt_var = f"__{VarName}_fmt" + if src_fmt_var in Gen.variables: + if dst_fmt_var not in Gen.variables: + dst_alloca = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) + Gen.variables[dst_fmt_var] = dst_alloca + src_fmt_ptr = Gen._load(Gen.variables[src_fmt_var], name=f"load_{call_func_name}_fmt_for_{VarName}") + Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) + src_kind_var = f"__{call_func_name}_kind" + dst_kind_var = f"__{VarName}_kind" + if src_kind_var in Gen.variables: + if dst_kind_var not in Gen.variables: + dst_kind_alloca = Gen._alloca_entry(ir.IntType(32), name=dst_kind_var) + Gen.variables[dst_kind_var] = dst_kind_alloca + src_kind_val = Gen._load(Gen.variables[src_kind_var], name=f"load_{call_func_name}_kind_for_{VarName}") + Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) + Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} + else: + Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} + elif isinstance(Target, ast.Attribute): + TargetType = None + AttrName = Target.attr + VarName = None + if isinstance(Target.value, ast.Name): + VarName = Target.value.id + if VarName: + ClassName = Gen.var_struct_class.get(VarName) + if not ClassName and getattr(Gen, 'global_struct_class', None): + ClassName = Gen.global_struct_class.get(VarName) + if ClassName: + Gen.var_struct_class[VarName] = ClassName + if not ClassName: + for CN in Gen.structs: + if VarName == CN.lower() or VarName.startswith(CN): + ClassName = CN + break + if ClassName and ClassName in Gen.class_members: + for m_name, m_type in Gen.class_members[ClassName]: + if m_name == AttrName: + TargetType = m_type + break + Value = self.HandleExprLlvm(Node.value, VarType=TargetType) + if Value: + self._HandleAttributeStoreLlvm(Target, Value) + elif isinstance(Target, ast.Subscript): + TargetType = None + SubVarName = None + if isinstance(Target.value, ast.Name): + SubVarName = Target.value.id + if SubVarName in Gen.var_struct_class: + ClassName = Gen.var_struct_class[SubVarName] + if ClassName in Gen.class_members: + for m_name, m_type in Gen.class_members[ClassName]: + if m_name == SubVarName: + if isinstance(m_type, ir.PointerType): + pointee = m_type.pointee + if isinstance(pointee, ir.ArrayType): + TargetType = pointee.element + elif isinstance(m_type, ir.ArrayType): + TargetType = m_type.element + break + if not TargetType and isinstance(Target.value, ast.Name): + SubVarName = Target.value.id + var_val = Gen.variables.get(SubVarName) + if var_val is None and SubVarName in Gen._direct_values: + var_val = Gen._direct_values[SubVarName] + if var_val is not None: + var_type = var_val.type + if isinstance(var_type, ir.PointerType): + pointee = var_type.pointee + if isinstance(pointee, ir.ArrayType): + TargetType = pointee.element + elif isinstance(var_type, ir.ArrayType): + TargetType = var_type.element + Value = self.HandleExprLlvm(Node.value, VarType=TargetType) + if Value: + self._HandleSubscriptStoreLlvm(Target, Value) + elif isinstance(Target, ast.Tuple): + if isinstance(Node.value, ast.Call): + FuncName = None + module_path = None + if isinstance(Node.value.func, ast.Name): + FuncName = Node.value.func.id + elif isinstance(Node.value.func, ast.Attribute): + FuncName = Node.value.func.attr + module_path = self.Trans.ExprCallHandle._get_module_path(Node.value.func.value) + CReturnTypes = [] + FuncDef = self.Trans.FunctionDefCache.get(FuncName) if FuncName else None + if FuncDef: + if FuncDef.returns and isinstance(FuncDef.returns, ast.Subscript): + if isinstance(FuncDef.returns.value, ast.Name) and FuncDef.returns.value.id == 'tuple': + slice_node = FuncDef.returns.slice + if isinstance(slice_node, ast.Tuple): + CReturnTypes = slice_node.elts + else: + CReturnTypes = [slice_node] + if FuncDef.decorator_list: + for decorator in FuncDef.decorator_list: + if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): + if decorator.func.attr == 'CReturn': + for arg in decorator.args: + CReturnTypes.append(arg) + if not CReturnTypes and FuncName: + func = Gen.functions.get(FuncName) + if func: + func_ft = getattr(func, 'ftype', None) + if func_ft: + ret_type = func_ft.return_type + if isinstance(ret_type, ir.LiteralStructType): + CReturnTypes = [None] * len(ret_type.elements) + if not CReturnTypes: + sym_key = FuncName + if sym_key not in self.Trans.SymbolTable: + if module_path: + sym_key = f"{module_path}.{FuncName}" + sym_info = self.Trans.SymbolTable.get(sym_key) + if sym_info and sym_info.IsFunction: + ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) + param_type_infos = [pt for _, pt in getattr(sym_info, 'FuncPtrParams', [])] + if ret_type_info: + if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: + ret_type = ret_type_info.ToLLVM(Gen) + else: + ret_type = Gen._type_str_to_llvm(str(ret_type_info) if ret_type_info else 'i32', False) + if isinstance(ret_type, ir.LiteralStructType): + CReturnTypes = [None] * len(ret_type.elements) + if FuncName not in Gen.functions: + if isinstance(ret_type, ir.VoidType): + ret_type = ir.IntType(32) + llvm_param_types = [] + for pt in param_type_infos: + if isinstance(pt, CTypeInfo) and pt.BaseType: + lp = pt.ToLLVM(Gen) + else: + lp = Gen._type_str_to_llvm(str(pt) if pt else 'i32', '*' in str(pt) if isinstance(pt, str) else False) + if isinstance(lp, ir.VoidType): + lp = ir.IntType(8).as_pointer() + llvm_param_types.append(lp) + func_type = ir.FunctionType(ret_type, llvm_param_types) + MangledName = Gen._mangle_func_name(FuncName) + func_decl = ir.Function(Gen.module, func_type, name=MangledName) + Gen.functions[MangledName] = func_decl + Gen.functions[FuncName] = func_decl + if not CReturnTypes and FuncName: + func = Gen.functions.get(FuncName) + if func: + func_ft = getattr(func, 'ftype', None) + if func_ft: + ret_type = func_ft.return_type + if isinstance(ret_type, ir.LiteralStructType): + CReturnTypes = [None] * len(ret_type.elements) + if CReturnTypes and len(Target.elts) == len(CReturnTypes): + CallArgs = [] + for arg in Node.value.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + for kw in Node.value.keywords: + pass + func = Gen.functions.get(FuncName) + func_ft = getattr(func, 'ftype', None) if func else None + func_params = list(getattr(func_ft, 'args', []) or []) if func_ft else [] + while len(CallArgs) < len(func_params): + FuncDef = self.Trans.FunctionDefCache.get(FuncName) + if FuncDef and len(CallArgs) < len(FuncDef.args.args): + arg_def = FuncDef.args.defaults + arg_idx = len(CallArgs) + total_args = len(FuncDef.args.args) + default_start = total_args - len(arg_def) + if arg_idx >= default_start: + def_idx = arg_idx - default_start + if def_idx < len(arg_def): + DefVal = self.HandleExprLlvm(arg_def[def_idx]) + if DefVal: + expected_type = func_params[arg_idx] + if DefVal.type != expected_type: + if isinstance(expected_type, ir.IntType) and isinstance(DefVal.type, ir.IntType): + if DefVal.type.width < expected_type.width: + DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}") + elif DefVal.type.width > expected_type.width: + DefVal = Gen.builder.trunc(DefVal, expected_type, name=f"trunc_default_{arg_idx}") + CallArgs.append(DefVal) + continue + if len(CallArgs) < len(func_params): + CallArgs.append(ir.Constant(func_params[len(CallArgs)], 0)) + else: + break + adjusted = Gen._adjust_args(CallArgs, func) + call_result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") + func_ft = getattr(func, 'ftype', None) + ret_type = getattr(func_ft, 'return_type', None) if func_ft else None + for j, elt in enumerate(Target.elts): + if isinstance(elt, ast.Name): + VarName = elt.id + field_val = Gen.builder.extract_value(call_result, j, name=f"extract_{FuncName}_{j}") + if CReturnTypes[j] is not None: + ReturnTypeInfo = CTypeInfo.FromNode(CReturnTypes[j], self.Trans.SymbolTable) + if ReturnTypeInfo is None: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + VarType = Gen._ctype_to_llvm(ReturnTypeInfo) + elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements): + VarType = ret_type.elements[j] + else: + VarType = field_val.type + if isinstance(VarType, ir.VoidType): + VarType = ir.IntType(32) + var = Gen._alloca(VarType, name=VarName) + Gen.variables[VarName] = var + if CReturnTypes[j] is not None: + Gen._record_var_signedness(VarName, ReturnTypeStr) + elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements): + elem_type = ret_type.elements[j] + if isinstance(elem_type, ir.IntType): + if elem_type.width == 16: + Gen._record_var_signedness(VarName, 'unsigned short') + elif elem_type.width == 32: + Gen._record_var_signedness(VarName, 'unsigned int') + elif elem_type.width == 64: + Gen._record_var_signedness(VarName, 'unsigned long long') + Gen._store(field_val, var) + return + + def _InitStructAtPtr(self, call_node, ClassName, VarPtr): + Gen = self.Trans.LlvmGen + if ClassName not in Gen.structs: + return + StructType = Gen.structs[ClassName] + StructPtrType = ir.PointerType(StructType) + RawPtr = Gen._load(VarPtr, name=getattr(VarPtr, 'name', 'ptr')) + StructPtr = Gen.builder.bitcast(RawPtr, StructPtrType, name=ClassName) + members = Gen.class_members.get(ClassName, []) + defaults = Gen.class_member_defaults.get(ClassName, {}) + member_values = {} + for member_name, member_type in members: + if member_name in defaults: + member_values[member_name] = defaults[member_name] + if call_node.args: + for i, arg in enumerate(call_node.args): + if i < len(members): + member_name, _ = members[i] + val = self.HandleExprLlvm(arg) + if val: + member_values[member_name] = val + if call_node.keywords: + for kw in call_node.keywords: + val = self.HandleExprLlvm(kw.value) + if val: + member_values[kw.arg] = val + has_vtable = ClassName in Gen.class_vtable + base = 1 if has_vtable else 0 + for i, (member_name, member_type) in enumerate(members): + if isinstance(member_type, ir.VoidType): + continue + if member_name in member_values: + ElemPtr = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"{ClassName}_{member_name}") + try: + Gen._store(member_values[member_name], ElemPtr) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + InitFuncName = f'{ClassName}.__init__' + if Gen._has_function(InitFuncName): + Args = [self.HandleExprLlvm(arg) for arg in call_node.args] + Args = [a for a in Args if a] + Gen.builder.call(Gen._get_function(InitFuncName), [StructPtr] + Args, name=f"call_{InitFuncName}") + + def _StoreOrStrCopy(self, VarName, VarPtr, Value): + Gen = self.Trans.LlvmGen + DestPtr = Gen._load(VarPtr, name=VarName) + if BaseHandle._is_char_pointer(DestPtr): + if BaseHandle._is_char_pointer(Value): + if 'strcpy' not in Gen.functions: + strcpy_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]) + Gen.functions['strcpy'] = ir.Function(Gen.module, strcpy_type, name='strcpy') + Gen.builder.call(Gen.functions['strcpy'], [DestPtr, Value]) + return + try: + CastedVal = Gen.builder.bitcast(Value, VarPtr.type.pointee, name=f"cast_{VarName}") + Gen._store(CastedVal, VarPtr) + except Exception: # 回退:bitcast 失败时 alloca 新变量 + NewVar = Gen._alloca_entry(Value.type, name=VarName) + Gen._store(Value, NewVar) + Gen.variables[VarName] = NewVar + + def _HandleAttributeStoreLlvm(self, Target, Value): + Gen = self.Trans.LlvmGen + AttrName = Target.attr + if isinstance(Target.value, ast.Name) and Target.value.id == 'self': + ClassName = self.Trans._CurrentCpythonObjectClass + if ClassName and ClassName in Gen.structs: + PropKey = f'{ClassName}.{AttrName}' + PropInfo = self.Trans.SymbolTable.get(PropKey) + if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: + SelfVar = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + SetterFunc = Gen._get_function(PropKey) + if SetterFunc and SelfPtr: + Gen.builder.call(SetterFunc, [SelfPtr, Value], name=f"prop_set_{PropKey}") + return + SelfVar = Gen._get_var_ptr('self') + if not SelfVar: + return + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + is_vtable_method = False + if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes: + if ClassName in Gen.class_methods: + for mi, mn in enumerate(Gen.class_methods[ClassName]): + method_short = mn.split('.')[-1] if '.' in mn else mn + if method_short == AttrName or mn == AttrName: + is_vtable_method = True + method_idx = mi + break + if is_vtable_method: + VtableSlotPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") + VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") + methods = Gen.class_methods[ClassName] + VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + ClassVtable = Gen.Vtables.get(ClassName) + if ClassVtable: + ClassVtableAddr = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}") + IsSameVtable = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}") + CopyBlock = Gen.func.append_basic_block(name=f"vtable_copy_self_{AttrName}") + SkipBlock = Gen.func.append_basic_block(name=f"vtable_skip_self_{AttrName}") + Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock) + Gen.builder.position_at_end(CopyBlock) + if not hasattr(Gen, '_vtable_copy_counter'): + Gen._vtable_copy_counter = 0 + Gen._vtable_copy_counter += 1 + CopyName = f"{Gen._mangle_name(ClassName)}_vtable_copy_self_{Gen._vtable_copy_counter}" + VtableCopyGlobal = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName) + VtableCopyGlobal.linkage = 'internal' + VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) + VtableCopyTyped = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed") + SrcTyped = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed") + VtableSize = len(methods) * Gen.ptr_size + MemcpyFunc = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64') + if not MemcpyFunc: + MemcpyType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) + MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64') + Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc + Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)]) + VtableCopyGlobalAddr = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr") + Gen._store(VtableCopyGlobalAddr, VtableSlotPtr) + Gen.builder.branch(SkipBlock) + Gen.builder.position_at_end(SkipBlock) + VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy") + VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") + MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}") + FuncPtrI8 = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") + Gen._store(FuncPtrI8, MethodPtrAddr) + return + offset = Gen._get_member_offset(AttrName, ClassName) + struct_type = Gen.structs[ClassName] + max_offset = len(struct_type.elements) if isinstance(struct_type, ir.IdentifiedStructType) else 0 + if offset >= max_offset: + VarName = f"self.{AttrName}" + if VarName not in Gen.variables: + NewVar = Gen._alloca_entry(Value.type, name=AttrName) + Gen.variables[VarName] = NewVar + Gen._store(Value, Gen.variables[VarName]) + return + MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + elif isinstance(Target.value, ast.Name): + VarName = Target.value.id + ClassName = Gen.var_struct_class.get(VarName) + + if not ClassName and getattr(Gen, 'global_struct_class', None): + ClassName = Gen.global_struct_class.get(VarName) + if ClassName: + Gen.var_struct_class[VarName] = ClassName + + if not ClassName: + for CN in Gen.structs: + if VarName == CN.lower() or VarName.startswith(CN): + ClassName = CN + break + + if not ClassName and VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(GVar.type.pointee) + if found: + ClassName = found[0] + Gen.var_struct_class[VarName] = ClassName + if getattr(Gen, 'global_struct_class', None): + Gen.global_struct_class[VarName] = ClassName + + if not ClassName and VarName in Gen.variables: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType): + pointee = VarPtr.type.pointee + if isinstance(pointee, ir.PointerType): + pointee = pointee.pointee + found = Gen.find_struct_by_pointee(pointee) + if found: + CN, ST = found + ClassName = CN + + IsUnion = False + if ClassName and ClassName in self.Trans.SymbolTable: + TypeInfo = self.Trans.SymbolTable[ClassName] + if TypeInfo.IsUnion: + IsUnion = True + + if ClassName and ClassName in Gen.structs: + PropKey = f'{ClassName}.{AttrName}' + PropInfo = self.Trans.SymbolTable.get(PropKey) + if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: + ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + SetterFunc = Gen._get_function(PropKey) + if SetterFunc and ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{ClassName}") + Gen.builder.call(SetterFunc, [ObjVal, Value], name=f"prop_set_{PropKey}") + return + ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + if ObjVal: + if BaseHandle._is_char_pointer(ObjVal): + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{ClassName}") + if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: + if IsUnion: + NestedStructName = f"{ClassName}_{AttrName}" + if NestedStructName in Gen.structs: + NestedStructType = Gen.structs[NestedStructName] + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") + offset = Gen._get_member_offset(AttrName, NestedStructName) + if offset is not None and offset < len(NestedStructType.elements): + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + return + bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {}) + if AttrName in bitfield_offsets: + self._store_bitfield_member(ObjVal, ClassName, AttrName, Value) + return + bitfields = Gen.class_member_bitfields.get(ClassName, {}) + if AttrName in bitfields and bitfields[AttrName] > 0: + if ClassName not in Gen.class_member_bitoffsets: + Gen.class_member_bitoffsets[ClassName] = {} + if AttrName not in Gen.class_member_bitoffsets[ClassName]: + bo = 0 + for bf_name, bf_width in bitfields.items(): + if bf_name == AttrName: + break + bo += bf_width + Gen.class_member_bitoffsets[ClassName][AttrName] = bo + self._store_bitfield_member(ObjVal, ClassName, AttrName, Value) + return + is_vtable_method = False + if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes: + if ClassName in Gen.class_methods: + for mi, mn in enumerate(Gen.class_methods[ClassName]): + method_short = mn.split('.')[-1] if '.' in mn else mn + if method_short == AttrName or mn == AttrName: + is_vtable_method = True + method_idx = mi + break + if is_vtable_method: + VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") + VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") + methods = Gen.class_methods[ClassName] + VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + ClassVtable = Gen.Vtables.get(ClassName) + if ClassVtable: + ClassVtableAddr = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}") + IsSameVtable = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}") + CopyBlock = Gen.func.append_basic_block(name=f"vtable_copy_{AttrName}") + SkipBlock = Gen.func.append_basic_block(name=f"vtable_skip_{AttrName}") + Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock) + Gen.builder.position_at_end(CopyBlock) + if not hasattr(Gen, '_vtable_copy_counter'): + Gen._vtable_copy_counter = 0 + Gen._vtable_copy_counter += 1 + CopyName = f"{Gen._mangle_name(ClassName)}_vtable_copy_{Gen._vtable_copy_counter}" + VtableCopyGlobal = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName) + VtableCopyGlobal.linkage = 'internal' + VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) + VtableCopyTyped = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed") + SrcTyped = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed") + VtableSize = len(methods) * Gen.ptr_size + MemcpyFunc = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64') + if not MemcpyFunc: + MemcpyType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) + MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64') + Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc + Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)]) + VtableCopyGlobalAddr = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr") + Gen._store(VtableCopyGlobalAddr, VtableSlotPtr) + Gen.builder.branch(SkipBlock) + Gen.builder.position_at_end(SkipBlock) + VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy") + VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") + MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}") + FuncPtrI8 = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") + Gen._store(FuncPtrI8, MethodPtrAddr) + return + offset = Gen._get_member_offset(AttrName, ClassName) + StructType = Gen.structs.get(ClassName) + if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + StructType = Gen.structs.get(ClassName) + if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): + return + if StructType is not None and StructType.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(StructType), name=f"cast_{ClassName}") + if offset is not None and StructType is not None and StructType.elements is not None and offset < len(StructType.elements): + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + else: + return + + byte_order = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "") + + if byte_order == 'big': + st = Gen.structs.get(ClassName) + if st is None or st.elements is None or len(st.elements) == 0: + return + member_type = st.elements[offset] + if isinstance(member_type, ir.IntType): + if member_type.width == 16: + Value = Gen.builder.bswap(Value, name=f"bswap_store_{AttrName}") + elif member_type.width == 32: + Value = Gen.builder.bswap(Value, name=f"bswap_store_{AttrName}") + elif member_type.width == 64: + Value = Gen.builder.bswap(Value, name=f"bswap_store_{AttrName}") + + self._StoreWithCoerce(Value, MemberPtr) + if not ClassName: + imported_modules = getattr(self.Trans, '_imported_modules', None) + import_aliases = getattr(self.Trans, '_import_aliases', {}) + resolved_mod = import_aliases.get(VarName, VarName) + if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): + PossibleKeys = [f"{VarName}.{AttrName}", AttrName] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + key = f"{mod_name}.{AttrName}" + if key not in PossibleKeys: + PossibleKeys.append(key) + for key in PossibleKeys: + if key in Gen.module.globals: + GVar = Gen.module.globals[key] + if isinstance(GVar, ir.Function): + return + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return + self._StoreWithCoerce(Value, GVar) + return + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + sha1_candidates = [VarName, resolved_mod] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + if mod_name not in sha1_candidates: + sha1_candidates.append(mod_name) + for cand in sha1_candidates: + sha1 = module_sha1_map.get(cand) + if sha1: + prefixed = f"{sha1}.{AttrName}" + if prefixed in Gen.module.globals: + GVar2 = Gen.module.globals[prefixed] + if isinstance(GVar2, ir.Function): + return + if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return + self._StoreWithCoerce(Value, GVar2) + return + elif isinstance(Target.value, ast.Attribute): + ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + if ObjVal and isinstance(ObjVal.type, ir.PointerType): + pointee = ObjVal.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None: + for CN, ST in Gen.structs.items(): + if isinstance(ST, ir.IdentifiedStructType) and ST.name == pointee.name and ST.elements is not None: + pointee = ST + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") + break + found_match = False + for CN, ST in Gen.structs.items(): + if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): + found_match = True + if ST.elements is None: + self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) + ST = Gen.structs.get(CN, ST) + if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") + bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {}) + if AttrName in bitfield_offsets: + self._store_bitfield_member(ObjVal, CN, AttrName, Value) + return + offset = Gen._get_member_offset(AttrName, CN) + if offset is not None and ST.elements is not None and offset < len(ST.elements): + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + break + if not found_match: + if isinstance(pointee, ir.IdentifiedStructType): + matched_cn = None + for CN in Gen.class_members: + members = Gen.class_members[CN] + for mname, mtype in members: + if mname == AttrName: + matched_cn = CN + break + if matched_cn: + break + if matched_cn and matched_cn in Gen.structs: + ST = Gen.structs[matched_cn] + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(matched_cn, Gen) + ST = Gen.structs.get(matched_cn, ST) + if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{matched_cn}") + offset = Gen._get_member_offset(AttrName, matched_cn) + if offset is not None and ST.elements is not None and offset < len(ST.elements): + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + return + elif isinstance(Target.value, ast.Call): + # Check if this is c.Deref(...) — we need the pointer, not the loaded value + ObjVal = None + is_cderef = (isinstance(Target.value.func, ast.Attribute) and + isinstance(Target.value.func.value, ast.Name) and + Target.value.func.value.id == 'c' and + Target.value.func.attr == 'Deref' and + Target.value.args) + if is_cderef: + # Get the pointer from c.Deref argument, don't load the value + deref_arg = Target.value.args[0] + inner_val = self.HandleExprLlvm(deref_arg) + if inner_val and isinstance(inner_val.type, ir.PointerType): + if isinstance(inner_val.type.pointee, ir.PointerType): + ObjVal = Gen._load(inner_val, name="deref_load_ptr") + else: + ObjVal = inner_val + if ObjVal is None: + ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + if ObjVal and isinstance(ObjVal.type, ir.PointerType): + pointee = ObjVal.type.pointee + if isinstance(pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr") + pointee = ObjVal.type.pointee + for CN, ST in Gen.structs.items(): + if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) + ST = Gen.structs.get(CN, ST) + if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") + bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {}) + if AttrName in bitfield_offsets: + self._store_bitfield_member(ObjVal, CN, AttrName, Value) + return + offset = Gen._get_member_offset(AttrName, CN) + if offset is not None and ST.elements is not None and offset < len(ST.elements): + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + break + elif isinstance(Target.value, ast.Subscript): + SubPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) + if SubPtr and isinstance(SubPtr.type, ir.PointerType): + pointee = SubPtr.type.pointee + + if isinstance(Target.value.value, ast.Attribute): + AttrNameSub = Target.value.value.attr + if AttrNameSub == 'items' and 'Item' in Gen.structs: + ObjValCast = Gen.builder.bitcast(SubPtr, ir.PointerType(Gen.structs['Item']), name=f"cast_Item") + offset = Gen._get_member_offset(AttrName, 'Item') + MemberPtr = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + return + + if BaseHandle._is_char_pointer(SubPtr): + for CN, ST in Gen.structs.items(): + ObjValCast = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}") + offset = Gen._get_member_offset(AttrName, CN) + MemberPtr = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + break + elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found = Gen.find_struct_by_pointee(pointee) + if found: + CN, ST = found + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) + ST = Gen.structs.get(CN, ST) + if ST.elements is not None and isinstance(SubPtr.type, ir.PointerType) and isinstance(SubPtr.type.pointee, ir.IdentifiedStructType) and SubPtr.type.pointee.elements is None: + SubPtr = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}") + offset = Gen._get_member_offset(AttrName, CN) + if offset is not None and ST.elements is not None and offset < len(ST.elements): + MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + elif isinstance(pointee, ir.PointerType): + LoadedPtr = Gen._load(SubPtr, name=f"load_{AttrName}_ptr") + if isinstance(LoadedPtr.type, ir.PointerType) and isinstance(LoadedPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(LoadedPtr.type.pointee) + if found: + CN, ST = found + offset = Gen._get_member_offset(AttrName, CN) + MemberPtr = Gen.builder.gep(LoadedPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + + def _HandleSubscriptStoreLlvm(self, Target, Value): + Gen = self.Trans.LlvmGen + if isinstance(Target.value, ast.Name): + SubVarName = Target.value.id + if SubVarName in Gen.var_const_flags: + src_info = Gen._get_node_info() + self.Trans.LogError(f"不能对 const 变量 '{SubVarName}' 的元素赋值{src_info}") + ClassName = self.Trans.ExprHandler._get_var_class(Target.value, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__setitem__'): + obj_val = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + idx_val = self.Trans.ExprHandler.HandleExprLlvm(Target.slice) + if obj_val and idx_val: + if BaseHandle._is_char_pointer(obj_val): + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Gen.builder.call(Gen._get_function(f'{ClassName}.__setitem__'), [obj_val, idx_val, Value], name=f"call_{ClassName}.__setitem__") + return + ValueVal = self.HandleExprLlvm(Target.value) + IndexVal = self.HandleExprLlvm(Target.slice) + if not ValueVal or not IndexVal: + return + if BaseHandle._is_char_pointer(IndexVal): + loaded_byte = Gen._load(IndexVal, name="load_char_idx_store") + IndexVal = Gen.builder.zext(loaded_byte, ir.IntType(32), name="char_to_int_idx_store") + if isinstance(ValueVal.type, ir.IntType): + var_ptr = self._get_int_ptr(Target.value) + if var_ptr: + i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr_store") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index_store") + ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr_store") + self._StoreWithCoerce(Value, ptr) + return + if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + self._StoreWithCoerce(Value, ElemPtr) + return + if isinstance(ValueVal.type, ir.PointerType): + pointee = ValueVal.type.pointee + if isinstance(pointee, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") + else: + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + self._StoreWithCoerce(Value, ElemPtr) + elif isinstance(ValueVal.type, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(Target.value, ast.Name): + VarName = Target.value.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") + self._StoreWithCoerce(Value, ElemPtr) + return + if isinstance(Target.value, ast.Subscript): + InnerPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) + if InnerPtr: + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript") + self._StoreWithCoerce(Value, ElemPtr) + return + if isinstance(Target.value, ast.Attribute): + AttrPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") + self._StoreWithCoerce(Value, ElemPtr) + return + arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp") + Gen._store(ValueVal, arr_alloc) + ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") + self._StoreWithCoerce(Value, ElemPtr) + ModifiedArr = Gen._load(arr_alloc, name="modified_arr") + if isinstance(Target.value, ast.Subscript): + OuterPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) + if OuterPtr: + Gen._store(ModifiedArr, OuterPtr) + elif isinstance(Target.value, ast.Attribute): + OuterPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value) + if OuterPtr: + Gen._store(ModifiedArr, OuterPtr) + + def _StoreWithCoerce(self, Value, Ptr): + Gen = self.Trans.LlvmGen + if isinstance(Ptr.type, ir.PointerType): + TargetType = Ptr.type.pointee + if Value.type != TargetType: + if isinstance(TargetType, ir.ArrayType) and isinstance(Value.type, ir.PointerType): + ElemType = TargetType.element + ElemSize = Gen._get_struct_size(ElemType) + for i in range(TargetType.count): + DstElem = Gen.builder.gep(Ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"arr_dst_{i}") + if ElemSize == 1: + SrcPtr = Gen.builder.gep(Value, [ir.Constant(ir.IntType(32), i)], name=f"arr_src_{i}") + else: + PtrInt = Gen.builder.ptrtoint(Value, ir.IntType(64)) + Offset = ir.Constant(ir.IntType(64), i * ElemSize) + NewPtrInt = Gen.builder.add(PtrInt, Offset) + SrcPtr = Gen.builder.inttoptr(NewPtrInt, ir.PointerType(ElemType), name=f"arr_src_{i}") + SrcVal = Gen._load(SrcPtr, name=f"arr_elem_{i}") + if SrcVal.type != ElemType: + try: + SrcVal = Gen.builder.bitcast(SrcVal, ElemType, name=f"arr_cast_{i}") + except Exception: # 回退:bitcast 失败时跳过该元素 + continue + Gen._store(SrcVal, DstElem) + return + if isinstance(TargetType, ir.PointerType) and isinstance(Value, ir.Constant) and Value.constant is None: + Value = ir.Constant(TargetType, None) + elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType): + try: + Value = Gen.builder.bitcast(Value, TargetType, name="null_ptr_bitcast") + except Exception: # 回退:bitcast 失败时设为 null 常量 + Value = ir.Constant(TargetType, None) + else: + Coerced = Gen._coerce_value(Value, TargetType) + if Coerced is not None: + Value = Coerced + Gen._store(Value, Ptr) + + + def _get_int_ptr(self, target): + Gen = self.Trans.LlvmGen + if isinstance(target, ast.Name): + VarName = target.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType): + pointee = VarPtr.type.pointee + if isinstance(pointee, ir.ArrayType): + return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") + return None + + def _EmitGlobalAnnAssignLlvm(self, Node, Gen): + if isinstance(Node.target, ast.Name): + VarName = Node.target.id + EffectiveAnnotation = Node.annotation + if VarName in self.Trans.SymbolTable: + Info = self.Trans.SymbolTable[VarName] + if Info.get('type') == 'typedef': + return + if isinstance(EffectiveAnnotation, ast.BinOp) and isinstance(EffectiveAnnotation.op, ast.BitOr): + for side in [EffectiveAnnotation.left, EffectiveAnnotation.right]: + if isinstance(side, ast.Subscript) and isinstance(side.value, ast.Name) and side.value.id == 'list': + EffectiveAnnotation = side + break + if isinstance(EffectiveAnnotation, ast.Subscript) and isinstance(EffectiveAnnotation.value, ast.Name) and EffectiveAnnotation.value.id == 'list': + slice_node = EffectiveAnnotation.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + elem_type_node = slice_node.elts[0] + count_node = slice_node.elts[1] + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + SymEntry = self.Trans.SymbolTable.get(elem_type_node.id) + if SymEntry and isinstance(SymEntry, CTypeInfo) and SymEntry.IsFuncPtr: + ElemType = ir.IntType(8).as_pointer() + else: + ElemType = Gen.structs[elem_type_node.id] + else: + ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable) + if ElemTypeInfo and ElemTypeInfo.IsFuncPtr: + ElemType = ir.IntType(8).as_pointer() + else: + if ElemTypeInfo is None: + ElemTypeInfo = CTypeInfo() + ElemTypeInfo.BaseType = t.CInt() + ElemType = Gen._ctype_to_llvm(ElemTypeInfo) + if isinstance(ElemType, ir.VoidType): + ElemType = ir.IntType(32) + ArrayCount = 1 + if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int): + ArrayCount = count_node.value + elif isinstance(count_node, ast.Name): + if count_node.id in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[count_node.id] + if isinstance(getattr(SymInfo, 'value', None), int): + ArrayCount = SymInfo.value + if ArrayCount == 1 and count_node.id in getattr(Gen, '_define_constants', {}): + DefVal = Gen._define_constants[count_node.id] + if isinstance(DefVal, int): + ArrayCount = DefVal + elif isinstance(count_node, ast.Attribute): + ev = self._eval_global_count(count_node, Gen) + if ev is not None: + ArrayCount = ev + elif isinstance(count_node, ast.BinOp): + ev = self._eval_global_count(count_node, Gen) + if ev is not None: + ArrayCount = ev + elif count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None): + if Node.value and isinstance(Node.value, ast.List): + ArrayCount = len(Node.value.elts) + elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): + ArrayCount = len(Node.value.value) + 1 + VarType = ir.ArrayType(ElemType, ArrayCount) + if VarName not in Gen.variables and VarName not in Gen.module.globals: + GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) + if isinstance(ElemType, ir.IdentifiedStructType): + GlobalVar.linkage = 'common' + elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): + str_val = Node.value.value + '\x00' + str_bytes = bytearray(str_val, 'utf-8') + if len(str_bytes) < ArrayCount: + str_bytes.extend(b'\x00' * (ArrayCount - len(str_bytes))) + try: + GlobalVar.initializer = ir.Constant(VarType, str_bytes[:ArrayCount]) + except Exception: # 回退:初始化常量失败时用零值 + GlobalVar.initializer = self._zero_value(VarType) + else: + InitConstants = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen) + if InitConstants: + GlobalVar.initializer = ir.Constant(VarType, InitConstants) + elif ArrayCount > 256: + GlobalVar.linkage = 'common' + else: + if self._contains_identified_struct(VarType): + GlobalVar.linkage = 'common' + else: + GlobalVar.initializer = ir.Constant(VarType, [ir.Constant(ElemType, ir.Undefined)] * ArrayCount) + Gen.variables[VarName] = GlobalVar + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + Gen.global_struct_class[VarName] = elem_type_node.id + return + if isinstance(EffectiveAnnotation, ast.Subscript) and isinstance(EffectiveAnnotation.value, ast.Name) and EffectiveAnnotation.value.id == 'list': + slice_node = EffectiveAnnotation.slice + elem_type_node = slice_node + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + ElemType = Gen.structs[elem_type_node.id] + else: + ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable) + if ElemTypeInfo is None: + ElemTypeInfo = CTypeInfo() + ElemTypeInfo.BaseType = t.CInt() + ElemType = Gen._ctype_to_llvm(ElemTypeInfo) + if isinstance(ElemType, ir.VoidType): + ElemType = ir.IntType(32) + VarType = ir.PointerType(ElemType) + if VarName not in Gen.variables and VarName not in Gen.module.globals: + GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) + GlobalVar.initializer = ir.Constant(VarType, None) + Gen.variables[VarName] = GlobalVar + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + Gen.global_struct_class[VarName] = elem_type_node.id + return + if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: + StructName = Node.annotation.id + VarType = Gen.structs[StructName] + if VarName not in Gen.variables and VarName not in Gen.module.globals: + GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) + if Node.value and isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == StructName: + const = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen) + if const: + GlobalVar.initializer = const + else: + GlobalVar.initializer = ir.Constant(VarType, None) + else: + GlobalVar.initializer = ir.Constant(VarType, None) + Gen.variables[VarName] = GlobalVar + Gen.global_struct_class[VarName] = StructName + return + TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) + if not TypeInfo or not TypeInfo.BaseType: + ArrayTypeInfo = CTypeInfo._HandleArraySubscript(Node.annotation, self.Trans.SymbolTable) + if ArrayTypeInfo: + TypeInfo = ArrayTypeInfo + IsCDefine = False + if TypeInfo and TypeInfo.BaseType: + if isinstance(TypeInfo.BaseType, t._CTypedef): + return + if isinstance(TypeInfo.BaseType, t.CDefine): + IsCDefine = True + if not IsCDefine and self._IsTypedefAnnotation(Node.annotation): + IsCDefine = True + TTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) + if TTypeInfo: + TTypeInfo.IsTypedef = True + TTypeInfo.Name = VarName + self.Trans.SymbolTable[VarName] = TTypeInfo + if IsCDefine: + if Node.value: + define_constants = vars(Gen).setdefault('_define_constants', {}) + try: + const_value = self._eval_const_expr(Node.value, Gen) + if const_value is not None: + define_constants[VarName] = const_value + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + return + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + VarType = Gen._ctype_to_llvm(TypeInfo) + if isinstance(VarType, ir.VoidType): + VarType = ir.IntType(32) + if VarName in Gen.variables or VarName in Gen.module.globals: + return + if isinstance(VarType, (ir.IdentifiedStructType, ir.LiteralStructType)): + GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) + GlobalVar.initializer = ir.Constant(VarType, None) + Gen.variables[VarName] = GlobalVar + if TypeInfo and TypeInfo.IsStruct and TypeInfo.Name: + Gen.global_struct_class[VarName] = TypeInfo.Name + return + GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) + if Node.value: + if isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) and isinstance(VarType, ir.PointerType): + str_val = Node.value.value + '\x00' + str_bytes = str_val.encode('utf-8') + arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + str_gv_name = VarName + '_str' + if str_gv_name not in Gen.module.globals: + str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name) + str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) + str_gv.linkage = 'internal' + else: + str_gv = Gen.module.globals[str_gv_name] + ptr_type = ir.PointerType(ir.IntType(8)) + if VarName not in Gen.module.globals: + ptr_gv = ir.GlobalVariable(Gen.module, ptr_type, name=VarName) + ptr_gv.initializer = ir.Constant(ptr_type, str_gv) + ptr_gv.linkage = 'internal' + else: + ptr_gv = Gen.module.globals[VarName] + Gen.variables[VarName] = ptr_gv + else: + if isinstance(VarType, ir.ArrayType) and isinstance(Node.value, (ast.List, ast.Set)): + InitConstants = self.Trans._BuildMultiDimArrayInitConstants(Node.value, VarType, Gen) + if InitConstants: + GlobalVar.initializer = ir.Constant(VarType, InitConstants) + else: + if self._contains_identified_struct(VarType): + GlobalVar.linkage = 'common' + else: + zv = self._zero_value(VarType) + if zv: + GlobalVar.initializer = zv + else: + GlobalVar.linkage = 'common' + else: + init_val = self._eval_global_const(Node.value, VarType, Gen) + if init_val: + GlobalVar.initializer = init_val + elif isinstance(VarType, ir.BaseStructType): + GlobalVar.linkage = 'common' + else: + GlobalVar.initializer = self._zero_value(VarType) + else: + if isinstance(VarType, ir.BaseStructType) or self._contains_identified_struct(VarType): + GlobalVar.linkage = 'common' + else: + GlobalVar.initializer = self._zero_value(VarType) + Gen.variables[VarName] = GlobalVar + + def _eval_global_const(self, value_node, var_type, Gen): + if isinstance(value_node, ast.Constant): + if isinstance(value_node.value, bool): + if isinstance(var_type, ir.IntType): + return ir.Constant(var_type, int(value_node.value)) + elif isinstance(value_node.value, int): + if isinstance(var_type, ir.IntType): + return ir.Constant(var_type, value_node.value) + elif isinstance(var_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(var_type, float(value_node.value)) + elif isinstance(value_node.value, float): + if isinstance(var_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(var_type, value_node.value) + elif isinstance(var_type, ir.IntType): + return ir.Constant(var_type, int(value_node.value)) + elif isinstance(value_node.value, str): + return None + # Handle type constructor calls like t.CDouble(1e-9), t.CFloat(3.14), t.CInt(42) + if isinstance(value_node, ast.Call): + inner_val = self._eval_type_ctor_const(value_node, var_type, Gen) + if inner_val is not None: + return inner_val + if isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.USub): + inner = self._eval_global_const(value_node.operand, var_type, Gen) + if inner: + return ir.Constant(var_type, -inner.constant) + return None + + def _eval_type_ctor_const(self, call_node, var_type, Gen): + """Try to evaluate t.CDouble(val), t.CFloat(val), t.CInt(val) etc. as a compile-time constant.""" + if not isinstance(call_node.func, ast.Attribute): + return None + if not isinstance(call_node.func.value, ast.Name): + return None + if call_node.func.value.id != 't': + return None + if not call_node.args or len(call_node.args) != 1: + return None + arg = call_node.args[0] + # Recursively evaluate the argument as a constant + arg_val = self._eval_global_const(arg, var_type, Gen) + if arg_val is not None: + return arg_val + return None + + def _store_bitfield_member(self, struct_ptr, ClassName, field_name, Value): + Gen = self.Trans.LlvmGen + bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {}) + bitfield_widths = Gen.class_member_bitfields.get(ClassName, {}) + if field_name not in bitfield_offsets: + return False + bit_offset = bitfield_offsets[field_name] + bit_width = bitfield_widths.get(field_name, 0) + if bit_width == 0: + return False + struct_type = Gen.structs.get(ClassName) + if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0: + return False + storage_type = struct_type.elements[0] + member_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr") + old_val = Gen._load(member_ptr, name=f"{field_name}_old_storage") + mask = (1 << bit_width) - 1 + shifted_mask = mask << bit_offset + inverted_mask = ir.Constant(storage_type, ~shifted_mask & ((1 << storage_type.width) - 1)) + cleared = Gen.builder.and_(old_val, inverted_mask, name=f"{field_name}_cleared") + if isinstance(Value.type, ir.IntType) and Value.type.width < storage_type.width: + if getattr(Value.type, 'is_signed', False): + Value = Gen.builder.sext(Value, storage_type, name=f"{field_name}_sext_store") + else: + Value = Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store") + elif Value.type.width != storage_type.width: + Value = Gen.builder.trunc(Value, storage_type, name=f"{field_name}_trunc_store") if Value.type.width > storage_type.width else Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store") + shifted_value = Gen.builder.shl(Value, ir.Constant(storage_type, bit_offset), name=f"{field_name}_shift_store") + masked_value = Gen.builder.and_(shifted_value, ir.Constant(storage_type, shifted_mask), name=f"{field_name}_mask_store") + new_val = Gen.builder.or_(cleared, masked_value, name=f"{field_name}_new_storage") + Gen._store(new_val, member_ptr) + return True + + def _CheckEnumMemberAssignment(self, node): + def _get_attr_path(n): + if isinstance(n, ast.Name): + return n.id + elif isinstance(n, ast.Attribute): + return f"{_get_attr_path(n.value)}.{n.attr}" + return None + attr_path = _get_attr_path(node) + if not attr_path: + return None + parts = attr_path.split('.') + if len(parts) >= 2: + enum_class_name = parts[-2] + member_name = parts[-1] + qualified_name = f"{enum_class_name}.{member_name}" + if qualified_name in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[qualified_name] + if info.IsEnumMember and info.EnumName: + return info.EnumName + under_name = f"{enum_class_name}_{member_name}" + if under_name in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[under_name] + if info.IsEnumMember and info.EnumName: + return info.EnumName + for key in self.Trans.SymbolTable: + if key == member_name: + info = self.Trans.SymbolTable[key] + if info.IsEnumMember and info.EnumName and info.EnumName == enum_class_name: + return enum_class_name + return None + + def _IsTypedefAnnotation(self, annotation): + if isinstance(annotation, ast.Attribute): + if annotation.attr in ('CTypedef', 'CDefine'): + return True + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return self._IsTypedefAnnotation(annotation.left) or self._IsTypedefAnnotation(annotation.right) + if isinstance(annotation, ast.Subscript): + return self._IsTypedefAnnotation(annotation.value) + return False + + def _EmitGlobalAssignLlvm(self, Node, Gen): + if len(Node.targets) == 1 and isinstance(Node.targets[0], ast.Name): + VarName = Node.targets[0].id + if VarName in Gen.variables or VarName in Gen.module.globals: + return + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): + FuncName = Node.value.func.id + if FuncName in Gen.structs: + IsUnion = False + if FuncName in self.Trans.SymbolTable: + TypeInfo = self.Trans.SymbolTable[FuncName] + if TypeInfo.IsUnion: + IsUnion = True + if IsUnion: + StructType = Gen.structs[FuncName] + StructPtrType = ir.PointerType(StructType) + GlobalVar = ir.GlobalVariable(Gen.module, StructPtrType, name=VarName) + GlobalVar.initializer = ir.Constant(StructPtrType, None) + Gen.variables[VarName] = GlobalVar + Gen.global_struct_class[VarName] = FuncName + return + StructName = FuncName + VarType = Gen.structs[StructName] + GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) + const = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen) + if const: + GlobalVar.initializer = const + else: + GlobalVar.linkage = 'common' + Gen.variables[VarName] = GlobalVar + Gen.global_struct_class[VarName] = StructName + return + GlobalVar = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName) + init_val = self._eval_global_const(Node.value, ir.IntType(32), Gen) + GlobalVar.initializer = init_val if init_val else ir.Constant(ir.IntType(32), 0) + Gen.variables[VarName] = GlobalVar + + def _eval_const_expr(self, node, Gen): + """计算常量表达式的值""" + import ast + if isinstance(node, ast.Constant): + return node.value + elif isinstance(node, ast.BinOp): + left = self._eval_const_expr(node.left, Gen) + right = self._eval_const_expr(node.right, Gen) + if left is None or right is None: + return None + if isinstance(node.op, ast.Add): + return left + right + elif isinstance(node.op, ast.Sub): + return left - right + elif isinstance(node.op, ast.Mult): + return left * right + elif isinstance(node.op, ast.Div): + return left // right if isinstance(left, int) and isinstance(right, int) else left / right + elif isinstance(node.op, ast.FloorDiv): + return left // right + elif isinstance(node.op, ast.Mod): + return left % right + elif isinstance(node.op, ast.Pow): + return left ** right + elif isinstance(node.op, ast.LShift): + return left << right + elif isinstance(node.op, ast.RShift): + return left >> right + elif isinstance(node.op, ast.BitOr): + return left | right + elif isinstance(node.op, ast.BitXor): + return left ^ right + elif isinstance(node.op, ast.BitAnd): + return left & right + elif isinstance(node, ast.UnaryOp): + operand = self._eval_const_expr(node.operand, Gen) + if operand is None: + return None + if isinstance(node.op, ast.USub): + return -operand + elif isinstance(node.op, ast.UAdd): + return +operand + elif isinstance(node.op, ast.Invert): + return ~operand + elif isinstance(node, ast.Name): + if node.id in getattr(Gen, '_define_constants', {}): + return Gen._define_constants[node.id] + if node.id in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[node.id] + val = getattr(SymInfo, 'value', None) + if isinstance(val, (int, float)): + return val + if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)): + return SymInfo.DefineValue + elif isinstance(node, ast.Attribute): + module_name = node.value.id if isinstance(node.value, ast.Name) else None + attr_name = node.attr + if module_name and attr_name: + combined_key = f"{module_name}.{attr_name}" + if combined_key in getattr(Gen, '_define_constants', {}): + val = Gen._define_constants[combined_key] + if isinstance(val, (int, float)): + return int(val) if isinstance(val, float) and val == int(val) else val + for key, SymInfo in self.Trans.SymbolTable.items(): + if key.endswith(f".{combined_key}") or key == combined_key: + if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)): + return int(SymInfo.DefineValue) if isinstance(SymInfo.DefineValue, float) and SymInfo.DefineValue == int(SymInfo.DefineValue) else SymInfo.DefineValue + all_dc = getattr(self.Trans, '_all_define_constants', None) or getattr(Gen, '_all_define_constants', {}) + if combined_key in all_dc: + val = all_dc[combined_key] + if isinstance(val, (int, float)): + return int(val) if isinstance(val, float) and val == int(val) else val + if attr_name in all_dc: + val = all_dc[attr_name] + if isinstance(val, (int, float)): + return int(val) if isinstance(val, float) and val == int(val) else val + for dc_key, dc_val in all_dc.items(): + if dc_key == attr_name or dc_key.endswith(f".{attr_name}"): + if isinstance(dc_val, (int, float)): + return int(dc_val) if isinstance(dc_val, float) and dc_val == int(dc_val) else dc_val + if attr_name in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[attr_name] + if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)): + return int(SymInfo.DefineValue) if isinstance(SymInfo.DefineValue, float) and SymInfo.DefineValue == int(SymInfo.DefineValue) else SymInfo.DefineValue + if attr_name in getattr(Gen, '_define_constants', {}): + val = Gen._define_constants[attr_name] + if isinstance(val, (int, float)): + return int(val) if isinstance(val, float) and val == int(val) else val + return None + + def _eval_global_count(self, node, Gen): + val = self._eval_const_expr(node, Gen) + if val is not None: + if isinstance(val, float): + return int(val) + if isinstance(val, int): + return val + return None diff --git a/lib/core/Handles/HandlesAugAssign.py b/lib/core/Handles/HandlesAugAssign.py new file mode 100644 index 0000000..575bd6e --- /dev/null +++ b/lib/core/Handles/HandlesAugAssign.py @@ -0,0 +1,212 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class AugAssignHandle(BaseHandle): + _AUGOP_MAP = { + ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__', + ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__', + } + _AUGOP_FALLBACK = { + ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__', + ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__', + } + + def _is_aug_unsigned(self, Node, OldVal, Value): + """判断增量赋值操作是否应使用无符号指令""" + Gen = self.Trans.LlvmGen + if isinstance(Node.target, ast.Name): + if Gen._check_node_unsigned(Node.target): + return True + elif isinstance(Node.target, ast.Attribute): + if Gen._check_node_unsigned(Node.target): + return True + elif isinstance(Node.target, ast.Subscript): + if Gen._check_node_unsigned(Node.target): + return True + if Node.value is not None and Gen._check_node_unsigned(Node.value): + return True + return False + + def _HandleAugAssignLlvm(self, Node): + Gen = self.Trans.LlvmGen + if isinstance(Node.target, ast.Name): + VarName = Node.target.id + if VarName in Gen.var_const_flags: + src_info = Gen._get_node_info() + print(f"[错误] 不能对 const 变量 '{VarName}' 增量赋值{src_info}") + import sys + sys.exit(1) + ClassName = Gen.var_struct_class.get(VarName) + iop_name = self._AUGOP_MAP.get(type(Node.op)) + if ClassName and iop_name: + iFuncName = f'{ClassName}.{iop_name}' + FuncName = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}' + if iFuncName in Gen.functions or FuncName in Gen.functions: + OldVal = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load())) + Value = self.HandleExprLlvm(Node.value) + if OldVal and Value: + if iFuncName in Gen.functions: + result = self.Trans.ExprHandler._try_operator_overload(ClassName, iop_name, OldVal, Gen, Value) + else: + result = self.Trans.ExprHandler._try_operator_overload(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value) + if result is not None: + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if VarPtr.type.pointee == result.type: + Gen._store(result, VarPtr) + elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType): + CastedVal = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}") + Gen._store(CastedVal, VarPtr) + else: + NewVar = Gen._alloca_entry(result.type, name=VarName) + Gen._store(result, NewVar) + Gen.variables[VarName] = NewVar + else: + Gen._reg_values[VarName] = result + Gen.variables[VarName] = None + return + Value = self.HandleExprLlvm(Node.value) + if not Value: + return + is_unsigned = self._is_aug_unsigned(Node, None, Value) + if isinstance(Node.target, ast.Name): + VarName = Node.target.id + Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if VarName in Gen.global_vars and VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + Gen.variables[VarName] = GVar + OldVal = Gen._load(GVar, name=VarName) + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + Gen._store(NewVal, GVar) + return + if VarName in Gen._reg_values: + OldVal = Gen._reg_values[VarName] + saved_block = Gen.builder.block + entry_block = Gen.func.entry_basic_block + Gen.builder.position_at_start(entry_block) + var = Gen.builder.alloca(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.builder.position_at_end(saved_block) + Gen.variables[VarName] = var + del Gen._reg_values[VarName] + if VarName in Gen._direct_values: + OldVal = Gen._direct_values.pop(VarName) + saved_block = Gen.builder.block + entry_block = Gen.func.entry_basic_block + Gen.builder.position_at_start(entry_block) + var = Gen.builder.alloca(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.builder.position_at_end(saved_block) + Gen.variables[VarName] = var + if Gen.builder.block.is_terminated: + return + if VarName in Gen.variables and Gen.variables[VarName] is not None: + OldVal = Gen._load(Gen.variables[VarName], name=VarName) + store_ptr = Gen.variables[VarName] + if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Value.type.width != 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset") + if Op == '-' or Op == '+': + if Op == '-': + NegValue = Gen.builder.neg(Value, name="neg_ptr_offset") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add") + else: + ptr_val = OldVal + OldVal = Gen._load(OldVal, name="deref_ptr_for_op") + orig_type = OldVal.type + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType): + if NewVal.type.width > orig_type.width: + NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result") + store_ptr = ptr_val + else: + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") + elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Op in ('+', '-'): + if Value.type.width < 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug") + if Op == '-': + NegValue = Gen.builder.neg(Value, name="neg_ptr_offset_aug") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug") + Gen._store(NewVal, store_ptr) + return + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(store_ptr.type, ir.PointerType): + TargetType = store_ptr.type.pointee + if NewVal.type != TargetType: + Coerced = Gen._coerce_value(NewVal, TargetType) + if Coerced is not None: + NewVal = Coerced + Gen._store(NewVal, store_ptr) + elif VarName == 'pos': + var = Gen._alloca_entry(Value.type, name=VarName) + Gen.variables[VarName] = var + OldVal = Gen._load(var, name=VarName) + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + Gen._store(NewVal, var) + elif isinstance(Node.target, ast.Attribute): + AttrName = Node.target.attr + OldVal = self.Trans.ExprHandler.HandleExprLlvm(Node.target) + if OldVal: + def _deref_if_ptr(val): + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): + return Gen._load(val, name="deref_aug") + return val + OldVal = _deref_if_ptr(OldVal) + Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr") + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal) + elif isinstance(Node.target, ast.Subscript): + SubTarget = Node.target + ElemPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget) + if ElemPtr: + if isinstance(ElemPtr.type, ir.PointerType): + OldVal = Gen._load(ElemPtr, name="old_subscript_val") + Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub") + elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Op in ('+', '-'): + if Value.type.width < 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub") + if Op == '-': + NegValue = Gen.builder.neg(Value, name="neg_ptr_offset_sub") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub") + Gen._store(NewVal, ElemPtr) + return + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType): + if NewVal.type.width > ElemPtr.type.pointee.width: + NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result") + Gen._store(NewVal, ElemPtr) diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py new file mode 100644 index 0000000..60b7983 --- /dev/null +++ b/lib/core/Handles/HandlesBase.py @@ -0,0 +1,1364 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.constants import config as _config +from lib.includes import t + +import ast +from typing import List, Dict +from enum import IntFlag, auto + + +EXCEPTION_CODE_MAP = { + 'ValueError': 1, 'TypeError': 2, 'RuntimeError': 3, + 'ZeroDivisionError': 4, 'IndexError': 5, 'KeyError': 6, + 'IOError': 7, 'OSError': 8, 'AssertionError': 9, 'Exception': 99, +} + + +class FuncMeta(IntFlag): + NONE = 0 + STATIC_METHOD = auto() + PROPERTY_GETTER = auto() + PROPERTY_SETTER = auto() + PROPERTY_DELETER = auto() + CLASS_METHOD = auto() + ABSTRACT = auto() + + +class CTypeInfo: + """ + C 类型信息对象 - 统一符号表条目和类型计算 + + 设计原则: + - BaseType 是 CType 实例(来自 t 模块),永远不使用硬编码字符串 + - 描述符分为两种: + - VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const + - DataConst/DataVolatile: 指向数据的限定符,如 const int * + + 属性(类型计算): + - BaseType: t.CType - 基础类型实例 (如 t.CInt(), t.CVoid()) + - PtrCount: int - 指针层数 + - VarConst: bool - 变量本身(指针)是否 const,如 int * const + - VarVolatile: bool - 变量本身(指针)是否 volatile + - DataConst: bool - 指向的数据是否 const,如 const int * + - DataVolatile: bool - 指向的数据是否 volatile + - ArrayDims: List[str] - 数组维度 + - Storage: t.CType - 存储类 (static, extern 等) + - IsFuncPtr: bool - 是否函数指针 + - FuncPtrParams: List[Tuple[str, CTypeInfo]] - 函数指针参数列表,每个元素是 (参数名, 参数类型) + - FuncPtrReturn: CTypeInfo - 函数指针返回类型 + - IsBitField: bool - 是否位域 + - BitWidth: int - 位域宽度 + - IsTypedef/IsStruct/IsEnum/IsUnion: bool - 类型种类 + + 属性(符号表元数据): + - Name: str - 名称(struct/enum/union/typedef 名) + - Members: Dict[str, CTypeInfo] - 成员字典(用于 struct/union) + - OriginalType: str - typedef 的原始类型 + - DeclaredType: str - 声明类型 + - CreturnTypes: list - C 返回类型列表 + - Lineno: int - 定义行号 + - IsAnonymous: bool - 是否匿名类型 + - IsCpythonObject: bool - 是否 CPython 对象 + - IsEnumMember: bool - 是否枚举成员 + """ + + def __init__(self): + self._BaseType: t.CType = None + self.PtrCount: int = 0 + self.VarConst: bool = False + self.VarVolatile: bool = False + self.DataConst: bool = False + self.DataVolatile: bool = False + self.ArrayDims: List[str] = [] + self.Storage: t.CType = None + self.IsFuncPtr: bool = False + self.FuncPtrParams: List[Tuple[str, 'CTypeInfo']] = [] # 函数指针参数列表:(参数名, 参数类型) + self.FuncParamNames: List[str] = [] # 函数参数名列表 + self.FuncPtrReturn: "CTypeInfo" = None + self.IsBitField: bool = False + self.BitWidth: int = 0 + self.ByteOrder: str = "" # "big", "little", or "" + self.IsTypedef: bool = False + self.IsStruct: bool = False + self.IsEnum: bool = False + self.IsUnion: bool = False + self.IsRenum: bool = False + self.RenumVariants: list = [] + self.Name: str = "" + self.Members: Dict[str, 'CTypeInfo'] = {} + self.OriginalType: "CTypeInfo" = None + self.DeclaredType: str = "" + self.CreturnTypes: list = [] + self.Lineno: int = 0 + self.file: str = "" + self.IsAnonymous: bool = False + self.IsCpythonObject: bool = False + self.IsEnumMember: bool = False + self.IsVariadic: bool = False + self.IsVariable: bool = False + self.IsFunction: bool = False + self.MetaList: FuncMeta = FuncMeta.NONE + self.IsArrayPtr: bool = False + self.ArrayPtr: 'CTypeInfo' = None + self.IsState: bool = False + self.IsDefine: bool = False + self.DefineValue = None + self.IsInline: bool = False + self.InlineBody: list = None + self.InlineParams: list = None + self.ModuleName: str = "" + self._extra: dict = {} + + + + @property + def BaseType(self) -> t.CType | tuple: + return self._BaseType + + @BaseType.setter + def BaseType(self, value: t.CType | type | tuple | List): + """设置 BaseType,接受以下类型: + + - None: 清空 + - t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志 + - type (CType 子类): 如 t.CStruct,自动实例化 + - tuple/list of t.CType: 多个组合类型 + """ + if value is None: + self._BaseType = None + self.IsStruct = False + self.IsEnum = False + self.IsUnion = False + self.IsRenum = False + return + + if isinstance(value, (tuple, list)): + self._BaseType = tuple(value) + for v in value: + if isinstance(v, t.CStruct): + self.IsStruct = True + elif isinstance(v, t.CEnum): + self.IsEnum = True + elif isinstance(v, t.CUnion): + self.IsUnion = True + elif isinstance(v, t.REnum): + self.IsRenum = True + self.IsEnum = True + return + + if isinstance(value, type) and issubclass(value, t.CType): + self._BaseType = value() + return + + if isinstance(value, t.CType): + self._BaseType = value + if isinstance(value, t.CStruct): + self.IsStruct = True + self.IsEnum = False + self.IsUnion = False + self.IsRenum = False + elif isinstance(value, t.REnum): + self.IsRenum = True + self.IsEnum = True + self.IsStruct = False + self.IsUnion = False + elif isinstance(value, t.CEnum): + self.IsEnum = True + self.IsStruct = False + self.IsUnion = False + self.IsRenum = False + elif isinstance(value, t.CUnion): + self.IsUnion = True + self.IsStruct = False + self.IsEnum = False + self.IsRenum = False + return + + raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}") + + @property + def TypeCls(self): + """获取 CType 类(从 BaseType 推断)""" + if self.BaseType: + return type(self.BaseType) + if self.IsStruct: + return t.CStruct + if self.IsEnum: + return t.CEnum + if self.IsUnion: + return t.CUnion + if self.IsTypedef: + return t._CTypedef + return None + + @property + def IsPtr(self) -> bool: + return self.PtrCount > 0 + + @property + def IsVoid(self) -> bool: + return isinstance(self.BaseType, t.CVoid) + + @property + def IsStr(self) -> bool: + return isinstance(self.BaseType, t.CChar) and self.PtrCount > 0 + + @property + def IsInt(self) -> bool: + return isinstance(self.BaseType, t.CType) and getattr(self.BaseType, 'IsSigned', None) is not None and self.BaseType.IsSigned is True and not self.IsVoid + + @property + def IsUInt(self) -> bool: + return isinstance(self.BaseType, t.CType) and getattr(self.BaseType, 'IsSigned', None) is False + + @property + def IsFloat(self) -> bool: + bt = self.BaseType + return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, t.CVoid) + + @property + def IsDouble(self) -> bool: + return isinstance(self.BaseType, t.CDouble) or (isinstance(self.BaseType, t.CFloat64T)) + + @property + def IsPointerToChar(self) -> bool: + return isinstance(self.BaseType, t.CChar) and self.PtrCount > 0 + + def ToString(self) -> str: + if self.IsFuncPtr: + return 'Callable' + parts = [] + + if self.Storage and not isinstance(self.Storage, t.CExport): + parts.append(self.Storage.CName) + + if self.DataConst or self.DataVolatile: + qualifiers = [] + if self.DataConst: + qualifiers.append("const") + if self.DataVolatile: + qualifiers.append("volatile") + parts.append("_".join(qualifiers)) + + if self.IsTypedef and self.Name: + return self.Name + elif self.IsRenum and self.Name: + base_name = self.Name + elif self.BaseType: + base_name = getattr(self.BaseType, 'CName', None) or (self.BaseType if isinstance(self.BaseType, str) else str(self.BaseType)) + else: + base_name = "void" + + if self.IsArrayPtr: + ptr_str = "" + if self.PtrCount > 0: + ptr_str = "*" * self.PtrCount + if self.ArrayPtr: + inner = self.ArrayPtr.ToString() + if ptr_str: + parts.append(f"{base_name} {ptr_str}({inner})") + else: + parts.append(f"{base_name} ({inner})") + else: + if ptr_str: + parts.append(f"{base_name} {ptr_str}()") + else: + parts.append(f"{base_name} ()") + elif self.ArrayPtr: + inner = self.ArrayPtr.ToString() + if self.PtrCount > 0: + parts.append(f"{base_name} {'*' * self.PtrCount}({inner})") + else: + parts.append(f"{base_name} ({inner})") + else: + parts.append(base_name) + if self.PtrCount > 0: + parts.append("*" * self.PtrCount) + if self.VarConst: + parts.append("const") + if self.VarVolatile: + parts.append("volatile") + + for dim in self.ArrayDims: + if dim: + parts.append(f"[{dim}]") + else: + parts.append("[]") + + return " ".join(parts) if parts else "void" + + @staticmethod + def CreateFromTypeName(TypeName: str) -> "CTypeInfo": + """从类型名字符串创建 CTypeInfo(兼容旧 API)""" + info = CTypeInfo() + if TypeName.startswith('struct '): + info.BaseType = t.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else t.CStruct() + elif TypeName.startswith('enum '): + info.BaseType = t.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else t.CEnum() + elif TypeName.startswith('union '): + info.BaseType = t.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else t.CUnion() + else: + info.BaseType = t.CStruct(name=TypeName) + return info + + # LLVM primitive type name → (CTypeClass, PtrCount) mapping + # Used when generic type inference produces LLVM type names like 'i64', 'double', etc. + _LLVM_PRIMITIVE_MAP = None + + @classmethod + def _get_llvm_primitive_map(cls): + if cls._LLVM_PRIMITIVE_MAP is not None: + return cls._LLVM_PRIMITIVE_MAP + from lib.includes import t as _t + cls._LLVM_PRIMITIVE_MAP = { + 'void': (_t.CVoid, 0), + 'i1': (_t.CInt, 0), + 'i8': (_t.CChar, 0), + 'i16': (_t.CShort, 0), + 'i32': (_t.CInt, 0), + 'i64': (_t.CLong, 0), + 'i128': (_t.CInt, 0), + 'float': (_t.CFloat, 0), + 'double': (_t.CDouble, 0), + 'fp128': (_t.CFloat128T, 0), + } + return cls._LLVM_PRIMITIVE_MAP + + @staticmethod + def FromTypeName(TypeName: str) -> "CTypeInfo": + """从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)""" + from lib.core.Handles.HandlesBase import BuiltinTypeMap + + # Handle pointer types like 'CUInt32T *', 'void *', etc. + ptr_count = 0 + base_name = TypeName + while base_name.endswith(' *') or base_name.endswith('*'): + ptr_count += 1 + base_name = base_name.rstrip(' *').rstrip() + + entry = BuiltinTypeMap.Get(base_name) + if entry: + TypeClass, base_ptr = entry + info = CTypeInfo() + info.BaseType = TypeClass + info.PtrCount = base_ptr + ptr_count + return info + # Handle LLVM primitive type names (e.g., 'i64', 'double' from generic type inference) + llvm_map = CTypeInfo._get_llvm_primitive_map() + llvm_entry = llvm_map.get(base_name) + if llvm_entry: + TypeClass, base_ptr = llvm_entry + info = CTypeInfo() + info.BaseType = TypeClass + info.PtrCount = base_ptr + ptr_count + return info + # Fallback with pointer count + info = CTypeInfo.CreateFromTypeName(TypeName) + if ptr_count > 0: + info.PtrCount = ptr_count + return info + + # FromStr 已移除 - 类型解析不再经过中间字符串格式 + # typedef 展开直接走 CTypeInfo 对象,不经过字符串解析 + + @staticmethod + def TryEvalConstExpr(node, SymbolTable): + if isinstance(node, ast.Constant) and isinstance(node.value, int): + return node.value + if isinstance(node, ast.BinOp): + left = CTypeInfo.TryEvalConstExpr(node.left, SymbolTable) + right = CTypeInfo.TryEvalConstExpr(node.right, SymbolTable) + if left is None or right is None: + return None + if isinstance(node.op, ast.Add): + return left + right + elif isinstance(node.op, ast.Sub): + return left - right + elif isinstance(node.op, ast.Mult): + return left * right + elif isinstance(node.op, ast.FloorDiv): + return left // right if right != 0 else None + elif isinstance(node.op, ast.Mod): + return left % right if right != 0 else None + elif isinstance(node.op, ast.LShift): + return left << right + elif isinstance(node.op, ast.RShift): + return left >> right + elif isinstance(node.op, ast.BitOr): + return left | right + elif isinstance(node.op, ast.BitAnd): + return left & right + elif isinstance(node.op, ast.BitXor): + return left ^ right + elif isinstance(node.op, ast.Pow): + return left ** right + return None + if isinstance(node, ast.UnaryOp): + operand = CTypeInfo.TryEvalConstExpr(node.operand, SymbolTable) + if operand is None: + return None + if isinstance(node.op, ast.USub): + return -operand + elif isinstance(node.op, ast.UAdd): + return +operand + elif isinstance(node.op, ast.Invert): + return ~operand + return None + if isinstance(node, ast.Name): + if node.id in SymbolTable: + info = SymbolTable[node.id] + if getattr(info, 'IsDefine', None) and isinstance(getattr(info, 'DefineValue', None), int): + return info.DefineValue + if isinstance(node, ast.Attribute): + parts = [] + current = node + while isinstance(current, ast.Attribute): + parts.append(current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.append(current.id) + parts.reverse() + attr_name = parts[-1] + possible_keys = [attr_name, '.'.join(parts)] + for key in possible_keys: + if key in SymbolTable: + info = SymbolTable[key] + if getattr(info, 'IsDefine', None) and isinstance(getattr(info, 'DefineValue', None), int): + return info.DefineValue + if len(parts) >= 2: + for mod_key, mod_info in SymbolTable.items(): + if getattr(mod_info, 'IsDefine', None) and isinstance(getattr(mod_info, 'DefineValue', None), int): + if mod_key.endswith('.' + attr_name) or mod_key == attr_name: + return mod_info.DefineValue + return None + + @classmethod + def FromNode(cls, Node: ast.AST, SymbolTable: dict) -> "CTypeInfo": + """从 AST 节点解析 CTypeInfo(类方法) + + Args: + Node: AST 节点(如 ast.Name, ast.Attribute 等) + SymbolTable: 符号表字典 + """ + if isinstance(Node, (ast.Constant, ast.Str)): + return cls._FromNode_Constant(Node, SymbolTable) + if isinstance(Node, ast.Name): + return cls._FromNode_Name(Node, SymbolTable) + if isinstance(Node, ast.Call): + return cls._FromNode_Call(Node, SymbolTable) + if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): + return cls._FromNode_BinOp(Node, SymbolTable) + if isinstance(Node, ast.Subscript): + return cls._FromNode_Subscript(Node, SymbolTable) + if isinstance(Node, ast.Attribute): + return cls._FromNode_Attribute(Node, SymbolTable) + return cls() + + @classmethod + def _FromNode_Constant(cls, Node: ast.AST, SymbolTable: dict) -> "CTypeInfo": + """处理 ast.Constant / ast.Str 节点""" + if isinstance(Node, ast.Constant): + TypeName = Node.value + else: + TypeName = Node.s + return cls.FromTypeName(TypeName) + + @classmethod + def _FromNode_Name(cls, Node: ast.Name, SymbolTable: dict) -> "CTypeInfo": + """处理 ast.Name 节点""" + from lib.includes import t + + TypeName = Node.id + TypeObj = CTypeHelper.GetTModuleCType(TypeName) + if TypeObj is None: + TypeObj = getattr(t, TypeName, None) + if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType) and TypeObj is not t.CType: + if TypeObj == t.CPtr: + Result = cls() + Result.PtrCount = 1 + Result.BaseType = t.CVoid() + return Result + if TypeObj == t.State: + Result = cls() + Result.IsState = True + Result.BaseType = t.CVoid() + return Result + Inst = TypeObj() + Result = cls() + Result.BaseType = TypeObj + if hasattr(Inst, 'CName') and Inst.CName: + Result.Name = Inst.CName + if hasattr(Inst, 'IsSigned'): + Result.IsSigned = Inst.IsSigned + return Result + if TypeName in SymbolTable: + Entry = SymbolTable[TypeName] + if Entry: + if isinstance(Entry, CTypeInfo): + if Entry.IsTypedef: + if Entry.BaseType and (not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0): + Result = Entry.Copy() + Result.IsTypedef = True + Result.Name = TypeName + return Result + if Entry.OriginalType: + if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr: + Result = cls() + Result.IsFuncPtr = True + Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else [] + Result.IsTypedef = True + Result.Name = TypeName + return Result + elif isinstance(Entry.OriginalType, CTypeInfo): + Resolved = Entry.OriginalType.Copy() + elif isinstance(Entry.OriginalType, str) and Entry.OriginalType == 'Callable': + Result = cls() + Result.IsFuncPtr = True + Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = [] + Result.IsTypedef = True + Result.Name = TypeName + return Result + elif isinstance(Entry.OriginalType, str): + Resolved = cls.FromTypeName(Entry.OriginalType) + else: + Resolved = Entry.OriginalType + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + TypeEntry = BuiltinTypeMap.Get(TypeName) + if TypeEntry: + Result = cls() + Result.BaseType = TypeEntry[0]() + Result.PtrCount = TypeEntry[1] + Result.IsTypedef = True + Result.Name = TypeName + return Result + return Entry + if Entry.IsEnum: + Result = cls() + Result.BaseType = t.CInt() + Result.IsEnum = True + Result.Name = TypeName + return Result + if getattr(Entry, 'IsExceptionClass', None): + Result = cls() + Result.BaseType = t.CInt() + Result.IsExceptionClass = True + Result.Name = TypeName + return Result + if Entry.BaseType is None and (Entry.IsStruct or Entry.Name): + Entry.BaseType = t.CStruct(name=TypeName) + Entry.IsStruct = True + return Entry + elif isinstance(Entry, dict): + if Entry.get('type') == 'typedef': + OriginalType = Entry.get('OriginalType', '') + if OriginalType: + if OriginalType == 'Callable': + Result = cls() + Result.IsFuncPtr = True + Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = [] + Result.IsTypedef = True + Result.Name = TypeName + return Result + Resolved = cls.FromTypeName(OriginalType) + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + TypeEntry = BuiltinTypeMap.Get(TypeName) + if TypeEntry: + Result = cls() + Result.BaseType = TypeEntry[0]() + Result.PtrCount = TypeEntry[1] + Result.IsTypedef = True + Result.Name = TypeName + return Result + Result = cls() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + Result.Name = TypeName + return Result + # 特殊处理 str 类型,它应该是 char*(指针) + if TypeName in ('str', 'bytes'): + Result = cls() + Result.BaseType = t.CChar() + Result.PtrCount = 1 + return Result + if TypeName == 'irq_handler_t': + pass + return cls.FromTypeName(TypeName) + + @classmethod + def _FromNode_Call(cls, Node: ast.Call, SymbolTable: dict) -> "CTypeInfo": + """处理 ast.Call 节点""" + from lib.includes import t + + if isinstance(Node.func, ast.Name) and Node.func.id == 'callable': + Result = cls() + Result.IsFuncPtr = True + Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = [] + try: + if len(Node.args) > 0: + RetInfo = cls.FromNode(Node.args[0], SymbolTable) + if RetInfo: + Result.FuncPtrReturn = RetInfo + for kw in Node.keywords: + ParamInfo = cls.FromNode(kw.value, SymbolTable) + if ParamInfo: + Result.FuncPtrParams.append((kw.arg or '', ParamInfo)) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import warnings; warnings.warn(f"异常被忽略: {_e}") + return Result + if isinstance(Node.func, ast.Attribute): + if isinstance(Node.func.value, ast.Name) and Node.func.value.id == 't': + if Node.func.attr == 'Bit' and len(Node.args) > 0: + Result = cls() + Result.BaseType = t.CInt() + Result.IsBitField = True + if isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, int): + Result.BitWidth = Node.args[0].value + else: + Result.BitWidth = 1 + return Result + return cls() + + @classmethod + def _FromNode_BinOp(cls, Node: ast.BinOp, SymbolTable: dict) -> "CTypeInfo": + """处理 ast.BinOp (BitOr) 节点""" + from lib.includes import t + + LeftInfo = cls.FromNode(Node.left, SymbolTable) + RightInfo = cls.FromNode(Node.right, SymbolTable) + + if LeftInfo.IsState or RightInfo.IsState: + Result = cls() + Result.IsState = True + NonStateInfo = LeftInfo if not LeftInfo.IsState else RightInfo + StateInfo = LeftInfo if LeftInfo.IsState else RightInfo + if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0): + Result.BaseType = NonStateInfo.BaseType + elif NonStateInfo.IsTypedef and NonStateInfo.Name: + if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0): + Result.BaseType = NonStateInfo.BaseType + Result.PtrCount = NonStateInfo.PtrCount + Result.IsTypedef = True + Result.Name = NonStateInfo.Name + if NonStateInfo.OriginalType: + Result.OriginalType = NonStateInfo.OriginalType + else: + Result.BaseType = t.CStruct(name=NonStateInfo.Name) + Result.IsStruct = True + Result.IsTypedef = True + Result.Name = NonStateInfo.Name + if NonStateInfo.OriginalType: + Result.OriginalType = NonStateInfo.OriginalType + else: + Result.BaseType = t.CVoid() + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if not Result.Storage: + Result.Storage = t.CExport() + if LeftInfo.Storage and not isinstance(LeftInfo.Storage, t.CExport): + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage and not isinstance(RightInfo.Storage, t.CExport): + Result.Storage = RightInfo.Storage + if LeftInfo.DataConst or RightInfo.DataConst: + Result.DataConst = True + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + return Result + + if LeftInfo.IsPtr or RightInfo.IsPtr: + Result = cls() + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + NonPtrInfo = LeftInfo if not LeftInfo.IsPtr else RightInfo + PtrInfo = RightInfo if RightInfo.IsPtr else LeftInfo + if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0): + Result.BaseType = NonPtrInfo.BaseType + elif NonPtrInfo.IsTypedef and NonPtrInfo.Name: + if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0): + Result.BaseType = NonPtrInfo.BaseType + Result.IsTypedef = True + Result.Name = NonPtrInfo.Name + if NonPtrInfo.OriginalType: + Result.OriginalType = NonPtrInfo.OriginalType + else: + Result.BaseType = t.CStruct(name=NonPtrInfo.Name) + Result.IsStruct = True + elif PtrInfo.BaseType and (not isinstance(PtrInfo.BaseType, (t._CTypedef,)) or PtrInfo.PtrCount > 0): + Result.BaseType = PtrInfo.BaseType + else: + Result.BaseType = t.CUnsignedChar() + if LeftInfo.DataConst or RightInfo.DataConst: + Result.DataConst = True + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + if LeftInfo.DataVolatile or RightInfo.DataVolatile: + Result.DataVolatile = True + if LeftInfo.VarVolatile or RightInfo.VarVolatile: + Result.VarVolatile = True + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + + if LeftInfo.DataConst or RightInfo.DataConst: + Result = cls() + BaseTypeSide = LeftInfo if not LeftInfo.DataConst else RightInfo + QualSide = LeftInfo if LeftInfo.DataConst else RightInfo + Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType + if not Result.BaseType: + Result.BaseType = t.CInt() + Result.DataConst = True + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + if LeftInfo.DataVolatile or RightInfo.DataVolatile: + Result.DataVolatile = True + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + + if LeftInfo.DataVolatile or RightInfo.DataVolatile: + Result = cls() + BaseTypeSide = LeftInfo if not LeftInfo.DataVolatile else RightInfo + QualSide = LeftInfo if LeftInfo.DataVolatile else RightInfo + Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType + if not Result.BaseType: + Result.BaseType = t.CInt() + Result.DataVolatile = True + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + + if LeftInfo.Storage or RightInfo.Storage: + Result = cls() + BaseTypeSide = LeftInfo if not LeftInfo.Storage else RightInfo + StorageSide = LeftInfo if LeftInfo.Storage else RightInfo + if BaseTypeSide.IsState or StorageSide.IsState: + Result.IsState = True + Result.BaseType = t.CVoid() + Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage + return Result + Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else StorageSide.BaseType + if not Result.BaseType: + Result.BaseType = t.CInt() + Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if LeftInfo.DataConst or RightInfo.DataConst: + Result.DataConst = True + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + return Result + + # 检查是否有位域类型 (t.Bit) + if LeftInfo.IsBitField: + Result = cls() + Result.BaseType = LeftInfo.BaseType if LeftInfo.BaseType else t.CInt() + Result.IsBitField = True + Result.BitWidth = LeftInfo.BitWidth + return Result + if RightInfo.IsBitField: + Result = cls() + Result.BaseType = RightInfo.BaseType if RightInfo.BaseType else t.CInt() + Result.IsBitField = True + Result.BitWidth = RightInfo.BitWidth + return Result + + # 处理字节序类型 (t.BigEndian, t.LittleEndian) + if LeftInfo.ByteOrder: + Result = cls() + Result.BaseType = LeftInfo.BaseType if LeftInfo.BaseType else t.CInt() + Result.ByteOrder = LeftInfo.ByteOrder + return Result + if RightInfo.ByteOrder: + Result = cls() + Result.BaseType = RightInfo.BaseType if RightInfo.BaseType else t.CInt() + Result.ByteOrder = RightInfo.ByteOrder + return Result + + if LeftInfo.IsFuncPtr or RightInfo.IsFuncPtr: + Result = cls() + FuncPtrSide = LeftInfo if LeftInfo.IsFuncPtr else RightInfo + Result.IsFuncPtr = True + Result.FuncPtrParams = list(FuncPtrSide.FuncPtrParams) + Result.FuncPtrReturn = FuncPtrSide.FuncPtrReturn + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + + if LeftInfo.IsTypedef and RightInfo.BaseType: + if LeftInfo.BaseType and (not isinstance(LeftInfo.BaseType, (t._CTypedef,)) or LeftInfo.PtrCount > 0): + Result = LeftInfo.Copy() + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + return RightInfo + if RightInfo.IsTypedef and LeftInfo.BaseType: + if RightInfo.BaseType and (not isinstance(RightInfo.BaseType, (t._CTypedef,)) or RightInfo.PtrCount > 0): + Result = RightInfo.Copy() + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + return Result + return LeftInfo + + if LeftInfo.BaseType: + return LeftInfo + elif RightInfo.BaseType: + return RightInfo + return cls() + + @classmethod + def _FromNode_Subscript(cls, Node: ast.Subscript, SymbolTable: dict) -> "CTypeInfo": + """处理 ast.Subscript 节点""" + from lib.includes import t + + base = Node.value + if isinstance(base, ast.Attribute): + if isinstance(base.value, ast.Name) and base.value.id == 't' and base.attr == 'Bit': + Result = cls() + Result.BaseType = t.CInt() + Result.IsBitField = True + if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int): + Result.BitWidth = Node.slice.value + else: + Result.BitWidth = 1 + return Result + if isinstance(base, ast.Name) and base.id == 'list': + slice_node = Node.slice + elts = [] + if isinstance(slice_node, ast.Tuple): + elts = slice_node.elts + elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)): + elts = [slice_node] + if elts: + ElemInfo = cls.FromNode(elts[0], SymbolTable) + if ElemInfo and ElemInfo.BaseType: + Result = cls() + Result.BaseType = ElemInfo.BaseType + Result.PtrCount = ElemInfo.PtrCount + Result.ArrayDims = list(ElemInfo.ArrayDims) + if len(elts) >= 2: + count_val = cls.TryEvalConstExpr(elts[1], SymbolTable) + if count_val is not None and isinstance(count_val, int) and count_val > 0: + Result.ArrayDims.insert(0, str(count_val)) + else: + Result.PtrCount += 1 + if ElemInfo.IsPtr and not ElemInfo.ArrayDims: + Result.PtrCount = max(Result.PtrCount, 1) + return Result + if isinstance(base, ast.Attribute): + parts = [] + current = base + while isinstance(current, ast.Attribute): + parts.insert(0, current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.insert(0, current.id) + if parts and parts[0] == 't' and parts[-1] == t.CPtr.__name__: + Result = cls() + Result.BaseType = t.CVoid() + Result.PtrCount = 1 + slice_node = Node.slice + if isinstance(slice_node, ast.Subscript): + InnerInfo = cls.FromNode(slice_node, SymbolTable) + if InnerInfo: + if InnerInfo.PtrCount > 0: + Result.PtrCount += InnerInfo.PtrCount + if InnerInfo.BaseType and not isinstance(InnerInfo.BaseType, t.CVoid): + Result.BaseType = InnerInfo.BaseType + elif isinstance(slice_node, ast.Attribute): + SliceInfo = cls.FromNode(slice_node, SymbolTable) + if SliceInfo: + if SliceInfo.IsPtr: + Result.PtrCount += SliceInfo.PtrCount + elif SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid): + Result.BaseType = SliceInfo.BaseType + elif isinstance(slice_node, ast.Name): + SliceType = getattr(t, slice_node.id, None) + if SliceType == t.CPtr: + Result.PtrCount += 1 + else: + SliceInfo = cls.FromNode(slice_node, SymbolTable) + if SliceInfo and SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid): + Result.BaseType = SliceInfo.BaseType + return Result + if parts and parts[0] == 't' and parts[-1] == 'Callable': + Result = cls() + Result.IsFuncPtr = True + slice_node = Node.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + params_list = slice_node.elts[0] + return_node = slice_node.elts[1] + ParamTypes = [] + if isinstance(params_list, ast.List): + for elt in params_list.elts: + ParamTypeInfo = cls.FromNode(elt, SymbolTable) + if ParamTypeInfo: + ParamTypes.append(('', ParamTypeInfo)) + if not ParamTypes: + ParamTypes.append(('', cls.FromTypeName('void'))) + Result.FuncPtrParams = ParamTypes + ReturnTypeInfo = cls.FromNode(return_node, SymbolTable) + Result.FuncPtrReturn = ReturnTypeInfo if ReturnTypeInfo else CTypeInfo.VoidTypeInfo() + return Result + return cls() + + @classmethod + def _FromNode_Attribute(cls, Node: ast.Attribute, SymbolTable: dict) -> "CTypeInfo": + """处理 ast.Attribute 节点""" + from lib.includes import t + + ModuleParts = [] + Current = Node + while isinstance(Current, ast.Attribute): + ModuleParts.insert(0, Current.attr) + Current = Current.value + + if isinstance(Current, ast.Name): + ModuleParts.insert(0, Current.id) + + if len(ModuleParts) >= 2: + TypeName = ModuleParts[-1] + ModulePath = '.'.join(ModuleParts[:-1]) + elif len(ModuleParts) == 1: + TypeName = ModuleParts[0] + ModulePath = None + else: + return cls() + + # 解析 import 别名: 如 import vpsdk.window as window -> window -> vpsdk.window + if ModulePath: + resolved = False + if hasattr(SymbolTable, 'translator'): + import_aliases = getattr(SymbolTable.translator, '_import_aliases', {}) + if ModulePath in import_aliases: + ModulePath = import_aliases[ModulePath] + resolved = True + if not resolved and ModulePath in SymbolTable: + entry = SymbolTable[ModulePath] + if isinstance(entry, CTypeInfo) and getattr(entry, 'IsModuleAlias', False): + resolved_name = getattr(entry, 'ResolvedModule', None) + if resolved_name: + ModulePath = resolved_name + + if ModulePath == 't' or (ModulePath and ModulePath.startswith('t.')): + TypeClass = CTypeHelper.GetTModuleCType(TypeName) + if TypeClass is None: + TypeClass = getattr(t, TypeName, None) + if TypeClass is not None and TypeClass.HasPosition(t.CType.POINTER): + Info = cls() + Info.PtrCount = 1 + if TypeClass == t.CArrayPtr: + Info.IsArrayPtr = True + Info.BaseType = t.CVoid + return Info + if TypeClass is not None and TypeClass.IsStorageClass(): + Info = cls() + Info.Storage = TypeClass() + if TypeClass == t.State: + Info.IsState = True + Info.BaseType = t.CVoid() + return Info + if TypeClass is not None and TypeClass.IsTypeQualifier(): + Info = cls() + if TypeClass == t.CConst: + Info.DataConst = True + elif TypeClass == t.CVolatile: + Info.DataVolatile = True + return Info + if (TypeClass is not None + and isinstance(TypeClass, type) + and issubclass(TypeClass, t.CType) + and TypeClass is not t.CType + and TypeClass.HasPosition(t.CType.BASE)): + if TypeClass == t.State: + Result = cls() + Result.IsState = True + Result.BaseType = t.CVoid() + return Result + Inst = TypeClass() + Result = cls() + Result.BaseType = TypeClass + if hasattr(Inst, 'CName') and Inst.CName: + Result.Name = Inst.CName + if hasattr(Inst, 'IsSigned'): + Result.IsSigned = Inst.IsSigned + return Result + CNAME = CTypeHelper.GetCName(TypeName) + if CNAME: + return cls.FromTypeName(CNAME) + + # 处理字节序类型 + if TypeName == 'BigEndian': + Result = cls() + Result.BaseType = t.CInt() + Result.ByteOrder = 'big' + return Result + if TypeName == 'LittleEndian': + Result = cls() + Result.BaseType = t.CInt() + Result.ByteOrder = 'little' + return Result + + FullName = f"{ModulePath}.{TypeName}" if ModulePath else TypeName + + if TypeName in SymbolTable: + Entry = SymbolTable[TypeName] + if Entry and getattr(Entry, 'IsTypedef', None): + Resolved = Entry.Copy() + if Resolved.BaseType is None: + Resolved.BaseType = t._CTypedef(TypeName) + return Resolved + if Entry and getattr(Entry, 'IsEnum', None): + Result = cls() + Result.BaseType = t.CInt() + Result.IsEnum = True + Result.Name = TypeName + return Result + if Entry and getattr(Entry, 'IsExceptionClass', None): + Result = cls() + Result.BaseType = t.CInt() + Result.IsExceptionClass = True + Result.Name = TypeName + return Result + if Entry: + Result = Entry.Copy() + if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name): + Result.BaseType = t.CStruct(name=TypeName) + Result.IsStruct = True + return Result + return cls() + + if FullName in SymbolTable: + Info = SymbolTable[FullName] + if Info and Info.IsTypedef: + OriginalType = Info.get('OriginalType', '') + if OriginalType and 'typedef' in OriginalType: + parts = OriginalType.split() + if len(parts) >= 2: + base_type_name = parts[1] + if not base_type_name.startswith('C'): + base_type_name = 'C' + base_type_name + CNAME = CTypeHelper.GetCName(base_type_name) + if CNAME: + return cls.FromTypeName(CNAME) + Result = cls() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + return Result + if Info: + Result = Info.Copy() + if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name): + Result.BaseType = t.CStruct(name=TypeName) + Result.IsStruct = True + return Result + return cls() + + return cls() + + @classmethod + def _HandleArraySubscript(cls, Node, SymbolTable): + if not isinstance(Node, ast.Subscript): + return None + dims = [] + current = Node + while isinstance(current, ast.Subscript): + if isinstance(current.slice, ast.Constant) and isinstance(current.slice.value, int): + dims.insert(0, str(current.slice.value)) + elif isinstance(current.slice, ast.Name): + dims.insert(0, current.slice.id) + else: + return None + current = current.value + base_info = cls.FromNode(current, SymbolTable) + if base_info and base_info.BaseType: + base_info.ArrayDims = dims + return base_info + return None + + def Copy(self) -> "CTypeInfo": + NewInfo = CTypeInfo() + NewInfo.BaseType = self.BaseType + NewInfo.PtrCount = self.PtrCount + NewInfo.VarConst = self.VarConst + NewInfo.VarVolatile = self.VarVolatile + NewInfo.DataConst = self.DataConst + NewInfo.DataVolatile = self.DataVolatile + NewInfo.ArrayDims = list(self.ArrayDims) + NewInfo.Storage = self.Storage + NewInfo.IsFuncPtr = self.IsFuncPtr + NewInfo.FuncPtrParams = list(self.FuncPtrParams) + NewInfo.FuncParamNames = list(self.FuncParamNames) + NewInfo.FuncPtrReturn = self.FuncPtrReturn.Copy() if isinstance(self.FuncPtrReturn, CTypeInfo) else self.FuncPtrReturn + NewInfo.IsBitField = self.IsBitField + NewInfo.BitWidth = self.BitWidth + NewInfo.IsTypedef = self.IsTypedef + NewInfo.IsStruct = self.IsStruct + NewInfo.IsEnum = self.IsEnum + NewInfo.IsUnion = self.IsUnion + NewInfo.IsRenum = self.IsRenum + NewInfo.RenumVariants = list(self.RenumVariants) + NewInfo.Name = self.Name + NewInfo.Members = dict(self.Members) + NewInfo.OriginalType = self.OriginalType.Copy() if isinstance(self.OriginalType, CTypeInfo) else self.OriginalType + NewInfo.DeclaredType = self.DeclaredType + NewInfo.CreturnTypes = list(self.CreturnTypes) + NewInfo.Lineno = self.Lineno + NewInfo.file = self.file + NewInfo.IsAnonymous = self.IsAnonymous + NewInfo.IsCpythonObject = self.IsCpythonObject + NewInfo.IsEnumMember = self.IsEnumMember + NewInfo.IsVariadic = self.IsVariadic + NewInfo.IsVariable = self.IsVariable + NewInfo.IsFunction = self.IsFunction + NewInfo.MetaList = self.MetaList + NewInfo.IsArrayPtr = self.IsArrayPtr + NewInfo.ArrayPtr = self.ArrayPtr.Copy() if self.ArrayPtr else None + NewInfo.IsState = self.IsState + NewInfo.IsDefine = self.IsDefine + NewInfo.DefineValue = self.DefineValue + NewInfo.IsInline = self.IsInline + NewInfo.InlineBody = self.InlineBody + NewInfo.InlineParams = list(self.InlineParams) if self.InlineParams else None + NewInfo._extra = dict(self._extra) + return NewInfo + + def get(self, key, default=None): + """获取额外属性""" + return self._extra.get(key, default) + + def set(self, key, value): + """设置额外属性""" + self._extra[key] = value + + @staticmethod + def VoidTypeInfo() -> "CTypeInfo": + info = CTypeInfo() + info.BaseType = t.CVoid() + return info + + def ToLLVM(self, Gen): + from llvmlite import ir as _ir + if Gen is None: + return _ir.IntType(32) + return Gen._ctype_to_llvm(self) + + def ToLLVMBase(self, Gen): + from llvmlite import ir as _ir + if Gen is None: + return _ir.IntType(32) + return Gen._base_ctype_to_llvm(self.BaseType, self) + + def __str__(self) -> str: + return self.ToString() + + def __repr__(self) -> str: + return f"CTypeInfo(BaseType={self.BaseType}, PtrCount={self.PtrCount}, IsTypedef={self.IsTypedef}, OriginalType={self.OriginalType!r}, VarConst={self.VarConst}, DataConst={self.DataConst})" + + +class CTypeHelper: + + @staticmethod + def GetTModuleCType(TypeName: str): + from lib.includes.t import CTypeRegistry + result = CTypeRegistry.GetClassByName(TypeName) + if result is not None: + return result + TypeClass = getattr(t, TypeName, None) + if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, t.CType): + return TypeClass + FallbackClass = getattr(t, f'_{TypeName}', None) + if FallbackClass and isinstance(FallbackClass, type) and issubclass(FallbackClass, t.CType): + return FallbackClass + return None + + @staticmethod + def GetCName(type_or_name) -> str: + from lib.includes.t import CTypeRegistry + if isinstance(type_or_name, str): + cls = CTypeRegistry.GetClassByName(type_or_name) + if cls is None: + cls = CTypeHelper.GetTModuleCType(type_or_name) + if cls: + return CTypeRegistry.CTypeToCName(cls) or type_or_name + return type_or_name + elif isinstance(type_or_name, type) and issubclass(type_or_name, t.CType): + return CTypeRegistry.CTypeToCName(type_or_name) or '' + return '' + + @staticmethod + def StripTypePrefix(TypeStr: str) -> str: + for prefix in ('struct ', 'enum ', 'union '): + if TypeStr.startswith(prefix): + return TypeStr[len(prefix):].strip() + return TypeStr + + @staticmethod + def IsVoidType(TypeStr: str) -> bool: + from lib.includes.t import CTypeRegistry + cls = CTypeRegistry.GetClassByName(TypeStr) or CTypeRegistry.CNameToClass(TypeStr) + if cls: + return CTypeRegistry.CTypeToLLVM(cls) == 'void' + return TypeStr == 'void' or TypeStr == 'struct void' or TypeStr == 'union void' + + @staticmethod + def IsStrType(TypeStr: str) -> bool: + from lib.includes.t import CTypeRegistry + resolved = CTypeRegistry.ResolveName(TypeStr) + if resolved: + ctype_cls, ptr_level = resolved + if CTypeRegistry.CTypeToLLVM(ctype_cls) == 'i8' and ptr_level > 0: + return True + return TypeStr in ('str', 'bytes', 'struct str', 'union str', 'c_char') + + +class BuiltinTypeMap: + """ + 内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射 + + 用法:BuiltinTypeMap.Get('int') -> (t.CInt, 0) + BuiltinTypeMap.Get('BYTEPTR') -> (t.CUnsignedChar, 1) + """ + + _map = None + + @classmethod + def _build_map(cls): + if cls._map is not None: + return cls._map + from lib.includes.t import CTypeRegistry + CTypeRegistry._build() + cls._map = {} + for cname, ctype_cls in CTypeRegistry._cname_to_class.items(): + cls._map[cname] = (ctype_cls, 0) + for pyname, ctype_cls in CTypeRegistry._name_to_class.items(): + pos = getattr(ctype_cls, 'position', frozenset()) + if t.CType.POINTER in pos and t.CType.BASE not in pos: + cls._map[pyname] = (ctype_cls, 1) + elif pyname not in cls._map: + cls._map[pyname] = (ctype_cls, 0) + _SPECIAL = { + 'str': (t.CChar, 1), 'bytes': (t.CChar, 1), 'unsigned': (t.CUnsigned, 0), + 'signed': (t.CInt, 0), 'signed int': (t.CInt, 0), + 'signed char': (t.CSignedChar, 0), 'bool': (t.CBool, 0), + 'void': (t.CVoid, 0), 'Void': (t.CVoid, 0), + } + for k, v in _SPECIAL.items(): + if k not in cls._map: + cls._map[k] = v + _PTR_ALIASES = { + 'INTPTR': (t.CInt, 1), 'UINTPTR': (t.CUnsignedInt, 1), + 'VOIDPTR': (t.CVoid, 1), 'BYTEPTR': (t.CUnsignedChar, 1), + 'CHAR8PTR': (t.CChar8T, 1), 'CHAR16PTR': (t.CChar16T, 1), + 'CHAR32PTR': (t.CChar32T, 1), + } + for k, v in _PTR_ALIASES.items(): + if k not in cls._map: + cls._map[k] = v + _FLOAT_ALIASES = { + 'FLOAT8': (t.CFloat8T, 0), 'FLOAT16': (t.CFloat16T, 0), + 'FLOAT32': (t.CFloat32T, 0), 'FLOAT64': (t.CFloat64T, 0), + 'FLOAT128': (t.CFloat128T, 0), + } + for k, v in _FLOAT_ALIASES.items(): + if k not in cls._map: + cls._map[k] = v + return cls._map + + @classmethod + def Get(cls, type_name: str): + """获取类型类和指针层级""" + return cls._build_map().get(type_name) + + +class BaseHandle: + def __init__(self, translator: "Translator") -> None: + self.Trans: Translator = translator + self._CurrentCpythonObjectClass: str = None + + @staticmethod + def _attr(obj, name, default=None): + if obj is None: + return default + return getattr(obj, name, default) + + @staticmethod + def _is_char_pointer(val): + """检查值是否为 char* (i8*) 指针""" + from llvmlite import ir + if not isinstance(val.type, ir.PointerType): + return False + pointee = val.type.pointee + return isinstance(pointee, ir.IntType) and pointee.width == 8 + + def HandleExprLlvm(self, Node, VarType=None): + return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) + + def HandleBodyLlvm(self, Body): + return self.Trans.BodyHandler.HandleBodyLlvm(Body) + + def _get_int_ptr(self, Node): + import ast + from llvmlite import ir + Gen = self.Trans.LlvmGen + if isinstance(Node, ast.Name): + if Node.id in Gen.variables: + return Gen.variables[Node.id] + elif isinstance(Node, ast.Attribute): + obj_val = self.HandleExprLlvm(Node.value) + if not obj_val: + return None + if isinstance(obj_val.type, ir.PointerType): + pointee = obj_val.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + StructName = None + if isinstance(pointee, ir.IdentifiedStructType): + StructName = pointee.name + if not StructName: + for ClassName, struct_type in Gen.structs.items(): + if struct_type == pointee: + StructName = ClassName + break + if StructName and StructName in Gen.structs: + offset = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen) + member_ptr = Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{Node.attr}_ptr") + return member_ptr + return None + + def _IsTModuleType(self, TypeName: str) -> bool: + if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'): + return True + TypeClass = getattr(t, TypeName, None) + if TypeClass and isinstance(TypeClass, type): + if issubclass(TypeClass, t.CType): + return True + FallbackClass = getattr(t, f'_{TypeName}', None) + if FallbackClass and isinstance(FallbackClass, type): + if issubclass(FallbackClass, t.CType): + return True + return False + + +StrictMode = _config.mode == 'strict' + + diff --git a/lib/core/Handles/HandlesBody.py b/lib/core/Handles/HandlesBody.py new file mode 100644 index 0000000..63a8d48 --- /dev/null +++ b/lib/core/Handles/HandlesBody.py @@ -0,0 +1,76 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast + + +class BodyHandle(BaseHandle): + def __init__(self, translator: "Translator"): + super().__init__(translator) + + def HandleBodyLlvm(self, Body): + Gen = self.Trans.LlvmGen + for Node in Body: + if Gen.builder and Gen.builder.block.is_terminated: + break + Gen._set_node_info(Node) + try: + if isinstance(Node, ast.Expr): + self.HandleExprLlvm(Node.value) + elif isinstance(Node, ast.Return): + self.Trans.ReturnHandler._HandleReturnLlvm(Node) + elif isinstance(Node, ast.Assign): + self.Trans.AssignHandler._HandleAssignLlvm(Node) + elif isinstance(Node, ast.AugAssign): + self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node) + elif isinstance(Node, ast.AnnAssign): + self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node) + elif isinstance(Node, ast.If): + self.Trans.IfHandler._HandleIfLlvm(Node) + elif isinstance(Node, ast.For): + self.Trans.ForHandler._HandleForLlvm(Node) + elif isinstance(Node, ast.While): + self.Trans.WhileHandler._HandleWhileLlvm(Node) + elif isinstance(Node, ast.Break): + if Gen.loop_break_targets: + Gen.builder.branch(Gen.loop_break_targets[-1]) + elif isinstance(Node, ast.Continue): + if Gen.loop_continue_targets: + Gen.builder.branch(Gen.loop_continue_targets[-1]) + elif isinstance(Node, ast.With): + self.Trans.WithHandler._HandleWithLlvm(Node) + elif isinstance(Node, ast.ClassDef): + pass + elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match): + self.Trans.MatchHandler._HandleMatchLlvm(Node) + elif isinstance(Node, ast.Try): + self.Trans.TryHandler._HandleTryLlvm(Node) + elif isinstance(Node, ast.Raise): + self.Trans.RaiseHandler._HandleRaiseLlvm(Node) + elif isinstance(Node, ast.Assert): + self.Trans.AssertHandler._HandleAssertLlvm(Node) + elif isinstance(Node, ast.Global): + self.Trans.ForHandler._HandleGlobalLlvm(Node) + elif isinstance(Node, ast.FunctionDef): + self.Trans.ForHandler._HandleNestedFunctionLlvm(Node) + elif isinstance(Node, ast.Nonlocal): + self.Trans.ForHandler._HandleNonlocalLlvm(Node) + elif isinstance(Node, ast.Delete): + self.Trans.DeleteHandler._HandleDeleteLlvm(Node) + except Exception as e: + lineno = getattr(Node, 'lineno', 0) + source_line = Gen._get_source_line(lineno) + src_file = getattr(Gen, '_current_source_file', '') + src_path = src_file if src_file else 'unknown' + line_info = "源代码 (%s, line %d)" % (src_path, lineno) + if source_line: + line_info += ":\n %d | %s" % (lineno, source_line) + self.Trans._error_stack.append((type(e).__name__, str(e), line_info)) + raise + if Gen.builder and not Gen.builder.block.is_terminated: + Gen._emit_temp_frees() + + def HandleExprLlvm(self, Node, VarType=None): + return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py new file mode 100644 index 0000000..29df85a --- /dev/null +++ b/lib/core/Handles/HandlesClassDef.py @@ -0,0 +1,965 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo +from lib.core.SymbolNode import SymbolNode +from lib.includes import t +import ast +import llvmlite.ir as ir + + +class ClassHandle(BaseHandle): + def _is_exception_class(self, Node): + if not Node.bases: + return False + for base in Node.bases: + if hasattr(base, 'id'): + if base.id == 'Exception': + return True + if base.id in self.Trans.exception_registry: + return True + elif hasattr(base, 'attr'): + if base.attr == 'Exception': + return True + if base.attr in self.Trans.exception_registry: + return True + return False + + def _get_exception_parent(self, Node): + if not Node.bases: + return None + for base in Node.bases: + if hasattr(base, 'id'): + if base.id != 'Exception' and base.id in self.Trans.exception_registry: + return base.id + elif hasattr(base, 'attr'): + if base.attr != 'Exception' and base.attr in self.Trans.exception_registry: + return base.attr + return None + + def _RegisterExceptionClass(self, Node): + ClassName = Node.name + if ClassName in self.Trans.exception_registry: + return + code = self.Trans._next_exception_code + self.Trans._next_exception_code += 1 + self.Trans.exception_registry[ClassName] = code + parent = self._get_exception_parent(Node) + if parent: + self.Trans.exception_parents[ClassName] = parent + ExcTypeInfo = CTypeInfo() + ExcTypeInfo.Name = ClassName + ExcTypeInfo.IsExceptionClass = True + ExcTypeInfo.value = code + self.Trans.SymbolTable[ClassName] = ExcTypeInfo + + def _is_generic_class(self, Node): + if hasattr(Node, 'type_params') and Node.type_params: + return True + return False + + def _mangle_generic_class_name(self, class_name, type_args): + from lib.includes.t import CTypeRegistry + mangled_args = [] + for ta in type_args: + llvm_str = CTypeRegistry.NameToLLVM(ta) + if llvm_str: + if llvm_str in ('float', 'double', 'half', 'fp128'): + mangled = 'f' + str(CTypeRegistry.GetClassByName(ta)().Size) + else: + mangled = llvm_str + else: + mangled = ta + mangled_args.append(mangled) + return class_name + '[' + ']['.join(mangled_args) + ']' + + def _specialize_generic_class(self, ClassName, type_args, Gen, type_names=None): + if not hasattr(self, '_generic_class_templates') or ClassName not in self._generic_class_templates: + return None + template = self._generic_class_templates[ClassName] + Node = template['node'] + type_param_names = template['type_params'] + if len(type_args) != len(type_param_names): + return None + spec_key = ClassName + '<' + ','.join(type_args) + '>' + if not hasattr(self, '_generic_class_specializations'): + self._generic_class_specializations = {} + if spec_key in self._generic_class_specializations: + return self._generic_class_specializations[spec_key] + spec_name = self._mangle_generic_class_name(ClassName, type_args) + type_map = {} + for i, tp_name in enumerate(type_param_names): + if type_names and i < len(type_names): + type_map[tp_name] = type_names[i] + else: + type_map[tp_name] = type_args[i] + if type_names: + if not hasattr(self.Trans, '_t_c_imported_names'): + self.Trans._t_c_imported_names = {} + for tn in type_names: + if tn not in self.Trans._t_c_imported_names: + self.Trans._t_c_imported_names[tn] = ('t', tn) + import copy + SpecNode = copy.deepcopy(Node) + SpecNode.type_params = [] + SpecNode.name = spec_name + for item in SpecNode.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + if item.annotation: + item.annotation = self.Trans.FunctionHandler._replace_type_in_annotation(item.annotation, type_map) + elif isinstance(item, ast.FunctionDef): + for arg in item.args.args: + if arg.annotation: + arg.annotation = self.Trans.FunctionHandler._replace_type_in_annotation(arg.annotation, type_map) + if item.returns: + item.returns = self.Trans.FunctionHandler._replace_type_in_annotation(item.returns, type_map) + self.Trans.FunctionHandler._apply_type_map_to_body(item.body, type_map) + saved_builder = Gen.builder + saved_func = Gen.func + saved_variables = dict(Gen.variables) if Gen.variables else {} + saved_direct_values = dict(Gen._direct_values) if Gen._direct_values else {} + saved_var_type_info = dict(Gen.var_type_info) if Gen.var_type_info else {} + saved_var_signedness = dict(Gen.var_signedness) if Gen.var_signedness else {} + saved_global_vars = set(Gen.global_vars) if Gen.global_vars else set() + saved_var_scopes = [dict(s) for s in self.Trans.VarScopes] if self.Trans.VarScopes else [] + saved_block = None + if Gen.builder and Gen.builder.block and not Gen.builder.block.is_terminated: + saved_block = Gen.builder.block + self._EmitClassLlvm(SpecNode, Gen) + Gen.builder = saved_builder + if saved_block is not None and Gen.builder is not None: + Gen.builder.position_at_end(saved_block) + Gen.func = saved_func + Gen.variables = saved_variables + Gen._direct_values = saved_direct_values + Gen.var_type_info = saved_var_type_info + Gen.var_signedness = saved_var_signedness + Gen.global_vars = saved_global_vars + self.Trans.VarScopes = saved_var_scopes + self._generic_class_specializations[spec_key] = spec_name + if not hasattr(self.Trans, '_generic_class_specializations'): + self.Trans._generic_class_specializations = {} + self.Trans._generic_class_specializations[spec_key] = spec_name + if hasattr(self.Trans, '_module_sha1') and self.Trans._module_sha1: + Gen._struct_sha1_map[spec_name] = self.Trans._module_sha1 + return spec_name + + def _EmitClassLlvm(self, Node, Gen): + ClassName = Node.name + if self._is_generic_class(Node): + if not hasattr(self, '_generic_class_templates'): + self._generic_class_templates = {} + type_params = [tp.name for tp in Node.type_params] + self._generic_class_templates[ClassName] = { + 'node': Node, + 'type_params': type_params, + } + return + if self._is_exception_class(Node): + self._RegisterExceptionClass(Node) + return + IsCenum = False + IsCunion = False + IsRenum = False + if Node.bases: + for base in Node.bases: + if hasattr(base, 'attr'): + if base.attr == 'CEnum' or base.attr == 'Enum': + IsCenum = True + break + elif base.attr == 'CUnion': + IsCunion = True + elif base.attr == 'REnum': + IsRenum = True + elif hasattr(base, 'id'): + if base.id == 'CEnum' or base.id == 'Enum': + IsCenum = True + break + elif base.id == 'CUnion': + IsCunion = True + elif base.id == 'REnum': + IsRenum = True + if IsCenum: + self._RegisterEnumMembers(Node) + return + if IsCunion: + self._EmitUnionLlvm(Node, Gen) + return + if IsRenum: + self._EmitREnumLlvm(Node, Gen) + return + IsCpythonObject = False + IsCVTable = False + if hasattr(Node, 'decorator_list') and Node.decorator_list: + for decorator in Node.decorator_list: + if isinstance(decorator, ast.Attribute): + if hasattr(decorator.value, 'id') and decorator.value.id == 't': + if decorator.attr == 'Object': + IsCpythonObject = True + elif decorator.attr == 'CVTable': + IsCVTable = True + elif isinstance(decorator, ast.Name): + if decorator.id == 'Object': + IsCpythonObject = True + elif decorator.id == 'CVTable': + IsCVTable = True + elif isinstance(decorator, ast.Call): + # 检测 @c.Attribute(t.attr.packed) + if isinstance(decorator.func, ast.Attribute): + if getattr(decorator.func.value, 'id', None) == 'c' and decorator.func.attr == 'Attribute': + for arg in decorator.args: + if isinstance(arg, ast.Attribute): + if isinstance(arg.value, ast.Attribute): + if getattr(arg.value.value, 'id', None) == 't' and arg.value.attr == 'attr' and arg.attr == 'packed': + Gen.class_packed.add(ClassName) + HasMethods = any(isinstance(item, ast.FunctionDef) for item in Node.body) + if HasMethods and not IsCpythonObject: + IsCpythonObject = True + HasParentClass = False + ParentClassName = None + if Node.bases: + for base in Node.bases: + base_name = None + if hasattr(base, 'id'): + base_name = base.id + elif hasattr(base, 'attr'): + base_name = base.attr + if base_name and base_name not in ('CEnum', 'Enum', 'CUnion', 'CStruct', 'Object', 'CVTable', 'Exception'): + if base_name in Gen.class_members or base_name in Gen.structs: + HasParentClass = True + ParentClassName = base_name + break + if HasParentClass and not IsCVTable: + IsCVTable = True + if IsCVTable: + Gen.class_vtable.add(ClassName) + if ParentClassName: + Gen.class_vtable.add(ParentClassName) + if ClassName not in Gen.class_methods: + Gen.class_methods[ClassName] = [] + # 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明 + Gen.class_members[ClassName] = [] + Gen.class_member_defaults[ClassName] = {} + Gen.class_member_signeds[ClassName] = {} + Gen.class_member_bitfields[ClassName] = {} + Gen.class_member_byteorders[ClassName] = {} + Gen.class_member_bitoffsets[ClassName] = {} + ParentClass = None + if Node.bases: + for base in Node.bases: + if hasattr(base, 'id'): + base_name = base.id + if base_name in Gen.class_members and base_name != ClassName: + ParentClass = base_name + break + elif hasattr(base, 'attr'): + base_name = base.attr + if base_name in Gen.class_members and base_name != ClassName: + ParentClass = base_name + break + if ParentClass: + Gen.class_parent[ClassName] = ParentClass + if ParentClass: + parent_members = list(Gen.class_members[ParentClass]) + parent_defaults = dict(Gen.class_member_defaults.get(ParentClass, {})) + existing_names = {m[0] for m in Gen.class_members[ClassName]} + inherited = [] + for pm_name, pm_type in parent_members: + if pm_name not in existing_names: + inherited.append((pm_name, pm_type)) + if pm_name in parent_defaults: + Gen.class_member_defaults[ClassName][pm_name] = parent_defaults[pm_name] + Gen.class_members[ClassName] = inherited + Gen.class_members[ClassName] + if ParentClass in Gen.class_methods: + parent_methods = list(Gen.class_methods[ParentClass]) + for pm in parent_methods: + method_name = pm.split('.')[-1] if '.' in pm else pm + child_method = f"{ClassName}.{method_name}" + if child_method not in Gen.class_methods[ClassName]: + Gen.class_methods[ClassName].append(child_method) + Gen.register_method(ClassName, child_method) + for item in Node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + VarName = item.target.id + try: + TypeInfo = CTypeInfo.FromNode(item.annotation, self.Trans.SymbolTable) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + IsPtr = TypeInfo.IsPtr + MemberType = Gen._ctype_to_llvm(TypeInfo) + if isinstance(MemberType, ir.VoidType): + MemberType = ir.PointerType(ir.IntType(8)) + Gen.class_members[ClassName].append((VarName, MemberType)) + if isinstance(MemberType, ir.PointerType) and isinstance(MemberType.pointee, ir.IntType) and MemberType.pointee.width == 8: + if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): + def _find_struct_in_annot(node): + if isinstance(node, ast.Name) and node.id in Gen.structs: + return node.id + if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in Gen.structs: + return node.value + if isinstance(node, ast.Attribute) and node.attr in Gen.structs: + return node.attr + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + result = _find_struct_in_annot(node.left) + if result: + return result + return _find_struct_in_annot(node.right) + return None + element_class = _find_struct_in_annot(item.annotation) + if element_class: + if ClassName not in Gen.class_member_element_class: + Gen.class_member_element_class[ClassName] = {} + Gen.class_member_element_class[ClassName][VarName] = element_class + if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'): + Gen.class_member_signeds[ClassName][VarName] = TypeInfo.BaseType.IsSigned + else: + Gen.class_member_signeds[ClassName][VarName] = None + if TypeInfo and TypeInfo.IsBitField: + Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth + else: + Gen.class_member_bitfields[ClassName][VarName] = 0 + if TypeInfo and TypeInfo.ByteOrder: + Gen.class_member_byteorders[ClassName][VarName] = TypeInfo.ByteOrder + else: + Gen.class_member_byteorders[ClassName][VarName] = "" + if item.value: + const = self._BuildScalarConstant(item.value, MemberType) + if const: + Gen.class_member_defaults[ClassName][VarName] = const + except Exception: # 回退:类成员类型解析失败时使用默认 i32 + Gen.class_members[ClassName].append((VarName, ir.IntType(32))) + Gen.class_member_signeds[ClassName][VarName] = None + Gen.class_member_bitfields[ClassName][VarName] = 0 + existing_members = {m[0] for m in Gen.class_members[ClassName]} + for item in Node.body: + if isinstance(item, ast.FunctionDef): + self._current_method_args = {} + for arg in item.args.args: + if arg.arg != 'self' and arg.annotation: + self._current_method_args[arg.arg] = arg.annotation + self._scan_method_body_for_self_members(item.body, ClassName, existing_members, Gen) + self._current_method_args = {} + for item in Node.body: + if isinstance(item, ast.FunctionDef): + MethodName = item.name + FullMethodName = f"{ClassName}.{MethodName}" + if FullMethodName not in Gen.class_methods[ClassName]: + Gen.class_methods[ClassName].append(FullMethodName) + Gen.register_method(ClassName, FullMethodName) + if IsCVTable: + Gen.class_vtable.add(ClassName) + Gen._generate_structs() + Gen._create_Vtable_globals() + if (IsCpythonObject or IsCVTable) and ClassName in Gen.structs: + self._EmitNewFunctionLlvm(ClassName, Gen, IsCVTable=IsCVTable, IsCpythonObject=IsCpythonObject) + for item in Node.body: + if isinstance(item, ast.FunctionDef): + self.Trans.FunctionHandler._EmitFunctionForwardDeclLlvm(item, Gen, ClassName=ClassName) + for item in Node.body: + if isinstance(item, ast.FunctionDef): + self.Trans.FunctionHandler._EmitFunctionLlvm(item, Gen, ClassName=ClassName) + if IsCVTable and ClassName in Gen.Vtables: + self._fill_vtable_with_methods(ClassName, Gen) + # Generate wrapper functions for inherited methods that are not overridden + if ParentClass: + self._generate_inherited_method_wrappers(ClassName, Gen) + + def _generate_inherited_method_wrappers(self, ClassName, Gen): + """为子类继承但未覆写的方法生成包装函数,使跨模块调用能正确链接。 + + 例如 Label 继承 Widget.place,生成 Label.place 函数, + 内部将 self 从 Label* bitcast 为 Widget*,然后调用 Widget.place。 + """ + methods = Gen.class_methods.get(ClassName, []) + if not methods: + return + if ClassName not in Gen.structs: + return + + for method_name in methods: + method_short = method_name.split('.')[-1] if '.' in method_name else method_name + child_full = f"{ClassName}.{method_short}" + + # 如果子类已经有该方法的实现,跳过 + if Gen._find_function(child_full): + continue + + # 沿继承链查找父类实现 + parent_func = None + parent_class = None + p = Gen.class_parent.get(ClassName) + while p: + parent_full = f"{p}.{method_short}" + parent_func = Gen._find_function(parent_full) + if parent_func: + parent_class = p + break + p = Gen.class_parent.get(p) + + if not parent_func or not parent_class: + continue + + # 父类和子类都需要有 struct 定义 + if parent_class not in Gen.structs: + continue + + # 构造子类包装函数签名:与父类函数相同,但 self 参数类型为子类指针 + parent_ftype = parent_func.function_type + parent_ret_type = parent_ftype.return_type + parent_param_types = list(parent_ftype.args) + is_vararg = parent_ftype.var_arg + + # 判断父类方法是否是静态方法: + # 如果第一个参数类型是父类指针,说明是实例方法;否则是静态方法 + parent_struct_ptr_type = ir.PointerType(Gen.structs[parent_class]) if parent_class in Gen.structs else None + is_static = True + if parent_param_types and parent_struct_ptr_type: + first_param = parent_param_types[0] + # 检查第一个参数是否是父类指针(或可以 bitcast 为父类指针的指针类型) + if isinstance(first_param, ir.PointerType): + if isinstance(first_param.pointee, ir.IdentifiedStructType): + if first_param.pointee.name == Gen.structs[parent_class].name: + is_static = False + elif first_param == ir.IntType(8): + # i8* 可能是前向声明时的 self 类型,视为实例方法 + is_static = False + + if is_static: + # 静态方法:签名与父类完全一致,不需要 self 参数 + child_param_types = list(parent_param_types) + child_struct_ptr = None + else: + # 实例方法:替换第一个参数(self)的类型为子类指针 + child_struct_ptr = ir.PointerType(Gen.structs[ClassName]) + if parent_param_types: + child_param_types = [child_struct_ptr] + parent_param_types[1:] + else: + child_param_types = [child_struct_ptr] + + child_func_type = ir.FunctionType(parent_ret_type, child_param_types, var_arg=is_vararg) + child_mangled = Gen._mangle_func_name(child_full) + child_func = Gen._get_or_declare_function(child_mangled, child_func_type) + Gen.functions[child_full] = child_func + + # 生成函数体 + entry_block = child_func.append_basic_block(name="entry") + saved_builder = Gen.builder + saved_func = Gen.func + Gen.builder = ir.IRBuilder(entry_block) + Gen.func = child_func + + # 准备参数 + call_args = [] + if is_static: + # 静态方法:参数直接传递,不做 bitcast + for arg in child_func.args: + call_args.append(arg) + else: + # 实例方法:bitcast self,其余参数直接传递 + for i, arg in enumerate(child_func.args): + if i == 0 and parent_param_types: + actual_self_type = parent_param_types[0] + casted_self = Gen.builder.bitcast(arg, actual_self_type, name="self_cast") + call_args.append(casted_self) + else: + call_args.append(arg) + + result = Gen.builder.call(parent_func, call_args, name="inherited_call") + + if isinstance(parent_ret_type, ir.VoidType): + Gen.builder.ret_void() + else: + Gen.builder.ret(result) + + Gen.builder = saved_builder + Gen.func = saved_func + + def _fill_vtable_with_methods(self, ClassName, Gen): + methods = Gen.class_methods.get(ClassName, []) + if not methods or ClassName not in Gen.Vtables: + return + Vtable = Gen.Vtables[ClassName] + VtableType = Vtable.type.pointee + null_i8ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + initializers = [] + for mi, method_name in enumerate(methods): + method_short = method_name.split('.')[-1] if '.' in method_name else method_name + func = Gen._find_function(f"{ClassName}.{method_short}") + if not func: + func = Gen._find_function(f"{ClassName}.{method_short}__") + if not func: + p = Gen.class_parent.get(ClassName) + while p: + func = Gen._find_function(f"{p}.{method_short}") + if not func: + func = Gen._find_function(f"{p}.{method_short}__") + if func: + break + p = Gen.class_parent.get(p) + if func: + initializers.append(func.bitcast(ir.PointerType(ir.IntType(8)))) + else: + initializers.append(null_i8ptr) + if initializers: + Vtable.initializer = ir.Constant(VtableType, initializers) + + def _scan_method_body_for_self_members(self, body, ClassName, existing_members, Gen): + for stmt in body: + self._scan_node_for_self_assign(stmt, ClassName, existing_members, Gen) + + def _scan_node_for_self_assign(self, node, ClassName, existing_members, Gen): + if isinstance(node, ast.AnnAssign): + if (isinstance(node.target, ast.Attribute) + and isinstance(node.target.value, ast.Name) + and node.target.value.id == 'self'): + VarName = node.target.attr + if VarName not in existing_members: + try: + TypeInfo = CTypeInfo.FromNode(node.annotation, self.Trans.SymbolTable) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + MemberType = Gen._ctype_to_llvm(TypeInfo) + if isinstance(MemberType, ir.VoidType): + MemberType = ir.IntType(32) + except Exception: # 回退:成员类型解析失败时使用默认 i32 + MemberType = ir.IntType(32) + Gen.class_members[ClassName].append((VarName, MemberType)) + Gen.class_member_signeds[ClassName][VarName] = None + Gen.class_member_bitfields[ClassName][VarName] = 0 + Gen.class_member_byteorders[ClassName][VarName] = "" + Gen.class_member_bitoffsets[ClassName][VarName] = 0 + existing_members.add(VarName) + len_name = f'{VarName}__len' + if isinstance(MemberType, ir.PointerType) and node.value and isinstance(node.value, ast.List): + if len_name not in existing_members: + Gen.class_members[ClassName].append((len_name, ir.IntType(64))) + Gen.class_member_signeds[ClassName][len_name] = None + Gen.class_member_bitfields[ClassName][len_name] = 0 + Gen.class_member_byteorders[ClassName][len_name] = "" + Gen.class_member_bitoffsets[ClassName][len_name] = 0 + Gen.class_member_defaults[ClassName][len_name] = ir.Constant(ir.IntType(64), len(node.value.elts)) + existing_members.add(len_name) + elif isinstance(node, ast.Assign): + for target in node.targets: + if (isinstance(target, ast.Attribute) + and isinstance(target.value, ast.Name) + and target.value.id == 'self'): + VarName = target.attr + if VarName not in existing_members: + MemberType = ir.IntType(32) + if node.value: + try: + if isinstance(node.value, ast.Constant): + if isinstance(node.value.value, int): + MemberType = ir.IntType(32) + elif isinstance(node.value.value, float): + MemberType = ir.DoubleType() + elif isinstance(node.value.value, str): + MemberType = ir.PointerType(ir.IntType(8)) + elif isinstance(node.value, ast.Name): + if hasattr(self, '_current_method_args'): + arg_info = self._current_method_args.get(node.value.id) + if arg_info: + TypeInfo = CTypeInfo.FromNode(arg_info, self.Trans.SymbolTable) + if TypeInfo: + InferredType = Gen._ctype_to_llvm(TypeInfo) + if not isinstance(InferredType, ir.VoidType): + MemberType = InferredType + elif isinstance(node.value, ast.Call): + if isinstance(node.value.func, ast.Name): + if node.value.func.id in ('float', 'double'): + MemberType = ir.DoubleType() + elif node.value.func.id in ('int', 'long', 'short', 'char'): + MemberType = ir.IntType(32) + elif isinstance(node.value.func, ast.Attribute): + if node.value.func.attr == 'len': + MemberType = ir.IntType(32) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + Gen.class_members[ClassName].append((VarName, MemberType)) + Gen.class_member_signeds[ClassName][VarName] = None + Gen.class_member_bitfields[ClassName][VarName] = 0 + Gen.class_member_byteorders[ClassName][VarName] = "" + Gen.class_member_bitoffsets[ClassName][VarName] = 0 + existing_members.add(VarName) + for child in ast.iter_child_nodes(node): + if isinstance(child, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): + continue + self._scan_node_for_self_assign(child, ClassName, existing_members, Gen) + + def _EmitUnionLlvm(self, Node, Gen): + ClassName = Node.name + union_member_types = [] + for item in Node.body: + if isinstance(item, ast.ClassDef): + nested_class_name = item.name + nested_member_types = [] + for nested_item in item.body: + if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name): + VarName = nested_item.target.id + try: + TypeInfo = CTypeInfo.FromNode(nested_item.annotation, self.Trans.SymbolTable) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + MemberType = Gen._ctype_to_llvm(TypeInfo) + if isinstance(MemberType, ir.VoidType): + MemberType = ir.PointerType(ir.IntType(8)) + nested_member_types.append(MemberType) + except Exception: # 回退:嵌套成员类型解析失败时使用默认 i32 + nested_member_types.append(ir.IntType(32)) + if nested_member_types: + nested_struct_type = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}") + nested_struct_type.set_body(*nested_member_types) + Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type + union_member_types.append(nested_struct_type) + nested_class_full_name = f"{ClassName}_{nested_class_name}" + if nested_class_full_name not in Gen.class_members: + Gen.class_members[nested_class_full_name] = [] + if nested_class_full_name not in Gen.class_member_signeds: + Gen.class_member_signeds[nested_class_full_name] = {} + for nested_item in item.body: + if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name): + VarName = nested_item.target.id + try: + TypeInfo = CTypeInfo.FromNode(nested_item.annotation, self.Trans.SymbolTable) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + MemberType = Gen._ctype_to_llvm(TypeInfo) + if isinstance(MemberType, ir.VoidType): + MemberType = ir.PointerType(ir.IntType(8)) + Gen.class_members[nested_class_full_name].append((VarName, MemberType)) + if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'): + Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned + else: + Gen.class_member_signeds[nested_class_full_name][VarName] = None + except Exception: # 回退:嵌套类成员类型解析失败时使用默认 i32 + Gen.class_members[nested_class_full_name].append((VarName, ir.IntType(32))) + Gen.class_member_signeds[nested_class_full_name][VarName] = None + if union_member_types: + max_size = 0 + for member_type in union_member_types: + try: + size = member_type.get_abi_size(ir.DataLayout(Gen.module.data_layout)) + except Exception: # 回退:获取类型大小失败时使用默认值 8 + size = 8 + max_size = max(max_size, size) + union_type = ir.IdentifiedStructType(Gen.module, ClassName) + union_type.set_body(ir.ArrayType(ir.IntType(8), max_size)) + Gen.structs[ClassName] = union_type + UnionNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='union', + lineno=Node.lineno, + file='' + ) + self.Trans.SymbolTable[ClassName] = UnionNode.attributes + + def _EmitREnumLlvm(self, Node, Gen): + ClassName = Node.name + variant_info = [] + variant_names = [] + variant_index = 0 + for item in Node.body: + if isinstance(item, ast.ClassDef): + VariantName = item.name + variant_names.append(VariantName) + member_types = [] + member_names = [] + member_annotations = [] + for nested_item in item.body: + if isinstance(nested_item, ast.AnnAssign) and isinstance(nested_item.target, ast.Name): + VarName = nested_item.target.id + try: + TypeInfo = CTypeInfo.FromNode(nested_item.annotation, self.Trans.SymbolTable) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + MemberType = Gen._ctype_to_llvm(TypeInfo) + if isinstance(MemberType, ir.VoidType): + MemberType = ir.PointerType(ir.IntType(8)) + member_types.append(MemberType) + member_names.append(VarName) + member_annotations.append(nested_item.annotation) + except Exception: # 回退:成员类型解析失败时使用默认 i32 + member_types.append(ir.IntType(32)) + member_names.append(VarName) + member_annotations.append(None) + variant_info.append((VariantName, member_types, member_names, member_annotations, item.lineno, variant_index)) + variant_index += 1 + elif isinstance(item, ast.Assign): + for target in item.targets: + if isinstance(target, ast.Name): + VarName = target.id + variant_names.append(VarName) + value = None + if item.value and isinstance(item.value, ast.Constant): + value = item.value.value + variant_index = value + 1 + else: + value = variant_index + variant_index += 1 + variant_info.append((VarName, [], [], [], item.lineno, value)) + max_variant_struct = None + max_variant_size = 0 + for _, member_types, _, _, _, _ in variant_info: + if member_types: + full_types = [ir.IntType(32)] + member_types + size = 4 + for mt in full_types: + if isinstance(mt, ir.IntType): + size += mt.width // 8 + elif isinstance(mt, ir.PointerType): + size += 8 + elif isinstance(mt, ir.FloatType): + size += 4 + elif isinstance(mt, ir.DoubleType): + size += 8 + elif isinstance(mt, ir.ArrayType): + if isinstance(mt.element, ir.IntType): + size += mt.element.width // 8 * mt.count + else: + size += 8 * mt.count + else: + size += 8 + if size > max_variant_size: + max_variant_size = size + max_variant_struct = full_types + if max_variant_struct is None: + max_variant_struct = [ir.IntType(32), ir.IntType(32)] + renum_type = ir.IdentifiedStructType(Gen.module, ClassName) + renum_type.set_body(*max_variant_struct) + Gen.structs[ClassName] = renum_type + for VariantName, member_types, member_names, member_annotations, lineno, tag_value in variant_info: + NestedStructName = f"{ClassName}_{VariantName}" + if member_types: + padded_member_types = list(max_variant_struct) + nested_struct_type = ir.IdentifiedStructType(Gen.module, NestedStructName) + nested_struct_type.set_body(*padded_member_types) + Gen.structs[NestedStructName] = nested_struct_type + if NestedStructName not in Gen.class_members: + Gen.class_members[NestedStructName] = [] + if NestedStructName not in Gen.class_member_signeds: + Gen.class_member_signeds[NestedStructName] = {} + Gen.class_members[NestedStructName].append(('__tag', ir.IntType(32))) + Gen.class_member_signeds[NestedStructName]['__tag'] = None + for i, (mname, mtype) in enumerate(zip(member_names, member_types)): + Gen.class_members[NestedStructName].append((mname, mtype)) + try: + ti = CTypeInfo.FromNode(member_annotations[i], self.Trans.SymbolTable) + if ti and hasattr(ti.BaseType, 'IsSigned'): + Gen.class_member_signeds[NestedStructName][mname] = ti.BaseType.IsSigned + else: + Gen.class_member_signeds[NestedStructName][mname] = None + except Exception: # 回退:签名信息解析失败时设为 None + Gen.class_member_signeds[NestedStructName][mname] = None + MemberNode = CTypeInfo() + MemberNode.Name = VariantName + MemberNode.BaseType = t.CEnum(ClassName) + MemberNode.value = tag_value + MemberNode.EnumName = ClassName + MemberNode.Lineno = lineno + MemberNode.IsEnumMember = True + self.Trans.SymbolTable[VariantName] = MemberNode + RenumTypeInfo = CTypeInfo() + RenumTypeInfo.Name = ClassName + RenumTypeInfo.BaseType = t.REnum(ClassName) + RenumTypeInfo.IsRenum = True + RenumTypeInfo.IsEnum = True + RenumTypeInfo.RenumVariants = variant_names + self.Trans.SymbolTable[ClassName] = RenumTypeInfo + + def _RegisterEnumMembers(self, Node): + ClassName = Node.name + EnumTypeInfo = CTypeInfo() + EnumTypeInfo.Name = ClassName + EnumTypeInfo.BaseType = t.CEnum(ClassName) + EnumTypeInfo.IsEnum = True + self.Trans.SymbolTable[ClassName] = EnumTypeInfo + from lib.core.export_table import EnumMember as ExportEnumMember + enum_export = self.Trans.ExportTable.add_enum( + name=ClassName, + lineno=Node.lineno, + is_public=True + ) + next_enum_value = 0 + for item in Node.body: + if isinstance(item, ast.Assign): + for target in item.targets: + if isinstance(target, ast.Name): + VarName = target.id + value = None + if item.value: + if isinstance(item.value, ast.Constant): + value = item.value.value + next_enum_value = value + 1 + elif isinstance(item.value, ast.UnaryOp) and isinstance(item.value.op, ast.USub): + if isinstance(item.value.operand, ast.Constant): + value = -item.value.operand.value + next_enum_value = value + 1 + elif isinstance(item.value, ast.Name): + value = item.value.id + if value in self.Trans.SymbolTable: + ref_info = self.Trans.SymbolTable[value] + if ref_info.value is not None and isinstance(ref_info.value, int): + next_enum_value = ref_info.value + 1 + else: + value = next_enum_value + next_enum_value += 1 + MemberNode = CTypeInfo() + MemberNode.Name = VarName + MemberNode.BaseType = t.CEnum(ClassName) + MemberNode.value = value + MemberNode.EnumName = ClassName + MemberNode.Lineno = item.lineno + MemberNode.IsEnumMember = True + self.Trans.SymbolTable[VarName] = MemberNode + enum_export.members.append(ExportEnumMember( + name=VarName, + value=value, + lineno=item.lineno + )) + elif isinstance(item, ast.AnnAssign): + if isinstance(item.target, ast.Name): + VarName = item.target.id + value = None + if item.value: + if isinstance(item.value, ast.Constant): + value = item.value.value + next_enum_value = value + 1 + elif isinstance(item.value, ast.UnaryOp) and isinstance(item.value.op, ast.USub): + if isinstance(item.value.operand, ast.Constant): + value = -item.value.operand.value + next_enum_value = value + 1 + elif isinstance(item.value, ast.Name): + value = item.value.id + if value in self.Trans.SymbolTable: + ref_info = self.Trans.SymbolTable[value] + if ref_info.value is not None and isinstance(ref_info.value, int): + next_enum_value = ref_info.value + 1 + else: + value = next_enum_value + next_enum_value += 1 + MemberNode = CTypeInfo() + MemberNode.Name = VarName + MemberNode.BaseType = t.CEnum(ClassName) + MemberNode.value = value + MemberNode.EnumName = ClassName + MemberNode.Lineno = item.lineno + MemberNode.IsEnumMember = True + self.Trans.SymbolTable[VarName] = MemberNode + enum_export.members.append(ExportEnumMember( + name=VarName, + value=value, + lineno=item.lineno + )) + + def _EmitNewFunctionLlvm(self, ClassName, Gen, IsCVTable=False, IsCpythonObject=False): + NewFuncName = f'{ClassName}.__before_init__' + existing_func = Gen.functions.get(NewFuncName) + if existing_func and len(existing_func.blocks) > 0: + return + MangledName = Gen._mangle_name(NewFuncName) + StructType = Gen.structs[ClassName] + if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + StructType = Gen.structs.get(ClassName, StructType) + StructPtrType = ir.PointerType(StructType) + FuncType = ir.FunctionType(ir.VoidType(), [StructPtrType]) + if existing_func: + func = existing_func + else: + func = Gen._get_or_declare_function(MangledName, FuncType) + Gen.functions[NewFuncName] = func + EntryBlock = func.append_basic_block(name="entry") + saved_builder = Gen.builder + saved_func = Gen.func + Gen.builder = ir.IRBuilder(EntryBlock) + Gen.func = func + StructPtr = func.args[0] + if IsCVTable: + base = 1 + if ClassName in Gen.Vtables: + VtablePtr = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="vtable_slot") + VtableAddr = Gen.builder.bitcast(Gen.Vtables[ClassName], ir.PointerType(ir.IntType(8)), name="vtable_addr") + Gen.builder.store(VtableAddr, VtablePtr) + members = Gen.class_members.get(ClassName, []) + defaults = Gen.class_member_defaults.get(ClassName, {}) + for i, (member_name, member_type) in enumerate(members): + ElemPtr = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"{ClassName}_{member_name}") + if member_name in defaults: + try: + val = defaults[member_name] + if not isinstance(val, ir.Constant): + val = ir.Constant(ElemPtr.type.pointee, val) + Gen.builder.store(val, ElemPtr) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + Gen.builder.ret_void() + Gen.builder = saved_builder + Gen.func = saved_func + + def _BuildScalarConstant(self, node, llvm_type): + if isinstance(node, ast.Constant): + if isinstance(node.value, bool): + try: + return ir.Constant(llvm_type, 1 if node.value else 0) + except Exception: # 回退:常量创建失败 + return None + elif isinstance(node.value, int): + try: + return ir.Constant(llvm_type, node.value) + except Exception: # 回退:常量创建失败 + return None + elif isinstance(node.value, float): + try: + return ir.Constant(llvm_type, node.value) + except Exception: # 回退:常量创建失败 + return None + elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub): + if isinstance(node.operand, ast.Constant) and isinstance(node.operand.value, int): + try: + return ir.Constant(llvm_type, -node.operand.value) + except Exception: # 回退:常量创建失败 + return None + return None + + def _BuildStructConstant(self, call_node, StructName, Gen): + struct_type = Gen.structs[StructName] + members = Gen.class_members.get(StructName, []) + defaults = Gen.class_member_defaults.get(StructName, {}) + member_values = [] + for member_name, member_type in members: + if member_name in defaults: + val = defaults[member_name] + if not isinstance(val, ir.Constant): + try: + val = ir.Constant(member_type, val) + except Exception: # 回退:常量转换失败时使用零值 + val = ir.Constant(member_type, 0) + member_values.append(val) + else: + try: + if isinstance(member_type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.PointerType, ir.ArrayType)): + member_values.append(ir.Constant(member_type, None)) + else: + member_values.append(ir.Constant(member_type, ir.Undefined)) + except Exception: # 回退:常量创建失败时使用零值 + member_values.append(ir.Constant(member_type, 0)) + if call_node.args: + for i, arg in enumerate(call_node.args): + if i < len(members): + _, member_type = members[i] + const = self._BuildScalarConstant(arg, member_type) + if const is not None: + member_values[i] = const + try: + return ir.Constant(struct_type, member_values) + except Exception: # 回退:结构体常量创建失败 + return None diff --git a/lib/core/Handles/HandlesDelete.py b/lib/core/Handles/HandlesDelete.py new file mode 100644 index 0000000..a511244 --- /dev/null +++ b/lib/core/Handles/HandlesDelete.py @@ -0,0 +1,96 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta +import ast +import llvmlite.ir as ir + + +class DeleteHandle(BaseHandle): + def _HandleDeleteLlvm(self, Node): + Gen = self.Trans.LlvmGen + for target in Node.targets: + if isinstance(target, ast.Subscript): + ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__delitem__'): + obj_val = self.Trans.ExprHandler.HandleExprLlvm(target.value) + idx_val = self.Trans.ExprHandler.HandleExprLlvm(target.slice) + if obj_val and idx_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__") + elif isinstance(target, ast.Name): + ClassName = Gen.var_struct_class.get(target.id) + if ClassName and Gen._has_function(f'{ClassName}.__delete__'): + obj_val = self.Trans.ExprHandler.HandleExprLlvm(target) + if obj_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__") + elif isinstance(target, ast.Attribute): + # 检查 property deleter + AttrName = target.attr + ClassName = None + obj_val_for_prop = None + + if isinstance(target.value, ast.Name) and target.value.id == 'self': + # del self.attr — 检查当前类的 property deleter + ClassName = self.Trans._CurrentCpythonObjectClass + if ClassName: + PropKey = f'{ClassName}.{AttrName}' + PropInfo = self.Trans.SymbolTable.get(PropKey) + if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: + SelfVar = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + DeleterFunc = Gen._get_function(PropKey) + if DeleterFunc and SelfPtr: + Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}") + continue + else: + # del obj.attr — 检查 obj 类的 property deleter + ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen) + if ClassName: + PropKey = f'{ClassName}.{AttrName}' + PropInfo = self.Trans.SymbolTable.get(PropKey) + if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: + obj_val = self.Trans.ExprHandler.HandleExprLlvm(target.value) + if obj_val: + DeleterFunc = Gen._get_function(PropKey) + if DeleterFunc: + Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}") + continue + + # 原有的 __del__ 处理逻辑 + obj_val = self.Trans.ExprHandler.HandleExprLlvm(target) + if obj_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType): + obj_val = Gen._load(obj_val, name="load_del_ptr") + ClassName = None + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + for CN, ST in Gen.structs.items(): + if obj_val.type.pointee == ST: + ClassName = CN + break + elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + if isinstance(target.value, ast.Name) and target.value.id == 'self': + AttrName = target.attr + SelfClassName = self.Trans._CurrentCpythonObjectClass + if SelfClassName and SelfClassName in Gen.class_members: + for member_name, member_type in Gen.class_members[SelfClassName]: + if member_name == AttrName: + for CN in Gen.structs: + if CN == AttrName or Gen._has_function(f'{CN}.__del__'): + ClassName = CN + break + break + if not ClassName: + for CN, ST in Gen.structs.items(): + if Gen._has_function(f'{CN}.__del__'): + ClassName = CN + break + if ClassName and Gen._has_function(f'{ClassName}.__del__'): + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Gen.builder.call(Gen._get_function(f'{ClassName}.__del__'), [obj_val], name=f"call_{ClassName}.__del__") \ No newline at end of file diff --git a/lib/core/Handles/HandlesExpr.py b/lib/core/Handles/HandlesExpr.py new file mode 100644 index 0000000..956994b --- /dev/null +++ b/lib/core/Handles/HandlesExpr.py @@ -0,0 +1,429 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprHandle(BaseHandle): + def __init__(self, translator: "Translator"): + super().__init__(translator) + + def GetOpSymbol(self, Op): + return self.Trans.ExprUtils.GetOpSymbol(Op) + + def GetUnaryOpSymbol(self, Op): + return self.Trans.ExprUtils.GetUnaryOpSymbol(Op) + + def GetComparatorSymbol(self, Op): + return self.Trans.ExprUtils.GetComparatorSymbol(Op) + + def _get_var_class(self, node, Gen): + return self.Trans.ExprUtils._get_var_class(node, Gen) + + def _try_operator_overload(self, ClassName, op_name, obj_val, Gen, other_val=None): + return self.Trans.ExprUtils._try_operator_overload(ClassName, op_name, obj_val, Gen, other_val) + + def _get_llvm_member_offset(self, field_name, ClassName, Gen): + return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen) + + def HandleExprLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + if not Gen or not Gen.builder: + return None + if isinstance(Node, ast.Constant): + return self._HandleConstantLlvm(Node, VarType) + elif isinstance(Node, ast.Name): + return self._HandleNameLlvm(Node, VarType) + elif isinstance(Node, ast.BinOp): + return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType) + elif isinstance(Node, ast.BoolOp): + return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node) + elif isinstance(Node, ast.UnaryOp): + return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node) + elif isinstance(Node, ast.Call): + return self.Trans.ExprCallHandle._HandleCallLlvm(Node) + elif isinstance(Node, ast.Compare): + return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node) + elif isinstance(Node, ast.Attribute): + return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node) + elif isinstance(Node, ast.Subscript): + return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node) + elif isinstance(Node, ast.IfExp): + return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node) + elif isinstance(Node, ast.NamedExpr): + return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node) + elif isinstance(Node, ast.JoinedStr): + in_str_method = getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__') + return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node, return_str=in_str_method) + elif isinstance(Node, ast.Lambda): + return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node) + elif isinstance(Node, ast.List): + return self._HandleListLlvm(Node, VarType) + return ir.Constant(ir.IntType(32), 0) + + def _HandleListLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + elements = Node.elts + if not elements: + return ir.Constant(ir.IntType(8).as_pointer(), None) + + array_len = len(elements) + elem_type = 'i8' + + if VarType and isinstance(VarType, str) and 'list[' in VarType: + import re + match = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType) + if match: + type_str = match.group(1).strip() + if match.group(2): + array_len = int(match.group(2)) + if 'CChar' in type_str or 'char' in type_str.lower(): + elem_type = 'i8' + elif 'CFloat' in type_str or type_str.lower() == 'float': + elem_type = 'float' + elif 'CDouble' in type_str or type_str.lower() == 'double': + elem_type = 'double' + elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()): + elem_type = 'i32' + elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower(): + elem_type = 'i32' + elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower(): + elem_type = 'i8' + elif 'CShort' in type_str or 'short' in type_str.lower(): + elem_type = 'i16' + elif 'CUnsignedShort' in type_str: + elem_type = 'i16' + elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements): + elem_type = 'float' + + alloc_size = array_len + if elem_type == 'i32': + alloc_size *= 4 + elif elem_type == 'i16': + alloc_size *= 2 + elif elem_type == 'float': + alloc_size *= 4 + elif elem_type == 'double': + alloc_size *= 8 + + malloc_fn = None + malloc_arg_type = ir.IntType(64) + for fn in Gen.module.global_values: + if fn.name == 'malloc': + malloc_fn = fn + func_ftype = getattr(fn, 'ftype', None) + if func_ftype and getattr(func_ftype, 'args', None): + if func_ftype.args: + malloc_arg_type = fn.ftype.args[0] + break + + if not malloc_fn: + try: + malloc_fn_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) + malloc_fn = ir.Function(Gen.module, malloc_fn_type, name='malloc') + Gen.functions['malloc'] = malloc_fn + except Exception: # 回退:malloc 函数创建失败时返回 null + return ir.Constant(ir.IntType(8).as_pointer(), None) + + alloc_ptr = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)]) + cast_ptr = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8))) + + for i, elem in enumerate(elements): + if i >= array_len: + break + + elem_val = self.HandleExprLlvm(elem, VarType=elem_type) + if elem_val is None: + continue + + byte_offset = i + if elem_type == 'i32': + byte_offset = i * 4 + elif elem_type == 'i16': + byte_offset = i * 2 + elif elem_type == 'float': + byte_offset = i * 4 + elif elem_type == 'double': + byte_offset = i * 8 + + ptr_as_int = Gen.builder.ptrtoint(cast_ptr, ir.IntType(64)) + new_ptr_val = Gen.builder.add(ptr_as_int, ir.Constant(ir.IntType(64), byte_offset)) + if elem_type == 'i32': + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(32))) + elif elem_type == 'i16': + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(16))) + elif elem_type == 'float': + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.FloatType())) + elif elem_type == 'double': + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.DoubleType())) + else: + elem_ptr = Gen.builder.inttoptr(new_ptr_val, ir.PointerType(ir.IntType(8))) + + if elem_type == 'i8': + if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8: + elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}") + elif isinstance(elem_val.type, ir.PointerType): + elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(64), name=f"ptrtoint_elem_{i}") + elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}") + elif elem_type == 'i32': + if isinstance(elem_val.type, ir.IntType): + if elem_val.type.width < 32: + elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}") + elif elem_val.type.width > 32: + elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}") + elif isinstance(elem_val.type, ir.PointerType): + elem_val = Gen.builder.ptrtoint(elem_val, ir.IntType(32), name=f"ptrtoint_elem_{i}") + elif elem_type == 'i16': + if isinstance(elem_val.type, ir.IntType): + if elem_val.type.width < 16: + elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}") + elif elem_val.type.width > 16: + elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}") + elif elem_type == 'float': + if isinstance(elem_val.type, ir.DoubleType): + elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}") + elif isinstance(elem_val.type, ir.IntType): + elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}") + elif elem_type == 'double': + if isinstance(elem_val.type, ir.FloatType): + elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}") + elif isinstance(elem_val.type, ir.IntType): + elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}") + + Gen.builder.store(elem_val, elem_ptr) + + if elem_type == 'float': + return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.FloatType()), name="list_float_ptr") + elif elem_type == 'double': + return Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.DoubleType()), name="list_double_ptr") + return cast_ptr + + def _HandleConstantLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + Value = Node.value + if Value is None: + if VarType is not None and isinstance(VarType, ir.PointerType): + return ir.Constant(VarType, None) + return ir.Constant(ir.IntType(8).as_pointer(), None) + elif isinstance(Value, bool): + return ir.Constant(ir.IntType(32), 1 if Value else 0) + elif isinstance(Value, int): + if VarType is not None: + if isinstance(VarType, ir.IntType): + return ir.Constant(VarType, Value & ((1 << VarType.width) - 1)) + if isinstance(VarType, ir.PointerType): + return ir.Constant(ir.IntType(64), Value) + if isinstance(VarType, (ir.FloatType, ir.DoubleType)): + return ir.Constant(VarType, float(Value)) + if isinstance(VarType, str) and '*' in VarType: + return ir.Constant(ir.IntType(64), Value) + if isinstance(VarType, str): + from lib.includes.t import CTypeRegistry as _CR + resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType) + if resolved: + ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved + inst = ctype_cls() + size = getattr(inst, 'Size', 32) + is_unsigned = getattr(inst, 'IsSigned', True) is False + mask = (1 << size) - 1 + return ir.Constant(ir.IntType(size), Value & mask) + llvm_match = __import__('re').match(r'^i(\d+)$', VarType) + if llvm_match: + width = int(llvm_match.group(1)) + return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1)) + if Value < 0 or Value > 0xFFFFFFFF: + return ir.Constant(ir.IntType(64), Value) + return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF) + elif isinstance(Value, float): + if VarType and isinstance(VarType, ir.FloatType): + return ir.Constant(VarType, Value) + elif VarType and isinstance(VarType, ir.DoubleType): + return ir.Constant(VarType, Value) + return ir.Constant(ir.DoubleType(), Value) + elif isinstance(Value, str): + is_wide = getattr(Node, 'kind', None) == 'u' + if len(Value) == 1 and not is_wide: + if VarType is not None and isinstance(VarType, ir.PointerType): + pass + elif isinstance(VarType, ir.IntType): + return ir.Constant(VarType, ord(Value[0])) + elif isinstance(VarType, str): + from lib.includes.t import CTypeRegistry as _CR + resolved = _CR.ResolveName(VarType) or _CR.CNameToClass(VarType) or _CR.LLVMToCType(VarType) + if resolved: + ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved + inst = ctype_cls() + size = getattr(inst, 'Size', 32) + return ir.Constant(ir.IntType(size), ord(Value[0])) + llvm_match = __import__('re').match(r'^i(\d+)$', VarType) + if llvm_match: + return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0])) + elif VarType is not None: + return ir.Constant(ir.IntType(8), ord(Value[0])) + if is_wide: + str_value = Value + '\x00' + wide_chars = [ord(c) for c in str_value] + target_count = len(wide_chars) + str_type = ir.ArrayType(ir.IntType(16), target_count) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, wide_chars) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return ptr + else: + str_value = Value + '\x00' + str_bytes = str_value.encode('utf-8') + target_count = len(str_bytes) + if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8: + target_count = VarType.count + if len(str_bytes) < target_count: + str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes)) + else: + str_bytes = str_bytes[:target_count] + str_type = ir.ArrayType(ir.IntType(8), target_count) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return ptr + return ir.Constant(ir.IntType(32), 0) + + def _HandleNameLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + VarName = Node.id + define_constants = getattr(Gen, '_define_constants', {}) + if VarName in define_constants: + val = define_constants[VarName] + if isinstance(val, int): + # Use VarType hint if available to avoid unnecessary type mismatch + if VarType is not None and isinstance(VarType, ir.IntType): + return ir.Constant(VarType, val & ((1 << VarType.width) - 1)) + if VarName in Gen.var_signedness and Gen.var_signedness[VarName]: + if val < -(1 << 31) or val > 0xFFFFFFFF: + return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF) + return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) + if val < -(1 << 31) or val > 0xFFFFFFFF: + return ir.Constant(ir.IntType(64), val) + return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) + elif isinstance(val, float): + return ir.Constant(ir.DoubleType(), val) + elif isinstance(val, str): + str_value = val + '\x00' + str_bytes = str_value.encode('utf-8') + str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return ptr + # 如果 _define_constants 中没有,尝试从符号表查找 + if VarName not in getattr(Gen, '_define_constants', {}): + try: + sym_info = self.translator.SymbolTable.get(VarName) + if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None: + val = sym_info.DefineValue + if isinstance(val, int): + # Use VarType hint if available + if VarType is not None and isinstance(VarType, ir.IntType): + return ir.Constant(VarType, val & ((1 << VarType.width) - 1)) + if val < -(1 << 31) or val > 0xFFFFFFFF: + return ir.Constant(ir.IntType(64), val) + return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF) + elif isinstance(val, float): + return ir.Constant(ir.DoubleType(), val) + elif isinstance(val, str): + str_value = val + '\x00' + str_bytes = str_value.encode('utf-8') + str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return ptr + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + # 优先检查 variables(alloca),因为变量可能已被 += 等操作迁移到 variables + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if VarName in Gen.global_struct_class: + Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] + return VarPtr + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if VarName in Gen.global_struct_class: + Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] + return VarPtr + return Gen._load(VarPtr, name=VarName) + if VarName in Gen._reg_values: + return Gen._reg_values[VarName] + if VarName in Gen._direct_values: + return Gen._direct_values[VarName] + if VarName in Gen.global_vars and VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + Gen.variables[VarName] = GVar + if isinstance(GVar, ir.Function): + return GVar + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return Gen._load(GVar, name=VarName) + if VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + Gen.variables[VarName] = GVar + if isinstance(GVar, ir.Function): + return GVar + if VarName in Gen.global_struct_class: + Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName] + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return Gen._load(GVar, name=VarName) + if VarName == 'self': + return Gen._get_var_ptr('self') + if Gen._has_function(VarName): + func = Gen._get_function(VarName) + if func: + return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") + if VarName in Gen.class_methods: + return ir.Constant(ir.IntType(8).as_pointer(), None) + if VarName == 'True' or VarName == 'False': + return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0) + if VarName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[VarName] + if getattr(SymInfo, 'IsEnumMember', None) and isinstance(getattr(SymInfo, 'value', None), int): + return ir.Constant(ir.IntType(32), SymInfo.value) + if getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsFuncPtr', False): + MangledName = Gen._mangle_func_name(VarName) + if MangledName in Gen.module.globals: + g = Gen.module.globals[MangledName] + if isinstance(g, ir.Function): + Gen.functions[VarName] = g + return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") + for sha1 in Gen.module_sha1_map.values(): + prefixed = f"{sha1}.{VarName}" + if prefixed in Gen.module.globals: + g = Gen.module.globals[prefixed] + if isinstance(g, ir.Function): + Gen.functions[VarName] = g + return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}") + t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) + if VarName in t_c_imported: + src_module, src_name = t_c_imported[VarName] + virtual_attr = ast.Attribute( + value=ast.Name(id=src_module, ctx=ast.Load()), + attr=src_name, + ctx=ast.Load() + ) + ast.copy_location(virtual_attr, Node) + return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr) + return ir.Constant(ir.IntType(32), 0) diff --git a/lib/core/Handles/HandlesExprAsm.py b/lib/core/Handles/HandlesExprAsm.py new file mode 100644 index 0000000..004babf --- /dev/null +++ b/lib/core/Handles/HandlesExprAsm.py @@ -0,0 +1,578 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir +import t + +# 猴子补丁 llvmlite.ir.InlineAsm 以支持 asm_dialect 参数 +# 添加保护避免重复补丁 +_InlineAsmPatched = getattr(ir.InlineAsm, '_transpyc_patched', False) + +if not _InlineAsmPatched: + _OrigInlineAsmInit = ir.InlineAsm.__init__ + _OrigInlineAsmDescr = ir.InlineAsm.descr + + def _patched_inline_asm_init(self, ftype, asm, constraint, side_effect=False, asm_dialect=None): + _OrigInlineAsmInit(self, ftype, asm, constraint, side_effect) + self.asm_dialect = asm_dialect + + def _patched_inline_asm_descr(self, buf): + sideeffect = 'sideeffect' if self.side_effect else '' + dialect_str = getattr(self, 'asm_dialect', None) + if dialect_str == 'intel': + dialect = 'inteldialect' + else: + dialect = '' + fmt = 'asm {sideeffect} {dialect} "{asm}", "{constraint}"' + buf.append(fmt.format(sideeffect=sideeffect, dialect=dialect, asm=self.asm, + constraint=self.constraint)) + + ir.InlineAsm.__init__ = _patched_inline_asm_init + ir.InlineAsm.descr = _patched_inline_asm_descr + ir.InlineAsm._transpyc_patched = True + + +class ExprAsmHandle(BaseHandle): + @staticmethod + def _format_to_dialect(asm_format): + """将用户指定的 format 参数转换为 LLVM asm_dialect 值""" + fmt = asm_format.lower() if asm_format else 'intel' + if fmt == 'att': + return 'att' + elif fmt == 'arm': + return None # ARM 没有专门的 dialect 标记 + else: + return 'intel' # 默认 Intel + + def _HandleAsmLlvm(self, Node): + Gen = self.Trans.LlvmGen + + op_arg = None + input_arg = None + output_arg = None + asm_format = 'Intel' # 汇编格式: Intel / AT&T / ARM + for kw in Node.keywords: + if kw.arg == 'op': + op_arg = kw.value + elif kw.arg in ('input', 'inp', 'inputs'): + input_arg = kw.value + elif kw.arg in ('output', 'out', 'outputs'): + output_arg = kw.value + elif kw.arg == 'format': + if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str): + asm_format = kw.value.value + + if len(Node.args) >= 1: + pos_op = None + if len(Node.args) >= 2 and op_arg is None: + pos_op = Node.args[1] + return self._HandleAsmWithOpLlvm(Node.args[0], op_arg or pos_op, input_arg, output_arg, asm_format) + + if len(Node.args) < 2: + return ir.Constant(ir.IntType(32), 1) + + args = Node.args + + if len(args) == 4: + output_type_arg = args[0] + asm_template_arg = args[1] + constraint_arg = args[2] + clobber_arg = args[3] + + output_type = self._infer_expr_llvm_type(output_type_arg) + if not output_type: + output_type = ir.IntType(32) + + asm_template = '' + if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): + asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value)) + + constraint = '' + if isinstance(constraint_arg, ast.Constant) and isinstance(constraint_arg.value, str): + constraint = constraint_arg.value + + clobber = '' + if isinstance(clobber_arg, ast.Constant) and isinstance(clobber_arg.value, str): + clobber = clobber_arg.value + + full_constraint = constraint + func_type = ir.FunctionType(output_type, []) + asm_dialect = self._format_to_dialect(asm_format) + inline_asm = ir.InlineAsm(func_type, asm_template, constraint, side_effect=True, asm_dialect=asm_dialect) + result = Gen.builder.call(inline_asm, [], name="asm_result") + return result + + elif len(args) >= 2: + output_type_arg = args[0] + asm_template_arg = args[1] + + output_type = self._infer_expr_llvm_type(output_type_arg) + if not output_type: + output_type = ir.IntType(32) + + asm_template = '' + if isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): + asm_template = self._prepare_intel_asm(self._mangle_asm_calls(asm_template_arg.value)) + + output_constraints = [] + output_values = [] + if len(args) > 2 and isinstance(args[2], (ast.List, ast.Tuple)): + for item in args[2].elts: + if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: + constraint_node = item.elts[0] + value_node = item.elts[1] + if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str): + output_constraints.append(constraint_node.value) + value = self.HandleExprLlvm(value_node) + if value: + output_values.append(value) + + input_constraints = [] + input_values = [] + if len(args) > 3 and isinstance(args[3], (ast.List, ast.Tuple)): + for item in args[3].elts: + if isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: + constraint_node = item.elts[0] + value_node = item.elts[1] + if isinstance(constraint_node, ast.Constant) and isinstance(constraint_node.value, str): + input_constraints.append(constraint_node.value) + value = self.HandleExprLlvm(value_node) + if value: + input_values.append(value) + + clobbers = [] + if len(args) > 4 and isinstance(args[4], (ast.List, ast.Tuple)): + for item in args[4].elts: + if isinstance(item, ast.Constant) and isinstance(item.value, str): + clobbers.append(item.value) + + constraint_parts = [] + for oc in output_constraints: + constraint_parts.append(oc) + + input_start_idx = len(output_constraints) + for ic in input_constraints: + constraint_parts.append(ic) + + full_constraint = ",".join(constraint_parts) + + if clobbers: + if full_constraint: + full_constraint += "," + for c in clobbers: + full_constraint += f"~{{{c}}}" + + operands = output_values + input_values + param_types = [v.type for v in operands] + func_type = ir.FunctionType(output_type, param_types) + asm_dialect = self._format_to_dialect(asm_format) + inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=False, asm_dialect=asm_dialect) + result = Gen.builder.call(inline_asm, operands, name="asm_result") + return result + + return None + + def _prepare_intel_asm(self, template: str) -> str: + import re + template = re.sub(r'%(\d+)', r'$\1', template) + template = re.sub(r'%([a-zA-Z][a-zA-Z0-9]*)', r'\1', template) + return template + + def _normalize_asm_template(self, template: str) -> str: + lines = template.split('\n') + if len(lines) <= 1: + return template + first_line = lines[0] + rest_lines = lines[1:] + stripped = [] + for line in rest_lines: + s = line.lstrip() + if s: + stripped.append(s) + else: + stripped.append('') + return '\n'.join([first_line] + stripped) + + def _process_joined_str_template(self, node, out_input_ops, out_input_constraints, + out_output_ops, out_output_constraints): + if not isinstance(node, ast.JoinedStr): + if isinstance(node, ast.Constant) and isinstance(node.value, str): + return node.value + return '' + + raw_parts = [] + for value in node.values: + if isinstance(value, ast.Constant) and isinstance(value.value, str): + raw_parts.append(('text', value.value)) + elif isinstance(value, ast.FormattedValue): + expr = value.value + if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute): + if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c': + if expr.func.attr == 'AsmInp': + if expr.args: + v = self.HandleExprLlvm(expr.args[0]) + if v: + c = 'r' + if len(expr.args) >= 2: + c = self._parse_asm_descr(expr.args[1]) + if not c: + c = 'r' + out_input_ops.append(v) + out_input_constraints.append(c) + raw_parts.append(('input', len(out_input_ops) - 1)) + elif expr.func.attr == 'AsmOut': + if expr.args: + target_ptr = self._get_var_ptr_for_asm(expr.args[0]) + if target_ptr: + v = target_ptr + else: + v = self.HandleExprLlvm(expr.args[0]) + if v: + c = '=r' + if len(expr.args) >= 2: + c = self._parse_asm_descr(expr.args[1]) + if not c: + c = '=r' + if not c.startswith('='): + c = '=' + c + out_output_ops.append(v) + out_output_constraints.append(c) + raw_parts.append(('output', len(out_output_ops) - 1)) + else: + fallback = self.HandleExprLlvm(expr) + if fallback and isinstance(fallback.type, ir.IntType): + out_input_ops.append(fallback) + out_input_constraints.append('r') + raw_parts.append(('input', len(out_input_ops) - 1)) + else: + raw_parts.append(('text', '')) + + num_outputs = len(out_output_ops) + parts = [] + for kind, data in raw_parts: + if kind == 'text': + parts.append(data) + elif kind == 'output': + parts.append(f'%{data}') + elif kind == 'input': + parts.append(f'%{num_outputs + data}') + return ''.join(parts) + + _X86_REGISTERS = frozenset({ + 'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', + 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', + 'eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp', + 'ax', 'bx', 'cx', 'dx', 'si', 'di', 'bp', 'sp', + 'al', 'bl', 'cl', 'dl', 'ah', 'bh', 'ch', 'dh', + 'sil', 'dil', 'bpl', 'spl', + 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', + 'r8w', 'r9w', 'r10w', 'r11w', 'r12w', 'r13w', 'r14w', 'r15w', + 'r8b', 'r9b', 'r10b', 'r11b', 'r12b', 'r13b', 'r14b', 'r15b', + }) + + def _mangle_asm_calls(self, template: str) -> str: + import re + Gen = self.Trans.LlvmGen + sha1 = getattr(Gen, 'module_sha1', '') + if not sha1: + return template + + def replace_call(m): + prefix = m.group(1) + func_name = m.group(2) + if func_name.lower() in self._X86_REGISTERS: + return m.group(0) + mangled = Gen._mangle_func_name(func_name) + if '.' in mangled: + return f'{prefix}\\22{mangled}\\22' + return f"{prefix}{mangled}" + + return re.sub(r'(call\s+)(\w+)', replace_call, template) + + def _HandleAsmWithOpLlvm(self, asm_template_arg, op_arg, input_arg=None, output_arg=None, asm_format='Intel'): + Gen = self.Trans.LlvmGen + + input_ops = [] + input_constraints = [] + output_ops = [] + output_constraints = [] + + if output_arg and isinstance(output_arg, (ast.List, ast.Tuple)): + for item in output_arg.elts: + if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute): + if item.func.value.id == 'c' and item.func.attr == 'AsmOut': + if len(item.args) >= 1: + target_ptr = self._get_var_ptr_for_asm(item.args[0]) + if target_ptr: + output_ops.append(target_ptr) + else: + value = self.HandleExprLlvm(item.args[0]) + if value: + output_ops.append(value) + constraint = '=r' + if len(item.args) >= 2: + base_constraint = self._parse_asm_descr(item.args[1]) + if base_constraint: + if base_constraint.startswith('='): + constraint = base_constraint + else: + constraint = '=' + base_constraint + output_constraints.append(constraint) + + if isinstance(asm_template_arg, ast.JoinedStr): + raw_template = self._normalize_asm_template( + self._process_joined_str_template( + asm_template_arg, input_ops, input_constraints, output_ops, output_constraints + ) + ) + elif isinstance(asm_template_arg, ast.Constant) and isinstance(asm_template_arg.value, str): + raw_template = self._normalize_asm_template(asm_template_arg.value) + else: + raw_template = '' + + raw_template = self._mangle_asm_calls(raw_template) + asm_dialect = self._format_to_dialect(asm_format) + if asm_format == 'AT&T': + asm_template = raw_template # AT&T 不需要转换 + elif asm_format == 'ARM': + asm_template = raw_template # ARM 不需要转换 + else: + asm_template = self._prepare_intel_asm(raw_template) # Intel → LLVM IR 格式 + + if input_arg and isinstance(input_arg, (ast.List, ast.Tuple)): + for item in input_arg.elts: + if isinstance(item, ast.Call) and isinstance(item.func, ast.Attribute): + if item.func.value.id == 'c' and item.func.attr == 'AsmInp': + if len(item.args) >= 1: + value = self.HandleExprLlvm(item.args[0]) + if value: + input_ops.append(value) + constraint = 'r' + if len(item.args) >= 2: + constraint = self._parse_asm_descr(item.args[1]) + if not constraint: + constraint = 'r' + input_constraints.append(constraint) + elif isinstance(item, (ast.List, ast.Tuple)) and len(item.elts) >= 2: + value_node = item.elts[0] + descr_node = item.elts[1] + value = self.HandleExprLlvm(value_node) + if value: + input_ops.append(value) + constraint = self._parse_asm_descr(descr_node) + if not constraint: + constraint = 'r' + input_constraints.append(constraint) + + clobbers = [] + if op_arg and isinstance(op_arg, (ast.List, ast.Tuple)): + for item in op_arg.elts: + clobber = self._parse_asm_descr(item) + if clobber: + clobbers.append(clobber) + + constraint_parts = [] + for oc in output_constraints: + c = oc if oc.startswith('=') else ('=' + oc) + constraint_parts.append(c) + for ic in input_constraints: + if ic in ('d', 'edx', 'rdx'): + constraint_parts.append('{dx}') + else: + constraint_parts.append(ic) + + full_constraint = ",".join(constraint_parts) + + constraint_to_reg = { + 'a': 'rax', 'b': 'rbx', 'c': 'rcx', 'd': 'rdx', + 'S': 'rsi', 'D': 'rdi', + 'A': 'rax', 'U': 'r8', + } + used_regs = set() + for ic in input_constraints: + if ic in constraint_to_reg: + used_regs.add(constraint_to_reg[ic]) + for oc in output_constraints: + base_oc = oc.lstrip('=').lstrip('+') + if base_oc in constraint_to_reg: + used_regs.add(constraint_to_reg[base_oc]) + + if clobbers: + has_memory = 'memory' in clobbers + if has_memory and output_ops: + clobbers = [c for c in clobbers if c != 'memory'] + if asm_format == 'ARM': + # ARM 不需要 x86 的 e→r 寄存器名转换 + clobber_final = [c for c in clobbers if c not in used_regs] + else: + clobber_64bit = [] + for c in clobbers: + if c in ['eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'ebp', 'esp']: + clobber_64bit.append(c.replace('e', 'r')) + else: + clobber_64bit.append(c) + clobber_final = [c for c in clobber_64bit if c not in used_regs] + if clobber_final: + if full_constraint: + full_constraint += "," + full_constraint += ",".join([f"~{{{c}}}" for c in clobber_final]) + + if output_ops: + single_out = len(output_ops) == 1 + if single_out: + op = output_ops[0] + if isinstance(op, ir.AllocaInstr): + ret_type = op.type.pointee + elif isinstance(op, ir.GlobalVariable): + ret_type = op.type.pointee + elif isinstance(op, (ir.GEPInstr, ir.CastInstr)): + ret_type = op.type.pointee if isinstance(op.type, ir.PointerType) else op.type + else: + ret_type = op.type + else: + def _get_ret_type(op): + if isinstance(op, (ir.AllocaInstr, ir.GlobalVariable)): + return op.type.pointee + return op.type + ret_type = ir.LiteralStructType([_get_ret_type(op) for op in output_ops]) + if isinstance(ret_type, ir.PointerType) and isinstance(ret_type.pointee, ir.IdentifiedStructType): + ret_type = ir.IntType(64) + operands = input_ops + param_types = [op.type for op in operands] + func_type = ir.FunctionType(ret_type, param_types) + inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=len(output_ops) == 0, asm_dialect=asm_dialect) + result = Gen.builder.call(inline_asm, operands, name="asm_result") + if single_out: + target = output_ops[0] + if isinstance(target, ir.AllocaInstr): + if target.type.pointee != result.type: + i64t = ir.IntType(64) + iv = Gen.builder.ptrtoint(result, i64t) + ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) + Gen.builder.store(iv, ptr) + else: + Gen.builder.store(result, target) + elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr, ir.CastInstr)): + target_pointee = target.type.pointee + if target_pointee != result.type: + if isinstance(target_pointee, ir.PointerType) and isinstance(result, ir.Instruction) and result.type == ir.IntType(64): + ptr_val = Gen.builder.inttoptr(result, target_pointee) + Gen.builder.store(ptr_val, target) + else: + i64t = ir.IntType(64) + iv = Gen.builder.ptrtoint(result, i64t) + ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) + Gen.builder.store(iv, ptr) + else: + Gen.builder.store(result, target) + else: + dst = Gen._alloca_entry(result.type) + Gen.builder.store(result, dst) + else: + for i, out_op in enumerate(output_ops): + val = Gen.builder.extract_value(result, i, name=f"asm_out_{i}") + target = out_op if isinstance(out_op, ir.AllocaInstr) else Gen._alloca_entry(val.type) + if isinstance(target, ir.AllocaInstr) and target.type.pointee != val.type: + i64t = ir.IntType(64) + iv = Gen.builder.ptrtoint(val, i64t) + ptr = Gen.builder.bitcast(target, ir.PointerType(i64t)) + Gen.builder.store(iv, ptr) + else: + Gen.builder.store(val, target) + else: + operands = input_ops + param_types = [op.type for op in operands] + func_type = ir.FunctionType(ir.VoidType(), param_types) + inline_asm = ir.InlineAsm(func_type, asm_template, full_constraint, side_effect=True, asm_dialect=asm_dialect) + Gen.builder.call(inline_asm, operands, name="asm_call") + return ir.Constant(ir.IntType(32), 1) + + def _get_var_ptr_for_asm(self, node): + Gen = self.Trans.LlvmGen + if isinstance(node, ast.Name): + var_name = node.id + if var_name in Gen.variables and Gen.variables[var_name] is not None: + ptr = Gen.variables[var_name] + if isinstance(ptr, ir.AllocaInstr): + return ptr + if isinstance(ptr, ir.GlobalVariable): + return ptr + elif isinstance(node, ast.Attribute): + obj_ptr = self._get_var_ptr_for_asm(node.value) + if obj_ptr is not None: + obj_type = obj_ptr.type.pointee + if isinstance(obj_type, ir.PointerType) and isinstance(obj_type.pointee, ir.IdentifiedStructType): + loaded = Gen.builder.load(obj_ptr, name="asm_attr_load") + struct_type = obj_type.pointee + class_name = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None + if class_name: + offset = Gen._get_member_offset(node.attr, class_name) + gep = Gen.builder.gep(loaded, [ir.Constant(ir.IntType(32), 0), + ir.Constant(ir.IntType(32), offset)], + inbounds=True) + return gep + for idx, elem_type in enumerate(struct_type.elements): + gep = Gen.builder.gep(loaded, [ir.Constant(ir.IntType(32), 0), + ir.Constant(ir.IntType(32), idx)], + inbounds=True) + return gep + elif isinstance(obj_type, ir.IdentifiedStructType): + class_name = Gen._resolve_class_for_var(node.value.id) if isinstance(node.value, ast.Name) else None + if class_name: + offset = Gen._get_member_offset(node.attr, class_name) + gep = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), + ir.Constant(ir.IntType(32), offset)], + inbounds=True) + return gep + for idx, elem_type in enumerate(obj_type.elements): + gep = Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), + ir.Constant(ir.IntType(32), idx)], + inbounds=True) + return gep + return None + + def _parse_asm_descr(self, expr): + from lib.includes import t + + if isinstance(expr, ast.BinOp): + left_val = self._parse_asm_descr(expr.left) + right_val = self._parse_asm_descr(expr.right) + return left_val + right_val + + elif isinstance(expr, ast.Attribute): + if isinstance(expr.value, ast.Attribute): + if (isinstance(expr.value.value, ast.Name) and + expr.value.value.id == 't' and + expr.value.attr == 'ASM_DESCR'): + AttrName = expr.attr + return getattr(t.ASM_DESCR, AttrName, "") + elif isinstance(expr.value, ast.Name) and expr.value.id == 't': + AttrName = expr.attr + return getattr(t.ASM_DESCR, AttrName, "") + + elif isinstance(expr, ast.Constant): + return expr.value + + return "" + + def _infer_expr_llvm_type(self, expr): + import llvmlite.ir as ir + if isinstance(expr, ast.Name): + type_name = expr.id + if hasattr(t, type_name): + ctype = getattr(t, type_name) + if isinstance(ctype, type) and issubclass(ctype, t.CType): + size = getattr(ctype, 'Size', None) + if size is not None: + return ir.IntType(size) + if type_name == 'CFloat': + return ir.FloatType() + elif type_name == 'CDouble': + return ir.DoubleType() + elif isinstance(expr, ast.Attribute): + if isinstance(expr.value, ast.Name) and expr.value.id == 't': + return self._infer_expr_llvm_type(ast.Name(id=expr.attr, ctx=ast.Load())) + return None diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py new file mode 100644 index 0000000..b476008 --- /dev/null +++ b/lib/core/Handles/HandlesExprAttr.py @@ -0,0 +1,1161 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta +import ast +import llvmlite.ir as ir + + +class ExprAttrHandle(BaseHandle): + + # ========== 辅助方法 ========== + + def _apply_bswap_on_load(self, val, ClassName, AttrName): + Gen = self.Trans.LlvmGen + byte_order = getattr(Gen, 'class_member_byteorders', {}).get(ClassName, {}).get(AttrName, "") + if byte_order == 'big' and isinstance(val.type, ir.IntType): + if val.type.width in (16, 32, 64): + val = Gen.builder.bswap(val, name=f"bswap_load_{AttrName}") + return val + + def _gep_and_load_member(self, Gen, ObjVal, offset, AttrName, ClassName, ST=None): + """从结构体指针通过 GEP 取成员,处理 array/struct pointer/class_members 特殊情况""" + if offset is None: + return None + if isinstance(ObjVal.type, ir.PointerType): + pointee = ObjVal.type.pointee + if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset >= len(pointee.elements): + return None + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.ArrayType): + return MemberPtr + if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.IdentifiedStructType): + return MemberPtr + # 检查 pointer-to-pointer 且实际元素是 ArrayType + if isinstance(MemberPtr.type, ir.PointerType) and isinstance(MemberPtr.type.pointee, ir.PointerType): + actual_elem_type = None + if ST is not None and isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None and offset < len(ST.elements): + actual_elem_type = ST.elements[offset] + if isinstance(actual_elem_type, ir.ArrayType): + return Gen.builder.bitcast(MemberPtr, ir.PointerType(actual_elem_type), name=f"cast_arr_{AttrName}") + # 检查 class_members 中的 ArrayType + if ClassName in Gen.class_members: + for member_name, member_type in Gen.class_members[ClassName]: + if member_name == AttrName and isinstance(member_type, ir.ArrayType): + return Gen.builder.bitcast(MemberPtr, ir.PointerType(member_type), name=f"cast_arr_{AttrName}") + val = Gen._load(MemberPtr, name=AttrName) + return self._apply_bswap_on_load(val, ClassName, AttrName) + + def _try_load_struct_from_stub(self, Gen, ClassName): + """尝试从 stub 加载结构体定义,返回 (struct_type, ok)""" + if ClassName not in Gen.structs: + return None, False + st = Gen.structs[ClassName] + if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + st = Gen.structs.get(ClassName, st) + if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): + return st, False + return st, True + + def _make_define_constant(self, Gen, val): + """将 CDefine 值转为 LLVM 常量""" + if isinstance(val, int): + if abs(val) > 2147483647: + return ir.Constant(ir.IntType(64), val) + return ir.Constant(ir.IntType(32), val) + elif isinstance(val, float): + return ir.Constant(ir.DoubleType(), val) + elif isinstance(val, str): + str_value = val + '\x00' + str_bytes = str_value.encode('utf-8') + str_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + gv_name = f"str_const_{Gen.string_const_counter}" + gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name) + gv.initializer = ir.Constant(str_type, bytearray(str_bytes)) + gv.linkage = 'internal' + Gen.string_const_counter += 1 + return Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast") + return None + + def _lookup_cdefine(self, Gen, VarName, AttrName): + """在符号表和模块中查找 CDefine 常量值""" + imported_modules = getattr(self.Trans, '_imported_modules', None) + if not imported_modules: + return None + PossibleKeys = [f"{VarName}.{AttrName}", AttrName] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + key = f"{mod_name}.{AttrName}" + if key not in PossibleKeys: + PossibleKeys.append(key) + for lookup_key in PossibleKeys: + SymInfo = self.Trans.SymbolTable.get(lookup_key) + if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None: + return self._make_define_constant(Gen, SymInfo.DefineValue) + # 也检查 _define_constants + define_constants = getattr(Gen, '_define_constants', {}) + for key in (f"{VarName}.{AttrName}", AttrName): + if key in define_constants: + return self._make_define_constant(Gen, define_constants[key]) + return None + + def _lookup_module_global(self, Gen, VarName, AttrName): + """在模块全局变量中查找 import 的属性""" + imported_modules = getattr(self.Trans, '_imported_modules', None) + import_aliases = getattr(self.Trans, '_import_aliases', {}) + if not imported_modules: + return None + resolved_mod = import_aliases.get(VarName, VarName) + if VarName not in imported_modules and resolved_mod not in imported_modules: + return None + PossibleKeys = [f"{VarName}.{AttrName}", AttrName] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + key = f"{mod_name}.{AttrName}" + if key not in PossibleKeys: + PossibleKeys.append(key) + for key in PossibleKeys: + if key in Gen.module.globals: + GVar = Gen.module.globals[key] + if isinstance(GVar, ir.Function): + return GVar + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return Gen._load(GVar, name=AttrName) + # SHA1 前缀查找 + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + sha1_candidates = [VarName, resolved_mod] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + if mod_name not in sha1_candidates: + sha1_candidates.append(mod_name) + for cand in sha1_candidates: + sha1 = module_sha1_map.get(cand) + if sha1: + prefixed = f"{sha1}.{AttrName}" + if prefixed in Gen.module.globals: + GVar2 = Gen.module.globals[prefixed] + if isinstance(GVar2, ir.Function): + return GVar2 + if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar2 + return Gen._load(GVar2, name=AttrName) + if AttrName in Gen.module.globals: + gv = Gen.module.globals[AttrName] + if AttrName in Gen.variables and Gen.variables[AttrName] is None: + str_gv_name = AttrName + '_str' + if str_gv_name in Gen.module.globals: + str_gv = Gen.module.globals[str_gv_name] + return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr") + return Gen.builder.load(gv, name=AttrName) + return None + + def _resolve_var_classname(self, Gen, VarName): + """根据变量名解析其结构体类名""" + ClassName = Gen.var_struct_class.get(VarName) + if not ClassName and getattr(Gen, 'global_struct_class', None): + ClassName = Gen.global_struct_class.get(VarName) + if ClassName: + Gen.var_struct_class[VarName] = ClassName + if not ClassName and VarName in Gen.module.globals: + GVar = Gen.module.globals[VarName] + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(GVar.type.pointee) + if found: + ClassName = found[0] + Gen.var_struct_class[VarName] = ClassName + if getattr(Gen, 'global_struct_class', None): + Gen.global_struct_class[VarName] = ClassName + if not ClassName and VarName in Gen.variables: + VarPtr = Gen.variables[VarName] + if VarPtr is not None and isinstance(VarPtr.type, ir.PointerType): + pointee = VarPtr.type.pointee + if isinstance(pointee, ir.PointerType): + pointee = pointee.pointee + found = Gen.find_struct_by_pointee(pointee) + if found: + ClassName = found[0] + return ClassName + + def _check_struct_match(self, Gen, ObjVal, ClassName): + """检查 ObjVal 是否指向 ClassName 对应的结构体""" + if ClassName not in Gen.structs: + return False + if isinstance(ObjVal.type, ir.PointerType): + ST = Gen.structs[ClassName] + if ObjVal.type.pointee == ST: + return True + if isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and ObjVal.type.pointee.name == ST.name: + return True + return False + + # ========== _HandleAttributeLlvm 子方法 ========== + + def _handle_attr_self(self, Node, VarName): + """处理 self.xxx 属性访问""" + Gen = self.Trans.LlvmGen + ClassName = self.Trans._CurrentCpythonObjectClass + if not ClassName: + return None + # 检查 property getter + PropKey = f'{ClassName}.{Node.attr}' + PropInfo = self.Trans.SymbolTable.get(PropKey) + if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: + SelfVar = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + GetterFunc = Gen._get_function(PropKey) + if GetterFunc and SelfPtr: + return Gen.builder.call(GetterFunc, [SelfPtr], name=f"prop_{PropKey}") + offset = Gen._get_member_offset(Node.attr, ClassName) + SelfVar = Gen._get_var_ptr('self') + if not SelfVar: + return None + SelfPtr = Gen._load(SelfVar, name="self") + if not isinstance(SelfPtr.type, ir.PointerType): + return None + pointee = SelfPtr.type.pointee + if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None: + for CN2, ST2 in Gen.structs.items(): + if isinstance(ST2, ir.IdentifiedStructType) and ST2.name == pointee.name and ST2.elements is not None: + pointee = ST2 + break + if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is not None and offset is not None and offset < len(pointee.elements): + if isinstance(pointee.elements[offset], ir.VoidType): + return None + return self._gep_and_load_member(Gen, SelfPtr, offset, Node.attr, ClassName, pointee) + DynamicVarName = f"self.{Node.attr}" + if DynamicVarName in Gen.variables: + return Gen._load(Gen.variables[DynamicVarName], name=Node.attr) + return None + + def _handle_attr_enum(self, Node, VarName): + """处理枚举成员访问 (VarName 是枚举类型名)""" + SymInfo = self.Trans.SymbolTable.get(VarName) + if not SymInfo or not getattr(SymInfo, 'IsEnum', None): + return None + if Node.attr in self.Trans.SymbolTable: + MemberInfo = self.Trans.SymbolTable[Node.attr] + if getattr(MemberInfo, 'IsEnumMember', None) and getattr(MemberInfo, 'EnumName', None) == VarName: + if isinstance(getattr(MemberInfo, 'value', None), int): + return ir.Constant(ir.IntType(32), MemberInfo.value) + for key, info in self.Trans.SymbolTable.items(): + if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == VarName and key == Node.attr: + if isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + return None + + def _handle_attr_name(self, Node, VarName): + """处理 x.attr 形式 (x 是普通 Name)""" + Gen = self.Trans.LlvmGen + AttrName = Node.attr + + # 先尝试枚举成员 + result = self._handle_attr_enum(Node, VarName) + if result is not None: + return result + + # 尝试 CDefine 常量 + result = self._lookup_cdefine(Gen, VarName, AttrName) + if result is not None: + return result + + # 尝试 import 模块全局变量 + result = self._lookup_module_global(Gen, VarName, AttrName) + if result is not None: + return result + + # 尝试 attr 直接作为全局变量 + if AttrName in Gen.module.globals: + gv = Gen.module.globals[AttrName] + if AttrName in Gen.variables and Gen.variables[AttrName] is None: + str_gv_name = AttrName + '_str' + if str_gv_name in Gen.module.globals: + str_gv = Gen.module.globals[str_gv_name] + return Gen.builder.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{AttrName}_str_ptr") + return Gen.builder.load(gv, name=AttrName) + + # 解析结构体类名并访问成员 + ClassName = self._resolve_var_classname(Gen, VarName) + if not ClassName: + return None + + # 检查 property getter + PropKey = f'{ClassName}.{AttrName}' + PropInfo = self.Trans.SymbolTable.get(PropKey) + if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList: + ObjVal = self.HandleExprLlvm(Node.value) + GetterFunc = Gen._get_function(PropKey) + if GetterFunc and ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") + return Gen.builder.call(GetterFunc, [ObjVal], name=f"prop_{PropKey}") + + # 获取类型信息 + TypeInfo = self.Trans.SymbolTable.get(ClassName) + IsUnion = TypeInfo.IsUnion if TypeInfo else False + IsCenum = TypeInfo.IsEnum if TypeInfo else False + IsRenum = getattr(TypeInfo, 'IsRenum', False) if TypeInfo else False + + # REnum 处理 + if IsRenum: + if AttrName == 'tag': + ObjVal = self.HandleExprLlvm(Node.value) + if ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") + tag_ptr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="tag_ptr") + return Gen._load(tag_ptr, name="tag_val") + NestedStructName = f"{ClassName}_{AttrName}" + if NestedStructName in Gen.structs: + NestedStructType = Gen.structs[NestedStructName] + ObjVal = self.HandleExprLlvm(Node.value) + if ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") + return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") + + # CEnum 处理 + if IsCenum: + for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"): + if qname in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[qname] + if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + for key, info in self.Trans.SymbolTable.items(): + if key == AttrName: + if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == ClassName: + if isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + break + + # CUnion 处理 + if IsUnion: + NestedStructName = f"{ClassName}_{AttrName}" + if NestedStructName in Gen.structs: + NestedStructType = Gen.structs[NestedStructName] + ObjVal = self.HandleExprLlvm(Node.value) + if ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") + return Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") + + # 普通结构体成员访问 + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal: + return None + # char* → struct* cast + if self._is_char_pointer(ObjVal): + if ClassName in Gen.structs: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + # 二级指针解引用 + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") + + # 检查结构体匹配 + struct_match = self._check_struct_match(Gen, ObjVal, ClassName) + if not struct_match and ClassName and VarName: + if VarName in Gen.var_struct_class: + CN = Gen.var_struct_class[VarName] + if CN != ClassName and CN in Gen.structs: + ClassName = CN + struct_match = self._check_struct_match(Gen, ObjVal, ClassName) + if not struct_match: + return None + + st, ok = self._try_load_struct_from_stub(Gen, ClassName) + if not ok: + return None + + # bitfield 处理 + bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {}) + bitfields = Gen.class_member_bitfields.get(ClassName, {}) + if AttrName in bitfield_offsets and bitfields.get(AttrName, 0) > 0: + return self._load_bitfield_member(ObjVal, ClassName, AttrName) + if AttrName in bitfields and bitfields[AttrName] > 0: + if ClassName not in Gen.class_member_bitoffsets: + Gen.class_member_bitoffsets[ClassName] = {} + if AttrName not in Gen.class_member_bitoffsets[ClassName]: + bo = 0 + for bf_name, bf_width in bitfields.items(): + if bf_name == AttrName: + break + bo += bf_width + Gen.class_member_bitoffsets[ClassName][AttrName] = bo + return self._load_bitfield_member(ObjVal, ClassName, AttrName) + + offset = Gen._get_member_offset(AttrName, ClassName) + # 检查 offset 是否超出实际结构体 + if isinstance(ObjVal.type, ir.PointerType): + actual_pointee = ObjVal.type.pointee + if isinstance(actual_pointee, ir.IdentifiedStructType): + actual_elems = actual_pointee.elements + if actual_elems is not None and offset is not None and offset >= len(actual_elems): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + actual_elems = actual_pointee.elements + if actual_elems is not None and offset >= len(actual_elems): + return None + return self._gep_and_load_member(Gen, ObjVal, offset, AttrName, ClassName, st) + + def _handle_attr_nested(self, Node): + """处理 a.b.c 嵌套属性访问""" + Gen = self.Trans.LlvmGen + if isinstance(Node.value.value, ast.Name): + ParentVarName = Node.value.value.id + ParentAttrName = Node.value.attr + enum_result = self._try_resolve_cross_module_enum(ParentVarName, ParentAttrName, Node.attr) + if enum_result is not None: + return enum_result + # 尝试跨模块子模块全局变量解析: a.b.c 其中 a.b 是已知子模块, c 是该模块的全局变量 + imported_modules = getattr(self.Trans, '_imported_modules', None) + if imported_modules: + full_module_path = f"{ParentVarName}.{ParentAttrName}" + if full_module_path in imported_modules: + result = self._lookup_module_global(Gen, full_module_path, Node.attr) + if result is not None: + return result + cdefine_result = self._try_resolve_nested_cdefine(Node) + if cdefine_result is not None: + return cdefine_result + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + return None + pointee = ObjVal.type.pointee + + # char* → struct* cast + 成员访问 + if isinstance(pointee, ir.IntType) and pointee.width == 8: + AttrClassName = self._get_attr_class(Node.value, Gen) + if AttrClassName and AttrClassName in Gen.structs: + st, ok = self._try_load_struct_from_stub(Gen, AttrClassName) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + CastedObj = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{AttrClassName}") + offset = Gen._get_member_offset(Node.attr, AttrClassName) + if offset is None: + return None + if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType): + return None + return self._gep_and_load_member(Gen, CastedObj, offset, Node.attr, AttrClassName, st) + + # 已知结构体类型 → 直接成员访问 + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): + st, ok = self._try_load_struct_from_stub(Gen, CN) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + break + bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {}) + if Node.attr in bitfield_offsets: + return self._load_bitfield_member(ObjVal, CN, Node.attr) + offset = Gen._get_member_offset(Node.attr, CN) + if offset is None: + break + return self._gep_and_load_member(Gen, ObjVal, offset, Node.attr, CN, st) + return None + + def _handle_attr_call_result(self, Node): + """处理 func().attr 属性访问""" + Gen = self.Trans.LlvmGen + # Check if this is c.Deref(...) — we need the pointer, not the loaded value + ObjVal = None + is_cderef = (isinstance(Node.value, ast.Call) and + isinstance(Node.value.func, ast.Attribute) and + isinstance(Node.value.func.value, ast.Name) and + Node.value.func.value.id == 'c' and + Node.value.func.attr == 'Deref' and + Node.value.args) + if is_cderef: + deref_arg = Node.value.args[0] + inner_val = self.HandleExprLlvm(deref_arg) + if inner_val and isinstance(inner_val.type, ir.PointerType): + if isinstance(inner_val.type.pointee, ir.PointerType): + ObjVal = Gen._load(inner_val, name="deref_load_ptr") + else: + ObjVal = inner_val + if ObjVal is None: + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + return None + pointee = ObjVal.type.pointee + if isinstance(pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr") + pointee = ObjVal.type.pointee + found = Gen.find_struct_by_pointee(pointee) + if not found: + return None + CN, ST = found + st, ok = self._try_load_struct_from_stub(Gen, CN) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + bitfield_offsets = Gen.class_member_bitoffsets.get(CN, {}) + if Node.attr in bitfield_offsets: + return self._load_bitfield_member(ObjVal, CN, Node.attr) + offset = Gen._get_member_offset(Node.attr, CN) + if offset is None: + return None + return self._gep_and_load_member(Gen, ObjVal, offset, Node.attr, CN, st) + + def _handle_attr_subscript_result(self, Node): + """处理 arr[i].attr 属性访问""" + Gen = self.Trans.LlvmGen + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + return None + pointee = ObjVal.type.pointee + if not isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + return None + found = Gen.find_struct_by_pointee(pointee) + if not found: + return None + CN, ST = found + st, ok = self._try_load_struct_from_stub(Gen, CN) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + offset = Gen._get_member_offset(Node.attr, CN) + if offset is None: + return None + return self._gep_and_load_member(Gen, ObjVal, offset, Node.attr, CN, st) + + def _handle_attr_fallback(self, Node): + """兜底:对任意值尝试指针解引用后查找结构体成员""" + Gen = self.Trans.LlvmGen + ObjVal = self.HandleExprLlvm(Node.value) + if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): + return None + pointee = ObjVal.type.pointee + if isinstance(pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr_fallback") + pointee = ObjVal.type.pointee + if not isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + return None + found = Gen.find_struct_by_pointee(pointee) + if not found: + return None + CN, ST = found + st, ok = self._try_load_struct_from_stub(Gen, CN) + if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + offset = Gen._get_member_offset(Node.attr, CN) + if offset is None: + return None + return self._gep_and_load_member(Gen, ObjVal, offset, Node.attr, CN, st) + + # ========== 主入口 ========== + + def _HandleAttributeLlvm(self, Node): + Gen = self.Trans.LlvmGen + + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + # 处理 t/c import 的别名重定向 + t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) + if VarName != 'self' and VarName in t_c_imported: + src_module, src_name = t_c_imported[VarName] + virtual_attr = ast.Attribute( + value=ast.Name(id=src_module, ctx=ast.Load()), + attr=src_name, ctx=ast.Load() + ) + ast.copy_location(virtual_attr, Node) + return self._HandleAttributeLlvm(ast.Attribute( + value=virtual_attr, attr=Node.attr, ctx=ast.Load() + )) + if VarName == 'self': + return self._handle_attr_self(Node, VarName) + return self._handle_attr_name(Node, VarName) + + elif isinstance(Node.value, ast.Attribute): + return self._handle_attr_nested(Node) + + elif isinstance(Node.value, ast.Call): + return self._handle_attr_call_result(Node) + + elif isinstance(Node.value, ast.Subscript): + return self._handle_attr_subscript_result(Node) + + # 兜底 + return self._handle_attr_fallback(Node) + + # ========== HandleSubscript 及其辅助 ========== + + def _HandleSubscriptLlvm(self, Node): + Gen = self.Trans.LlvmGen + ClassName = self.Trans.ExprHandler._get_var_class(Node.value, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__getitem__'): + obj_val = self.HandleExprLlvm(Node.value) + idx_val = self.HandleExprLlvm(Node.slice) + if obj_val and idx_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64: + idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx") + result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__") + return result + ValueVal = self.HandleExprLlvm(Node.value) + if not ValueVal: + return None + IndexVal = self.HandleExprLlvm(Node.slice) + if not IndexVal: + return None + if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8: + loaded_byte = Gen._load(IndexVal, name="load_char_idx") + IndexVal = Gen.builder.zext(loaded_byte, ir.IntType(32), name="char_to_int_idx") + if isinstance(ValueVal.type, ir.IntType): + var_ptr = self._get_int_ptr(Node.value) + if var_ptr: + i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") + ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") + return Gen._load(ptr, name="int_subscript_val") + return None + if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + if isinstance(ValueVal.type.pointee.pointee, ir.IntType) and ValueVal.type.pointee.pointee.width == 8: + return Gen._load(ElemPtr, name="subscript_val") + return Gen._load(ElemPtr, name="subscript_val") + if isinstance(ValueVal.type, ir.PointerType): + pointee = ValueVal.type.pointee + if isinstance(pointee, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") + elem_type = pointee.element + if isinstance(elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + else: + if isinstance(pointee, ir.IntType) and pointee.width == 8: + elem_class = self._infer_element_struct_class(Node.value, Gen) + if elem_class and elem_class in Gen.structs: + CastedPtr = Gen.builder.bitcast(ValueVal, ir.PointerType(Gen.structs[elem_class]), name=f"cast_{elem_class}_arr") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_arr_index") + ElemPtr = Gen.builder.gep(CastedPtr, [IndexVal], name="subscript") + if isinstance(pointee, ir.IntType): + return Gen._load(ElemPtr, name="subscript_val") + return ElemPtr + arr_type = self._infer_array_member_type(Node.value, Gen) + if arr_type and isinstance(arr_type, ir.ArrayType): + arr_ptr = Gen.builder.bitcast(ValueVal, ir.PointerType(arr_type), name=f"cast_arr_subscript") + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(arr_ptr, [zero, IndexVal], name="subscript") + arr_elem_type = arr_type.element + if isinstance(arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + elif isinstance(ValueVal.type, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") + var_arr_elem_type = VarPtr.type.pointee.element + if isinstance(var_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + if isinstance(Node.value, ast.Attribute): + AttrPtr = self._get_attr_ptr(Node.value) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") + attr_arr_elem_type = AttrPtr.type.pointee.element + if isinstance(attr_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + if isinstance(Node.value, ast.Subscript): + InnerPtr = self.HandleSubscriptPtrLlvm(Node.value) + if InnerPtr and isinstance(InnerPtr.type, ir.PointerType): + inner_pointee = InnerPtr.type.pointee + if isinstance(inner_pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript") + inner_elem_type = inner_pointee.element + if isinstance(inner_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp") + Gen._store(ValueVal, arr_alloc) + ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") + alloc_arr_elem_type = ValueVal.type.element + if isinstance(alloc_arr_elem_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + return ElemPtr + return Gen._load(ElemPtr, name="subscript_val") + return None + + def HandleSubscriptPtrLlvm(self, Node): + Gen = self.Trans.LlvmGen + ValueVal = self.HandleExprLlvm(Node.value) + if not ValueVal: + return None + IndexVal = self.HandleExprLlvm(Node.slice) + if not IndexVal: + return None + if isinstance(IndexVal.type, ir.PointerType) and isinstance(IndexVal.type.pointee, ir.IntType) and IndexVal.type.pointee.width == 8: + loaded_byte = Gen._load(IndexVal, name="load_char_idx_ptr") + IndexVal = Gen.builder.zext(loaded_byte, ir.IntType(32), name="char_to_int_idx_ptr") + if isinstance(ValueVal.type, ir.PointerType): + pointee = ValueVal.type.pointee + if isinstance(pointee, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + elif isinstance(pointee, ir.PointerType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_ptr") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr") + return ElemPtr + else: + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript_ptr") + return ElemPtr + elif isinstance(ValueVal.type, ir.IntType): + var_ptr = self._get_int_ptr(Node.value) + if var_ptr: + i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") + ElemPtr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") + return ElemPtr + elif isinstance(ValueVal.type, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + if isinstance(Node.value, ast.Subscript): + InnerPtr = self.HandleSubscriptPtrLlvm(Node.value) + if InnerPtr: + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + if isinstance(Node.value, ast.Attribute): + AttrPtr = self._get_attr_ptr(Node.value) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp") + Gen._store(ValueVal, arr_alloc) + ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript_ptr") + return ElemPtr + return None + + # ========== _get_attr_ptr / _get_int_ptr / _get_attr_class ========== + + def _get_attr_ptr(self, Node): + Gen = self.Trans.LlvmGen + if not isinstance(Node, ast.Attribute): + return None + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName == 'self': + ClassName = self.Trans._CurrentCpythonObjectClass + if ClassName: + offset = Gen._get_member_offset(Node.attr, ClassName) + SelfVar = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr = Gen._load(SelfVar, name="self") + if isinstance(SelfPtr.type, ir.PointerType): + MemberPtr = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + ClassName = Gen.var_struct_class.get(VarName) + if not ClassName and getattr(Gen, 'global_struct_class', None): + ClassName = Gen.global_struct_class.get(VarName) + if not ClassName: + imported_modules = getattr(self.Trans, '_imported_modules', None) + import_aliases = getattr(self.Trans, '_import_aliases', {}) + resolved_mod = import_aliases.get(VarName, VarName) + if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): + AttrName = Node.attr + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + candidates = [VarName, resolved_mod] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + if mod_name not in candidates: + candidates.append(mod_name) + for cand in candidates: + sha1 = module_sha1_map.get(cand) + if sha1: + prefixed = f"{sha1}.{AttrName}" + if prefixed in Gen.module.globals: + return Gen.module.globals[prefixed] + if AttrName in Gen.module.globals: + gv = Gen.module.globals[AttrName] + if isinstance(gv, ir.GlobalVariable): + return gv + if ClassName and ClassName in Gen.structs: + VarPtr = Gen.variables.get(VarName) + if VarPtr: + ObjVal = VarPtr + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"load_{VarName}") + if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == Gen.structs[ClassName]: + ST = Gen.structs[ClassName] + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + ST = Gen.structs.get(ClassName, ST) + if ST.elements is not None and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{ClassName}") + offset = Gen._get_member_offset(Node.attr, ClassName) + if offset is not None and ST.elements is not None: + MemberPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + elif isinstance(Node.value, ast.Attribute): + InnerPtr = self._get_attr_ptr(Node.value) + if InnerPtr and isinstance(InnerPtr.type, ir.PointerType): + pointee = InnerPtr.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(pointee) + if found: + CN, ST = found + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) + ST = Gen.structs.get(CN, ST) + if ST.elements is not None and isinstance(InnerPtr.type, ir.PointerType) and isinstance(InnerPtr.type.pointee, ir.IdentifiedStructType) and InnerPtr.type.pointee.elements is None: + InnerPtr = Gen.builder.bitcast(InnerPtr, ir.PointerType(ST), name=f"cast_{CN}") + offset = Gen._get_member_offset(Node.attr, CN) + if offset is not None and ST.elements is not None: + MemberPtr = Gen.builder.gep(InnerPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + AttrClassName = self._get_attr_class(Node.value, Gen) + if AttrClassName and AttrClassName in Gen.structs: + CastedObj = Gen.builder.bitcast(InnerPtr, ir.PointerType(Gen.structs[AttrClassName]), name=f"cast_{AttrClassName}") + offset = Gen._get_member_offset(Node.attr, AttrClassName) + if offset is not None: + MemberPtr = Gen.builder.gep(CastedObj, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + elif isinstance(Node.value, ast.Subscript): + SubPtr = self.HandleSubscriptPtrLlvm(Node.value) + if SubPtr and isinstance(SubPtr.type, ir.PointerType): + pointee = SubPtr.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(pointee) + if found: + CN, ST = found + offset = Gen._get_member_offset(Node.attr, CN) + if offset is not None: + MemberPtr = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=Node.attr) + return MemberPtr + return None + + def _HandleSliceLlvm(self, base_val, slice_node, base_ast): + Gen = self.Trans.LlvmGen + lower_val = None + upper_val = None + step_val = None + if isinstance(slice_node, ast.Slice): + if slice_node.lower: + lower_val = self.HandleExprLlvm(slice_node.lower) + if slice_node.upper: + upper_val = self.HandleExprLlvm(slice_node.upper) + if slice_node.step: + step_val = self.HandleExprLlvm(slice_node.step) + if isinstance(slice_node, ast.Index): + return self.HandleExprLlvm(slice_node.value) + return None + + def _infer_element_struct_class(self, node, Gen): + if isinstance(node, ast.Attribute): + attr_name = node.attr + if isinstance(node.value, ast.Name) and node.value.id == 'self': + current_class = self.Trans._CurrentCpythonObjectClass + if current_class: + if current_class in Gen.class_member_element_class: + elem_class = Gen.class_member_element_class[current_class].get(attr_name) + if elem_class and elem_class in Gen.structs: + return elem_class + if current_class in Gen.class_members: + for member_name, member_type in Gen.class_members[current_class]: + if member_name == attr_name: + if isinstance(member_type, ir.IdentifiedStructType): + found = Gen.find_struct_by_pointee(member_type) + if found: + return found[0] + break + class_name = Gen.var_struct_class.get(attr_name) + if class_name: + return class_name + elif isinstance(node, ast.Name): + var_name = node.id + class_name = Gen.var_struct_class.get(var_name) + if class_name: + return class_name + return None + + def _get_int_ptr(self, target): + Gen = self.Trans.LlvmGen + if isinstance(target, ast.Name): + VarName = target.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType): + pointee = VarPtr.type.pointee + if isinstance(pointee, ir.ArrayType): + return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") + return VarPtr + elif isinstance(target, ast.Attribute): + if isinstance(target.value, ast.Name): + obj_name = target.value.id + if obj_name in Gen.variables and Gen.variables[obj_name] is not None: + obj_ptr = Gen.variables[obj_name] + if isinstance(obj_ptr.type, ir.PointerType): + pointee = obj_ptr.type.pointee + if isinstance(pointee, ir.PointerType): + obj_ptr = Gen._load(obj_ptr, name=f"load_{obj_name}") + pointee = obj_ptr.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + StructName = None + if isinstance(pointee, ir.IdentifiedStructType): + StructName = pointee.name + if not StructName: + found = Gen.find_struct_by_pointee(pointee) + if found: + StructName = found[0] + if StructName and StructName in Gen.structs: + offset = Gen._get_member_offset(target.attr, StructName) + if offset is not None: + return Gen.builder.gep(obj_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr") + obj_val = self.HandleExprLlvm(target.value) + if obj_val and isinstance(obj_val.type, ir.PointerType): + if isinstance(obj_val.type.pointee, ir.PointerType): + obj_val = Gen._load(obj_val, name="load_attr_ptr") + pointee = obj_val.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + StructName = None + if isinstance(pointee, ir.IdentifiedStructType): + StructName = pointee.name + if not StructName: + found = Gen.find_struct_by_pointee(pointee) + if found: + StructName = found[0] + if StructName and StructName in Gen.structs: + offset = Gen._get_member_offset(target.attr, StructName) + if offset is not None: + return Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr") + return None + + def _resolve_struct_class_for_attr(self, Node, Gen): + if isinstance(Node, ast.Name): + VarName = Node.id + if VarName in Gen.var_struct_class: + return Gen.var_struct_class[VarName] + elif isinstance(Node, ast.Attribute): + ClassName = self._resolve_struct_class_for_attr(Node.value, Gen) + if ClassName and ClassName in Gen.class_members: + for member_name, _ in Gen.class_members[ClassName]: + if member_name == Node.attr: + return ClassName + return None + + def _infer_array_member_type(self, Node, Gen): + if isinstance(Node, ast.Attribute): + parent_class = self._get_attr_class(Node, Gen) + if parent_class and parent_class in Gen.class_members: + for m_name, m_type in Gen.class_members[parent_class]: + if m_name == Node.attr and isinstance(m_type, ir.ArrayType): + return m_type + if parent_class and parent_class in Gen.structs: + st = Gen.structs[parent_class] + if isinstance(st, ir.IdentifiedStructType) and st.elements is not None: + offset = Gen._get_member_offset(Node.attr, parent_class) + if offset is not None and offset < len(st.elements): + elem = st.elements[offset] + if isinstance(elem, ir.ArrayType): + return elem + return None + + def _build_attr_path(self, node): + parts = [] + current = node + while isinstance(current, ast.Attribute): + parts.append(current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.append(current.id) + parts.reverse() + return parts + + def _try_resolve_nested_cdefine(self, Node): + Gen = self.Trans.LlvmGen + imported_modules = getattr(self.Trans, '_imported_modules', None) + if not imported_modules: + return None + import_aliases = getattr(self.Trans, '_import_aliases', {}) + parts = self._build_attr_path(Node) + if len(parts) < 2: + return None + attr_name = parts[-1] + module_parts = parts[:-1] + possible_keys = [attr_name] + full_path = '.'.join(parts) + possible_keys.append(full_path) + if module_parts: + module_path = '.'.join(module_parts) + resolved_first = import_aliases.get(module_parts[0], module_parts[0]) + if resolved_first != module_parts[0]: + resolved_parts = [resolved_first] + module_parts[1:] + resolved_path = '.'.join(resolved_parts) + possible_keys.append(f"{resolved_path}.{attr_name}") + for mod_name in imported_modules: + if mod_name.endswith('.' + module_path) or mod_name == module_path: + key = f"{mod_name}.{attr_name}" + if key not in possible_keys: + possible_keys.append(key) + if module_parts and (mod_name.endswith('.' + module_parts[-1]) or mod_name == module_parts[-1]): + key = f"{mod_name}.{attr_name}" + if key not in possible_keys: + possible_keys.append(key) + for lookup_key in possible_keys: + SymInfo = self.Trans.SymbolTable.get(lookup_key) + if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None: + val = SymInfo.DefineValue + if isinstance(val, int): + if val > 0x7FFFFFFF or val < -0x80000000: + return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF) + return ir.Constant(ir.IntType(32), val) + elif isinstance(val, float): + return ir.Constant(ir.FloatType(), val) + return None + + def _try_resolve_cross_module_enum(self, module_alias, enum_class_name, member_name): + Gen = self.Trans.LlvmGen + imported_modules = getattr(self.Trans, '_imported_modules', None) + if not imported_modules: + return None + import_aliases = getattr(self.Trans, '_import_aliases', {}) + resolved_module = import_aliases.get(module_alias, module_alias) + if resolved_module not in imported_modules and module_alias not in imported_modules: + return None + enum_keys = [enum_class_name, f"{resolved_module}.{enum_class_name}"] + for enum_key in enum_keys: + if enum_key in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[enum_key] + if getattr(SymInfo, 'IsEnum', None): + for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"): + if qname in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[qname] + if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + for key, info in self.Trans.SymbolTable.items(): + if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_key and key == member_name: + if isinstance(getattr(info, 'value', None), int): + return ir.Constant(ir.IntType(32), info.value) + for key, info in self.Trans.SymbolTable.items(): + if getattr(info, 'IsEnumMember', None) and key == member_name: + if isinstance(getattr(info, 'value', None), int): + for enum_key in enum_keys: + if getattr(info, 'EnumName', None) == enum_key: + return ir.Constant(ir.IntType(32), info.value) + return None + + def _get_attr_class(self, Node, Gen): + if isinstance(Node, ast.Attribute): + # 注: 不再硬编码 ZLIB_VERSION / C_OK,它们应从符号表查找 + if isinstance(Node.value, ast.Name) and Node.value.id == 'self': + ClassName = self.Trans._CurrentCpythonObjectClass + if ClassName and ClassName in Gen.class_member_element_class: + return Gen.class_member_element_class[ClassName].get(Node.attr) + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName in Gen.var_struct_class: + ParentClass = Gen.var_struct_class[VarName] + if ParentClass in Gen.class_member_element_class: + return Gen.class_member_element_class[ParentClass].get(Node.attr) + if isinstance(Node.value, ast.Attribute): + ParentClass = self._get_attr_class(Node.value, Gen) + if ParentClass and ParentClass in Gen.class_member_element_class: + return Gen.class_member_element_class[ParentClass].get(Node.attr) + return None + + def _get_llvm_member_offset(self, field_name, ClassName, Gen): + return Gen._get_member_offset(field_name, ClassName) + + def _load_bitfield_member(self, struct_ptr, ClassName, field_name): + Gen = self.Trans.LlvmGen + bitfield_offsets = Gen.class_member_bitoffsets.get(ClassName, {}) + bitfield_widths = Gen.class_member_bitfields.get(ClassName, {}) + if field_name not in bitfield_offsets: + return None + bit_offset = bitfield_offsets[field_name] + bit_width = bitfield_widths.get(field_name, 0) + if bit_width == 0: + return None + struct_type = Gen.structs.get(ClassName) + if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0: + return None + storage_type = struct_type.elements[0] + member_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr") + storage_val = Gen._load(member_ptr, name=f"{field_name}_storage") + shift_amount = bit_offset + if shift_amount > 0: + shifted = Gen.builder.lshr(storage_val, ir.Constant(storage_type, shift_amount), name=f"{field_name}_shift") + else: + shifted = storage_val + mask = (1 << bit_width) - 1 + masked = Gen.builder.and_(shifted, ir.Constant(storage_type, mask), name=f"{field_name}_mask") + is_signed = Gen.class_member_signeds.get(ClassName, {}).get(field_name, False) + if is_signed and bit_width > 0: + sign_bit = 1 << (bit_width - 1) + sign_masked = Gen.builder.and_(shifted, ir.Constant(storage_type, sign_bit), name=f"{field_name}_sign") + sign_extend = Gen.builder.icmp_signed('!=', sign_masked, ir.Constant(storage_type, 0), name=f"{field_name}_sign_check") + extended = Gen.builder.select(sign_extend, + Gen.builder.sext(masked, ir.IntType(32), name=f"{field_name}_sext"), + Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext"), + name=f"{field_name}_extend") + return extended + return Gen.builder.zext(masked, ir.IntType(32), name=f"{field_name}_zext") \ No newline at end of file diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py new file mode 100644 index 0000000..0bb130e --- /dev/null +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -0,0 +1,854 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprBuiltinHandle(BaseHandle): + _C_LIB_FUNCS = { + 'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), + 'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), + 'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]), + 'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), + 'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), + 'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), + 'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), + 'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), + 'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), + 'abs': lambda: (ir.IntType(32), [ir.IntType(32)]), + 'labs': lambda: (ir.IntType(64), [ir.IntType(64)]), + } + + def _HandleBuiltinCallLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not isinstance(Node.func, ast.Name): + return None + FuncName = Node.func.id + + if FuncName == 'print': + return self._HandlePrintLlvm(Node) + elif FuncName == 'len': + if Node.args: + return self._HandleLenLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'sizeof': + if Node.args: + return self._HandleSizeofLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'abs': + if Node.args: + return self._HandleAbsLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'arg': + return self._HandleArgLlvm(Node.args) + elif FuncName == 'bool': + if Node.args: + Val = self.HandleExprLlvm(Node.args[0]) + if Val: + if isinstance(Val.type, ir.IntType): + if Val.type.width == 1: + return Val + return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result") + elif isinstance(Val.type, ir.PointerType): + return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result") + return Val + return ir.Constant(ir.IntType(1), 0) + elif FuncName == 'int': + if Node.args: + Val = self.HandleExprLlvm(Node.args[0]) + if Val: + if isinstance(Val.type, ir.IntType): + if Val.type.width < 32: + return Gen.builder.zext(Val, ir.IntType(32), name="cast_int") + elif Val.type.width > 32: + return Gen.builder.trunc(Val, ir.IntType(32), name="trunc_int") + return Val + elif isinstance(Val.type, ir.PointerType): + if isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: + result = self._HandleAtoiLlvm(Val) + if result: + return result + elif isinstance(Val.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fptosi(Val, ir.IntType(32), name="float_to_int") + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'float' or FuncName == 'double': + if Node.args: + Val = self.HandleExprLlvm(Node.args[0]) + if Val: + target_type = ir.DoubleType() if FuncName == 'double' else ir.FloatType() + if isinstance(Val.type, (ir.FloatType, ir.DoubleType)): + if Val.type != target_type: + if isinstance(target_type, ir.DoubleType): + return Gen.builder.fpext(Val, target_type, name="fpext_double") + return Gen.builder.fptrunc(Val, target_type, name="fptrunc_float") + return Val + elif isinstance(Val.type, ir.IntType): + if Val.type.width == 1: + return Gen.builder.uitofp(Val, target_type, name="uitofp") + return Gen.builder.sitofp(Val, target_type, name="sitofp") + return ir.Constant(ir.DoubleType() if FuncName == 'double' else ir.FloatType(), 0.0) + elif FuncName == 'min': + if len(Node.args) >= 2: + a = self.HandleExprLlvm(Node.args[0]) + b = self.HandleExprLlvm(Node.args[1]) + if a and b: + is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType)) + if is_float: + fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="min_int2float") + fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="min_int2float") + cmp = Gen.builder.fcmp_ordered('olt', fa, fb, name="min_cmp") + return Gen.builder.select(cmp, fa, fb, name="min_val") + else: + cmp = Gen.builder.icmp_signed('<', a, b, name="min_cmp") + return Gen.builder.select(cmp, a, b, name="min_val") + elif len(Node.args) == 1: + return self.HandleExprLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'max': + if len(Node.args) >= 2: + a = self.HandleExprLlvm(Node.args[0]) + b = self.HandleExprLlvm(Node.args[1]) + if a and b: + is_float = isinstance(a.type, (ir.FloatType, ir.DoubleType)) or isinstance(b.type, (ir.FloatType, ir.DoubleType)) + if is_float: + fa = Gen._to_float(a, ir.FloatType()) if isinstance(a.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(a, ir.FloatType(), name="max_int2float") + fb = Gen._to_float(b, ir.FloatType()) if isinstance(b.type, (ir.FloatType, ir.DoubleType)) else Gen.builder.sitofp(b, ir.FloatType(), name="max_int2float") + cmp = Gen.builder.fcmp_ordered('ogt', fa, fb, name="max_cmp") + return Gen.builder.select(cmp, fa, fb, name="max_val") + else: + cmp = Gen.builder.icmp_signed('>', a, b, name="max_cmp") + return Gen.builder.select(cmp, a, b, name="max_val") + elif len(Node.args) == 1: + return self.HandleExprLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'str': + if Node.args: + arg_node = Node.args[0] + arg_val = self.HandleExprLlvm(arg_node) + if arg_val: + if isinstance(arg_val.type, ir.PointerType): + ClassName = self.Trans.ExprHandler._get_var_class(arg_node, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__str__'): + if isinstance(arg_val.type, ir.PointerType) and isinstance(arg_val.type.pointee, ir.IntType) and arg_val.type.pointee.width == 8: + if ClassName in Gen.structs: + arg_val = Gen.builder.bitcast(arg_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_str") + str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__") + return str_val + return arg_val + return self._EmitStringFromValue(arg_val) + return ir.Constant(ir.IntType(8).as_pointer(), None) + elif FuncName == 'input': + return self._HandleInputLlvm(Node) + elif FuncName == 'ord': + if Node.args: + return self._HandleOrdLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'chr': + if Node.args: + return self._HandleChrLlvm(Node.args[0]) + return ir.Constant(ir.IntType(8), 0) + elif FuncName == 'malloc': + return self._HandleMallocLlvm(Node.args) + elif FuncName == 'realloc': + return self._HandleReallocLlvm(Node.args) + elif FuncName == 'free': + return self._HandleFreeLlvm(Node.args) + elif FuncName == 'memcpy': + return self._HandleMemcpyLlvm(Node.args) + elif FuncName == 'memset': + return self._HandleMemsetLlvm(Node.args) + elif FuncName == 'va_start': + return self._HandleVaStartLlvm(Node.args) + elif FuncName == 'va_end': + return self._HandleVaEndLlvm(Node.args) + elif FuncName == 'va_arg': + return self._HandleVaArgLlvm(Node.args) + elif FuncName == 'dir': + return self._HandleDirLlvm(Node) + elif FuncName == 'type': + return self._HandleTypeLlvm(Node) + return None + + def _HandlePrintLlvm(self, Node): + Gen = self.Trans.LlvmGen + printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + args = Node.args + end_arg = None + sep_arg = None + if Node.keywords: + for kw in Node.keywords: + if kw.arg == 'end': + end_arg = kw.value + elif kw.arg == 'sep': + sep_arg = kw.value + sep_str = ' ' + if sep_arg and isinstance(sep_arg, ast.Constant) and isinstance(sep_arg.value, str): + sep_str = sep_arg.value + end_str = '\n' + if end_arg: + if isinstance(end_arg, ast.Constant) and isinstance(end_arg.value, str): + end_str = end_arg.value + elif isinstance(end_arg, ast.Constant) and end_arg.value is None: + end_str = '' + if not args: + if end_str: + nl_fmt = Gen.emit_constant(end_str, 'string') + Gen.builder.call(printf_func, [nl_fmt], name="print_nl") + return + has_fstring = any(isinstance(arg, ast.JoinedStr) for arg in args) + if has_fstring: + self._HandlePrintWithFString(Node, printf_func, args, sep_str, end_str) + return + fmt_parts = [] + fmt_args = [] + for i, arg in enumerate(args): + if i > 0: + fmt_parts.append(sep_str) + val = self.HandleExprLlvm(arg) + if not val: + fmt_parts.append('(null)') + continue + if isinstance(val, ir.Constant) and isinstance(val.type, ir.PointerType) and val.constant is None: + fmt_parts.append('nil') + continue + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, ir.IntType) and pointee.width == 8: + fmt_parts.append('%s') + fmt_args.append(val) + elif isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8: + elem_ptr = Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="print_arr_to_ptr") + fmt_parts.append('%s') + fmt_args.append(elem_ptr) + elif isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen) + if not ClassName and isinstance(arg, ast.Name): + ClassName = Gen.var_struct_class.get(arg.id) + if ClassName and Gen._has_function(f'{ClassName}.__str__'): + if isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8: + if ClassName in Gen.structs: + val = Gen.builder.bitcast(val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [val], name=f"call_{ClassName}.__str__") + fmt_parts.append('%s') + fmt_args.append(str_val) + else: + int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int") + fmt_parts.append('0x%llx') + fmt_args.append(int_val) + else: + int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int") + fmt_parts.append('%lld') + fmt_args.append(int_val) + elif isinstance(val.type, ir.IntType): + is_unsigned = self._is_val_unsigned(arg, val) + if val.type.width == 1: + fmt_parts.append('%d') + val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print") + elif val.type.width == 8: + if self._is_char_type(arg): + char_var = Gen._alloca_entry(ir.IntType(8), name="print_char_buf") + Gen.builder.store(val, char_var) + fmt_parts.append('%c') + fmt_args.append(char_var) + continue + fmt_parts.append('%d') + if is_unsigned: + val = Gen.builder.zext(val, ir.IntType(32), name="zext_i8_print") + else: + val = Gen.builder.sext(val, ir.IntType(32), name="sext_i8_print") + elif val.type.width == 16: + fmt_parts.append('%u' if is_unsigned else '%d') + if is_unsigned: + val = Gen.builder.zext(val, ir.IntType(32), name="zext_i16_print") + else: + val = Gen.builder.sext(val, ir.IntType(32), name="sext_i16_print") + elif val.type.width == 32: + fmt_parts.append('%u' if is_unsigned else '%d') + elif val.type.width == 64: + fmt_parts.append('%llu' if is_unsigned else '%lld') + else: + fmt_parts.append('%d') + val = Gen.builder.zext(val, ir.IntType(32), name="zext_int_print") + fmt_args.append(val) + elif isinstance(val.type, ir.FloatType): + fmt_parts.append('%f') + fmt_args.append(Gen.builder.fpext(val, ir.DoubleType(), name="fpext_printf_float")) + elif isinstance(val.type, ir.DoubleType): + fmt_parts.append('%f') + fmt_args.append(val) + else: + fmt_parts.append('(unknown)') + fmt_parts.append(end_str) + fmt_str = ''.join(fmt_parts) + fmt_bytes = fmt_str.encode('utf-8') + b'\x00' + fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes)) + fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes)) + fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}") + Gen.string_const_counter += 1 + fmt_gvar.initializer = fmt_const + fmt_gvar.linkage = 'internal' + fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name="print_fmt") + call_args = [fmt_ptr] + fmt_args + return Gen.builder.call(printf_func, call_args, name="print_call") + + def _HandlePrintWithFString(self, Node, printf_func, args, sep_str, end_str): + Gen = self.Trans.LlvmGen + for i, arg in enumerate(args): + if i > 0: + sep_const = Gen.emit_constant(sep_str, 'string') + Gen.builder.call(printf_func, [sep_const], name="print_sep") + if isinstance(arg, ast.JoinedStr): + self.HandleExprLlvm(arg) + else: + ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__str__'): + obj_val = self.HandleExprLlvm(arg) + if obj_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + if ClassName in Gen.structs: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__") + Gen._register_temp_ptr(str_val) + Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) + else: + val = self.HandleExprLlvm(arg) + if val: + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if not (isinstance(pointee, ir.IntType) and pointee.width == 8): + try: + val = Gen._load(val, name="print_load") + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + is_u = Gen._check_node_unsigned(arg) + if not is_u and id(val) in Gen._unsigned_results: + is_u = True + Gen._emit_printf([val], unsigned_flags=[is_u], sep=None, end=None) + if end_str: + end_const = Gen.emit_constant(end_str, 'string') + Gen.builder.call(printf_func, [end_const], name="print_end") + return ir.Constant(ir.IntType(32), 0) + + def _is_char_type(self, arg_node): + if isinstance(arg_node, ast.Call): + if isinstance(arg_node.func, ast.Name): + return arg_node.func.id in ('CChar', 'CUInt8T', 'CInt8T') + if isinstance(arg_node.func, ast.Attribute): + return arg_node.func.attr in ('CChar', 'CUInt8T', 'CInt8T') + return False + + def _is_val_unsigned(self, arg_node, val): + Gen = self.Trans.LlvmGen + if isinstance(arg_node, ast.Name): + var_name = arg_node.id + signedness = Gen.var_signedness.get(var_name) + if signedness: + if isinstance(signedness, bool): + return signedness + return 'unsigned' in signedness + if isinstance(val.type, ir.IntType): + return False + return False + + def _try_declare_c_lib_func(self, func_name, Gen): + if func_name not in self._C_LIB_FUNCS: + return None + ret_type, param_types = self._C_LIB_FUNCS[func_name]() + func_type = ir.FunctionType(ret_type, param_types) + func = ir.Function(Gen.module, func_type, name=func_name) + Gen.functions[func_name] = func + return func + + def _HandleLenLlvm(self, arg_node): + Gen = self.Trans.LlvmGen + if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self': + attr_name = arg_node.attr + len_member = f'{attr_name}__len' + current_class = self.Trans._CurrentCpythonObjectClass + if current_class and current_class in Gen.class_members: + for m_name, m_type in Gen.class_members[current_class]: + if m_name == len_member: + self_val = Gen._get_var_ptr('self') + if self_val: + self_ptr = Gen._load(self_val, name="self_for_len") + offset = Gen._get_member_offset(len_member, current_class) + len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr") + return Gen._load(len_ptr, name=f"self_{len_member}") + val = self.HandleExprLlvm(arg_node) + if not val: + return None + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, ir.PointerType): + val = Gen._load(val, name="len_deref") + pointee = val.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + result = self.Trans.ExprUtils._try_operator_overload(CN, '__len__', val, Gen) + if result is not None: + return result + break + if isinstance(pointee, ir.ArrayType): + return ir.Constant(ir.IntType(64), pointee.count) + if isinstance(pointee, (ir.FloatType, ir.DoubleType, ir.IntType)) and pointee.width != 8: + return ir.Constant(ir.IntType(64), 0) + if val.type != ir.PointerType(ir.IntType(8)): + val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast") + correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))]) + strlen_func = None + if 'strlen' in Gen.functions: + existing = Gen.functions['strlen'] + if existing.ftype == correct_strlen_type: + strlen_func = existing + if not strlen_func: + try: + strlen_func = ir.Function(Gen.module, correct_strlen_type, name='strlen') + Gen.functions['strlen'] = strlen_func + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + if strlen_func: + result = Gen.builder.call(strlen_func, [val], name="strlen_call") + return result + elif isinstance(val.type, ir.ArrayType): + return ir.Constant(ir.IntType(64), val.type.count) + return ir.Constant(ir.IntType(64), 0) + + def _HandleSizeofLlvm(self, Node): + Gen = self.Trans.LlvmGen + if isinstance(Node, ast.Name): + type_name = Node.id + elif isinstance(Node, ast.Attribute): + type_name = Node.attr + else: + return ir.Constant(ir.IntType(64), 0) + + if type_name not in Gen.structs: + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(type_name) + if ctype_cls is not None: + try: + ctype_inst = ctype_cls() + size_bits = getattr(ctype_inst, 'Size', 0) or 0 + size_bytes = size_bits // 8 + return ir.Constant(ir.IntType(64), size_bytes) + except Exception: + pass + resolved = CTypeRegistry.ResolveName(type_name) + if resolved: + ctype_cls, ptr_level = resolved + try: + ctype_inst = ctype_cls() + size_bits = getattr(ctype_inst, 'Size', 0) or 0 + size_bytes = size_bits // 8 + if ptr_level > 0: + size_bytes = 8 + return ir.Constant(ir.IntType(64), size_bytes) + except Exception: + pass + return ir.Constant(ir.IntType(64), 0) + + struct_type = Gen.structs[type_name] + if isinstance(struct_type, ir.PointerType): + struct_type = struct_type.pointee + if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen) + struct_type = Gen.structs.get(type_name, struct_type) + size = Gen._get_struct_size(struct_type) + if size > 0: + return ir.Constant(ir.IntType(64), size) + return ir.Constant(ir.IntType(64), 0) + + def _HandleAbsLlvm(self, arg_node): + Gen = self.Trans.LlvmGen + val = self.HandleExprLlvm(arg_node) + if not val: + return None + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + result = self.Trans.ExprUtils._try_operator_overload(CN, '__abs__', val, Gen) + if result is not None: + return result + break + if isinstance(val.type, ir.IntType): + neg_val = Gen.builder.neg(val, name="abs_neg") + is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg") + return Gen.builder.select(is_neg, neg_val, val, name="abs_result") + elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): + zero = ir.Constant(val.type, 0.0) + neg_val = Gen.builder.fneg(val, name="fabs_neg") + is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg") + return Gen.builder.select(is_neg, neg_val, val, name="fabs_result") + return None + + def _HandleDirLlvm(self, Node): + Gen = self.Trans.LlvmGen + return ir.Constant(ir.IntType(8).as_pointer(), None) + + def _HandleTypeLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + type_str = "" + else: + arg = Node.args[0] + enum_type_name = None + + def _get_attr_path(node): + if isinstance(node, ast.Name): + return node.id + elif isinstance(node, ast.Attribute): + return f"{_get_attr_path(node.value)}.{node.attr}" + return None + + if isinstance(arg, ast.Name): + arg_name = arg.id + Gen = self.Trans.LlvmGen + if arg_name in Gen.var_type_info: + type_info = Gen.var_type_info[arg_name] + if isinstance(type_info, dict) and type_info.get('type') == 'enum': + enum_type_name = type_info.get('name') + if not enum_type_name and arg_name in self.Trans.SymbolTable: + TypeInfo = self.Trans.SymbolTable[arg_name] + if TypeInfo.IsEnum: + enum_type_name = arg_name + elif isinstance(arg, ast.Attribute): + last_part = None + enum_class_name = None + if isinstance(arg.value, ast.Name): + last_part = arg.attr + if last_part in self.Trans.SymbolTable: + AttrInfo = self.Trans.SymbolTable[last_part] + if getattr(AttrInfo, 'IsEnumMember', None) and getattr(AttrInfo, 'EnumName', None): + enum_type_name = AttrInfo.EnumName + elif isinstance(arg.value, ast.Attribute): + attr_path = _get_attr_path(arg) + if attr_path: + parts = attr_path.split('.') + if len(parts) >= 2: + enum_class_name = parts[-2] + last_part = parts[-1] + qualified_name_dot = f"{enum_class_name}.{last_part}" + qualified_name_under = f"{enum_class_name}_{last_part}" + enum_member_found = None + for qname in (qualified_name_dot, qualified_name_under): + if qname in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[qname] + if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name: + enum_member_found = info + break + if not enum_member_found: + for key in self.Trans.SymbolTable: + if key == last_part: + info = self.Trans.SymbolTable[key] + if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name: + enum_member_found = info + break + if enum_member_found: + enum_type_name = enum_class_name + if enum_type_name: + type_str = f"" + else: + llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg) + if isinstance(llvm_type, ir.PointerType): + pointee = llvm_type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + llvm_type = pointee + type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type) + type_str = f"" + return Gen.emit_constant(type_str, 'string') + + def _HandleInputLlvm(self, Node): + Gen = self.Trans.LlvmGen + if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str): + prompt = Node.args[0].value + prompt_ptr = Gen.emit_constant(prompt, 'string') + printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + Gen.builder.call(printf_func, [prompt_ptr]) + scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer") + result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer]) + return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result") + + def _HandleAtoiLlvm(self, str_ptr): + Gen = self.Trans.LlvmGen + atoi_func = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))])) + return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result") + + def _HandleOrdLlvm(self, expr_node): + Gen = self.Trans.LlvmGen + val = self.HandleExprLlvm(expr_node) + if val and isinstance(val.type, ir.PointerType) and isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == 8: + return Gen._load(val, name="ord_result") + return ir.Constant(ir.IntType(32), 0) + + def _HandleChrLlvm(self, expr_node): + Gen = self.Trans.LlvmGen + val = self.HandleExprLlvm(expr_node) + if val: + char_ptr = Gen._alloca(ir.IntType(8), name="chr_char") + Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr) + return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result") + return ir.Constant(ir.IntType(8).as_pointer(), None) + + def _EmitStringFromValue(self, val): + Gen = self.Trans.LlvmGen + if isinstance(val.type, ir.IntType): + if val.type.width == 8: + buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 2)) + null_ptr = Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 1)], name="null_byte") + Gen.builder.store(ir.Constant(ir.IntType(8), 0), null_ptr) + Gen.builder.store(val, buf) + return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") + buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32)) + snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [ + ir.PointerType(ir.IntType(8)), + ir.IntType(64), + ir.PointerType(ir.IntType(8)) + ], var_arg=True)) + fmt_ptr = Gen.emit_constant("%d", 'string') + Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(64), 32), fmt_ptr, val]) + return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") + return ir.Constant(ir.IntType(8).as_pointer(), None) + + def _HandleMallocLlvm(self, args): + Gen = self.Trans.LlvmGen + malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) + malloc_func = Gen._get_or_declare_func('malloc', malloc_type) + param_type = malloc_func.type.pointee.args[0] + size_val = None + if args: + size_val = self.HandleExprLlvm(args[0]) + if size_val and isinstance(size_val.type, ir.IntType): + if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width: + if size_val.type.width < param_type.width: + size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size") + else: + size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size") + if not size_val: + size_val = ir.Constant(param_type, 1) + result = Gen.builder.call(malloc_func, [size_val], name="malloc_result") + return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast") + + def _HandleReallocLlvm(self, args): + Gen = self.Trans.LlvmGen + realloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)]) + realloc_func = Gen._get_or_declare_func('realloc', realloc_type) + size_param_type = realloc_func.type.pointee.args[1] + ptr_val = None + size_val = None + if len(args) >= 2: + ptr_val = self.HandleExprLlvm(args[0]) + size_val = self.HandleExprLlvm(args[1]) + elif len(args) == 1: + size_val = self.HandleExprLlvm(args[0]) + if not ptr_val: + ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None) + if isinstance(ptr_val.type, ir.PointerType) and not (isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8): + ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr") + if size_val and isinstance(size_val.type, ir.IntType): + if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width: + if size_val.type.width < size_param_type.width: + size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size") + else: + size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size") + if not size_val: + size_val = ir.Constant(size_param_type, 0) + result = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result") + return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast") + + def _HandleFreeLlvm(self, args): + Gen = self.Trans.LlvmGen + free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) + free_func = Gen._get_or_declare_func('free', free_type) + if args: + var_name = None + if isinstance(args[0], ast.Name): + var_name = args[0].id + ptr_val = self.HandleExprLlvm(args[0]) + if ptr_val is not None: + if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr: + registered_val = Gen._var_to_heap_ptr[var_name] + Gen._unregister_local_heap_ptr(registered_val) + del Gen._var_to_heap_ptr[var_name] + if isinstance(ptr_val.type, ir.PointerType): + if isinstance(ptr_val.type.pointee, ir.IntType) and ptr_val.type.pointee.width == 8: + pass + else: + ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr") + elif isinstance(ptr_val.type, ir.IntType): + ptr_val = Gen.builder.inttoptr(ptr_val, ir.PointerType(ir.IntType(8)), name="free_inttoptr") + Gen.builder.call(free_func, [ptr_val], name="free_call") + return ir.Constant(ir.IntType(32), 0) + + def _HandleMemcpyLlvm(self, args): + Gen = self.Trans.LlvmGen + if 'llvm.memcpy' not in Gen.functions: + memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) + Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy') + if len(args) >= 3: + dst = self.HandleExprLlvm(args[0]) + src = self.HandleExprLlvm(args[1]) + size = self.HandleExprLlvm(args[2]) + if dst and src and size: + i8ptr = ir.PointerType(ir.IntType(8)) + if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr: + dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast") + elif isinstance(dst.type, ir.IntType): + if dst.type.width < 64: + dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr") + dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr") + if isinstance(src.type, ir.PointerType) and src.type != i8ptr: + src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast") + elif isinstance(src.type, ir.IntType): + if src.type.width < 64: + src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr") + src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr") + if isinstance(size.type, ir.IntType) and size.type.width < 64: + size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size") + isvolatile = ir.Constant(ir.IntType(1), 0) + Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call") + return ir.Constant(ir.IntType(32), 0) + + def _HandleMemsetLlvm(self, args): + Gen = self.Trans.LlvmGen + memset_func = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)])) + if len(args) >= 3: + dst = self.HandleExprLlvm(args[0]) + val = self.HandleExprLlvm(args[1]) + size = self.HandleExprLlvm(args[2]) + if dst and val is not None and size: + if isinstance(dst.type, ir.PointerType) and not (isinstance(dst.type.pointee, ir.IntType) and dst.type.pointee.width == 8): + dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast") + elif isinstance(dst.type, ir.IntType): + if dst.type.width < 64: + dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_memset_dst") + elif dst.type.width > 64: + dst = Gen.builder.trunc(dst, ir.IntType(64), name="trunc_memset_dst") + dst = Gen.builder.inttoptr(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_int2ptr") + if isinstance(val.type, ir.IntType) and val.type.width != 32: + if val.type.width < 32: + val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val") + else: + val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val") + if isinstance(size.type, ir.IntType) and size.type.width < 64: + size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size") + elif isinstance(size.type, ir.IntType) and size.type.width > 64: + size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size") + Gen.builder.call(memset_func, [dst, val, size], name="memset_call") + return ir.Constant(ir.IntType(32), 0) + + def _HandleVaStartLlvm(self, args): + Gen = self.Trans.LlvmGen + return ir.Constant(ir.IntType(32), 0) + + def _HandleVaEndLlvm(self, args): + Gen = self.Trans.LlvmGen + return ir.Constant(ir.IntType(32), 0) + + def _HandleArgLlvm(self, args, CallNode=None): + Gen = self.Trans.LlvmGen + va_list_ptr = None + variadic_info = getattr(Gen, '_va_arg_info', None) + if not variadic_info: + variadic_info = getattr(Gen, '_variadic_info', None) + if variadic_info: + va_list_ptr = variadic_info.get('va_list_ptr') + if not va_list_ptr: + vararg_name = variadic_info.get('vararg_name', 'args') if variadic_info else 'args' + if vararg_name in Gen.variables: + va_list_ptr = Gen.variables[vararg_name] + if not va_list_ptr: + return ir.Constant(ir.IntType(32), 0) + target_type = ir.IntType(32) + if args: + type_arg = args[0] + if isinstance(type_arg, ast.Name): + type_name = type_arg.id + from lib.includes.t import CTypeRegistry + if type_name in ('str', 'bytes'): + target_type = ir.PointerType(ir.IntType(8)) + elif type_name == 'CPtr': + target_type = ir.PointerType(ir.IntType(8)) + elif type_name in Gen.structs: + target_type = ir.PointerType(Gen.structs[type_name]) + else: + ctype_cls = CTypeRegistry.GetClassByName(type_name) + if ctype_cls is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + resolved = Gen._type_str_to_llvm(llvm_str) + if resolved: + target_type = resolved + else: + resolved = CTypeRegistry.ResolveName(type_name) + if resolved is not None: + ctype_cls, ptr_level = resolved + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str: + base = Gen._type_str_to_llvm(llvm_str) + if base is not None: + for _ in range(ptr_level): + if isinstance(base, ir.VoidType): + base = ir.IntType(8).as_pointer() + else: + base = ir.PointerType(base) + target_type = base + elif isinstance(type_arg, ast.Attribute): + if isinstance(type_arg.value, ast.Name) and type_arg.value.id == 't': + attr_name = type_arg.attr + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(attr_name) + if ctype_cls is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + resolved = Gen._type_str_to_llvm(llvm_str) + if resolved: + target_type = resolved + else: + assign_node = getattr(self.Trans, '_current_assign_node', None) + if assign_node: + ann = getattr(assign_node, 'annotation', None) + if ann: + ann_name = None + if isinstance(ann, ast.Name): + ann_name = ann.id + elif isinstance(ann, ast.Attribute): + ann_name = ann.attr + elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): + left = ann.left + if isinstance(left, ast.Name): + ann_name = left.id + elif isinstance(left, ast.Attribute): + ann_name = left.attr + if ann_name: + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(ann_name) + if ctype_cls is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + resolved = Gen._type_str_to_llvm(llvm_str) + if resolved: + target_type = resolved + elif ann_name in Gen.structs: + target_type = ir.PointerType(Gen.structs[ann_name]) + if not getattr(Gen, '_va_arg_counter', None): + Gen._va_arg_counter = 0 + Gen._va_arg_counter += 1 + result = Gen.emit_va_arg(va_list_ptr, target_type) + if result is not None and getattr(result, 'name', None): + result.name = f"va_arg_result_{Gen._va_arg_counter}" + return result + + def _HandleVaArgLlvm(self, args): + Gen = self.Trans.LlvmGen + return ir.Constant(ir.IntType(32), 0) diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py new file mode 100644 index 0000000..5082730 --- /dev/null +++ b/lib/core/Handles/HandlesExprCall.py @@ -0,0 +1,3350 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta +from lib.core.Handles.HandlesAssign import AssignHandle +from lib.includes import t +import ast +import llvmlite.ir as ir + + +class ExprCallHandle(BaseHandle): + def _append_eh_msg_out_arg(self, CallArgs, func, Gen): + if not func: + return + func_args = func.function_type.args + n_user_args = len(CallArgs) + has_eh_msg = False + has_eh_code = False + if len(func_args) > n_user_args: + last_type = func_args[-1] + if (isinstance(last_type, ir.PointerType) + and isinstance(last_type.pointee, ir.IntType) + and last_type.pointee.width == 32): + has_eh_code = True + if len(func_args) > n_user_args + (1 if has_eh_code else 0): + check_idx = len(func_args) - 1 - (1 if has_eh_code else 0) + check_type = func_args[check_idx] + if (isinstance(check_type, ir.PointerType) + and isinstance(check_type.pointee, ir.PointerType) + and isinstance(check_type.pointee.pointee, ir.IntType) + and check_type.pointee.pointee.width == 8): + has_eh_msg = True + if not has_eh_msg: + return + eh_msg_ptr = None + eh_code_ptr = None + if Gen.eh_except_block_stack: + _, _, exception_code, eh_message = Gen.eh_except_block_stack[-1] + if eh_message is not None: + eh_msg_ptr = eh_message + if exception_code is not None: + eh_code_ptr = exception_code + if eh_msg_ptr is None and Gen.func and len(Gen.func.args) > 0: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__' and eh_msg_ptr is None: + eh_msg_ptr = arg + elif arg.name == '__eh_code_out__' and eh_code_ptr is None: + eh_code_ptr = arg + if eh_msg_ptr is None: + eh_msg_ptr = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") + if eh_code_ptr is None: + eh_code_ptr = Gen._alloca_entry(ir.IntType(32), name="eh_code_out_null") + Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_msg_ptr) + Gen._store(ir.Constant(ir.IntType(32), 0), eh_code_ptr) + CallArgs.append(eh_msg_ptr) + if has_eh_code: + CallArgs.append(eh_code_ptr) + + def _check_eh_return(self, result, func_name, Gen, called_func=None): + has_eh_msg_out = False + has_eh_code_out = False + if called_func and hasattr(called_func, 'args') and len(called_func.args) > 0: + for arg in called_func.args: + if arg.name == '__eh_msg_out__': + has_eh_msg_out = True + elif arg.name == '__eh_code_out__': + has_eh_code_out = True + if not has_eh_msg_out: + return + eh_msg_ptr = None + eh_code_ptr = None + if Gen.eh_except_block_stack: + _, _, exception_code, eh_message = Gen.eh_except_block_stack[-1] + if eh_message is not None: + eh_msg_ptr = eh_message + if exception_code is not None: + eh_code_ptr = exception_code + if eh_msg_ptr is None and Gen.func and len(Gen.func.args) > 0: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__' and eh_msg_ptr is None: + eh_msg_ptr = arg + elif arg.name == '__eh_code_out__' and eh_code_ptr is None: + eh_code_ptr = arg + if eh_msg_ptr is not None: + eh_msg_val = Gen._load(eh_msg_ptr, name=f"load_eh_msg_{func_name}") + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + is_error = Gen.builder.icmp_signed('!=', eh_msg_val, null_ptr, name=f"check_eh_msg_{func_name}") + OkBB = Gen.func.append_basic_block(name=f"ok_after_{func_name}") + ErrorBB = Gen.func.append_basic_block(name=f"error_after_{func_name}") + Gen.builder.cbranch(is_error, ErrorBB, OkBB) + Gen.builder.position_at_start(ErrorBB) + ret_type = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None + error_ret_val = None + if isinstance(ret_type, ir.IdentifiedStructType): + if ret_type.elements: + error_ret_val = ir.Constant(ret_type, [ + ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) + else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) + else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + error_ret_val = ir.Constant(ret_type, None) + elif isinstance(ret_type, ir.PointerType): + error_ret_val = ir.Constant(ret_type, None) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + error_ret_val = ir.Constant(ret_type, 0.0) + elif isinstance(ret_type, ir.IntType): + error_ret_val = ir.Constant(ret_type, 1) + elif isinstance(ret_type, ir.VoidType): + pass + else: + error_ret_val = ir.Constant(ir.IntType(32), 1) + if Gen.eh_except_block_stack: + ExceptBB, _, exception_code, _ = Gen.eh_except_block_stack[-1] + if ExceptBB is not None: + if has_eh_code_out and eh_code_ptr is not None: + eh_code_val = Gen._load(eh_code_ptr, name=f"load_eh_code_{func_name}") + Gen._store(eh_code_val, exception_code) + else: + Gen._store(ir.Constant(ir.IntType(32), 1), exception_code) + Gen.builder.branch(ExceptBB) + else: + if isinstance(ret_type, ir.VoidType): + Gen.builder.ret_void() + else: + Gen.builder.ret(error_ret_val) + else: + if isinstance(ret_type, ir.VoidType): + Gen.builder.ret_void() + else: + Gen.builder.ret(error_ret_val) + Gen.builder.position_at_start(OkBB) + + def _fill_default_args(self, CallArgs, func, func_name=None): + + global_defaults = getattr(self.Trans, '_global_function_default_args', {}) + func_defaults = None + if func_name: + func_defaults = global_defaults.get(func_name) + if not func_defaults and func: + func_defaults = global_defaults.get(func.name) + if not func_defaults and func_name: + for gk, gv in global_defaults.items(): + if func_name in gk or gk.endswith(func_name) or gk.endswith('.' + func_name): + func_defaults = gv + break + if func and len(CallArgs) < len(func.args): + total_params = len(func.args) + if func_defaults: + num_defaults = len(func_defaults) + default_start = total_params - num_defaults + else: + num_defaults = 0 + default_start = total_params + while len(CallArgs) < total_params: + arg_idx = len(CallArgs) + arg = func.args[arg_idx] + param_type = arg.type if hasattr(arg, 'type') else arg + if func_defaults and arg_idx >= default_start: + def_idx = arg_idx - default_start + if def_idx < num_defaults and func_defaults[def_idx] is not None: + default_val = func_defaults[def_idx] + if isinstance(param_type, ir.IntType): + max_val = (1 << param_type.width) - 1 + if isinstance(default_val, bool): + default_val = 1 if default_val else 0 + if isinstance(default_val, int) and default_val > max_val: + default_val = default_val & max_val + if isinstance(default_val, int) and default_val < 0: + default_val = default_val & max_val + CallArgs.append(ir.Constant(param_type, default_val)) + elif isinstance(param_type, ir.PointerType): + CallArgs.append(ir.Constant(param_type, None)) + else: + try: + CallArgs.append(AssignHandle._zero_value(param_type)) + except (AssertionError, TypeError): + CallArgs.append(ir.Constant(ir.IntType(32), 0)) + else: + if isinstance(param_type, ir.PointerType): + CallArgs.append(ir.Constant(param_type, None)) + elif isinstance(param_type, ir.IntType): + CallArgs.append(ir.Constant(param_type, 0)) + else: + try: + CallArgs.append(AssignHandle._zero_value(param_type)) + except (AssertionError, TypeError): + CallArgs.append(ir.Constant(ir.IntType(32), 0)) + else: + if isinstance(param_type, ir.PointerType): + CallArgs.append(ir.Constant(param_type, None)) + elif isinstance(param_type, ir.IntType): + CallArgs.append(ir.Constant(param_type, 0)) + else: + try: + CallArgs.append(AssignHandle._zero_value(param_type)) + except (AssertionError, TypeError): + CallArgs.append(ir.Constant(ir.IntType(32), 0)) + + def _HandleCallLlvm(self, Node): + Gen = self.Trans.LlvmGen + func_attr = None + module_path = None + if isinstance(Node.func, ast.Name): + FuncName = Node.func.id + if hasattr(self.Trans.FunctionHandler, '_generic_templates') and FuncName in self.Trans.FunctionHandler._generic_templates: + return self._HandleGenericCallLlvm(Node, FuncName) + result = self.Trans.ExprBuiltinHandle._HandleBuiltinCallLlvm(Node) + if result is not None: + return result + if FuncName == 'print': + return self._HandlePrintLlvm(Node) + elif FuncName == 'len': + if Node.args: + return self._HandleLenLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'sizeof': + if Node.args: + return self._HandleSizeofLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'abs': + if Node.args: + return self._HandleAbsLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'arg': + return self._HandleArgLlvm(Node.args, CallNode=Node) + elif FuncName == 'bool': + if Node.args: + Val = self.HandleExprLlvm(Node.args[0]) + if Val: + if isinstance(Val.type, ir.IntType): + if Val.type.width == 1: + return Val + return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result") + elif isinstance(Val.type, ir.PointerType): + return Gen.builder.icmp_signed('!=', Val, Gen._zero_const(Val.type), name="bool_result") + return Val + return ir.Constant(ir.IntType(1), 0) + elif FuncName == 'int': + if Node.args: + Val = self.HandleExprLlvm(Node.args[0]) + if Val: + if isinstance(Val.type, ir.IntType): + if Val.type.width < 32: + return Gen.builder.zext(Val, ir.IntType(32), name="cast_int") + elif Val.type.width > 32: + return Gen.builder.trunc(Val, ir.IntType(32), name="trunc_int") + return Val + elif isinstance(Val.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fptosi(Val, ir.IntType(32), name="fptosi_int") + elif isinstance(Val.type, ir.PointerType): + if self._is_char_pointer(Val): + result = self._HandleAtoiLlvm(Val) + if result: + return result + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'float' or FuncName == 'double': + if Node.args: + Val = self.HandleExprLlvm(Node.args[0]) + if Val: + target_type = ir.DoubleType() + if isinstance(Val.type, (ir.FloatType, ir.DoubleType)): + if Val.type != target_type: + return Gen.builder.fpext(Val, target_type, name="fpext_double") + return Val + elif isinstance(Val.type, ir.IntType): + if Val.type.width == 1: + return Gen.builder.uitofp(Val, target_type, name="uitofp_double") + return Gen.builder.sitofp(Val, target_type, name="sitofp_double") + return ir.Constant(ir.DoubleType(), 0.0) + elif FuncName == 'str': + if Node.args: + arg_node = Node.args[0] + arg_val = self.HandleExprLlvm(arg_node) + if arg_val: + if isinstance(arg_val.type, ir.PointerType): + ClassName = self.Trans.ExprHandler._get_var_class(arg_node, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__str__'): + if self._is_char_pointer(arg_val): + if ClassName in Gen.structs: + arg_val = Gen.builder.bitcast(arg_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_str") + str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__") + return str_val + return arg_val + return self._EmitStringFromValue(arg_val) + return ir.Constant(ir.IntType(8).as_pointer(), None) + elif FuncName == 'input': + return self._HandleInputLlvm(Node) + elif FuncName == 'ord': + if Node.args: + return self._HandleOrdLlvm(Node.args[0]) + return ir.Constant(ir.IntType(32), 0) + elif FuncName == 'chr': + if Node.args: + return self._HandleChrLlvm(Node.args[0]) + return ir.Constant(ir.IntType(8), 0) + elif FuncName == 'malloc': + return self._HandleMallocLlvm(Node.args) + elif FuncName == 'realloc': + return self._HandleReallocLlvm(Node.args) + elif FuncName == 'free': + return self._HandleFreeLlvm(Node.args) + elif FuncName == 'memcpy': + return self._HandleMemcpyLlvm(Node.args) + elif FuncName == 'memset': + return self._HandleMemsetLlvm(Node.args) + elif FuncName == 'va_start': + return self._HandleVaStartLlvm(Node.args) + elif FuncName == 'va_end': + return self._HandleVaEndLlvm(Node.args) + elif FuncName == 'va_arg': + return self._HandleVaArgLlvm(Node.args) + elif FuncName == 'dir': + return self._HandleDirLlvm(Node) + elif FuncName == 'type': + return self._HandleTypeLlvm(Node) + if Gen._has_function(FuncName): + return self._HandleClosureCallLlvm(Node, FuncName) + if FuncName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[FuncName] + if SymInfo.IsEnum: + if Node.args: + arg_val = self.HandleExprLlvm(Node.args[0]) + if arg_val: + if isinstance(arg_val.type, ir.IntType) and arg_val.type.width != 32: + if arg_val.type.width < 32: + arg_val = Gen.builder.zext(arg_val, ir.IntType(32), name="zext_enum_arg") + else: + arg_val = Gen.builder.trunc(arg_val, ir.IntType(32), name="trunc_enum_arg") + return arg_val + return ir.Constant(ir.IntType(32), 0) + if SymInfo.IsTypedef: + return self._HandleTypedefCastLlvm(Node, FuncName) + NewFuncName = f'{FuncName}.__before_init__' + InitFuncName = f'{FuncName}.__init__' + if Gen._has_function(NewFuncName): + return self._HandleClassNewLlvm(Node, FuncName) + if Gen._has_function(InitFuncName) and FuncName in Gen.structs: + return self._HandleClassNewLlvm(Node, FuncName) + if FuncName in Gen.structs: + return self._HandleClassNewLlvm(Node, FuncName) + if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and FuncName in self.Trans.ClassHandler._generic_class_templates: + return self._HandleClassNewLlvm(Node, FuncName) + if self.Trans.FunctionDefCache.get(FuncName): + return self._HandleClosureCallLlvm(Node, FuncName) + if FuncName in self._C_LIB_FUNCS: + return self._HandleClosureCallLlvm(Node, FuncName) + ClassName = Gen.var_struct_class.get(FuncName) + if ClassName and Gen._has_function(f'{ClassName}.__call__'): + return self._HandleInstanceCallLlvm(Node, FuncName, ClassName) + t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) + if FuncName in t_c_imported: + src_module, src_name = t_c_imported[FuncName] + virtual_node = self._make_virtual_attr_call(Node, src_module, src_name) + return self._HandleCallLlvm(virtual_node) + # 检查是否是闭包变量(lambda 赋值给变量后调用) + if FuncName in Gen.variables and Gen.variables[FuncName] is not None: + closure_ptr = Gen._load(Gen.variables[FuncName], name=f"load_closure_{FuncName}") + if isinstance(closure_ptr.type, ir.PointerType) and isinstance(closure_ptr.type.pointee, ir.LiteralStructType): + st = closure_ptr.type.pointee + if len(st.elements) == 2 and isinstance(st.elements[1], ir.PointerType) and isinstance(st.elements[1].pointee, ir.FunctionType): + fn_ptr_type = st.elements[1] + fn_ptr = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name=f"fn_ptr_{FuncName}") + fn_val = Gen._load(fn_ptr, name=f"fn_{FuncName}") + args = [] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + args.append(ArgVal) + env_ptr = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"env_ptr_{FuncName}") + env_val = Gen._load(env_ptr, name=f"env_{FuncName}") + call_args = [env_val] + args + expected_fn_type = fn_ptr_type.pointee + if len(call_args) < len(expected_fn_type.args): + while len(call_args) < len(expected_fn_type.args): + call_args.append(ir.Constant(expected_fn_type.args[len(call_args)], 0)) + # 如果函数期望的 env 类型与闭包中存储的 i8* 不同,做 bitcast + if len(expected_fn_type.args) > 0 and call_args[0].type != expected_fn_type.args[0]: + call_args[0] = Gen.builder.bitcast(call_args[0], expected_fn_type.args[0], name=f"cast_env_{FuncName}") + return Gen.builder.call(fn_val, call_args, name=f"call_{FuncName}") + raise Exception(f"Undefined function: '{FuncName}'") + if isinstance(Node.func, ast.Attribute): + if Node.func.attr in ('update', 'final', 'transform'): + pass + if Node.func.attr == '__sizeof__': + ObjVal = self.HandleExprLlvm(Node.func.value) + if ObjVal and isinstance(ObjVal.type, ir.PointerType): + pointee = ObjVal.type.pointee + if isinstance(pointee, ir.ArrayType): + # Calculate element size in bytes + elem = pointee.element + if isinstance(elem, ir.IntType): + elem_size = elem.width // 8 + elif isinstance(elem, ir.PointerType): + elem_size = 8 # 64-bit pointers + elif isinstance(elem, (ir.LiteralStructType, ir.IdentifiedStructType)): + # Approximate: sum of field sizes + elem_size = 0 + for field in getattr(elem, 'elements', []): + if isinstance(field, ir.IntType): + elem_size += field.width // 8 + elif isinstance(field, ir.PointerType): + elem_size += 8 + elif isinstance(field, ir.ArrayType): + if isinstance(field.element, ir.IntType): + elem_size += field.count * (field.element.width // 8) + else: + elem_size += field.count * 8 + else: + elem_size += 8 + elif isinstance(elem, ir.ArrayType): + if isinstance(elem.element, ir.IntType): + elem_size = elem.count * (elem.element.width // 8) + else: + elem_size = elem.count * 8 + elif isinstance(elem, ir.FloatType): + elem_size = 4 + elif isinstance(elem, ir.DoubleType): + elem_size = 8 + else: + elem_size = 8 # fallback + return ir.Constant(ir.IntType(64), pointee.count * elem_size) + if isinstance(Node.func.value, ast.Name): + type_name = Node.func.value.id + SizeofNode = ast.Name(id=type_name, ctx=ast.Load()) + return self._HandleSizeofLlvm(SizeofNode) + elif isinstance(Node.func.value, ast.Attribute): + type_name = Node.func.value.attr + SizeofNode = ast.Name(id=type_name, ctx=ast.Load()) + return self._HandleSizeofLlvm(SizeofNode) + module_path = self._get_module_path(Node.func.value) + if module_path: + aliases = getattr(self.Trans, '_import_aliases', {}) + first_part = module_path.split('.')[0] + if first_part in aliases: + module_path = aliases[first_part] + module_path[len(first_part):] + is_instance_var = isinstance(Node.func.value, ast.Name) and Node.func.value.id in Gen.var_struct_class and Node.func.value.id not in Gen.module_sha1_map + is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or (Node.func.value.id in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[Node.func.value.id], 'IsStruct', False))) + if is_instance_var and not is_class_name: + return self._HandleMethodCallLlvm(Node) + func_attr = Node.func.attr + if func_attr in Gen.structs: + result = self._HandleClassNewLlvm(Node, func_attr) + if result is not None: + return result + if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and func_attr in self.Trans.ClassHandler._generic_class_templates: + return self._HandleGenericClassNewLlvm(Node, func_attr) + if func_attr in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[func_attr] + if SymInfo.IsStruct: + if func_attr not in Gen.structs: + self._ensure_struct_declared(func_attr) + if func_attr in Gen.structs: + result = self._HandleClassNewLlvm(Node, func_attr) + if result is not None: + return result + if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None): + EnumName = SymInfo.EnumName + if EnumName in self.Trans.SymbolTable: + EnumInfo = self.Trans.SymbolTable[EnumName] + if getattr(EnumInfo, 'IsRenum', False): + result = self._HandleREnumConstructLlvm(Node, EnumName, func_attr, SymInfo.value) + if result is not None: + return result + FullAttrKey = f"{module_path}.{func_attr}" + if FullAttrKey in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[FullAttrKey] + if SymInfo.IsStruct: + if func_attr not in Gen.structs: + self._ensure_struct_declared(func_attr) + if func_attr in Gen.structs: + result = self._HandleClassNewLlvm(Node, func_attr) + if result is not None: + return result + if is_class_name: + ClassName = Node.func.value.id + result = self._HandleStaticMethodCallLlvm(Node, ClassName, func_attr) + if result is not None: + return result + FullAttrKey = f"{module_path}.{func_attr}" + if FullAttrKey in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[FullAttrKey] + if getattr(SymInfo, 'IsTypedef', False): + return ir.Constant(ir.IntType(32), 0) + if getattr(SymInfo, 'IsStruct', False): + if func_attr not in Gen.structs: + self._ensure_struct_declared(func_attr) + if func_attr in Gen.structs: + result = self._HandleClassNewLlvm(Node, func_attr) + if result is not None: + return result + if func_attr in Gen.structs: + result = self._HandleClassNewLlvm(Node, func_attr) + if result is not None: + return result + if module_path == 'c': + if func_attr == 'Asm': + return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node) + elif func_attr == 'Addr': + return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node) + elif func_attr == 'Set': + return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node) + elif func_attr == 'Load': + return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node) + elif func_attr == 'Deref': + return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node) + elif func_attr == 'DerefAs': + return self._HandleCDerefAsLlvm(Node) + elif func_attr == 'PtrToInt': + return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node) + elif func_attr in ('CIf', 'CElif'): + return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node) + elif func_attr == 'CError': + msg = "compile-time error" + if Node.args: + arg = Node.args[0] + if isinstance(arg, ast.Constant) and isinstance(arg.value, str): + msg = arg.value + elif isinstance(arg, ast.Str): + msg = arg.s + lineno = getattr(Node, 'lineno', 0) + raise Exception(f"#error: {msg} (line {lineno})") + elif func_attr in ('AsmInp', 'AsmOut'): + return ir.Constant(ir.IntType(32), 0) + elif func_attr == 'LLVMIR': + return self._HandleLLVMIRLlvm(Node) + elif func_attr in ('LInp', 'LOut'): + return ir.Constant(ir.IntType(32), 0) + if module_path == 't': + method_result_t = self._HandleMethodCallLlvm(Node) + if method_result_t is not None: + return method_result_t + raise Exception(f"Undefined method: 't.{func_attr}'") + if isinstance(Node.func.value, ast.Attribute): + inner_attr = Node.func.value.attr + if inner_attr in Gen.structs or (inner_attr in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[inner_attr], 'IsStruct', False)): + static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, func_attr) + if static_result is not None: + return static_result + method_result_attr = self._HandleMethodCallLlvm(Node) + is_zero_attr = isinstance(method_result_attr, ir.Constant) and isinstance(method_result_attr.type, ir.IntType) and method_result_attr.constant == 0 + if method_result_attr is not None and not is_zero_attr: + return method_result_attr + result = self._HandleExternalCallLlvm(Node, func_attr, module_path) + if result is not None: + return result + method_result = self._HandleMethodCallLlvm(Node) + is_zero_result = isinstance(method_result, ir.Constant) and isinstance(method_result.type, ir.IntType) and method_result.constant == 0 + if is_zero_result and func_attr is not None: + mangled_name = Gen._mangle_func_name(func_attr, module_path if module_path and module_path != 't' else None) + if Gen._has_function(mangled_name): + CallArgs = [] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + return Gen.builder.call(Gen._get_function(mangled_name), CallArgs, name=f"call_{func_attr}") + if method_result is None or is_zero_result: + imported = getattr(self.Trans, '_imported_modules', set()) + aliases = getattr(self.Trans, '_import_aliases', {}) + is_known = module_path in imported or module_path in aliases + if module_path and is_known: + raise Exception(f"Undefined symbol: '{module_path}.{func_attr}'") + if module_path and module_path not in {'t', 'c'} and not is_known: + raise Exception(f"Unknown module: '{module_path}' (undefined symbol: '{module_path}.{func_attr}')") + if not module_path and func_attr: + raise Exception(f"Undefined method: '{func_attr}'") + return method_result if method_result is not None else ir.Constant(ir.IntType(32), 0) + if isinstance(Node.func, ast.BinOp) and isinstance(Node.func.op, ast.BitOr): + return self._HandleTypeUnionCastLlvm(Node) + raise Exception(f"Unsupported call expression") + + def _ensure_struct_declared(self, class_name): + Gen = self.Trans.LlvmGen + if class_name in Gen.structs: + existing = Gen.structs[class_name] + if isinstance(existing, ir.IdentifiedStructType) and (existing.elements is None or len(existing.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen) + existing = Gen.structs.get(class_name, existing) + if isinstance(existing, ir.IdentifiedStructType) and existing.elements is not None and len(existing.elements) > 0: + return + else: + return + SymInfo = self.Trans.SymbolTable.get(class_name) + if SymInfo and SymInfo.Members: + member_types = [] + if isinstance(SymInfo.Members, dict): + for member_name, member_info in SymInfo.Members.items(): + if isinstance(member_info, CTypeInfo): + mt = member_info.ToLLVM(Gen) + elif isinstance(member_info, str): + mt = Gen._CType2LLVM(member_info, '*' in member_info) + else: + mt = Gen._CType2LLVM(str(member_info) if member_info else 'int', False) + if isinstance(mt, ir.VoidType): + mt = ir.IntType(8) + member_types.append(mt) + else: + for item in SymInfo.Members: + if isinstance(item, (list, tuple)) and len(item) == 2: + member_name, member_type_str = item + mt = Gen._CType2LLVM(member_type_str, '*' in member_type_str) + if isinstance(mt, ir.VoidType): + mt = ir.IntType(8) + member_types.append(mt) + if member_types: + st = Gen._get_or_create_struct(class_name) + if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): + st.set_body(*member_types) + else: + Gen._get_or_create_struct(class_name) + else: + if class_name not in Gen.structs: + self.Trans.ImportHandler._TryLoadStructFromStub(class_name, Gen) + Gen._get_or_create_struct(class_name) + + def _HandleStaticMethodCallLlvm(self, Node, ClassName, MethodName): + Gen = self.Trans.LlvmGen + struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) + class_sha1 = struct_sha1_map.get(ClassName) + if class_sha1: + MangledName = f'{class_sha1}.{ClassName}.{MethodName}' + else: + MangledName = f'{ClassName}.{MethodName}' + func = Gen._find_function(MangledName) + if not func: + func = Gen._find_function(f'{MangledName}__') + if not func: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MangledName, Gen) + if stub_func_type: + func = ir.Function(Gen.module, stub_func_type, name=MangledName) + Gen.functions[MangledName] = func + if not func and class_sha1: + plain_name = f'{ClassName}.{MethodName}' + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen) + if stub_func_type: + func = ir.Function(Gen.module, stub_func_type, name=MangledName) + Gen.functions[MangledName] = func + if not func: + if ClassName not in Gen.structs: + self._ensure_struct_declared(ClassName) + SymKey = f'{ClassName}.{MethodName}' + SymInfo = self.Trans.SymbolTable.get(SymKey) or self.Trans.SymbolTable.get(MethodName) + if SymInfo and SymInfo.IsFunction: + ret_type_info = getattr(SymInfo, 'FuncPtrReturn', None) + if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: + ret_type = ret_type_info.ToLLVM(Gen) + else: + ret_type = Gen._CType2LLVM('i32', False) + param_type_infos = [pt for _, pt in (getattr(SymInfo, 'FuncPtrParams', None) or [])] + if isinstance(ret_type, ir.VoidType): + ret_type = ir.IntType(32) + llvm_param_types = [] + is_static = hasattr(SymInfo, 'MetaList') and FuncMeta.STATIC_METHOD in SymInfo.MetaList + if ClassName in Gen.structs and not is_static: + llvm_param_types.append(ir.PointerType(Gen.structs[ClassName])) + for pt in param_type_infos: + if isinstance(pt, CTypeInfo) and pt.BaseType: + lp = pt.ToLLVM(Gen) + else: + lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False) + if isinstance(lp, ir.VoidType): + lp = ir.IntType(8).as_pointer() + llvm_param_types.append(lp) + func_type = ir.FunctionType(ret_type, llvm_param_types) + func = ir.Function(Gen.module, func_type, name=MangledName) + Gen.functions[MangledName] = func + if not func: + p = Gen.class_parent.get(ClassName) + while p: + parent_mangled = Gen._mangle_name(f'{p}.{MethodName}') + parent_func = Gen.functions.get(parent_mangled) + if parent_func: + func = parent_func + break + parent_func = Gen._find_function(f'{p}.{MethodName}') + if parent_func: + func = parent_func + break + p = Gen.class_parent.get(p) + if not func: + return None + CallArgs = [] + SymKey = f'{ClassName}.{MethodName}' + SymInfo = self.Trans.SymbolTable.get(SymKey) or self.Trans.SymbolTable.get(MethodName) + is_static_call = SymInfo is not None and hasattr(SymInfo, 'MetaList') and FuncMeta.STATIC_METHOD in SymInfo.MetaList + is_classmethod_call = SymInfo is not None and hasattr(SymInfo, 'MetaList') and FuncMeta.CLASS_METHOD in SymInfo.MetaList + # @classmethod: 在参数列表前插入 cls(栈上分配的类实例指针) + if is_classmethod_call and ClassName in Gen.structs: + ClsPtr = Gen._alloca(Gen.structs[ClassName], name=f"cls_{ClassName}") + CallArgs.append(ClsPtr) + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + if ClassName in Gen.class_vtable and ClassName in Gen.class_methods and CallArgs and not is_static_call: + methods = Gen.class_methods[ClassName] + if class_sha1: + FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}' + else: + FullMethodName = f'{ClassName}.{MethodName}' + method_idx = -1 + for mi, mn in enumerate(methods): + if mn == FullMethodName or mn == MethodName or mn.endswith(f'.{MethodName}'): + method_idx = mi + break + if method_idx >= 0: + ObjVal = CallArgs[0] + if self._is_char_pointer(ObjVal): + if ClassName in Gen.structs: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}_static") + CallArgs[0] = ObjVal + VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}_static") + VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_static") + VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}_static") + MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_ptr_addr_{MethodName}_static") + MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}_static") + FuncPtrType = ir.PointerType(func.function_type) + MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}_static") + self._fill_default_args(CallArgs, func, FullMethodName) + self._append_eh_msg_out_arg(CallArgs, func, Gen) + adjusted = Gen._adjust_args(CallArgs, func) + result = Gen.builder.call(MethodPtrTyped, adjusted, name=f"vcall_{FullMethodName}") + self._check_eh_return(result, FullMethodName, Gen, called_func=func) + return result + self._append_eh_msg_out_arg(CallArgs, func, Gen) + adjusted = Gen._adjust_args(CallArgs, func) + result = Gen.builder.call(func, adjusted, name=f"call_{MangledName}") + self._check_eh_return(result, MangledName, Gen, called_func=func) + return result + + def _HandleInstanceCallLlvm(self, Node, VarName, ClassName): + Gen = self.Trans.LlvmGen + ObjVal = self.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load())) + if not ObjVal: + raise Exception(f"Cannot evaluate object '{VarName}' for __call__") + if self._is_char_pointer(ObjVal): + if ClassName in Gen.structs: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + CallArgs = [ObjVal] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + CallFuncName = f'{ClassName}.__call__' + struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) + class_sha1 = struct_sha1_map.get(ClassName) + if class_sha1: + CallFuncName = f'{class_sha1}.{ClassName}.__call__' + if not Gen._has_function(CallFuncName): + raise Exception(f"Class '{ClassName}' has no __call__ method") + func = Gen._get_function(CallFuncName) + self._append_eh_msg_out_arg(CallArgs, func, Gen) + adjusted = Gen._adjust_args(CallArgs, func) + result = Gen.builder.call(func, adjusted, name=f"call_{CallFuncName}") + self._check_eh_return(result, CallFuncName, Gen, called_func=func) + return result + + def _make_virtual_attr_call(self, Node, module_name, attr_name): + virtual_func = ast.Attribute( + value=ast.Name(id=module_name, ctx=ast.Load()), + attr=attr_name, + ctx=ast.Load() + ) + new_node = ast.Call( + func=virtual_func, + args=Node.args, + keywords=Node.keywords + ) + ast.copy_location(new_node, Node) + return new_node + + def _get_module_path(self, node): + parts = [] + while isinstance(node, ast.Attribute): + parts.append(node.attr) + node = node.value + if isinstance(node, ast.Name): + parts.append(node.id) + parts.reverse() + return '.'.join(parts) if parts else None + + def _HandleLLVMIRLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return ir.Constant(ir.IntType(32), 0) + + all_ops = [] + input_ops = [] + output_targets = [] + operand_seq = 0 + + ret_type = ir.IntType(32) + if len(Node.args) >= 2: + ret_type_arg = Node.args[1] + inferred = self.Trans.ExprAsmHandle._infer_expr_llvm_type(ret_type_arg) + if inferred: + ret_type = inferred + + ir_template = "" + first_arg = Node.args[0] + + if isinstance(first_arg, ast.JoinedStr): + parts = [] + for value in first_arg.values: + if isinstance(value, ast.Constant) and isinstance(value.value, str): + parts.append(value.value) + elif isinstance(value, ast.FormattedValue): + expr = value.value + if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute): + if isinstance(expr.func.value, ast.Name) and expr.func.value.id == 'c': + if expr.func.attr == 'LInp': + if expr.args: + val = self.HandleExprLlvm(expr.args[0]) + if val: + input_ops.append(val) + all_ops.append(('inp', len(input_ops) - 1)) + parts.append(f'%__OP{operand_seq}__') + operand_seq += 1 + elif expr.func.attr == 'LOut': + if expr.args: + target_ptr = self.Trans.ExprAsmHandle._get_var_ptr_for_asm(expr.args[0]) + if target_ptr: + val = target_ptr + else: + val = self.HandleExprLlvm(expr.args[0]) + if val: + output_targets.append(val) + all_ops.append(('out', len(output_targets) - 1)) + parts.append(f'%__OP{operand_seq}__') + operand_seq += 1 + else: + fallback = self.HandleExprLlvm(expr) + if fallback: + input_ops.append(fallback) + all_ops.append(('inp', len(input_ops) - 1)) + parts.append(f'%__OP{operand_seq}__') + operand_seq += 1 + else: + fallback = self.HandleExprLlvm(expr) + if fallback: + input_ops.append(fallback) + all_ops.append(('inp', len(input_ops) - 1)) + parts.append(f'%__OP{operand_seq}__') + operand_seq += 1 + ir_template = ''.join(parts) + elif isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): + ir_template = first_arg.value + + return self._EmitLLVMIRInstruction(Gen, ir_template, input_ops, output_targets, all_ops, ret_type) + + def _EmitLLVMIRInstruction(self, Gen, ir_template, input_ops, output_targets, all_ops, ret_type): + import re + template = ir_template.strip() + + def resolve_op(idx): + if idx < len(all_ops): + kind, local_idx = all_ops[idx] + if kind == 'inp' and local_idx < len(input_ops): + return input_ops[local_idx] + elif kind == 'out' and local_idx < len(output_targets): + return output_targets[local_idx] + return None + + assign_match = re.match(r'%__OP(\d+)__\s*=\s*(.+)', template) + if assign_match: + template = assign_match.group(2).strip() + + binop_map = { + 'add': 'add', 'fadd': 'fadd', 'sub': 'sub', 'fsub': 'fsub', + 'mul': 'mul', 'fmul': 'fmul', 'udiv': 'udiv', 'sdiv': 'sdiv', + 'fdiv': 'fdiv', 'urem': 'urem', 'srem': 'srem', 'frem': 'frem', + 'shl': 'shl', 'lshr': 'lshr', 'ashr': 'ashr', + 'and': 'and_', 'or': 'or_', 'xor': 'xor_', + } + + icmp_match = re.match(r'icmp\s+(\w+)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template) + if icmp_match: + pred = icmp_match.group(1) + op1 = resolve_op(int(icmp_match.group(3))) + op2 = resolve_op(int(icmp_match.group(4))) + if op1 and op2: + result = Gen.builder.icmp_signed(pred, op1, op2, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + fcmp_match = re.match(r'fcmp\s+(\w+(?:\s+fast)?)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template) + if fcmp_match: + pred = fcmp_match.group(1) + op1 = resolve_op(int(fcmp_match.group(3))) + op2 = resolve_op(int(fcmp_match.group(4))) + if op1 and op2: + result = Gen.builder.fcmp_ordered(pred, op1, op2, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + for op_name, method_name in binop_map.items(): + pattern = re.compile( + rf'{op_name}\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', + re.IGNORECASE if op_name in ('and', 'or', 'xor') else 0 + ) + m = pattern.match(template) + if m: + op1 = resolve_op(int(m.group(2))) + op2 = resolve_op(int(m.group(3))) + if op1 and op2: + method = getattr(Gen.builder, method_name, None) + if method: + result = method(op1, op2, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + select_match = re.match(r'select\s+i1\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__', template) + if select_match: + cond = resolve_op(int(select_match.group(1))) + true_val = resolve_op(int(select_match.group(3))) + false_val = resolve_op(int(select_match.group(5))) + if cond and true_val and false_val: + result = Gen.builder.select(cond, true_val, false_val, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + cast_map = { + 'zext': 'zext', 'sext': 'sext', 'trunc': 'trunc', + 'bitcast': 'bitcast', 'inttoptr': 'inttoptr', 'ptrtoint': 'ptrtoint', + 'uitofp': 'uitofp', 'sitofp': 'sitofp', 'fptoui': 'fptoui', 'fptosi': 'fptosi', + 'fpext': 'fpext', 'fptrunc': 'fptrunc', + } + for op_name, method_name in cast_map.items(): + pattern = re.compile(rf'{op_name}\s+(\w+)\s+%__OP(\d+)__\s+to\s+(\w+)') + m = pattern.match(template) + if m: + src_val = resolve_op(int(m.group(2))) + dest_type_str = m.group(3) + dest_type = self._ParseLLVMType(Gen, dest_type_str) + if src_val and dest_type: + method = getattr(Gen.builder, method_name, None) + if method: + result = method(src_val, dest_type, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + load_match = re.match(r'load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__', template) + if load_match: + ptr_val = resolve_op(int(load_match.group(3))) + if ptr_val: + result = Gen.builder.load(ptr_val, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + store_match = re.match(r'store\s+(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__', template) + if store_match: + val = resolve_op(int(store_match.group(2))) + ptr = resolve_op(int(store_match.group(4))) + if val and ptr: + Gen.builder.store(val, ptr) + return ir.Constant(ir.IntType(32), 0) + + gep_match = re.match(r'getelementptr\s+(?:inbounds\s+)?(\w+),\s*(\w+)\s+%__OP(\d+)__,\s*(.+)', template) + if gep_match: + ptr_val = resolve_op(int(gep_match.group(3))) + indices_str = gep_match.group(4) + if ptr_val: + indices = [] + for idx_part in re.split(r',\s*', indices_str): + idx_part = idx_part.strip() + idx_m = re.match(r'%__OP(\d+)__', idx_part) + if idx_m: + idx_op = resolve_op(int(idx_m.group(1))) + if idx_op: + indices.append(idx_op) + else: + try: + indices.append(ir.Constant(ir.IntType(32), int(idx_part))) + except ValueError: + break + if indices: + result = Gen.builder.gep(ptr_val, indices, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + neg_match = re.match(r'sub\s+(\w+)\s+(\d+),\s*%__OP(\d+)__', template) + if neg_match: + op = resolve_op(int(neg_match.group(3))) + if op: + zero = ir.Constant(op.type, int(neg_match.group(2))) + result = Gen.builder.sub(zero, op, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + not_match = re.match(r'xor\s+(\w+)\s+(-1|\d+),\s*%__OP(\d+)__', template) + if not_match: + op = resolve_op(int(not_match.group(3))) + if op: + mask = ir.Constant(op.type, int(not_match.group(2))) + result = Gen.builder.xor_(op, mask, name="llvmir_result") + return self._StoreLLVMIROutputs(Gen, result, output_targets) + + call_match = re.match(r'call\s+(\w+)\s+@([\w.]+)\((.+)\)', template) + if call_match: + call_ret_str = call_match.group(1) + func_name = call_match.group(2) + args_str = call_match.group(3) + call_args = [] + for arg_part in re.split(r',\s*', args_str): + arg_part = arg_part.strip() + typed_op = re.match(r'(\w+\*?)\s+%__OP(\d+)__', arg_part) + if typed_op: + expected_type_str = typed_op.group(1) + op_idx = int(typed_op.group(2)) + val = resolve_op(op_idx) + if val: + val = self._ConvertLLVMIRType(Gen, val, expected_type_str) + if val: + call_args.append(val) + else: + const_m = re.match(r'(\w+)\s+(-?\d+)', arg_part) + if const_m: + const_type = self._ParseLLVMType(Gen, const_m.group(1)) + if const_type: + call_args.append(ir.Constant(const_type, int(const_m.group(2)))) + if call_args: + call_ret_type = self._ParseLLVMType(Gen, call_ret_str) or ir.VoidType() + func_type = ir.FunctionType(call_ret_type, [a.type for a in call_args]) + if func_name.startswith('llvm.'): + existing = Gen.module.globals.get(func_name) + if existing: + func = existing + else: + try: + func = Gen.module.declare_intrinsic(func_name, [a.type for a in call_args]) + except Exception: + func = ir.Function(Gen.module, func_type, name=func_name) + else: + existing = Gen.module.globals.get(func_name) + if existing: + func = existing + else: + func = ir.Function(Gen.module, func_type, name=func_name) + result = Gen.builder.call(func, call_args, name="llvmir_result") + if output_targets: + return self._StoreLLVMIROutputs(Gen, result, output_targets) + if isinstance(call_ret_type, ir.VoidType): + return ir.Constant(ir.IntType(32), 0) + return result + + if output_targets: + for i, target in enumerate(output_targets): + if isinstance(target, ir.AllocaInstr): + Gen.builder.store(ir.Constant(target.type.pointee, 0), target) + return ir.Constant(ir.IntType(32), 0) + + return ir.Constant(ret_type, 0) + + def _StoreLLVMIROutputs(self, Gen, result, output_targets): + for target in output_targets: + if isinstance(target, ir.AllocaInstr): + if target.type.pointee == result.type: + Gen.builder.store(result, target) + else: + i64t = ir.IntType(64) + if isinstance(result.type, ir.IntType) and result.type.width == 64 and isinstance(target.type.pointee, ir.PointerType): + ptr_val = Gen.builder.inttoptr(result, target.type.pointee) + Gen.builder.store(ptr_val, target) + elif isinstance(result.type, ir.PointerType) and isinstance(target.type.pointee, ir.IntType) and target.type.pointee.width == 64: + int_val = Gen.builder.ptrtoint(result, i64t) + Gen.builder.store(int_val, target) + else: + try: + cast_val = Gen.builder.bitcast(result, target.type.pointee) + Gen.builder.store(cast_val, target) + except Exception: + Gen.builder.store(result, target) + elif isinstance(target, (ir.GlobalVariable, ir.GEPInstr)): + if isinstance(target.type, ir.PointerType): + if target.type.pointee == result.type: + Gen.builder.store(result, target) + else: + try: + cast_val = Gen.builder.bitcast(result, target.type.pointee) + Gen.builder.store(cast_val, target) + except Exception: + Gen.builder.store(result, target) + return result + + def _ParseLLVMType(self, Gen, type_str): + type_map = { + 'i1': ir.IntType(1), 'i8': ir.IntType(8), 'i16': ir.IntType(16), + 'i32': ir.IntType(32), 'i64': ir.IntType(64), 'i128': ir.IntType(128), + 'float': ir.FloatType(), 'double': ir.DoubleType(), + 'void': ir.VoidType(), + } + if type_str in type_map: + return type_map[type_str] + if type_str.endswith('*'): + pointee = self._ParseLLVMType(Gen, type_str[:-1]) + if pointee: + return ir.PointerType(pointee) + return None + + def _ConvertLLVMIRType(self, Gen, val, expected_type_str): + expected_type = self._ParseLLVMType(Gen, expected_type_str.rstrip('*')) + if not expected_type: + return val + is_ptr = expected_type_str.endswith('*') + if is_ptr: + expected_ptr_type = ir.PointerType(expected_type) + if isinstance(val.type, ir.PointerType) and val.type != expected_ptr_type: + try: + return Gen.builder.bitcast(val, expected_ptr_type) + except Exception: + return val + elif isinstance(val.type, ir.IntType) and val.type.width == 64: + try: + return Gen.builder.inttoptr(val, expected_ptr_type) + except Exception: + return val + return val + if val.type == expected_type: + return val + if isinstance(val.type, ir.IntType) and isinstance(expected_type, ir.IntType): + if expected_type.width < val.type.width: + return Gen.builder.trunc(val, expected_type) + else: + return Gen.builder.zext(val, expected_type) + if isinstance(val.type, ir.PointerType) and isinstance(expected_type, ir.IntType): + if expected_type.width == 64: + return Gen.builder.ptrtoint(val, expected_type) + if isinstance(val.type, ir.IntType) and isinstance(expected_type, ir.PointerType): + if val.type.width == 64: + return Gen.builder.inttoptr(val, expected_type) + return val + + def _HandleExternalCallLlvm(self, Node, func_name, module_path): + Gen = self.Trans.LlvmGen + + # 解析 import 别名: 如 window -> vpsdk.window + if module_path and module_path not in ('c', 't'): + import_aliases = getattr(self.Trans, '_import_aliases', {}) + if module_path in import_aliases: + module_path = import_aliases[module_path] + + is_user_module = (module_path and module_path not in ('c', 't') and + (module_path in Gen.module_sha1_map or + module_path in getattr(self.Trans, '_imported_modules', set()) or + module_path in getattr(self.Trans, '_import_aliases', {}))) + if module_path and module_path not in ('c', 't') and not is_user_module: + is_user_module = (module_path in Gen.module_sha1_map or + module_path.split('.')[-1] in Gen.module_sha1_map) + if is_user_module and module_path not in Gen.module_sha1_map: + module_path = module_path.split('.')[-1] + + if module_path and module_path not in ('c', 't') and not is_user_module: + return None + + if is_user_module: + mangled_name = Gen._mangle_func_name(func_name, module_path) + sym_key = f'{module_path}.{func_name}' + sym_info = self.Trans.SymbolTable.get(sym_key) or self.Trans.SymbolTable.get(func_name) + is_inline = sym_info and (getattr(sym_info, 'IsInline', False) or isinstance(getattr(sym_info, 'Storage', None), t.CInline)) + if is_inline and getattr(sym_info, 'InlineBody', None): + self._HandleInlineExpandLlvm(Node, sym_info) + return ir.Constant(ir.IntType(32), 1) + sym_info_exact = self.Trans.SymbolTable.get(sym_key) + if sym_info_exact: + exact_params = getattr(sym_info_exact, 'FuncPtrParams', []) + exact_param_names = [pn for pn, _ in exact_params] + if exact_param_names: + provided = len(Node.args) + kw_provided = set() + for kw in Node.keywords: + if kw.arg and kw.arg in exact_param_names: + kw_provided.add(exact_param_names.index(kw.arg)) + for i in range(len(exact_param_names)): + if i >= provided and i not in kw_provided: + raise Exception(f"调用 {module_path}.{func_name}() 缺少必需参数 '{exact_param_names[i]}',该参数没有默认值") + elif module_path in Gen.module_sha1_map and len(Node.args) == 0: + func = Gen.functions.get(mangled_name) + if func and len(func.function_type.args) > 0: + raise Exception(f"调用 {module_path}.{func_name}() 缺少必需参数,函数需要 {len(func.function_type.args)} 个参数但未传入任何参数") + if Gen._has_function(mangled_name): + return self._HandleClosureCallLlvm(Node, mangled_name) + try: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) + except Exception: + stub_func_type = None + if not stub_func_type and mangled_name != func_name: + try: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(func_name, Gen) + except Exception: + stub_func_type = None + if stub_func_type: + if is_user_module: + decl_name = mangled_name + else: + decl_name = mangled_name if mangled_name in self.Trans.ImportHandler._stub_func_cache else func_name + if decl_name in Gen.functions: + func_decl = Gen.functions[decl_name] + else: + func_decl = ir.Function(Gen.module, stub_func_type, name=decl_name) + Gen.functions[decl_name] = func_decl + if decl_name != func_name and func_name not in Gen.functions: + Gen.functions[func_name] = func_decl + return self._HandleClosureCallLlvm(Node, decl_name) + sym_key = f'{module_path}.{func_name}' + sym_info = self.Trans.SymbolTable.get(sym_key) + if not sym_info: + sym_info = self.Trans.SymbolTable.get(func_name) + if sym_info: + is_func = getattr(sym_info, 'IsFunction', False) + sym_is_variadic = getattr(sym_info, 'IsVariadic', False) + if is_func: + ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) + if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: + ret_type = ret_type_info.ToLLVM(Gen) + else: + ret_type = Gen._CType2LLVM('i32', False) + sym_params = getattr(sym_info, 'FuncPtrParams', []) + param_type_infos = [pt for _, pt in sym_params] + if isinstance(ret_type, ir.VoidType): + ret_type = ir.IntType(32) + llvm_param_types = [] + for pi, pt in enumerate(param_type_infos): + if isinstance(pt, CTypeInfo) and pt.BaseType: + lp = pt.ToLLVM(Gen) + else: + lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False) + if isinstance(lp, ir.VoidType): + lp = ir.IntType(8).as_pointer() + llvm_param_types.append(lp) + if mangled_name not in Gen.functions: + func_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) + func_decl = ir.Function(Gen.module, func_type, name=mangled_name) + Gen.functions[mangled_name] = func_decl + else: + existing = Gen.functions[mangled_name] + existing_type = getattr(existing, 'ftype', None) + new_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) + if existing_type and existing_type != new_type: + replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, func_name, new_type) + if replaced and replaced != existing: + Gen.functions[mangled_name] = replaced + return self._HandleClosureCallLlvm(Node, mangled_name) + return None + + if module_path == 'c': + if func_name == 'Asm': + return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node) + elif func_name == 'Addr': + return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node) + elif func_name == 'Set': + return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node) + elif func_name == 'Load': + return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node) + elif func_name == 'Deref': + return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node) + elif func_name == 'DerefAs': + return self._HandleCDerefAsLlvm(Node) + elif func_name == 'PtrToInt': + return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node) + elif func_name in ('CIf', 'CElif'): + return self.Trans.CSpecialCallHandle._HandleCIfLlvm(Node) + elif func_name == 'CError': + msg = "compile-time error" + if Node.args: + arg = Node.args[0] + if isinstance(arg, ast.Constant) and isinstance(arg.value, str): + msg = arg.value + elif isinstance(arg, ast.Str): + msg = arg.s + lineno = getattr(Node, 'lineno', 0) + raise Exception(f"#error: {msg} (line {lineno})") + elif func_name in ('AsmInp', 'AsmOut'): + return ir.Constant(ir.IntType(32), 0) + elif func_name == 'LLVMIR': + return self._HandleLLVMIRLlvm(Node) + elif func_name in ('LInp', 'LOut'): + return ir.Constant(ir.IntType(32), 0) + + win32_apis = { + 'SetConsoleOutputCP': (ir.IntType(32), [ir.IntType(32)]), + 'SetConsoleCP': (ir.IntType(32), [ir.IntType(32)]), + 'GetConsoleOutputCP': (ir.IntType(32), []), + 'GetConsoleCP': (ir.IntType(32), []), + } + if module_path and 'win32console' in module_path and func_name in win32_apis: + ret_type, param_types = win32_apis[func_name] + if func_name not in Gen.functions: + func_type = ir.FunctionType(ret_type, param_types) + func_decl = ir.Function(Gen.module, func_type, name=func_name) + func_decl.linkage = 'external' + Gen.functions[func_name] = func_decl + call_args = [] + if Node.args: + arg_val = self.HandleExprLlvm(Node.args[0]) + if arg_val: + target_type = param_types[0] if param_types else ir.IntType(32) + if isinstance(arg_val.type, ir.IntType) and arg_val.type.width < target_type.width: + arg_val = Gen.builder.zext(arg_val, target_type, name="zext_win32_arg") + elif isinstance(arg_val.type, ir.IntType) and arg_val.type.width > target_type.width: + arg_val = Gen.builder.trunc(arg_val, target_type, name="trunc_win32_arg") + call_args.append(arg_val) + return Gen.builder.call(Gen.functions[func_name], call_args, name=f"call_{func_name}") + + if Gen._has_function(func_name): + return self._HandleClosureCallLlvm(Node, func_name) + + if func_name in self.Trans.FunctionDefCache: + return self._HandleClosureCallLlvm(Node, func_name) + + if func_name in self._C_LIB_FUNCS: + return self._HandleClosureCallLlvm(Node, func_name) + + mangled_name = Gen._mangle_func_name(func_name, module_path) + try: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) + except Exception: + stub_func_type = None + if not stub_func_type and mangled_name != func_name: + try: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(func_name, Gen) + except Exception: + stub_func_type = None + if stub_func_type: + decl_name = mangled_name if mangled_name in self.Trans.ImportHandler._stub_func_cache else func_name + func_decl = ir.Function(Gen.module, stub_func_type, name=decl_name) + Gen.functions[decl_name] = func_decl + if decl_name != func_name: + Gen.functions[func_name] = func_decl + return self._HandleClosureCallLlvm(Node, decl_name) + + sym_key = f'{module_path}.{func_name}' if module_path else func_name + sym_info = self.Trans.SymbolTable.get(sym_key) + if not sym_info: + sym_info = self.Trans.SymbolTable.get(func_name) + if sym_info: + is_func = getattr(sym_info, 'IsFunction', False) + sym_is_variadic = getattr(sym_info, 'IsVariadic', False) + if is_func: + ret_type_info = getattr(sym_info, 'FuncPtrReturn', None) + if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: + ret_type = ret_type_info.ToLLVM(Gen) + else: + ret_type = Gen._CType2LLVM('i32', False) + param_type_infos = [pt for _, pt in getattr(sym_info, 'FuncPtrParams', [])] + if isinstance(ret_type, ir.VoidType): + ret_type = ir.IntType(32) + llvm_param_types = [] + for pt in param_type_infos: + if isinstance(pt, CTypeInfo) and pt.BaseType: + lp = pt.ToLLVM(Gen) + else: + lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False) + if isinstance(lp, ir.VoidType): + lp = ir.IntType(8).as_pointer() + llvm_param_types.append(lp) + mangled_name = Gen._mangle_func_name(func_name, module_path) + if mangled_name not in Gen.functions: + func_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) + func_decl = ir.Function(Gen.module, func_type, name=mangled_name) + Gen.functions[mangled_name] = func_decl + else: + existing = Gen.functions[mangled_name] + existing_type = getattr(existing, 'ftype', None) + new_type = ir.FunctionType(ret_type, llvm_param_types, var_arg=sym_is_variadic) + if existing_type and existing_type != new_type: + replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, func_name, new_type) + if replaced and replaced != existing: + Gen.functions[mangled_name] = replaced + return self._HandleClosureCallLlvm(Node, mangled_name) + + return None + + def _HandleTypeUnionCastLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return None + from lib.core.Handles.HandlesBase import CTypeInfo + type_info = None + try: + type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func) + except Exception: + pass + if not isinstance(type_info, CTypeInfo): + return None + target_type_str = type_info.ToString() + is_ptr = type_info.IsPtr + if is_ptr and target_type_str and '*' not in target_type_str: + target_type_str += ' *' + if not target_type_str: + return None + if type_info.IsPtr and not is_ptr: + is_ptr = True + if '*' not in target_type_str: + target_type_str += ' *' + if isinstance(type_info.Storage, t.CExport) or isinstance(type_info.Storage, t.CExtern): + pass + if type_info.IsState: + Gen._export_funcs.add('_type_union_cast') + return self._HandleTypeCastLlvm(Node.args[0], target_type_str) + + def _HandleTypeCastLlvm(self, expr_node, target_type_str): + Gen = self.Trans.LlvmGen + val = self.HandleExprLlvm(expr_node) + if val is None: + return Gen.emit_constant(0, target_type_str) + target_type = Gen._CType2LLVM(target_type_str) + if not target_type: + return val + if val.type == target_type: + if Gen._is_type_unsigned(target_type_str): + Gen._unsigned_results[id(val)] = True + return val + src_is_float = isinstance(val.type, (ir.FloatType, ir.DoubleType)) + dst_is_float = isinstance(target_type, (ir.FloatType, ir.DoubleType)) + src_is_int = isinstance(val.type, ir.IntType) + dst_is_int = isinstance(target_type, ir.IntType) + src_is_ptr = isinstance(val.type, ir.PointerType) + dst_is_ptr = isinstance(target_type, ir.PointerType) + if src_is_int and dst_is_float: + is_unsigned = Gen._check_node_unsigned(expr_node) + if is_unsigned: + return Gen.builder.uitofp(val, target_type, name="uint2float") + return Gen.builder.sitofp(val, target_type, name="int2float") + if src_is_float and dst_is_int: + return Gen.builder.fptosi(val, target_type, name="float2int") + if src_is_int and dst_is_int: + is_dst_unsigned = Gen._is_type_unsigned(target_type_str) + if val.type.width < target_type.width: + is_unsigned = Gen._check_node_unsigned(expr_node) + if is_unsigned or is_dst_unsigned: + result = Gen.builder.zext(val, target_type, name="zext_cast") + else: + result = Gen.builder.sext(val, target_type, name="sext_cast") + if is_dst_unsigned: + Gen._unsigned_results[id(result)] = True + return result + if val.type.width > target_type.width: + result = Gen.builder.trunc(val, target_type, name="trunc_cast") + if is_dst_unsigned: + Gen._unsigned_results[id(result)] = True + return result + if is_dst_unsigned: + Gen._unsigned_results[id(val)] = True + return val + if src_is_float and dst_is_float: + if isinstance(val.type, ir.FloatType) and isinstance(target_type, ir.DoubleType): + return Gen.builder.fpext(val, target_type, name="fpext_cast") + if isinstance(val.type, ir.DoubleType) and isinstance(target_type, ir.FloatType): + return Gen.builder.fptrunc(val, target_type, name="fptrunc_cast") + return val + if src_is_ptr and dst_is_int: + if target_type.width < 64: + ptr_to_i64 = Gen.builder.ptrtoint(val, ir.IntType(64), name="ptr2i64") + return Gen.builder.trunc(ptr_to_i64, target_type, name="ptr2int_cast") + return Gen.builder.ptrtoint(val, target_type, name="ptr2int_cast") + if src_is_int and dst_is_ptr: + return Gen.builder.inttoptr(val, target_type, name="int2ptr_cast") + if src_is_ptr and dst_is_ptr: + if isinstance(val.type.pointee, ir.PointerType) and isinstance(target_type.pointee, ir.IntType): + loaded = Gen._load(val, name="load_ptr") + return loaded + return Gen.builder.bitcast(val, target_type, name="ptrcast") + try: + return Gen.builder.bitcast(val, target_type, name="cast") + except Exception: # 回退:bitcast 失败时返回原值 + return val + + def _HandleREnumConstructLlvm(self, Node, RenumName, VariantName, TagValue): + Gen = self.Trans.LlvmGen + if RenumName not in Gen.structs: + return None + RenumType = Gen.structs[RenumName] + result = Gen._alloca_entry(RenumType, name=f"{RenumName}_{VariantName}") + tag_ptr = Gen.builder.gep(result, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="renum_tag_ptr") + Gen._store(ir.Constant(ir.IntType(32), TagValue), tag_ptr) + NestedStructName = f"{RenumName}_{VariantName}" + if NestedStructName in Gen.structs and Node.args: + NestedStructType = Gen.structs[NestedStructName] + NestedStructPtrType = ir.PointerType(NestedStructType) + variant_ptr = Gen.builder.bitcast(result, NestedStructPtrType, name=f"cast_{NestedStructName}") + members = Gen.class_members.get(NestedStructName, []) + payload_members = [(n, t) for n, t in members if n != '__tag'] + for i, arg in enumerate(Node.args): + if i < len(payload_members): + member_name, member_type = payload_members[i] + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + Coerced = Gen._coerce_value(ArgVal, member_type) + if Coerced is not None: + ArgVal = Coerced + elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i + 1)], name=f"{VariantName}_{member_name}") + Gen._store(ArgVal, elem_ptr) + return result + + def _HandleTypedefCastLlvm(self, Node, TypedefName): + Gen = self.Trans.LlvmGen + SymInfo = self.Trans.SymbolTable.get(TypedefName) + if not SymInfo or not SymInfo.IsTypedef: + return ir.Constant(ir.IntType(32), 0) + TargetType = Gen._ctype_to_llvm(SymInfo) + if not Node.args: + if isinstance(TargetType, ir.IntType): + return ir.Constant(TargetType, 0) + elif isinstance(TargetType, ir.PointerType): + return ir.Constant(TargetType, None) + return ir.Constant(ir.IntType(32), 0) + ArgVal = self.HandleExprLlvm(Node.args[0]) + if not ArgVal: + if isinstance(TargetType, ir.IntType): + return ir.Constant(TargetType, 0) + return ir.Constant(ir.IntType(32), 0) + if ArgVal.type == TargetType: + return ArgVal + if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType): + if ArgVal.type.width < TargetType.width: + return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast") + elif ArgVal.type.width > TargetType.width: + return Gen.builder.trunc(ArgVal, TargetType, name=f"trunc_{TypedefName}_cast") + return ArgVal + if isinstance(TargetType, ir.PointerType): + if isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.bitcast(ArgVal, TargetType, name=f"bitcast_{TypedefName}_cast") + if isinstance(ArgVal.type, ir.IntType): + return Gen.builder.inttoptr(ArgVal, TargetType, name=f"inttoptr_{TypedefName}_cast") + # 如果参数是结构体值,需要 alloca 并返回指针 + if isinstance(ArgVal.type, ir.BaseStructType): + alloca = Gen.builder.alloca(ArgVal.type, name=f"struct_alloca_{TypedefName}") + Gen.builder.store(ArgVal, alloca, align=8) + return Gen.builder.bitcast(alloca, TargetType, name=f"bitcast_struct_{TypedefName}") + if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.ptrtoint(ArgVal, TargetType, name=f"ptrtoint_{TypedefName}_cast") + if isinstance(TargetType, (ir.FloatType, ir.DoubleType)) and isinstance(ArgVal.type, ir.IntType): + return Gen.builder.sitofp(ArgVal, TargetType, name=f"sitofp_{TypedefName}_cast") + if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fptosi(ArgVal, TargetType, name=f"fptosi_{TypedefName}_cast") + return ArgVal + + def _HandleInlineExpandLlvm(self, Node, sym_info): + Gen = self.Trans.LlvmGen + inline_body = sym_info.InlineBody + inline_params = sym_info.InlineParams or [] + call_args = [] + for arg in Node.args: + call_args.append(self.Trans.ExprHandler.HandleExprLlvm(arg)) + saved_vars = {} + for i, param_name in enumerate(inline_params): + if i < len(call_args): + saved_vars[param_name] = call_args[i] + old_var_scopes = list(self.Trans.VarScopes) + for param_name, val in saved_vars.items(): + if val is not None: + alloca = Gen._alloca_entry(val.type, name=f"inline_arg_{param_name}") + Gen._store(val, alloca) + self.Trans.VarScopes.append((param_name, alloca)) + self.Trans.BodyHandler.HandleBodyLlvm(inline_body) + for param_name, _ in saved_vars.items(): + if self.Trans.VarScopes and self.Trans.VarScopes[-1][0] == param_name: + self.Trans.VarScopes.pop() + self.Trans.VarScopes = old_var_scopes + return None + + def _HandleClosureCallLlvm(self, Node, FuncName): + Gen = self.Trans.LlvmGen + func = Gen.functions.get(FuncName) + if not func: + if FuncName in self.Trans.FunctionDefCache: + FuncDef = self.Trans.FunctionDefCache[FuncName] + self.Trans.FunctionHandler._EmitFunctionForwardDeclLlvm(FuncDef, Gen) + func = Gen.functions.get(FuncName) + if not func: + func = self._try_declare_c_lib_func(FuncName, Gen) + if not func: + raise Exception(f"Undefined function: '{FuncName}'") + + FuncDef = self.Trans.FunctionDefCache.get(FuncName) + param_names = [] + FuncDef_args = getattr(FuncDef, 'args', None) if FuncDef else None + if FuncDef_args: + param_names = [arg.arg for arg in FuncDef.args.args] + + num_params = len(func.function_type.args) + nonlocal_param_count = len(Gen.nonlocal_params.get(FuncName, [])) + eh_msg_out_count = 0 + if num_params > 0 and func.args: + for arg in func.args: + if arg.name in ('__eh_msg_out__', '__eh_code_out__'): + eh_msg_out_count += 1 + regular_param_count = num_params - nonlocal_param_count - eh_msg_out_count + is_variadic = False + func_ft = getattr(func, 'function_type', None) + is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False + + if not is_variadic and len(Node.args) > regular_param_count: + raise Exception(f"调用 {FuncName}() 传入了 {len(Node.args)} 个参数,但函数只需要 {regular_param_count} 个参数") + + max_args = len(Node.args) if is_variadic else regular_param_count + resolved = [None] * max_args + + for i, arg in enumerate(Node.args): + if i < max_args: + arg_var_type = None + if i < num_params: + arg_var_type = func.function_type.args[i] + ArgVal = self.HandleExprLlvm(arg, VarType=arg_var_type) + if ArgVal: + resolved[i] = ArgVal + + for kw in Node.keywords: + if kw.arg is None: + if isinstance(kw.value, ast.Dict): + pass + elif isinstance(kw.value, ast.Call): + pass + continue + ArgVal = self.HandleExprLlvm(kw.value) + if not ArgVal: + continue + kw_name = kw.arg + if kw_name in param_names: + idx = param_names.index(kw_name) + if idx < regular_param_count: + resolved[idx] = ArgVal + + FuncDef_args_defaults = getattr(getattr(FuncDef, 'args', None), 'defaults', []) if FuncDef else [] + if FuncDef_args_defaults: + defaults = FuncDef.args.defaults + num_defaults = len(defaults) + if num_defaults > 0: + min_args = regular_param_count - num_defaults + for i in range(regular_param_count): + if resolved[i] is None and i >= min_args: + default_idx = i - min_args + if default_idx < len(defaults): + default_node = defaults[default_idx] + default_val = self.HandleExprLlvm(default_node) + if default_val: + param_type = func.function_type.args[i] + if default_val.type != param_type: + if isinstance(param_type, ir.IntType) and isinstance(default_val.type, ir.IntType): + if default_val.type.width < param_type.width: + default_val = Gen.builder.zext(default_val, param_type, name=f"zext_default_{i}") + elif default_val.type.width > param_type.width: + default_val = Gen.builder.trunc(default_val, param_type, name=f"trunc_default_{i}") + elif isinstance(param_type, ir.PointerType) and isinstance(default_val.type, ir.IntType): + default_val = Gen.builder.inttoptr(default_val, param_type, name=f"inttoptr_default_{i}") + resolved[i] = default_val + + if FuncDef and param_names: + min_args = regular_param_count - num_defaults if FuncDef_args_defaults else regular_param_count + provided = len(Node.args) + kw_provided = set() + for kw in Node.keywords: + if kw.arg and kw.arg in param_names: + kw_provided.add(param_names.index(kw.arg)) + for i in range(min(min_args, len(param_names))): + if i >= provided and i not in kw_provided: + raise Exception(f"调用 {FuncName}() 缺少必需参数 '{param_names[i]}',该参数没有默认值") + + CallArgs = [] + for i in range(max_args): + if resolved[i] is not None: + CallArgs.append(resolved[i]) + elif i < regular_param_count: + arg_type = func.function_type.args[i] + if isinstance(arg_type, ir.PointerType): + CallArgs.append(ir.Constant(arg_type, None)) + elif isinstance(arg_type, (ir.IdentifiedStructType, ir.LiteralStructType)): + zero_val = Gen._zero_value_for_type(arg_type) + if zero_val is not None: + CallArgs.append(zero_val) + else: + CallArgs.append(ir.Constant(ir.PointerType(arg_type), None)) + elif isinstance(arg_type, ir.ArrayType): + zero_val = Gen._zero_value_for_type(arg_type) + if zero_val is not None: + CallArgs.append(zero_val) + else: + CallArgs.append(ir.Constant(arg_type, 0)) + else: + CallArgs.append(ir.Constant(arg_type, 0)) + + if FuncName in Gen.nonlocal_params: + for var_name, ptr_type in Gen.nonlocal_params[FuncName]: + if var_name in Gen.variables and Gen.variables[var_name] is not None: + CallArgs.append(Gen.variables[var_name]) + elif var_name in Gen._reg_values: + OldVal = Gen._reg_values[var_name] + var = Gen._alloca_entry(OldVal.type, name=var_name) + Gen._store(OldVal, var) + Gen.variables[var_name] = var + del Gen._reg_values[var_name] + CallArgs.append(var) + + self._append_eh_msg_out_arg(CallArgs, func, Gen) + + if is_variadic: + # 对于可变参数函数,需要手动处理参数类型转换 + adjusted = [] + for i, arg in enumerate(CallArgs): + if i < num_params: + # 固定参数:尝试类型转换 + param_type = func.function_type.args[i] + if arg.type != param_type: + try: + if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType): + adjusted.append(self.builder.inttoptr(arg, param_type)) + elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType): + adjusted.append(Gen.builder.ptrtoint(arg, param_type)) + elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width: + adjusted.append(Gen.builder.zext(arg, param_type)) + else: + adjusted.append(arg) + except Exception: # 回退:参数类型调整失败时使用原值 + adjusted.append(arg) + else: + adjusted.append(arg) + else: + # 可变参数:应用默认参数提升(float -> double, i32 -> i64) + if isinstance(arg.type, ir.FloatType): + arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{FuncName}") + elif isinstance(arg.type, ir.IntType) and arg.type.width < 64: + # 有符号整数用 sext,无符号整数用 zext + is_signed = True + arg_node = Node.args[i] if i < len(Node.args) else None + if arg_node is not None: + is_u = Gen._check_node_unsigned(arg_node) + if is_u: + is_signed = False + if is_signed: + arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{FuncName}") + else: + arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{FuncName}") + adjusted.append(arg) + result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") + else: + adjusted = Gen._adjust_args(CallArgs, func) + result = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") + self._check_eh_return(result, FuncName, Gen, called_func=func) + return result + + def _HandleMethodCallLlvm(self, Node): + Gen = self.Trans.LlvmGen + MethodName = Node.func.attr + # 检查是否为 @staticmethod 或 @classmethod,如果是则走特殊路径 + if isinstance(Node.func.value, ast.Name): + VarName = Node.func.value.id + ClassName = Gen.var_struct_class.get(VarName) + if ClassName: + SymKey = f'{ClassName}.{MethodName}' + SymInfo = self.Trans.SymbolTable.get(SymKey) + if SymInfo and hasattr(SymInfo, 'MetaList'): + if FuncMeta.STATIC_METHOD in SymInfo.MetaList: + return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName) + if FuncMeta.CLASS_METHOD in SymInfo.MetaList: + return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName) + if isinstance(Node.func.value, ast.Name) and Node.func.value.id == 't': + result = self.Trans.TSpecialCallHandle._HandleTSpecialCallLlvm(Node) + if result is not None: + return result + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(MethodName) + if ctype_cls is not None: + try: + ctype_inst = ctype_cls() + except Exception: + ctype_inst = None + target_bits = getattr(ctype_inst, 'Size', None) if ctype_inst else None + if target_bits is None: + target_bits = 0 + is_float = getattr(ctype_inst, 'IsSigned', False) is None and target_bits > 0 if ctype_inst else False + is_ptr_cast = len(Node.args) >= 2 and ( + (isinstance(Node.args[1], ast.Attribute) and Node.args[1].attr == 'CPtr' and isinstance(Node.args[1].value, ast.Name) and Node.args[1].value.id == 't') or + (isinstance(Node.args[1], ast.Name) and Node.args[1].id == 'CPtr') + ) + if Node.args: + ArgNode = Node.args[0] + if isinstance(ArgNode, ast.Subscript): + SubscriptPtr = self._HandleSubscriptPtrLlvm(ArgNode) + if SubscriptPtr: + if MethodName == 'CPtr' or is_ptr_cast: + return SubscriptPtr + if isinstance(SubscriptPtr.type, ir.PointerType): + val = Gen._load(SubscriptPtr, name="load_subscript_val") + else: + val = SubscriptPtr + if target_bits > 0 and isinstance(val.type, ir.IntType) and not is_float: + if val.type.width < target_bits: + val = Gen.builder.zext(val, ir.IntType(target_bits), name="zext_cast") + elif val.type.width > target_bits: + val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast") + return val + val = self.HandleExprLlvm(ArgNode) + if is_ptr_cast: + if target_bits > 0 and not is_float: + target_ptr_type = ir.PointerType(ir.IntType(target_bits)) + elif is_float and target_bits == 32: + target_ptr_type = ir.PointerType(ir.FloatType()) + elif is_float and target_bits == 64: + target_ptr_type = ir.PointerType(ir.DoubleType()) + else: + target_ptr_type = ir.PointerType(ir.IntType(8)) + if isinstance(val.type, ir.PointerType): + if val.type != target_ptr_type: + val = Gen.builder.bitcast(val, target_ptr_type, name="ptr_cast") + elif isinstance(val.type, ir.IntType): + if val.type.width < 64: + val = Gen.builder.zext(val, ir.IntType(64), name="zext_ptr_cast") + val = Gen.builder.inttoptr(val, target_ptr_type, name="int_to_ptr_cast") + return val + if val and target_bits > 0 and not is_float: + if isinstance(val.type, ir.IntType): + if val.type.width < target_bits: + val = Gen.builder.zext(val, ir.IntType(target_bits), name="zext_cast") + elif val.type.width > target_bits: + val = Gen.builder.trunc(val, ir.IntType(target_bits), name="trunc_cast") + elif isinstance(val.type, ir.PointerType): + val = Gen.builder.ptrtoint(val, ir.IntType(target_bits), name="ptrtoint_cast") + return val + if is_float: + return ir.Constant(ir.FloatType() if target_bits == 32 else ir.DoubleType(), 0.0) + return ir.Constant(ir.IntType(target_bits) if target_bits > 0 else ir.IntType(32), 0) + if MethodName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[MethodName] + if SymInfo.IsTypedef: + return self._HandleTypedefCastLlvm(Node, MethodName) + if isinstance(Node.func.value, ast.Name) and Node.func.value.id == 'c': + if MethodName == 'Asm': + return self.Trans.ExprAsmHandle._HandleAsmLlvm(Node) + if MethodName == 'Addr': + return self.Trans.CSpecialCallHandle._HandleCAddrLlvm(Node) + elif MethodName == 'Set': + return self.Trans.CSpecialCallHandle._HandleCSetLlvm(Node) + elif MethodName == 'Load': + return self.Trans.CSpecialCallHandle._HandleCLoadLlvm(Node) + elif MethodName == 'Deref': + return self.Trans.CSpecialCallHandle._HandleCDerefLlvm(Node) + elif MethodName == 'DerefAs': + return self._HandleCDerefAsLlvm(Node) + elif MethodName == 'PtrToInt': + return self.Trans.CSpecialCallHandle._HandleCPtrToIntLlvm(Node) + elif MethodName in ('CIf', 'CElif'): + if Node.args: + ArgVal = self.HandleExprLlvm(Node.args[0]) + if ArgVal: + if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType): + return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0) + if isinstance(ArgVal.type, ir.IntType): + return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond") + if isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond") + return ir.Constant(ir.IntType(1), 0) + elif MethodName in ('CIfdef', 'CIfndef'): + return ir.Constant(ir.IntType(1), 1) + elif MethodName == 'CError': + msg = "compile-time error" + if Node.args: + arg = Node.args[0] + if isinstance(arg, ast.Constant) and isinstance(arg.value, str): + msg = arg.value + elif isinstance(arg, ast.Str): + msg = arg.s + else: + try: + val = self.HandleExprLlvm(arg) + if isinstance(val, str): + msg = val + except Exception: + pass + lineno = getattr(Node, 'lineno', 0) + raise Exception(f"#error: {msg} (line {lineno})") + elif MethodName in ('CElse', 'CEndif', 'CPragma', 'CUndef'): + return ir.Constant(ir.IntType(1), 1) + elif MethodName in ('LLVMIR', 'LInp', 'LOut'): + return None + ObjVal = self.HandleExprLlvm(Node.func.value) + if not ObjVal: + return None + if isinstance(ObjVal.type, (ir.IdentifiedStructType, ir.LiteralStructType)): + if isinstance(Node.func.value, ast.Name): + var_name = Node.func.value.id + if var_name in Gen.variables: + var_ptr = Gen.variables[var_name] + if isinstance(var_ptr.type, ir.PointerType) and isinstance(var_ptr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + ObjVal = var_ptr + else: + tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp") + Gen._store(ObjVal, tmp) + ObjVal = tmp + else: + tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp") + Gen._store(ObjVal, tmp) + ObjVal = tmp + else: + tmp = Gen._alloca_entry(ObjVal.type, name="chain_method_tmp") + Gen._store(ObjVal, tmp) + ObjVal = tmp + if isinstance(Node.func.value, ast.Name): + ModuleName = Node.func.value.id + aliases = getattr(self.Trans, '_import_aliases', {}) + imported = getattr(self.Trans, '_imported_modules', set()) + actual_module = aliases.get(ModuleName, ModuleName) + if ModuleName in imported or actual_module in imported: + mangled_name = Gen._mangle_func_name(MethodName, actual_module) + if Gen._has_function(mangled_name): + CallArgs = [] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + func = Gen._get_function(mangled_name) + self._fill_default_args(CallArgs, func, MethodName) + func_ft = getattr(func, 'function_type', None) + is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False + num_fixed_params = len(func_ft.args) if func_ft else 0 + if is_variadic: + adjusted = [] + for i, arg in enumerate(CallArgs): + if i < num_fixed_params: + param_type = func_ft.args[i] + if arg.type != param_type: + try: + if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType): + adjusted.append(self.builder.inttoptr(arg, param_type)) + elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType): + adjusted.append(Gen.builder.ptrtoint(arg, param_type)) + elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width: + adjusted.append(Gen.builder.zext(arg, param_type)) + else: + adjusted.append(arg) + except Exception: # 回退:参数类型调整失败时使用原值 + adjusted.append(arg) + else: + adjusted.append(arg) + else: + if isinstance(arg.type, ir.FloatType): + arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}") + elif isinstance(arg.type, ir.IntType) and arg.type.width < 64: + is_signed = True + arg_node = Node.args[i] if i < len(Node.args) else None + if arg_node is not None: + is_u = Gen._check_node_unsigned(arg_node) + if is_u: + is_signed = False + if is_signed: + arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{MethodName}") + else: + arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{MethodName}") + adjusted.append(arg) + result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") + else: + adjusted = Gen._adjust_args(CallArgs, func) + result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") + return result + if Gen._has_function(MethodName): + _mf = Gen._get_function(MethodName) + if '.' not in _mf.name: + CallArgs = [] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + func = _mf + self._fill_default_args(CallArgs, func, MethodName) + func_ft = getattr(func, 'function_type', None) + is_variadic = getattr(func_ft, 'var_arg', False) if func_ft else False + num_fixed_params = len(func_ft.args) if func_ft else 0 + if is_variadic: + adjusted = [] + for i, arg in enumerate(CallArgs): + if i < num_fixed_params: + param_type = func_ft.args[i] + if arg.type != param_type: + try: + if isinstance(arg.type, ir.IntType) and isinstance(param_type, ir.PointerType): + adjusted.append(self.builder.inttoptr(arg, param_type)) + elif isinstance(arg.type, ir.PointerType) and isinstance(param_type, ir.IntType): + adjusted.append(Gen.builder.ptrtoint(arg, param_type)) + elif isinstance(arg.type, ir.IntType) and arg.type.width < param_type.width: + adjusted.append(Gen.builder.zext(arg, param_type)) + else: + adjusted.append(arg) + except Exception: # 回退:参数类型调整失败时使用原值 + adjusted.append(arg) + else: + adjusted.append(arg) + else: + if isinstance(arg.type, ir.FloatType): + arg = Gen.builder.fpext(arg, ir.DoubleType(), name=f"fpext_vararg_{MethodName}") + elif isinstance(arg.type, ir.IntType) and arg.type.width < 64: + is_signed = True + arg_node = Node.args[i] if i < len(Node.args) else None + if arg_node is not None: + is_u = Gen._check_node_unsigned(arg_node) + if is_u: + is_signed = False + if is_signed: + arg = Gen.builder.sext(arg, ir.IntType(64), name=f"sext_vararg_{MethodName}") + else: + arg = Gen.builder.zext(arg, ir.IntType(64), name=f"zext_vararg_{MethodName}") + adjusted.append(arg) + result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") + else: + adjusted = Gen._adjust_args(CallArgs, func) + result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") + return result + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) + if not stub_func_type: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(MethodName, Gen) + if not stub_func_type and mangled_name != MethodName: + for sha1 in getattr(Gen, 'module_sha1_map', {}).values(): + alt_name = f"{sha1}.{MethodName}" + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(alt_name, Gen) + if stub_func_type: + mangled_name = alt_name + break + if stub_func_type: + func = ir.Function(Gen.module, stub_func_type, name=mangled_name) + Gen.functions[mangled_name] = func + CallArgs = [] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + self._fill_default_args(CallArgs, func, mangled_name) + self._append_eh_msg_out_arg(CallArgs, func, Gen) + adjusted = Gen._adjust_args(CallArgs, func) + result = Gen.builder.call(func, adjusted, name=f"call_{MethodName}") + self._check_eh_return(result, mangled_name, Gen, called_func=func) + return result + return ir.Constant(ir.IntType(32), 0) + CallArgs = [] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + ClassName = None + if isinstance(Node.func.value, ast.Name): + ClassName = Gen.var_struct_class.get(Node.func.value.id) + if not ClassName: + for CN, ST in Gen.structs.items(): + if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == ST: + ClassName = CN + break + if not ClassName and self._is_char_pointer(ObjVal): + MethodName = Node.func.attr + for CN, ST in Gen.structs.items(): + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + continue + method_key = f'{CN}.{MethodName}' + if not Gen._has_function(method_key): + continue + try: + casted = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") + ClassName = CN + ObjVal = casted + break + except Exception: # 回退:bitcast 失败时尝试下一个类 + continue + if not ClassName and isinstance(Node.func.value, ast.Call): + if isinstance(Node.func.value.func, ast.Attribute): + InnerAttrName = Node.func.value.func.attr + for CN in Gen.structs: + if CN.endswith(f'__{InnerAttrName}') or f'__{InnerAttrName}' in CN: + continue + method_name = f'{CN}__{InnerAttrName}' + if Gen._has_function(method_name): + func = Gen._get_function(method_name) + ret_type = func.fnty.return_type + if isinstance(ret_type, ir.PointerType): + for CN2, ST in Gen.structs.items(): + if ret_type.pointee == ST: + ClassName = CN2 + break + elif isinstance(ret_type, ir.IdentifiedStructType): + for CN2, ST in Gen.structs.items(): + if ret_type == ST: + ClassName = CN2 + break + if ClassName: + break + if not ClassName: + return ir.Constant(ir.IntType(32), 0) + struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) + class_sha1 = struct_sha1_map.get(ClassName) + if class_sha1: + FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}' + else: + FullMethodName = f'{ClassName}.{MethodName}' + if ClassName in Gen.class_vtable and ClassName in Gen.class_methods: + methods = Gen.class_methods[ClassName] + method_idx = -1 + for mi, mn in enumerate(methods): + if mn == FullMethodName or mn == MethodName or mn.endswith(f'.{MethodName}'): + method_idx = mi + break + if method_idx >= 0: + func = Gen._find_function(FullMethodName) + if not func: + func = Gen._find_function(f'{FullMethodName}__') + if not func: + p = Gen.class_parent.get(ClassName) + while p: + parent_full = f'{p}.{MethodName}' + func = Gen._find_function(parent_full) + if not func: + func = Gen._find_function(f'{parent_full}__') + if func: + break + p = Gen.class_parent.get(p) + if func: + VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") + VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") + VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + VtableTyped = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") + MethodPtrAddr = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_ptr_addr_{MethodName}") + MethodPtrI8 = Gen._load(MethodPtrAddr, name=f"vmethod_ptr_{MethodName}") + FuncPtrType = ir.PointerType(func.function_type) + MethodPtrTyped = Gen.builder.bitcast(MethodPtrI8, FuncPtrType, name=f"vmethod_typed_{MethodName}") + call_args = [ObjVal] + CallArgs + self._fill_default_args(call_args, func, FullMethodName) + self._append_eh_msg_out_arg(call_args, func, Gen) + adjusted = Gen._adjust_args(call_args, func) + result = Gen.builder.call(MethodPtrTyped, adjusted, name=f"vcall_{FullMethodName}") + self._check_eh_return(result, FullMethodName, Gen, called_func=func) + return result + func = Gen._find_function(FullMethodName) + if not func: + func = Gen._find_function(f'{FullMethodName}__') + if not func and class_sha1: + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(FullMethodName, Gen) + if stub_func_type: + func = ir.Function(Gen.module, stub_func_type, name=FullMethodName) + Gen.functions[FullMethodName] = func + if not func and class_sha1: + plain_name = f'{ClassName}.{MethodName}' + stub_func_type = self.Trans.ImportHandler._LookupStubFuncType(plain_name, Gen) + if stub_func_type: + func = ir.Function(Gen.module, stub_func_type, name=FullMethodName) + Gen.functions[FullMethodName] = func + if func: + call_args = [ObjVal] + CallArgs + self._fill_default_args(call_args, func, FullMethodName) + self._append_eh_msg_out_arg(call_args, func, Gen) + adjusted = Gen._adjust_args(call_args, func) + result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}") + self._check_eh_return(result, FullMethodName, Gen, called_func=func) + return result + i8ptr = ir.PointerType(ir.IntType(8)) + member_idx = -1 + if ClassName in Gen.class_members: + for mi, (mn, mt) in enumerate(Gen.class_members[ClassName]): + if mn == MethodName: + member_idx = mi + break + if member_idx >= 0 and isinstance(ObjVal.type, ir.PointerType): + has_vtable = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes + base = 1 if has_vtable else 0 + member_ptr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + member_idx)], name=f"funcptr_{MethodName}_ptr") + raw_ptr = Gen._load(member_ptr, name=f"funcptr_{MethodName}_raw") + func_ptr_type = ir.PointerType(ir.FunctionType(ir.IntType(32), [i8ptr] + [a.type for a in CallArgs])) + typed_ptr = Gen.builder.bitcast(raw_ptr, func_ptr_type, name=f"funcptr_{MethodName}_typed") + obj_as_i8 = Gen.builder.bitcast(ObjVal, i8ptr, name=f"funcptr_self_{ClassName}") + call_args = [obj_as_i8] + CallArgs + result = Gen.builder.call(typed_ptr, call_args, name=f"call_funcptr_{ClassName}.{MethodName}") + return result + if class_sha1 and ClassName in Gen.structs: + struct_type = Gen.structs[ClassName] + self_ptr_type = ir.PointerType(struct_type) + param_types = [self_ptr_type] + [a.type for a in CallArgs] + func_type = ir.FunctionType(ir.IntType(32), param_types) + func = ir.Function(Gen.module, func_type, name=FullMethodName) + Gen.functions[FullMethodName] = func + if isinstance(ObjVal.type, ir.PointerType) and ObjVal.type.pointee == struct_type: + call_self = ObjVal + else: + call_self = Gen.builder.bitcast(ObjVal, self_ptr_type, name=f"method_self_{ClassName}") + adjusted = Gen._adjust_args([call_self] + CallArgs, func) + result = Gen.builder.call(func, adjusted, name=f"call_{FullMethodName}") + return result + raise Exception(f"Undefined method '{MethodName}' in class '{ClassName}' (no function declaration found for '{FullMethodName}')") + + def _HandlePrintLlvm(self, Node): + Gen = self.Trans.LlvmGen + printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + args = Node.args + end_arg = None + sep_arg = None + if Node.keywords: + for kw in Node.keywords: + if kw.arg == 'end': + end_arg = kw.value + elif kw.arg == 'sep': + sep_arg = kw.value + sep_str = ' ' + if sep_arg and isinstance(sep_arg, ast.Constant) and isinstance(sep_arg.value, str): + sep_str = sep_arg.value + end_str = '\n' + if end_arg: + if isinstance(end_arg, ast.Constant) and isinstance(end_arg.value, str): + end_str = end_arg.value + elif isinstance(end_arg, ast.Constant) and end_arg.value is None: + end_str = '' + if not args: + if end_str: + nl_fmt = Gen.emit_constant(end_str, 'string') + Gen.builder.call(printf_func, [nl_fmt], name="print_nl") + return + has_fstring = any(isinstance(arg, ast.JoinedStr) for arg in args) + if has_fstring: + self._HandlePrintWithFString(Node, printf_func, args, sep_str, end_str) + return + fmt_parts = [] + fmt_args = [] + for i, arg in enumerate(args): + if i > 0: + fmt_parts.append(sep_str) + val = self.HandleExprLlvm(arg) + if not val: + fmt_parts.append('(null)') + continue + if isinstance(val, ir.Constant) and isinstance(val.type, ir.PointerType) and val.constant is None: + fmt_parts.append('nil') + continue + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if self._is_char_pointer(val): + fmt_parts.append('%s') + fmt_args.append(val) + elif isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8: + elem_ptr = Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="print_arr_to_ptr") + fmt_parts.append('%s') + fmt_args.append(elem_ptr) + elif isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen) + if not ClassName and isinstance(arg, ast.Name): + ClassName = Gen.var_struct_class.get(arg.id) + if ClassName and Gen._has_function(f'{ClassName}.__str__'): + if self._is_char_pointer(val): + if ClassName in Gen.structs: + val = Gen.builder.bitcast(val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [val], name=f"call_{ClassName}.__str__") + fmt_parts.append('%s') + fmt_args.append(str_val) + else: + int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int") + fmt_parts.append('0x%llx') + fmt_args.append(int_val) + else: + int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="print_ptr_to_int") + fmt_parts.append('%lld') + fmt_args.append(int_val) + elif isinstance(val.type, ir.IntType): + is_unsigned = self._is_val_unsigned(arg, val) + if val.type.width == 1: + fmt_parts.append('%d') + val = Gen.builder.zext(val, ir.IntType(32), name="zext_bool_print") + elif val.type.width == 8: + if self._is_char_type(arg): + char_var = Gen._alloca_entry(ir.IntType(8), name="print_char_buf") + Gen.builder.store(val, char_var) + fmt_parts.append('%c') + fmt_args.append(char_var) + continue + fmt_parts.append('%d') + if is_unsigned: + val = Gen.builder.zext(val, ir.IntType(32), name="zext_i8_print") + else: + val = Gen.builder.sext(val, ir.IntType(32), name="sext_i8_print") + elif val.type.width == 16: + fmt_parts.append('%u' if is_unsigned else '%d') + if is_unsigned: + val = Gen.builder.zext(val, ir.IntType(32), name="zext_i16_print") + else: + val = Gen.builder.sext(val, ir.IntType(32), name="sext_i16_print") + elif val.type.width == 32: + fmt_parts.append('%u' if is_unsigned else '%d') + elif val.type.width == 64: + fmt_parts.append('%llu' if is_unsigned else '%lld') + else: + fmt_parts.append('%d') + val = Gen.builder.zext(val, ir.IntType(32), name="zext_int_print") + fmt_args.append(val) + elif isinstance(val.type, ir.FloatType): + fmt_parts.append('%f') + fmt_args.append(Gen.builder.fpext(val, ir.DoubleType(), name="fpext_printf_float")) + elif isinstance(val.type, ir.DoubleType): + fmt_parts.append('%f') + fmt_args.append(val) + else: + fmt_parts.append('(unknown)') + fmt_parts.append(end_str) + fmt_str = ''.join(fmt_parts) + fmt_bytes = fmt_str.encode('utf-8') + b'\x00' + fmt_type = ir.ArrayType(ir.IntType(8), len(fmt_bytes)) + fmt_const = ir.Constant(fmt_type, bytearray(fmt_bytes)) + fmt_gvar = ir.GlobalVariable(Gen.module, fmt_type, name=f"str_const_{Gen.string_const_counter}") + Gen.string_const_counter += 1 + fmt_gvar.initializer = fmt_const + fmt_gvar.linkage = 'internal' + fmt_ptr = Gen.builder.bitcast(fmt_gvar, ir.PointerType(ir.IntType(8)), name="print_fmt") + call_args = [fmt_ptr] + fmt_args + Gen.builder.call(printf_func, call_args, name="print_call") + + def _HandlePrintWithFString(self, Node, printf_func, args, sep_str, end_str): + Gen = self.Trans.LlvmGen + for i, arg in enumerate(args): + if i > 0: + sep_const = Gen.emit_constant(sep_str, 'string') + Gen.builder.call(printf_func, [sep_const], name="print_sep") + if isinstance(arg, ast.JoinedStr): + self.HandleExprLlvm(arg) + else: + ClassName = self.Trans.ExprHandler._get_var_class(arg, Gen) + if not ClassName and isinstance(arg, ast.Name): + ClassName = Gen.var_struct_class.get(arg.id) + if ClassName and Gen._has_function(f'{ClassName}.__str__'): + obj_val = self.HandleExprLlvm(arg) + if obj_val: + if self._is_char_pointer(obj_val): + if ClassName in Gen.structs: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [obj_val], name=f"call_{ClassName}.__str__") + Gen._register_temp_ptr(str_val) + Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) + elif isinstance(arg, ast.Name) and arg.id in Gen.var_struct_class: + ClassName = Gen.var_struct_class[arg.id] + obj_val = self.HandleExprLlvm(arg) + if obj_val and ClassName in Gen.structs: + str_func = Gen._find_function(f'{ClassName}.__str__') + if str_func: + if isinstance(obj_val.type, ir.PointerType) and not isinstance(obj_val.type.pointee, type(Gen.structs[ClassName])): + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + str_val = Gen.builder.call(str_func, [obj_val], name=f"call_{ClassName}.__str__") + Gen._register_temp_ptr(str_val) + Gen._emit_printf([str_val], unsigned_flags=[False], sep=None, end=None) + else: + val = self.HandleExprLlvm(arg) + self._print_value(val=val, arg=arg, Gen=Gen, fmt_parts=fmt_parts, fmt_args=fmt_args) + else: + val = self.HandleExprLlvm(arg) + self._print_value(val=val, arg=arg, Gen=Gen, fmt_parts=fmt_parts, fmt_args=fmt_args) + else: + val = self.HandleExprLlvm(arg) + if val: + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if not self._is_char_pointer(val): + try: + val = Gen._load(val, name="print_load") + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + is_u = Gen._check_node_unsigned(arg) + if not is_u and id(val) in Gen._unsigned_results: + is_u = True + Gen._emit_printf([val], unsigned_flags=[is_u], sep=None, end=None) + if end_str: + end_const = Gen.emit_constant(end_str, 'string') + Gen.builder.call(printf_func, [end_const], name="print_end") + + def _is_char_type(self, arg_node): + if isinstance(arg_node, ast.Call): + if isinstance(arg_node.func, ast.Name): + return arg_node.func.id in ('CChar', 'CUInt8T', 'CInt8T') + if isinstance(arg_node.func, ast.Attribute): + return arg_node.func.attr in ('CChar', 'CUInt8T', 'CInt8T') + return False + + def _is_val_unsigned(self, arg_node, val): + Gen = self.Trans.LlvmGen + if isinstance(arg_node, ast.Name): + var_name = arg_node.id + signedness = Gen.var_signedness.get(var_name) + if signedness: + if isinstance(signedness, bool): + return signedness + return 'unsigned' in signedness + if isinstance(val.type, ir.IntType): + return False + return False + + _C_LIB_FUNCS = { + 'malloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.IntType(64)]), + 'calloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)]), + 'realloc': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'free': lambda: (ir.VoidType(), [ir.PointerType(ir.IntType(8))]), + 'strlen': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), + 'strlength': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), + 'memset': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)]), + 'memcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'memmove': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'memcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'strcmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), + 'strncmp': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'strcpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), + 'strncpy': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64)]), + 'strcat': lambda: (ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))]), + 'puts': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), + 'atoi': lambda: (ir.IntType(32), [ir.PointerType(ir.IntType(8))]), + 'atol': lambda: (ir.IntType(64), [ir.PointerType(ir.IntType(8))]), + 'abs': lambda: (ir.IntType(32), [ir.IntType(32)]), + 'labs': lambda: (ir.IntType(64), [ir.IntType(64)]), + } + + def _try_declare_c_lib_func(self, func_name, Gen): + if func_name not in self._C_LIB_FUNCS: + return None + ret_type, param_types = self._C_LIB_FUNCS[func_name]() + func_type = ir.FunctionType(ret_type, param_types) + func = ir.Function(Gen.module, func_type, name=func_name) + Gen.functions[func_name] = func + return func + + def _HandleLenLlvm(self, arg_node): + Gen = self.Trans.LlvmGen + if isinstance(arg_node, ast.Attribute) and isinstance(arg_node.value, ast.Name) and arg_node.value.id == 'self': + attr_name = arg_node.attr + len_member = f'{attr_name}__len' + current_class = self.Trans._CurrentCpythonObjectClass + if current_class and current_class in Gen.class_members: + for m_name, m_type in Gen.class_members[current_class]: + if m_name == len_member: + self_val = Gen._get_var_ptr('self') + if self_val: + self_ptr = Gen._load(self_val, name="self_for_len") + offset = Gen._get_member_offset(len_member, current_class) + len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr") + return Gen._load(len_ptr, name=f"self_{len_member}") + val = self.HandleExprLlvm(arg_node) + if not val: + return None + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, ir.PointerType): + val = Gen._load(val, name="len_deref") + pointee = val.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + result = self.Trans.ExprUtils._try_operator_overload(CN, '__len__', val, Gen) + if result is not None: + return result + break + if isinstance(pointee, ir.ArrayType): + return ir.Constant(ir.IntType(64), pointee.count) + if isinstance(pointee, (ir.FloatType, ir.DoubleType, ir.IntType)) and pointee.width != 8: + return ir.Constant(ir.IntType(64), 0) + if val.type != ir.PointerType(ir.IntType(8)): + val = Gen.builder.bitcast(val, ir.PointerType(ir.IntType(8)), name="str_ptr_cast") + correct_strlen_type = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))]) + strlen_func = None + if 'strlen' in Gen.functions: + existing = Gen.functions['strlen'] + if existing.ftype == correct_strlen_type: + strlen_func = existing + if not strlen_func: + try: + strlen_func = ir.Function(Gen.module, correct_strlen_type, name='strlen') + Gen.functions['strlen'] = strlen_func + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + if strlen_func: + result = Gen.builder.call(strlen_func, [val], name="strlen_call") + return result + elif isinstance(val.type, ir.ArrayType): + return ir.Constant(ir.IntType(64), val.type.count) + return ir.Constant(ir.IntType(64), 0) + + def _HandleSizeofLlvm(self, Node): + Gen = self.Trans.LlvmGen + if isinstance(Node, ast.Name): + type_name = Node.id + elif isinstance(Node, ast.Attribute): + type_name = Node.attr + else: + return ir.Constant(ir.IntType(64), 0) + + if type_name not in Gen.structs: + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(type_name) + if ctype_cls is not None: + try: + ctype_inst = ctype_cls() + size_bits = getattr(ctype_inst, 'Size', 0) or 0 + size_bytes = size_bits // 8 + return ir.Constant(ir.IntType(64), size_bytes) + except Exception: + pass + resolved = CTypeRegistry.ResolveName(type_name) + if resolved: + ctype_cls, ptr_level = resolved + try: + ctype_inst = ctype_cls() + size_bits = getattr(ctype_inst, 'Size', 0) or 0 + size_bytes = size_bits // 8 + if ptr_level > 0: + size_bytes = 8 + return ir.Constant(ir.IntType(64), size_bytes) + except Exception: + pass + return ir.Constant(ir.IntType(64), 0) + + struct_type = Gen.structs[type_name] + if isinstance(struct_type, ir.PointerType): + struct_type = struct_type.pointee + if isinstance(struct_type, ir.IdentifiedStructType) and (struct_type.elements is None or len(struct_type.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(type_name, Gen) + struct_type = Gen.structs.get(type_name, struct_type) + size = Gen._get_struct_size(struct_type) + if size > 0: + return ir.Constant(ir.IntType(64), size) + return ir.Constant(ir.IntType(64), 0) + + def _HandleAbsLlvm(self, arg_node): + Gen = self.Trans.LlvmGen + val = self.HandleExprLlvm(arg_node) + if not val: + return None + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + result = self.Trans.ExprUtils._try_operator_overload(CN, '__abs__', val, Gen) + if result is not None: + return result + break + if isinstance(val.type, ir.IntType): + neg_val = Gen.builder.neg(val, name="abs_neg") + is_neg = Gen.builder.icmp_signed('<', val, ir.Constant(val.type, 0), name="is_neg") + return Gen.builder.select(is_neg, neg_val, val, name="abs_result") + elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): + zero = ir.Constant(val.type, 0.0) + neg_val = Gen.builder.fneg(val, name="fabs_neg") + is_neg = Gen.builder.fcmp_ordered('<', val, zero, name="f_is_neg") + return Gen.builder.select(is_neg, neg_val, val, name="fabs_result") + return None + + def _HandleDirLlvm(self, Node): + Gen = self.Trans.LlvmGen + return ir.Constant(ir.IntType(8).as_pointer(), None) + + def _HandleTypeLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + type_str = "" + else: + arg = Node.args[0] + enum_type_name = None + + def _get_attr_path(node): + if isinstance(node, ast.Name): + return node.id + elif isinstance(node, ast.Attribute): + return f"{_get_attr_path(node.value)}.{node.attr}" + return None + + if isinstance(arg, ast.Name): + arg_name = arg.id + Gen = self.Trans.LlvmGen + if arg_name in Gen.var_type_info: + type_info = Gen.var_type_info[arg_name] + if isinstance(type_info, dict) and type_info.get('type') == 'enum': + enum_type_name = type_info.get('name') + if not enum_type_name and arg_name in self.Trans.SymbolTable: + TypeInfo = self.Trans.SymbolTable[arg_name] + if TypeInfo.IsEnum: + enum_type_name = arg_name + elif isinstance(arg, ast.Attribute): + last_part = None + enum_class_name = None + if isinstance(arg.value, ast.Name): + last_part = arg.attr + if last_part in self.Trans.SymbolTable: + AttrInfo = self.Trans.SymbolTable[last_part] + if AttrInfo.IsEnumMember and AttrInfo.EnumName: + enum_type_name = AttrInfo.EnumName + elif isinstance(arg.value, ast.Attribute): + attr_path = _get_attr_path(arg) + if attr_path: + parts = attr_path.split('.') + if len(parts) >= 2: + enum_class_name = parts[-2] + last_part = parts[-1] + qualified_name_dot = f"{enum_class_name}.{last_part}" + qualified_name_under = f"{enum_class_name}_{last_part}" + enum_member_found = None + for qname in (qualified_name_dot, qualified_name_under): + if qname in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[qname] + if info.IsEnumMember and info.EnumName == enum_class_name: + enum_member_found = info + break + if not enum_member_found: + for key in self.Trans.SymbolTable: + if key == last_part: + info = self.Trans.SymbolTable[key] + if info.IsEnumMember and info.EnumName == enum_class_name: + enum_member_found = info + break + if enum_member_found: + enum_type_name = enum_class_name + if enum_type_name: + type_str = f"" + else: + llvm_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(arg) + if isinstance(llvm_type, ir.PointerType): + pointee = llvm_type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + llvm_type = pointee + type_info = self.Trans.ExprUtils._llvm_type_to_detailed_string(llvm_type) + type_str = f"" + return Gen.emit_constant(type_str, 'string') + + def _HandleInputLlvm(self, Node): + Gen = self.Trans.LlvmGen + if Node.args and isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, str): + prompt = Node.args[0].value + prompt_ptr = Gen.emit_constant(prompt, 'string') + printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + Gen.builder.call(printf_func, [prompt_ptr]) + scanf_func = Gen.get_or_declare_c_func('scanf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + input_buffer = Gen._alloca(ir.ArrayType(ir.IntType(8), 256), name="input_buffer") + result = Gen.builder.call(scanf_func, [Gen.emit_constant("%255s", 'string'), input_buffer]) + return Gen.builder.gep(input_buffer, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="input_result") + + def _HandleAtoiLlvm(self, str_ptr): + Gen = self.Trans.LlvmGen + atoi_func = Gen.get_or_declare_c_func('atoi', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))])) + return Gen.builder.call(atoi_func, [str_ptr], name="atoi_result") + + def _HandleOrdLlvm(self, expr_node): + Gen = self.Trans.LlvmGen + val = self.HandleExprLlvm(expr_node) + if val and self._is_char_pointer(val): + return Gen._load(val, name="ord_result") + return ir.Constant(ir.IntType(32), 0) + + def _HandleChrLlvm(self, expr_node): + Gen = self.Trans.LlvmGen + val = self.HandleExprLlvm(expr_node) + if val: + char_ptr = Gen._alloca(ir.IntType(8), name="chr_char") + Gen.builder.store(Gen.builder.trunc(val, ir.IntType(8), name="trunc_chr"), char_ptr) + return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result") + return ir.Constant(ir.IntType(8).as_pointer(), None) + + def _EmitStringFromValue(self, val): + Gen = self.Trans.LlvmGen + if isinstance(val.type, ir.IntType): + buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32)) + snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [ + ir.PointerType(ir.IntType(8)), + ir.IntType(32), + ir.PointerType(ir.IntType(8)) + ])) + fmt_ptr = Gen.emit_constant("%d", 'string') + Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(32), 32), fmt_ptr, val]) + return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") + return ir.Constant(ir.IntType(8).as_pointer(), None) + + def _HandleMallocLlvm(self, args): + Gen = self.Trans.LlvmGen + malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) + malloc_func = Gen._get_or_declare_func('malloc', malloc_type) + param_type = malloc_func.type.pointee.args[0] + size_val = None + if args: + size_val = self.HandleExprLlvm(args[0]) + if size_val and isinstance(size_val.type, ir.IntType): + if isinstance(param_type, ir.IntType) and size_val.type.width != param_type.width: + if size_val.type.width < param_type.width: + size_val = Gen.builder.zext(size_val, param_type, name="zext_malloc_size") + else: + size_val = Gen.builder.trunc(size_val, param_type, name="trunc_malloc_size") + if not size_val: + size_val = ir.Constant(param_type, 1) + result = Gen.builder.call(malloc_func, [size_val], name="malloc_result") + return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="malloc_cast") + + def _HandleReallocLlvm(self, args): + Gen = self.Trans.LlvmGen + realloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(64)]) + realloc_func = Gen._get_or_declare_func('realloc', realloc_type) + size_param_type = realloc_func.type.pointee.args[1] + ptr_val = None + size_val = None + if len(args) >= 2: + ptr_val = self.HandleExprLlvm(args[0]) + size_val = self.HandleExprLlvm(args[1]) + elif len(args) == 1: + size_val = self.HandleExprLlvm(args[0]) + if not ptr_val: + ptr_val = ir.Constant(ir.PointerType(ir.IntType(8)), None) + if isinstance(ptr_val.type, ir.PointerType) and not self._is_char_pointer(ptr_val): + ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="realloc_cast_ptr") + if size_val and isinstance(size_val.type, ir.IntType): + if isinstance(size_param_type, ir.IntType) and size_val.type.width != size_param_type.width: + if size_val.type.width < size_param_type.width: + size_val = Gen.builder.zext(size_val, size_param_type, name="zext_realloc_size") + else: + size_val = Gen.builder.trunc(size_val, size_param_type, name="trunc_realloc_size") + if not size_val: + size_val = ir.Constant(size_param_type, 0) + result = Gen.builder.call(realloc_func, [ptr_val, size_val], name="realloc_result") + return Gen.builder.bitcast(result, ir.IntType(8).as_pointer(), name="realloc_cast") + + def _HandleFreeLlvm(self, args): + Gen = self.Trans.LlvmGen + free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) + free_func = Gen._get_or_declare_func('free', free_type) + if args: + var_name = None + if isinstance(args[0], ast.Name): + var_name = args[0].id + ptr_val = self.HandleExprLlvm(args[0]) + if ptr_val: + if var_name and hasattr(Gen, '_var_to_heap_ptr') and var_name in Gen._var_to_heap_ptr: + registered_val = Gen._var_to_heap_ptr[var_name] + Gen._unregister_local_heap_ptr(registered_val) + del Gen._var_to_heap_ptr[var_name] + if isinstance(ptr_val.type, ir.PointerType) and not self._is_char_pointer(ptr_val): + ptr_val = Gen.builder.bitcast(ptr_val, ir.PointerType(ir.IntType(8)), name="free_cast_ptr") + Gen.builder.call(free_func, [ptr_val], name="free_call") + return ir.Constant(ir.IntType(32), 0) + + def _HandleMemcpyLlvm(self, args): + Gen = self.Trans.LlvmGen + if 'llvm.memcpy' not in Gen.functions: + memcpy_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) + Gen.functions['llvm.memcpy'] = ir.Function(Gen.module, memcpy_type, name='llvm.memcpy') + if len(args) >= 3: + dst = self.HandleExprLlvm(args[0]) + src = self.HandleExprLlvm(args[1]) + size = self.HandleExprLlvm(args[2]) + if dst and src and size: + i8ptr = ir.PointerType(ir.IntType(8)) + if isinstance(dst.type, ir.PointerType) and dst.type != i8ptr: + dst = Gen.builder.bitcast(dst, i8ptr, name="memcpy_dst_cast") + elif isinstance(dst.type, ir.IntType): + if dst.type.width < 64: + dst = Gen.builder.zext(dst, ir.IntType(64), name="zext_dst_ptr") + dst = Gen.builder.inttoptr(dst, i8ptr, name="dst_int2ptr") + if isinstance(src.type, ir.PointerType) and src.type != i8ptr: + src = Gen.builder.bitcast(src, i8ptr, name="memcpy_src_cast") + elif isinstance(src.type, ir.IntType): + if src.type.width < 64: + src = Gen.builder.zext(src, ir.IntType(64), name="zext_src_ptr") + src = Gen.builder.inttoptr(src, i8ptr, name="src_int2ptr") + if isinstance(size.type, ir.IntType) and size.type.width < 64: + size = Gen.builder.zext(size, ir.IntType(64), name="zext_memcpy_size") + isvolatile = ir.Constant(ir.IntType(1), 0) + Gen.builder.call(Gen.functions['llvm.memcpy'], [dst, src, size, isvolatile], name="memcpy_call") + return None + + def _HandleMemsetLlvm(self, args): + Gen = self.Trans.LlvmGen + memset_func = Gen.get_or_declare_c_func('memset', ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8)), ir.IntType(32), ir.IntType(64)])) + if len(args) >= 3: + dst = self.HandleExprLlvm(args[0]) + val = self.HandleExprLlvm(args[1]) + size = self.HandleExprLlvm(args[2]) + if dst and val is not None and size: + if isinstance(dst.type, ir.PointerType) and not self._is_char_pointer(dst): + dst = Gen.builder.bitcast(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_cast") + if isinstance(val.type, ir.IntType) and val.type.width != 32: + if val.type.width < 32: + val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val") + else: + val = Gen.builder.trunc(val, ir.IntType(32), name="trunc_memset_val") + if isinstance(size.type, ir.IntType) and size.type.width < 64: + size = Gen.builder.zext(size, ir.IntType(64), name="zext_memset_size") + elif isinstance(size.type, ir.IntType) and size.type.width > 64: + size = Gen.builder.trunc(size, ir.IntType(64), name="trunc_memset_size") + Gen.builder.call(memset_func, [dst, val, size], name="memset_call") + return None + + def _HandleVaStartLlvm(self, args): + Gen = self.Trans.LlvmGen + return None + + def _HandleVaEndLlvm(self, args): + Gen = self.Trans.LlvmGen + return None + + def _HandleArgLlvm(self, args, CallNode=None): + Gen = self.Trans.LlvmGen + va_list_ptr = None + variadic_info = getattr(Gen, '_va_arg_info', None) + if not variadic_info: + variadic_info = getattr(Gen, '_variadic_info', None) + if variadic_info: + va_list_ptr = variadic_info.get('va_list_ptr') + if not va_list_ptr: + vararg_name = variadic_info.get('vararg_name', 'args') if variadic_info else 'args' + if vararg_name in Gen.variables: + va_list_ptr = Gen.variables[vararg_name] + if not va_list_ptr: + return ir.Constant(ir.IntType(32), 0) + target_type = ir.IntType(32) + if args: + type_arg = args[0] + if isinstance(type_arg, ast.Name): + type_name = type_arg.id + from lib.includes.t import CTypeRegistry + if type_name in ('str', 'bytes'): + target_type = ir.PointerType(ir.IntType(8)) + elif type_name == 'CPtr': + target_type = ir.PointerType(ir.IntType(8)) + elif type_name in Gen.structs: + target_type = ir.PointerType(Gen.structs[type_name]) + else: + ctype_cls = CTypeRegistry.GetClassByName(type_name) + if ctype_cls is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + resolved = Gen._type_str_to_llvm(llvm_str) + if resolved: + target_type = resolved + else: + resolved = CTypeRegistry.ResolveName(type_name) + if resolved is not None: + ctype_cls, ptr_level = resolved + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str: + base = Gen._type_str_to_llvm(llvm_str) + if base is not None: + for _ in range(ptr_level): + if isinstance(base, ir.VoidType): + base = ir.IntType(8).as_pointer() + else: + base = ir.PointerType(base) + target_type = base + elif isinstance(type_arg, ast.Attribute): + if isinstance(type_arg.value, ast.Name) and type_arg.value.id == 't': + attr_name = type_arg.attr + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(attr_name) + if ctype_cls is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + resolved = Gen._type_str_to_llvm(llvm_str) + if resolved: + target_type = resolved + else: + assign_node = getattr(self.Trans, '_current_assign_node', None) + if assign_node: + ann = getattr(assign_node, 'annotation', None) + if ann: + ann_name = None + if isinstance(ann, ast.Name): + ann_name = ann.id + elif isinstance(ann, ast.Attribute): + ann_name = ann.attr + elif isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): + left = ann.left + if isinstance(left, ast.Name): + ann_name = left.id + elif isinstance(left, ast.Attribute): + ann_name = left.attr + if ann_name: + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(ann_name) + if ctype_cls is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + resolved = Gen._type_str_to_llvm(llvm_str) + if resolved: + target_type = resolved + elif ann_name in Gen.structs: + target_type = ir.PointerType(Gen.structs[ann_name]) + va_arg_counter = getattr(Gen, '_va_arg_counter', 0) + Gen._va_arg_counter = va_arg_counter + 1 + result = Gen.emit_va_arg(va_list_ptr, target_type) + if result is not None and getattr(result, 'name', ''): + result.name = f"va_arg_result_{Gen._va_arg_counter}" + return result + + def _HandleVaArgLlvm(self, args): + Gen = self.Trans.LlvmGen + return ir.Constant(ir.IntType(32), 0) + + def _HandleCDerefAsLlvm(self, Node): + Gen = self.Trans.LlvmGen + if len(Node.args) < 2: + return ir.Constant(ir.IntType(32), 0) + ptr_val = self.HandleExprLlvm(Node.args[0]) + val_val = self.HandleExprLlvm(Node.args[1]) + if ptr_val is None or val_val is None: + return ir.Constant(ir.IntType(32), 0) + if isinstance(ptr_val.type, ir.PointerType): + store_val = val_val + if isinstance(val_val.type, ir.PointerType): + void_pp = ir.PointerType(ir.PointerType(ir.IntType(8))) + if ptr_val.type != void_pp: + ptr_val = Gen.builder.bitcast(ptr_val, void_pp, name="deref_as_pp") + if val_val.type.pointee != ir.IntType(8): + store_val = Gen.builder.bitcast(val_val, ir.PointerType(ir.IntType(8)), name="deref_as_vp") + elif isinstance(val_val.type, ir.IntType) and isinstance(ptr_val.type.pointee, ir.IntType): + if val_val.type.width != ptr_val.type.pointee.width: + if ptr_val.type.pointee.width == 8 and val_val.type.width > 8: + target_ptr_type = ir.PointerType(val_val.type) + ptr_val = Gen.builder.bitcast(ptr_val, target_ptr_type, name="deref_as_cast") + elif val_val.type.width < ptr_val.type.pointee.width: + store_val = Gen.builder.zext(val_val, ptr_val.type.pointee, name="deref_as_zext") + else: + store_val = Gen.builder.trunc(val_val, ptr_val.type.pointee, name="deref_as_trunc") + elif isinstance(val_val.type, ir.IntType) and isinstance(ptr_val.type.pointee, ir.PointerType): + if val_val.type.width == 64: + store_val = Gen.builder.inttoptr(val_val, ptr_val.type.pointee, name="deref_as_inttoptr") + else: + ext = Gen.builder.zext(val_val, ir.IntType(64), name="deref_as_zext") + store_val = Gen.builder.inttoptr(ext, ptr_val.type.pointee, name="deref_as_inttoptr") + elif val_val.type != ptr_val.type.pointee: + target_ptr_type = ir.PointerType(val_val.type) + ptr_val = Gen.builder.bitcast(ptr_val, target_ptr_type, name="deref_as_cast") + Gen.builder.store(store_val, ptr_val) + return ir.Constant(ir.IntType(32), 0) + + def _HandleClassNewLlvm(self, Node, ClassName): + Gen = self.Trans.LlvmGen + if hasattr(self.Trans.ClassHandler, '_generic_class_templates') and ClassName in self.Trans.ClassHandler._generic_class_templates: + return self._HandleGenericClassNewLlvm(Node, ClassName) + NewFuncName = f'{ClassName}.__before_init__' + InitFuncName = f'{ClassName}.__init__' + NewMethodFuncName = f'{ClassName}.__new__' + has_new_method = Gen._find_function(NewMethodFuncName) is not None + if Gen._has_function(NewFuncName): + NewFunc = Gen._get_function(NewFuncName) + StructType = Gen.structs.get(ClassName) + if StructType: + result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca") + else: + return ir.Constant(ir.IntType(32), 0) + Gen.builder.call(NewFunc, [result], name=f"before_init_{ClassName}") + if has_new_method: + NewMethodFunc = Gen._find_function(NewMethodFuncName) + if NewMethodFunc: + NewMethodArgs = [result] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + NewMethodArgs.append(ArgVal) + for kw in Node.keywords: + ArgVal = self.HandleExprLlvm(kw.value) + if ArgVal: + NewMethodArgs.append(ArgVal) + self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName) + adjusted_new = Gen._adjust_args(NewMethodArgs, NewMethodFunc) + heap_ptr = Gen.builder.call(NewMethodFunc, adjusted_new, name=f"new_{ClassName}") + if heap_ptr: + target_ptr_type = ir.PointerType(StructType) if StructType else None + if isinstance(heap_ptr.type, ir.PointerType): + # Bitcast the returned pointer to the struct pointer type if needed + if target_ptr_type and heap_ptr.type != target_ptr_type: + result = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{ClassName}_cast") + else: + result = heap_ptr + elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type: + # __new__ returned an integer (pointer as int), convert back to pointer + if heap_ptr.type.width < 64: + i64_val = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{ClassName}_i64") + result = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{ClassName}_ptr") + else: + result = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{ClassName}_ptr") + if Gen._has_function(InitFuncName): + InitFunc = Gen._get_function(InitFuncName) + InitArgs = [result] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + InitArgs.append(ArgVal) + for kw in Node.keywords: + ArgVal = self.HandleExprLlvm(kw.value) + if ArgVal: + InitArgs.append(ArgVal) + self._fill_default_args(InitArgs, InitFunc, InitFuncName) + self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen) + adjusted_init = Gen._adjust_args(InitArgs, InitFunc) + Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}") + return result + if ClassName in Gen.structs: + StructType = Gen.structs[ClassName] + if isinstance(StructType, ir.PointerType): + StructType = StructType.pointee + is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0) + if is_opaque: + self._ensure_struct_declared(ClassName) + StructType = Gen.structs.get(ClassName, StructType) + if isinstance(StructType, ir.PointerType): + StructType = StructType.pointee + is_opaque = isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0) + if is_opaque: + result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca") + Gen.builder.store(ir.Constant(StructType, None), result) + InitFunc = Gen.functions.get(InitFuncName) + if not InitFunc: + g = Gen.module.globals.get(InitFuncName) + if g and isinstance(g, ir.Function): + Gen.functions[InitFuncName] = g + InitFunc = g + if InitFunc: + InitArgs = [result] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + InitArgs.append(ArgVal) + for kw in Node.keywords: + ArgVal = self.HandleExprLlvm(kw.value) + if ArgVal: + InitArgs.append(ArgVal) + self._fill_default_args(InitArgs, InitFunc, InitFuncName) + self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen) + adjusted_init = Gen._adjust_args(InitArgs, InitFunc) + Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}") + return result + result = Gen._alloca_entry(StructType, name=f"{ClassName}_alloca") + # Call __new__ method if it exists (may replace self with heap pointer) + if has_new_method: + NewMethodFunc = Gen._find_function(NewMethodFuncName) + if NewMethodFunc: + NewMethodArgs = [result] + for arg in Node.args: + ArgVal = self.HandleExprLlvm(arg) + if ArgVal: + NewMethodArgs.append(ArgVal) + for kw in Node.keywords: + ArgVal = self.HandleExprLlvm(kw.value) + if ArgVal: + NewMethodArgs.append(ArgVal) + self._fill_default_args(NewMethodArgs, NewMethodFunc, NewMethodFuncName) + adjusted_new = Gen._adjust_args(NewMethodArgs, NewMethodFunc) + heap_ptr = Gen.builder.call(NewMethodFunc, adjusted_new, name=f"new_{ClassName}") + if heap_ptr: + target_ptr_type = ir.PointerType(StructType) if StructType else None + if isinstance(heap_ptr.type, ir.PointerType): + # Bitcast the returned pointer to the struct pointer type if needed + if target_ptr_type and heap_ptr.type != target_ptr_type: + result = Gen.builder.bitcast(heap_ptr, target_ptr_type, name=f"new_{ClassName}_cast") + else: + result = heap_ptr + elif isinstance(heap_ptr.type, ir.IntType) and target_ptr_type: + # __new__ returned an integer (pointer as int), convert back to pointer + if heap_ptr.type.width < 64: + i64_val = Gen.builder.zext(heap_ptr, ir.IntType(64), name=f"new_{ClassName}_i64") + result = Gen.builder.inttoptr(i64_val, target_ptr_type, name=f"new_{ClassName}_ptr") + else: + result = Gen.builder.inttoptr(heap_ptr, target_ptr_type, name=f"new_{ClassName}_ptr") + InitFunc = Gen.functions.get(InitFuncName) + if not InitFunc: + g = Gen.module.globals.get(InitFuncName) + if g and isinstance(g, ir.Function): + Gen.functions[InitFuncName] = g + InitFunc = g + if InitFunc: + InitArgs = [result] + init_param_types = InitFunc.function_type.args if hasattr(InitFunc, 'function_type') else [] + for i, arg in enumerate(Node.args): + arg_var_type = init_param_types[i + 1] if i + 1 < len(init_param_types) else None + ArgVal = self.HandleExprLlvm(arg, VarType=arg_var_type) + if ArgVal: + InitArgs.append(ArgVal) + for kw in Node.keywords: + kw_idx = None + if hasattr(InitFunc, 'args'): + for j, a in enumerate(InitFunc.args): + if a.name == kw.arg: + kw_idx = j + break + kw_var_type = init_param_types[kw_idx] if kw_idx is not None and kw_idx < len(init_param_types) else None + ArgVal = self.HandleExprLlvm(kw.value, VarType=kw_var_type) + if ArgVal: + InitArgs.append(ArgVal) + self._fill_default_args(InitArgs, InitFunc, InitFuncName) + self._append_eh_msg_out_arg(InitArgs, InitFunc, Gen) + adjusted_init = Gen._adjust_args(InitArgs, InitFunc) + Gen.builder.call(InitFunc, adjusted_init, name=f"init_{ClassName}") + elif Node.args or Node.keywords: + self._InitStructDefaults(result, ClassName, StructType) + self._InitStructFromArgs(result, Node, ClassName, StructType) + else: + self._InitStructDefaults(result, ClassName, StructType) + return result + return ir.Constant(ir.IntType(32), 0) + + def _ZeroInitStruct(self, struct_ptr, StructType): + Gen = self.Trans.LlvmGen + if isinstance(StructType, ir.IdentifiedStructType) and StructType.elements: + for i, elem_type in enumerate(StructType.elements): + elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"zero_elem_{i}") + zero_val = self._GetZeroValue(elem_type) + if zero_val is not None: + Gen._store(zero_val, elem_ptr) + elif isinstance(StructType, ir.IntType): + Gen._store(ir.Constant(StructType, 0), struct_ptr) + elif isinstance(StructType, ir.ArrayType) and isinstance(StructType.pointee, ir.IntType): + zero_arr = ir.Constant(StructType, None) + Gen._store(zero_arr, struct_ptr) + + def _GetZeroValue(self, typ): + if isinstance(typ, ir.IntType): + return ir.Constant(typ, 0) + elif isinstance(typ, ir.PointerType): + return ir.Constant(typ, None) + elif isinstance(typ, (ir.FloatType, ir.DoubleType)): + return ir.Constant(typ, 0.0) + elif isinstance(typ, ir.ArrayType): + return ir.Constant(typ, None) + return None + + def _InitStructDefaults(self, struct_ptr, ClassName, StructType): + Gen = self.Trans.LlvmGen + defaults = Gen.class_member_defaults.get(ClassName, {}) + members = Gen.class_members.get(ClassName, []) + if not defaults or not members: + return + if not isinstance(StructType, ir.IdentifiedStructType): + return + has_vtable = ClassName in Gen.class_vtable + base = 1 if has_vtable else 0 + for i, (member_name, member_type) in enumerate(members): + if member_name in defaults: + default_val = defaults[member_name] + if isinstance(default_val, ir.Constant): + elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"default_{ClassName}_{member_name}") + Gen._store(default_val, elem_ptr) + + def _InitStructFromArgs(self, struct_ptr, Node, ClassName, StructType): + Gen = self.Trans.LlvmGen + if not isinstance(StructType, ir.IdentifiedStructType): + return + members = Gen.class_members.get(ClassName, []) + has_vtable = ClassName in Gen.class_vtable + base = 1 if has_vtable else 0 + for i, arg in enumerate(Node.args): + if i >= len(members): + break + val = self.HandleExprLlvm(arg) + if not val: + continue + member_name, member_type = members[i] + elem_idx = base + i + if StructType.elements is None or elem_idx >= len(StructType.elements): + break + elem_type = StructType.elements[elem_idx] + if isinstance(elem_type, ir.IntType) and isinstance(val.type, ir.IntType): + if val.type.width < elem_type.width: + val = Gen.builder.zext(val, elem_type, name=f"zext_init_{ClassName}_{i}") + elif val.type.width > elem_type.width: + val = Gen.builder.trunc(val, elem_type, name=f"trunc_init_{ClassName}_{i}") + elif isinstance(elem_type, ir.PointerType) and isinstance(val.type, ir.PointerType): + if val.type.pointee != elem_type.pointee: + val = Gen.builder.bitcast(val, elem_type, name=f"bitcast_init_{ClassName}_{i}") + elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"init_elem_{ClassName}_{member_name}") + Gen._store(val, elem_ptr) + if Node.keywords: + member_map = {name: (base + i) for i, (name, _) in enumerate(members)} + for kw in Node.keywords: + if kw.arg in member_map: + val = self.HandleExprLlvm(kw.value) + if not val: + continue + elem_idx = member_map[kw.arg] + if StructType.elements is None or elem_idx >= len(StructType.elements): + continue + elem_type = StructType.elements[elem_idx] + if isinstance(elem_type, ir.IntType) and isinstance(val.type, ir.IntType): + if val.type.width < elem_type.width: + val = Gen.builder.zext(val, elem_type, name=f"zext_init_{ClassName}_{kw.arg}") + elif val.type.width > elem_type.width: + val = Gen.builder.trunc(val, elem_type, name=f"trunc_init_{ClassName}_{kw.arg}") + elif isinstance(elem_type, ir.PointerType) and isinstance(val.type, ir.PointerType): + if val.type.pointee != elem_type.pointee: + val = Gen.builder.bitcast(val, elem_type, name=f"bitcast_init_{ClassName}_{kw.arg}") + elem_ptr = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), elem_idx)], name=f"init_elem_{ClassName}_{kw.arg}") + Gen._store(val, elem_ptr) + + def _HandleSubscriptPtrLlvm(self, Node): + Gen = self.Trans.LlvmGen + ClassName = self.Trans.ExprHandler._get_var_class(Node.value, Gen) + if ClassName and ClassName in Gen.structs and Gen._has_function(f'{ClassName}.__getitem__'): + obj_val = self.HandleExprLlvm(Node.value) + idx_val = self.HandleExprLlvm(Node.slice) + if obj_val and idx_val: + if self._is_char_pointer(obj_val): + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + if isinstance(idx_val.type, ir.IntType) and idx_val.type.width < 64: + idx_val = Gen.builder.zext(idx_val, ir.IntType(64), name="zext_idx") + result = Gen.builder.call(Gen._get_function(f'{ClassName}.__getitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__getitem__") + return result + ValueVal = self.HandleExprLlvm(Node.value) + if not ValueVal: + return None + IndexVal = self.HandleExprLlvm(Node.slice) + if not IndexVal: + return None + if isinstance(ValueVal.type, ir.IntType): + var_ptr = self._get_int_ptr(Node.value) + if var_ptr: + i8_ptr = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index") + ptr = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr") + return ptr + return None + if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): + LoadedValueVal = Gen._load(ValueVal, name="load_subscript") + if isinstance(LoadedValueVal.type, ir.PointerType): + ElemPtr = Gen.builder.gep(LoadedValueVal, [IndexVal], name="subscript") + return ElemPtr + if isinstance(ValueVal.type, ir.PointerType): + pointee = ValueVal.type.pointee + if isinstance(pointee, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") + return Gen._load(ElemPtr, name="arr_subscript_val") + else: + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index") + ElemPtr = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + if isinstance(pointee, ir.IntType): + return Gen._load(ElemPtr, name="subscript_val") + return ElemPtr + elif isinstance(ValueVal.type, ir.ArrayType): + zero = ir.Constant(ir.IntType(32), 0) + if isinstance(Node.value, ast.Name): + VarName = Node.value.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") + return ElemPtr + arr_alloc = Gen._alloca_entry(ValueVal.type, name="arr_subscript_tmp") + Gen._store(ValueVal, arr_alloc) + ElemPtr = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") + return ElemPtr + return None + + def _HandleGenericCallLlvm(self, Node, FuncName): + Gen = self.Trans.LlvmGen + template = self.Trans.FunctionHandler._generic_templates[FuncName] + type_param_names = template['type_params'] + type_args = [] + CallArgs = [] + for i, arg_node in enumerate(Node.args): + arg_val = self.HandleExprLlvm(arg_node) + if arg_val: + CallArgs.append(arg_val) + type_str = self.Trans.FunctionHandler._infer_type_arg_from_value(arg_val, Gen) + type_args.append(type_str) + else: + type_args.append('int') + while len(type_args) < len(type_param_names): + type_args.append('int') + type_args = type_args[:len(type_param_names)] + spec_name = self.Trans.FunctionHandler._specialize_generic_function(FuncName, type_args, Gen) + if spec_name is None: + return None + mangled_spec = Gen._mangle_func_name(spec_name) + func = None + if mangled_spec in Gen.functions: + func = Gen.functions[mangled_spec] + elif spec_name in Gen.functions: + func = Gen.functions[spec_name] + else: + for fname, fobj in Gen.functions.items(): + if spec_name in fname or fname.endswith(spec_name): + func = fobj + break + if func is None: + return None + if not CallArgs: + CallArgs = [ir.Constant(ir.IntType(32), 0) for _ in func.args] + adjusted = Gen._adjust_args(CallArgs, func) + return Gen.builder.call(func, adjusted, name=f"call_{spec_name}") + + def _HandleGenericClassNewLlvm(self, Node, ClassName): + Gen = self.Trans.LlvmGen + template = self.Trans.ClassHandler._generic_class_templates[ClassName] + type_param_names = template['type_params'] + type_args = [] + type_names = [] + all_inferred = [] + for i, arg_node in enumerate(Node.args): + type_str = 'int' + type_name = 'CInt' + if isinstance(arg_node, ast.Constant): + if isinstance(arg_node.value, float): + type_str = 'double' + type_name = 'CDouble' + elif isinstance(arg_node.value, int): + type_str = 'int' + type_name = 'CInt' + elif isinstance(arg_node.value, bool): + type_str = 'i8' + type_name = 'CBool' + elif isinstance(arg_node, ast.Call): + if isinstance(arg_node.func, ast.Name): + func_id = arg_node.func.id + if func_id == 'float': + type_str = 'double' + type_name = 'CDouble' + elif func_id == 'int': + type_str = 'int' + type_name = 'CInt' + else: + float_types = {'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'} + int_types = {'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'} + if func_id in float_types: + type_str = 'double' + type_name = func_id + elif func_id in int_types: + type_str = 'int' + type_name = func_id + elif isinstance(arg_node.func, ast.Attribute): + attr_name = arg_node.func.attr + float_types = {'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'} + int_types = {'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'} + if attr_name in float_types: + type_str = 'double' + type_name = attr_name + elif attr_name in int_types: + type_str = 'int' + type_name = attr_name + elif isinstance(arg_node, ast.Name): + var_info = self.Trans.SymbolTable.get(arg_node.id) + if var_info and isinstance(var_info, dict): + var_type = var_info.get('type', '') + if var_type in ('double', 'float'): + type_str = 'double' + type_name = 'CDouble' + all_inferred.append((type_str, type_name)) + hint_types = [(ts, tn) for ts, tn in all_inferred if tn != 'CInt' or ts != 'int'] + for i in range(len(type_param_names)): + if i < len(hint_types): + type_args.append(hint_types[i][0]) + type_names.append(hint_types[i][1]) + elif i < len(all_inferred): + type_args.append(all_inferred[i][0]) + type_names.append(all_inferred[i][1]) + else: + type_args.append('int') + type_names.append('CInt') + spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names) + if spec_name is None: + return ir.Constant(ir.IntType(32), 0) + return self._HandleClassNewLlvm(Node, spec_name) + diff --git a/lib/core/Handles/HandlesExprFormat.py b/lib/core/Handles/HandlesExprFormat.py new file mode 100644 index 0000000..8000bcc --- /dev/null +++ b/lib/core/Handles/HandlesExprFormat.py @@ -0,0 +1,110 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprFormatHandle(BaseHandle): + def _HandleJoinedStrLlvm(self, Node, return_str=False): + Gen = self.Trans.LlvmGen + if not Gen or not Gen.builder: + return ir.Constant(ir.IntType(8).as_pointer(), None) + format_str = "" + cast_args = [] + for part in Node.values: + if isinstance(part, ast.Constant) and isinstance(part.value, str): + format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0') + elif isinstance(part, ast.FormattedValue): + fmt_class = self.Trans.ExprHandler._get_var_class(part.value, Gen) + if fmt_class and Gen._has_function(f'{fmt_class}.__str__'): + obj_val = self.HandleExprLlvm(part.value) + if obj_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + if fmt_class in Gen.structs: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}") + val = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__") + Gen._register_temp_ptr(val) + format_str += "%s" + cast_args.append(val) + else: + format_str += "%s" + cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) + continue + val = self.HandleExprLlvm(part.value) + if not val: + format_str += "%d" + cast_args.append(ir.Constant(ir.IntType(32), 0)) + continue + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, ir.IntType) and pointee.width == 8: + format_str += "%s" + cast_args.append(val) + elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + int_val = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int") + trunc_val = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc") + format_str += "%d" + cast_args.append(trunc_val) + else: + loaded = Gen._load(val, name="fstr_deref") + if isinstance(loaded.type, ir.IntType): + if loaded.type.width == 8: + format_str += "%c" + ext = Gen.builder.zext(loaded, ir.IntType(32), name="fstr_char2int") + cast_args.append(ext) + else: + format_str += "%d" + cast_args.append(loaded) + elif isinstance(loaded.type, (ir.FloatType, ir.DoubleType)): + format_str += "%f" + cast_args.append(loaded) + elif isinstance(loaded.type, ir.PointerType): + format_str += "%s" + cast_args.append(loaded) + else: + format_str += "%d" + cast_args.append(loaded) + elif isinstance(val.type, ir.IntType): + if val.type.width == 8: + format_str += "%c" + ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int") + cast_args.append(ext) + elif val.type.width == 1: + zext = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int") + format_str += "%d" + cast_args.append(zext) + else: + is_u = Gen._check_node_unsigned(part.value) + format_str += "%u" if is_u else "%d" + cast_args.append(val) + elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): + format_str += "%f" + cast_args.append(val) + else: + format_str += "%d" + cast_args.append(val) + if not format_str and not cast_args: + return Gen.emit_constant("", 'string') + encoded = format_str.encode('utf-8') + b'\x00' + string_type = ir.ArrayType(ir.IntType(8), len(encoded)) + string_const = ir.Constant(string_type, bytearray(encoded)) + global_var = ir.GlobalVariable(Gen.module, string_type, name=f"str_const_{Gen.string_const_counter}") + Gen.string_const_counter += 1 + global_var.initializer = string_const + global_var.linkage = 'internal' + format_ptr = Gen.builder.bitcast(global_var, ir.PointerType(ir.IntType(8))) + if return_str: + buf_size = ir.Constant(ir.IntType(64), 1024) + calloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64), ir.IntType(64)]) + calloc_func = Gen._get_or_declare_func('calloc', calloc_type) + buf_ptr = Gen.builder.call(calloc_func, [ir.Constant(ir.IntType(64), 1), buf_size], name="call_calloc_buf") + sprintf_func = Gen.get_or_declare_c_func('sprintf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8))], var_arg=True)) + sprintf_args = [buf_ptr, format_ptr] + cast_args + Gen.builder.call(sprintf_func, sprintf_args, name="call_sprintf") + return buf_ptr + printf_func = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + call_args = [format_ptr] + cast_args + return Gen.builder.call(printf_func, call_args, name="call_fstring") diff --git a/lib/core/Handles/HandlesExprLambda.py b/lib/core/Handles/HandlesExprLambda.py new file mode 100644 index 0000000..9c3309c --- /dev/null +++ b/lib/core/Handles/HandlesExprLambda.py @@ -0,0 +1,232 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprLambdaHandle(BaseHandle): + def _HandleLambdaLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not getattr(Gen, '_lambda_counter', None): + Gen._lambda_counter = 0 + lambda_id = Gen._lambda_counter + Gen._lambda_counter += 1 + fn_name = f"lambda_fn_{lambda_id}" + captured_vars = self._get_lambda_captured_vars(Node) + env_types = [] + env_var_names = [] + for var_name, var_val in captured_vars: + env_types.append(var_val.type) + env_var_names.append(var_name) + env_struct_type = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([]) + ret_type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body) + param_types = [ir.PointerType(env_struct_type)] + if Node.args: + for arg in Node.args.args: + param_types.append(ir.IntType(32)) + fn_type = ir.FunctionType(ret_type, param_types) + fn = ir.Function(Gen.module, fn_type, name=fn_name) + Gen.functions[fn_name] = fn + entry_block = fn.append_basic_block(name=f"{fn_name}_entry") + prev_builder = Gen.builder + prev_func = Gen.func + prev_vars = dict(Gen.variables) + Gen.builder = ir.IRBuilder(entry_block) + Gen.func = fn + Gen.variables = {} + for i, arg in enumerate(fn.args): + arg.name = f"arg_{i}" if i > 0 else "env" + if env_types: + for idx, var_name in enumerate(env_var_names): + env_ptr = fn.args[0] + zero = ir.Constant(ir.IntType(32), 0) + member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}") + loaded = Gen._load(member_ptr, name=f"load_env_{var_name}") + temp_alloca = Gen._alloca(loaded.type, name=f"temp_{var_name}") + Gen._store(loaded, temp_alloca) + Gen.variables[var_name] = temp_alloca + if Node.args: + for i, arg in enumerate(Node.args.args): + Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg) + Gen._store(fn.args[i + 1], Gen.variables[arg.arg]) + body_val = self.HandleExprLlvm(Node.body) + if body_val: + if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): + body_val = Gen._load(body_val, name="load_lambda_ret") + if body_val.type != ret_type: + if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType): + if body_val.type.width < ret_type.width: + body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret") + elif body_val.type.width > ret_type.width: + body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret") + elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType): + body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret") + Gen.builder.ret(body_val) + else: + Gen.builder.ret(ir.Constant(ret_type, 0)) + Gen.builder = prev_builder + Gen.func = prev_func + Gen.variables = prev_vars + closure_struct_type = ir.LiteralStructType([ + ir.PointerType(ir.IntType(8)), + ir.PointerType(fn_type) + ]) + closure_ptr = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}") + env_ptr = Gen._alloca(env_struct_type, name=f"env_{lambda_id}") + if env_types: + for idx, (var_name, var_val) in enumerate(captured_vars): + zero = ir.Constant(ir.IntType(32), 0) + member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}") + Gen._store(var_val, member_ptr) + zero = ir.Constant(ir.IntType(32), 0) + env_field_ptr = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr") + env_i8_ptr = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr") + Gen._store(env_i8_ptr, env_field_ptr) + fn_field_ptr = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr") + Gen._store(fn, fn_field_ptr) + return closure_ptr + + def _get_lambda_captured_vars(self, Node): + Gen = self.Trans.LlvmGen + captured = [] + free_vars = self._get_lambda_free_vars(Node) + for var_name in free_vars: + if var_name in Gen.variables: + var_ptr = Gen.variables[var_name] + if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable): + loaded = Gen._load(var_ptr, name=f"capture_{var_name}") + captured.append((var_name, loaded)) + return captured + + def _get_lambda_free_vars(self, Node): + bound_vars = set() + free_vars = set() + # 收集 lambda body 中的 bound 和 free 变量 + self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars) + # lambda 参数也是 bound 的 + if Node.args: + for arg in Node.args.args: + bound_vars.add(arg.arg) + # free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量 + result = free_vars - bound_vars + return list(result) + + def _HandleIfExpLlvm(self, Node): + Gen = self.Trans.LlvmGen + TestVal = self.HandleExprLlvm(Node.test) + if not TestVal: + return None + if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1: + TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._zero_const(TestVal.type), name="ifexp_cond") + ThenBB = Gen.func.append_basic_block(name="ifexp.then") + ElseBB = Gen.func.append_basic_block(name="ifexp.else") + MergeBB = Gen.func.append_basic_block(name="ifexp.end") + Gen.builder.cbranch(TestVal, ThenBB, ElseBB) + # 先在 ThenBB 中生成 BodyVal + Gen.builder.position_at_start(ThenBB) + BodyVal = self.HandleExprLlvm(Node.body) + if not BodyVal: + BodyVal = ir.Constant(ir.IntType(32), 0) + ThenEndBB = Gen.builder.block + # 在 ElseBB 中生成 OrelseVal + Gen.builder.position_at_start(ElseBB) + OrelseVal = self.HandleExprLlvm(Node.orelse) + if not OrelseVal: + OrelseVal = ir.Constant(ir.IntType(32), 0) + ElseEndBB = Gen.builder.block + # 确定 phi 节点的目标类型 + result_type = BodyVal.type + if BodyVal.type != OrelseVal.type: + if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType): + result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType): + # 指针类型,使用 BodyVal 的类型 + result_type = BodyVal.type + elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType): + # BodyVal 是整数,OrelseVal 是指针(字符串字面量) + # 如果指针指向 i8,将指针转换为 i8(加载字符) + if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: + result_type = ir.IntType(8) + else: + result_type = OrelseVal.type + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType): + # BodyVal 是指针(字符串字面量),OrelseVal 是整数 + # 如果指针指向 i8,将指针转换为 i8(加载字符) + if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8: + result_type = ir.IntType(8) + else: + result_type = BodyVal.type + else: + result_type = OrelseVal.type + # 在 ThenBB 末尾添加类型转换(如果需要)和分支 + if not ThenEndBB.is_terminated: + Gen.builder.position_at_end(ThenEndBB) + if BodyVal.type != result_type: + if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType): + if BodyVal.type.width < result_type.width: + BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext") + else: + BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc") + elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): + # 如果 result_type 是 i8*,说明 Else 分支是字符串字面量 + # 不应该将整数转换为指针,而应该保持整数类型 + # 这里将 result_type 改为 i8 + result_type = ir.IntType(8) + # 重新处理 Else 分支的类型转换 + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): + # 指针转整数 + BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int") + Gen.builder.branch(MergeBB) + # 在 ElseBB 末尾添加类型转换(如果需要)和分支 + if not ElseEndBB.is_terminated: + Gen.builder.position_at_end(ElseEndBB) + if OrelseVal.type != result_type: + if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType): + if OrelseVal.type.width < result_type.width: + OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext") + else: + OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc") + elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): + # 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量 + # 不应该将整数转换为指针,而应该保持整数类型 + # 这里将 result_type 改为 i8 + result_type = ir.IntType(8) + # 重新处理 BodyVal 分支的类型转换(已经在上面处理过了) + elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): + # 如果指针指向 i8,加载字符值 + if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: + OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_load_char") + else: + OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int") + Gen.builder.branch(MergeBB) + Gen.builder.position_at_start(MergeBB) + result_phi = Gen.builder.phi(result_type, name="ifexp.result") + result_phi.add_incoming(BodyVal, ThenEndBB) + result_phi.add_incoming(OrelseVal, ElseEndBB) + return result_phi + + def _HandleNamedExprLlvm(self, Node): + Gen = self.Trans.LlvmGen + ValueVal = self.HandleExprLlvm(Node.value) + if not ValueVal: + return None + TargetName = Node.target.id + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + if TargetName in Gen.variables and Gen.variables[TargetName] is not None: + VarPtr = Gen.variables[TargetName] + if VarPtr.type.pointee == ValueVal.type: + Gen._store(ValueVal, VarPtr) + else: + NewVar = Gen._alloca(ValueVal.type, name=TargetName) + Gen._store(ValueVal, NewVar) + Gen.variables[TargetName] = NewVar + else: + NewVar = Gen._alloca(ValueVal.type, name=TargetName) + Gen._store(ValueVal, NewVar) + Gen.variables[TargetName] = NewVar + Gen._reg_values[TargetName] = ValueVal + return ValueVal diff --git a/lib/core/Handles/HandlesExprOps.py b/lib/core/Handles/HandlesExprOps.py new file mode 100644 index 0000000..5b061ff --- /dev/null +++ b/lib/core/Handles/HandlesExprOps.py @@ -0,0 +1,402 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ExprOpsHandle(BaseHandle): + def _HandleBinOpLlvm(self, Node, VarType=None): + Gen = self.Trans.LlvmGen + Gen._set_node_info(Node, "BinOp") + LeftVal = self.HandleExprLlvm(Node.left, VarType) + if not LeftVal: + return None + RightVal = self.HandleExprLlvm(Node.right, VarType) + if not RightVal: + return None + Op = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if not Op: + return None + OP_OVERLOAD_MAP = { + '+': '__add__', '-': '__sub__', '*': '__mul__', + '/': '__truediv__', '//': '__floordiv__', '%': '__mod__', + '**': '__pow__', + } + if Op in OP_OVERLOAD_MAP: + LeftClassName = None + if isinstance(LeftVal.type, ir.PointerType): + pointee = LeftVal.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + LeftClassName = CN + break + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen) + if LeftClassName and LeftClassName in Gen.structs: + TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) + LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") + if LeftClassName is None and isinstance(Node.left, ast.Name): + LeftClassName = Gen.var_struct_class.get(Node.left.id) + if LeftClassName and LeftClassName in Gen.structs: + if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: + TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) + LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") + if LeftClassName: + op_name = OP_OVERLOAD_MAP[Op] + result = self.Trans.ExprUtils._try_operator_overload(LeftClassName, op_name, LeftVal, Gen, RightVal) + if result is not None: + return result + if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: + if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1: + CharVal = Gen._load(LeftVal, name="load_char_const") + CharAsInt = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int") + result = Gen.builder.add(CharAsInt, RightVal, name="char_add") + TruncResult = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char") + return TruncResult + is_unsigned = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right) + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="zext_right") + elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType): + LeftVal = Gen._load(LeftVal, name="deref_ptr_binop") + if LeftVal.type.width < RightVal.type.width: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left") + elif LeftVal.type.width > RightVal.type.width: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref") + elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): + if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType): + RightVal = Gen._load(RightVal, name="deref_ptr_binop_r") + if RightVal.type.width < LeftVal.type.width: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right") + elif RightVal.type.width > LeftVal.type.width: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref") + if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name): + vname = Node.left.id + if vname in Gen.var_signedness and Gen.var_signedness[vname]: + is_unsigned = True + result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned) + return result + + def _HandleBoolOpLlvm(self, Node): + Gen = self.Trans.LlvmGen + + def _to_bool(val, name): + if isinstance(val.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name) + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + return Gen.builder.icmp_signed('!=', val, Gen._zero_const(val.type), name=name) + return val + + values = Node.values + if len(values) < 2: + return self.HandleExprLlvm(values[0]) if values else None + if isinstance(Node.op, ast.And): + phi_incomings = [] + end_bb = Gen.func.append_basic_block(name="and.end") + for idx in range(len(values) - 1): + val = self.HandleExprLlvm(values[idx]) + if not val: + if not end_bb.is_terminated: + saved_block = Gen.builder.block + Gen.builder.position_at_start(end_bb) + Gen.builder.unreachable() + Gen.builder.position_at_end(saved_block) + return None + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + val = _to_bool(val, f"andcond{idx}") + cur_bb = Gen.builder.block + next_bb = Gen.func.append_basic_block(name=f"and.rhs{idx}") + Gen.builder.cbranch(val, next_bb, end_bb) + phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb)) + Gen.builder.position_at_start(next_bb) + last_val = self.HandleExprLlvm(values[-1]) + if not last_val: + last_val = ir.Constant(ir.IntType(1), 0) + if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: + last_val = _to_bool(last_val, "andcond_last") + last_bb = Gen.builder.block + Gen.builder.branch(end_bb) + Gen.builder.position_at_start(end_bb) + result_phi = Gen.builder.phi(ir.IntType(1), name="and.result") + for const_val, bb in phi_incomings: + result_phi.add_incoming(const_val, bb) + result_phi.add_incoming(last_val, last_bb) + return result_phi + elif isinstance(Node.op, ast.Or): + phi_incomings = [] + end_bb = Gen.func.append_basic_block(name="or.end") + for idx in range(len(values) - 1): + val = self.HandleExprLlvm(values[idx]) + if not val: + if not end_bb.is_terminated: + saved_block = Gen.builder.block + Gen.builder.position_at_start(end_bb) + Gen.builder.unreachable() + Gen.builder.position_at_end(saved_block) + return None + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + val = _to_bool(val, f"orcond{idx}") + cur_bb = Gen.builder.block + next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}") + Gen.builder.cbranch(val, end_bb, next_bb) + phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb)) + Gen.builder.position_at_start(next_bb) + last_val = self.HandleExprLlvm(values[-1]) + if not last_val: + last_val = ir.Constant(ir.IntType(1), 1) + if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: + last_val = _to_bool(last_val, "orcond_last") + last_bb = Gen.builder.block + Gen.builder.branch(end_bb) + Gen.builder.position_at_start(end_bb) + result_phi = Gen.builder.phi(ir.IntType(1), name="or.result") + for const_val, bb in phi_incomings: + result_phi.add_incoming(const_val, bb) + result_phi.add_incoming(last_val, last_bb) + return result_phi + return None + + def _HandleUnaryOpLlvm(self, Node): + Gen = self.Trans.LlvmGen + OperandVal = self.HandleExprLlvm(Node.operand) + if not OperandVal: + return None + OpSymbol = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op) + if not OpSymbol: + return None + UNARY_OVERLOAD_MAP = { + '-': '__neg__', + '+': '__pos__', + '~': '__invert__', + } + if OpSymbol in UNARY_OVERLOAD_MAP: + ClassName = None + if isinstance(OperandVal.type, ir.PointerType): + pointee = OperandVal.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + ClassName = CN + break + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen) + if ClassName and ClassName in Gen.structs: + TargetStructPtr = ir.PointerType(Gen.structs[ClassName]) + OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") + if ClassName is None and isinstance(Node.operand, ast.Name): + ClassName = Gen.var_struct_class.get(Node.operand.id) + if ClassName and ClassName in Gen.structs: + if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8: + TargetStructPtr = ir.PointerType(Gen.structs[ClassName]) + OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") + if ClassName: + op_name = UNARY_OVERLOAD_MAP[OpSymbol] + result = self.Trans.ExprUtils._try_operator_overload(ClassName, op_name, OperandVal, Gen) + if result is not None: + return result + if OpSymbol == 'not': + if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1: + return Gen.builder.not_(OperandVal, name="not_result") + if isinstance(OperandVal.type, ir.PointerType): + null_val = ir.Constant(OperandVal.type, None) + return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result") + zero = ir.Constant(OperandVal.type, 0) + return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result") + elif OpSymbol == '~': + if isinstance(OperandVal.type, ir.IntType): + mask = (1 << OperandVal.type.width) - 1 + return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result") + return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result") + elif OpSymbol == '+': + return OperandVal + elif OpSymbol == '-': + if isinstance(OperandVal.type, ir.IntType): + return Gen.builder.neg(OperandVal, name="neg_result") + elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fneg(OperandVal, name="fneg_result") + return None + + def _HandleCompareLlvm(self, Node): + Gen = self.Trans.LlvmGen + LeftVal = self.HandleExprLlvm(Node.left) + if not LeftVal: + return None + is_unsigned = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False) + if len(Node.ops) == 1: + Op = Node.ops[0] + ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op) + if not ComparatorSymbol: + return None + RightVal = self.HandleExprLlvm(Node.comparators[0]) + if not RightVal: + return None + if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant): + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + lv, rv = LeftVal.constant, RightVal.constant + lw, rw = LeftVal.type.width, RightVal.type.width + if lw < rw: + lv = lv if lv >= 0 else lv + (1 << lw) + elif rw < lw: + rv = rv if rv >= 0 else rv + (1 << rw) + if is_unsigned: + mask_l = (1 << max(lw, rw)) - 1 + lv = lv & mask_l + rv = rv & mask_l + cmp_map = { + '==': lv == rv, '!=': lv != rv, + '<': lv < rv, '>': lv > rv, + '<=': lv <= rv, '>=': lv >= rv, + } + result = cmp_map.get(ComparatorSymbol, False) + return ir.Constant(ir.IntType(1), 1 if result else 0) + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + # 如果宽类型常量值超出窄类型有符号范围,则必须用zext + # i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节) + need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max or RightVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max or LeftVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp") + elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8: + LeftVal = Gen._load(LeftVal, name="load_char_ptr_cmp") + else: + if isinstance(RightVal, ir.Constant) and RightVal.constant == 0: + RightVal = ir.Constant(LeftVal.type, None) + else: + RightVal = Gen.builder.inttoptr(RightVal, LeftVal.type, name="int2ptr_cmp") + elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): + if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8: + RightVal = Gen._load(RightVal, name="load_char_ptr_cmp") + else: + if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0: + LeftVal = ir.Constant(RightVal.type, None) + else: + LeftVal = Gen.builder.inttoptr(LeftVal, RightVal.type, name="int2ptr_cmp") + if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType): + result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): + if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): + RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp") + elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): + LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp") + result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + elif is_unsigned: + result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + else: + result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + return result + EndBB = Gen.func.append_basic_block(name="cmp.end") + result_val = None + PrevBB = Gen.builder.block + for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)): + ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op) + if not ComparatorSymbol: + continue + RightVal = self.HandleExprLlvm(Comparator) + if not RightVal: + continue + NextBB = Gen.func.append_basic_block(name="cmp.next") + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max or RightVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max or LeftVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}") + if is_unsigned: + cmp_result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): + if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): + RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}") + elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): + LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}") + cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + else: + cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + if result_val is None: + result_val = cmp_result + else: + result_val = Gen.builder.and_(result_val, cmp_result, name=f"and_cmp_{i}") + Gen.builder.cbranch(cmp_result, NextBB, EndBB) + Gen.builder.position_at_start(NextBB) + LeftVal = RightVal + Gen.builder.branch(EndBB) + Gen.builder.position_at_start(EndBB) + final_result = Gen.builder.phi(ir.IntType(1), name="final_cmp") + final_result.add_incoming(ir.Constant(ir.IntType(1), 0), PrevBB) + for i in range(len(Node.ops)): + bb = Gen.func.append_basic_block(name=f"cmp.end.{i}") + final_result.add_incoming(ir.Constant(ir.IntType(1), 1), bb) + return final_result diff --git a/lib/core/Handles/HandlesExprUtils.py b/lib/core/Handles/HandlesExprUtils.py new file mode 100644 index 0000000..2dfda20 --- /dev/null +++ b/lib/core/Handles/HandlesExprUtils.py @@ -0,0 +1,240 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +import ast +import llvmlite.ir as ir + + +class ExprUtils: + def __init__(self, translator: "Translator"): + self.Trans = translator + + def GetOpSymbol(self, Op): + OpMap = { + ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/', + ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&', + ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>', + ast.MatMult: '@', + } + return OpMap.get(type(Op), None) + + def GetUnaryOpSymbol(self, Op): + OpMap = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'} + return OpMap.get(type(Op), None) + + def GetComparatorSymbol(self, Op): + OpMap = { + ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=', + ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not', + ast.In: 'in', ast.NotIn: 'not in', + } + return OpMap.get(type(Op), None) + + def _get_var_class(self, node, Gen): + if isinstance(node, ast.Name): + VarName = node.id + return Gen.var_struct_class.get(VarName) + if isinstance(node, ast.Attribute): + AttrName = node.attr + return Gen.var_struct_class.get(AttrName) + return None + + def _try_operator_overload(self, ClassName, op_name, obj_val, Gen, other_val=None): + FullMethodName = f'{ClassName}.{op_name}' + if not Gen._has_function(FullMethodName): + FullMethodName = f'{ClassName}.{op_name}__' + if Gen._has_function(FullMethodName): + func = Gen._get_function(FullMethodName) + call_args = [obj_val] + if other_val is not None: + call_args.append(other_val) + if len(func.ftype.args) == len(call_args): + for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)): + if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType): + if expected_type != actual_val.type: + if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}") + result = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}") + return result + return None + + def _llvm_type_to_detailed_string(self, llvm_type, var_name=""): + info = { + 'name': "unknown", + 'size': 0, + 'signed': False, + 'ptr': False + } + if isinstance(llvm_type, ir.IntType): + info['size'] = llvm_type.width // 8 + info['signed'] = True + if llvm_type.width == 8: + info['name'] = "char" + elif llvm_type.width == 16: + info['name'] = "short" + elif llvm_type.width == 32: + info['name'] = "int" + elif llvm_type.width == 64: + info['name'] = "long long" + else: + info['name'] = f"int{llvm_type.width}" + elif isinstance(llvm_type, ir.DoubleType): + info['size'] = 8 + info['signed'] = True + info['name'] = "double" + elif isinstance(llvm_type, ir.FloatType): + info['size'] = 4 + info['signed'] = True + info['name'] = "float" + elif isinstance(llvm_type, ir.PointerType): + info['size'] = 8 + info['signed'] = False + info['ptr'] = True + pointee_info = self._llvm_type_to_detailed_string(llvm_type.pointee) + info['name'] = f"{pointee_info['name']}*" + elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)): + size = 0 + for elem in llvm_type.elements: + elem_info = self._llvm_type_to_detailed_string(elem) + size += elem_info['size'] + info['size'] = size + info['signed'] = False + if isinstance(llvm_type, ir.IdentifiedStructType): + info['name'] = llvm_type.name + else: + info['name'] = "struct" + elif isinstance(llvm_type, ir.ArrayType): + elem_info = self._llvm_type_to_detailed_string(llvm_type.element) + info['size'] = elem_info['size'] * llvm_type.count + info['signed'] = elem_info['signed'] + info['name'] = f"{elem_info['name']}[]" + elif isinstance(llvm_type, ir.VoidType): + info['size'] = 0 + info['signed'] = False + info['name'] = "void" + else: + info['size'] = 0 + info['signed'] = False + info['name'] = str(llvm_type) + return info + + def _infer_expr_llvm_type_full(self, node): + Gen = self.Trans.LlvmGen + if isinstance(node, ast.Constant): + if isinstance(node.value, bool): + return ir.IntType(32) + elif isinstance(node.value, int): + return ir.IntType(32) + elif isinstance(node.value, float): + return ir.DoubleType() + elif isinstance(node.value, str): + if getattr(node, 'kind', None) == 'u': + return ir.PointerType(ir.IntType(16)) + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.Name): + if node.id in Gen.variables: + var_ptr = Gen.variables[node.id] + if isinstance(var_ptr.type, ir.PointerType): + return var_ptr.type.pointee + return var_ptr.type + if node.id in Gen._reg_values: + return Gen._reg_values[node.id].type + return ir.IntType(32) + elif isinstance(node, ast.Attribute): + attr_name = node.attr + if attr_name in self.Trans.SymbolTable: + AttrInfo = self.Trans.SymbolTable[attr_name] + if getattr(AttrInfo, 'IsEnumMember', None): + return ir.IntType(32) + return ir.IntType(32) + elif isinstance(node, ast.BinOp): + left_type = self._infer_expr_llvm_type_full(node.left) + right_type = self._infer_expr_llvm_type_full(node.right) + if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)): + return ir.DoubleType() + if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType): + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.UnaryOp): + return self._infer_expr_llvm_type_full(node.operand) + elif isinstance(node, ast.Subscript): + val_type = self._infer_expr_llvm_type_full(node.value) + if isinstance(val_type, ir.PointerType): + if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8: + return ir.IntType(8) + if isinstance(val_type.pointee, ir.ArrayType): + return ir.PointerType(val_type.pointee.element) + return val_type.pointee + if isinstance(val_type, ir.ArrayType): + return val_type.element + if isinstance(val_type, ir.IntType): + return ir.IntType(8) + return ir.IntType(32) + elif isinstance(node, ast.Call): + if isinstance(node.func, ast.Name): + func_name = node.func.id + if Gen._has_function(func_name): + fn = Gen._get_function(func_name) + return fn.function_type.return_type + if func_name == 'len': + return ir.IntType(32) + if func_name == 'sizeof': + return ir.IntType(32) + if func_name == 'ord': + return ir.IntType(32) + if func_name == 'chr': + return ir.IntType(8) + if func_name == 'int': + return ir.IntType(32) + if func_name == 'float' or func_name == 'double': + return ir.DoubleType() + elif isinstance(node.func, ast.Attribute): + if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': + if node.func.attr == 'Deref': + return ir.IntType(64) + if isinstance(node.func.value, ast.Name) and node.func.value.id == 't': + if node.func.attr == 'CChar': + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.Compare): + return ir.IntType(1) + elif isinstance(node, ast.BoolOp): + return ir.IntType(1) + elif isinstance(node, ast.IfExp): + return self._infer_expr_llvm_type_full(node.body) + elif isinstance(node, ast.Attribute): + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + + def _collect_names(self, node, bound, free=None): + """收集 AST 节点中的绑定变量和自由变量 + + Args: + node: AST 节点 + bound: 集合,收集绑定变量(ast.Store 上下文) + free: 集合,收集自由变量(ast.Load 上下文),可为 None + """ + if free is None: + free = set() + if isinstance(node, ast.Name): + if isinstance(node.ctx, ast.Store): + bound.add(node.id) + elif isinstance(node.ctx, ast.Load): + free.add(node.id) + elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)): + # 这些节点有自己的作用域,不递归进入 + # 但需要收集参数名作为 bound + if hasattr(node, 'args') and node.args: + for arg in node.args.args: + bound.add(arg.arg) + elif getattr(node, '_fields', None): + for field in node._fields: + value = getattr(node, field, None) + if isinstance(value, list): + for item in value: + if isinstance(item, (ast.stmt, ast.expr)): + self._collect_names(item, bound, free) + elif isinstance(value, (ast.stmt, ast.expr)): + self._collect_names(value, bound, free) diff --git a/lib/core/Handles/HandlesFor.py b/lib/core/Handles/HandlesFor.py new file mode 100644 index 0000000..f4053a4 --- /dev/null +++ b/lib/core/Handles/HandlesFor.py @@ -0,0 +1,495 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class ForHandle(BaseHandle): + def _HandleForLlvm(self, Node): + Gen = self.Trans.LlvmGen + Gen._set_node_info(Node, "For") + if not isinstance(Node.target, ast.Name): + return + TargetName = Node.target.id + StartVal = None + EndVal = None + StepVal = None + IsRange = False + CondOp = '<' + if isinstance(Node.iter, ast.Call): + CallFunc = Node.iter.func + if isinstance(CallFunc, ast.Name) and CallFunc.id == 'range': + IsRange = True + RangeArgs = Node.iter.args + RangeEndArg = RangeArgs[1] if len(RangeArgs) >= 2 else RangeArgs[0] if len(RangeArgs) >= 1 else None + OptimizedEnd = False + if len(RangeArgs) >= 2 and isinstance(RangeEndArg, ast.BinOp): + if isinstance(RangeEndArg.op, ast.Add): + if (isinstance(RangeEndArg.right, ast.Constant) and RangeEndArg.right.value == 1): + EndVal = self.HandleExprLlvm(RangeEndArg.left) + CondOp = '<=' + OptimizedEnd = True + elif (isinstance(RangeEndArg.left, ast.Constant) and RangeEndArg.left.value == 1): + EndVal = self.HandleExprLlvm(RangeEndArg.right) + CondOp = '<=' + OptimizedEnd = True + elif isinstance(RangeEndArg.op, ast.Sub): + if isinstance(RangeEndArg.right, ast.Constant) and RangeEndArg.right.value == 1: + EndVal = self.HandleExprLlvm(RangeEndArg.left) + CondOp = '<' + OptimizedEnd = True + if not OptimizedEnd: + if len(RangeArgs) == 1: + EndVal = self.HandleExprLlvm(RangeArgs[0]) + else: + EndVal = self.HandleExprLlvm(RangeEndArg) + if len(RangeArgs) == 1: + StartVal = ir.Constant(ir.IntType(32), 0) + elif len(RangeArgs) >= 2: + StartVal = self.HandleExprLlvm(RangeArgs[0]) + if len(RangeArgs) >= 3: + StepVal = self.HandleExprLlvm(RangeArgs[2]) + # Check if step is a negative constant — need to flip condition + step_arg = RangeArgs[2] + if isinstance(step_arg, ast.UnaryOp) and isinstance(step_arg.op, ast.USub): + if isinstance(step_arg.operand, ast.Constant) and isinstance(step_arg.operand.value, (int, float)): + if step_arg.operand.value > 0: + CondOp = '>' + elif isinstance(step_arg, ast.Constant) and isinstance(step_arg.value, (int, float)): + if step_arg.value < 0: + CondOp = '>' + if not EndVal: + return + if not isinstance(EndVal.type, ir.IntType): + if isinstance(EndVal.type, ir.PointerType) and isinstance(EndVal.type.pointee, ir.IntType): + EndVal = Gen._load(EndVal, name="load_end") + else: + EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end") + if StartVal and not isinstance(StartVal.type, ir.IntType): + if isinstance(StartVal.type, ir.PointerType) and isinstance(StartVal.type.pointee, ir.IntType): + StartVal = Gen._load(StartVal, name="load_start") + else: + StartVal = Gen.builder.ptrtoint(StartVal, ir.IntType(64), name="start") + else: + StartVal = ir.Constant(ir.IntType(64), 0) + if not StartVal: + StartVal = ir.Constant(EndVal.type, 0) + if StepVal is None: + StepVal = ir.Constant(EndVal.type, 1) + if not IsRange: + IterClassName = self.Trans.ExprHandler._get_var_class(Node.iter, Gen) + if not IterClassName and isinstance(Node.iter, ast.Call) and isinstance(Node.iter.func, ast.Name): + IterClassName = Node.iter.func.id + if IterClassName not in Gen.structs: + IterClassName = None + if IterClassName and Gen._has_function(f'{IterClassName}.__iter__') and Gen._has_function(f'{IterClassName}.__next__'): + self._HandleForIterLlvm(Node, IterClassName) + return + IterVal = self.HandleExprLlvm(Node.iter) + if not IterVal: + return + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: + self._HandleForStrLlvm(Node, IterVal) + return + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.ArrayType): + self._HandleForListLlvm(Node, IterVal) + return + StartVal = ir.Constant(ir.IntType(32), 0) + EndVal = IterVal + if not isinstance(EndVal.type, ir.IntType): + EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end") + StartVal = ir.Constant(ir.IntType(64), 0) + StepVal = ir.Constant(EndVal.type, 1) + CondOp = '<' + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + if TargetName in Gen.variables and Gen.variables[TargetName] is not None: + LoopVar = Gen.variables[TargetName] + if isinstance(LoopVar.type, ir.PointerType) and isinstance(LoopVar.type.pointee, ir.IntType) and LoopVar.type.pointee == EndVal.type and isinstance(EndVal.type, ir.IntType) and StartVal.type == LoopVar.type.pointee and EndVal.type == StartVal.type: + Gen._store(StartVal, LoopVar) + else: + NewVar = Gen._alloca_entry(EndVal.type, name=TargetName) + if StartVal.type != EndVal.type: + if isinstance(EndVal.type, ir.IntType) and isinstance(StartVal.type, ir.IntType): + if StartVal.type.width < EndVal.type.width: + StartVal = Gen.builder.zext(StartVal, EndVal.type, name="zext_loop_start") + elif StartVal.type.width > EndVal.type.width: + StartVal = Gen.builder.trunc(StartVal, EndVal.type, name="trunc_loop_start") + Gen._store(StartVal, NewVar) + Gen.variables[TargetName] = NewVar + LoopVar = NewVar + else: + LoopVar = Gen._alloca_entry(EndVal.type, name=TargetName) + Gen.variables[TargetName] = LoopVar + Gen._store(StartVal, LoopVar) + if StepVal and isinstance(StepVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType): + if StepVal.type.width < EndVal.type.width: + StepVal = Gen.builder.zext(StepVal, EndVal.type, name="zext_loop_step") + elif StepVal.type.width > EndVal.type.width: + StepVal = Gen.builder.trunc(StepVal, EndVal.type, name="trunc_loop_step") + Gen._record_var_signedness(TargetName, 'int') + CondBB = Gen.func.append_basic_block(name="for.cond") + BodyBB = Gen.func.append_basic_block(name="for.body") + StepBB = Gen.func.append_basic_block(name="for.step") + ElseBB = Gen.func.append_basic_block(name="for.else") if Node.orelse else None + AfterBB = Gen.func.append_basic_block(name="for.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + LoopVal = Gen._load(LoopVar, name=TargetName) + is_unsigned = Gen._is_var_unsigned(TargetName) + if is_unsigned: + Cond = Gen.builder.icmp_unsigned(CondOp, LoopVal, EndVal, name="forcond") + else: + Cond = Gen.builder.icmp_signed(CondOp, LoopVal, EndVal, name="forcond") + Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) + Gen.builder.position_at_start(BodyBB) + CachedLoopVal = Gen._load(LoopVar, name=TargetName) + Gen._reg_values[TargetName] = CachedLoopVal + self.HandleBodyLlvm(Node.body) + StepLoopVal = CachedLoopVal + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is CachedLoopVal: + del Gen._reg_values[TargetName] + else: + StepLoopVal = Gen._load(LoopVar, name=TargetName) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + StepLoopVal2 = Gen._load(LoopVar, name=TargetName) + NextVal = Gen.builder.add(StepLoopVal2, StepVal, name="next") + Gen._store(NextVal, LoopVar) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleGlobalLlvm(self, Node): + Gen = self.Trans.LlvmGen + for name in Node.names: + Gen.global_vars.add(name) + if name in Gen.module.globals: + Gen.variables[name] = Gen.module.globals[name] + if name in Gen._reg_values: + del Gen._reg_values[name] + + def _HandleNonlocalLlvm(self, Node): + Gen = self.Trans.LlvmGen + for name in Node.names: + if name in Gen._reg_values and name not in Gen.variables: + OldVal = Gen._reg_values[name] + var = Gen._alloca_entry(OldVal.type, name=name) + Gen._store(OldVal, var) + Gen.variables[name] = var + del Gen._reg_values[name] + + def _collect_implicit_nonlocal(self, Node, Gen): + param_names = set() + for arg in Node.args.args: + param_names.add(arg.arg) + local_names = set() + for child in ast.walk(Node): + if isinstance(child, ast.Assign): + for target in child.targets: + if isinstance(target, ast.Name): + local_names.add(target.id) + elif isinstance(target, ast.Tuple): + for elt in target.elts: + if isinstance(elt, ast.Name): + local_names.add(elt.id) + elif isinstance(child, ast.AugAssign): + if isinstance(child.target, ast.Name): + local_names.add(child.target.id) + elif isinstance(child, ast.AnnAssign): + if isinstance(child.target, ast.Name): + local_names.add(child.target.id) + elif isinstance(child, ast.For): + if isinstance(child.target, ast.Name): + local_names.add(child.target.id) + read_names = set() + for child in ast.walk(Node): + if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Load): + name = child.id + if name not in param_names and name not in local_names: + read_names.add(name) + implicit = [] + for name in read_names: + if name in Gen.variables and Gen.variables[name] is not None: + implicit.append(name) + elif name in Gen._reg_values: + implicit.append(name) + for called_name in read_names: + if called_name in Gen.nonlocal_params: + for nv, _ in Gen.nonlocal_params[called_name]: + if nv not in param_names and nv not in local_names: + if nv not in read_names: + if nv in Gen.variables and Gen.variables[nv] is not None: + implicit.append(nv) + elif nv in Gen._reg_values: + implicit.append(nv) + return implicit + + def _collect_all_nonlocal_names(self, Node): + """Recursively collect all nonlocal variable names from a function and its nested functions.""" + names = set() + for stmt in Node.body: + if isinstance(stmt, ast.Nonlocal): + for name in stmt.names: + names.add(name) + elif isinstance(stmt, ast.FunctionDef): + # Recursively collect from nested functions + sub_names = self._collect_all_nonlocal_names(stmt) + names.update(sub_names) + return names + + def _HandleNestedFunctionLlvm(self, Node): + Gen = self.Trans.LlvmGen + nonlocal_var_names = [] + for stmt in Node.body: + if isinstance(stmt, ast.Nonlocal): + for name in stmt.names: + nonlocal_var_names.append(name) + # Pre-scan ALL nested functions recursively for their nonlocal needs (passthrough) + for stmt in Node.body: + if isinstance(stmt, ast.FunctionDef): + sub_nonlocal_names = self._collect_all_nonlocal_names(stmt) + for name in sub_nonlocal_names: + if name not in nonlocal_var_names: + nonlocal_var_names.append(name) + implicit_names = self._collect_implicit_nonlocal(Node, Gen) + for name in implicit_names: + if name not in nonlocal_var_names: + nonlocal_var_names.append(name) + extra_params = [] + for var_name in nonlocal_var_names: + if var_name in Gen.variables and Gen.variables[var_name] is not None: + var = Gen.variables[var_name] + extra_params.append((var_name, var.type)) + elif var_name in Gen._reg_values: + OldVal = Gen._reg_values[var_name] + var = Gen._alloca_entry(OldVal.type, name=var_name) + Gen._store(OldVal, var) + Gen.variables[var_name] = var + del Gen._reg_values[var_name] + extra_params.append((var_name, var.type)) + else: + # Search outer scope stack for the variable + found_var = None + for scope in reversed(Gen._variable_scope_stack): + if var_name in scope and scope[var_name] is not None: + found_var = scope[var_name] + break + if found_var is not None: + # Add to current scope so it can be passed to nested functions + Gen.variables[var_name] = found_var + extra_params.append((var_name, found_var.type)) + else: + var = Gen._alloca_entry(ir.IntType(32), name=var_name) + Gen.variables[var_name] = var + extra_params.append((var_name, var.type)) + if extra_params: + Gen.nonlocal_params[Node.name] = [(name, ptr_type) for name, ptr_type in extra_params] + # Push current variables to scope stack before compiling nested function + Gen._variable_scope_stack.append(Gen.variables.copy()) + saved_builder = Gen.builder + saved_func = Gen.func + saved_variables = Gen.variables.copy() + saved_reg_values = Gen._reg_values.copy() + saved_global_vars = Gen.global_vars.copy() + saved_var_signedness = Gen.var_signedness.copy() + saved_var_type_info = Gen.var_type_info.copy() + saved_var_type_assignments = Gen.var_type_assignments.copy() + saved_CurrentCReturnTypes = getattr(self.Trans, 'CurrentCReturnTypes', None) + saved_CurrentCpythonObjectClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None) + saved_VarScopes = len(self.Trans.VarScopes) + self.Trans.FunctionHandler._EmitFunctionLlvm(Node, Gen, extra_params=extra_params if extra_params else None) + Gen.builder = saved_builder + Gen.func = saved_func + Gen.variables = saved_variables + Gen._reg_values = saved_reg_values + Gen.global_vars = saved_global_vars + Gen.var_signedness = saved_var_signedness + Gen.var_type_info = saved_var_type_info + Gen.var_type_assignments = saved_var_type_assignments + self.Trans.CurrentCReturnTypes = saved_CurrentCReturnTypes + self.Trans._CurrentCpythonObjectClass = saved_CurrentCpythonObjectClass + while len(self.Trans.VarScopes) > saved_VarScopes: + self.Trans.VarScopes.pop() + # Pop scope stack + if Gen._variable_scope_stack: + Gen._variable_scope_stack.pop() + + def _HandleForListLlvm(self, Node, ArrPtr): + Gen = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Name): + return + TargetName = Node.target.id + ElemType = ArrPtr.type.pointee.element + ArrayCount = ArrPtr.type.pointee.count + IdxVal = Gen._alloca_entry(ir.IntType(32), name=f"arr_idx") + Gen.builder.store(ir.Constant(ir.IntType(32), 0), IdxVal) + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + LoopVar = Gen._alloca_entry(ElemType, name=TargetName) + Gen.variables[TargetName] = LoopVar + Gen._store(ir.Constant(ElemType, None), LoopVar) + CondBB = Gen.func.append_basic_block(name="arrfor.cond") + BodyBB = Gen.func.append_basic_block(name="arrfor.body") + StepBB = Gen.func.append_basic_block(name="arrfor.step") + ElseBB = Gen.func.append_basic_block(name="arrfor.else") if Node.orelse else None + AfterBB = Gen.func.append_basic_block(name="arrfor.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + CurIdx = Gen._load(IdxVal, name="cur_idx") + IsDone = Gen.builder.icmp_signed('<', CurIdx, ir.Constant(ir.IntType(32), ArrayCount), name="arr_in_bounds") + Gen.builder.cbranch(IsDone, BodyBB, ElseBB if ElseBB else AfterBB) + Gen.builder.position_at_start(BodyBB) + ElemPtr = Gen.builder.gep(ArrPtr, [ir.Constant(ir.IntType(32), 0), CurIdx], name="arr_elem_ptr") + ElemVal = Gen._load(ElemPtr, name="arr_elem_val") + Gen._store(ElemVal, LoopVar) + Gen._record_var_signedness(TargetName, 'ptr') + Gen._reg_values[TargetName] = ElemVal + self.HandleBodyLlvm(Node.body) + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is ElemVal: + del Gen._reg_values[TargetName] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + CurIdx2 = Gen._load(IdxVal, name="cur_idx2") + NextIdx = Gen.builder.add(CurIdx2, ir.Constant(ir.IntType(32), 1), name="next_idx") + Gen._store(NextIdx, IdxVal) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleForStrLlvm(self, Node, StrVal): + Gen = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Name): + return + TargetName = Node.target.id + Gen._unregister_temp_ptr(StrVal) + PtrVal = Gen.builder.alloca(ir.IntType(8).as_pointer(), name=f"str_ptr_copy") + Gen.builder.store(StrVal, PtrVal) + CharType = ir.IntType(8) + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + LoopVar = Gen._alloca_entry(CharType, name=TargetName) + Gen.variables[TargetName] = LoopVar + Gen._store(ir.Constant(CharType, 0), LoopVar) + CondBB = Gen.func.append_basic_block(name="strfor.cond") + BodyBB = Gen.func.append_basic_block(name="strfor.body") + StepBB = Gen.func.append_basic_block(name="strfor.step") + ElseBB = Gen.func.append_basic_block(name="strfor.else") if Node.orelse else None + AfterBB = Gen.func.append_basic_block(name="strfor.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + CurrentPtr = Gen._load(PtrVal, name="current_ptr") + RawChar = Gen._load(CurrentPtr, name="raw_char") + NullCond = Gen.builder.icmp_signed('==', RawChar, ir.Constant(CharType, 0), name="is_null") + Gen.builder.cbranch(NullCond, ElseBB if ElseBB else AfterBB, BodyBB) + Gen.builder.position_at_start(BodyBB) + Gen._store(RawChar, LoopVar) + Gen._record_var_signedness(TargetName, 'char') + Gen._reg_values[TargetName] = RawChar + self.HandleBodyLlvm(Node.body) + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is RawChar: + del Gen._reg_values[TargetName] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + CurrentPtr2 = Gen._load(PtrVal, name="current_ptr2") + NextPtr = Gen.builder.gep(CurrentPtr2, [ir.Constant(ir.IntType(32), 1)], name="next_ptr") + Gen._store(NextPtr, PtrVal) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleForIterLlvm(self, Node, ClassName): + Gen = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Name): + return + TargetName = Node.target.id + IterVal = self.HandleExprLlvm(Node.iter) + if not IterVal: + return + Gen._unregister_temp_ptr(IterVal) + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: + IterVal = Gen.builder.bitcast(IterVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + IterCall = Gen._get_function(f'{ClassName}.__iter__') + IterResult = Gen.builder.call(IterCall, [IterVal], name=f"call_{ClassName}.__iter__") + Gen._unregister_temp_ptr(IterResult) + if isinstance(IterResult.type, ir.PointerType) and isinstance(IterResult.type.pointee, ir.IntType) and IterResult.type.pointee.width == 8: + IterResult = Gen.builder.bitcast(IterResult, ir.PointerType(Gen.structs[ClassName]), name=f"cast_iter_{ClassName}") + NextCall = Gen._get_function(f'{ClassName}.__next__') + StopFlagPtr = Gen._alloca_entry(ir.IntType(1), name="stop_iter_flag") + Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) + NextReturnType = NextCall.function_type.return_type + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + LoopVar = Gen._alloca_entry(NextReturnType, name=TargetName) + Gen.variables[TargetName] = LoopVar + CondBB = Gen.func.append_basic_block(name="iter.cond") + BodyBB = Gen.func.append_basic_block(name="iter.body") + StepBB = Gen.func.append_basic_block(name="iter.step") + ElseBB = Gen.func.append_basic_block(name="iter.else") if Node.orelse else None + AfterBB = Gen.func.append_basic_block(name="iter.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) + NextCallArgs = [IterResult, StopFlagPtr] + if NextCall and len(NextCall.function_type.args) > len(NextCallArgs): + last_param_type = NextCall.function_type.args[-1] + if (isinstance(last_param_type, ir.PointerType) + and isinstance(last_param_type.pointee, ir.PointerType) + and isinstance(last_param_type.pointee.pointee, ir.IntType) + and last_param_type.pointee.pointee.width == 8): + null_msg = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") + NextCallArgs.append(null_msg) + NextVal = Gen.builder.call(NextCall, NextCallArgs, name=f"call_{ClassName}.__next__") + StopFlag = Gen.builder.load(StopFlagPtr, name="stop_flag") + Cond = Gen.builder.icmp_signed('==', StopFlag, ir.Constant(ir.IntType(1), 0), name="iter_cond") + Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) + Gen.builder.position_at_start(BodyBB) + Gen._store(NextVal, LoopVar) + Gen._reg_values[TargetName] = NextVal + self.HandleBodyLlvm(Node.body) + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is NextVal: + del Gen._reg_values[TargetName] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py new file mode 100644 index 0000000..e7c0e50 --- /dev/null +++ b/lib/core/Handles/HandlesFunctions.py @@ -0,0 +1,1382 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta +from lib.includes import t +import ast +import llvmlite.ir as ir + + +class FunctionHandle(BaseHandle): + @staticmethod + def _ExtractFuncMeta(decorator_list) -> FuncMeta: + meta = FuncMeta.NONE + if not decorator_list: + return meta + for d in decorator_list: + if isinstance(d, ast.Name): + if d.id == 'staticmethod': + meta |= FuncMeta.STATIC_METHOD + elif d.id == 'property': + meta |= FuncMeta.PROPERTY_GETTER + elif d.id == 'classmethod': + meta |= FuncMeta.CLASS_METHOD + elif isinstance(d, ast.Attribute): + if isinstance(d.value, ast.Name) and d.value.id == 'property': + if d.attr == 'setter': + meta |= FuncMeta.PROPERTY_SETTER + elif d.attr == 'getter': + meta |= FuncMeta.PROPERTY_GETTER + elif d.attr == 'deleter': + meta |= FuncMeta.PROPERTY_DELETER + return meta + + def _body_contains_raise(self, body): + for node in ast.walk(ast.Module(body=body, type_ignores=[])): + if isinstance(node, ast.Raise): + if node.exc: + if isinstance(node.exc, ast.Name) and node.exc.id == 'StopIteration': + continue + if isinstance(node.exc, ast.Call) and isinstance(node.exc.func, ast.Name) and node.exc.func.id == 'StopIteration': + continue + return True + if isinstance(node, ast.Call): + called_name = None + if isinstance(node.func, ast.Name): + called_name = node.func.id + elif isinstance(node.func, ast.Attribute): + called_name = node.func.attr + if called_name: + Gen = self.Trans.LlvmGen + for prefix in ['', f'{called_name}.', f'__']: + for suffix in ['', f'.{called_name}']: + fname = f'{prefix}{called_name}{suffix}' + if fname in Gen.functions: + func = Gen.functions[fname] + if len(func.args) > 0: + for arg in func.args: + if hasattr(arg, 'name') and arg.name in ('__eh_msg_out__', '__eh_code_out__'): + return True + break + return False + + _LLVM_ATTR_NAMES = frozenset({ + 'nobuiltin', 'nounwind', 'noredzone', 'willreturn', 'mustprogress', + 'optnone', 'noinline', 'alwaysinline', 'readnone', 'readonly', + 'writeonly', 'inaccessiblememonly', 'inaccessiblemem_or_argmemonly', + }) + + def _ExtractLLVMAttrs(self, node): + attrs = [] + if isinstance(node, ast.BinOp): + attrs.extend(self._ExtractLLVMAttrs(node.left)) + attrs.extend(self._ExtractLLVMAttrs(node.right)) + elif isinstance(node, ast.Attribute): + attr_name = self._GetAttrLLVMName(node) + if attr_name: + attrs.append(attr_name) + return attrs + + def _GetAttrLLVMName(self, node): + if not isinstance(node, ast.Attribute): + return None + if node.attr not in self._LLVM_ATTR_NAMES: + return None + value = node.value + if not isinstance(value, ast.Attribute) or value.attr != 'llvm': + return None + inner = value.value + if not isinstance(inner, ast.Attribute) or inner.attr != 'attr': + return None + if not isinstance(inner.value, ast.Name) or inner.value.id != 't': + return None + return node.attr + + def _infer_return_type_from_body(self, Node, Gen=None, ClassName=None): + local_var_types = {} + for child in ast.walk(Node): + if isinstance(child, ast.Assign) and len(child.targets) == 1: + target = child.targets[0] + if isinstance(target, ast.Name) and isinstance(child.value, ast.Subscript): + sub = child.value + if (isinstance(sub.value, ast.Attribute) + and isinstance(sub.value.value, ast.Name) + and sub.value.value.id == 'self' + and ClassName and ClassName in Gen.class_members): + member_name = sub.value.attr + for m_name, m_type in Gen.class_members[ClassName]: + if m_name == member_name: + if isinstance(m_type, ir.ArrayType): + elem_type = m_type.element + if isinstance(elem_type, ir.FloatType): + local_var_types[target.id] = ('float', False) + elif isinstance(elem_type, ir.DoubleType): + local_var_types[target.id] = ('double', False) + elif isinstance(elem_type, ir.IntType): + if elem_type.width == 8: + local_var_types[target.id] = ('char', False) + else: + local_var_types[target.id] = ('int', False) + elif isinstance(elem_type, ir.PointerType): + if isinstance(elem_type.pointee, ir.IntType) and elem_type.pointee.width == 8: + local_var_types[target.id] = ('char', True) + else: + local_var_types[target.id] = ('void', True) + elif isinstance(elem_type, ir.IdentifiedStructType): + struct_name = elem_type.name + if struct_name: + for sn, st in Gen.structs.items(): + if st.name == struct_name or sn == struct_name: + local_var_types[target.id] = (sn, False) + break + else: + local_var_types[target.id] = (elem_type.name, False) + elif isinstance(m_type, ir.PointerType): + pointee = m_type.pointee + if isinstance(pointee, ir.FloatType): + local_var_types[target.id] = ('float', False) + elif isinstance(pointee, ir.DoubleType): + local_var_types[target.id] = ('double', False) + elif isinstance(pointee, ir.IntType): + if pointee.width == 8: + local_var_types[target.id] = ('char', False) + else: + local_var_types[target.id] = ('int', False) + elif isinstance(pointee, ir.PointerType): + local_var_types[target.id] = ('void', True) + elif isinstance(pointee, ir.IdentifiedStructType): + for sn, st in Gen.structs.items(): + if st == pointee or st.name == pointee.name: + local_var_types[target.id] = (sn, True) + break + break + for child in ast.walk(Node): + if isinstance(child, ast.Return) and child.value: + val = child.value + if isinstance(val, ast.Name) and val.id == 'self' and ClassName: + return (ClassName, True) + if isinstance(val, ast.Call): + if isinstance(val.func, ast.Name): + callee = val.func.id + if callee == 'malloc': + return ('char', True) + if callee == 'chr': + return ('char', False) + if Gen and callee in Gen.functions: + func = Gen.functions[callee] + if hasattr(func, 'ftype'): + ret_type = func.ftype.return_type + if isinstance(ret_type, ir.PointerType): + if isinstance(ret_type.pointee, ir.IntType) and ret_type.pointee.width == 8: + return ('char', True) + return ('void', True) + elif isinstance(ret_type, ir.IntType): + if ret_type.width == 8: + return ('char', False) + return ('int', False) + elif isinstance(ret_type, ir.VoidType): + return ('void', False) + elif isinstance(val.func, ast.Attribute): + pass + callee_name = None + if isinstance(val.func, ast.Name): + callee_name = val.func.id + elif isinstance(val.func, ast.Attribute): + callee_name = getattr(val.func, 'attr', None) + if callee_name: + sym = self.Trans.SymbolTable.get(callee_name) + if sym and isinstance(sym, dict): + ret_type_str = sym.get('return_type', '') + if ret_type_str and ret_type_str != 'int': + is_ptr = sym.get('is_ptr', False) + return (ret_type_str, is_ptr) + elif isinstance(val, ast.Constant): + if val.value is None: + return ('char', True) + elif isinstance(val.value, str) and len(val.value) <= 1: + return ('char', True) + elif isinstance(val, ast.Name): + var_name = val.id + if var_name in local_var_types: + return local_var_types[var_name] + var_info = self.Trans.SymbolTable.get(var_name) + if var_info and isinstance(var_info, dict): + var_type = var_info.get('type', '') + if var_type and var_type != 'int': + is_ptr = var_info.get('is_ptr', False) + return (var_type, is_ptr) + elif isinstance(val, ast.Subscript): + if (isinstance(val.value, ast.Attribute) + and isinstance(val.value.value, ast.Name) + and val.value.value.id == 'self' + and ClassName): + member_name = val.value.attr + if ClassName in Gen.class_members: + for m_name, m_type in Gen.class_members[ClassName]: + if m_name == member_name: + if isinstance(m_type, ir.ArrayType): + elem_type = m_type.element + if isinstance(elem_type, ir.FloatType): + return ('float', False) + elif isinstance(elem_type, ir.DoubleType): + return ('double', False) + elif isinstance(elem_type, ir.IntType): + if elem_type.width == 8: + return ('char', False) + return ('int', False) + elif isinstance(elem_type, ir.PointerType): + if isinstance(elem_type.pointee, ir.IntType) and elem_type.pointee.width == 8: + return ('char', True) + return ('void', True) + elif isinstance(elem_type, ir.IdentifiedStructType): + struct_name = elem_type.name + if struct_name: + for sn, st in Gen.structs.items(): + if st.name == struct_name or sn == struct_name: + return (sn, False) + return (elem_type.name, False) + elif isinstance(m_type, ir.PointerType): + pointee = m_type.pointee + if isinstance(pointee, ir.FloatType): + return ('float', False) + elif isinstance(pointee, ir.DoubleType): + return ('double', False) + elif isinstance(pointee, ir.IntType): + if pointee.width == 8: + return ('char', False) + return ('int', False) + elif isinstance(pointee, ir.PointerType): + return ('void', True) + elif isinstance(pointee, ir.IdentifiedStructType): + for sn, st in Gen.structs.items(): + if st == pointee or st.name == pointee.name: + return (sn, True) + return (pointee.name, True) + break + if isinstance(val.value, ast.Name): + var_name = val.value.id + var_info = self.Trans.SymbolTable.get(var_name) + if var_info and isinstance(var_info, dict): + var_type = var_info.get('type', '') + if var_type.startswith('list[') or var_type.startswith('List['): + inner = var_type[var_type.index('[') + 1:var_type.rindex(']')] + parts = inner.split(',') + elem_type_str = parts[0].strip() + if elem_type_str and elem_type_str != 'int': + is_ptr = var_info.get('is_ptr', False) + return (elem_type_str, is_ptr) + return None + + def _GetFunctionSignatureLlvm(self, Node, Gen, ClassName=None, extra_params=None): + RawFuncName = Node.name + if ClassName: + FuncName = f"{ClassName}.{RawFuncName}" + else: + FuncName = RawFuncName + # property setter/deleter 使用不同的函数名后缀,避免与 getter 冲突 + func_meta = self._ExtractFuncMeta(Node.decorator_list) + if FuncMeta.PROPERTY_SETTER in func_meta: + FuncName = FuncName + '$set' + elif FuncMeta.PROPERTY_DELETER in func_meta: + FuncName = FuncName + '$del' + CReturnTypes = [] + if Node.decorator_list: + for decorator in Node.decorator_list: + if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): + if decorator.func.attr == 'CReturn': + for arg in decorator.args: + CReturnTypes.append(arg) + if Node.returns: + llvm_attrs = self._ExtractLLVMAttrs(Node.returns) + if llvm_attrs: + if not hasattr(self, '_pending_llvm_attrs'): + self._pending_llvm_attrs = {} + self._pending_llvm_attrs[FuncName] = llvm_attrs + if isinstance(Node.returns, ast.Subscript) and isinstance(Node.returns.value, ast.Name) and Node.returns.value.id == 'tuple': + slice_node = Node.returns.slice + if isinstance(slice_node, ast.Tuple): + for elt in slice_node.elts: + CReturnTypes.append(elt) + else: + CReturnTypes.append(slice_node) + IsPtr = False + ReturnTypeInfo = None + if Node.returns: + if CReturnTypes: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CVoid() + else: + try: + if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): + ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns) + if not isinstance(ReturnTypeInfo, CTypeInfo): + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CVoid() + if (ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or ReturnTypeInfo.PtrCount >= 2: + def _FindNonVoidCTypeInfo(node): + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + results = [] + for child in [node.left, node.right]: + r = _FindNonVoidCTypeInfo(child) + if r and not r.IsVoid: + results.append(r) + for r in results: + if not r.IsPtr and not r.IsStruct: + return r + return results[0] if results else None + try: + SideInfo = CTypeInfo.FromNode(node, self.Trans.SymbolTable) + if SideInfo: + return SideInfo + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + return None + found = _FindNonVoidCTypeInfo(Node.returns) + if found and not found.IsVoid: + ReturnTypeInfo = found + if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + else: + is_str_type = False + if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'): + is_str_type = True + ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) + if ReturnTypeInfo and ReturnTypeInfo.IsDefine: + inferred = self._infer_return_type_from_body(Node, Gen, ClassName) + if inferred: + ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0]) + ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0 + else: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + if not hasattr(self, '_cdefine_funcs'): + self._cdefine_funcs = set() + self._cdefine_funcs.add(FuncName) + elif ReturnTypeInfo and ReturnTypeInfo.IsState: + if ReturnTypeInfo.PtrCount > 0 or (ReturnTypeInfo.BaseType and not isinstance(ReturnTypeInfo.BaseType, t.CVoid)): + pass + else: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CVoid() + if ReturnTypeInfo is None: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CVoid() + if is_str_type or ReturnTypeInfo.IsStr: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CChar() + ReturnTypeInfo.PtrCount = 1 + if ReturnTypeInfo.IsVoid and not ReturnTypeInfo.IsState: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + except Exception: # 回退:设置默认返回类型为 CInt + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + else: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + inferred = self._infer_return_type_from_body(Node, Gen, ClassName) + if inferred: + ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0]) + ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0 + IsPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False + ReturnType = Gen._ctype_to_llvm(ReturnTypeInfo) + if isinstance(ReturnType, ir.PointerType) and isinstance(ReturnType.pointee, ir.PointerType): + if isinstance(ReturnType.pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + ReturnType = ir.PointerType(ReturnType.pointee.pointee) + if isinstance(ReturnType, ir.IntType) and ReturnType.width == 8: + if RawFuncName == '__str__': + ReturnType = ir.PointerType(ir.IntType(8)) + if isinstance(ReturnType, ir.VoidType) and FuncName == 'main': + ReturnType = ir.IntType(32) + IsMethod = False + IsClassMethod = False + ResolvedClassName = ClassName + func_meta = self._ExtractFuncMeta(Node.decorator_list) + if not ResolvedClassName: + for potential_class in Gen.class_methods: + if FuncName.startswith(f"{potential_class}."): + IsMethod = True + ResolvedClassName = potential_class + break + else: + IsMethod = FuncMeta.STATIC_METHOD not in func_meta and FuncMeta.CLASS_METHOD not in func_meta + IsClassMethod = FuncMeta.CLASS_METHOD in func_meta + if RawFuncName == '__init__': + IsMethod = False + ParamTypes = [] + ParamNames = [] + ParamTypeStrs = [] + CReturnLlvmTypes = [] + if CReturnTypes: + for i, ReturnTypeNode in enumerate(CReturnTypes): + ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable) + if ReturnTypeInfo and ReturnTypeInfo.IsStr: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CChar() + ReturnTypeInfo.PtrCount = 1 + if ReturnTypeInfo is None: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + RetType = Gen._ctype_to_llvm(ReturnTypeInfo) + CReturnLlvmTypes.append(RetType) + ReturnType = ir.LiteralStructType(CReturnLlvmTypes) + for Arg in Node.args.args: + if Arg.annotation: + try: + if isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr): + ParamTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Arg.annotation) + if ParamTypeInfo is None: + ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable) + else: + ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable) + if ParamTypeInfo is None: + ParamTypeInfo = CTypeInfo() + ParamTypeInfo.BaseType = t.CInt() + IsPtr = ParamTypeInfo.IsPtr + if ParamTypeInfo and getattr(ParamTypeInfo, 'IsCpythonObject', False) and not IsPtr: + IsPtr = True + ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1) + if ParamTypeInfo.IsStr or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')): + ParamTypeInfo = CTypeInfo() + ParamTypeInfo.BaseType = t.CChar() + ParamTypeInfo.PtrCount = 1 + IsPtr = True + ParamType = Gen._ctype_to_llvm(ParamTypeInfo) + ParamTypeStr = ParamTypeInfo + except Exception as e: + ParamType = ir.IntType(32) + ParamTypeStr = CTypeInfo() + ParamTypeStr.BaseType = t.CInt() + else: + if ClassName and Arg.arg != 'self': + op_method_names = ['__add__', '__sub__', '__mul__', '__truediv__', '__floordiv__', '__mod__', '__pow__', + '__radd__', '__rsub__', '__rmul__', '__rtruediv__', '__rfloordiv__', '__rmod__', '__rpow__', + '__iadd__', '__isub__', '__imul__', '__itruediv__', '__ifloordiv__', '__imod__', '__ipow__', + '__eq__', '__ne__', '__lt__', '__le__', '__gt__', '__ge__', + '__neg__', '__pos__', '__abs__', '__call__'] + if RawFuncName in op_method_names and ClassName in Gen.structs: + ParamType = ir.PointerType(Gen.structs[ClassName]) + else: + ParamType = ir.IntType(32) + else: + ParamType = ir.IntType(32) + ParamTypeStr = CTypeInfo() + ParamTypeStr.BaseType = t.CInt() + ParamTypes.append(ParamType) + ParamNames.append(Arg.arg) + ParamTypeStrs.append(ParamTypeStr) + if IsMethod and ResolvedClassName and ResolvedClassName in Gen.structs: + StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName]) + SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1) + if SelfIdx >= 0: + ParamTypes[SelfIdx] = StructPtrType + else: + ParamTypes.insert(0, StructPtrType) + ParamNames.insert(0, "self") + ParamTypeStrs.insert(0, f"struct {ResolvedClassName}") + elif not IsMethod and ResolvedClassName and ResolvedClassName in Gen.structs: + SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1) + if SelfIdx >= 0: + StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName]) + ParamTypes[SelfIdx] = StructPtrType + # @classmethod: 将 cls 参数设为类指针类型 + if IsClassMethod: + ClsIdx = next((i for i, n in enumerate(ParamNames) if n == "cls"), -1) + if ClsIdx >= 0: + StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName]) + ParamTypes[ClsIdx] = StructPtrType + IsVariadic = Node.args.vararg is not None + if extra_params: + for var_name, ptr_type in extra_params: + ParamTypes.append(ptr_type) + ParamNames.append(f'__nonlocal_{var_name}__') + if IsMethod and RawFuncName == '__next__': + ParamTypes.append(ir.PointerType(ir.IntType(1))) + ParamNames.append('__stop_iter_flag__') + HasRaise = self._body_contains_raise(Node.body) + if HasRaise and RawFuncName != 'main': + ParamTypes.append(ir.PointerType(ir.PointerType(ir.IntType(8)))) + ParamNames.append('__eh_msg_out__') + ParamTypes.append(ir.PointerType(ir.IntType(32))) + ParamNames.append('__eh_code_out__') + FuncType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic) + return FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, CReturnTypes, IsMethod, ResolvedClassName, IsVariadic + + def _is_generic_function(self, Node): + if hasattr(Node, 'type_params') and Node.type_params: + return True + return False + + def _mangle_generic_name(self, func_name, type_args, has_cexport=False): + from lib.includes.t import CTypeRegistry + mangled_args = [] + for ta in type_args: + llvm_str = CTypeRegistry.NameToLLVM(ta) + if llvm_str: + if llvm_str in ('float', 'double', 'half', 'fp128'): + mangled = 'f' + str(CTypeRegistry.GetClassByName(ta)().Size) + else: + mangled = llvm_str + else: + mangled = ta + mangled_args.append(mangled) + if has_cexport: + return func_name + '_T_' + '_'.join(mangled_args) + return func_name + '[' + ']['.join(mangled_args) + ']' + + def _apply_type_map_to_node(self, Node, type_map): + for arg in Node.args.args: + if arg.annotation: + arg.annotation = self._replace_type_in_annotation(arg.annotation, type_map) + if Node.returns: + Node.returns = self._replace_type_in_annotation(Node.returns, type_map) + self._apply_type_map_to_body(Node.body, type_map) + + def _replace_type_in_annotation(self, node, type_map): + if isinstance(node, ast.Name): + if node.id in type_map: + replacement = type_map[node.id] + return ast.Name(id=replacement, ctx=ast.Load()) + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + node.left = self._replace_type_in_annotation(node.left, type_map) + node.right = self._replace_type_in_annotation(node.right, type_map) + elif isinstance(node, ast.Attribute): + if hasattr(node, 'attr') and node.attr in type_map: + replacement = type_map[node.attr] + return ast.Name(id=replacement, ctx=ast.Load()) + return node + + def _apply_type_map_to_body(self, body, type_map): + for stmt in body: + self._apply_type_map_to_stmt(stmt, type_map) + + def _apply_type_map_to_stmt(self, node, type_map): + if isinstance(node, ast.Return) and node.value: + self._apply_type_map_to_expr(node.value, type_map) + elif isinstance(node, ast.Assign): + for t in node.targets: + self._apply_type_map_to_expr(t, type_map) + self._apply_type_map_to_expr(node.value, type_map) + elif isinstance(node, ast.AnnAssign): + if node.annotation: + node.annotation = self._replace_type_in_annotation(node.annotation, type_map) + if node.value: + self._apply_type_map_to_expr(node.value, type_map) + elif isinstance(node, ast.AugAssign): + self._apply_type_map_to_expr(node.target, type_map) + self._apply_type_map_to_expr(node.value, type_map) + elif isinstance(node, ast.Expr): + self._apply_type_map_to_expr(node.value, type_map) + elif isinstance(node, ast.If): + self._apply_type_map_to_expr(node.test, type_map) + for s in node.body: + self._apply_type_map_to_stmt(s, type_map) + for s in node.orelse: + self._apply_type_map_to_stmt(s, type_map) + elif isinstance(node, ast.For): + self._apply_type_map_to_expr(node.iter, type_map) + for s in node.body: + self._apply_type_map_to_stmt(s, type_map) + elif isinstance(node, ast.While): + self._apply_type_map_to_expr(node.test, type_map) + for s in node.body: + self._apply_type_map_to_stmt(s, type_map) + + def _apply_type_map_to_expr(self, node, type_map): + if node is None: + return + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Name) and node.func.id in type_map: + replacement = type_map[node.func.id] + node.func = ast.Name(id=replacement, ctx=ast.Load()) + elif isinstance(node.func, ast.Attribute): + if isinstance(node.func.value, ast.Name) and node.func.value.id in type_map: + replacement = type_map[node.func.value.id] + node.func.value = ast.Name(id=replacement, ctx=ast.Load()) + for arg in node.args: + self._apply_type_map_to_expr(arg, type_map) + elif isinstance(node, ast.Attribute): + if isinstance(node.value, ast.Name) and node.value.id in type_map: + replacement = type_map[node.value.id] + node.value = ast.Name(id=replacement, ctx=ast.Load()) + elif isinstance(node, ast.BinOp): + self._apply_type_map_to_expr(node.left, type_map) + self._apply_type_map_to_expr(node.right, type_map) + elif isinstance(node, ast.UnaryOp): + self._apply_type_map_to_expr(node.operand, type_map) + elif isinstance(node, ast.Compare): + self._apply_type_map_to_expr(node.left, type_map) + for comp in node.comparators: + self._apply_type_map_to_expr(comp, type_map) + elif isinstance(node, ast.BoolOp): + for val in node.values: + self._apply_type_map_to_expr(val, type_map) + elif isinstance(node, ast.IfExp): + self._apply_type_map_to_expr(node.test, type_map) + self._apply_type_map_to_expr(node.body, type_map) + self._apply_type_map_to_expr(node.orelse, type_map) + + def _infer_type_arg_from_value(self, val, Gen): + if val is None: + return 'int' + if isinstance(val.type, ir.IntType): + if val.type.width == 64: + return 'i64' + elif val.type.width == 16: + return 'i16' + elif val.type.width == 8: + return 'i8' + return 'int' + elif isinstance(val.type, ir.DoubleType): + return 'double' + elif isinstance(val.type, ir.FloatType): + return 'float' + elif isinstance(val.type, ir.PointerType): + return 'void*' + return 'int' + + def _specialize_generic_function(self, FuncName, type_args, Gen): + if not hasattr(self, '_generic_templates') or FuncName not in self._generic_templates: + return None + template = self._generic_templates[FuncName] + Node = template['node'] + type_param_names = template['type_params'] + ClassName = template['class_name'] + if len(type_args) != len(type_param_names): + return None + spec_key = FuncName + '<' + ','.join(type_args) + '>' + if not hasattr(self, '_generic_specializations'): + self._generic_specializations = {} + if spec_key in self._generic_specializations: + return self._generic_specializations[spec_key] + has_cexport = False + if Node.returns: + try: + if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): + RetTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Node.returns) + else: + RetTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) + if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport): + has_cexport = True + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + spec_name = self._mangle_generic_name(FuncName, type_args, has_cexport) + type_map = {} + for i, tp_name in enumerate(type_param_names): + type_map[tp_name] = type_args[i] + import copy + SpecNode = copy.deepcopy(Node) + SpecNode.type_params = [] + SpecNode.name = spec_name + self._apply_type_map_to_node(SpecNode, type_map) + if has_cexport: + if not hasattr(Gen, '_export_funcs'): + Gen._export_funcs = set() + Gen._export_funcs.add(spec_name) + saved_builder = Gen.builder + saved_variables = dict(Gen.variables) if Gen.variables else {} + saved_direct_values = dict(Gen._direct_values) if Gen._direct_values else {} + saved_var_type_info = dict(Gen.var_type_info) if Gen.var_type_info else {} + saved_var_signedness = dict(Gen.var_signedness) if Gen.var_signedness else {} + saved_global_vars = set(Gen.global_vars) if Gen.global_vars else set() + saved_var_scopes = [dict(s) for s in self.Trans.VarScopes] if self.Trans.VarScopes else [] + saved_func = Gen.func + saved_current_func_name = getattr(Gen, '_current_func_name', None) + saved_block = None + if Gen.builder and Gen.builder.block and not Gen.builder.block.is_terminated: + saved_block = Gen.builder.block + self._EmitFunctionForwardDeclLlvm(SpecNode, Gen, ClassName=ClassName) + self._EmitFunctionLlvm(SpecNode, Gen, ClassName=ClassName) + Gen.builder = saved_builder + if saved_block is not None and Gen.builder is not None: + Gen.builder.position_at_end(saved_block) + Gen.variables = saved_variables + Gen._direct_values = saved_direct_values + Gen.var_type_info = saved_var_type_info + Gen.var_signedness = saved_var_signedness + Gen.global_vars = saved_global_vars + Gen.func = saved_func + if saved_current_func_name is not None: + Gen._current_func_name = saved_current_func_name + self.Trans.VarScopes = saved_var_scopes + self._generic_specializations[spec_key] = spec_name + if not hasattr(self.Trans, '_generic_specializations'): + self.Trans._generic_specializations = {} + self.Trans._generic_specializations[spec_key] = spec_name + return spec_name + + def _EmitFunctionForwardDeclLlvm(self, Node, Gen, ClassName=None): + if self._is_generic_function(Node): + if not hasattr(self, '_generic_templates'): + self._generic_templates = {} + RawFuncName = Node.name + if ClassName: + FuncName = f"{ClassName}.{RawFuncName}" + else: + FuncName = RawFuncName + type_params = [tp.name for tp in Node.type_params] + self._generic_templates[FuncName] = { + 'node': Node, + 'type_params': type_params, + 'class_name': ClassName, + } + return + result = self._GetFunctionSignatureLlvm(Node, Gen, ClassName) + if result is None: + return + FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, CReturnTypes, IsMethod, ResolvedClassName, IsVariadic = result + if Node.returns: + try: + RetTypeInfo = None + if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): + RetTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns) + else: + RetTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) + if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport) and not RetTypeInfo.IsState: + Gen._export_funcs.add(FuncName) + if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExtern): + Gen._export_funcs.add(FuncName) + if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState: + Gen._export_funcs.add(FuncName) # t.State 标记的函数必须保持原始名称,以便链接器解析 + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + MangledName = Gen._mangle_func_name(FuncName) + need_new = MangledName not in Gen.functions + if not need_new: + existing = Gen.functions[MangledName] + if getattr(existing, 'name', MangledName) != MangledName: + need_new = True + if need_new: + try: + func = ir.Function(Gen.module, FuncType, name=MangledName) + func.attributes.add('noredzone') + if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs: + func.linkage = 'linkonce_odr' + func.attributes.add('alwaysinline') + if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs: + for attr_name in self._pending_llvm_attrs[FuncName]: + try: + func.attributes.add(attr_name) + except Exception: + pass + Gen.functions[MangledName] = func + Gen.functions[FuncName] = func + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + else: + existing = Gen.functions[MangledName] + existing_type = getattr(existing, 'ftype', None) + if existing_type and existing_type != FuncType: + Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType) + Gen.functions[FuncName] = Gen.functions[MangledName] + elif not existing_type: + try: + Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType) + Gen.functions[FuncName] = Gen.functions[MangledName] + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + self.Trans.FunctionDefCache[FuncName] = Node + + def _replace_function_decl(self, Gen, FuncName, NewFuncType): + MangledName = Gen._mangle_func_name(FuncName) + old_func = Gen.functions.get(MangledName) + if old_func is None: + try: + return ir.Function(Gen.module, NewFuncType, name=MangledName) + except Exception: # 回退:函数已存在时返回旧函数 + return old_func + try: + old_name = old_func.name + if old_name in getattr(Gen.module, 'globals', {}): + del Gen.module.globals[old_name] + module_scope = getattr(Gen.module, 'scope', None) + if getattr(module_scope, '_useset', None): + module_scope._useset.discard(old_name) + if getattr(Gen.module, '_guessed_names', None): + Gen.module._guessed_names.discard(FuncName) + new_func = ir.Function(Gen.module, NewFuncType, name=MangledName) + Gen.functions[MangledName] = new_func + Gen.functions[FuncName] = new_func + return new_func + except Exception as ex: + import traceback + traceback.print_exc() + Gen.functions[MangledName] = old_func + Gen.functions[FuncName] = old_func + return old_func + + def _EmitFunctionLlvm(self, Node, Gen, ClassName=None, extra_params=None): + if self._is_generic_function(Node): + return + RawFuncName = Node.name + if ClassName: + FuncName = f"{ClassName}.{RawFuncName}" + else: + FuncName = RawFuncName + CReturnTypes = [] + IsPtr = False + fn_attrs = {} + # 自定义行为装饰器列表,用于生成 wrapper 函数 + # 任何 @name 或 @name(args) 只要不是内置装饰器,都视为自定义行为装饰器 + behavior_decorators = [] + # 内置装饰器名称,这些由编译器特殊处理,不作为行为装饰器 + _BUILTIN_DECORATORS = {'staticmethod', 'property', 'classmethod'} + if Node.decorator_list: + for decorator in Node.decorator_list: + # 识别自定义行为装饰器:@name(ast.Name 形式) + if isinstance(decorator, ast.Name): + if decorator.id not in _BUILTIN_DECORATORS: + behavior_decorators.append({'name': decorator.id, 'args': [], 'kwargs': {}}) + continue + # 识别带参数的自定义行为装饰器:@name(arg1, key=val)(ast.Call + ast.Name 形式) + if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Name): + deco_name = decorator.func.id + if deco_name not in _BUILTIN_DECORATORS: + deco_info = {'name': deco_name, 'args': [], 'kwargs': {}} + for arg in decorator.args: + if isinstance(arg, ast.Constant): + deco_info['args'].append(arg.value) + for kw in decorator.keywords: + if isinstance(kw.value, ast.Constant): + deco_info['kwargs'][kw.arg] = kw.value.value + behavior_decorators.append(deco_info) + continue + if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): + if decorator.func.attr == 'CReturn': + for arg in decorator.args: + CReturnTypes.append(arg) + elif decorator.func.attr == 'Attribute' and isinstance(decorator.func.value, ast.Name) and decorator.func.value.id == 'c': + for arg in decorator.args: + if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute): + if isinstance(arg.func.value, ast.Attribute) and isinstance(arg.func.value.value, ast.Name) and arg.func.value.value.id == 't' and arg.func.value.attr == 'attr': + attr_name = arg.func.attr + str_args = [a.value for a in arg.args if isinstance(a, ast.Constant) and isinstance(a.value, str)] + int_args = [a.value for a in arg.args if isinstance(a, ast.Constant) and isinstance(a.value, int)] + if attr_name == 'section' and str_args: + fn_attrs['section'] = str_args[0] + elif attr_name == 'aligned' and int_args: + fn_attrs['aligned'] = int_args[0] + elif attr_name == 'visibility' and str_args: + fn_attrs['visibility'] = str_args[0] + elif attr_name in ('noreturn', 'always_inline', 'noinline', 'cold', 'hot', 'constructor', 'destructor', 'pure', 'const', 'malloc', 'returns_nonnull', 'used', 'naked', 'no_instrument_function', 'warn_unused_result', 'weak', 'fallthrough'): + if not arg.args: + fn_attrs[attr_name] = True + elif isinstance(arg.func.value, ast.Attribute) and arg.func.value.attr == 'llvm' and isinstance(arg.func.value.value, ast.Attribute) and arg.func.value.value.attr == 'attr' and isinstance(arg.func.value.value.value, ast.Name) and arg.func.value.value.value.id == 't': + llvm_attr_name = arg.func.attr + if llvm_attr_name in self._LLVM_ATTR_NAMES: + fn_attrs[f'llvm.{llvm_attr_name}'] = True + elif isinstance(arg, ast.Attribute): + if isinstance(arg.value, ast.Attribute) and isinstance(arg.value.value, ast.Name) and arg.value.value.id == 't' and arg.value.attr == 'attr': + attr_name = arg.attr + if attr_name in ('noreturn', 'always_inline', 'noinline', 'cold', 'hot', 'constructor', 'destructor', 'pure', 'const', 'malloc', 'returns_nonnull', 'used', 'naked', 'no_instrument_function', 'warn_unused_result', 'weak', 'fallthrough', 'packed'): + fn_attrs[attr_name] = True + elif isinstance(arg.value, ast.Attribute) and arg.value.attr == 'llvm' and isinstance(arg.value.value, ast.Attribute) and arg.value.value.attr == 'attr' and isinstance(arg.value.value.value, ast.Name) and arg.value.value.value.id == 't': + llvm_attr_name = arg.attr + if llvm_attr_name in self._LLVM_ATTR_NAMES: + fn_attrs[f'llvm.{llvm_attr_name}'] = True + if Node.returns: + if isinstance(Node.returns, ast.Subscript) and isinstance(Node.returns.value, ast.Name) and Node.returns.value.id == 'tuple': + slice_node = Node.returns.slice + if isinstance(slice_node, ast.Tuple): + for elt in slice_node.elts: + CReturnTypes.append(elt) + else: + CReturnTypes.append(slice_node) + + # 先强制检查 str 类型注解 + is_str_return = False + ReturnTypeInfo = None + if Node.returns: + if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'): + is_str_return = True + else: + try: + rt_info = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) + if rt_info and rt_info.IsStr: + is_str_return = True + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + + if is_str_return: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CChar() + ReturnTypeInfo.PtrCount = 1 + elif Node.returns: + if CReturnTypes: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CVoid() + else: + try: + if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): + ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns) + if not isinstance(ReturnTypeInfo, CTypeInfo): + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CVoid() + if (ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or ReturnTypeInfo.PtrCount >= 2: + def _FindNonVoidCTypeInfo(node): + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + results = [] + for child in [node.left, node.right]: + r = _FindNonVoidCTypeInfo(child) + if r and not r.IsVoid: + results.append(r) + for r in results: + if not r.IsPtr and not r.IsStruct: + return r + return results[0] if results else None + try: + SideInfo = CTypeInfo.FromNode(node, self.Trans.SymbolTable) + if SideInfo: + return SideInfo + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + return None + found = _FindNonVoidCTypeInfo(Node.returns) + if found and not found.IsVoid: + ReturnTypeInfo = found + if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + else: + is_str_type = False + if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'): + is_str_type = True + ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) + if ReturnTypeInfo and ReturnTypeInfo.IsDefine: + inferred = self._infer_return_type_from_body(Node, Gen, ClassName) + if inferred: + ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0]) + ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0 + else: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + if not hasattr(self, '_cdefine_funcs'): + self._cdefine_funcs = set() + self._cdefine_funcs.add(FuncName) + elif ReturnTypeInfo and ReturnTypeInfo.IsState: + pass # t.State is a modifier, preserve the actual return type + if ReturnTypeInfo is None: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CVoid() + if is_str_type or ReturnTypeInfo.IsStr: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CChar() + ReturnTypeInfo.PtrCount = 1 + if ReturnTypeInfo.IsVoid and not ReturnTypeInfo.IsState: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + except Exception: # 回退:设置默认返回类型为 CInt + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + else: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + inferred = self._infer_return_type_from_body(Node, Gen, ClassName) + if inferred: + ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0]) + ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0 + + ReturnType = Gen._ctype_to_llvm(ReturnTypeInfo) + + if isinstance(ReturnType, ir.VoidType) and FuncName == 'main': + ReturnType = ir.IntType(32) + IsMethod = False + IsClassMethod = False + ResolvedClassName = ClassName + func_meta = self._ExtractFuncMeta(Node.decorator_list) + if not ResolvedClassName: + for potential_class in Gen.class_methods: + if FuncName.startswith(f"{potential_class}."): + IsMethod = True + ResolvedClassName = potential_class + break + else: + IsMethod = FuncMeta.STATIC_METHOD not in func_meta and FuncMeta.CLASS_METHOD not in func_meta + IsClassMethod = FuncMeta.CLASS_METHOD in func_meta + if RawFuncName == '__init__': + IsMethod = False + # __new__ methods should return a pointer to the struct (for heap allocation replacement) + if RawFuncName == '__new__' and ResolvedClassName: + StructType = Gen.structs.get(ResolvedClassName) + if StructType: + if isinstance(StructType, ir.PointerType): + ReturnType = StructType + else: + ReturnType = ir.PointerType(StructType) + ParamTypes = [] + ParamNames = [] + ParamTypeStrs = [] + self.Trans.VarScopes.append({}) + for Arg in Node.args.args: + ParamIsUnsigned = False + if Arg.annotation: + try: + if isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr): + ParamTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Arg.annotation) + if ParamTypeInfo is None: + ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable) + else: + ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable) + if ParamTypeInfo is None: + ParamTypeInfo = CTypeInfo() + ParamTypeInfo.BaseType = t.CInt() + IsPtr = ParamTypeInfo.IsPtr + if ParamTypeInfo and getattr(ParamTypeInfo, 'IsCpythonObject', False) and not IsPtr: + IsPtr = True + ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1) + if ParamTypeInfo.IsStr or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')): + ParamTypeInfo = CTypeInfo() + ParamTypeInfo.BaseType = t.CChar() + ParamTypeInfo.PtrCount = 1 + IsPtr = True + ParamType = Gen._ctype_to_llvm(ParamTypeInfo) + if ParamTypeInfo and ParamTypeInfo.IsFuncPtr: + ParamType = ir.IntType(8).as_pointer() + ParamIsUnsigned = ParamTypeInfo.IsUInt + except Exception: # 回退:参数类型解析失败时使用默认 i32 + ParamType = ir.IntType(32) + ParamTypeInfo = CTypeInfo() + ParamTypeInfo.BaseType = t.CInt() + else: + ParamType = ir.IntType(32) + ParamTypeInfo = CTypeInfo() + ParamTypeInfo.BaseType = t.CInt() + ParamTypes.append(ParamType) + ParamNames.append(Arg.arg) + ParamTypeStrs.append(ParamTypeInfo) + Gen._record_var_signedness(Arg.arg, ParamIsUnsigned) + self.Trans.VarScopes[-1][Arg.arg] = ParamTypeInfo + if Arg.annotation: + try: + if isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr): + PInfo = self.Trans.TypeMergeHandler.MergeTypes(Arg.annotation) + if PInfo is None: + PInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable) + else: + PInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable) + if PInfo and (PInfo.DataConst or PInfo.VarConst): + Gen.var_const_flags[Arg.arg] = True + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + if CReturnTypes: + CReturnLlvmTypes = [] + for i, ReturnTypeNode in enumerate(CReturnTypes): + ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable) + if ReturnTypeInfo and ReturnTypeInfo.IsStr: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CChar() + ReturnTypeInfo.PtrCount = 1 + if ReturnTypeInfo is None: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + RetType = Gen._ctype_to_llvm(ReturnTypeInfo) + CReturnLlvmTypes.append(RetType) + ReturnType = ir.LiteralStructType(CReturnLlvmTypes) + self.Trans.CurrentCReturnTypes = CReturnTypes + else: + self.Trans.CurrentCReturnTypes = None + if IsMethod and ResolvedClassName and ResolvedClassName in Gen.structs: + StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName]) + SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1) + if SelfIdx >= 0: + ParamTypes[SelfIdx] = StructPtrType + else: + ParamTypes.insert(0, StructPtrType) + ParamNames.insert(0, "self") + elif not IsMethod and ResolvedClassName and ResolvedClassName in Gen.structs: + SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1) + if SelfIdx >= 0: + StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName]) + ParamTypes[SelfIdx] = StructPtrType + # @classmethod: 将 cls 参数设为类指针类型 + if IsClassMethod: + ClsIdx = next((i for i, n in enumerate(ParamNames) if n == "cls"), -1) + if ClsIdx >= 0: + StructPtrType = ir.PointerType(Gen.structs[ResolvedClassName]) + ParamTypes[ClsIdx] = StructPtrType + IsVariadic = Node.args.vararg is not None + if extra_params: + for var_name, ptr_type in extra_params: + ParamTypes.append(ptr_type) + ParamNames.append(f'__nonlocal_{var_name}__') + HasStopIterFlag = False + if IsMethod and RawFuncName == '__next__': + ParamTypes.append(ir.PointerType(ir.IntType(1))) + ParamNames.append('__stop_iter_flag__') + HasStopIterFlag = True + HasRaise = self._body_contains_raise(Node.body) + if HasRaise and RawFuncName != 'main': + ParamTypes.append(ir.PointerType(ir.PointerType(ir.IntType(8)))) + ParamNames.append('__eh_msg_out__') + ParamTypes.append(ir.PointerType(ir.IntType(32))) + ParamNames.append('__eh_code_out__') + FuncType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic) + self.Trans.FunctionDefCache[FuncName] = Node + IsInlineFunc = False + IsExternFunc = False + IsStateFunc = False + if Node.returns: + try: + RetTypeInfo = None + if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): + RetTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns) + else: + RetTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) + if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CInline): + IsInlineFunc = True + if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport) and not RetTypeInfo.IsState: + Gen._export_funcs.add(FuncName) + if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExtern): + IsExternFunc = True + Gen._export_funcs.add(FuncName) + if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState: + IsStateFunc = True + Gen._export_funcs.add(FuncName) # 外部 C 函数声明必须保持原始名称 + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + MangledName = Gen._mangle_func_name(FuncName) + if MangledName in Gen.functions: + func = Gen.functions[MangledName] + if getattr(func, 'name', MangledName) != MangledName: + func = ir.Function(Gen.module, FuncType, name=MangledName) + Gen.functions[MangledName] = func + else: + existing_type = getattr(func, 'ftype', None) + if existing_type and existing_type != FuncType: + func = self._replace_function_decl(Gen, FuncName, FuncType) + else: + func = ir.Function(Gen.module, FuncType, name=MangledName) + Gen.functions[MangledName] = func + Gen.functions[FuncName] = func + func.attributes.add('noredzone') + if IsInlineFunc: + func.linkage = 'linkonce_odr' + func.attributes.add('alwaysinline') + if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs: + func.linkage = 'linkonce_odr' + func.attributes.add('alwaysinline') + if fn_attrs: + _LLVM_FN_ATTR_MAP = { + 'noreturn': 'noreturn', + 'always_inline': 'alwaysinline', + 'noinline': 'noinline', + 'cold': 'cold', + 'hot': 'hot', + 'constructor': 'constructor', + 'destructor': 'destructor', + 'malloc': 'malloc', + 'returns_nonnull': 'returns_nonnull', + 'used': 'used', + 'naked': 'naked', + 'no_instrument_function': 'no_instrument_function', + 'warn_unused_result': 'warn_unused_result', + 'fallthrough': 'fallthrough', + 'pure': 'readonly', + 'const': 'readnone', + } + if 'section' in fn_attrs: + func.section = fn_attrs['section'] + if 'visibility' in fn_attrs: + func.linkage = 'internal' + func.attributes.add('visibility') + if fn_attrs.get('weak'): + func.linkage = 'weak' + for attr_name, llvm_name in _LLVM_FN_ATTR_MAP.items(): + if fn_attrs.get(attr_name): + try: + func.attributes.add(llvm_name) + except Exception: + pass + for key in fn_attrs: + if key.startswith('llvm.'): + llvm_attr_name = key[5:] + try: + func.attributes.add(llvm_attr_name) + except Exception: + pass + if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs: + for attr_name in self._pending_llvm_attrs.pop(FuncName): + try: + func.attributes.add(attr_name) + except Exception: + pass + # 记录自定义行为装饰器信息,供 DecoratorPass 使用 + if behavior_decorators: + if not hasattr(Gen, '_decorated_funcs'): + Gen._decorated_funcs = {} + Gen._decorated_funcs[MangledName] = { + 'decorators': behavior_decorators, + 'func_name': FuncName, + 'func_type': FuncType, + 'return_type': FuncType.return_type, + 'param_types': [p.type for p in func.args], + 'param_names': ParamNames, + 'is_export': FuncName in Gen._export_funcs, + } + if IsExternFunc or IsStateFunc: + return + EntryBlock = func.append_basic_block(name="entry") + Gen.builder = ir.IRBuilder(EntryBlock) + Gen.func = func + Gen.variables = {} + Gen._reg_values = {} + Gen.global_vars = set() + if 'aligned' in fn_attrs: + Gen._emit_stack_align(fn_attrs['aligned']) + # 保存当前的 var_type_info,以便函数结束时恢复 + saved_var_type_info = Gen.var_type_info.copy() + saved_var_type_assignments = Gen.var_type_assignments.copy() + # 函数内部定义的变量会在赋值时添加到 var_type_info 中 + # 这样函数内部定义的元类型变量(如 a = t.CInt32T)就能被正确处理 + for stmt in Node.body: + if isinstance(stmt, ast.Global): + for gname in stmt.names: + Gen.global_vars.add(gname) + if gname in Gen.module.globals: + Gen.variables[gname] = Gen.module.globals[gname] + for param, param_name in zip(func.args, ParamNames): + param.name = param_name + if param_name == '__stop_iter_flag__': + Gen._stop_iter_flag_param = param + Gen.builder.store(ir.Constant(ir.IntType(1), 0), param) + elif param_name.startswith('__nonlocal_') and param_name.endswith('__'): + var_name = param_name[len('__nonlocal_'):-2] + Gen.variables[var_name] = param + else: + if isinstance(param.type, ir.PointerType) and isinstance(param.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + var = Gen.builder.alloca(param.type, name=param_name) + Gen._store(param, var) + Gen.variables[param_name] = var + for CN, ST in Gen.structs.items(): + if param.type.pointee == ST or (isinstance(param.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and param.type.pointee.name == ST.name): + Gen.var_struct_class[param_name] = CN + break + elif isinstance(param.type, (ir.LiteralStructType, ir.IdentifiedStructType)): + var = Gen.builder.alloca(param.type, name=param_name) + Gen._store(param, var) + Gen.variables[param_name] = var + for CN, ST in Gen.structs.items(): + if param.type == ST or (isinstance(param.type, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and param.type.name == ST.name): + Gen.var_struct_class[param_name] = CN + break + else: + # 所有参数都存入 alloca,确保循环体中对参数的修改能正确反映 + var = Gen._alloca_entry(param.type, name=param_name) + Gen._store(param, var) + Gen.variables[param_name] = var + if ResolvedClassName and (IsMethod or RawFuncName == '__init__'): + self.Trans._CurrentCpythonObjectClass = ResolvedClassName + Gen._variadic_info = None + if IsVariadic and Node.args.vararg: + vararg_name = getattr(Node.args.vararg, 'arg', 'args') + last_param_name = ParamNames[-1] if ParamNames else None + last_param_ptr = None + for param, pn in zip(func.args, ParamNames): + if pn == last_param_name: + last_param_ptr = param + break + triple = getattr(Gen, 'module_triple', '') or getattr(Gen.module, 'triple', '') + is_windows = 'windows' in triple if triple else False + ptr_size = getattr(Gen, 'ptr_size', 8) + # va_list 大小取决于 ABI:Windows x64 = 1个指针,Linux x64 = __va_list_tag[1](24字节) + # 32位平台:Windows = 4字节指针,Linux = 12字节 + if ptr_size == 4: + va_list_size = 4 if is_windows else 12 + va_list_align = 4 + else: + va_list_size = 8 if is_windows else 24 + va_list_align = 8 if is_windows else 16 + va_list_type = ir.ArrayType(ir.IntType(8), va_list_size) + va_list_alloc = Gen._alloca_entry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align) + va_list_ptr = Gen.builder.bitcast(va_list_alloc, ir.IntType(8).as_pointer(), name=f"{vararg_name}_va_list_i8ptr") + Gen._variadic_info = { + 'vararg_name': vararg_name, + 'va_list_ptr': va_list_ptr, + 'last_param_ptr': last_param_ptr, + 'va_start_called': False, + } + if last_param_ptr: + last_param_alloc = Gen._alloca_entry(last_param_ptr.type, name="last_param_copy") + Gen.builder.store(last_param_ptr, last_param_alloc) + Gen.emit_va_start(va_list_ptr) + Gen._variadic_info['va_start_called'] = True + Gen.variables[vararg_name] = va_list_ptr + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + if 'naked' in fn_attrs: + Gen.builder.unreachable() + return + Gen._emit_local_heap_frees() + if Gen._variadic_info and Gen._variadic_info.get('va_start_called'): + va_list_ptr = Gen._variadic_info.get('va_list_ptr') + if va_list_ptr: + Gen.emit_va_end(va_list_ptr) + ActualReturnType = func.function_type.return_type + if isinstance(ActualReturnType, ir.VoidType): + Gen.builder.ret_void() + elif isinstance(ActualReturnType, ir.IntType): + Gen.builder.ret(ir.Constant(ActualReturnType, 0)) + elif isinstance(ActualReturnType, (ir.FloatType, ir.DoubleType)): + Gen.builder.ret(ir.Constant(ActualReturnType, 0.0)) + elif isinstance(ActualReturnType, ir.PointerType): + Gen.builder.ret(ir.Constant(ActualReturnType, None)) + elif isinstance(ActualReturnType, ir.IdentifiedStructType): + if ActualReturnType.elements: + zero_val = ir.Constant(ActualReturnType, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ActualReturnType.elements]) + else: + zero_val = ir.Constant(ActualReturnType, None) + Gen.builder.ret(zero_val) + elif isinstance(ActualReturnType, ir.ArrayType): + Gen.builder.ret(ir.Constant(ActualReturnType, None)) + else: + Gen.builder.ret_void() + Gen.builder = None + Gen.func = None + Gen.variables = {} + Gen.var_signedness = {} + Gen._reg_values = {} + Gen._direct_values = {} + Gen.var_struct_class = {} + Gen.var_const_flags = {} + # 恢复保存的 var_type_info + Gen.var_type_info = saved_var_type_info + Gen.var_type_assignments = saved_var_type_assignments + Gen._stop_iter_flag_param = None + Gen._local_heap_ptrs = [] + Gen._var_to_heap_ptr = {} + Gen._variadic_info = None + self.Trans._CurrentCpythonObjectClass = None + self.Trans.CurrentCReturnTypes = None + if self.Trans.VarScopes: + self.Trans.VarScopes.pop() + self.Trans.FunctionReturnTypes[FuncName] = ReturnTypeInfo + if FuncName not in self.Trans.SymbolTable: + FuncInfo = CTypeInfo() + FuncInfo.Name = FuncName + FuncInfo.IsFunction = True + FuncInfo.MetaList = func_meta + if IsInlineFunc: + FuncInfo.IsInline = True + FuncInfo.InlineBody = Node.body + FuncInfo.InlineParams = [arg.arg for arg in Node.args.args] + self.Trans.SymbolTable[FuncName] = FuncInfo + else: + existing = self.Trans.SymbolTable[FuncName] + if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE: + existing.MetaList = func_meta + if IsInlineFunc: + existing.IsInline = True + existing.InlineBody = Node.body + existing.InlineParams = [arg.arg for arg in Node.args.args] + return func diff --git a/lib/core/Handles/HandlesIf.py b/lib/core/Handles/HandlesIf.py new file mode 100644 index 0000000..f11f3d6 --- /dev/null +++ b/lib/core/Handles/HandlesIf.py @@ -0,0 +1,302 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import llvmlite.ir as ir +import ast + + +class IfHandle(BaseHandle): + def _get_attr_full_name(self, node): + if isinstance(node, ast.Attribute): + parts = [] + cur = node + while isinstance(cur, ast.Attribute): + parts.append(cur.attr) + cur = cur.value + if isinstance(cur, ast.Name): + parts.append(cur.id) + parts.reverse() + return '.'.join(parts) + return None + + def _is_cif_call(self, node): + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': + return node.func.attr in ('CIf', 'CIfdef', 'CIfndef') + if isinstance(node.func, ast.Name): + return node.func.id in ('CIf', 'CIfdef', 'CIfndef') + return False + + def _resolve_macro_name(self, arg): + if isinstance(arg, ast.Name): + return arg.id + if isinstance(arg, ast.Constant) and isinstance(arg.value, str): + return arg.value + if isinstance(arg, ast.Attribute): + full_name = self._get_attr_full_name(arg) + if full_name: + return full_name + return None + + def _evaluate_cif_condition(self, node): + if not isinstance(node, ast.Call): + return None + args = node.args + if not args: + return False + if isinstance(node.func, ast.Attribute): + kind = node.func.attr + elif isinstance(node.func, ast.Name): + kind = node.func.id + else: + return None + if kind == 'CIfdef': + name = self._resolve_macro_name(args[0]) + if name is None: + return False + return self._is_macro_defined(name) + elif kind == 'CIfndef': + name = self._resolve_macro_name(args[0]) + if name is None: + return True + return not self._is_macro_defined(name) + elif kind == 'CIf': + return self._eval_const_expr(args[0]) + return None + + def _is_macro_defined(self, name): + Gen = self.Trans.LlvmGen + if hasattr(Gen, '_define_constants') and name in Gen._define_constants: + return True + if name in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[name] + if getattr(info, 'IsDefine', False): + return True + platform_macros = self._get_platform_macros() + return name in platform_macros + + def _get_macro_value(self, name): + Gen = self.Trans.LlvmGen + if hasattr(Gen, '_define_constants') and name in Gen._define_constants: + val = Gen._define_constants[name] + if isinstance(val, (int, float)): + return val + if name in self.Trans.SymbolTable: + info = self.Trans.SymbolTable[name] + if getattr(info, 'IsDefine', False): + val = getattr(info, 'DefineValue', 0) + if isinstance(val, (int, float)): + return val + platform_macros = self._get_platform_macros() + if name in platform_macros: + return platform_macros[name] + return None + + def _get_platform_macros(self): + Gen = self.Trans.LlvmGen + macros = {} + pi = getattr(Gen, '_platform_info', {}) + ptr_size = getattr(Gen, 'ptr_size', 8) + # 根据目标平台设置宏(从三元组推导) + if pi.get('is_windows'): + macros['_WIN32'] = 1 + if not pi.get('is_32bit'): + macros['_WIN64'] = 1 + macros['WIN64'] = 1 + macros['WIN32'] = 1 + if pi.get('is_linux'): + macros['__linux__'] = 1 + if pi.get('is_macos'): + macros['__APPLE__'] = 1 + macros['__MACH__'] = 1 + if pi.get('is_x86_64'): + macros['__x86_64__'] = 1 + macros['__x86_64'] = 1 + macros['_M_X64'] = 1 + elif pi.get('is_arm64'): + macros['__aarch64__'] = 1 + macros['_M_ARM64'] = 1 + if not pi.get('is_32bit') and pi.get('is_linux'): + macros['__LP64__'] = 1 + elif pi.get('is_32bit'): + macros['_ILP32'] = 1 + macros['SIZEOF_VOID_P'] = ptr_size + macros['__SIZEOF_POINTER__'] = ptr_size + macros['NDEBUG'] = 0 + return macros + + def _eval_const_expr(self, node): + if isinstance(node, ast.Constant): + val = node.value + if isinstance(val, bool): + return 1 if val else 0 + if isinstance(val, int): + return val + if isinstance(val, float): + return 1 if val != 0.0 else 0 + return 0 + if isinstance(node, ast.Name): + name = node.id + val = self._get_macro_value(name) + if val is not None: + return val + return None + if isinstance(node, ast.Attribute): + full_key = self._get_attr_full_name(node) + if full_key: + val = self._get_macro_value(full_key) + if val is not None: + return val + short_name = full_key.split('.')[-1] if '.' in full_key else full_key + val = self._get_macro_value(short_name) + if val is not None: + return val + return None + if isinstance(node, ast.UnaryOp): + operand = self._eval_const_expr(node.operand) + if operand is None: + return None + if isinstance(node.op, ast.Not): + return 1 if not operand else 0 + if isinstance(node.op, ast.USub): + return -operand + if isinstance(node.op, ast.Invert): + return ~operand + return None + if isinstance(node, ast.BinOp): + left = self._eval_const_expr(node.left) + right = self._eval_const_expr(node.right) + if left is None or right is None: + return None + try: + if isinstance(node.op, ast.Add): + return left + right + elif isinstance(node.op, ast.Sub): + return left - right + elif isinstance(node.op, ast.Mult): + return left * right + elif isinstance(node.op, ast.FloorDiv): + return left // right if right != 0 else 0 + elif isinstance(node.op, ast.Mod): + return left % right if right != 0 else 0 + elif isinstance(node.op, ast.LShift): + return left << right + elif isinstance(node.op, ast.RShift): + return left >> right + elif isinstance(node.op, ast.BitOr): + return left | right + elif isinstance(node.op, ast.BitAnd): + return left & right + elif isinstance(node.op, ast.BitXor): + return left ^ right + except Exception: + return None + return None + if isinstance(node, ast.BoolOp): + if isinstance(node.op, ast.And): + for val in node.values: + result = self._eval_const_expr(val) + if result is None: + return None + if not result: + return 0 + return 1 + elif isinstance(node.op, ast.Or): + for val in node.values: + result = self._eval_const_expr(val) + if result is None: + return None + if result: + return 1 + return 0 + if isinstance(node, ast.Compare): + left = self._eval_const_expr(node.left) + if left is None: + return None + for op, comparator in zip(node.ops, node.comparators): + right = self._eval_const_expr(comparator) + if right is None: + return None + if isinstance(op, ast.Eq): + result = left == right + elif isinstance(op, ast.NotEq): + result = left != right + elif isinstance(op, ast.Lt): + result = left < right + elif isinstance(op, ast.LtE): + result = left <= right + elif isinstance(op, ast.Gt): + result = left > right + elif isinstance(op, ast.GtE): + result = left >= right + else: + return None + if not result: + return 0 + return 1 + if isinstance(node, ast.Call): + if self._is_cif_call(node): + return self._evaluate_cif_condition(node) + return None + + def _HandleIfLlvm(self, Node): + Gen = self.Trans.LlvmGen + if self._is_cif_call(Node.test): + compile_time_val = self._evaluate_cif_condition(Node.test) + if compile_time_val is not None: + if compile_time_val: + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + elif Node.orelse: + if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): + self._HandleIfLlvm(Node.orelse[0]) + else: + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + return + Cond = self.Trans.ExprHandler.HandleExprLlvm(Node.test) + if not Cond: + return + is_const = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1 + if is_const: + if Cond.constant: + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + elif Node.orelse: + if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): + self._HandleIfLlvm(Node.orelse[0]) + else: + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + return + if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1: + ClassName = self.Trans.ExprHandler._get_var_class(Node.test, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__bool__'): + obj_val = Cond + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__") + if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1: + Cond = Gen.builder.icmp_signed('!=', Cond, Gen._zero_const(Cond.type), name="bool_result") + else: + if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)): + Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond") + else: + Cond = Gen.builder.icmp_signed('!=', Cond, Gen._zero_const(Cond.type), name="ifcond") + ThenBB = Gen.func.append_basic_block(name="then") + ElseBB = Gen.func.append_basic_block(name="else") if Node.orelse else None + MergeBB = Gen.func.append_basic_block(name="endif") + if not Gen.builder.block.is_terminated: + Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB) + Gen.builder.position_at_start(ThenBB) + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(MergeBB) + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(MergeBB) + if not MergeBB.is_terminated: + Gen.builder.position_at_start(MergeBB) + else: + Gen.builder.position_at_end(MergeBB) diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py new file mode 100644 index 0000000..620b5a7 --- /dev/null +++ b/lib/core/Handles/HandlesImports.py @@ -0,0 +1,1884 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta +from lib.includes import t +import ast +import os +import hashlib +import llvmlite.ir as ir + + +class ImportHandle(BaseHandle): + _stub_cache = {} + _stub_cache_dir = None + _struct_load_cache = {} + _pyi_cache = {} + _pyi_cache_dir = None + _project_root_cache = None + + def _reset_file_cache(self): + self._struct_load_cache.clear() + + def _find_project_root(self): + if self._project_root_cache is not None: + return self._project_root_cache + import os + current_file = getattr(self.Trans, 'CurrentFile', '') or '' + if current_file: + current_dir = os.path.dirname(os.path.abspath(current_file)) + search_dir = current_dir + for _ in range(10): + if os.path.isdir(os.path.join(search_dir, 'temp')) and os.path.isdir(os.path.join(search_dir, 'output')): + self._project_root_cache = search_dir + return search_dir + parent = os.path.dirname(search_dir) + if parent == search_dir: + break + search_dir = parent + self._project_root_cache = current_dir + return current_dir + self._project_root_cache = os.getcwd() + return os.getcwd() + + def _EmitImportDeclarationsLlvm(self, Node, Gen): + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + if not getattr(self.Trans, '_import_aliases', None): + self.Trans._import_aliases = {} + for alias in Node.names: + name = alias.name + if name in ('c', 't'): + continue + self.Trans._imported_modules.add(name) + if alias.asname: + self.Trans._import_aliases[alias.asname] = name + # 同时在符号表中注册模块别名,以便 CTypeInfo.FromNode 能解析 + AliasInfo = CTypeInfo() + AliasInfo.IsModuleAlias = True + AliasInfo.ResolvedModule = name + self.Trans.SymbolTable[alias.asname] = AliasInfo + current_module = self._get_current_module_name() + self._EmitModuleDeclarationsLlvm(name, Gen, register_module_name=current_module) + + def _RegisterFromImportAliases(self, Node, Gen, module): + """Register 'from module import y as z' aliases after module declarations are loaded""" + if not Node.names: + return + for alias in Node.names: + name = alias.name + asname = alias.asname + # For 'from X import Y' (no asname), register CDefine constants + # into _define_constants so they can be found by _HandleNameLlvm + if not asname or asname == name: + # Check if this name is a CDefine constant in SymbolTable + sym_info = self.Trans.SymbolTable.get(name) + if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None: + define_constants = vars(Gen).setdefault('_define_constants', {}) + if name not in define_constants: + define_constants[name] = sym_info.DefineValue + # Also check with module prefix + for prefix_key in [f"{module}.{name}", name]: + sym_info2 = self.Trans.SymbolTable.get(prefix_key) + if sym_info2 and getattr(sym_info2, 'IsDefine', None) and getattr(sym_info2, 'DefineValue', None) is not None: + define_constants = vars(Gen).setdefault('_define_constants', {}) + if name not in define_constants: + define_constants[name] = sym_info2.DefineValue + break + continue + if not hasattr(self.Trans, '_t_c_imported_names'): + self.Trans._t_c_imported_names = {} + self.Trans._t_c_imported_names[asname] = (module, name) + if name in Gen.functions: + Gen.functions[asname] = Gen.functions[name] + if name in Gen.structs: + Gen.structs[asname] = Gen.structs[name] + if name in self.Trans.SymbolTable: + self.Trans.SymbolTable[asname] = self.Trans.SymbolTable[name] + if name in Gen.variables: + Gen.variables[asname] = Gen.variables[name] + if name in Gen.global_vars: + Gen.global_vars[asname] = Gen.global_vars[name] + for func_name in list(Gen.functions.keys()): + if func_name.startswith(f'{name}.'): + method_suffix = func_name[len(name):] + Gen.functions[f'{asname}{method_suffix}'] = Gen.functions[func_name] + for key in list(self.Trans.SymbolTable.keys()): + if key.startswith(f'{name}.'): + suffix = key[len(name):] + self.Trans.SymbolTable[f'{asname}{suffix}'] = self.Trans.SymbolTable[key] + for meta_dict in (Gen.class_members, Gen.class_member_defaults, + Gen.class_member_signeds, Gen.class_member_bitfields, + Gen.class_member_byteorders, Gen.class_member_bitoffsets, + Gen.class_methods): + if name in meta_dict: + meta_dict[asname] = meta_dict[name] + if name in Gen.class_vtable: + Gen.class_vtable.add(asname) + if name in Gen.class_packed: + Gen.class_packed.add(asname) + struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) + if name in struct_sha1_map: + struct_sha1_map[asname] = struct_sha1_map[name] + + def _EmitImportFromDeclarationsLlvm(self, Node, Gen): + module = Node.module if Node.module else '' + if module in ('c', 't'): + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + if not getattr(self.Trans, '_import_aliases', None): + self.Trans._import_aliases = {} + self.Trans._imported_modules.add(module) + if not hasattr(self.Trans, '_t_c_imported_names'): + self.Trans._t_c_imported_names = {} + for alias in Node.names: + name = alias.name + asname = alias.asname or name + self.Trans._t_c_imported_names[asname] = (module, name) + return + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + if not getattr(self.Trans, '_import_aliases', None): + self.Trans._import_aliases = {} + current_module = self._get_current_module_name() + if Node.level and Node.level > 0: + current_file = getattr(self.Trans, 'CurrentFile', '') or '' + current_dir = os.path.dirname(os.path.abspath(current_file)) + parent_dir = current_dir + for _ in range(Node.level - 1): + parent_dir = os.path.dirname(parent_dir) + if module: + SearchExtensions = ['.pyi', '.py'] + sub_path_base = os.path.join(parent_dir, module) + for ext in SearchExtensions: + candidate = sub_path_base + ext + if os.path.isfile(candidate): + self.Trans._imported_modules.add(module) + self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module, register_module_name=current_module) + self._RegisterFromImportAliases(Node, Gen, module) + return + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + # 尝试完整模块名和短模块名 + full_mod_name = f"{current_module}.{module}" if current_module else module + target_sha1 = module_sha1_map.get(full_mod_name) or module_sha1_map.get(module) + if target_sha1: + temp_dir = getattr(Gen, '_temp_dir', None) + if temp_dir: + sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") + if os.path.isfile(sha1_pyi): + self.Trans._imported_modules.add(module) + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module, register_module_name=current_module) + self._RegisterFromImportAliases(Node, Gen, module) + return + else: + mod_dir = parent_dir + + SearchExtensions = ['.pyi', '.py'] + pkg_name = '' + if not module: + # When 'from . import name' is used, load the package's __init__ + # to make package-level names (functions, classes, constants) available + pkg_name = self._LoadPackageInitForRelativeImport(mod_dir, Gen, current_module) + + # Also try to load each alias as a submodule + for alias in Node.names: + found_sub = False + for ext in SearchExtensions: + sub_path = os.path.join(mod_dir, alias.name + ext) + if os.path.isfile(sub_path): + self.Trans._imported_modules.add(alias.name) + self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=alias.name, register_module_name=current_module) + if alias.asname: + self.Trans._import_aliases[alias.asname] = alias.name + found_sub = True + break + if not found_sub: + # SHA1 map fallback for submodule + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + sub_module_path = f"{pkg_name}.{alias.name}" if pkg_name else alias.name + target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name) + if target_sha1: + temp_dir = getattr(Gen, '_temp_dir', None) + if temp_dir: + sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") + if os.path.isfile(sha1_pyi): + self.Trans._imported_modules.add(sub_module_path) + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=current_module) + if alias.asname: + self.Trans._import_aliases[alias.asname] = alias.name + self._RegisterFromImportAliases(Node, Gen, module or pkg_name) + return + self.Trans._imported_modules.add(module) + self._EmitModuleDeclarationsLlvm(module, Gen, register_module_name=current_module) + self._RegisterFromImportAliases(Node, Gen, module) + + def _LoadModuleDeclarationsFromFile(self, pyi_path, Gen, module_name=None, register_module_name=None, actual_module_name=None, reexport_package=None): + if not pyi_path or not os.path.isfile(pyi_path): + return + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + ModuleCode = f.read() + ModuleTree = ast.parse(ModuleCode) + for node in ModuleTree.body: + if isinstance(node, ast.FunctionDef): + if node.name in ('va_start', 'va_arg', 'va_end'): + continue + file_module_name = os.path.splitext(os.path.basename(pyi_path))[0] + effective_register = register_module_name or module_name + reexport_names = [] + if module_name and module_name != file_module_name and module_name != effective_register: + reexport_names.append(module_name) + # When loading a submodule for 'from .xxx import yyy' inside a package's __init__.py, + # re-export functions under the package name so 'pkg.func()' resolves correctly + if reexport_package and reexport_package != file_module_name and reexport_package not in reexport_names: + reexport_names.append(reexport_package) + self._EmitExternalFuncDeclLlvm(node, Gen, source_module_name=file_module_name, register_module_name=effective_register, reexport_module_names=reexport_names if reexport_names else None) + elif isinstance(node, ast.AnnAssign): + self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=pyi_path) + elif isinstance(node, ast.Assign): + self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=pyi_path) + elif isinstance(node, ast.ClassDef): + if hasattr(node, 'type_params') and node.type_params: + if not hasattr(self.Trans.ClassHandler, '_generic_class_templates'): + self.Trans.ClassHandler._generic_class_templates = {} + type_params = [tp.name for tp in node.type_params] + self.Trans.ClassHandler._generic_class_templates[node.name] = { + 'node': node, + 'type_params': type_params, + } + self._EmitExternalClassDeclLlvm(node, Gen, module_name=module_name, actual_module_name=actual_module_name) + elif isinstance(node, ast.ImportFrom): + if node.level > 0: + current_dir = os.path.dirname(os.path.abspath(pyi_path)) + parent_dir = current_dir + for _ in range(node.level - 1): + parent_dir = os.path.dirname(parent_dir) + if node.module: + SearchExtensions = ['.pyi', '.py'] + sub_path_base = os.path.join(parent_dir, node.module) + found_sub = False + for ext in SearchExtensions: + candidate = sub_path_base + ext + if os.path.isfile(candidate): + actual_module = f"{register_module_name}.{node.module}" if register_module_name else node.module + self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen) + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + self.Trans._imported_modules.add(actual_module) + for alias in node.names: + if alias.name == '*': + self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) + else: + self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=reexport_package or module_name) + found_sub = True + break + # SHA1 map 回退 + if not found_sub: + actual_module = f"{register_module_name}.{node.module}" if register_module_name else node.module + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + target_sha1 = module_sha1_map.get(actual_module) or module_sha1_map.get(node.module) + if target_sha1: + temp_dir = getattr(Gen, '_temp_dir', None) + if temp_dir: + sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") + if os.path.isfile(sha1_pyi): + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + self.Trans._imported_modules.add(actual_module) + for alias in node.names: + if alias.name == '*': + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) + else: + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=reexport_package or module_name) + else: + mod_dir = parent_dir + SearchExtensions = ['.pyi', '.py'] + # Load __init__.py to make package-level names available + self._LoadPackageInitForRelativeImport(mod_dir, Gen, register_module_name) + for alias in node.names: + found_alias = False + for ext in SearchExtensions: + sub_path = os.path.join(mod_dir, alias.name + ext) + if os.path.isfile(sub_path): + sub_module_path = f"{register_module_name}.{alias.name}" if register_module_name else alias.name + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + self.Trans._imported_modules.add(sub_module_path) + if alias.name == '*': + self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) + else: + self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) + found_alias = True + break + # SHA1 map 回退 + if not found_alias: + sub_module_path = f"{register_module_name}.{alias.name}" if register_module_name else alias.name + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name) + if target_sha1: + temp_dir = getattr(Gen, '_temp_dir', None) + if temp_dir: + sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") + if os.path.isfile(sha1_pyi): + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + self.Trans._imported_modules.add(sub_module_path) + if alias.name == '*': + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) + else: + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=reexport_package or module_name) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + + def _get_current_module_name(self): + current_file = getattr(self.Trans, 'CurrentFile', '') or '' + if current_file: + return os.path.splitext(os.path.basename(current_file))[0] + return None + + def _RegisterSubModuleSha1(self, candidate_path, actual_module, short_module, Gen): + """Register a submodule's SHA1 in module_sha1_map so cross-module class references work""" + try: + with open(candidate_path, 'r', encoding='utf-8') as f: + sub_content = f.read() + sub_sha1 = hashlib.sha1(sub_content.encode('utf-8')).hexdigest()[:16] + if hasattr(Gen, 'module_sha1_map'): + Gen.module_sha1_map[actual_module] = sub_sha1 + if short_module and short_module not in Gen.module_sha1_map: + Gen.module_sha1_map[short_module] = sub_sha1 + except Exception: + pass + + def _LoadPackageInitForRelativeImport(self, mod_dir, Gen, register_module_name): + """Load __init__.py from the package directory for 'from . import name' resolution. + This makes package-level names (functions, classes, constants) available. + Returns the package name.""" + pkg_name = os.path.basename(mod_dir) + init_loaded = False + + # 跳过当前正在编译的文件,避免重复加载导致 class_members 重复 + current_sha1 = getattr(Gen, 'module_sha1', None) + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + pkg_sha1 = module_sha1_map.get(pkg_name) + if pkg_sha1 and pkg_sha1 == current_sha1: + return pkg_name + + # Try SHA1 map first (correct mangled names from stub) + if pkg_sha1: + temp_dir = getattr(Gen, '_temp_dir', None) + if temp_dir: + sha1_pyi = os.path.join(temp_dir, f"{pkg_sha1}.pyi") + if os.path.isfile(sha1_pyi): + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=pkg_name, register_module_name=register_module_name) + init_loaded = True + + # Fallback: try loading __init__.py directly from the package directory + if not init_loaded: + for ext in ['.pyi', '.py']: + init_path = os.path.join(mod_dir, '__init__' + ext) + if os.path.isfile(init_path): + self._LoadModuleDeclarationsFromFile(init_path, Gen, module_name=pkg_name, register_module_name=register_module_name) + init_loaded = True + break + + return pkg_name + + def _EmitModuleDeclarationsLlvm(self, module_name, Gen, register_module_name=None): + if module_name in ('pyzlib',): + source_sig_files = getattr(self.Trans, '_source_module_sig_files', None) + ModulePath = module_name.replace('.', os.sep) + '.pyi' + PackageInitPath = module_name.replace('.', os.sep) + os.sep + '__init__.pyi' + ProjectRoot = os.path.dirname(os.path.abspath(getattr(self.Trans, 'CurrentFile', '') or '')) or os.getcwd() + + import inspect + HandlesFile = os.path.abspath(inspect.getfile(self.__class__)) + TransPyCRoot = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(HandlesFile)))) + + FullModulePath = None + SearchDirs = [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths) + + for LibPath in SearchDirs: + SearchPath = os.path.join(ProjectRoot, LibPath) if not os.path.isabs(LibPath) else LibPath + CandidatePath = os.path.join(SearchPath, ModulePath) + if os.path.isfile(CandidatePath): + FullModulePath = CandidatePath + break + CandidatePath = os.path.join(SearchPath, PackageInitPath) + if os.path.isfile(CandidatePath): + FullModulePath = CandidatePath + break + ModuleParts = ModulePath.split(os.sep) + if len(ModuleParts) > 1: + LibPathBasename = os.path.basename(LibPath.rstrip('/\\')) + if LibPathBasename == ModuleParts[0]: + RemainingPath = os.sep.join(ModuleParts[1:]) + CandidatePath = os.path.join(SearchPath, RemainingPath) + if os.path.isfile(CandidatePath): + FullModulePath = CandidatePath + break + if not FullModulePath: + ModulePathPy = module_name.replace('.', os.sep) + '.py' + PackageInitPathPy = module_name.replace('.', os.sep) + os.sep + '__init__.py' + SearchDirsForPy = [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths) + for LibPath in SearchDirsForPy: + SearchPath = os.path.join(ProjectRoot, LibPath) if not os.path.isabs(LibPath) else LibPath + CandidatePath = os.path.join(SearchPath, ModulePathPy) + if os.path.isfile(CandidatePath): + FullModulePath = CandidatePath + break + CandidatePath = os.path.join(SearchPath, PackageInitPathPy) + if os.path.isfile(CandidatePath): + FullModulePath = CandidatePath + break + if not FullModulePath or not os.path.isfile(FullModulePath): + source_sig_files = getattr(self.Trans, '_source_module_sig_files', None) + if source_sig_files: + sig_path = source_sig_files.get(module_name) + if sig_path and os.path.isfile(sig_path): + FullModulePath = sig_path + else: + for key, val in source_sig_files.items(): + if key.endswith('.' + module_name) or key == module_name: + FullModulePath = val + break + if not FullModulePath or not os.path.isfile(FullModulePath): + if module_name in ('pyzlib', 'zdeflate', 'zinflate', 'zchecksum', 'zdef', 'zhuff'): + pass + if not FullModulePath: + CurrentFile = getattr(self.Trans, 'CurrentFile', None) or '' + if CurrentFile: + CurrentFileDir = os.path.dirname(os.path.abspath(CurrentFile)) + SearchFromDirs = [CurrentFileDir, os.getcwd()] + else: + SearchFromDirs = [os.getcwd()] + SearchDirsForSubmodule = SearchFromDirs + [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths) + for SearchPath in SearchDirsForSubmodule: + if os.path.isdir(SearchPath): + for root, dirs, files in os.walk(SearchPath): + if '__pycache__' in root: + continue + if module_name + '.py' in files: + FullModulePath = os.path.join(root, module_name + '.py') + break + if module_name + '.pyi' in files: + FullModulePath = os.path.join(root, module_name + '.pyi') + break + if FullModulePath: + break + self._LoadDeclarationsFromStubLlvm(module_name, Gen) + if module_name == 'pyzlib': + pass + try: + with open(FullModulePath, 'r', encoding='utf-8') as f: + ModuleCode = f.read() + ModuleTree = ast.parse(ModuleCode) + if module_name == 'pyzlib': + func_names = [n.name for n in ModuleTree.body if isinstance(n, ast.FunctionDef)] + has_functions_or_classes = False + for node in ModuleTree.body: + if module_name == 'pyzlib': + node_type = type(node).__name__ + name = getattr(node, 'name', getattr(node, 'attr', '?')) + try: + if isinstance(node, ast.FunctionDef): + if node.name in ('va_start', 'va_arg', 'va_end'): + continue + effective_register = register_module_name or module_name + self._EmitExternalFuncDeclLlvm(node, Gen, source_module_name=module_name, register_module_name=effective_register) + has_functions_or_classes = True + elif isinstance(node, ast.AnnAssign): + self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=FullModulePath) + has_functions_or_classes = True + elif isinstance(node, ast.Assign): + self._EmitExternalGlobalDeclLlvm(node, Gen, module_name=module_name, module_path=FullModulePath) + has_functions_or_classes = True + elif isinstance(node, ast.ClassDef): + if hasattr(node, 'type_params') and node.type_params: + if not hasattr(self.Trans.ClassHandler, '_generic_class_templates'): + self.Trans.ClassHandler._generic_class_templates = {} + type_params = [tp.name for tp in node.type_params] + self.Trans.ClassHandler._generic_class_templates[node.name] = { + 'node': node, + 'type_params': type_params, + } + self._EmitExternalClassDeclLlvm(node, Gen, module_name=module_name) + has_functions_or_classes = True + elif isinstance(node, ast.ImportFrom): + if node.level > 0: + current_dir = os.path.dirname(os.path.abspath(FullModulePath)) + parent_dir = current_dir + for _ in range(node.level - 1): + parent_dir = os.path.dirname(parent_dir) + if node.module: + SearchExtensions = ['.pyi', '.py'] + sub_path_base = os.path.join(parent_dir, node.module) + found_sub = False + for ext in SearchExtensions: + candidate = sub_path_base + ext + if os.path.isfile(candidate): + actual_module = f"{module_name}.{node.module}" if module_name else node.module + self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen) + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + self.Trans._imported_modules.add(actual_module) + for alias in node.names: + if alias.name == '*': + self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name) + else: + self._LoadModuleDeclarationsFromFile(candidate, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=module_name) + has_functions_or_classes = True + found_sub = True + break + # SHA1 map 回退:当文件查找失败时,从 SHA1 映射中查找子模块 stub + if not found_sub: + actual_module = f"{module_name}.{node.module}" if module_name else node.module + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + # 尝试完整模块名和短模块名 + target_sha1 = module_sha1_map.get(actual_module) or module_sha1_map.get(node.module) + if target_sha1: + temp_dir = getattr(Gen, '_temp_dir', None) + if temp_dir: + sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") + if os.path.isfile(sha1_pyi): + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + self.Trans._imported_modules.add(actual_module) + for alias in node.names: + if alias.name == '*': + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name) + else: + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, actual_module_name=actual_module, reexport_package=module_name) + has_functions_or_classes = True + else: + mod_dir = parent_dir + SearchExtensions = ['.pyi', '.py'] + # Load __init__.py to make package-level names available + self._LoadPackageInitForRelativeImport(mod_dir, Gen, register_module_name or module_name) + for alias in node.names: + found_alias = False + for ext in SearchExtensions: + sub_path = os.path.join(mod_dir, alias.name + ext) + if os.path.isfile(sub_path): + sub_module_path = f"{module_name}.{alias.name}" if module_name else alias.name + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + self.Trans._imported_modules.add(sub_module_path) + if alias.name == '*': + self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name) + else: + self._LoadModuleDeclarationsFromFile(sub_path, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=module_name) + has_functions_or_classes = True + found_alias = True + break + # SHA1 map 回退 + if not found_alias: + sub_module_path = f"{module_name}.{alias.name}" if module_name else alias.name + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + target_sha1 = module_sha1_map.get(sub_module_path) or module_sha1_map.get(alias.name) + if target_sha1: + temp_dir = getattr(Gen, '_temp_dir', None) + if temp_dir: + sha1_pyi = os.path.join(temp_dir, f"{target_sha1}.pyi") + if os.path.isfile(sha1_pyi): + if not getattr(self.Trans, '_imported_modules', None): + self.Trans._imported_modules = set() + self.Trans._imported_modules.add(sub_module_path) + if alias.name == '*': + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=module_name, register_module_name=register_module_name, reexport_package=module_name) + else: + self._LoadModuleDeclarationsFromFile(sha1_pyi, Gen, module_name=alias.name, register_module_name=register_module_name, reexport_package=module_name) + has_functions_or_classes = True + except Exception as e: + if module_name == 'pyzlib': + node_type = type(node).__name__ + name = getattr(node, 'name', getattr(node, 'attr', '?')) + continue + if not has_functions_or_classes and module_name: + self._LoadDeclarationsFromStubLlvm(module_name, Gen) + elif 'includes' in FullModulePath and module_name: + self._LoadDeclarationsFromStubLlvm(module_name, Gen) + except Exception as e: + if module_name: + self._LoadDeclarationsFromStubLlvm(module_name, Gen) + + def _EmitExternalGlobalDeclLlvm(self, Node, Gen, module_name=None, module_path=None): + """Emit external global variable declaration from imported module""" + if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name): + VarName = Node.target.id + # 不再跳过 _ 开头的全局变量,跨模块引用需要声明它们 + var_type = ir.IntType(32) + is_ptr = False + is_string_val = False + if VarName in Gen.module.globals: + existing = Gen.module.globals[VarName] + if isinstance(existing, ir.GlobalVariable): + old_pointee = existing.type.pointee if isinstance(existing.type, ir.PointerType) else None + if isinstance(old_pointee, ir.IdentifiedStructType): + if old_pointee.elements is not None and len(old_pointee.elements) > 0: + return + elif isinstance(old_pointee, ir.ArrayType): + return + if Node.annotation: + if isinstance(Node.annotation, ast.Subscript) and isinstance(Node.annotation.value, ast.Name) and Node.annotation.value.id == 'list': + slice_node = Node.annotation.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + elem_type_node = slice_node.elts[0] + count_node = slice_node.elts[1] + ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable) + if ElemTypeInfo: + elem_type = Gen._ctype_to_llvm(ElemTypeInfo) + if isinstance(elem_type, ir.VoidType): + elem_type = ir.IntType(8) + if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int): + var_type = ir.ArrayType(elem_type, count_node.value) + elif isinstance(count_node, ast.Constant) and count_node.value is None: + var_type = ir.ArrayType(elem_type, 0) + else: + var_type = Gen._ctype_to_llvm(ElemTypeInfo) + is_ptr = False + else: + TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) + if TypeInfo: + var_type = Gen._ctype_to_llvm(TypeInfo) + is_ptr = TypeInfo.IsPtr + elif isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): + list_node = None + for side in (Node.annotation.left, Node.annotation.right): + if isinstance(side, ast.Subscript) and isinstance(side.value, ast.Name) and side.value.id == 'list': + list_node = side + break + if list_node: + slice_node = list_node.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + elem_type_node = slice_node.elts[0] + count_node = slice_node.elts[1] + ElemTypeInfo = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable) + if ElemTypeInfo: + elem_type = Gen._ctype_to_llvm(ElemTypeInfo) + if isinstance(elem_type, ir.VoidType): + elem_type = ir.IntType(8) + if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int): + var_type = ir.ArrayType(elem_type, count_node.value) + elif isinstance(count_node, ast.Constant) and count_node.value is None: + var_type = ir.ArrayType(elem_type, 0) + else: + var_type = Gen._ctype_to_llvm(ElemTypeInfo) + is_ptr = False + else: + TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) + if TypeInfo: + var_type = Gen._ctype_to_llvm(TypeInfo) + is_ptr = TypeInfo.IsPtr + else: + TypeInfo = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) + if TypeInfo: + var_type = Gen._ctype_to_llvm(TypeInfo) + is_ptr = TypeInfo.IsPtr + if isinstance(var_type, ir.IdentifiedStructType) and (var_type.elements is None or len(var_type.elements) == 0): + var_type = ir.IntType(32) + if Node.value and module_path and is_ptr and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): + str_val = Node.value.value + '\x00' + str_bytes = str_val.encode('utf-8') + arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + str_gv_name = VarName + '_str' + if str_gv_name not in Gen.module.globals: + str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name) + str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) + str_gv.linkage = 'internal' + ptr_type = ir.PointerType(ir.IntType(8)) + if VarName not in Gen.module.globals: + ptr_gv = ir.GlobalVariable(Gen.module, ptr_type, name=VarName) + str_gv = Gen.module.globals[str_gv_name] + ptr_gv.initializer = ir.Constant.gep(str_gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)]) + ptr_gv.linkage = 'internal' + Gen.variables[VarName] = None + return + + # 检查是否是 CDefine 常量或 CTypedef 类型别名 + IsCDefine = False + IsCTypedef = False + if Node.annotation: + if isinstance(Node.annotation, ast.Attribute): + if getattr(Node.annotation.value, 'id', None) == 't' and Node.annotation.attr == 'CDefine': + IsCDefine = True + elif getattr(Node.annotation.value, 'id', None) == 't' and Node.annotation.attr == 'CTypedef': + IsCTypedef = True + elif isinstance(Node.annotation, ast.Name): + if Node.annotation.id == 'CDefine': + IsCDefine = True + elif Node.annotation.id == 'CTypedef': + IsCTypedef = True + + if IsCTypedef: + if Node.value: + ValueTypeInfo = None + if isinstance(Node.value, ast.BinOp) and isinstance(Node.value.op, ast.BitOr): + ValueTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Node.value) + else: + ValueTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.value) + if isinstance(ValueTypeInfo, CTypeInfo) and (ValueTypeInfo.BaseType or ValueTypeInfo.PtrCount > 0): + ValueTypeInfo.IsTypedef = True + ValueTypeInfo.Name = VarName + self.Trans.SymbolTable[VarName] = ValueTypeInfo + if module_name: + FullName = f"{module_name}.{VarName}" + self.Trans.SymbolTable[FullName] = ValueTypeInfo + return + TTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) + if TTypeInfo: + TTypeInfo.IsTypedef = True + TTypeInfo.Name = VarName + self.Trans.SymbolTable[VarName] = TTypeInfo + if module_name: + FullName = f"{module_name}.{VarName}" + self.Trans.SymbolTable[FullName] = TTypeInfo + return + + if IsCDefine: + # CDefine 宏不生成 LLVM 全局变量,只注册到 SymbolTable + # 引用时会直接替换为立即数 + DefineValue = None + if Node.value: + DefineValue = self._ExtractConstValue(Node.value) + # 注册不带前缀的键名(例如 Z_NO_COMPRESSION) + self._RegisterCDefineSymbol(VarName, DefineValue, Node.lineno, module_path or 'unknown') + # 如果提供了模块名,也注册带模块前缀的键名 + if module_name: + FullName = f"{module_name}.{VarName}" + self._RegisterCDefineSymbol(FullName, DefineValue, Node.lineno, module_path or 'unknown') + return # 不再继续生成 LLVM 全局变量 + + gv = ir.GlobalVariable(Gen.module, var_type, name=VarName) + + if Node.value: + InitVal = self._ExtractValue(Node.value, var_type, VarName) + if InitVal is not None: + gv.initializer = InitVal + gv.linkage = 'available_externally' + else: + gv.linkage = 'external' + else: + gv.linkage = 'external' + elif isinstance(node, ast.Assign) and Node.targets and isinstance(Node.targets[0], ast.Name): + VarName = Node.targets[0].id + if VarName.startswith('_'): + return + if VarName in Gen.module.globals: + return + gv = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName) + if Node.value and module_path: + InitVal = self._ExtractValue(Node.value, ir.IntType(32), VarName) + if InitVal is not None: + gv.initializer = InitVal + gv.linkage = 'available_externally' + else: + gv.linkage = 'external' + else: + gv.linkage = 'external' + + def _ExtractValue(self, value_node, target_type, var_name=None): + """Extract constant value from AST node for global variable initializer""" + # 处理负号 + if isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.USub): + if isinstance(value_node.operand, ast.Constant) and isinstance(value_node.operand.value, int): + neg_val = -value_node.operand.value + if isinstance(target_type, ir.IntType): + return ir.Constant(target_type, neg_val) + return ir.Constant(ir.IntType(32), neg_val) + # 处理正号 + elif isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.UAdd): + return self._ExtractValue(value_node.operand, target_type) + + if isinstance(value_node, ast.Constant): + if isinstance(value_node.value, bool): + if isinstance(target_type, ir.IntType): + return ir.Constant(target_type, 1 if value_node.value else 0) + return ir.Constant(ir.IntType(32), 1 if value_node.value else 0) + elif isinstance(value_node.value, int): + if isinstance(target_type, ir.IntType): + return ir.Constant(target_type, value_node.value) + return ir.Constant(ir.IntType(32), value_node.value) + elif isinstance(value_node.value, str): + str_val = value_node.value + '\x00' + str_bytes = str_val.encode('utf-8') + arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + Gen = self.Trans.LlvmGen + gv_name = var_name + '_str' if var_name else f"str_global_{id(value_node)}" + if gv_name in Gen.module.globals: + gv = Gen.module.globals[gv_name] + else: + gv = ir.GlobalVariable(Gen.module, arr_type, name=gv_name) + gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) + gv.linkage = 'internal' + ptr_type = ir.PointerType(ir.IntType(8)) + return ir.Constant(ptr_type, gv.reference) + elif isinstance(value_node.value, bool): + return ir.Constant(ir.IntType(32), 1 if value_node.value else 0) + elif value_node.value is None: + if isinstance(target_type, ir.BaseStructType): + return ir.Constant(target_type, None) + if isinstance(target_type, ir.PointerType): + return ir.Constant(target_type, None) + return ir.Constant(target_type, 0) + elif isinstance(value_node, ast.Name): + if value_node.id == 'None': + if isinstance(target_type, ir.BaseStructType): + return ir.Constant(target_type, None) + if isinstance(target_type, ir.PointerType): + return ir.Constant(target_type, None) + return ir.Constant(target_type, 0) + return None + + def _ExtractConstValue(self, value_node): + """Extract constant value from AST node for SymbolTable registration + 支持常量、一元运算符、二元运算符和常量引用 + """ + import ast + + if isinstance(value_node, ast.Constant): + return value_node.value + elif isinstance(value_node, ast.BinOp): + left = self._ExtractConstValue(value_node.left) + right = self._ExtractConstValue(value_node.right) + if left is None or right is None: + return None + if isinstance(value_node.op, ast.Add): + return left + right + elif isinstance(value_node.op, ast.Sub): + return left - right + elif isinstance(value_node.op, ast.Mult): + return left * right + elif isinstance(value_node.op, ast.Div): + return left // right if isinstance(left, int) and isinstance(right, int) else left / right + elif isinstance(value_node.op, ast.FloorDiv): + return left // right + elif isinstance(value_node.op, ast.Mod): + return left % right + elif isinstance(value_node.op, ast.Pow): + return left ** right + elif isinstance(value_node.op, ast.LShift): + return left << right + elif isinstance(value_node.op, ast.RShift): + return left >> right + elif isinstance(value_node.op, ast.BitOr): + return left | right + elif isinstance(value_node.op, ast.BitXor): + return left ^ right + elif isinstance(value_node.op, ast.BitAnd): + return left & right + elif isinstance(value_node, ast.UnaryOp): + operand = self._ExtractConstValue(value_node.operand) + if operand is None: + return None + if isinstance(value_node.op, ast.USub): + return -operand + elif isinstance(value_node.op, ast.UAdd): + return +operand + elif isinstance(value_node.op, ast.Invert): + return ~operand + elif isinstance(value_node, ast.Name): + if value_node.id in getattr(self.Trans, 'SymbolTable', {}): + info = self.Trans.SymbolTable[value_node.id] + if getattr(info, 'IsDefine', None) and getattr(info, 'DefineValue', None) is not None: + return info.DefineValue + elif isinstance(value_node, ast.Call): + if isinstance(value_node.func, ast.Attribute): + if getattr(value_node.func.value, 'id', None) == 't': + if value_node.args: + return self._ExtractConstValue(value_node.args[0]) + elif isinstance(value_node.func, ast.Name): + if value_node.args: + return self._ExtractConstValue(value_node.args[0]) + return None + + def _ExtractTypedefOriginalType(self, value_node): + import ast + from lib.includes.t import CTypeRegistry + if isinstance(value_node, ast.Attribute): + if getattr(value_node.value, 'id', None) == 't': + llvm_str = CTypeRegistry.NameToLLVM(value_node.attr) + if llvm_str: + return llvm_str + elif isinstance(value_node, ast.Name): + llvm_str = CTypeRegistry.NameToLLVM(value_node.id) + if llvm_str: + return llvm_str + elif isinstance(value_node, ast.BinOp) and isinstance(value_node.op, ast.BitOr): + left = self._ExtractTypedefOriginalType(value_node.left) + right = self._ExtractTypedefOriginalType(value_node.right) + parts = [] + if left: + parts.append(left) + if right: + parts.append(right) + if parts: + return '|'.join(parts) + elif isinstance(value_node, ast.Call): + if isinstance(value_node.func, ast.Attribute): + if getattr(value_node.func.value, 'id', None) == 't': + llvm_str = CTypeRegistry.NameToLLVM(value_node.func.attr) + if llvm_str: + return llvm_str + elif isinstance(value_node.func, ast.Name): + llvm_str = CTypeRegistry.NameToLLVM(value_node.func.id) + if llvm_str: + return llvm_str + return None + + def _RegisterCDefineSymbol(self, FullName, DefineValue, lineno, FilePath): + """Register CDefine constant to SymbolTable""" + from lib.core.Handles.HandlesBase import CTypeInfo + info = CTypeInfo() + info.IsDefine = True + info.DefineValue = DefineValue + info.Lineno = lineno + info.file = FilePath + # 直接添加到 SymbolTable 字典 + self.Trans.SymbolTable[FullName] = info + + def _check_annotation_for_state(self, annotation) -> bool: + import ast + if isinstance(annotation, ast.Attribute): + if hasattr(annotation, 'attr') and annotation.attr in ('CExport', 'CExtern', 'State'): + return True + if hasattr(annotation, 'value') and isinstance(annotation.value, ast.Name) and annotation.value.id == 't' and annotation.attr == 'State': + return True + elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return self._check_annotation_for_state(annotation.left) or self._check_annotation_for_state(annotation.right) + elif isinstance(annotation, ast.Name): + return annotation.id in ('CExport', 'CExtern', 'State') + return False + + def _EmitExternalFuncDeclLlvm(self, Node, Gen, is_class_method=False, source_module_name=None, register_module_name=None, reexport_module_names=None): + FuncName = Node.name + if Node.returns and self._check_annotation_for_state(Node.returns): + Gen._export_funcs.add(FuncName) # t.State 标记的外部 C 函数必须保持原始名称,以便链接器解析 + if FuncName in Gen.functions: + return + CReturnTypes = [] + if Node.decorator_list: + for decorator in Node.decorator_list: + if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): + if decorator.func.attr == 'CReturn': + for arg in decorator.args: + CReturnTypes.append(arg) + IsPtr = False + ReturnTypeInfo = None + if Node.returns: + try: + if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): + ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns) + if not isinstance(ReturnTypeInfo, CTypeInfo): + ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) + else: + ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) + if ReturnTypeInfo and ReturnTypeInfo.IsStr: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CChar() + ReturnTypeInfo.PtrCount = 1 + if ReturnTypeInfo is None: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + IsPtr = ReturnTypeInfo.IsPtr + except Exception: # 回退:返回类型解析失败时使用默认 CInt + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + else: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + ReturnType = Gen._ctype_to_llvm(ReturnTypeInfo) + if (isinstance(ReturnType, ir.VoidType) or (isinstance(ReturnType, ir.PointerType) and isinstance(ReturnType.pointee, ir.VoidType))) and Node.returns: + RetAnnName = None + if isinstance(Node.returns, ast.Name): + RetAnnName = Node.returns.id + elif isinstance(Node.returns, ast.Attribute): + RetAnnName = Node.returns.attr + elif isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): + left = Node.returns.left + if isinstance(left, ast.Name): + RetAnnName = left.id + elif isinstance(left, ast.Attribute): + RetAnnName = left.attr + if RetAnnName and RetAnnName in Gen.structs: + ReturnType = ir.PointerType(Gen.structs[RetAnnName]) + elif IsPtr or RetAnnName: + ReturnType = ir.PointerType(ir.IntType(8)) + ParamTypes = [] + is_method = is_class_method or '.__' in FuncName + class_name_for_method = FuncName.split('.')[0] if '.' in FuncName else None + class_is_cpython = class_name_for_method and class_name_for_method in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[class_name_for_method], 'IsCpythonObject', False) + for i, Arg in enumerate(Node.args.args): + if i == 0 and is_method: + # self parameter of a method should always be a pointer to the struct + ParamType = ir.PointerType(Gen.structs.get(class_name_for_method or FuncName.split('.')[0], ir.IntType(8))) + elif Arg.annotation: + try: + if isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr): + ParamTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Arg.annotation) + if ParamTypeInfo is None or not isinstance(ParamTypeInfo, CTypeInfo): + ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable) + else: + ParamTypeInfo = CTypeInfo.FromNode(Arg.annotation, self.Trans.SymbolTable) + if ParamTypeInfo is None: + ParamTypeInfo = CTypeInfo() + ParamTypeInfo.BaseType = t.CInt() + ParamIsPtr = ParamTypeInfo.IsPtr + if i == 0 and is_method and Arg.arg == 'self' and class_is_cpython: + ParamIsPtr = True + ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1) + if ParamTypeInfo.IsStr: + ParamTypeInfo = CTypeInfo() + ParamTypeInfo.BaseType = t.CChar() + ParamTypeInfo.PtrCount = 1 + ParamIsPtr = True + ParamType = Gen._ctype_to_llvm(ParamTypeInfo) + except Exception: # 回退:参数类型解析失败时使用默认 i32 + ParamType = ir.IntType(32) + if isinstance(ParamType, ir.VoidType) or (isinstance(ParamType, ir.PointerType) and isinstance(ParamType.pointee, ir.VoidType)): + AnnName = None + if isinstance(Arg.annotation, ast.Name): + AnnName = Arg.annotation.id + elif isinstance(Arg.annotation, ast.Attribute): + AnnName = Arg.annotation.attr + elif isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr): + left = Arg.annotation.left + if isinstance(left, ast.Name): + AnnName = left.id + elif isinstance(left, ast.Attribute): + AnnName = left.attr + if AnnName and AnnName in Gen.structs: + ParamType = ir.PointerType(Gen.structs[AnnName]) + else: + ParamType = ir.PointerType(ir.IntType(8)) + else: + ParamType = ir.IntType(32) + ParamTypes.append(ParamType) + if CReturnTypes: + for _ in CReturnTypes: + ParamTypes.append(ir.PointerType(ir.IntType(8))) + IsVariadic = Node.args.vararg is not None + FuncType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic) + _is_export = False + if isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsState: + _is_export = True + if isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.Storage and isinstance(ReturnTypeInfo.Storage, t.CExport) and not ReturnTypeInfo.IsState: + Gen._export_funcs.add(FuncName) + _is_export = True + if isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.Storage and isinstance(ReturnTypeInfo.Storage, t.CExtern): + Gen._export_funcs.add(FuncName) + _is_export = True + if not _is_export and Node.returns: + _is_export = self._check_annotation_for_state(Node.returns) + MangledName = Gen._mangle_func_name(FuncName, module_name=source_module_name) + func = ir.Function(Gen.module, FuncType, name=MangledName) + Gen.functions[MangledName] = func + Gen.functions[FuncName] = func + func_meta = FuncMeta.NONE + if Node.decorator_list: + for d in Node.decorator_list: + if isinstance(d, ast.Name): + if d.id == 'staticmethod': + func_meta |= FuncMeta.STATIC_METHOD + elif d.id == 'property': + func_meta |= FuncMeta.PROPERTY_GETTER + elif d.id == 'classmethod': + func_meta |= FuncMeta.CLASS_METHOD + elif isinstance(d, ast.Attribute): + if isinstance(d.value, ast.Name) and d.value.id == 'property': + if d.attr == 'setter': + func_meta |= FuncMeta.PROPERTY_SETTER + elif d.attr == 'getter': + func_meta |= FuncMeta.PROPERTY_GETTER + elif d.attr == 'deleter': + func_meta |= FuncMeta.PROPERTY_DELETER + if FuncName not in self.Trans.SymbolTable: + FuncInfo = CTypeInfo() + FuncInfo.Name = FuncName + FuncInfo.IsFunction = True + FuncInfo.MetaList = func_meta + self.Trans.SymbolTable[FuncName] = FuncInfo + else: + existing = self.Trans.SymbolTable[FuncName] + if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE: + existing.MetaList = func_meta + if register_module_name and register_module_name != source_module_name: + ReexportName = Gen._mangle_func_name(FuncName, module_name=register_module_name) + Gen.functions[ReexportName] = func + if reexport_module_names: + for reexport_mod in reexport_module_names: + if reexport_mod and reexport_mod != source_module_name: + ReexportName2 = Gen._mangle_func_name(FuncName, module_name=reexport_mod) + if ReexportName2 not in Gen.functions: + Gen.functions[ReexportName2] = func + + def _EmitExternalClassDeclLlvm(self, Node, Gen, module_name=None, actual_module_name=None): + ClassName = Node.name + if hasattr(Node, 'type_params') and Node.type_params: + return + IsCenum = False + IsCpythonObject = False + IsCVTable = False + if Node.bases: + for base in Node.bases: + if getattr(base, 'attr', None): + if base.attr == 'CEnum' or base.attr == 'Enum' or base.attr == 'REnum': + IsCenum = True + break + elif getattr(base, 'id', None): + if base.id == 'CEnum' or base.id == 'Enum' or base.id == 'REnum': + IsCenum = True + break + if not IsCenum and getattr(Node, 'decorator_list', None): + for decorator in Node.decorator_list: + if isinstance(decorator, ast.Attribute): + if getattr(decorator.value, 'id', None) == 't': + if decorator.attr == 'Object': + IsCpythonObject = True + elif decorator.attr == 'CVTable': + IsCVTable = True + elif isinstance(decorator, ast.Call): + if isinstance(decorator.func, ast.Attribute): + if getattr(decorator.func.value, 'id', None) == 't': + if decorator.func.attr == 'Object': + IsCpythonObject = True + elif decorator.func.attr == 'CVTable': + IsCVTable = True + elif isinstance(decorator.func, ast.Name): + if decorator.func.id == 'Object': + IsCpythonObject = True + elif decorator.func.id == 'CVTable': + IsCVTable = True + if ClassName.startswith('_') and not IsCpythonObject and not IsCenum: + return + IsPacked = False + if getattr(Node, 'decorator_list', None): + for decorator in Node.decorator_list: + if isinstance(decorator, ast.Call): + if isinstance(decorator.func, ast.Attribute): + if getattr(decorator.func.value, 'id', None) == 'c' and decorator.func.attr == 'Attribute': + for arg in decorator.args: + if isinstance(arg, ast.Attribute): + if isinstance(arg.value, ast.Attribute): + if getattr(arg.value.value, 'id', None) == 't' and arg.value.attr == 'attr' and arg.attr == 'packed': + IsPacked = True + if IsPacked: + Gen.class_packed.add(ClassName) + if IsCpythonObject: + CInfo = CTypeInfo() + CInfo.Name = ClassName + CInfo.IsCpythonObject = True + CInfo.IsStruct = True + if module_name: + FullName = f"{module_name}.{ClassName}" + self.Trans.SymbolTable[FullName] = CInfo + self.Trans.SymbolTable[ClassName] = CInfo + if IsCenum: + EnumTypeNode = CTypeInfo() + EnumTypeNode.Name = ClassName + EnumTypeNode.BaseType = t.CEnum(ClassName) + EnumTypeNode.IsEnum = True + self.Trans.SymbolTable[ClassName] = EnumTypeNode + for item in Node.body: + VarName = None + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + VarName = item.target.id + elif isinstance(item, ast.Assign): + for target in item.targets: + if isinstance(target, ast.Name): + VarName = target.id + break + if VarName is None: + continue + value = 0 + if isinstance(item, ast.Assign) and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + value = item.value.value + MemberNode = CTypeInfo() + MemberNode.Name = VarName + MemberNode.BaseType = t.CEnum(ClassName) + MemberNode.value = value + MemberNode.EnumName = ClassName + MemberNode.Lineno = item.lineno + MemberNode.IsEnumMember = True + self.Trans.SymbolTable[VarName] = MemberNode + self.Trans.SymbolTable[f"{ClassName}.{VarName}"] = MemberNode + self.Trans.SymbolTable[f"{ClassName}_{VarName}"] = MemberNode + return + self._TryLoadStructFromStub(ClassName, Gen) + source_sha1 = None + if actual_module_name and hasattr(Gen, 'module_sha1_map') and actual_module_name in Gen.module_sha1_map: + source_sha1 = Gen.module_sha1_map[actual_module_name] + elif module_name and hasattr(Gen, 'module_sha1_map') and module_name in Gen.module_sha1_map: + source_sha1 = Gen.module_sha1_map[module_name] + # Track which module defines this class (for cross-module name mangling) + if source_sha1: + if not hasattr(Gen, 'class_sha1_map'): + Gen.class_sha1_map = {} + Gen.class_sha1_map[ClassName] = source_sha1 + Gen._get_or_create_struct(ClassName, source_sha1=source_sha1, packed=IsPacked) + if ClassName not in Gen.class_members: + Gen.class_members[ClassName] = [] + if ClassName not in Gen.class_member_defaults: + Gen.class_member_defaults[ClassName] = {} + if ClassName not in Gen.class_member_signeds: + Gen.class_member_signeds[ClassName] = {} + if ClassName not in Gen.class_member_bitfields: + Gen.class_member_bitfields[ClassName] = {} + if ClassName not in Gen.class_member_byteorders: + Gen.class_member_byteorders[ClassName] = {} + if ClassName not in Gen.class_member_bitoffsets: + Gen.class_member_bitoffsets[ClassName] = {} + has_methods = False + for item in Node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + VarName = item.target.id + try: + TypeInfo = CTypeInfo.FromNode(item.annotation, self.Trans.SymbolTable) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + MemberType = Gen._ctype_to_llvm(TypeInfo) + if isinstance(MemberType, ir.VoidType): + MemberType = ir.PointerType(ir.IntType(8)) + if TypeInfo and TypeInfo.IsBitField: + Gen.class_member_bitfields[ClassName][VarName] = TypeInfo.BitWidth + else: + Gen.class_members[ClassName].append((VarName, MemberType)) + Gen.class_member_bitfields[ClassName][VarName] = 0 + if TypeInfo and TypeInfo.ByteOrder: + Gen.class_member_byteorders[ClassName][VarName] = TypeInfo.ByteOrder + else: + Gen.class_member_byteorders[ClassName][VarName] = "" + if item.value: + const = self._BuildScalarConstant(item.value, MemberType, Gen) + if const: + Gen.class_member_defaults[ClassName][VarName] = const + except Exception: # 回退:类成员类型解析失败时使用默认 i32 + Gen.class_members[ClassName].append((VarName, ir.IntType(32))) + Gen.class_member_signeds[ClassName][VarName] = None + Gen.class_member_bitfields[ClassName][VarName] = 0 + elif isinstance(item, ast.FunctionDef): + has_methods = True + MethodName = item.name + FuncFullName = f"{ClassName}.__init__" if MethodName == "__init__" else f"{ClassName}.__call__" if MethodName == "__call__" else f"{ClassName}.{MethodName}" + is_item_static = any(isinstance(d, ast.Name) and d.id == 'staticmethod' for d in item.decorator_list) + is_item_property = any(isinstance(d, ast.Name) and d.id == 'property' for d in item.decorator_list) + is_item_classmethod = any(isinstance(d, ast.Name) and d.id == 'classmethod' for d in item.decorator_list) + is_item_prop_setter = any(isinstance(d, ast.Attribute) and d.attr == 'setter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list) + is_item_prop_getter = any(isinstance(d, ast.Attribute) and d.attr == 'getter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list) + is_item_prop_deleter = any(isinstance(d, ast.Attribute) and d.attr == 'deleter' and isinstance(d.value, ast.Name) and d.value.id == 'property' for d in item.decorator_list) + if FuncFullName not in Gen.functions: + FuncDeclNode = ast.FunctionDef( + name=FuncFullName, + args=item.args, + body=item.body, + decorator_list=item.decorator_list, + returns=item.returns + ) + self._EmitExternalFuncDeclLlvm(FuncDeclNode, Gen, is_class_method=not is_item_static and not is_item_classmethod, source_module_name=module_name) + func_meta = FuncMeta.NONE + if is_item_static: + func_meta |= FuncMeta.STATIC_METHOD + if is_item_property: + func_meta |= FuncMeta.PROPERTY_GETTER + if is_item_classmethod: + func_meta |= FuncMeta.CLASS_METHOD + if is_item_prop_setter: + func_meta |= FuncMeta.PROPERTY_SETTER + if is_item_prop_getter: + func_meta |= FuncMeta.PROPERTY_GETTER + if is_item_prop_deleter: + func_meta |= FuncMeta.PROPERTY_DELETER + SymKey = FuncFullName + if SymKey not in self.Trans.SymbolTable: + FuncInfo = CTypeInfo() + FuncInfo.Name = FuncFullName + FuncInfo.IsFunction = True + FuncInfo.MetaList = func_meta + self.Trans.SymbolTable[SymKey] = FuncInfo + else: + existing = self.Trans.SymbolTable[SymKey] + if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE: + existing.MetaList = func_meta + if has_methods: + if IsCVTable: + Gen._cross_module_vtable_classes.add(ClassName) + Gen.class_vtable.add(ClassName) + NewFuncName = f'{ClassName}.__before_init__' + if not Gen._has_function(NewFuncName) and (IsCpythonObject or IsCVTable): + source_sha1 = None + if module_name and hasattr(Gen, 'module_sha1_map') and module_name in Gen.module_sha1_map: + source_sha1 = Gen.module_sha1_map[module_name] + MangledName = Gen._mangle_name(NewFuncName) if not source_sha1 else f"{source_sha1}.{NewFuncName}" + StructType = Gen.structs.get(ClassName) + if StructType: + StructPtrType = ir.PointerType(StructType) + NewFuncType = ir.FunctionType(ir.VoidType(), [StructPtrType]) + NewFunc = ir.Function(Gen.module, NewFuncType, name=MangledName) + Gen.functions[NewFuncName] = NewFunc + bitfields = Gen.class_member_bitfields.get(ClassName, {}) + if any(v > 0 for v in bitfields.values()): + current_bit_offset = 0 + for name, _ in Gen.class_members.get(ClassName, []): + bw = bitfields.get(name, 0) + Gen.class_member_bitoffsets[ClassName][name] = current_bit_offset + current_bit_offset += bw + + def _TryLoadStructFromStub(self, class_name: str, Gen): + cache_key = class_name + if cache_key in self._struct_load_cache: + return + self._struct_load_cache[cache_key] = True + + import os, re + ProjectRoot = self._find_project_root() + temp_dir = os.path.join(ProjectRoot, 'temp') + if not os.path.isdir(temp_dir): + return + + if self._stub_cache_dir != temp_dir: + self._stub_cache.clear() + self._stub_cache_dir = temp_dir + for filename in os.listdir(temp_dir): + if not filename.endswith('.stub.ll'): + continue + stub_path = os.path.join(temp_dir, filename) + source_sha1 = filename.replace('.stub.ll', '') + try: + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + for line in content.splitlines(): + stripped = line.strip() + match = re.match(r'%"?((?:[a-f0-9]+\.)?(\w+))"?\s*=\s*type\s*(.*)', stripped) + if match: + full_name = match.group(1) + short_name = match.group(2) + struct_body = match.group(3).strip() + self._stub_cache.setdefault(short_name, []).append((full_name, struct_body, source_sha1)) + if '.' in full_name: + self._stub_cache.setdefault(full_name, []).append((full_name, struct_body, source_sha1)) + except Exception: + pass + + if class_name not in self._stub_cache: + return + + for full_name, struct_body, source_sha1 in self._stub_cache[class_name]: + is_packed = struct_body.startswith('<{') and struct_body.endswith('}>') + if struct_body and struct_body != 'opaque': + elem_types = [] + if is_packed: + inner = struct_body[2:-1].strip() + else: + inner = struct_body.strip('{}') + if inner: + for elem in inner.split(','): + elem = elem.strip() + if elem: + et = self._parse_llvm_type(elem, Gen, source_sha1=source_sha1) + elem_types.append(et if et else ir.IntType(32)) + try: + st = Gen._get_or_create_struct(class_name, source_sha1=source_sha1, packed=is_packed) + if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): + st.set_body(*elem_types) + if is_packed: + Gen.class_packed.add(class_name) + except Exception: + pass + stub_filename = source_sha1 + '.stub.ll' + self._TryLoadClassMembersFromPyi(class_name, stub_filename, Gen) + return + + def _TryLoadClassMembersFromPyi(self, class_name: str, stub_filename: str, Gen): + import os + ProjectRoot = self._find_project_root() + temp_dir = os.path.join(ProjectRoot, 'temp') + if class_name in Gen.class_members and len(Gen.class_members[class_name]) > 0: + return + pyi_basename = stub_filename.replace('.stub.ll', '.pyi') + pyi_path = os.path.join(temp_dir, pyi_basename) + + if self._pyi_cache_dir != temp_dir: + self._pyi_cache.clear() + self._pyi_cache_dir = temp_dir + + if pyi_path not in self._pyi_cache: + if not os.path.isfile(pyi_path): + self._pyi_cache[pyi_path] = None + return + try: + with open(pyi_path, 'r', encoding='utf-8') as f: + self._pyi_cache[pyi_path] = ast.parse(f.read()) + except Exception: + self._pyi_cache[pyi_path] = None + return + + pyi_tree = self._pyi_cache[pyi_path] + if pyi_tree is None: + return + source_sha1 = stub_filename.replace('.stub.ll', '') + module_name = None + if hasattr(Gen, 'module_sha1_map'): + for mod_name, mod_sha1 in Gen.module_sha1_map.items(): + if mod_sha1 == source_sha1 and '.' not in mod_name: + module_name = mod_name + break + if module_name is None: + for mod_name, mod_sha1 in Gen.module_sha1_map.items(): + if mod_sha1 == source_sha1: + module_name = mod_name + break + if module_name is None and hasattr(Gen, 'module_sha1') and Gen.module_sha1 == source_sha1: + module_name = '__self__' + found = False + for node in pyi_tree.body: + if isinstance(node, ast.ClassDef) and node.name == class_name: + self._EmitExternalClassDeclLlvm(node, Gen, module_name=module_name) + found = True + break + if not found: + return + if class_name in Gen.class_members and len(Gen.class_members[class_name]) > 0: + return + return + + def _BuildScalarConstant(self, value_node, target_type, Gen): + """Build a scalar constant value from AST node""" + if isinstance(target_type, ir.BaseStructType): + return None + if isinstance(value_node, ast.Constant): + if isinstance(value_node.value, int): + return ir.Constant(target_type, value_node.value) + elif isinstance(value_node.value, str): + str_val = value_node.value + '\x00' + str_bytes = str_val.encode('utf-8') + arr_type = ir.ArrayType(ir.IntType(8), len(str_bytes)) + gv_name = f"str_const_{id(value_node)}" + gv = ir.GlobalVariable(Gen.module, arr_type, name=gv_name) + gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) + gv.linkage = 'internal' + ptr_type = ir.PointerType(ir.IntType(8)) + return ir.Constant(ptr_type, gv.reference) + elif isinstance(value_node.value, bool): + return ir.Constant(target_type, 1 if value_node.value else 0) + elif isinstance(value_node, ast.Name): + if value_node.id == 'True': + return ir.Constant(target_type, 1) + elif value_node.id == 'False': + if isinstance(target_type, ir.PointerType): + return ir.Constant(target_type, None) + return ir.Constant(target_type, 0) + return None + + def _LookupStubFuncType(self, func_name, Gen): + """从 stub.ll 文件中查找指定函数的 LLVM 类型""" + import os + import re + import llvmlite.ir as ir + + if not getattr(self, '_stub_func_cache', None): + self._stub_func_cache = {} + + ProjectRoot = self._find_project_root() + temp_dir = os.path.join(ProjectRoot, 'temp') + + if not os.path.isdir(temp_dir): + return None + + if func_name not in self._stub_func_cache: + for filename in os.listdir(temp_dir): + if not filename.endswith('.stub.ll'): + continue + + stub_path = os.path.join(temp_dir, filename) + source_sha1 = filename.replace('.stub.ll', '') + try: + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + + for line in content.splitlines(): + stripped = line.strip() + if not stripped.startswith('declare '): + continue + + name_match = stripped.split('@', 1) + if len(name_match) < 2: + continue + + stub_func_name = name_match[1].split('(', 1)[0].strip().strip('"') + + match = re.match(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$', stripped) + if match: + stub_ret = match.group(1).strip() + stub_params = match.group(3).strip() + self._stub_func_cache[stub_func_name] = (stub_ret, stub_params, '...' in stub_params, source_sha1) + except Exception: + pass + + if func_name not in self._stub_func_cache: + return None + + ret_str, params_str, is_variadic, source_sha1 = self._stub_func_cache[func_name] + ret_type = self._parse_llvm_type(ret_str, Gen, source_sha1=source_sha1, create_structs=False) + if ret_type is None: + ret_type = ir.IntType(32) + param_types = [] + if params_str and params_str != 'void': + depth = 0 + current = '' + for ch in params_str: + if ch == ',' and depth == 0: + p = self._strip_llvm_param_name(current.strip()) + if p and p != '...': + pt = self._parse_llvm_type(p, Gen, source_sha1=source_sha1, create_structs=False) + if pt is not None: + param_types.append(pt) + else: + param_types.append(ir.PointerType(ir.IntType(8))) + current = '' + else: + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + current += ch + p = self._strip_llvm_param_name(current.strip()) + if p and p != '...': + pt = self._parse_llvm_type(p, Gen, source_sha1=source_sha1, create_structs=False) + if pt is not None: + param_types.append(pt) + else: + param_types.append(ir.PointerType(ir.IntType(8))) + return ir.FunctionType(ret_type, param_types, var_arg=is_variadic) + + def _strip_llvm_param_name(self, param_str): + """剥离 LLVM IR 参数字符串中的参数名,仅保留类型部分""" + import re + param_str = param_str.strip() + result = re.sub(r'\s+%[\w.]+\s*$', '', param_str) + return result.strip() + + def _parse_simple_llvm_type(self, type_str): + """解析简单的 LLVM 类型字符串(不创建结构体,避免副作用)""" + import llvmlite.ir as ir + + type_str = type_str.strip() + + type_map = { + 'void': ir.VoidType(), + 'i1': ir.IntType(1), + 'i8': ir.IntType(8), + 'i16': ir.IntType(16), + 'i32': ir.IntType(32), + 'i64': ir.IntType(64), + 'float': ir.FloatType(), + 'double': ir.DoubleType(), + } + + if type_str in type_map: + return type_map[type_str] + + if type_str.endswith('*'): + pointee = type_str[:-1].strip() + pointee_type = self._parse_simple_llvm_type(pointee) + if pointee_type: + return ir.PointerType(pointee_type) + return ir.PointerType(ir.IntType(8)) + + if type_str.startswith('[') and ']' in type_str: + import re + arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str) + if arr_match: + size = int(arr_match.group(1)) + elem_type = self._parse_simple_llvm_type(arr_match.group(2).strip()) + if elem_type: + return ir.ArrayType(elem_type, size) + + if type_str.startswith('%'): + return ir.PointerType(ir.IntType(8)) + + return None + + def _LoadDeclarationsFromStubLlvm(self, module_name: str, Gen): + """从 stub.ll 文件加载函数声明和结构体定义到 Gen""" + import os + import re + import llvmlite.ir as ir + + ProjectRoot = self._find_project_root() + temp_dir = os.path.join(ProjectRoot, 'temp') + + if not os.path.isdir(temp_dir): + return + + all_stub_files = [f for f in os.listdir(temp_dir) if f.endswith('.stub.ll')] + + source_sig_files = getattr(self.Trans, '_source_module_sig_files', {}) + target_sha1 = None + if module_name: + for key, val in source_sig_files.items(): + if key == module_name or key.endswith('.' + module_name): + target_sha1 = os.path.basename(val).replace('.pyi', '') + break + if not target_sha1: + module_sha1_map = getattr(Gen, 'module_sha1_map', {}) + target_sha1 = module_sha1_map.get(module_name) + + if target_sha1: + target_stub = f"{target_sha1}.stub.ll" + if target_stub in all_stub_files: + stub_files = [target_stub] + else: + stub_files = [] + else: + stub_files = [] + + needed_sha1s = set() + for filename in stub_files: + stub_path = os.path.join(temp_dir, filename) + try: + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + for line in content.splitlines(): + stripped = line.strip() + if stripped.startswith('%') and '=' in stripped and 'type' in stripped: + for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped): + needed_sha1s.add(m.group(1)) + elif stripped.startswith('declare '): + for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped): + needed_sha1s.add(m.group(1)) + except Exception: + pass + + preload_files = [] + for sha1 in needed_sha1s: + dep_stub = f"{sha1}.stub.ll" + if dep_stub in all_stub_files and dep_stub not in stub_files: + preload_files.append(dep_stub) + + load_order = preload_files + stub_files + + for filename in load_order: + stub_path = os.path.join(temp_dir, filename) + source_sha1 = filename.replace('.stub.ll', '') + is_preload = filename in preload_files + try: + with open(stub_path, 'r', encoding='utf-8') as f: + content = f.read() + + for line in content.splitlines(): + stripped = line.strip() + + if stripped.startswith('%') and '=' in stripped and 'type' in stripped: + struct_def_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?\s*=\s*type\s*(.*)', stripped) + if struct_def_match: + raw_name = struct_def_match.group(1) + if '.' in raw_name: + clean_name = raw_name.split('.', 1)[1] + else: + clean_name = raw_name + struct_body = struct_def_match.group(2).strip() + if struct_body and struct_body != 'opaque': + elem_types = [] + is_packed = struct_body.startswith('<{') and struct_body.endswith('}>') + if is_packed: + inner = struct_body[2:-1].strip() + else: + inner = struct_body.strip('{}') + if inner: + for elem in inner.split(','): + elem = elem.strip() + if elem: + elem_type = self._parse_llvm_type(elem, Gen, source_sha1=source_sha1) + if elem_type is not None: + elem_types.append(elem_type) + else: + elem_types.append(ir.IntType(32)) + st = Gen._get_or_create_struct(clean_name, source_sha1=source_sha1, packed=is_packed) + if isinstance(st, ir.IdentifiedStructType) and (st.elements is None or len(st.elements) == 0): + try: + st.set_body(*elem_types) + except Exception: + pass + continue + + if not stripped.startswith('declare '): + continue + + if is_preload: + continue + + func_name_match = stripped.split('@', 1) + if len(func_name_match) < 2: + continue + + func_name = func_name_match[1].split('(', 1)[0].strip().strip('"') + + if not module_name: + continue + + try: + func_type = self._parse_llvm_declare(stripped, Gen) + if func_type is not None: + if func_name in Gen.functions: + existing_func = Gen.functions[func_name] + existing_ftype = getattr(existing_func, 'ftype', None) or existing_func.type.pointee + if str(existing_ftype) != str(func_type): + func = ir.Function(Gen.module, func_type, name=func_name) + Gen.functions[func_name] = func + if '.' in func_name: + short_name = func_name.split('.', 1)[1] + Gen.functions[short_name] = func + else: + func = ir.Function(Gen.module, func_type, name=func_name) + Gen.functions[func_name] = func + if '.' in func_name: + short_name = func_name.split('.', 1)[1] + Gen.functions[short_name] = func + except Exception: + pass + except Exception: + pass + + def _parse_llvm_declare(self, declare_line: str, Gen): + """解析 LLVM declare 语句""" + import re + import llvmlite.ir as ir + + match = re.match(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$', declare_line) + if not match: + return None + + ret_type_str = match.group(1).strip() + params_str = match.group(3).strip() + + ret_type = self._parse_llvm_type(ret_type_str, Gen) + if ret_type is None: + return None + + param_types = [] + if params_str and params_str != 'void': + depth = 0 + current = '' + for ch in params_str: + if ch == ',' and depth == 0: + p = self._strip_llvm_param_name(current.strip()) + if p and p != '...': + pt = self._parse_llvm_type(p, Gen) + if pt is not None: + param_types.append(pt) + current = '' + else: + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + current += ch + p = self._strip_llvm_param_name(current.strip()) + if p and p != '...': + pt = self._parse_llvm_type(p, Gen) + if pt is not None: + param_types.append(pt) + + is_variadic = '...' in params_str + return ir.FunctionType(ret_type, param_types, var_arg=is_variadic) + + def _parse_llvm_type(self, type_str: str, Gen, source_sha1=None, create_structs=True): + """解析 LLVM 类型字符串""" + import re + import llvmlite.ir as ir + + type_str = type_str.strip() + + type_map = { + 'void': ir.VoidType(), + 'i1': ir.IntType(1), + 'i8': ir.IntType(8), + 'i16': ir.IntType(16), + 'i32': ir.IntType(32), + 'i64': ir.IntType(64), + 'float': ir.FloatType(), + 'double': ir.DoubleType(), + } + + if type_str in type_map: + return type_map[type_str] + + if type_str.startswith('{') and type_str.endswith('}'): + inner = type_str[1:-1].strip() + field_types = [] + depth = 0 + current = '' + for ch in inner: + if ch == ',' and depth == 0: + field_types.append(current.strip()) + current = '' + else: + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + current += ch + if current.strip(): + field_types.append(current.strip()) + llvm_fields = [] + for ft in field_types: + parsed = self._parse_llvm_type(ft, Gen, source_sha1=source_sha1, create_structs=create_structs) + if parsed is not None: + llvm_fields.append(parsed) + else: + return None + if llvm_fields: + return ir.LiteralStructType(llvm_fields) + return None + + if type_str.endswith('*'): + pointee = type_str[:-1].strip() + pointee_type = self._parse_llvm_type(pointee, Gen, source_sha1=source_sha1, create_structs=create_structs) + if pointee_type is not None: + return ir.PointerType(pointee_type) + return ir.PointerType(ir.IntType(8)) + + if type_str.startswith('[') and ']' in type_str: + arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str) + if arr_match: + size = int(arr_match.group(1)) + elem_type = self._parse_llvm_type(arr_match.group(2).strip(), Gen, source_sha1=source_sha1, create_structs=create_structs) + if elem_type is not None: + return ir.ArrayType(elem_type, size) + + typedef_names = {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'} + struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.]+)"?', type_str) + if struct_match: + raw_name = struct_match.group(1) + actual_source_sha1 = source_sha1 + if '.' in raw_name: + parts = raw_name.split('.', 1) + if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]): + actual_source_sha1 = parts[0] + struct_name = parts[1] + else: + struct_name = raw_name + if struct_name not in typedef_names: + if create_structs: + return Gen._get_or_create_struct(struct_name, source_sha1=actual_source_sha1) + else: + existing = Gen.structs.get(struct_name) + if existing is not None: + return existing + return None + return ir.IntType(32) + + return None + + def _strip_param_name(self, param_str): + """从 LLVM 参数字符串中剥离参数名,只保留类型部分 + 例如: '%"sha1.struct_name"* %param_name' -> '%"sha1.struct_name"*' + 'i8* %path' -> 'i8*' + 'i32' -> 'i32' + """ + import re + param_str = param_str.strip() + stripped = re.sub(r'\s+%[\w.]+\s*$', '', param_str) + return stripped.strip() diff --git a/lib/core/Handles/HandlesMatch.py b/lib/core/Handles/HandlesMatch.py new file mode 100644 index 0000000..638feb8 --- /dev/null +++ b/lib/core/Handles/HandlesMatch.py @@ -0,0 +1,333 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class MatchHandle(BaseHandle): + def _HandleMatchLlvm(self, Node): + Gen = self.Trans.LlvmGen + SubjectVal = self.HandleExprLlvm(Node.subject) + if not SubjectVal: + return + + IsRenumMatch = False + RenumName = None + SubjectPtr = None + if isinstance(Node.subject, ast.Name): + VarName = Node.subject.id + if VarName in self.Trans.SymbolTable: + TypeInfo = self.Trans.SymbolTable[VarName] + if getattr(TypeInfo, 'IsRenum', False): + IsRenumMatch = True + RenumName = TypeInfo.Name + SubjectPtr = Gen._load_var(VarName) + + if not IsRenumMatch: + for case in Node.cases: + if isinstance(case.pattern, ast.MatchClass): + cls_node = case.pattern.cls + VariantName = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + if VariantName and VariantName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[VariantName] + if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None): + EnumName = SymInfo.EnumName + if EnumName in self.Trans.SymbolTable: + EnumInfo = self.Trans.SymbolTable[EnumName] + if getattr(EnumInfo, 'IsRenum', False): + IsRenumMatch = True + RenumName = EnumName + if SubjectPtr is None: + SubjectPtr = self.HandleExprLlvm(Node.subject) + break + + if IsRenumMatch and SubjectPtr: + self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr) + return + + if not isinstance(SubjectVal.type, ir.IntType): + try: + SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj") + SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32") + except Exception: # 回退:ptrtoint 失败时直接返回 + return + SwitchIntType = SubjectVal.type + DefaultBB = Gen.func.append_basic_block(name="match.default") + AfterBB = Gen.func.append_basic_block(name="match.end") + CaseBBs = [] + CaseValues = [] + HasDefault = False + HasNoBreak = [] + for i, case in enumerate(Node.cases): + pattern = case.pattern + if isinstance(pattern, ast.MatchValue): + Val = self.HandleExprLlvm(pattern.value) + if Val: + if isinstance(Val.type, ir.IntType): + if Val.type != SwitchIntType: + if Val.type.width > SwitchIntType.width: + CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) + else: + CaseVal = ir.Constant(SwitchIntType, Val.constant) + else: + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(SwitchIntType, 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + elif isinstance(pattern, ast.MatchOr): + for j, SubPattern in enumerate(pattern.patterns): + if isinstance(SubPattern, ast.MatchValue): + Val = self.HandleExprLlvm(SubPattern.value) + if Val: + if isinstance(Val.type, ir.IntType): + if Val.type != SwitchIntType: + if Val.type.width > SwitchIntType.width: + CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) + else: + CaseVal = ir.Constant(SwitchIntType, Val.constant) + else: + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(SwitchIntType, 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}")) + elif isinstance(pattern, ast.MatchSingleton): + if pattern.value is None: + CaseValues.append(ir.Constant(SwitchIntType, 0)) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + HasDefault = True + CaseBBs.append(DefaultBB) + elif isinstance(pattern, ast.MatchSequence): + HasDefault = True + CaseBBs.append(DefaultBB) + def _HasNoBreak(stmts): + for stmt in stmts: + if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): + if isinstance(stmt.value.func, ast.Attribute): + if (isinstance(stmt.value.func.value, ast.Name) and + stmt.value.func.value.id == 'c' and + stmt.value.func.attr == 'NoBreak'): + return True + if getattr(stmt, 'body', None) and isinstance(stmt.body, list): + if _HasNoBreak(stmt.body): + return True + if getattr(stmt, 'orelse', None): + if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): + return True + return False + HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) + if not HasDefault: + CaseBBs.append(DefaultBB) + SwitchCases = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] + switch_instr = Gen.builder.switch(SubjectVal, DefaultBB) + for val, bb in SwitchCases: + switch_instr.add_case(val, bb) + CaseIdx = 0 + for i, case in enumerate(Node.cases): + pattern = case.pattern + if isinstance(pattern, ast.MatchOr): + NumSubCases = len(pattern.patterns) + for j in range(NumSubCases): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchSequence): + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + if not HasDefault: + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleRenumMatchLlvm(self, Node, RenumName, SubjectPtr): + Gen = self.Trans.LlvmGen + if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType): + SubjectPtr = Gen._load(SubjectPtr, name="load_match_subj") + tag_ptr = Gen.builder.gep(SubjectPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="match_tag_ptr") + TagVal = Gen._load(tag_ptr, name="match_tag_val") + DefaultBB = Gen.func.append_basic_block(name="match.default") + AfterBB = Gen.func.append_basic_block(name="match.end") + CaseBBs = [] + CaseValues = [] + CaseBindings = [] + HasDefault = False + HasNoBreak = [] + for i, case in enumerate(Node.cases): + pattern = case.pattern + bindings = [] + if isinstance(pattern, ast.MatchClass): + cls_node = pattern.cls + VariantName = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + if VariantName: + TagValue = None + if VariantName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[VariantName] + if getattr(SymInfo, 'IsEnumMember', False): + TagValue = SymInfo.value + if TagValue is not None: + CaseValues.append(ir.Constant(ir.IntType(32), TagValue)) + CaseBB = Gen.func.append_basic_block(name=f"match.case_{VariantName}") + CaseBBs.append(CaseBB) + NestedStructName = f"{RenumName}_{VariantName}" + if NestedStructName in Gen.structs: + members = Gen.class_members.get(NestedStructName, []) + payload_members = [(n, t) for n, t in members if n != '__tag'] + for j, sub_pat in enumerate(pattern.patterns): + if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payload_members): + bindings.append((sub_pat.name, payload_members[j][0], payload_members[j][1], j)) + CaseBindings.append(bindings) + else: + CaseValues.append(ir.Constant(ir.IntType(32), 0)) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchValue): + Val = self.HandleExprLlvm(pattern.value) + if Val: + if isinstance(Val.type, ir.IntType): + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(ir.IntType(32), 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + HasDefault = True + CaseBBs.append(DefaultBB) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchSequence): + HasDefault = True + CaseBBs.append(DefaultBB) + CaseBindings.append([]) + def _HasNoBreak(stmts): + for stmt in stmts: + if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): + if isinstance(stmt.value.func, ast.Attribute): + if (isinstance(stmt.value.func.value, ast.Name) and + stmt.value.func.value.id == 'c' and + stmt.value.func.attr == 'NoBreak'): + return True + if getattr(stmt, 'body', None) and isinstance(stmt.body, list): + if _HasNoBreak(stmt.body): + return True + if getattr(stmt, 'orelse', None): + if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): + return True + return False + HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) + if not HasDefault: + CaseBBs.append(DefaultBB) + SwitchCases = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] + switch_instr = Gen.builder.switch(TagVal, DefaultBB) + for val, bb in SwitchCases: + switch_instr.add_case(val, bb) + CaseIdx = 0 + for i, case in enumerate(Node.cases): + pattern = case.pattern + if isinstance(pattern, ast.MatchClass): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + bindings = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else [] + cls_node = pattern.cls + VariantName = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + if VariantName: + NestedStructName = f"{RenumName}_{VariantName}" + if NestedStructName in Gen.structs: + NestedStructType = Gen.structs[NestedStructName] + NestedStructPtrType = ir.PointerType(NestedStructType) + variant_ptr = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}") + for bind_name, member_name, member_type, member_idx in bindings: + elem_ptr = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}") + Gen.variables[bind_name] = elem_ptr + self.HandleBodyLlvm(case.body) + for bind_name, _, _, _ in bindings: + if bind_name in Gen.variables: + del Gen.variables[bind_name] + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchValue): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchSequence): + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + if not HasDefault: + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) diff --git a/lib/core/Handles/HandlesRaise.py b/lib/core/Handles/HandlesRaise.py new file mode 100644 index 0000000..c1ecef3 --- /dev/null +++ b/lib/core/Handles/HandlesRaise.py @@ -0,0 +1,135 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP +import ast +import llvmlite.ir as ir + + +class RaiseHandle(BaseHandle): + def _get_exception_code(self, ExcName): + if ExcName in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[ExcName] + if ExcName in self.Trans.exception_registry: + return self.Trans.exception_registry[ExcName] + return 1 + + def _HandleRaiseLlvm(self, Node): + Gen = self.Trans.LlvmGen + exc_val = ir.Constant(ir.IntType(32), 1) + exc_msg = None + IsStopIteration = False + if Node.exc: + if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int): + exc_val = ir.Constant(ir.IntType(32), Node.exc.value) + elif isinstance(Node.exc, ast.Name): + ExcName = Node.exc.id + if ExcName == 'StopIteration': + IsStopIteration = True + exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) + elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name): + ExcName = Node.exc.func.id + if ExcName == 'StopIteration': + IsStopIteration = True + exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) + if Node.exc.args: + first_arg = Node.exc.args[0] + if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): + exc_msg = self.HandleExprLlvm(first_arg) + elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)): + arg_val = self.HandleExprLlvm(first_arg) + if arg_val: + if isinstance(arg_val.type, ir.PointerType): + if self._is_char_pointer(arg_val): + exc_msg = arg_val + else: + try: + exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast") + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + else: + try: + exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr") + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + else: + val = self.HandleExprLlvm(Node.exc) + if val: + if isinstance(val.type, ir.IntType): + if val.type.width != 32: + try: + val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc") + except Exception: # 回退:trunc 失败时设默认值 1 + val = ir.Constant(ir.IntType(32), 1) + exc_val = val + else: + try: + val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int") + exc_val = val + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + if IsStopIteration: + if Gen._stop_iter_flag_param is not None: + Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param) + if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType(): + ret_type = Gen.func.type.pointee.return_type + Gen.builder.ret(ir.Constant(ret_type, 0)) + else: + Gen.builder.ret_void() + return + if Gen.eh_except_block_stack: + ExceptBB, EndBB, exception_code, eh_message = Gen.eh_except_block_stack[-1] + Gen._store(exc_val, exception_code) + if exc_msg: + Gen._store(exc_msg, eh_message) + else: + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen._store(null_ptr, eh_message) + if Gen.func and ExceptBB and ExceptBB.function is Gen.func: + Gen.builder.branch(ExceptBB) + else: + eh_msg_arg = None + eh_code_arg = None + if Gen.func: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_arg = arg + if eh_msg_arg is not None: + if exc_msg: + Gen.builder.store(exc_msg, eh_msg_arg) + else: + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen.builder.store(null_ptr, eh_msg_arg) + if eh_code_arg is not None: + Gen.builder.store(exc_val, eh_code_arg) + if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: + Gen.builder.ret_void() + else: + eh_msg_arg = None + eh_code_arg = None + if Gen.func: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_arg = arg + if eh_msg_arg is not None: + if exc_msg: + Gen.builder.store(exc_msg, eh_msg_arg) + else: + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen.builder.store(null_ptr, eh_msg_arg) + if eh_code_arg is not None: + Gen.builder.store(exc_val, eh_code_arg) + if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: + Gen.builder.ret_void() \ No newline at end of file diff --git a/lib/core/Handles/HandlesReturn.py b/lib/core/Handles/HandlesReturn.py new file mode 100644 index 0000000..95b76ff --- /dev/null +++ b/lib/core/Handles/HandlesReturn.py @@ -0,0 +1,155 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, CTypeHelper +import ast +import llvmlite.ir as ir + + +class ReturnHandle(BaseHandle): + def _find_active_finally(self, Gen): + for item in reversed(Gen.eh_finally_stack): + if item is not None and item[0] is not None: + return item + return None + + def _HandleReturnLlvm(self, Node): + Gen = self.Trans.LlvmGen + active_finally = self._find_active_finally(Gen) + if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value: + return_values = [] + if isinstance(Node.value, ast.Tuple): + return_values = Node.value.elts + else: + return_values = [Node.value] + if len(return_values) == len(self.Trans.CurrentCReturnTypes): + llvm_vals = [] + expected_types = [] + for i, val in enumerate(return_values): + ReturnTypeInfo = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable) + IsRetPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False + if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'): + IsRetPtr = True + ExpectedType = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr) + expected_types.append(ExpectedType) + Val = self.HandleExprLlvm(val) + if Val is None: + if isinstance(ExpectedType, ir.PointerType): + Val = ir.Constant(ExpectedType, None) + elif isinstance(ExpectedType, ir.IntType): + Val = ir.Constant(ExpectedType, 0) + else: + Val = ir.Constant(ExpectedType, ir.Undefined) + else: + if Val.type != ExpectedType: + if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType): + if Val.type.width < ExpectedType.width: + Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}") + elif Val.type.width > ExpectedType.width: + Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}") + elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType): + Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}") + llvm_vals.append(Val) + if llvm_vals: + struct_type = ir.LiteralStructType(expected_types) + result = ir.Constant(struct_type, ir.Undefined) + for i, val in enumerate(llvm_vals): + result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}") + if active_finally: + FinallyBB, pending_ret_flag, pending_ret_val = active_finally + if pending_ret_val: + Gen._store(result, pending_ret_val) + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + Gen.emit_return(result) + return + if Node.value: + Val = self.HandleExprLlvm(Node.value) + if Val: + ret_type = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None + if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None: + if ret_type.elements: + zero_val = ir.Constant(ret_type, [ + ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) + else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) + else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + if active_finally: + FinallyBB, pending_ret_flag, pending_ret_val = active_finally + if pending_ret_val: + Gen._store(zero_val, pending_ret_val) + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + Gen.emit_return(zero_val) + return + if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes: + struct_type = Gen.func.ftype.return_type + if isinstance(struct_type, ir.LiteralStructType): + result = ir.Constant(struct_type, ir.Undefined) + if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType): + result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0") + for j in range(1, len(struct_type.elements)): + elem_type = struct_type.elements[j] + zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) + result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") + else: + for j, elem_type in enumerate(struct_type.elements): + if j == 0: + if Val.type == elem_type: + result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}") + elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType): + if Val.type.width < elem_type.width: + Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}") + elif Val.type.width > elem_type.width: + Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}") + result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}") + else: + zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) + result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") + else: + zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) + result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") + if active_finally: + FinallyBB, pending_ret_flag, pending_ret_val = active_finally + if pending_ret_val: + Gen._store(result, pending_ret_val) + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + Gen.emit_return(result) + return + if active_finally: + FinallyBB, pending_ret_flag, pending_ret_val = active_finally + if pending_ret_val: + Gen._store(Val, pending_ret_val) + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + Gen.emit_return(Val) + else: + if active_finally: + FinallyBB, pending_ret_flag, pending_ret_val = active_finally + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + ret_type = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None + if isinstance(ret_type, ir.IntType): + Gen.builder.ret(ir.Constant(ret_type, 0)) + elif isinstance(ret_type, ir.PointerType): + Gen.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + Gen.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.IdentifiedStructType): + if ret_type.elements: + zero_val = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + Gen.builder.ret(zero_val) + elif isinstance(ret_type, ir.ArrayType): + Gen.builder.ret(ir.Constant(ret_type, None)) + else: + Gen.emit_return() \ No newline at end of file diff --git a/lib/core/Handles/HandlesSpecialCall.py b/lib/core/Handles/HandlesSpecialCall.py new file mode 100644 index 0000000..f2d57be --- /dev/null +++ b/lib/core/Handles/HandlesSpecialCall.py @@ -0,0 +1,354 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class CSpecialCallHandle(BaseHandle): + def _HandleCIfLlvm(self, Node): + Gen = self.Trans.LlvmGen + if Node.args: + ArgVal = self.HandleExprLlvm(Node.args[0]) + if ArgVal: + if isinstance(ArgVal, ir.Constant) and isinstance(ArgVal.type, ir.IntType): + return ir.Constant(ir.IntType(1), 1 if ArgVal.constant != 0 else 0) + if isinstance(ArgVal.type, ir.IntType): + return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond") + if isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.icmp_signed('!=', ArgVal, Gen._zero_const(ArgVal.type), name="cif_cond") + return ir.Constant(ir.IntType(1), 0) + def _HandleCAddrLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return ir.Constant(ir.IntType(8).as_pointer(), None) + Arg = Node.args[0] + if isinstance(Arg, ast.Call): + ClassName = None + if isinstance(Arg.func, ast.Name): + ClassName = Arg.func.id + elif isinstance(Arg.func, ast.Attribute): + ClassName = Arg.func.attr + if ClassName and ClassName in Gen.structs: + StructType = Gen.structs[ClassName] + if isinstance(StructType, ir.PointerType): + StructType = StructType.pointee + ObjPtr = Gen._alloca_entry(StructType, name=f"{ClassName}_obj") + Gen.builder.store(ir.Constant(StructType, None), ObjPtr) + ConstructorName = f"{ClassName}.__init__" + if ConstructorName in Gen.functions: + func = Gen.functions[ConstructorName] + InitArgs = [ObjPtr] + for carg in Arg.args: + ArgVal = self.HandleExprLlvm(carg) + if ArgVal: + InitArgs.append(ArgVal) + for kw in Arg.keywords: + ArgVal = self.HandleExprLlvm(kw.value) + if ArgVal: + InitArgs.append(ArgVal) + if hasattr(self.Trans.ExprCallHandle, '_append_eh_msg_out_arg'): + self.Trans.ExprCallHandle._append_eh_msg_out_arg(InitArgs, func, Gen) + adjusted = Gen._adjust_args(InitArgs, func) + Gen.builder.call(func, adjusted, name=f"{ClassName}_construct") + return Gen.builder.bitcast(ObjPtr, ir.IntType(8).as_pointer(), name=f"{ClassName}_as_i8ptr") + if isinstance(Arg, ast.Subscript): + SubPtr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Arg) + if SubPtr and isinstance(SubPtr.type, ir.PointerType): + return Gen.builder.bitcast(SubPtr, ir.IntType(8).as_pointer(), name="addr_subscript_as_i8ptr") + if isinstance(Arg, ast.Attribute): + AttrPtr = self.Trans.ExprAttrHandle._get_attr_ptr(Arg) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType): + return Gen.builder.bitcast(AttrPtr, ir.IntType(8).as_pointer(), name="addr_attr_as_i8ptr") + if isinstance(Arg, ast.Name): + VarName = Arg.id + if VarName in Gen.functions: + func = Gen.functions[VarName] + return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name="addr_func_as_i8ptr") + if VarName in Gen.variables and Gen.variables[VarName] is not None: + var_ptr = Gen.variables[VarName] + if isinstance(var_ptr.type, ir.PointerType): + # For pointer-to-pointer allocas (var_ptr is T**): + # - If T is a named struct (@t.Object class), the variable semantically + # IS the struct, so c.Addr should return the struct pointer value. + # - If T is a primitive pointer type (e.g., i8*), the variable semantically + # holds a pointer, so c.Addr should return &var (alloca address). + if isinstance(var_ptr.type.pointee, ir.PointerType): + pointee = var_ptr.type.pointee.pointee + if isinstance(pointee, ir.IdentifiedStructType): + # @t.Object class variable — return loaded struct pointer + ArgVal = self.HandleExprLlvm(Arg) + if ArgVal and isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") + # Pointer-type variable — return alloca address (&var) + return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") + return Gen.builder.bitcast(var_ptr, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") + ArgVal = self.HandleExprLlvm(Arg) + if ArgVal: + if isinstance(ArgVal.type, ir.IntType): + alloca = Gen._alloca(ArgVal.type, name="addr_tmp") + Gen._store(ArgVal, alloca) + return Gen.builder.bitcast(alloca, ir.IntType(8).as_pointer(), name="addr_as_i8ptr") + elif isinstance(ArgVal.type, ir.PointerType): + return Gen.builder.bitcast(ArgVal, ir.IntType(8).as_pointer(), name="addr_bitcast") + return ir.Constant(ir.IntType(8).as_pointer(), None) + + def _HandleCSetLlvm(self, Node): + Gen = self.Trans.LlvmGen + if len(Node.args) >= 2: + target_arg = Node.args[0] + value_arg = Node.args[1] + target_ptr = None + if isinstance(target_arg, ast.Call) and isinstance(target_arg.func, ast.Attribute): + if isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 'c': + if target_arg.func.attr == 'Deref' and target_arg.args: + deref_arg = target_arg.args[0] + if isinstance(deref_arg, ast.Name) and deref_arg.id in Gen.variables and Gen.variables[deref_arg.id] is not None: + target_ptr = Gen._load(Gen.variables[deref_arg.id], name="deref_load_ptr") + else: + inner_value = self.HandleExprLlvm(deref_arg) + if inner_value: + if isinstance(inner_value.type, ir.PointerType): + if isinstance(inner_value.type.pointee, ir.PointerType): + inner_value = Gen._load(inner_value, name="cast_deref") + target_ptr = inner_value + elif target_arg.func.attr == 'Addr' and target_arg.args: + target_ptr = self.HandleExprLlvm(target_arg) + elif isinstance(target_arg.func.value, ast.Name) and target_arg.func.value.id == 't': + type_attr = target_arg.func.attr + resolved_cname = self.Trans.TSpecialCallHandle._ResolveTAttrToCName(type_attr) + if target_arg.args and resolved_cname is not None: + inner_val = self.HandleExprLlvm(target_arg.args[0]) + if inner_val and isinstance(inner_val.type, ir.PointerType): + target_llvm_type = Gen._basic_type_to_llvm(resolved_cname) + if target_llvm_type: + target_ptr = Gen.builder.bitcast(inner_val, ir.PointerType(target_llvm_type), name="tcast_ptr") + if not target_ptr: + if isinstance(target_arg, ast.Subscript): + target_ptr = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(target_arg) + else: + target_ptr = self.HandleExprLlvm(target_arg) + Val = self.HandleExprLlvm(value_arg) + if target_ptr and Val: + if isinstance(target_ptr.type, ir.PointerType): + ValToStore = Val + pointee = target_ptr.type.pointee + if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, ir.IntType) and pointee.pointee.width == 8: + if isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: + ValToStore = Val + elif isinstance(Val.type, ir.IntType): + ValToStore = Gen.builder.inttoptr(Val, pointee, name="int_to_ptr_set") + elif isinstance(pointee, ir.IntType): + if isinstance(Val.type, ir.ArrayType) and isinstance(Val.type.element, ir.IntType) and Val.type.element.width == 8: + zero = ir.Constant(ir.IntType(32), 0) + value_ptr = Gen.builder.gep(Val, [zero, zero], name="value_ptr") + ValToStore = Gen._load(value_ptr, name="load_value") + elif isinstance(Val.type, ir.PointerType) and isinstance(Val.type.pointee, ir.IntType) and Val.type.pointee.width == 8: + ValToStore = Gen._load(Val, name="load_char_value") + if isinstance(ValToStore.type, ir.IntType) and isinstance(pointee, ir.IntType): + if ValToStore.type.width < pointee.width: + ValToStore = Gen.builder.zext(ValToStore, pointee, name="zext_set") + elif ValToStore.type.width > pointee.width: + ValToStore = Gen.builder.trunc(ValToStore, pointee, name="trunc_set") + elif Val.type != pointee: + if isinstance(pointee, ir.PointerType) and isinstance(Val.type, ir.PointerType): + ValToStore = Gen.builder.bitcast(Val, pointee, name="bitcast_set") + Gen._store(ValToStore, target_ptr) + return ir.Constant(ir.IntType(32), 1) + + def _HandleCLoadLlvm(self, Node): + Gen = self.Trans.LlvmGen + if len(Node.args) < 2: + return ir.Constant(ir.IntType(32), 0) + src_val = self.HandleExprLlvm(Node.args[0]) + dst_val = self.HandleExprLlvm(Node.args[1]) + if not src_val or not dst_val: + return ir.Constant(ir.IntType(32), 0) + if not isinstance(src_val.type, ir.PointerType) or not isinstance(dst_val.type, ir.PointerType): + return ir.Constant(ir.IntType(32), 0) + loaded = Gen._load(src_val, name="cload_src") + if loaded is None: + return ir.Constant(ir.IntType(32), 0) + pointee = dst_val.type.pointee + val_to_store = loaded + if isinstance(pointee, ir.IntType) and isinstance(loaded.type, ir.IntType): + if loaded.type.width < pointee.width: + val_to_store = Gen.builder.zext(loaded, pointee, name="cload_zext") + elif loaded.type.width > pointee.width: + val_to_store = Gen.builder.trunc(loaded, pointee, name="cload_trunc") + elif isinstance(pointee, ir.PointerType) and isinstance(loaded.type, ir.PointerType): + val_to_store = Gen.builder.bitcast(loaded, pointee, name="cload_bitcast") + elif loaded.type != pointee: + target_ptr = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cload_cast") + loaded = Gen._load(target_ptr, name="cload_casted") + if loaded is None: + return ir.Constant(ir.IntType(32), 0) + val_to_store = loaded + Gen._store(val_to_store, dst_val) + return ir.Constant(ir.IntType(32), 1) + + def _HandleCDerefLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return ir.Constant(ir.IntType(64), 0) + arg_val = self.HandleExprLlvm(Node.args[0]) + if arg_val is None: + return ir.Constant(ir.IntType(32), 0) + if isinstance(arg_val.type, ir.PointerType): + loaded = Gen._load(arg_val, name="deref") + if loaded is not None: + return loaded + return arg_val + + def _HandleCPtrToIntLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return ir.Constant(ir.IntType(64), 0) + arg_val = self.HandleExprLlvm(Node.args[0]) + if arg_val is None: + return ir.Constant(ir.IntType(64), 0) + if isinstance(arg_val.type, ir.PointerType): + return Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptrtoint_result") + if isinstance(arg_val.type, ir.IntType): + if arg_val.type.width < 64: + return Gen.builder.zext(arg_val, ir.IntType(64), name="zext_ptrtoint") + elif arg_val.type.width > 64: + return Gen.builder.trunc(arg_val, ir.IntType(64), name="trunc_ptrtoint") + return arg_val + return ir.Constant(ir.IntType(64), 0) + + +class TSpecialCallHandle(BaseHandle): + + @staticmethod + def _ResolveTAttrToCName(attr: str) -> str: + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.GetClassByName(attr) + if ctype_cls is not None: + try: + inst = ctype_cls() + cname = getattr(inst, 'CName', '') + if cname: + return cname + except Exception: + pass + return None + + def _HandleTSpecialCallLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Node.args: + return None + attr = Node.func.attr + + if attr == 'CType': + return self._HandleCTypeLlvm(Node) + + target_type = self._ResolveTAttrToCName(attr) + if target_type is not None: + is_ptr_cast = False + if len(Node.args) >= 2: + second_arg = Node.args[1] + if isinstance(second_arg, ast.Attribute) and isinstance(second_arg.value, ast.Name) and second_arg.value.id == 't' and second_arg.attr == 'CPtr': + is_ptr_cast = True + elif isinstance(second_arg, ast.Name) and second_arg.id == 'CPtr': + is_ptr_cast = True + if is_ptr_cast: + return self._HandleTPtrCastLlvm(Node, attr) + if target_type == 'void': + target_type = 'void *' + return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type) + return None + + def _HandleCTypeLlvm(self, Node): + Gen = self.Trans.LlvmGen + arg_val = self.HandleExprLlvm(Node.args[0]) + if not arg_val: + return None + target_type_str = 'unsigned long long' + if len(Node.args) >= 2: + type_parts = [] + ptr_count = 0 + for i in range(1, len(Node.args)): + type_arg = Node.args[i] + if isinstance(type_arg, ast.Attribute) and isinstance(type_arg.value, ast.Name) and type_arg.value.id == 't': + type_attr = type_arg.attr + _PREFIX_MAP = { + 'CUnsigned': 'unsigned', 'CSigned': 'signed', + 'CConst': 'const', 'CVolatile': 'volatile', + } + if type_attr in _PREFIX_MAP: + type_parts.append(_PREFIX_MAP[type_attr]) + elif type_attr in ('CPtr', 'CArrayPtr'): + ptr_count += 1 + else: + resolved = self._ResolveTAttrToCName(type_attr) + if resolved is not None: + type_parts.append(resolved) + if type_parts: + target_type_str = ' '.join(type_parts) + if ptr_count > 0: + target_type_str += ' ' + '*' * ptr_count + if isinstance(arg_val.type, ir.PointerType): + int_val = Gen.builder.ptrtoint(arg_val, ir.IntType(64), name="ptr_to_int") + return int_val + return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], target_type_str) + + def _HandleTPtrCastLlvm(self, Node, attr): + Gen = self.Trans.LlvmGen + from lib.includes.t import CTypeRegistry + if attr in ('CChar', 'CUnsignedChar'): + first_arg = Node.args[0] + if isinstance(first_arg, ast.Call) and isinstance(first_arg.func, ast.Attribute) and isinstance(first_arg.func.value, ast.Name) and first_arg.func.value.id == 't' and first_arg.func.attr == 'CInt' and first_arg.args: + inner_val = self.HandleExprLlvm(first_arg.args[0]) + if isinstance(inner_val.type, ir.PointerType): + return Gen.builder.bitcast(inner_val, ir.PointerType(ir.IntType(8)), name=f"c{attr.lower()}_ptr_from_cint") + expr_val = self.HandleExprLlvm(Node.args[0]) + if isinstance(expr_val.type, ir.IntType) and expr_val.type.width == 8: + var = Gen._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"c{attr.lower()}_ptr") + zero = ir.Constant(ir.IntType(32), 0) + char_ptr = Gen.builder.gep(var, [zero, zero], name="char_ptr") + Gen._store(expr_val, char_ptr) + null_char = ir.Constant(ir.IntType(8), 0) + null_ptr = Gen.builder.gep(var, [zero, ir.Constant(ir.IntType(32), 1)], name="null_ptr") + Gen._store(null_char, null_ptr) + return char_ptr + elif isinstance(expr_val.type, ir.PointerType): + if isinstance(expr_val.type.pointee, ir.PointerType): + loaded_ptr = Gen._load(expr_val, name="load_ptr") + if isinstance(loaded_ptr.type, ir.PointerType) and isinstance(loaded_ptr.type.pointee, ir.IntType) and loaded_ptr.type.pointee.width == 8: + return loaded_ptr + if isinstance(expr_val.type.pointee, ir.IntType) and expr_val.type.pointee.width == 8: + return expr_val + return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(8)), name="cast_to_char_ptr") + elif isinstance(expr_val.type, ir.IntType): + if expr_val.type.width == 32: + expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") + return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(8)), name=f"inttoptr_c{attr.lower()}") + return Gen.emit_constant(0, 'int') + elif attr == 'CVoid': + return self.Trans.ExprCallHandle._HandleTypeCastLlvm(Node.args[0], 'void *') + elif attr == 'CInt': + expr_val = self.HandleExprLlvm(Node.args[0]) + if expr_val: + if isinstance(expr_val.type, ir.IntType): + if expr_val.type.width < 64: + expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") + return Gen.builder.inttoptr(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr") + return Gen.builder.bitcast(expr_val, ir.PointerType(ir.IntType(32)), name="cint_ptr") + else: + ctype_cls = CTypeRegistry.GetClassByName(attr) + if ctype_cls is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + target_type = Gen._type_str_to_llvm(llvm_str) + if target_type and isinstance(target_type, (ir.IntType, ir.FloatType, ir.DoubleType)): + target_ptr_type = ir.PointerType(target_type) + expr_val = self.HandleExprLlvm(Node.args[0]) + if expr_val: + if isinstance(expr_val.type, ir.IntType): + if expr_val.type.width < 64: + expr_val = Gen.builder.zext(expr_val, ir.IntType(64), name="zext_to_64") + return Gen.builder.inttoptr(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") + return Gen.builder.bitcast(expr_val, target_ptr_type, name=f"{attr.lower()}_ptr") + return None diff --git a/lib/core/Handles/HandlesTry.py b/lib/core/Handles/HandlesTry.py new file mode 100644 index 0000000..93e63d4 --- /dev/null +++ b/lib/core/Handles/HandlesTry.py @@ -0,0 +1,211 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP +import ast +import llvmlite.ir as ir + + +class TryHandle(BaseHandle): + def _get_exception_type_code(self, type_node): + if isinstance(type_node, ast.Name): + name = type_node.id + if name in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[name] + if name in self.Trans.exception_registry: + return self.Trans.exception_registry[name] + return 1 + if isinstance(type_node, ast.Attribute): + name = type_node.attr + if name in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[name] + if name in self.Trans.exception_registry: + return self.Trans.exception_registry[name] + return 1 + if isinstance(type_node, ast.Tuple): + for elt in type_node.elts: + code = self._get_exception_type_code(elt) + if code != 1: + return code + return 1 + return 1 + + def _get_exception_name(self, type_node): + if isinstance(type_node, ast.Name): + return type_node.id + if isinstance(type_node, ast.Attribute): + return type_node.attr + return None + + def _get_all_match_codes(self, type_node): + name = self._get_exception_name(type_node) + if name is None: + return [self._get_exception_type_code(type_node)] + if name not in self.Trans.exception_registry: + return [self._get_exception_type_code(type_node)] + codes = [self.Trans.exception_registry[name]] + self._collect_descendant_codes(name, codes) + return codes + + def _collect_descendant_codes(self, parent_name, codes): + for child_name, parent in self.Trans.exception_parents.items(): + if parent == parent_name: + child_code = self.Trans.exception_registry.get(child_name) + if child_code is not None and child_code not in codes: + codes.append(child_code) + self._collect_descendant_codes(child_name, codes) + + def _HandleTryLlvm(self, Node): + Gen = self.Trans.LlvmGen + if not Gen.func: + return + exception_code = Gen._alloca_entry(ir.IntType(32), name="eh_code") + eh_message = Gen._alloca_entry(ir.PointerType(ir.IntType(8)), name="eh_message") + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message) + HasFinally = bool(Node.finalbody) + if HasFinally: + Gen.eh_finally_stack.append((None, None, None)) + else: + Gen.eh_finally_stack.append(None) + DispatchBB = Gen.func.append_basic_block(name="try.dispatch") + AfterBB = Gen.func.append_basic_block(name="try.after") + except_blocks = [] + for i, handler in enumerate(Node.handlers): + ExcTypeCodes = [1] + if handler.type: + ExcTypeCodes = self._get_all_match_codes(handler.type) + ExceptBB = Gen.func.append_basic_block(name=f"try.except_{i}") + Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message)) + except_blocks.append((ExceptBB, ExcTypeCodes, handler)) + TryBB = Gen.func.append_basic_block(name="try.body") + ElseBB = None + if Node.orelse: + ElseBB = Gen.func.append_basic_block(name="try.else") + Gen.builder.branch(TryBB) + Gen.builder.position_at_start(TryBB) + self.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + if ElseBB: + Gen.builder.branch(ElseBB) + else: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(DispatchBB) + eh_code_val = Gen._load(exception_code, name="load_eh_code") + next_check_bb = None + handler_var_map = {} + UnhandledBB = Gen.func.append_basic_block(name="try.unhandled") + for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): + MatchBB = Gen.func.append_basic_block(name=f"try.match_{i}") + if i > 0 and next_check_bb is not None: + Gen.builder.position_at_start(next_check_bb) + eh_code_val = Gen._load(exception_code, name=f"load_eh_code_{i}") + if handler.type is None: + Gen.builder.branch(MatchBB) + else: + match_cond = None + for code in ExcTypeCodes: + is_code_match = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}") + if match_cond is None: + match_cond = is_code_match + else: + match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}") + if i < len(except_blocks) - 1: + next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}") + else: + next_check_bb = UnhandledBB + Gen.builder.cbranch(match_cond, MatchBB, next_check_bb) + Gen.builder.position_at_start(MatchBB) + if handler.name: + var_alloca = Gen._alloca_entry(ir.IntType(8).as_pointer(), name=handler.name) + eh_msg_val = Gen._load(eh_message, name=f"load_eh_msg_{handler.name}") + Gen._store(eh_msg_val, var_alloca) + handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name)) + Gen.builder.branch(ExceptBB) + Gen.builder.position_at_start(UnhandledBB) + eh_msg_out_arg = None + eh_code_out_arg = None + if Gen.func and len(Gen.func.args) > 0: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_out_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_out_arg = arg + if eh_msg_out_arg is not None and eh_code_out_arg is not None: + eh_msg_val = Gen._load(eh_message, name="load_eh_msg_propagate") + eh_code_val_prop = Gen._load(exception_code, name="load_eh_code_propagate") + Gen._store(eh_msg_val, eh_msg_out_arg) + Gen._store(eh_code_val_prop, eh_code_out_arg) + ret_type = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None + if isinstance(ret_type, ir.IdentifiedStructType): + if ret_type.elements: + zero_val = ir.Constant(ret_type, [ + ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) + else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) + else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + Gen.builder.ret(zero_val) + elif isinstance(ret_type, ir.PointerType): + Gen.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + Gen.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.IntType): + Gen.builder.ret(ir.Constant(ret_type, 1)) + elif isinstance(ret_type, ir.VoidType): + Gen.builder.ret_void() + else: + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + Gen.builder.branch(AfterBB) + for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): + Gen.builder.position_at_start(ExceptBB) + old_var = None + if idx in handler_var_map: + hname, var_alloca, old_var = handler_var_map[idx] + Gen.variables[hname] = var_alloca + self.HandleBodyLlvm(handler.body) + if idx in handler_var_map: + hname, _, old_var = handler_var_map[idx] + if old_var is not None: + Gen.variables[hname] = old_var + elif hname in Gen.variables: + del Gen.variables[hname] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.eh_except_block_stack.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + if HasFinally: + Gen.eh_finally_stack.pop() + if Node.finalbody: + FinallyBB = Gen.func.append_basic_block(name="try.finally") + pending_ret_flag = Gen._alloca_entry(ir.IntType(32), name="pending_ret_flag") + pending_ret_val = Gen._alloca_entry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None + Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val)) + Gen.builder.branch(FinallyBB) + Gen.builder.position_at_start(FinallyBB) + Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag) + self.HandleBodyLlvm(Node.finalbody) + if Gen.eh_finally_stack: + _, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1] + Gen.eh_finally_stack.pop() + ret_flag_val = Gen._load(pending_ret_flag, name="load_ret_flag") + ret_flag_is_set = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag") + RetBB = Gen.func.append_basic_block(name="finally.ret") + ContinueBB = Gen.func.append_basic_block(name="try.continue") + Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB) + Gen.builder.position_at_start(RetBB) + if pending_ret_val: + ret_val = Gen._load(pending_ret_val, name="load_ret_val") + Gen.builder.ret(ret_val) + else: + Gen.builder.ret_void() + Gen.builder.position_at_start(ContinueBB) \ No newline at end of file diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py new file mode 100644 index 0000000..09ccf98 --- /dev/null +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -0,0 +1,1052 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from typing import List +from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo, StrictMode +from lib.includes import t +import importlib +import ast +import sys +import os + + +class HandlesTypeMerge(BaseHandle): + """处理类型合并逻辑 - 所有类型分析的核心模块""" + + def _MakeVoidCTypeInfo(self) -> CTypeInfo: + Info = CTypeInfo() + Info.BaseType = t.CVoid + return Info + + @staticmethod + def _MakeCTypeInfoFromName(TypeName: str) -> CTypeInfo: + """直接从类型名构造 CTypeInfo,不经过 FromStr/字符串解析""" + return CTypeInfo.FromTypeName(TypeName) + + def GetCTypeInfo(self, Node: ast.AST) -> CTypeInfo: + """获取 CTypeInfo 对象""" + Result = self._GetCTypeInfoInternal(Node) + if isinstance(Result, CTypeInfo): + return Result + elif isinstance(Result, str): + return self._MakeCTypeInfoFromName(Result) + else: + return self._MakeVoidCTypeInfo() + + def _GetCTypeInfoInternal(self, Node: ast.AST): + """鍐呴儴鏂规硶锛岃繑鍥?CTypeInfo""" + LineNum = getattr(Node, 'lineno', None) + + self.Trans.DebugPrint(f"[GetCTypeInfo] Node type: {type(Node).__name__}, dump: {ast.dump(Node)[:60]}...") + + if isinstance(Node, (ast.Constant, ast.Str)): + if isinstance(Node, ast.Constant): + TypeName = Node.value + else: + TypeName = Node.s + return self._MakeCTypeInfoFromName(TypeName) + + if isinstance(Node, ast.Name): + TypeName = Node.id + t_c_imported = getattr(self.Trans, '_t_c_imported_names', {}) + if TypeName in t_c_imported: + src_module, src_name = t_c_imported[TypeName] + virtual_attr = ast.Attribute( + value=ast.Name(id=src_module, ctx=ast.Load()), + attr=src_name, + ctx=ast.Load() + ) + ast.copy_location(virtual_attr, Node) + return self.GetCTypeInfo(virtual_attr) + if TypeName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[TypeName] + if Entry and Entry.IsTypedef: + if isinstance(Entry, CTypeInfo) and Entry.BaseType: + if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0: + Result = Entry.Copy() + Result.IsTypedef = True + Result.Name = TypeName + return Result + if Entry.OriginalType: + if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr: + Result = CTypeInfo() + Result.IsFuncPtr = True + Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else [] + Result.IsTypedef = True + Result.Name = TypeName + return Result + elif isinstance(Entry.OriginalType, CTypeInfo): + Resolved = Entry.OriginalType.Copy() + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + return Entry + if isinstance(Entry, CTypeInfo) and Entry.IsEnum: + return Entry.Copy() + if isinstance(Entry, dict) and Entry.get('IsEnum'): + Result = CTypeInfo() + Result.BaseType = t.CEnum(TypeName) + Result.IsEnum = True + return Result + return self._MakeCTypeInfoFromName(TypeName) + + elif isinstance(Node, ast.Attribute): + ModuleParts = [] + Current = Node + while isinstance(Current, ast.Attribute): + ModuleParts.insert(0, Current.attr) + Current = Current.value + + if isinstance(Current, ast.Name): + ModuleParts.insert(0, Current.id) + + if len(ModuleParts) >= 2: + TypeName = ModuleParts[-1] + ModulePath = '.'.join(ModuleParts[:-1]) + elif len(ModuleParts) == 1: + TypeName = ModuleParts[0] + ModulePath = None + else: + return self._MakeVoidCTypeInfo() + + # 解析 import 别名: 如 import fat32_types as types -> types -> fat32_types + if ModulePath: + import_aliases = getattr(self.Trans, '_import_aliases', {}) + if ModulePath in import_aliases: + ModulePath = import_aliases[ModulePath] + else: + # 也尝试在符号表中查找模块别名 + if ModulePath in self.Trans.SymbolTable: + entry = self.Trans.SymbolTable[ModulePath] + if isinstance(entry, CTypeInfo) and getattr(entry, 'IsModuleAlias', False): + resolved = getattr(entry, 'ResolvedModule', None) + if resolved: + ModulePath = resolved + + self.Trans.DebugPrint(f"[GetCTypeInfo-Attribute] 查询: '{TypeName}' ModulePath: {ModulePath}") + + if ModulePath == 't' and TypeName == 'State': + Info = CTypeInfo() + Info.BaseType = t.CVoid + Info.IsState = True + return Info + + if ModulePath == 't' or (ModulePath and ModulePath.startswith('t.')): + if self._IsTModuleType(TypeName): + TypeClass = CTypeHelper.GetTModuleCType(TypeName) or getattr(t, TypeName, None) + if TypeClass == t.CArrayPtr: + Info = CTypeInfo() + Info.IsArrayPtr = True + Info.BaseType = t.CVoid + return Info + elif TypeClass == t.CPtr: + Info = CTypeInfo() + Info.PtrCount = 1 + Info.BaseType = t.CVoid + return Info + elif TypeClass == t.CConst: + Info = CTypeInfo() + Info.DataConst = True + Info.BaseType = t.CVoid + return Info + elif TypeClass == t.CVolatile: + Info = CTypeInfo() + Info.DataVolatile = True + Info.BaseType = t.CVoid + return Info + elif TypeClass == t.CInline: + Info = CTypeInfo() + Info.Storage = t.CInline() + Info.BaseType = t.CVoid + return Info + elif TypeClass == t.CStatic: + Info = CTypeInfo() + Info.Storage = t.CStatic() + Info.BaseType = t.CVoid + return Info + elif TypeClass == t.CExtern: + Info = CTypeInfo() + Info.Storage = t.CExtern() + Info.BaseType = t.CVoid + return Info + elif TypeClass == t.CExport: + Info = CTypeInfo() + Info.Storage = t.CExport() + Info.BaseType = t.CVoid + return Info + elif TypeClass: + Info = CTypeInfo() + Info.BaseType = TypeClass + return Info + elif CTypeHelper.GetCName(TypeName): + return self._MakeCTypeInfoFromName(CTypeHelper.GetCName(TypeName)) + + FullName = f"{ModulePath}.{TypeName}" if ModulePath else TypeName + + if TypeName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[TypeName] + if Entry and Entry.IsTypedef: + if isinstance(Entry, CTypeInfo) and Entry.BaseType: + if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0: + Result = Entry.Copy() + Result.IsTypedef = True + Result.Name = TypeName + return Result + if Entry.OriginalType: + if isinstance(Entry.OriginalType, CTypeInfo): + Resolved = Entry.OriginalType.Copy() + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + Result = CTypeInfo() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + return Result + if Entry: + # If BaseType is None but this is a class/struct, set BaseType to CStruct + Result = Entry.Copy() + if Result.BaseType is None: + Result.BaseType = t.CStruct(name=TypeName) + Result.IsStruct = True + return Result + return CTypeInfo() + + if FullName in self.Trans.SymbolTable: + Info = self.Trans.SymbolTable[FullName] + if Info and Info.IsTypedef: + if isinstance(Info, CTypeInfo) and Info.BaseType and (not isinstance(Info.BaseType, (t._CTypedef,)) or Info.PtrCount > 0): + Result = Info.Copy() + Result.IsTypedef = True + Result.Name = TypeName + return Result + if Info.OriginalType: + if isinstance(Info.OriginalType, CTypeInfo): + Resolved = Info.OriginalType.Copy() + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + Result = CTypeInfo() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + return Result + return Info.Copy() if Info else CTypeInfo() + + if TypeName not in self.Trans.SymbolTable: + if not self._IsTModuleType(TypeName) and not (ModulePath and ModulePath.startswith(('t.', 'c.'))): + IsEnumMember = False + FirstName = ModuleParts[0] + if FirstName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[FirstName] + if Entry and Entry.IsEnum: + IsEnumMember = True + + if not IsEnumMember and FullName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[FullName] + if Entry and Entry.IsEnumMember: + IsEnumMember = True + + IsVariable = False + if not IsEnumMember and FullName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[FullName] + if Entry and Entry.TypeCls is not None: + IsVariable = True + + TypeWarningLogged = getattr(self.Trans, '_TypeWarningLogged', set()) + if not IsEnumMember and not IsVariable and FullName not in TypeWarningLogged: + TypeWarningLogged.add(FullName) + if not getattr(self.Trans, '_TypeWarningLogged', None): + self.Trans._TypeWarningLogged = TypeWarningLogged + self.Trans.DebugPrint(f"[GetCTypeInfo-Attribute]{(' line ' + str(LineNum)) if LineNum else ''} 警告: 符号表中未找到类?'{FullName}'") + + FirstName = ModuleParts[0] + + FullName = f"{ModulePath}.{TypeName}" if ModulePath else TypeName + if FullName in self.Trans.SymbolTable: + Info = self.Trans.SymbolTable[FullName] + if Info and Info.IsEnumMember: + Result = CTypeInfo() + Result.BaseType = t._CTypedef(TypeName) + Result.IsEnumMember = True + return Result + if Info and Info.IsTypedef: + if isinstance(Info, CTypeInfo) and Info.BaseType and (not isinstance(Info.BaseType, (t._CTypedef,)) or Info.PtrCount > 0): + Result = Info.Copy() + Result.IsTypedef = True + Result.Name = TypeName + return Result + if Info.OriginalType: + if isinstance(Info.OriginalType, CTypeInfo): + Resolved = Info.OriginalType.Copy() + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + Result = CTypeInfo() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + return Result + return Info.Copy() if Info else CTypeInfo() + + if FirstName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[FirstName] + if Entry: + Result = CTypeInfo() + if Entry.IsEnum: + Result.BaseType = t.CEnum(TypeName) + return Result + if Entry.IsTypedef and Entry.OriginalType: + if isinstance(Entry.OriginalType, CTypeInfo): + if Entry.OriginalType.IsEnum: + EnumName = TypeName + elif isinstance(Entry.OriginalType.BaseType, t.CEnum): + EnumName = Entry.OriginalType.BaseType.name or TypeName + elif isinstance(Entry.OriginalType.BaseType, t.CStruct): + EnumName = Entry.OriginalType.BaseType.name or TypeName + else: + EnumName = None + else: + EnumName = CTypeHelper.StripTypePrefix(Entry.OriginalType) + if EnumName and EnumName in self.Trans.SymbolTable: + EnumEntry = self.Trans.SymbolTable[EnumName] + if EnumEntry and EnumEntry.IsEnum: + Result.BaseType = t._CTypedef(TypeName) + Result.IsEnumMember = True + return Result + + if FirstName in self.Trans.GeneratedTypes: + if FirstName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[FirstName] + if Entry and Entry.IsEnum: + Result.BaseType = t.CEnum(TypeName) + return Result + + if len(ModuleParts) >= 2 and ModuleParts[-1] == 'State' and ModuleParts[-2] == 't': + Result = CTypeInfo() + Result.BaseType = t.CVoid + Result.IsState = True + return Result + + if ModulePath: + ModuleName = ModulePath + else: + ModuleName = None + + if ModuleName: + if ModuleName not in self.Trans._UserTypeModules: + try: + CurrentDir = os.path.dirname(os.path.abspath(__file__)) + ProjectRoot = os.path.dirname(os.path.dirname(os.path.dirname(CurrentDir))) + if ProjectRoot not in sys.path: + sys.path.insert(0, ProjectRoot) + + Module = importlib.import_module(ModuleName) + self.Trans._UserTypeModules[ModuleName] = Module + + if ModuleName in self.Trans.AnnotationModules: + for AttrName in dir(Module): + Attr = getattr(Module, AttrName) + if isinstance(Attr, type) and issubclass(Attr, t.CType) and Attr is not t.CType: + AttrInfo = CTypeInfo() + AttrInfo.Name = AttrName + AttrInfo.IsTypedef = True + try: + inst = Attr() + OriginalInfo = CTypeInfo() + OriginalInfo.BaseType = inst + AttrInfo.OriginalType = OriginalInfo + except Exception: + AttrInfo.OriginalType = self._MakeCTypeInfoFromName(Attr().CName) if hasattr(Attr(), 'CName') else None + self.Trans.SymbolTable[AttrName] = AttrInfo + except Exception as e: + self.Trans._UserTypeModules[ModuleName] = None + + FullName = f'{ModulePath}.{TypeName}' if ModulePath else TypeName + if FullName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[FullName] + if Entry and Entry.IsTypedef: + if isinstance(Entry, CTypeInfo) and Entry.BaseType: + if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0: + Result = Entry.Copy() + Result.IsTypedef = True + Result.Name = TypeName + return Result + if Entry.OriginalType: + if isinstance(Entry.OriginalType, CTypeInfo): + Resolved = Entry.OriginalType.Copy() + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + Result = CTypeInfo() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + return Result + return Entry.Copy() if Entry else CTypeInfo() + + if TypeName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[TypeName] + if Entry and Entry.IsTypedef: + if isinstance(Entry, CTypeInfo) and Entry.BaseType: + if not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0: + Result = Entry.Copy() + Result.IsTypedef = True + Result.Name = TypeName + return Result + if Entry.OriginalType: + if isinstance(Entry.OriginalType, CTypeInfo): + Resolved = Entry.OriginalType.Copy() + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + Result = CTypeInfo() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + return Result + return Entry.Copy() if Entry else CTypeInfo() + + if ModuleName == 't': + TypeObj = CTypeHelper.GetTModuleCType(TypeName) + if TypeObj is None: + TypeObj = getattr(t, TypeName, None) + if TypeObj is None: + return None + Info = CTypeInfo() + Info.BaseType = TypeObj + return Info + + IsEnumMember = False + if ModuleParts and len(ModuleParts) >= 2: + FirstName = ModuleParts[0] + if FirstName in self.Trans.SymbolTable: + Entry = self.Trans.SymbolTable[FirstName] + if Entry and Entry.IsEnum: + return TypeName + + FullTypeName = f'{ModuleName}.{TypeName}' + + if StrictMode: + self.Trans.LogError(f"类型 '{FullTypeName}' 未在符号表中找到,严格模式下需要定义此类型", LineNum) + sys.exit(1) + else: + self.Trans.LogWarning(f"类型 '{FullTypeName}' 未在符号表中找到,假定为 struct {TypeName}", LineNum) + Info = CTypeInfo() + Info.Name = TypeName + Info.IsStruct = True + Info.BaseType = t.CStruct(name=TypeName) + return Info + + return self._MakeVoidCTypeInfo() + + elif isinstance(Node, ast.Call): + if isinstance(Node.func, ast.Name) and Node.func.id == 'callable': + ReturnTypeInfo = self._GetCTypeInfoInternal(Node.args[0]) if Node.args else None + if isinstance(ReturnTypeInfo, CTypeInfo): + ReturnType = ReturnTypeInfo + else: + ReturnType = CTypeInfo() + ReturnType.BaseType = t.CVoid() + + ParamTypes = [] + ParamNames = [] + for kw in Node.keywords: + ParamTypeInfo = self._GetCTypeInfoInternal(kw.value) + if not isinstance(ParamTypeInfo, CTypeInfo): + ParamTypeInfo = self._MakeCTypeInfoFromName('int') + ParamTypes.append(ParamTypeInfo) + ParamNames.append(kw.arg) + + for arg in Node.args[1:]: + if isinstance(arg, ast.Tuple): + for elt in arg.elts: + ParamTypeInfo = self._GetCTypeInfoInternal(elt) + if not isinstance(ParamTypeInfo, CTypeInfo): + ParamTypeInfo = self._MakeCTypeInfoFromName('int') + ParamTypes.append(ParamTypeInfo) + ParamNames.append('') + else: + ParamTypeInfo = self._GetCTypeInfoInternal(arg) + if not isinstance(ParamTypeInfo, CTypeInfo): + ParamTypeInfo = self._MakeCTypeInfoFromName('int') + ParamTypes.append(ParamTypeInfo) + ParamNames.append('') + + if not ParamTypes: + ParamTypes.append(self._MakeCTypeInfoFromName('void')) + ParamNames.append('') + + Info = CTypeInfo() + Info.IsFuncPtr = True + Info.FuncPtrReturn = ReturnType + Info.FuncPtrParams = list(zip(ParamNames, ParamTypes)) + return Info + + if isinstance(Node.func, ast.Attribute) and isinstance(Node.func.value, ast.Name): + ModuleName = Node.func.value.id + TypeName = Node.func.attr + + if ModuleName == 't' and CTypeHelper.GetTModuleCType(TypeName) == t._CTypedef and Node.args: + TypeArg = Node.args[0] + if isinstance(TypeArg, ast.Name): + return TypeArg.id + elif isinstance(TypeArg, ast.Attribute): + AttrModule = TypeArg.value.id if isinstance(TypeArg.value, ast.Name) else None + AttrName = TypeArg.attr + if AttrModule == 't' and getattr(t, AttrName, None): + TypeObj = getattr(t, AttrName) + if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType): + return TypeObj().CName + return AttrName + elif isinstance(TypeArg, ast.Constant): + return str(TypeArg.value) + + if ModuleName in self.Trans._UserTypeModules: + module = self.Trans._UserTypeModules[ModuleName] + if getattr(module, TypeName, None): + TypeObj = getattr(module, TypeName) + if isinstance(TypeObj, type): + if issubclass(TypeObj, t.CType): + return TypeObj().CName + + if ModuleName == 't': + TypeObj = CTypeHelper.GetTModuleCType(TypeName) + if TypeObj is None: + TypeObj = getattr(t, TypeName, None) + if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType): + Result = CTypeInfo() + Result.BaseType = TypeObj + return Result + + if ModuleName == 't' and TypeName == 'State': + Result = CTypeInfo() + Result.IsState = True + return Result + + if ModuleName == 't' and TypeName == 'Bit': + if Node.args and isinstance(Node.args[0], ast.Constant): + BitWidth = Node.args[0].value + Result = CTypeInfo() + Result.IsBitField = True + Result.BitWidth = BitWidth + Result.BaseType = t.CInt + return Result + + Result = CTypeInfo() + Result.BaseType = t.CVoid + return Result + + elif isinstance(Node, ast.Subscript): + if (isinstance(Node.value, ast.Attribute) + and isinstance(Node.value.value, ast.Name) + and Node.value.value.id == 't' + and Node.value.attr == 'Bit'): + if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int): + Result = CTypeInfo() + Result.IsBitField = True + Result.BitWidth = Node.slice.value + Result.BaseType = t.CInt + return Result + return self._HandleSubscript(Node) + + elif isinstance(Node, ast.BinOp): + return self.MergeTypes(Node) + + elif isinstance(Node, ast.List): + if Node.elts: + BaseTypes = [] + for elt in Node.elts: + EltType = self._GetCTypeInfoInternal(elt) + if isinstance(EltType, CTypeInfo) and EltType.BaseType: + BaseTypes.append(EltType.BaseType) + if BaseTypes: + Result = CTypeInfo() + Result.BaseType = tuple(BaseTypes) + return Result + return self._MakeVoidCTypeInfo() + + return self._MakeVoidCTypeInfo() + + def _HandleSubscript(self, Node): + """澶勭悊 Subscript 鑺傜偣锛屼娇鐢?CTypeInfo 鏍戝舰缁撴瀯鍒嗘瀽 AST + + 例如? + t.CVoid[5] -> void *[5] + t.CPtr[t.CPtr[t.CPtr]][5][6] -> void ***[5][6] + t.CArrayPtr[t.CArrayPtr] -> void *(*)[] + t.CPtr[t.CArrayPtr[t.CArrayPtr]] -> void *(*(*))[] + """ + def CollectAll(node, ParentIsArrayPtr=False) -> CTypeInfo: + """鏀堕泦绫诲瀷淇℃伅锛岃繑鍥?CTypeInfo""" + if isinstance(node, ast.Subscript): + value_node = node.value + slice_node = node.slice + + if isinstance(value_node, ast.Attribute): + VtInfo = self.GetCTypeInfo(value_node) + + if isinstance(value_node, ast.Attribute) and value_node.attr == 'Callable' and isinstance(value_node.value, ast.Name) and value_node.value.id == 't': + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + params_list = slice_node.elts[0] + return_node = slice_node.elts[1] + ParamTypes = [] + ParamNames = [] + if isinstance(params_list, ast.List): + for elt in params_list.elts: + ParamTypeInfo = self._GetCTypeInfoInternal(elt) + if isinstance(ParamTypeInfo, CTypeInfo): + ParamTypes.append(ParamTypeInfo) + ParamNames.append('') + else: + ParamTypes.append(self._MakeCTypeInfoFromName('int')) + ParamNames.append('') + if not ParamTypes: + ParamTypes.append(self._MakeCTypeInfoFromName('void')) + ParamNames.append('') + ReturnTypeInfo = self._GetCTypeInfoInternal(return_node) + if isinstance(ReturnTypeInfo, CTypeInfo): + ReturnType = ReturnTypeInfo + else: + ReturnType = CTypeInfo() + ReturnType.BaseType = t.CVoid() + Info = CTypeInfo() + Info.IsFuncPtr = True + Info.FuncPtrReturn = ReturnType + Info.FuncPtrParams = list(zip(ParamNames, ParamTypes)) + return Info + + if VtInfo and VtInfo.IsArrayPtr: + ResultInfo = CTypeInfo() + ResultInfo.PtrCount = VtInfo.PtrCount + ResultInfo.IsArrayPtr = True + if isinstance(slice_node, ast.Attribute): + SliceVtInfo = self.GetCTypeInfo(slice_node) + if SliceVtInfo and SliceVtInfo.IsArrayPtr: + ResultInfo.ArrayPtr = CTypeInfo() + ResultInfo.ArrayPtr.IsArrayPtr = True + ResultInfo.ArrayPtr.PtrCount = SliceVtInfo.PtrCount + if SliceVtInfo.ArrayPtr: + ResultInfo.ArrayPtr.ArrayPtr = SliceVtInfo.ArrayPtr + elif SliceVtInfo and SliceVtInfo.PtrCount > 0: + ResultInfo.ArrayPtr = SliceVtInfo + else: + ResultInfo.ArrayPtr = CTypeInfo() + ResultInfo.ArrayPtr.IsArrayPtr = True + elif isinstance(slice_node, ast.Subscript): + ResultInfo.ArrayPtr = CollectAll(slice_node) + elif isinstance(slice_node, ast.Name): + ResultInfo.ArrayPtr = CTypeInfo() + ResultInfo.ArrayPtr.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType + elif isinstance(slice_node, ast.BinOp): + ResultInfo.ArrayPtr = CTypeInfo() + try: + ResultInfo.ArrayPtr.ArrayDims.append(ast.unparse(slice_node)) + except Exception: # 回退:unparse 失败时用 'N' + ResultInfo.ArrayPtr.ArrayDims.append('N') + elif isinstance(slice_node, ast.Constant): + ResultInfo.ArrayPtr = CTypeInfo() + ResultInfo.ArrayPtr.ArrayDims.append(str(slice_node.value)) + else: + ResultInfo.ArrayPtr = CTypeInfo() + ResultInfo.ArrayPtr.IsArrayPtr = True + elif VtInfo and VtInfo.PtrCount == 1 and not VtInfo.ArrayPtr: + ResultInfo = CTypeInfo() + ResultInfo.BaseType = t.CVoid + ResultInfo.PtrCount = 1 + if isinstance(slice_node, ast.Subscript): + inner_info = CollectAll(slice_node) + if inner_info and inner_info.PtrCount > 0: + ResultInfo.PtrCount += inner_info.PtrCount + if inner_info.BaseType and not isinstance(inner_info.BaseType, t.CVoid): + ResultInfo.BaseType = inner_info.BaseType + elif inner_info and inner_info.ArrayPtr: + ResultInfo.ArrayPtr = inner_info + elif inner_info and inner_info.BaseType and not isinstance(inner_info.BaseType, t.CVoid): + ResultInfo.BaseType = inner_info.BaseType + elif isinstance(slice_node, ast.Attribute): + SliceVtInfo = self.GetCTypeInfo(slice_node) + if SliceVtInfo and SliceVtInfo.PtrCount == 1 and not SliceVtInfo.ArrayPtr: + ResultInfo.PtrCount = 2 + if SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid): + ResultInfo.BaseType = SliceVtInfo.BaseType + elif SliceVtInfo and SliceVtInfo.IsArrayPtr: + inner = CTypeInfo() + inner.ArrayPtr = CTypeInfo() + ResultInfo.ArrayPtr = inner + elif SliceVtInfo and SliceVtInfo.ArrayPtr: + ResultInfo.ArrayPtr = SliceVtInfo + elif SliceVtInfo and SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid): + ResultInfo.BaseType = SliceVtInfo.BaseType + elif isinstance(slice_node, ast.Name): + SliceType = getattr(t, slice_node.id, None) + if SliceType == t.CPtr: + ResultInfo.PtrCount += 1 + elif SliceType == t.CArrayPtr: + inner = CTypeInfo() + inner.ArrayPtr = CTypeInfo() + ResultInfo.ArrayPtr = inner + else: + ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType + elif isinstance(slice_node, ast.BinOp): + merged = self.MergeTypes(slice_node) + if merged: + ResultInfo.PtrCount += merged.PtrCount + if merged.BaseType and not isinstance(merged.BaseType, t.CVoid): + ResultInfo.BaseType = merged.BaseType + if merged.ArrayPtr: + ResultInfo.ArrayPtr = merged.ArrayPtr + elif isinstance(slice_node, ast.Constant): + ResultInfo.ArrayDims.append(str(slice_node.value)) + elif VtInfo: + ResultInfo = CTypeInfo() + ResultInfo.BaseType = VtInfo.BaseType + if isinstance(slice_node, ast.Constant): + ResultInfo.ArrayDims.append(str(slice_node.value)) + elif isinstance(slice_node, ast.Name): + ResultInfo.ArrayDims.append(slice_node.id) + elif isinstance(slice_node, ast.BinOp): + try: + ResultInfo.ArrayDims.append(ast.unparse(slice_node)) + except Exception: # 回退:unparse 失败时用 'N' + ResultInfo.ArrayDims.append('N') + elif isinstance(slice_node, ast.Subscript): + ResultInfo.ArrayPtr = CollectAll(slice_node) + else: + ResultInfo = CTypeInfo() + if isinstance(slice_node, ast.Constant): + ResultInfo.ArrayDims.append(str(slice_node.value)) + elif isinstance(slice_node, ast.Name): + SliceType = getattr(t, slice_node.id, None) + if SliceType == t.CPtr: + ResultInfo.PtrCount += 1 + elif SliceType == t.CArrayPtr: + ResultInfo.ArrayPtr = CTypeInfo() + else: + ResultInfo.ArrayDims.append(slice_node.id) + elif isinstance(value_node, ast.Subscript): + ResultInfo = CollectAll(value_node) + if isinstance(slice_node, ast.Attribute): + SliceVtInfo = self.GetCTypeInfo(slice_node) + if SliceVtInfo and SliceVtInfo.PtrCount >= 1 and not SliceVtInfo.ArrayPtr: + ResultInfo.PtrCount += SliceVtInfo.PtrCount + if SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid): + ResultInfo.BaseType = SliceVtInfo.BaseType + elif SliceVtInfo and SliceVtInfo.IsArrayPtr: + NewInfo = CTypeInfo() + NewInfo.ArrayPtr = ResultInfo + ResultInfo = NewInfo + elif SliceVtInfo and SliceVtInfo.BaseType and not isinstance(SliceVtInfo.BaseType, t.CVoid): + ResultInfo.BaseType = SliceVtInfo.BaseType + elif isinstance(slice_node, ast.Subscript): + InnerNode = CollectAll(slice_node) + if ResultInfo.ArrayPtr is None: + ResultInfo.ArrayPtr = InnerNode + else: + current = ResultInfo + while current.ArrayPtr is not None: + current = current.ArrayPtr + current.ArrayPtr = InnerNode + elif isinstance(slice_node, ast.Constant): + ResultInfo.ArrayDims.append(str(slice_node.value)) + elif isinstance(slice_node, ast.Name): + SliceType = getattr(t, slice_node.id, None) + if SliceType == t.CPtr: + ResultInfo.PtrCount += 1 + elif SliceType == t.CArrayPtr: + ResultInfo.ArrayPtr = CTypeInfo() + else: + ResultInfo.ArrayDims.append(slice_node.id) + elif isinstance(slice_node, ast.BinOp): + try: + ResultInfo.ArrayDims.append(ast.unparse(slice_node)) + except Exception: # 回退:unparse 失败时用 'N' + ResultInfo.ArrayDims.append('N') + elif isinstance(value_node, ast.Name): + ResultInfo = CTypeInfo() + if value_node.id == 'list': + if not isinstance(slice_node, ast.Tuple): + ElementType = self._GetCTypeInfoInternal(slice_node) + if ElementType and isinstance(ElementType, CTypeInfo): + ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else t.CVoid() + ResultInfo.PtrCount = ElementType.PtrCount + 1 + ResultInfo.IsFuncPtr = ElementType.IsFuncPtr + ResultInfo.FuncPtrReturn = ElementType.FuncPtrReturn + ResultInfo.FuncPtrParams = ElementType.FuncPtrParams + else: + ResultInfo.BaseType = t.CVoid() + ResultInfo.PtrCount = 1 + elif isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: + ElementType = self._GetCTypeInfoInternal(slice_node.elts[0]) + if ElementType and isinstance(ElementType, CTypeInfo): + ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else t.CVoid() + ResultInfo.PtrCount = ElementType.PtrCount + ResultInfo.IsFuncPtr = ElementType.IsFuncPtr + ResultInfo.FuncPtrReturn = ElementType.FuncPtrReturn + ResultInfo.FuncPtrParams = ElementType.FuncPtrParams + for elt in slice_node.elts[1:]: + if isinstance(elt, ast.Constant): + ResultInfo.ArrayDims.append(str(elt.value)) + elif isinstance(elt, ast.Name): + ResultInfo.ArrayDims.append(elt.id) + else: + try: + ResultInfo.ArrayDims.append(ast.unparse(elt)) + except Exception: # 回退:unparse 失败时用 'N' + ResultInfo.ArrayDims.append('N') + else: + ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(value_node.id).BaseType + else: + ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(value_node.id).BaseType + if isinstance(slice_node, ast.Constant): + ResultInfo.ArrayDims.append(str(slice_node.value)) + elif isinstance(slice_node, ast.Name): + SliceType = getattr(t, slice_node.id, None) + if SliceType == t.CPtr: + ResultInfo.PtrCount += 1 + elif SliceType == t.CArrayPtr: + ResultInfo.ArrayPtr = CTypeInfo() + else: + ResultInfo.ArrayDims.append(slice_node.id) + elif isinstance(slice_node, ast.BinOp): + try: + ResultInfo.ArrayDims.append(ast.unparse(slice_node)) + except Exception: # 回退:unparse 失败时用 'N' + ResultInfo.ArrayDims.append('N') + elif isinstance(slice_node, ast.Subscript): + InnerNode = CollectAll(slice_node) + ResultInfo.ArrayDims.extend(InnerNode.ArrayDims) + else: + ResultInfo = CTypeInfo() + + return ResultInfo + elif isinstance(node, ast.Attribute): + VtInfo = self.GetCTypeInfo(node) + result = CTypeInfo() + if VtInfo and VtInfo.IsArrayPtr: + result.ArrayPtr = CTypeInfo() + return result + elif VtInfo and VtInfo.PtrCount == 1 and not VtInfo.ArrayPtr: + result.BaseType = t.CVoid + result.PtrCount = 1 + return result + elif VtInfo and VtInfo.BaseType: + result.BaseType = VtInfo.BaseType + return result + else: + return CTypeInfo() + elif isinstance(node, ast.Name): + result = CTypeInfo() + result.BaseType = CTypeInfo.CreateFromTypeName(node.id).BaseType + return result + else: + return CTypeInfo() + + return CollectAll(Node) + + def _CollectAllOperandTypes(self, Node: ast.AST) -> List: + """递归收集所有操作数的类型(用于一次性合并)""" + Types = [] + + if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): + Types.extend(self._CollectAllOperandTypes(Node.left)) + Types.extend(self._CollectAllOperandTypes(Node.right)) + else: + Types.append(Node) + + return Types + + def _GetTypeFromNode(self, Node: ast.AST) -> CTypeInfo: + """浠?AST 鑺傜偣鑾峰彇绫诲瀷""" + if isinstance(Node, ast.Call): + if isinstance(Node.func, ast.Name) and Node.func.id == 'callable': + return self.GetCTypeInfo(Node) + elif isinstance(Node.func, ast.Attribute) and CTypeHelper.GetTModuleCType(Node.func.attr) == t._CTypedef: + return self.GetCTypeInfo(Node) + elif isinstance(Node.func, ast.Attribute) and Node.func.attr == 'Bit': + if Node.args and isinstance(Node.args[0], ast.Constant): + Result = CTypeInfo() + Result.BaseType = t.CInt + Result.IsBitField = True + Result.BitWidth = Node.args[0].value + return Result + return self._MakeVoidCTypeInfo() + elif isinstance(Node, ast.Subscript): + if (isinstance(Node.value, ast.Attribute) + and isinstance(Node.value.value, ast.Name) + and Node.value.value.id == 't' + and Node.value.attr == 'Bit'): + if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int): + Result = CTypeInfo() + Result.BaseType = t.CInt + Result.IsBitField = True + Result.BitWidth = Node.slice.value + return Result + return self.GetCTypeInfo(Node) + else: + return self.GetCTypeInfo(Node) + + def MergeTypes(self, Node: ast.BinOp): + """处理类型组合,如 t.CInt | t.CPtr ?t.CStatic | t.CInt + + 这是 | 运算符的类型合并处理函数 + 收集所有操作数,一次性合? + """ + if not isinstance(Node, ast.BinOp) or not isinstance(Node.op, ast.BitOr): + return None + + AllOperands = self._CollectAllOperandTypes(Node) + + AllTypes = [] + for Operand in AllOperands: + TypeItem = self._GetTypeFromNode(Operand) + AllTypes.append(TypeItem) + + if isinstance(Node.left, ast.Attribute): + LeftParts = [] + current = Node.left + while isinstance(current, ast.Attribute): + attr_type = getattr(t, current.attr, None) + if attr_type and isinstance(attr_type, type) and issubclass(attr_type, t.CType): + LeftParts.insert(0, attr_type) + current = current.value + if isinstance(current, ast.Name): + name_type = getattr(t, current.id, None) + if name_type and isinstance(name_type, type) and issubclass(name_type, t.CType): + LeftParts.insert(0, name_type) + if LeftParts and LeftParts[-1] == t._CTypedef: + for type_item in AllTypes: + if isinstance(type_item, CTypeInfo) and type_item.IsFuncPtr: + type_item.IsTypedef = True + type_item.OriginalType = CTypeInfo() + type_item.OriginalType.IsFuncPtr = True + type_item.OriginalType.FuncPtrReturn = type_item.FuncPtrReturn or CTypeInfo.VoidTypeInfo() + type_item.OriginalType.FuncPtrParams = list(type_item.FuncPtrParams) if type_item.FuncPtrParams else [] + return type_item + Result = CTypeInfo() + if isinstance(AllTypes[-1], CTypeInfo): + Result.BaseType = AllTypes[-1].BaseType + else: + Result.BaseType = t.CInt + Result.IsTypedef = True + return Result + + return self._MergeAllComponentTypes(*AllTypes) + + def _MergeAllComponentTypes(self, *Types: CTypeInfo) -> CTypeInfo: + """合并多个类型 - 直接使用 CTypeInfo 类""" + if not Types: + return CTypeInfo() + + Result = CTypeInfo() + + for TypeItem in Types: + if TypeItem is None: + continue + if TypeItem.IsState: + Result.IsState = True + if not Result.Storage: + Result.Storage = t.CExport() + continue + if TypeItem.IsBitField: + Result.BaseType = t.CInt + Result.IsBitField = True + Result.BitWidth = TypeItem.BitWidth + return Result + if TypeItem.IsFuncPtr: + Result.BaseType = t.CVoid + Result.IsFuncPtr = True + Result.FuncPtrParams = TypeItem.FuncPtrParams + Result.FuncPtrReturn = TypeItem.FuncPtrReturn + return Result + if TypeItem.IsTypedef: + if TypeItem.BaseType and (not isinstance(TypeItem.BaseType, (t._CTypedef,)) or TypeItem.PtrCount > 0): + if Result.BaseType is None or isinstance(Result.BaseType, (t.CVoid, t._CTypedef)): + Result.BaseType = TypeItem.BaseType + Result.Name = TypeItem.Name + Result.IsTypedef = True + Result.PtrCount = max(Result.PtrCount, TypeItem.PtrCount) + if TypeItem.OriginalType: + Result.OriginalType = TypeItem.OriginalType + else: + Result.IsTypedef = True + Result.Name = TypeItem.Name + if TypeItem.OriginalType: + Result.OriginalType = TypeItem.OriginalType + continue + self._MergeCTypeInfoInto(Result, TypeItem) + + if Result.BaseType is None: + Result.BaseType = t.CVoid + + return Result + + def _MergeCTypeInfoInto(self, Target: CTypeInfo, Source: CTypeInfo): + if Source.PtrCount > 0 and Source.BaseType and (Source.BaseType is t.CVoid or isinstance(Source.BaseType, t.CVoid)): + if Target.PtrCount < Source.PtrCount: + Target.PtrCount = Source.PtrCount + elif Source.PtrCount > 0 and Source.BaseType and Source.BaseType is not t.CVoid and not isinstance(Source.BaseType, t.CVoid): + if Target.BaseType is None or Target.BaseType is t.CVoid or isinstance(Target.BaseType, t.CVoid): + Target.BaseType = Source.BaseType + Target.PtrCount = Source.PtrCount + elif Target.PtrCount == 0: + Target.PtrCount = Source.PtrCount + elif Source.PtrCount > Target.PtrCount: + Target.PtrCount = Source.PtrCount + elif Source.PtrCount > Target.PtrCount: + Target.PtrCount = Source.PtrCount + if Source.BaseType and Source.BaseType is not t.CVoid and not isinstance(Source.BaseType, (t.CVoid, t._CTypedef)): + if Target.BaseType is None: + Target.BaseType = Source.BaseType + elif (Target.BaseType is t.CVoid or isinstance(Target.BaseType, t.CVoid)) and Target.PtrCount == 0: + Target.BaseType = Source.BaseType + elif (Source.BaseType is t.CVoid or isinstance(Source.BaseType, t.CVoid)) and Target.BaseType is None: + Target.BaseType = Source.BaseType + if Source.IsTypedef and Source.Name: + if Source.BaseType and (not isinstance(Source.BaseType, (t._CTypedef,)) or Source.PtrCount > 0): + if Target.BaseType is None or isinstance(Target.BaseType, (t.CVoid, t._CTypedef)): + Target.BaseType = Source.BaseType + Target.IsTypedef = True + Target.Name = Source.Name + if Source.OriginalType: + Target.OriginalType = Source.OriginalType + elif Target.BaseType is None or isinstance(Target.BaseType, (t.CVoid, t._CTypedef)): + if Source.OriginalType: + if isinstance(Source.OriginalType, CTypeInfo) and Source.OriginalType.BaseType: + Target.BaseType = Source.OriginalType.BaseType + Target.PtrCount = max(Target.PtrCount, Source.OriginalType.PtrCount) + Target.IsTypedef = True + Target.Name = Source.Name + Target.OriginalType = Source.OriginalType + elif isinstance(Source.OriginalType, CTypeInfo): + Target.IsTypedef = True + Target.Name = Source.Name + Target.OriginalType = Source.OriginalType + else: + Target.BaseType = t.CStruct(name=Source.Name) + Target.IsStruct = True + else: + Target.BaseType = t.CStruct(name=Source.Name) + Target.IsStruct = True + if Source.ArrayPtr: + if Target.ArrayPtr is None: + Target.ArrayPtr = Source.ArrayPtr + else: + if Source.PtrCount > Target.PtrCount: + Target.PtrCount = Source.PtrCount + Target.ArrayPtr = Source.ArrayPtr + if Source.PtrCount > 0: + Target.ArrayDims = [] + elif Source.ArrayDims: + Target.ArrayDims.extend(Source.ArrayDims) + if Source.VarConst: + Target.VarConst = True + if Source.VarVolatile: + Target.VarVolatile = True + if Source.DataConst: + Target.DataConst = True + if Source.DataVolatile: + Target.DataVolatile = True + if Source.IsFuncPtr: + Target.IsFuncPtr = True + Target.FuncPtrParams = Source.FuncPtrParams + Target.FuncPtrReturn = Source.FuncPtrReturn + if Source.Storage and not Target.Storage: + Target.Storage = Source.Storage diff --git a/lib/core/Handles/HandlesWhile.py b/lib/core/Handles/HandlesWhile.py new file mode 100644 index 0000000..aecbbd8 --- /dev/null +++ b/lib/core/Handles/HandlesWhile.py @@ -0,0 +1,54 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import llvmlite.ir as ir + + +class WhileHandle(BaseHandle): + def _HandleWhileLlvm(self, Node): + Gen = self.Trans.LlvmGen + if Gen._direct_values: + for var_name in list(Gen._direct_values.keys()): + OldVal = Gen._direct_values.pop(var_name) + if var_name not in Gen.variables or Gen.variables.get(var_name) is None: + saved_block = Gen.builder.block + entry_block = Gen.func.entry_basic_block + Gen.builder.position_at_start(entry_block) + var = Gen.builder.alloca(OldVal.type, name=var_name) + Gen._store(OldVal, var) + Gen.builder.position_at_end(saved_block) + Gen.variables[var_name] = var + CondBB = Gen.func.append_basic_block(name="while.cond") + BodyBB = Gen.func.append_basic_block(name="while.body") + ElseBB = Gen.func.append_basic_block(name="while.else") if Node.orelse else None + AfterBB = Gen.func.append_basic_block(name="while.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(CondBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + Cond = self.HandleExprLlvm(Node.test) + if Cond: + if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1: + if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)): + Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="whilecond") + else: + Cond = Gen.builder.icmp_signed('!=', Cond, Gen._zero_const(Cond.type), name="whilecond") + if not Gen.builder.block.is_terminated: + Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) + else: + if not Gen.builder.block.is_terminated: + Gen.builder.branch(ElseBB if ElseBB else AfterBB) + Gen.builder.position_at_start(BodyBB) + self.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) diff --git a/lib/core/Handles/HandlesWith.py b/lib/core/Handles/HandlesWith.py new file mode 100644 index 0000000..f6eae1d --- /dev/null +++ b/lib/core/Handles/HandlesWith.py @@ -0,0 +1,138 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import ast +import llvmlite.ir as ir + + +class WithHandle(BaseHandle): + def _HandleWithLlvm(self, Node): + Gen = self.Trans.LlvmGen + for item in Node.items: + context_expr = item.context_expr + asname = None + target = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None))) + if target and isinstance(target, ast.Name): + asname = target.id + ClassName = None + if isinstance(context_expr, ast.Call): + if isinstance(context_expr.func, ast.Name): + ClassName = context_expr.func.id + elif isinstance(context_expr.func, ast.Attribute): + ClassName = context_expr.func.attr + if ClassName and ClassName not in Gen.structs: + if ClassName in self.Trans.SymbolTable: + SymInfo = self.Trans.SymbolTable[ClassName] + if getattr(SymInfo, 'IsStruct', False) or getattr(SymInfo, 'IsRenum', False): + pass + else: + ClassName = None + else: + ClassName = None + elif isinstance(context_expr, ast.Name): + VarName = context_expr.id + if VarName in Gen.var_struct_class: + ClassName = Gen.var_struct_class[VarName] + ctx_val = self.HandleExprLlvm(context_expr) + if not ctx_val: + continue + original_ctx_val = ctx_val + if ClassName and isinstance(ctx_val.type, ir.PointerType): + pointee = ctx_val.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found = Gen.find_struct_by_pointee(pointee) + if found: + CN, ST = found + ClassName = CN + StructPtrType = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None + if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName): + ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx") + ctx_alloca = Gen._alloca_entry(ctx_val.type, name="__with_ctx") + Gen._store(ctx_val, ctx_alloca) + Gen._unregister_temp_ptr(ctx_val) + if ClassName: + Gen.var_struct_class['__with_ctx'] = ClassName + Gen._var_to_heap_ptr['__with_ctx'] = ctx_val + original_asname_heap_ptr = Gen._var_to_heap_ptr.get(asname) if asname else None + ctx_is_var_ref = isinstance(context_expr, ast.Name) + enter_result = None + if ClassName: + EnterFuncName = f'{ClassName}.__enter__' + if EnterFuncName in Gen.functions: + ctx_loaded = Gen._load(ctx_alloca, name="__with_ctx") + enter_call = Gen.builder.call(Gen.functions[EnterFuncName], [ctx_loaded], name="call_enter") + enter_result = enter_call + if isinstance(enter_call.type, ir.PointerType): + pointee = enter_call.type.pointee + if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + enter_result = Gen._load(enter_call, name="enter_deref") + elif self._is_char_pointer(enter_call) and StructPtrType: + enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter") + if asname and enter_result: + if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found = Gen.find_struct_by_pointee(enter_result.type.pointee) + if found: + CN, ST = found + Gen.var_struct_class[asname] = CN + Gen._var_to_heap_ptr[asname] = enter_result + Gen._register_local_heap_ptr(enter_result, VarName=asname) + if asname in Gen._reg_values: + OldVal = Gen._reg_values[asname] + var = Gen._alloca_entry(OldVal.type, name=asname) + Gen._store(OldVal, var) + Gen.variables[asname] = var + del Gen._reg_values[asname] + if asname in Gen.variables and Gen.variables[asname] is not None: + VarPtr = Gen.variables[asname] + if VarPtr.type.pointee == enter_result.type: + Gen._store(enter_result, VarPtr) + elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): + CastedVal = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}") + Gen._store(CastedVal, VarPtr) + else: + NewVar = Gen._alloca(enter_result.type, name=asname) + Gen._store(enter_result, NewVar) + Gen.variables[asname] = NewVar + else: + Gen._reg_values[asname] = enter_result + Gen.variables[asname] = None + self.Trans.VarScopes.append({}) + if asname: + self.Trans.VarScopes[-1][asname] = True + self.HandleBodyLlvm(Node.body) + if self.Trans.VarScopes: + self.Trans.VarScopes.pop() + if ClassName: + ExitFuncName = f'{ClassName}.__exit__' + if ExitFuncName in Gen.functions: + ctx_loaded = Gen._load(ctx_alloca, name="__with_ctx") + Gen.builder.call(Gen.functions[ExitFuncName], [ctx_loaded], name="call_exit") + Gen._unregister_local_heap_ptr(original_ctx_val) + if ctx_val is not original_ctx_val: + Gen._unregister_local_heap_ptr(ctx_val) + if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val: + Gen._unregister_local_heap_ptr(original_asname_heap_ptr) + if '__with_ctx' in Gen._var_to_heap_ptr: + del Gen._var_to_heap_ptr['__with_ctx'] + if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): + ctx_int = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int") + enter_int = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int") + same_ptr = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check") + with_free_bb = Gen.func.append_basic_block("with_free_ctx") + with_skip_bb = Gen.func.append_basic_block("with_skip_free") + Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb) + Gen.builder.position_at_start(with_free_bb) + raw = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") + free_func = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) + Gen.builder.call(free_func, [raw]) + Gen.builder.branch(with_skip_bb) + Gen.builder.position_at_start(with_skip_bb) + Gen._unregister_local_heap_ptr(enter_result) + Gen._unregister_local_heap_ptr(original_ctx_val) + elif isinstance(ctx_val.type, ir.PointerType): + raw = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") + free_func = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) + Gen.builder.call(free_func, [raw]) + Gen._unregister_local_heap_ptr(original_ctx_val) \ No newline at end of file diff --git a/lib/core/Handles/__init__.py b/lib/core/Handles/__init__.py new file mode 100644 index 0000000..ba56367 --- /dev/null +++ b/lib/core/Handles/__init__.py @@ -0,0 +1,32 @@ +""" +Handles 包 - 使用 Mixin 模式组织 Handle 函数 +""" + +from .HandlesIf import IfHandle +from .HandlesFor import ForHandle +from .HandlesWhile import WhileHandle +from .HandlesAnnAssign import AnnAssignHandle +from .HandlesTypeMerge import HandlesTypeMerge +from .HandlesExpr import ExprHandle +from .HandlesExprUtils import ExprUtils +from .HandlesExprOps import ExprOpsHandle +from .HandlesExprAttr import ExprAttrHandle +from .HandlesExprBuiltin import ExprBuiltinHandle +from .HandlesExprAsm import ExprAsmHandle +from .HandlesExprFormat import ExprFormatHandle +from .HandlesExprLambda import ExprLambdaHandle +from .HandlesExprCall import ExprCallHandle +from .HandlesSpecialCall import CSpecialCallHandle, TSpecialCallHandle +from .HandlesBody import BodyHandle +from .HandlesReturn import ReturnHandle +from .HandlesAssign import AssignHandle +from .HandlesAugAssign import AugAssignHandle +from .HandlesDelete import DeleteHandle +from .HandlesWith import WithHandle +from .HandlesTry import TryHandle +from .HandlesAssert import AssertHandle +from .HandlesRaise import RaiseHandle +from .HandlesMatch import MatchHandle +from .HandlesClassDef import ClassHandle +from .HandlesFunctions import FunctionHandle +from .HandlesImports import ImportHandle diff --git a/lib/core/LlvmCodeGenerator.py b/lib/core/LlvmCodeGenerator.py new file mode 100644 index 0000000..2f3c786 --- /dev/null +++ b/lib/core/LlvmCodeGenerator.py @@ -0,0 +1,2556 @@ +import re +import ast +import os +import hashlib +import llvmlite.ir as ir +from llvmlite.ir.values import _Undefined +from lib.core.AsmIntelToAtt import convert as _intel_to_att + +TYPEDEF_NAMES = {'UINT', 'INT', 'BYTE', 'BYTEPTR', 'WORD', 'DWORD', 'QWORD', + 'INT8', 'INT16', 'INT32', 'INT64', 'UINT8', 'UINT16', 'UINT32', 'UINT64', + 'INTPTR', 'UINTPTR', 'SIZE_T', 'SSIZE_T', 'PTRDIFF_T', + 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', + 'atomic_int', 'atomic_uint', 'atomic_long', 'atomic_ulong', + 'atomic_int8', 'atomic_uint8', 'atomic_int16', 'atomic_uint16', + 'atomic_int32', 'atomic_uint32', 'atomic_int64', 'atomic_uint64', + 'atomic_ptr', 'atomic_flag', 'typedef', + 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', + 'BOOL', 'type'} + + +class VaArgInstruction(ir.Instruction): + def descr(self, buf): + ptr = self.operands[0] + buf.append("va_arg {0} {1}, {2}\n".format( + ptr.type, ptr.get_reference(), self.type)) + + +class LlvmCodeGenerator: + + @staticmethod + def _parse_triple(triple): + """解析目标三元组,返回平台信息字典""" + info = { + 'is_windows': False, 'is_linux': False, 'is_macos': False, + 'is_x86_64': False, 'is_arm64': False, 'is_32bit': False, + 'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32, + } + if not triple: + return info + triple_lower = triple.lower() + # 检测操作系统 + if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower: + info['is_windows'] = True + # Windows LLP64: long = 32 位, wchar_t = 16 位 + info['long_size'] = 32 + info['wchar_t_size'] = 16 + elif 'linux' in triple_lower: + info['is_linux'] = True + elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower: + info['is_macos'] = True + # 检测架构 + if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower: + info['is_x86_64'] = True + elif 'aarch64' in triple_lower or 'arm64' in triple_lower: + info['is_arm64'] = True + elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower: + info['is_32bit'] = True + info['ptr_size'] = 4 + info['long_size'] = 32 + if info['is_windows']: + info['wchar_t_size'] = 16 + else: + info['wchar_t_size'] = 32 + return info + + def __init__(self, triple=None, datalayout=None): + self.module = ir.Module(name="transpyc_module") + if triple: + self.module.triple = triple + else: + self.module.triple = "x86_64-none-elf" + if datalayout: + self.module.data_layout = datalayout + else: + self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + + # 解析目标平台信息 + self._platform_info = self._parse_triple(self.module.triple) + self.ptr_size = self._platform_info['ptr_size'] + # 根据目标平台配置 t 模块中的平台相关类型大小 + import t as _t + _t.configure_platform(self.module.triple) + self.builder = None + self.func = None + self.functions = {} + self.variables = {} + self._direct_values = {} + self._reg_values = {} + self.var_signedness = {} + self._unsigned_results = {} + self.string_const_counter = 0 + self.Vtables = {} + self.class_methods = {} + self.class_members = {} + self.class_member_defaults = {} + self.class_member_signeds = {} + self.class_member_bitfields = {} + self.class_member_byteorders = {} + self.class_member_element_class = {} + self.class_member_bitoffsets = {} + self.structs = {} + self._cross_module_vtable_classes = set() + self.class_vtable = set() + self.class_parent = {} + # Store member annotations for deferred type resolution (cross-module class references) + self.class_member_annotations = {} + self.loop_break_targets = [] + self.loop_continue_targets = [] + self.eh_jmp_buf_stack = [] + self.eh_except_block_stack = [] + self.eh_finally_stack = [] + self.global_vars = set() + self.nonlocal_params = {} + self._variable_scope_stack = [] # Stack of outer scope variables for nested function nonlocal lookup + self.var_struct_class = {} + self.global_struct_class = {} + self.var_type_info = {} + self.var_const_flags = {} + self._current_source_file = None + self._current_source_lines = [] + self._ns_cache = {} + self._type_cache = {} + self._typedef_cache = {} + self._func_sig_cache = {} + self.var_type_assignments = {} + self._temp_struct_ptrs = [] + self._stop_iter_flag_param = None + self._local_heap_ptrs = [] + self._var_to_heap_ptr = {} + self.known_return_types = {} + self._current_lineno = 0 + self._current_node_info = "" + self.module_sha1 = None + self.module_sha1_map = {} + self._temp_dir = None + self._export_funcs = set() + self._export_extern_funcs = set() + self._current_module_func_names = set() + self.class_packed = set() + self._define_constants = {} + pi = self._platform_info + # 根据目标平台设置宏(声明式,从三元组推导) + if pi['is_windows']: + self._define_constants['_WIN32'] = 1 + if not pi['is_32bit']: + self._define_constants['_WIN64'] = 1 + self._define_constants['WIN64'] = 1 + self._define_constants['WIN32'] = 1 + if pi['is_linux']: + self._define_constants['__linux__'] = 1 + if pi['is_macos']: + self._define_constants['__APPLE__'] = 1 + self._define_constants['__MACH__'] = 1 + if pi['is_x86_64']: + self._define_constants['__x86_64__'] = 1 + self._define_constants['__x86_64'] = 1 + self._define_constants['_M_X64'] = 1 + elif pi['is_arm64']: + self._define_constants['__aarch64__'] = 1 + self._define_constants['_M_ARM64'] = 1 + if not pi['is_32bit'] and pi['is_linux']: + self._define_constants['__LP64__'] = 1 + elif pi['is_32bit']: + self._define_constants['_ILP32'] = 1 + self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size'] + self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size'] + + def find_struct_by_pointee(self, pointee): + """根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None""" + for class_name, struct_type in self.structs.items(): + if pointee == struct_type: + return (class_name, struct_type) + return None + + def _get_or_create_struct(self, name, source_sha1=None, packed=False): + clean_name = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_') + if clean_name in self.structs: + existing = self.structs[clean_name] + if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed: + existing.packed = True + return existing + if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}: + return ir.IntType(8) + if hasattr(self, 'SymbolTable') and self.SymbolTable and clean_name in self.SymbolTable: + Entry = self.SymbolTable[clean_name] + if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: + resolved_str = self._resolve_typedef(clean_name) + if resolved_str != clean_name: + return self._type_str_to_llvm(resolved_str) + if hasattr(Entry, 'BaseType') and Entry.BaseType: + from lib.includes import t as _t + if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0: + resolved = self._resolve_ctype_to_str(Entry) + if resolved: + return self._type_str_to_llvm(resolved) + if hasattr(Entry, 'IsRenum') and Entry.IsRenum: + if clean_name in self.structs: + return self.structs[clean_name] + if hasattr(Entry, 'IsEnum') and Entry.IsEnum: + return ir.IntType(32) + if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + return ir.IntType(32) + if hasattr(Entry, 'BaseType'): + from lib.includes import t as _t + if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum): + return ir.IntType(32) + if Entry.BaseType is _t.CEnum: + return ir.IntType(32) + if source_sha1: + ns_name = f"{source_sha1}.{clean_name}" + elif hasattr(self, '_struct_sha1_map') and clean_name in self._struct_sha1_map: + ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}" + else: + ns_name = self._mangle_name(clean_name) + st = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) + self.structs[clean_name] = st + return st + + def _set_node_info(self, node, extra_info=""): + if hasattr(node, 'lineno'): + self._current_lineno = node.lineno + else: + self._current_lineno = 0 + if hasattr(node, 'col_offset'): + self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}" + else: + self._current_node_info = f"line {self._current_lineno}" + if extra_info: + self._current_node_info += f" ({extra_info})" + + def _set_source_info(self, filepath): + self._current_source_file = filepath + try: + with open(filepath, 'r', encoding='utf-8') as f: + self._current_source_lines = f.readlines() + except Exception: # 文件读取失败时回退为空行列表 + self._current_source_lines = [] + + def _ns_hash(self): + if 'workspace' in self._ns_cache: + return self._ns_cache['workspace'] + cwd = os.getcwd().replace('\\', '/').lower() + digest = hashlib.sha1(cwd.encode('utf-8')).hexdigest()[:12] + self._ns_cache['workspace'] = digest + return digest + + def _skip_mangle(self, name): + skip_prefixes = ('llvm.', 'str_const_', 'printf', 'memset_pattern') + if any(name.startswith(p) for p in skip_prefixes): + return True + if '.' in name: + parts = name.split('.', 1) + if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]): + return True + return False + + def _mangle_name(self, name): + if self._skip_mangle(name): + return name + if name in self._export_funcs: + return name + if self.module_sha1: + return f"{self.module_sha1}.{name}" + return name + + def _find_function(self, name): + if name in self.functions: + return self.functions[name] + g = self.module.globals.get(name) + if g and isinstance(g, ir.Function): + self.functions[name] = g + return g + mangled = self._mangle_func_name(name) + if mangled != name: + if mangled in self.functions: + self.functions[name] = self.functions[mangled] + return self.functions[mangled] + g = self.module.globals.get(mangled) + if g and isinstance(g, ir.Function): + self.functions[mangled] = g + self.functions[name] = g + return g + for sha1 in self.module_sha1_map.values(): + prefixed = f"{sha1}.{name}" + if prefixed in self.functions: + self.functions[name] = self.functions[prefixed] + return self.functions[prefixed] + g = self.module.globals.get(prefixed) + if g and isinstance(g, ir.Function): + self.functions[prefixed] = g + self.functions[name] = g + return g + return None + + def _has_function(self, name): + return self._find_function(name) is not None + + def _get_or_declare_function(self, mangled_name, func_type): + for g in self.module.globals: + if isinstance(g, ir.Function) and g.name == mangled_name: + return g + return ir.Function(self.module, func_type, name=mangled_name) + + def _get_function(self, name): + func = self._find_function(name) + return func + + def _mangle_func_name(self, name, module_name=None): + if name in self._export_funcs: + return name + if name in self._export_extern_funcs and name not in self._current_module_func_names: + return name + # main 函数作为程序入口点,永远不混淆 + if name == 'main': + return name + # Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5') + class_sha1_map = getattr(self, 'class_sha1_map', {}) + if class_sha1_map: + if '.' in name: + base_class = name.split('.')[0] + if base_class in class_sha1_map: + sha1 = class_sha1_map[base_class] + return f"{sha1}.{name}" + elif name in class_sha1_map: + sha1 = class_sha1_map[name] + return f"{sha1}.{name}" + # If module_name is already a SHA1 hash (16 hex chars), use it directly + if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name): + return f"{module_name}.{name}" + if module_name and module_name in self.module_sha1_map: + sha1 = self.module_sha1_map[module_name] + return f"{sha1}.{name}" + # Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__') + if module_name: + init_name = f"{module_name}.__init__" + if init_name in self.module_sha1_map: + sha1 = self.module_sha1_map[init_name] + return f"{sha1}.{name}" + if self._skip_mangle(name): + return name + if self.module_sha1: + return f"{self.module_sha1}.{name}" + return name + + def _get_source_line(self, lineno): + if 0 < lineno <= len(self._current_source_lines): + return self._current_source_lines[lineno - 1].rstrip('\r\n') + return None + + def _get_node_info(self): + info = "" + if self._current_node_info: + info = f" [{self._current_node_info}]" + if self._current_source_file: + info += f" in {self._current_source_file}" + lineno = self._current_lineno + if lineno > 0: + info += f", line {lineno}:" + source_line = self._get_source_line(lineno) + if source_line: + info += f"\n → {source_line}" + return info + + def _register_local_heap_ptr(self, val, ClassName=None, VarName=None): + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + self._local_heap_ptrs.append((val, 'struct', ClassName)) + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + self._local_heap_ptrs.append((val, 'i8', ClassName)) + if VarName: + self._var_to_heap_ptr[VarName] = val + + def _unregister_local_heap_ptr(self, val): + self._local_heap_ptrs = [(v, t, cn) for v, t, cn in self._local_heap_ptrs if v is not val] + + def _emit_local_heap_frees(self): + if not self._local_heap_ptrs or not self.builder: + return + # 创建一个集合来跟踪已经删除的对象 + deleted_objects = set() + for ptr, ptr_type, ClassName in self._local_heap_ptrs: + # 先检查指针是否为 null + if ptr_type == 'i8': + # 对于 i8* 类型的指针,加载其值并检查是否为 null + loaded_ptr = self.builder.load(ptr, name="load_ptr") + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + is_null = self.builder.icmp_unsigned('==', loaded_ptr, null_ptr, name="is_null") + # 创建一个基本块来处理非 null 的情况 + not_null_block = self.builder.append_basic_block(name="not_null") + # 创建一个基本块来处理下一个对象 + next_block = self.builder.append_basic_block(name="next") + # 如果指针为 null,跳转到下一个对象 + self.builder.cbranch(is_null, next_block, not_null_block) + # 切换到非 null 的基本块 + self.builder.position_at_end(not_null_block) + # 然后调用 __del__ 方法 + if ClassName and self._has_function(f'{ClassName}.__del__'): + if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: + cast_ptr = self.builder.bitcast(ptr, ir.PointerType(self.structs[ClassName]), name=f"cast_{ClassName}") + else: + cast_ptr = ptr + if cast_ptr not in deleted_objects: + self.builder.call(self._get_function(f'{ClassName}.__del__'), [cast_ptr], name=f"call_{ClassName}.__del__") + deleted_objects.add(cast_ptr) + # 最后释放内存 + if ptr_type == 'struct': + raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="local_free_cast") + elif ptr_type == 'i8': + raw = ptr + else: + continue + free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) + free_func = self._get_or_declare_func('free', free_type) + self.builder.call(free_func, [raw]) + # 如果是 i8* 类型的指针,跳转到下一个对象 + if ptr_type == 'i8': + self.builder.branch(next_block) + # 切换到下一个对象的基本块 + self.builder.position_at_end(next_block) + self._local_heap_ptrs = [] + + def _register_temp_ptr(self, val): + if isinstance(val.type, ir.PointerType): + pointee = val.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + for CN, ST in self.structs.items(): + if pointee == ST: + self._temp_struct_ptrs.append(val) + return + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + self._temp_struct_ptrs.append(val) + + def _unregister_temp_ptr(self, val): + self._temp_struct_ptrs = [t for t in self._temp_struct_ptrs if t is not val] + + def _emit_temp_frees(self): + if not self._temp_struct_ptrs or not self.builder: + return + for ptr in self._temp_struct_ptrs: + if isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + raw = self.builder.bitcast(ptr, ir.PointerType(ir.IntType(8)), name="free_cast") + elif isinstance(ptr.type, ir.PointerType) and isinstance(ptr.type.pointee, ir.IntType) and ptr.type.pointee.width == 8: + raw = ptr + else: + continue + free_type = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))]) + free_func = self._get_or_declare_func('free', free_type) + self.builder.call(free_func, [raw]) + self._temp_struct_ptrs = [] + + def setup_from_symbol_table(self, SymbolTable): + self.SymbolTable = SymbolTable + for name, info in SymbolTable.items(): + if not isinstance(info, dict): + if hasattr(info, 'get'): + info = dict(info) if hasattr(info, '__iter__') else {} + else: + continue + TypeKind = info.get('type', '') + if TypeKind == 'struct': + ClassName = name + self.class_methods[ClassName] = [] + self.class_members[ClassName] = [] + members = info.get('members', {}) + if members: + for MemberName, MemberInfo in members.items(): + if isinstance(MemberInfo, dict): + MemberType = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False)) + self.class_members[ClassName].append((MemberName, MemberType)) + elif isinstance(MemberInfo, _CTypeInfo): + MemberType = self._ctype_to_llvm(MemberInfo) + if MemberType is None: + MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr) + self.class_members[ClassName].append((MemberName, MemberType)) + self._generate_structs() + self._create_Vtable_globals() + + def register_method(self, ClassName, MethodName): + if ClassName not in self.class_methods: + self.class_methods[ClassName] = [] + if ClassName not in self.class_members: + self.class_members[ClassName] = [] + self._generate_structs() + self._create_Vtable_globals() + if MethodName not in self.class_methods[ClassName]: + self.class_methods[ClassName].append(MethodName) + + def _ctype_to_llvm(self, type_info): + from lib.includes import t as _t + from lib.includes.t import CTypeRegistry + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + + if type_info is None: + return ir.IntType(32) + + if isinstance(type_info, str): + return self._type_str_to_llvm(type_info) + + if not isinstance(type_info, _CTypeInfo): + return ir.IntType(32) + + if type_info.IsFuncPtr: + return ir.IntType(8).as_pointer() + + if type_info.IsState and type_info.PtrCount == 0 and not type_info.IsTypedef: + if type_info.BaseType is None or (isinstance(type_info.BaseType, type) and issubclass(type_info.BaseType, _t.CVoid)) or isinstance(type_info.BaseType, _t.CVoid): + return ir.VoidType() + + if type_info.IsTypedef and type_info.Name: + resolved = self._resolve_typedef_ctype(type_info) + if resolved is not None: + return resolved + + base_type = self._base_ctype_to_llvm(type_info.BaseType, type_info) + + result = base_type + for _ in range(type_info.PtrCount): + if isinstance(result, ir.VoidType): + result = ir.IntType(8).as_pointer() + else: + result = ir.PointerType(result) + + for dim in reversed(type_info.ArrayDims): + try: + dim_val = int(dim) + if dim_val > 0: + result = ir.ArrayType(result, dim_val) + except (ValueError, TypeError): + pass + + return result + + def _resolve_typedef_ctype(self, type_info): + from lib.includes import t as _t + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + + name = type_info.Name + if not name or not hasattr(self, 'SymbolTable') or not self.SymbolTable: + return None + + entry = self.SymbolTable.get(name) + if not entry or not isinstance(entry, _CTypeInfo): + return None + + if entry.BaseType and (not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0): + resolved = entry.Copy() + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + + if entry.OriginalType: + if isinstance(entry.OriginalType, _CTypeInfo): + resolved = entry.OriginalType.Copy() + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + elif isinstance(entry.OriginalType, str): + resolved = _CTypeInfo.FromTypeName(entry.OriginalType) + if resolved and resolved.BaseType: + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + + return None + + def _base_ctype_to_llvm(self, base_type, type_info=None): + from lib.includes import t as _t + from lib.includes.t import CTypeRegistry + + if base_type is None: + return ir.VoidType() + + if isinstance(base_type, (tuple, list)): + elem_types = [self._base_ctype_to_llvm(bt, type_info) for bt in base_type] + return ir.LiteralStructType(elem_types) if elem_types else ir.IntType(32) + + if isinstance(base_type, type) and issubclass(base_type, _t.CType): + base_type = base_type() + + if isinstance(base_type, _t.CVoid): + return ir.VoidType() + + if isinstance(base_type, _t.CStruct): + struct_name = getattr(base_type, 'name', '') or (type_info.Name if type_info else '') + if struct_name and struct_name in self.structs: + return self.structs[struct_name] + if struct_name: + return self._get_or_create_struct(struct_name) + return ir.LiteralStructType([]) + + if isinstance(base_type, (_t.CEnum, _t.REnum)): + enum_name = type_info.Name if type_info else '' + if enum_name and enum_name in self.structs: + return self.structs[enum_name] + return ir.IntType(32) + + if isinstance(base_type, _t.CUnion): + union_name = type_info.Name if type_info else '' + if union_name and union_name in self.structs: + return self.structs[union_name] + if union_name: + return self._get_or_create_struct(union_name) + return ir.IntType(32) + + if isinstance(base_type, _t._CTypedef): + typedef_name = getattr(base_type, 'value', '') or (type_info.Name if type_info else '') + if typedef_name and hasattr(self, 'SymbolTable') and self.SymbolTable: + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + entry = self.SymbolTable.get(typedef_name) + if entry and isinstance(entry, _CTypeInfo) and entry.BaseType: + if not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0: + return self._base_ctype_to_llvm(entry.BaseType, entry) + return ir.IntType(32) + + if isinstance(base_type, _t.CDefine): + # Use 64-bit type if the define value exceeds 32-bit range + if type_info and hasattr(type_info, 'DefineValue') and isinstance(type_info.DefineValue, int): + if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF: + return ir.IntType(64) + return ir.IntType(32) + + if isinstance(base_type, _t.CPass): + return ir.VoidType() + + llvm_str = CTypeRegistry.CTypeToLLVM(type(base_type)) + return self._llvm_str_to_ir(llvm_str) + + def _llvm_str_to_ir(self, llvm_str): + _map = { + 'void': ir.VoidType, 'i1': lambda: ir.IntType(1), + 'i8': lambda: ir.IntType(8), 'i16': lambda: ir.IntType(16), + 'i32': lambda: ir.IntType(32), 'i64': lambda: ir.IntType(64), + 'i128': lambda: ir.IntType(128), 'half': lambda: ir.IntType(16), + 'float': ir.FloatType, 'double': ir.DoubleType, + 'fp128': lambda: ir.IntType(128), 'i8*': lambda: ir.IntType(8).as_pointer(), + 'f8': lambda: ir.IntType(8), 'f16': lambda: ir.IntType(16), + 'f32': ir.FloatType, 'f64': ir.DoubleType, 'f128': lambda: ir.IntType(128), + } + factory = _map.get(llvm_str) + if factory: + return factory() if callable(factory) else factory + return ir.IntType(32) + + def _resolve_typedef(self, type_name: str) -> str: + if type_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + return type_name + if type_name == 'Callable': + return 'Callable' + visited = set() + current = type_name + while current not in visited: + visited.add(current) + if hasattr(self, 'SymbolTable') and self.SymbolTable and current in self.SymbolTable: + Entry = self.SymbolTable[current] + if isinstance(Entry, dict) and Entry.get('type') == 'typedef': + OriginalType = Entry.get('OriginalType', '') + if OriginalType: + current = OriginalType + continue + elif hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: + if hasattr(Entry, 'OriginalType') and Entry.OriginalType: + if isinstance(Entry.OriginalType, _CTypeInfo): + if Entry.OriginalType.IsFuncPtr: + return 'Callable' + return Entry.OriginalType.ToString() if Entry.OriginalType.BaseType else current + elif isinstance(Entry.OriginalType, str): + current = Entry.OriginalType + continue + if hasattr(Entry, 'BaseType') and Entry.BaseType: + from lib.includes import t as _t + if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0: + resolved = self._resolve_ctype_to_str(Entry) + if resolved and resolved != current: + current = resolved + continue + from lib.core.Handles.HandlesBase import BuiltinTypeMap + bm = BuiltinTypeMap.Get(current) + if bm: + base_cls = bm[0] + try: + instance = base_cls() + cname = getattr(instance, 'CName', '') + if cname: + current = cname + ' *' * bm[1] + continue + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + pass + from lib.core.Handles.HandlesBase import BuiltinTypeMap + bm = BuiltinTypeMap.Get(current) + if bm and bm[1] > 0: + base_cls = bm[0] + try: + instance = base_cls() + cname = getattr(instance, 'CName', '') + if cname: + current = cname + ' *' * bm[1] + continue + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + pass + break + return current + + def _resolve_ctype_to_str(self, type_info) -> str: + from lib.includes import t as _t + parts = [] + base = type_info.BaseType + if base is None or base is _t.CVoid or isinstance(base, _t.CVoid): + parts.append('void') + elif isinstance(base, _t._CTypedef) or base is _t._CTypedef: + return '' + elif isinstance(base, _t.CStruct) or base is _t.CStruct: + parts.append(f'struct {getattr(base, "name", "")}') + elif isinstance(base, _t.CEnum) or base is _t.CEnum: + parts.append(f'enum {getattr(base, "name", "")}') + else: + cname = getattr(base, 'CName', '') + if not cname and isinstance(base, type) and issubclass(base, _t.CType): + try: + inst = base() + cname = getattr(inst, 'CName', '') + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + pass + if cname: + parts.append(cname) + else: + return '' + if type_info.PtrCount > 0: + parts.append('*' * type_info.PtrCount) + return ' '.join(parts) + + def _type_str_to_llvm(self, type_str, IsPtr=False): + type_str = type_str.strip() + cache_key = (type_str, IsPtr) + cached = self._type_cache.get(cache_key) + if cached is not None: + return cached + result = self._type_str_to_llvm_impl(type_str, IsPtr) + if result is not None: + if isinstance(result, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): + self._type_cache[cache_key] = result + elif isinstance(result, ir.PointerType) and isinstance(result.pointee, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): + self._type_cache[cache_key] = result + elif isinstance(result, ir.ArrayType) and not isinstance(result.element, (ir.IdentifiedStructType, ir.LiteralStructType)): + self._type_cache[cache_key] = result + return result + + _CType2LLVM = _type_str_to_llvm + + def _type_str_to_llvm_impl(self, type_str, IsPtr=False): + array_dims = [] + dim_match = __import__('re').findall(r'\[(\d+)\]', type_str) + if dim_match: + array_dims = [int(d) for d in dim_match] + type_str = __import__('re').sub(r'\s*\[\d+\]', '', type_str).strip() + result = self._type_str_to_llvm_base(type_str, IsPtr) + for dim in reversed(array_dims): + result = ir.ArrayType(result, dim) + return result + + def _type_str_to_llvm_base(self, type_str, IsPtr=False): + ptr_depth = 0 + while type_str.endswith('*'): + ptr_depth += 1 + type_str = type_str[:-1].strip() + if ptr_depth > 0: + IsPtr = True + if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + if IsPtr: + result = ir.IntType(8).as_pointer() + for _ in range(ptr_depth - 1): + result = ir.PointerType(result) + return result + return ir.IntType(32) + if type_str in {'const', 'volatile'}: + return ir.IntType(8) + if type_str == 'Callable': + return ir.IntType(8).as_pointer() + if type_str.startswith('const '): + inner_type = self._type_str_to_llvm(type_str[6:].strip(), IsPtr) + return inner_type + if type_str.startswith('volatile '): + inner_type = self._type_str_to_llvm(type_str[9:].strip(), IsPtr) + return inner_type + if type_str.startswith('const_'): + inner_type = self._type_str_to_llvm(type_str[6:], IsPtr) + return inner_type + if type_str.startswith('volatile_'): + inner_type = self._type_str_to_llvm(type_str[9:], IsPtr) + return inner_type + if type_str.startswith('static '): + return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) + if type_str.startswith('extern '): + return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) + if type_str.startswith('register '): + return self._type_str_to_llvm(type_str[9:].strip(), IsPtr) + if type_str.startswith('inline '): + return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) + if type_str.startswith('export '): + return self._type_str_to_llvm(type_str[7:].strip(), IsPtr) + resolved = self._resolve_typedef(type_str) + if resolved != type_str: + if '*' in resolved: + IsPtr = False + return self._type_str_to_llvm(resolved, IsPtr) + if type_str.endswith('*'): + base_type = type_str[:-1].strip() + base_llvm = self._basic_type_to_llvm(base_type) + if base_llvm is not None and isinstance(base_llvm, ir.VoidType): + result = ir.IntType(8).as_pointer() + for _ in range(ptr_depth): + result = ir.PointerType(result) + return result + if base_llvm is not None and not isinstance(base_llvm, ir.VoidType): + if isinstance(base_llvm, ir.PointerType): + return base_llvm + return ir.PointerType(base_llvm) + if base_type in self.structs: + return ir.PointerType(self.structs[base_type]) + if base_type.startswith('struct '): + stripped = base_type[7:].strip() + if stripped in self.structs: + return ir.PointerType(self.structs[stripped]) + if '.' in base_type: + last_part = base_type.split('.')[-1] + if last_part in self.structs: + return ir.PointerType(self.structs[last_part]) + placeholder = self._get_or_create_struct(last_part) + return ir.PointerType(placeholder) + if base_llvm is not None and isinstance(base_llvm, ir.VoidType): + return ir.PointerType(ir.IntType(8)) + if type_str.startswith('{') and type_str.endswith('}'): + inner = type_str[1:-1].strip() + elem_strs = [] + depth = 0 + current = '' + for ch in inner: + if ch == ',' and depth == 0: + elem_strs.append(current.strip()) + current = '' + else: + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + current += ch + if current.strip(): + elem_strs.append(current.strip()) + elem_types = [] + for es in elem_strs: + et = self._type_str_to_llvm(es, '*' in es) + if isinstance(et, ir.VoidType): + et = ir.IntType(8).as_pointer() + elem_types.append(et) + if elem_types: + return ir.LiteralStructType(elem_types) + return ir.IntType(32) + if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + return ir.IntType(32) + if type_str.startswith('%'): + stripped = type_str[1:] + if stripped in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + basic_stripped = self._basic_type_to_llvm(stripped) + if basic_stripped is not None: + if IsPtr and not isinstance(basic_stripped, ir.VoidType): + return ir.PointerType(basic_stripped) + return basic_stripped + if hasattr(self, 'SymbolTable') and self.SymbolTable and type_str in self.SymbolTable: + _Entry = self.SymbolTable[type_str] + if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef: + resolved_str = self._resolve_typedef(type_str) + if resolved_str != type_str: + return self._type_str_to_llvm(resolved_str, IsPtr) + if hasattr(_Entry, 'BaseType') and _Entry.BaseType: + from lib.includes import t as _t + if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0: + resolved = self._resolve_ctype_to_str(_Entry) + if resolved: + return self._type_str_to_llvm(resolved, IsPtr) + if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum: + if type_str in self.structs: + return self.structs[type_str] + if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if hasattr(_Entry, 'BaseType'): + from lib.includes import t as _t + if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + for ClassName in self.structs: + if type_str == ClassName: + if IsPtr: + return ir.PointerType(self.structs[ClassName]) + return self.structs[ClassName] + if '.' in type_str and not type_str.startswith('%'): + last_part = type_str.split('.')[-1] + basic_last = self._basic_type_to_llvm(last_part) + if basic_last is not None: + if IsPtr and not isinstance(basic_last, ir.VoidType): + return ir.PointerType(basic_last) + return basic_last + if hasattr(self, 'SymbolTable') and self.SymbolTable and last_part in self.SymbolTable: + _Entry = self.SymbolTable[last_part] + if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef: + resolved_str = self._resolve_typedef(last_part) + if resolved_str != last_part: + return self._type_str_to_llvm(resolved_str, IsPtr) + if hasattr(_Entry, 'BaseType') and _Entry.BaseType: + from lib.includes import t as _t + if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0: + resolved = self._resolve_ctype_to_str(_Entry) + if resolved: + return self._type_str_to_llvm(resolved, IsPtr) + if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum: + if last_part in self.structs: + return self.structs[last_part] + if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if hasattr(_Entry, 'BaseType'): + from lib.includes import t as _t + if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if last_part in self.structs: + if IsPtr: + return ir.PointerType(self.structs[last_part]) + return self.structs[last_part] + placeholder = self._get_or_create_struct(last_part) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('struct '): + stripped = type_str[7:].strip().replace(' *', '').replace('*', '') + if stripped in self.structs: + if IsPtr: + return ir.PointerType(self.structs[stripped]) + return self.structs[stripped] + basic_match = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + placeholder = self._get_or_create_struct(stripped) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('%struct.'): + stripped = type_str[8:].strip().replace(' *', '').replace('*', '') + if stripped in self.structs: + if IsPtr: + return ir.PointerType(self.structs[stripped]) + return self.structs[stripped] + basic_match = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + placeholder = self._get_or_create_struct(stripped) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('union '): + stripped = type_str[6:].strip() + basic_match = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + if type_str.endswith('*'): + pointee = self._type_str_to_llvm(type_str[:-1].strip()) + if isinstance(pointee, ir.VoidType): + return ir.PointerType(ir.IntType(8)) + return ir.PointerType(pointee) + result = self._basic_type_to_llvm(type_str) + if result is None: + result = ir.IntType(32) + if IsPtr: + if isinstance(result, ir.VoidType): + result = ir.PointerType(ir.IntType(8)) + elif isinstance(result, ir.PointerType): + pass + else: + result = ir.PointerType(result) + for _ in range(ptr_depth - 1): + result = ir.PointerType(result) + return result + + def _llvm_str_to_ir(self, llvm_str): + _LLVM_IR_TYPES = { + 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), + 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), + 'i128': ir.IntType(128), 'float': ir.FloatType(), 'double': ir.DoubleType(), + 'half': ir.IntType(16), 'fp128': ir.IntType(128), + } + return _LLVM_IR_TYPES.get(llvm_str) + + def _basic_type_to_llvm(self, type_str): + _LLVM_IR_TYPES = { + 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), + 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), + 'i128': ir.IntType(128), 'f32': ir.FloatType(), 'f64': ir.DoubleType(), + 'half': ir.IntType(16), 'fp128': ir.IntType(128), + } + if type_str in _LLVM_IR_TYPES: + return _LLVM_IR_TYPES[type_str] + from lib.includes.t import CTypeRegistry + resolved = CTypeRegistry.ResolveName(type_str) + if resolved is not None: + ctype_cls, ptr_level = resolved + llvm_str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str: + base = self._llvm_str_to_ir(llvm_str) + if base is not None: + for _ in range(ptr_level): + if isinstance(base, ir.VoidType): + base = ir.IntType(8).as_pointer() + else: + base = ir.PointerType(base) + return base + cnameres = CTypeRegistry.CNameToClass(type_str) + if cnameres is not None: + llvm_str = CTypeRegistry.CTypeToLLVM(cnameres) + if llvm_str: + return self._llvm_str_to_ir(llvm_str) + if type_str == '*': + return ir.IntType(8) + if type_str in ('const_', 'const'): + return ir.IntType(8) + return None + + def _is_type_unsigned(self, type_str): + s = type_str.strip() + if s.endswith('*'): + return True + if s.startswith('unsigned'): + return True + from lib.includes.t import CTypeRegistry + resolved = CTypeRegistry.ResolveName(s) + if resolved is not None: + ctype_cls, _ = resolved + try: + inst = ctype_cls() + if getattr(inst, 'IsSigned', None) is False: + return True + except Exception: + pass + cnameres = CTypeRegistry.CNameToClass(s) + if cnameres is not None: + try: + inst = cnameres() + if getattr(inst, 'IsSigned', None) is False: + return True + except Exception: + pass + return False + + def _record_var_signedness(self, name, type_str_or_bool): + if isinstance(type_str_or_bool, bool): + self.var_signedness[name] = type_str_or_bool + else: + self.var_signedness[name] = self._is_type_unsigned(type_str_or_bool) + + def _is_var_unsigned(self, name): + return self.var_signedness.get(name, False) + + def _check_node_unsigned(self, node): + if isinstance(node, ast.Name): + return self._is_var_unsigned(node.id) + if isinstance(node, ast.BinOp): + return self._check_node_unsigned(node.left) or self._check_node_unsigned(node.right) + if isinstance(node, ast.UnaryOp): + return self._check_node_unsigned(node.operand) + if isinstance(node, ast.Call): + return False + if isinstance(node, ast.Subscript): + return self._check_node_unsigned(node.value) + if isinstance(node, ast.Attribute): + return self._check_node_unsigned(node.value) + return False + + def _get_align(self, llvm_type): + if isinstance(llvm_type, ir.IntType): + return max(1, llvm_type.width // 8) + if isinstance(llvm_type, ir.FloatType): + return 4 + if isinstance(llvm_type, ir.DoubleType): + return 8 + if isinstance(llvm_type, ir.PointerType): + return self.ptr_size + if isinstance(llvm_type, ir.ArrayType): + return self._get_align(llvm_type.element) + if isinstance(llvm_type, ir.LiteralStructType): + return max((self._get_align(f) for f in llvm_type.elements), default=1) + if isinstance(llvm_type, ir.IdentifiedStructType): + if llvm_type.elements is None or len(llvm_type.elements) == 0: + return self.ptr_size # opaque struct, assume pointer alignment + return max((self._get_align(f) for f in llvm_type.elements), default=1) + if isinstance(llvm_type, ir.VoidType): + return 0 + return 4 + + def _get_struct_size(self, llvm_type): + if isinstance(llvm_type, ir.IntType): + return max(1, llvm_type.width // 8) + if isinstance(llvm_type, ir.FloatType): + return 4 + if isinstance(llvm_type, ir.DoubleType): + return 8 + if isinstance(llvm_type, ir.PointerType): + return self.ptr_size + if isinstance(llvm_type, ir.ArrayType): + return self._get_struct_size(llvm_type.element) * llvm_type.count + if isinstance(llvm_type, ir.LiteralStructType): + total = 0 + max_align = 1 + for f in llvm_type.fields: + fa = self._get_align(f) + fs = self._get_struct_size(f) + max_align = max(max_align, fa) + if fa > 1: + total = (total + fa - 1) // fa * fa + total += fs + if max_align > 1: + total = (total + max_align - 1) // max_align * max_align + return total + if isinstance(llvm_type, ir.IdentifiedStructType): + if llvm_type.elements is None or len(llvm_type.elements) == 0: + return self.ptr_size # opaque struct, assume pointer size + total = 0 + max_align = 1 + for f in llvm_type.elements: + fa = self._get_align(f) + fs = self._get_struct_size(f) + max_align = max(max_align, fa) + if fa > 1: + total = (total + fa - 1) // fa * fa + total += fs + if max_align > 1: + total = (total + max_align - 1) // max_align * max_align + return total + return 4 + + @staticmethod + def _strip_unnecessary_quotes(ir_str): + def _unquote(m): + prefix = m.group(1) + name = m.group(2) + if '.' in name: + return m.group(0) + if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name): + return prefix + name + return m.group(0) + return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str) + + def finalize(self): + self._set_Vtable_initializers() + self._fix_global_var_init() + try: + ir_text = str(self.module) + except TypeError as e: + for func in self.module.functions: + for block in func.blocks: + for instr in block.instructions: + try: + str(instr) + except TypeError as te: + pass + raise + ir_text = self._strip_unnecessary_quotes(ir_text) + struct_defs = [] + struct_names = set() + typedef_names = TYPEDEF_NAMES + for ClassName, struct_type in self.structs.items(): + if isinstance(struct_type, ir.IdentifiedStructType): + sname = struct_type.name + if sname[0].isdigit() or '.' in sname or not sname.replace('_', '').replace('.', '').isalnum(): + sname_ir = f'%"{sname}"' + else: + sname_ir = f'%{sname}' + if struct_type.elements is None or len(struct_type.elements) == 0: + if ClassName not in typedef_names: + struct_names.add(sname) + struct_defs.append(f'{sname_ir} = type opaque') + continue + elems = ', '.join(str(e) for e in struct_type.elements) + if struct_type.packed: + struct_defs.append(f'{sname_ir} = type <{{ {elems} }}>') + else: + struct_defs.append(f'{sname_ir} = type {{ {elems} }}') + struct_names.add(sname) + if struct_defs: + lines = ir_text.split('\n') + filtered = [] + for line in lines: + stripped = line.strip() + skip = False + for name in struct_names: + if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum(): + patterns = [f'%"{name}" = type', f'%"{name}"=type', f'%{name} = type', f'%{name}=type'] + else: + patterns = [f'%{name} = type', f'%{name}= type', f'%{name}=type'] + for p in patterns: + if stripped.startswith(p): + skip = True + break + if skip: + break + if not skip: + filtered.append(line) + ir_text = '\n'.join(filtered) + header_end = ir_text.find('\ndefine') + if header_end == -1: + header_end = ir_text.find('\ndeclare') + if header_end == -1: + header_end = ir_text.find('\n@') + if header_end == -1: + header_end = len(ir_text) + insert_pos = ir_text.rfind('\n', 0, header_end) + if insert_pos == -1: + insert_pos = header_end + struct_block = '\n'.join(struct_defs) + '\n' + ir_text = ir_text[:insert_pos + 1] + struct_block + ir_text[insert_pos + 1:] + for name in struct_names: + if name[0].isdigit() or '.' in name: + ir_text = re.sub( + r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)', + r'%"' + name + r'"', + ir_text + ) + + return ir_text + + def _collect_classes_and_methods(self, ast_nodes, parent=None): + current_class = None + for node in ast_nodes: + if isinstance(node, str): + continue + node.parent = parent + node_type = type(node).__name__ + if node_type == 'Struct': + if hasattr(node, 'name'): + current_class = node.name + self.class_methods[current_class] = [] + self.class_members[current_class] = [] + if hasattr(node, 'decls') and node.decls: + for decl in node.decls: + if type(decl).__name__ == 'Decl' and hasattr(decl, 'name'): + member_type = self._get_type(decl.type) if hasattr(decl, 'type') else ir.IntType(32) + self.class_members[current_class].append((decl.name, member_type)) + elif node_type == 'FuncDef': + if current_class and current_class in self.class_methods: + MethodName = node.decl.name if hasattr(node.decl, 'name') else 'unknown_method' + if not MethodName.startswith(f"{current_class}."): + MethodName = f"{current_class}.{MethodName}" + self.class_methods[current_class].append(MethodName) + if hasattr(node, 'body') and isinstance(node.body, list): + self._collect_classes_and_methods(node.body, parent=node) + elif hasattr(node, 'BlockItems') and node.BlockItems: + self._collect_classes_and_methods(node.BlockItems, parent=node) + + def _generate_structs(self): + all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) + + preserved_structs = {} + for name, st in self.structs.items(): + if name not in all_classes: + preserved_structs[name] = st + elif isinstance(st, ir.IdentifiedStructType): + preserved_structs[name] = st + + self.structs.clear() + + for name, st in preserved_structs.items(): + self.structs[name] = st + + # Step 1: 先为所有类创建空的 struct,确保后面可以正确引用 + all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) + for ClassName in all_classes: + is_packed = ClassName in self.class_packed + if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable: + Entry = self.SymbolTable[ClassName] + if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + continue + if hasattr(Entry, 'IsEnum') and Entry.IsEnum: + if not getattr(Entry, 'IsRenum', False): + continue + if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef: + if hasattr(Entry, 'BaseType') and Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)): + import lib.includes.t as _t + if not isinstance(Entry.BaseType, (_t._CTypedef,)): + continue + if ClassName in self.structs: + if is_packed: + self.structs[ClassName].packed = True + continue + mangled_name = self._mangle_name(ClassName) + struct_type = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed) + self.structs[ClassName] = struct_type + + # Step 2: 解析跨模块的成员类型 + for ClassName, annotations in self.class_member_annotations.items(): + if ClassName not in self.class_members: + continue + for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): + if member_name in annotations: + annotation = annotations[member_name] + ResolvedType = None + + if isinstance(annotation, ast.Attribute): + ClassTypeName = annotation.attr + if ClassTypeName in self.structs: + ResolvedType = self.structs[ClassTypeName] + elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + left = annotation.left + if isinstance(left, ast.Attribute): + ClassTypeName = left.attr + if ClassTypeName in self.structs: + ResolvedType = self.structs[ClassTypeName] + + if ResolvedType: + self.class_members[ClassName][i] = (member_name, ResolvedType) + + struct_name_map = {} + for struct_name, struct in self.structs.items(): + try: + struct_name_map[struct.name] = struct + except AssertionError: + struct_name_map[struct_name] = struct + orig = getattr(struct, '_original_name', None) + if orig: + struct_name_map[orig] = struct + + # Step 3: 更新成员类型,确保使用正确的 mangled struct 引用 + for ClassName in all_classes: + if ClassName not in self.class_members: + continue + for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): + if isinstance(member_type, ir.PointerType): + pointee = member_type.pointee + if isinstance(pointee, ir.IdentifiedStructType): + try: + pname = pointee.name + except AssertionError: + pname = None + struct = struct_name_map.get(pname) if pname else None + if struct is None: + orig = getattr(pointee, '_original_name', None) + struct = struct_name_map.get(orig) if orig else None + if struct is not None: + self.class_members[ClassName][i] = (member_name, ir.PointerType(struct)) + else: + raw_name = pname or '' + if raw_name.startswith('struct.'): + raw_name = raw_name[7:] + new_struct = self._get_or_create_struct(raw_name) + self.class_members[ClassName][i] = (member_name, ir.PointerType(new_struct)) + elif isinstance(member_type, ir.IdentifiedStructType): + try: + mname = member_type.name + except AssertionError: + mname = None + struct = struct_name_map.get(mname) if mname else None + if struct is None: + orig = getattr(member_type, '_original_name', None) + struct = struct_name_map.get(orig) if orig else None + if struct is not None: + self.class_members[ClassName][i] = (member_name, struct) + else: + raw_name = mname or '' + if raw_name.startswith('struct.'): + raw_name = raw_name[7:] + new_struct = self._get_or_create_struct(raw_name) + self.class_members[ClassName][i] = (member_name, new_struct) + + # Step 4: 创建最终的 structs 并设置正确的成员类型 + for ClassName in all_classes: + if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable: + Entry = self.SymbolTable[ClassName] + if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass: + continue + if hasattr(Entry, 'IsEnum') and Entry.IsEnum: + if not getattr(Entry, 'IsRenum', False): + continue + existing_st = self.structs.get(ClassName) + if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0: + # 即使 struct 已有元素,也需要修正 packed 属性 + if ClassName in self.class_packed and not existing_st.packed: + existing_st.packed = True + continue + has_vtable = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes + if not has_vtable: + p = self.class_parent.get(ClassName) + while p: + if p in self.class_vtable or p in self._cross_module_vtable_classes: + has_vtable = True + self.class_vtable.add(ClassName) + break + p = self.class_parent.get(p) + has_bitfield = ClassName in self.class_member_bitfields and any( + self.class_member_bitfields[ClassName].get(name, 0) > 0 + for name, _ in self.class_members.get(ClassName, []) + ) + all_members = self.class_members.get(ClassName, []) + all_bitfield = all( + self.class_member_bitfields.get(ClassName, {}).get(name, 0) > 0 + for name, _ in all_members + ) if all_members else False + + mangled_name = self._mangle_name(ClassName) + + if has_bitfield and all_bitfield: + total_bits = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0) + for name, _ in all_members) + if total_bits <= 8: + storage_type = ir.IntType(8) + elif total_bits <= 16: + storage_type = ir.IntType(16) + elif total_bits <= 32: + storage_type = ir.IntType(32) + else: + storage_type = ir.IntType(64) + member_types = [storage_type] + bitfield_offsets = {} + current_bit_offset = 0 + for name, _ in all_members: + bit_width = self.class_member_bitfields.get(ClassName, {}).get(name, 0) + bitfield_offsets[name] = current_bit_offset + current_bit_offset += bit_width + self.class_member_bitoffsets[ClassName] = bitfield_offsets + else: + member_types = [] + if has_vtable: + member_types.append(ir.PointerType(ir.IntType(8))) + if ClassName in self.class_members: + for _, member_type in self.class_members[ClassName]: + if member_type is None: + member_type = ir.IntType(32) + member_types.append(member_type) + else: + member_types = [ir.IntType(8)] + + # 获取之前创建的 struct 并设置成员 + struct_type = self.structs[ClassName] + if ClassName in self.class_packed: + struct_type.packed = True + # 只在未设置 body 时设置,避免重复定义错误 + if struct_type.elements is None: + struct_type.set_body(*member_types) + + def _create_Vtable_globals(self): + for ClassName, methods in self.class_methods.items(): + if ClassName in self.Vtables: + continue + if not methods: + continue + if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: + continue + VtableType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + Vtable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable")) + Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) + Vtable.linkage = 'internal' + self.Vtables[ClassName] = Vtable + + def _fix_global_var_init(self): + for gv_name, gv in list(self.module.globals.items()): + if not isinstance(gv, ir.GlobalVariable): + continue + if gv.linkage in ('external', 'extern_weak'): + continue + needs_fix = False + if gv.initializer is None: + needs_fix = True + elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined): + needs_fix = True + elif isinstance(gv.initializer, ir.Constant): + if isinstance(gv.initializer.constant, list): + if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant): + needs_fix = True + if not needs_fix: + continue + gv.initializer = ir.Constant(gv.value_type, None) + if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'): + gv.linkage = 'internal' + + def _zero_value_for_type(self, var_type): + if isinstance(var_type, ir.IntType): + return ir.Constant(var_type, 0) + elif isinstance(var_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(var_type, 0.0) + elif isinstance(var_type, ir.PointerType): + return ir.Constant(var_type, None) + elif isinstance(var_type, ir.ArrayType): + elem_zv = self._zero_value_for_type(var_type.element) + if elem_zv is None: + return None + return ir.Constant(var_type, [elem_zv] * var_type.count) + elif isinstance(var_type, ir.BaseStructType): + if var_type.elements is not None and len(var_type.elements) > 0: + elem_zvs = [self._zero_value_for_type(m) for m in var_type.elements] + if any(zv is None for zv in elem_zvs): + return None + return ir.Constant(var_type, elem_zvs) + return None + return None + + def _set_Vtable_initializers(self): + for ClassName, methods in self.class_methods.items(): + if ClassName not in self.Vtables: + continue + if not methods: + continue + struct_type = self.structs.get(ClassName) + if not struct_type: + continue + Vtable = self.Vtables[ClassName] + Vtable_entries = [] + for MethodName in methods: + short_name = MethodName.split('.')[-1] if '.' in MethodName else MethodName + full_MethodName = f"{ClassName}.{short_name}" + func = None + if full_MethodName in self.functions: + func = self.functions[full_MethodName] + if func is None: + parent_cls = self.class_parent.get(ClassName) + while parent_cls: + parent_full = f"{parent_cls}.{short_name}" + if parent_full in self.functions: + func = self.functions[parent_full] + break + parent_cls = self.class_parent.get(parent_cls) + if func is None: + Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) + continue + Vtable_entries.append(func.bitcast(ir.PointerType(ir.IntType(8)))) + Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries) + + def _adjust_args(self, args, func): + adjusted = [] + for i, (arg, param) in enumerate(zip(args, func.args)): + if arg.type != param.type: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + adjusted.append(self._load(arg, name=f"load_arg_{i}")) + continue + try: + if isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): + if isinstance(param.type.pointee, ir.IntType) and param.type.pointee.width == 8 and arg.type.width == 8: + # 当参数是 i8(字符值)而函数期望 i8*(字符串指针)时 + # 为字符值分配内存,创建 null-terminated 字符串 + tmp = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}") + zero = ir.Constant(ir.IntType(32), 0) + char_ptr = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}") + self._store(arg, char_ptr) + null_ptr = self.builder.gep(tmp, [zero, ir.Constant(ir.IntType(32), 1)], name=f"char2str_null_{i}") + self._store(ir.Constant(ir.IntType(8), 0), null_ptr) + adjusted.append(char_ptr) + else: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 当参数是指针而函数期望整数时,使用 ptrtoint + adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) + else: + if arg.type.width < 32: + arg = self.builder.zext(arg, ir.IntType(32), name=f"zext_arg_{i}") + adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 当参数是指针而函数期望整数时,使用 ptrtoint + adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): + if isinstance(arg.type.pointee, ir.PointerType) and isinstance(param.type.pointee, ir.IntType): + loaded = self._load(arg, name=f"load_arg_{i}") + adjusted.append(loaded) + elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): + zero = ir.Constant(ir.IntType(32), 0) + elem_ptr = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") + if elem_ptr.type != param.type: + adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) + else: + adjusted.append(elem_ptr) + elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, ir.PointerType): + zero = ir.Constant(ir.IntType(32), 0) + elem_ptr = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") + if elem_ptr.type != param.type: + adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) + else: + adjusted.append(elem_ptr) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + else: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + adjusted.append(self._load(arg, name=f"load_arg_{i}")) + elif isinstance(arg.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + tmp = self._alloca(param.type, name=f"temp_arg_{i}") + loaded = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") + loaded_val = self._load(loaded, name=f"load_arg_{i}") + self._store(loaded_val, tmp) + adjusted.append(self._load(tmp, name=f"reload_arg_{i}")) + else: + tmp = self._alloca(param.type, name=f"temp_arg_{i}") + cast_ptr = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") + loaded_val = self._load(cast_ptr, name=f"load_arg_{i}") + self._store(loaded_val, tmp) + adjusted.append(self._load(tmp, name=f"reload_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: + adjusted.append(self._load(arg, name=f"load_arg_{i}")) + elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: + tmp = self._alloca(arg.type, name=f"temp_arg_{i}") + self._store(arg, tmp) + adjusted.append(tmp) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.IntType): + if arg.type.width < param.type.width: + # 整数扩展:使用 sext(符号扩展)以正确处理负数 + adjusted.append(self.builder.sext(arg, param.type, name=f"sext_arg_{i}")) + else: + adjusted.append(self.builder.trunc(arg, param.type, name=f"trunc_arg_{i}")) + elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): + if isinstance(arg.type, ir.DoubleType) and isinstance(param.type, ir.FloatType): + adjusted.append(self.builder.fptrunc(arg, param.type, name=f"fptrunc_arg_{i}")) + elif isinstance(arg.type, ir.FloatType) and isinstance(param.type, ir.DoubleType): + adjusted.append(self.builder.fpext(arg, param.type, name=f"fpext_arg_{i}")) + else: + adjusted.append(arg) + elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, ir.IntType): + adjusted.append(self.builder.fptosi(arg, param.type, name=f"fptosi_arg_{i}")) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): + adjusted.append(self.builder.sitofp(arg, param.type, name=f"sitofp_arg_{i}")) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): + # 整数转指针:inttoptr + if arg.type.width < 64: + i64_val = self.builder.sext(arg, ir.IntType(64), name=f"sext_arg_{i}") + adjusted.append(self.builder.inttoptr(i64_val, param.type, name=f"inttoptr_arg_{i}")) + else: + adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 指针转整数:ptrtoint + i64_val = self.builder.ptrtoint(arg, ir.IntType(64), name=f"ptrtoint_arg_{i}") + if i64_val.type.width > param.type.width: + adjusted.append(self.builder.trunc(i64_val, param.type, name=f"trunc_arg_{i}")) + elif i64_val.type.width < param.type.width: + adjusted.append(self.builder.sext(i64_val, param.type, name=f"sext_arg_{i}")) + else: + adjusted.append(i64_val) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + except Exception: # 参数类型调整失败时使用简化回退逻辑 + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + adjusted.append(self._load(arg, name=f"load_arg_{i}")) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: + adjusted.append(self._load(arg, name=f"load_arg_{i}")) + elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: + tmp = self._alloca(arg.type, name=f"temp_arg_{i}") + self._store(arg, tmp) + adjusted.append(tmp) + else: + adjusted.append(arg) + else: + adjusted.append(arg) + while len(adjusted) < len(func.args): + missing_idx = len(adjusted) + param = func.args[missing_idx] + param_type = param.type if hasattr(param, 'type') else param + if isinstance(param_type, ir.PointerType): + adjusted.append(ir.Constant(param_type, None)) + elif isinstance(param_type, ir.IntType): + adjusted.append(ir.Constant(param_type, 0)) + elif isinstance(param_type, (ir.FloatType, ir.DoubleType)): + adjusted.append(ir.Constant(param_type, 0.0)) + else: + adjusted.append(ir.Constant(ir.IntType(32), 0)) + if func.type.pointee.var_arg: + for i in range(len(func.args), len(args)): + arg = args[i] + adjusted.append(arg) + return adjusted + + def _get_member_offset(self, field_name, ClassName=None): + has_vtable = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes) + base = 1 if has_vtable else 0 + if ClassName and ClassName in self.structs: + struct_type = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: + if ClassName in self.class_members: + expected_fields = len(self.class_members[ClassName]) + actual_elements = len(struct_type.elements) + if base > 0 and actual_elements == expected_fields: + base = 0 + if ClassName and ClassName in self.class_members: + for i, (name, _) in enumerate(self.class_members[ClassName]): + if name == field_name: + return base + i + short_name = ClassName.split('.')[-1] if ClassName and '.' in ClassName else None + if short_name and short_name in self.class_members: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + if ClassName and field_name: + if ClassName not in self.class_members or field_name not in [n for n, _ in self.class_members.get(ClassName, [])]: + if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ImportHandler'): + sha1_map = getattr(self, 'module_sha1_map', {}) + for mod_name, mod_sha1 in sha1_map.items(): + stub_name = f"{mod_sha1}.stub.ll" + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, stub_name, self) + if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: + for i, (name, _) in enumerate(self.class_members[ClassName]): + if name == field_name: + return base + i + break + if short_name: + for mod_name, mod_sha1 in sha1_map.items(): + stub_name = f"{mod_sha1}.stub.ll" + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_name, stub_name, self) + if short_name in self.class_members and len(self.class_members[short_name]) > 0: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + break + if ClassName and field_name: + for cn_key in self.class_members: + if cn_key == ClassName or cn_key.endswith(f'.{ClassName}') or (short_name and (cn_key == short_name or cn_key.endswith(f'.{short_name}'))): + for i, (name, _) in enumerate(self.class_members[cn_key]): + if name == field_name: + return base + i + if ClassName and ClassName in self.structs: + struct_type = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: + for cn_key, members in self.class_members.items(): + if cn_key == short_name or (short_name and cn_key.endswith(f'.{short_name}')): + for i, (name, _) in enumerate(members): + if name == field_name and i < len(struct_type.elements): + return i + break + else: + if short_name: + for cn_key, members in self.class_members.items(): + sn = cn_key.split('.')[-1] if '.' in cn_key else cn_key + if sn == short_name: + for i, (name, _) in enumerate(members): + if name == field_name and i < len(struct_type.elements): + return i + break + if ClassName and field_name and ClassName not in self.class_members: + if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ImportHandler'): + for temp_dir_candidate in [getattr(self, '_temp_dir', None)]: + if temp_dir_candidate and os.path.isdir(temp_dir_candidate): + for pyi_file in os.listdir(temp_dir_candidate): + if pyi_file.endswith('.pyi'): + stub_name = pyi_file.replace('.pyi', '.stub.ll') + short_cn = short_name if short_name else ClassName + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self) + if short_cn in self.class_members and len(self.class_members[short_cn]) > 0: + for i, (name, _) in enumerate(self.class_members[short_cn]): + if name == field_name: + return base + i + break + if ClassName and ClassName in self.structs and (ClassName not in self.class_members or len(self.class_members.get(ClassName, [])) == 0): + struct_type = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None: + if hasattr(self, '_Trans') and self._Trans and hasattr(self._Trans, 'ClassHandler'): + class_handler = self._Trans.ClassHandler + if hasattr(self, '_current_tree') and self._current_tree: + for node in ast.iter_child_nodes(self._current_tree): + if isinstance(node, ast.ClassDef) and (node.name == ClassName or node.name == short_name): + if node.name not in self.class_members: + self.class_members[node.name] = [] + if len(self.class_members[node.name]) == 0: + class_handler._PreRegisterClassMembers(node, self) + if ClassName in self.class_members: + for i, (name, _) in enumerate(self.class_members[ClassName]): + if name == field_name: + return base + i + if short_name and short_name in self.class_members: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + break + return None + + def _resolve_class_for_var(self, var_name): + for ClassName in self.class_methods: + if var_name == ClassName or var_name.startswith(f"__with_{ClassName}_"): + return ClassName + if var_name in self.variables: + var = self.variables[var_name] + if isinstance(var.type, ir.PointerType): + for ClassName, struct_type in self.structs.items(): + if var.type.pointee == struct_type: + return ClassName + if isinstance(var.type.pointee, ir.PointerType) and var.type.pointee.pointee == struct_type: + return ClassName + return None + + def _GetOrCreateFunc(self, FuncName, ArgTypes): + mangled_name = self._mangle_func_name(FuncName) + if mangled_name in self.functions: + return self.functions[mangled_name] + FuncType = self._InferFuncTypeForCall(FuncName, ArgTypes) + try: + func = ir.Function(self.module, FuncType, name=mangled_name) + except Exception: # 函数名冲突时添加前缀重试 + func = ir.Function(self.module, FuncType, name=f"_{mangled_name}") + self.functions[mangled_name] = func + return func + + def _resolve_method_class(self, MethodName): + for ClassName, methods in self.class_methods.items(): + if MethodName in methods: + return ClassName + full_name = f"{ClassName}.{MethodName}" + if full_name in methods: + return ClassName + return None + + def _get_va_start_intrinsic(self): + if 'llvm.va_start' in self.functions: + return self.functions['llvm.va_start'] + ftype = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()]) + func = ir.Function(self.module, ftype, name='llvm.va_start') + self.functions['llvm.va_start'] = func + return func + + def _get_va_end_intrinsic(self): + if 'llvm.va_end' in self.functions: + return self.functions['llvm.va_end'] + ftype = ir.FunctionType(ir.VoidType(), [ir.IntType(8).as_pointer()]) + func = ir.Function(self.module, ftype, name='llvm.va_end') + self.functions['llvm.va_end'] = func + return func + + def emit_va_start(self, va_list_ptr): + if not self.builder: + return None + func = self._get_va_start_intrinsic() + i8ptr_type = ir.IntType(8).as_pointer() + if va_list_ptr.type == i8ptr_type: + self.builder.call(func, [va_list_ptr]) + else: + ptr = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr") + self.builder.call(func, [ptr]) + return None + + def _emit_stack_align(self, alignment=16): + if not self.builder: + return None + void = ir.VoidType() + asm_type = ir.FunctionType(void, []) + mask = -alignment + intel_asm = f"and rsp, {mask}" + asm_str = _intel_to_att(intel_asm) + asm_func = ir.InlineAsm(asm_type, asm_str, "~{dirflag},~{fpsr},~{flags},~{rsp}", side_effect=True) + self.builder.call(asm_func, [], name="align_stack") + return None + + def emit_va_end(self, va_list_ptr): + if not self.builder: + return None + func = self._get_va_end_intrinsic() + i8ptr_type = ir.IntType(8).as_pointer() + if va_list_ptr.type == i8ptr_type: + self.builder.call(func, [va_list_ptr]) + else: + ptr = self.builder.bitcast(va_list_ptr, i8ptr_type, name="va_list_i8ptr") + self.builder.call(func, [ptr]) + return None + + def emit_va_arg(self, va_list_ptr, arg_type): + if not self.builder: + return self._zero_const(arg_type) + if not hasattr(self, '_va_arg_counter'): + self._va_arg_counter = 0 + self._va_arg_counter += 1 + import sys + is_x86_64 = sys.platform in ('win32', 'win64', 'windows', 'linux', 'linux2', 'darwin') + if is_x86_64: + if isinstance(arg_type, ir.PointerType): + va_arg_type = ir.IntType(64) + elif isinstance(arg_type, (ir.FloatType, ir.DoubleType)): + va_arg_type = ir.DoubleType() + elif isinstance(arg_type, ir.IntType) and arg_type.width < 64: + va_arg_type = ir.IntType(64) + else: + va_arg_type = arg_type + instr = VaArgInstruction(self.builder.block, va_arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}') + self.builder._insert(instr) + if va_arg_type != arg_type: + if isinstance(arg_type, ir.PointerType): + result = self.builder.inttoptr(instr, arg_type, name=f'va_arg_ptr_{self._va_arg_counter}') + elif isinstance(arg_type, ir.FloatType): + result = self.builder.fptrunc(instr, arg_type, name=f'va_arg_fptrunc_{self._va_arg_counter}') + else: + result = self.builder.trunc(instr, arg_type, name=f'va_arg_trunc_{self._va_arg_counter}') + else: + result = instr + return result + else: + if isinstance(arg_type, ir.IntType) and arg_type.width < 64: + arg_type = ir.IntType(64) + instr = VaArgInstruction(self.builder.block, arg_type, 'va_arg', (va_list_ptr,), name=f'va_arg_raw_{self._va_arg_counter}') + self.builder._insert(instr) + return instr + + def _infer_return_type(self, FuncName): + if FuncName in self.functions: + return self.functions[FuncName].type.pointee.return_type + if FuncName in self.known_return_types: + return self.known_return_types[FuncName] + for ClassName, methods in self.class_methods.items(): + for method in methods: + if FuncName == method: + return ir.VoidType() + return ir.IntType(32) + + def _InferFuncTypeForCall(self, FuncName, ArgTypes): + return_type = self._infer_return_type(FuncName) + if not ArgTypes: + for ClassName, methods in self.class_methods.items(): + if FuncName in methods: + if ClassName in self.structs: + ArgTypes = [ir.PointerType(self.structs[ClassName])] + else: + ArgTypes = [ir.PointerType(ir.LiteralStructType([ir.PointerType(ir.IntType(8)), ir.IntType(32)]))] + break + else: + ArgTypes = [ir.IntType(32)] + return ir.FunctionType(return_type, ArgTypes) + + def _zero_const(self, typ): + if isinstance(typ, ir.PointerType): + return ir.Constant(typ, None) + return ir.Constant(typ, 0) + + def _alloca(self, typ, name='', align=None, size=None): + if align is None: + align = self._get_align(typ) + if size is not None: + instr = self.builder.alloca(typ, size=size, name=name) + else: + instr = self.builder.alloca(typ, name=name) + if align: + instr.align = align + return instr + + def _alloca_entry(self, typ, name='', align=None): + if align is None: + align = self._get_align(typ) + saved_block = self.builder.block + entry_block = self.func.entry_basic_block + if entry_block.instructions: + first_instr = entry_block.instructions[0] + self.builder.position_before(first_instr) + instr = self.builder.alloca(typ, name=name) + if align: + instr.align = align + self.builder.position_at_end(saved_block) + else: + self.builder.position_at_start(entry_block) + instr = self.builder.alloca(typ, name=name) + if align: + instr.align = align + self.builder.position_at_end(saved_block) + return instr + + def _load(self, ptr, name='', align=None): + if align is None: + if isinstance(ptr.type, ir.PointerType): + align = self._get_align(ptr.type.pointee) + else: + align = 0 + if isinstance(ptr.type, ir.PointerType): + pointee_type = ptr.type.pointee + typedef_names = TYPEDEF_NAMES + if isinstance(pointee_type, ir.IdentifiedStructType) and pointee_type.name in typedef_names: + actual_type = ir.IntType(32) + if pointee_type.name in {'BYTE', 'INT8', 'UINT8'}: + actual_type = ir.IntType(8) + elif pointee_type.name in {'WORD', 'INT16', 'UINT16'}: + actual_type = ir.IntType(16) + elif pointee_type.name in {'DWORD', 'INT32', 'UINT32'}: + actual_type = ir.IntType(32) + elif pointee_type.name in {'QWORD', 'INT64', 'UINT64'}: + actual_type = ir.IntType(64) + bitcast_ptr = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast_load") + return self.builder.load(bitcast_ptr, name=name, align=align) + return self.builder.load(ptr, name=name, align=align) + + def _load_var(self, name): + if name in self._direct_values: + return self._direct_values[name] + if name in self.variables and self.variables[name] is not None: + VarPtr = self.variables[name] + if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return VarPtr + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return VarPtr + return self._load(VarPtr, name=name) + if name in self.global_vars and name in self.module.globals: + GVar = self.module.globals[name] + self.variables[name] = GVar + if isinstance(GVar, ir.Function): + return GVar + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return self._load(GVar, name=name) + if name in self.module.globals: + GVar = self.module.globals[name] + self.variables[name] = GVar + if isinstance(GVar, ir.Function): + return GVar + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return GVar + return self._load(GVar, name=name) + return None + + def _store_var(self, name, value): + if name in self._direct_values: + old_val = self._direct_values.pop(name) + if name not in self.variables or self.variables[name] is None: + var = self.builder.alloca(old_val.type, name=name) + self._store(old_val, var) + self.variables[name] = var + if name in self.variables and self.variables[name] is not None: + self._store(value, self.variables[name]) + else: + var = self.builder.alloca(value.type, name=name) + self._store(value, var) + self.variables[name] = var + + def _ensure_alloca(self, name, llvm_type): + if name in self._direct_values: + val = self._direct_values.pop(name) + var = self.builder.alloca(llvm_type, name=name) + self._store(val, var) + self.variables[name] = var + return var + if name in self.variables and self.variables[name] is not None: + return self.variables[name] + var = self.builder.alloca(llvm_type, name=name) + self.variables[name] = var + return var + + def _coerce_value(self, val, target_type): + if val.type == target_type: + return val + typedef_names = TYPEDEF_NAMES + if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in typedef_names: + if isinstance(val.type, ir.IntType): + return val + if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.IntType): + if target_type.width < val.type.width: + return self.builder.trunc(val, target_type, name="trunc_store") + else: + # 使用 sext(符号扩展)以正确处理负数 + return self.builder.sext(val, target_type, name="sext_store") + if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.PointerType): + if isinstance(val, ir.Constant) and val.constant is None: + return ir.Constant(target_type, None) + return self.builder.bitcast(val, target_type, name="ptr_bitcast_store") + if isinstance(target_type, ir.PointerType) and isinstance(val.type, ir.IntType): + if val.type.width < 64: + val = self.builder.zext(val, ir.IntType(64), name="zext_ptr_store") + return self.builder.inttoptr(val, target_type, name="int_to_ptr_store") + if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.PointerType): + if isinstance(val.type.pointee, ir.IntType) and val.type.pointee.width == target_type.width: + return self.builder.load(val, name="load_ptr_as_int_store") + if target_type.width <= 8 and isinstance(val.type.pointee, ir.IntType): + loaded = self.builder.load(val, name="load_ptr_byte_store") + if loaded.type != target_type: + if isinstance(loaded.type, ir.IntType) and isinstance(target_type, ir.IntType): + if target_type.width < loaded.type.width: + return self.builder.trunc(loaded, target_type, name="trunc_ptr_byte_store") + return self.builder.zext(loaded, target_type, name="zext_ptr_byte_store") + return loaded + return self.builder.ptrtoint(val, target_type, name="ptr_to_int_store") + if isinstance(target_type, ir.FloatType) and isinstance(val.type, ir.DoubleType): + return self.builder.fptrunc(val, target_type, name="fptrunc_store") + if isinstance(target_type, ir.DoubleType) and isinstance(val.type, ir.FloatType): + return self.builder.fpext(val, target_type, name="fpext_store") + if isinstance(target_type, ir.IntType) and isinstance(val.type, (ir.FloatType, ir.DoubleType)): + return self.builder.fptosi(val, target_type, name="fptosi_store") + if isinstance(target_type, (ir.FloatType, ir.DoubleType)) and isinstance(val.type, ir.IntType): + return self.builder.sitofp(val, target_type, name="sitofp_store") + if isinstance(target_type, ir.ArrayType) and isinstance(val.type, ir.ArrayType): + if target_type.count == val.type.count and target_type.element == val.type.element: + return val + if (isinstance(target_type.element, ir.IntType) and target_type.element.width == 8 + and isinstance(val.type.element, ir.IntType) and val.type.element.width == 8): + if target_type.count > val.type.count: + padded = list(val.constant) if hasattr(val, 'constant') else [] + if padded and len(padded) == val.type.count: + padded.extend([ir.Constant(ir.IntType(8), 0)] * (target_type.count - val.type.count)) + return ir.Constant(target_type, padded) + elif target_type.count < val.type.count: + trimmed = list(val.constant) if hasattr(val, 'constant') else [] + if trimmed and len(trimmed) == val.type.count: + return ir.Constant(target_type, trimmed[:target_type.count]) + if isinstance(val.type, ir.PointerType) and not isinstance(target_type, ir.PointerType): + if val.type.pointee == target_type: + return self.builder.load(val, name="load_struct_for_store") + if isinstance(val.type.pointee, ir.IdentifiedStructType) and isinstance(target_type, ir.IdentifiedStructType): + if val.type.pointee.name == target_type.name: + loaded = self.builder.load(val, name="load_struct_for_store") + if loaded.type == target_type: + return loaded + return None + + def _store(self, val, ptr, align=None): + if align is None: + if isinstance(ptr.type, ir.PointerType): + align = self._get_align(ptr.type.pointee) + else: + align = 0 + if isinstance(ptr.type, ir.PointerType): + target_type = ptr.type.pointee + typedef_names = TYPEDEF_NAMES + if isinstance(target_type, ir.IdentifiedStructType) and target_type.name in typedef_names: + if isinstance(val.type, ir.IntType): + actual_type = ir.IntType(32) + if target_type.name in {'BYTE', 'INT8', 'UINT8'}: + actual_type = ir.IntType(8) + elif target_type.name in {'WORD', 'INT16', 'UINT16'}: + actual_type = ir.IntType(16) + elif target_type.name in {'DWORD', 'INT32', 'UINT32'}: + actual_type = ir.IntType(32) + elif target_type.name in {'QWORD', 'INT64', 'UINT64'}: + actual_type = ir.IntType(64) + bitcast_ptr = self.builder.bitcast(ptr, ir.PointerType(actual_type), name="typedef_bitcast") + if val.type.width != actual_type.width: + if val.type.width > actual_type.width: + val = self.builder.trunc(val, actual_type, name="trunc_typedef") + else: + val = self.builder.zext(val, actual_type, name="zext_typedef") + return self.builder.store(val, bitcast_ptr, align=align) + if val.type != target_type: + if isinstance(val, ir.Constant) and val.constant is None: + if isinstance(target_type, ir.PointerType): + val = ir.Constant(target_type, None) + elif isinstance(target_type, ir.IdentifiedStructType): + val = ir.Constant(ir.PointerType(target_type), None) + ptr = self.builder.bitcast(ptr, ir.PointerType(ir.PointerType(target_type)), name="null_struct_ptr_cast") + else: + coerced = self._coerce_value(val, target_type) + if coerced is not None: + val = coerced + else: + src_info = self._get_node_info() + raise TypeError(f"cannot store {val.type} to {ptr.type}: mismatching types{src_info}") + return self.builder.store(val, ptr, align=align) + + def _get_var_ptr(self, name): + if name in self._reg_values: + val = self._reg_values[name] + var = self._alloca(val.type, name=name) + self._store(val, var) + self.variables[name] = var + del self._reg_values[name] + return var + if name in self.variables and self.variables[name] is not None: + return self.variables[name] + return None + + def emit_constant(self, value, type_name='int'): + if type_name == 'int': + return ir.Constant(ir.IntType(32), int(value)) + elif type_name == 'uint64_t' or type_name == 'unsigned long long': + return ir.Constant(ir.IntType(64), int(value)) + elif type_name == 'uint32_t' or type_name == 'unsigned int': + return ir.Constant(ir.IntType(32), int(value)) + elif type_name == 'uint16_t' or type_name == 'unsigned short': + return ir.Constant(ir.IntType(16), int(value)) + elif type_name == 'uint8_t' or type_name == 'unsigned char': + return ir.Constant(ir.IntType(8), int(value)) + elif type_name == 'int64_t' or type_name == 'long long': + return ir.Constant(ir.IntType(64), int(value)) + elif type_name == 'int32_t' or type_name == 'int': + return ir.Constant(ir.IntType(32), int(value)) + elif type_name == 'int16_t' or type_name == 'short': + return ir.Constant(ir.IntType(16), int(value)) + elif type_name == 'int8_t' or type_name == 'char': + return ir.Constant(ir.IntType(8), int(value)) + elif type_name == 'float' or type_name == 'float32_t' or type_name == 'FLOAT32': + return ir.Constant(ir.FloatType(), float(value)) + elif type_name == 'double' or type_name == 'float64_t' or type_name == 'FLOAT64': + return ir.Constant(ir.DoubleType(), float(value)) + elif type_name == 'float16_t' or type_name == 'FLOAT16': + return ir.Constant(ir.IntType(16), int(value)) + elif type_name == 'float8_t' or type_name == 'FLOAT8': + return ir.Constant(ir.IntType(8), int(value)) + elif type_name == 'float128_t' or type_name == 'FLOAT128': + return ir.Constant(ir.IntType(128), int(value)) + elif type_name == 'string': + encoded = value.encode('utf-8') + b'\x00' + str_type = ir.ArrayType(ir.IntType(8), len(encoded)) + str_const = ir.Constant(str_type, bytearray(encoded)) + global_var = ir.GlobalVariable(self.module, str_type, name=f"str_const_{self.string_const_counter}") + self.string_const_counter += 1 + global_var.initializer = str_const + global_var.linkage = 'internal' + return self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8)), name="str") + return ir.Constant(ir.IntType(32), int(value)) + + def emit_binary_op(self, op, left, right, is_unsigned=False): + # 处理指针和整数之间的类型转换 + if isinstance(left.type, ir.PointerType) and isinstance(right.type, ir.IntType): + right = self.builder.zext(right, ir.IntType(64), name="int2ptrint") + if op == '+' or op == 'Add': + return self.builder.gep(left, [right], name="ptr_add") + elif op == '-' or op == 'Sub': + return self.builder.gep(left, [self.builder.neg(right, name="neg")], name="ptr_sub") + if isinstance(left.type, ir.IntType) and isinstance(right.type, ir.PointerType): + left = self.builder.zext(left, ir.IntType(64), name="int2ptrint2") + if op == '+' or op == 'Add': + return self.builder.gep(right, [left], name="ptr_add_rev") + is_float = isinstance(left.type, (ir.FloatType, ir.DoubleType)) or \ + isinstance(right.type, (ir.FloatType, ir.DoubleType)) + if is_float: + if isinstance(left.type, (ir.FloatType, ir.DoubleType)): + ftype = left.type + elif isinstance(right.type, (ir.FloatType, ir.DoubleType)): + ftype = right.type + else: + ftype = ir.DoubleType() + if not isinstance(left.type, (ir.FloatType, ir.DoubleType)): + left = self._to_float(left, ftype) + elif left.type != ftype: + if isinstance(left.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): + left = self.builder.fpext(left, ftype, name="fpext_l") + else: + left = self.builder.fptrunc(left, ftype, name="fptrunc_l") + if not isinstance(right.type, (ir.FloatType, ir.DoubleType)): + right = self._to_float(right, ftype) + elif right.type != ftype: + if isinstance(right.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): + right = self.builder.fpext(right, ftype, name="fpext_r") + else: + right = self.builder.fptrunc(right, ftype, name="fptrunc_r") + float_ops = { + '+': self.builder.fadd, 'Add': self.builder.fadd, + '-': self.builder.fsub, 'Sub': self.builder.fsub, + '*': self.builder.fmul, 'Mult': self.builder.fmul, + '/': self.builder.fdiv, 'Div': self.builder.fdiv, + '%': self.builder.frem, 'Mod': self.builder.frem, + } + float_cmp_ops = { + '==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=', + '<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=', + '>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=', + } + if op in float_ops: + return float_ops[op](left, right, name=op) + if op in float_cmp_ops: + return self.builder.fcmp_ordered(float_cmp_ops[op], left, right, name=op) + if is_unsigned: + ops = { + '+': self.builder.add, 'Add': self.builder.add, + '-': self.builder.sub, 'Sub': self.builder.sub, + '*': self.builder.mul, 'Mult': self.builder.mul, + '/': self.builder.udiv, 'Div': self.builder.udiv, + '%': self.builder.urem, 'Mod': self.builder.urem, + '//': self.builder.udiv, 'FloorDiv': self.builder.udiv, + } + else: + ops = { + '+': self.builder.add, 'Add': self.builder.add, + '-': self.builder.sub, 'Sub': self.builder.sub, + '*': self.builder.mul, 'Mult': self.builder.mul, + '/': self.builder.sdiv, 'Div': self.builder.sdiv, + '%': self.builder.srem, 'Mod': self.builder.srem, + '//': self.builder.sdiv, 'FloorDiv': self.builder.sdiv, + } + cmp_ops = { + '==': '==', 'Eq': '==', '!=': '!=', 'NotEq': '!=', + '<': '<', 'Lt': '<', '<=': '<=', 'LtE': '<=', + '>': '>', 'Gt': '>', '>=': '>=', 'GtE': '>=', + } + logic_ops = { + '&&': self.builder.and_, 'And': self.builder.and_, + '||': self.builder.or_, 'Or': self.builder.or_, + } + if op in ('>>', 'RShift') and not is_unsigned: + if isinstance(left.type, ir.IntType): + if left.type.width == 8: + is_unsigned = True + elif left.type.width == 16: + is_unsigned = True + elif left.type.width == 32: + if hasattr(self, '_last_var_name') and self._last_var_name: + is_unsigned = self._is_var_unsigned(self._last_var_name) + elif left.type.width == 64: + if hasattr(self, '_last_var_name') and self._last_var_name: + is_unsigned = self._is_var_unsigned(self._last_var_name) + shift_ops = { + '>>': self.builder.lshr if is_unsigned else self.builder.ashr, + 'RShift': self.builder.lshr if is_unsigned else self.builder.ashr, + '<<': self.builder.shl, 'LShift': self.builder.shl, + } + bit_ops = { + '&': self.builder.and_, + '|': self.builder.or_, + '^': self.builder.xor, + } + if op == '**' or op == 'Pow': + if isinstance(left, ir.Constant) and isinstance(right, ir.Constant): + try: + lv = left.constant + rv = right.constant + if isinstance(lv, int) and isinstance(rv, int) and rv >= 0: + result = lv ** rv + return ir.Constant(left.type, result) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + pass + if isinstance(left.type, (ir.FloatType, ir.DoubleType)): + ftype = left.type + elif isinstance(right.type, (ir.FloatType, ir.DoubleType)): + ftype = right.type + else: + ftype = ir.DoubleType() + lf = self._to_float(left, ftype) + rf = self._to_float(right, ftype) + powf = self.module.globals.get('llvm.pow.f64') + if not powf: + fnty = ir.FunctionType(ir.DoubleType(), [ir.DoubleType(), ir.DoubleType()]) + powf = ir.Function(self.module, fnty, name='llvm.pow.f64') + if lf.type != ir.DoubleType(): + lf = self.builder.fpext(lf, ir.DoubleType(), name="ext_f64") + if rf.type != ir.DoubleType(): + rf = self.builder.fpext(rf, ir.DoubleType(), name="ext_f64") + result = self.builder.call(powf, [lf, rf], name="pow") + both_int = isinstance(left.type, ir.IntType) and isinstance(right.type, ir.IntType) + right_is_pos_int_const = isinstance(right, ir.Constant) and isinstance(right.constant, int) and right.constant >= 0 + if both_int and right_is_pos_int_const: + return self.builder.fptosi(result, left.type, name="pow2int") + if isinstance(left.type, ir.FloatType): + return self.builder.fptrunc(result, ir.FloatType(), name="pow2f32") + return result + if op in ops: + try: + return ops[op](left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + if op in shift_ops: + try: + return shift_ops[op](left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + if op in bit_ops: + try: + return bit_ops[op](left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + if op in cmp_ops: + try: + if is_unsigned: + return self.builder.icmp_unsigned(cmp_ops[op], left, right, name=op) + return self.builder.icmp_signed(cmp_ops[op], left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + if op in logic_ops: + try: + return logic_ops[op](left, right, name=op) + except Exception as e: + raise ValueError(f"{e}{self._get_node_info()}") + return left + + def _to_float(self, val, ftype=None): + if ftype is None: + ftype = ir.DoubleType() + if isinstance(val.type, (ir.FloatType, ir.DoubleType)): + if val.type == ftype: + return val + if isinstance(val.type, ir.FloatType) and isinstance(ftype, ir.DoubleType): + return self.builder.fpext(val, ftype, name="fpext") + return self.builder.fptrunc(val, ftype, name="fptrunc") + if isinstance(val.type, ir.IntType): + if val.type.width == 1: + val = self.builder.zext(val, ir.IntType(32), name="bool2i32") + return self.builder.sitofp(val, ftype, name="int2float") + return val + + def emit_return(self, value=None): + if not self.builder or self.builder.block.is_terminated: + return + if value is not None: + self._unregister_local_heap_ptr(value) + self._emit_local_heap_frees() + if hasattr(self, '_variadic_info') and self._variadic_info and self._variadic_info.get('va_start_called'): + va_list_ptr = self._variadic_info['va_list_ptr'] + self.emit_va_end(va_list_ptr) + if value is None: + if self.func and hasattr(self.func, 'ftype'): + ret_type = self.func.ftype.return_type + if isinstance(ret_type, ir.IntType): + self.builder.ret(ir.Constant(ret_type, 0)) + elif isinstance(ret_type, ir.PointerType): + self.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + self.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.IdentifiedStructType): + if ret_type.elements: + zero_val = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + self.builder.ret(zero_val) + elif isinstance(ret_type, ir.ArrayType): + self.builder.ret(ir.Constant(ret_type, None)) + else: + self.builder.ret_void() + else: + self.builder.ret_void() + else: + if self.func and hasattr(self.func, 'ftype'): + ret_type = self.func.ftype.return_type + if ret_type != value.type: + if isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.PointerType): + if value.type.pointee == ret_type: + value = self._load(value, name="ret_load") + else: + value = self.builder.bitcast(value, ret_type, name="ret_cast") + elif isinstance(value.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): + if isinstance(value.type.pointee, ir.IntType) and isinstance(ret_type, ir.IntType) and value.type.pointee.width == ret_type.width: + value = self._load(value, name="ret_load") + elif isinstance(ret_type, ir.IntType): + value = self.builder.ptrtoint(value, ret_type, name="ret_ptrtoint") + elif isinstance(value.type.pointee, ret_type.__class__) and not isinstance(value.type.pointee, ir.IntType): + value = self._load(value, name="ret_load") + elif isinstance(value.type.pointee, ir.PointerType): + loaded = self._load(value, name="ret_deref") + if loaded.type == ret_type: + value = loaded + elif isinstance(ret_type, ir.IntType): + value = self.builder.ptrtoint(loaded, ret_type, name="ret_ptrtoint") + elif isinstance(ret_type, ir.IntType) and isinstance(value.type, ir.IntType): + if value.type.width < ret_type.width: + # 有符号值用 sext,无符号值用 zext + is_unsigned = id(value) in self._unsigned_results + if is_unsigned: + value = self.builder.zext(value, ret_type, name="ret_zext") + else: + value = self.builder.sext(value, ret_type, name="ret_sext") + elif value.type.width > ret_type.width: + value = self.builder.trunc(value, ret_type, name="ret_trunc") + elif isinstance(ret_type, ir.PointerType) and isinstance(value.type, ir.IntType): + value = self.builder.inttoptr(value, ret_type, name="ret_inttoptr") + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, ir.IntType): + value = self.builder.sitofp(value, ret_type, name="ret_int2float") + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)) and isinstance(value.type, (ir.FloatType, ir.DoubleType)): + if ret_type != value.type: + value = self.builder.fpext(value, ret_type, name="ret_fpext") + self.builder.ret(value) + + def _emit_printf(self, args, unsigned_flags=None, sep=" ", end="\n"): + if not args: + return None + if unsigned_flags is None: + unsigned_flags = [] + format_str = "" + cast_args = [] + for i, arg in enumerate(args): + is_u = i < len(unsigned_flags) and unsigned_flags[i] + if isinstance(arg.type, ir.IntType): + if arg.type.width == 8: + format_str += "%c" + ext = self.builder.zext(arg, ir.IntType(32), name="char2int") + cast_args.append(ext) + elif arg.type.width == 64: + format_str += "%llu" if is_u else "%lld" + cast_args.append(arg) + else: + format_str += "%u" if is_u else "%d" + cast_args.append(arg) + elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)): + format_str += "%f" + cast_args.append(arg) + elif isinstance(arg.type, ir.PointerType): + if isinstance(arg.type.pointee, ir.IntType) and arg.type.pointee.width == 8: + format_str += "%s" + cast_args.append(arg) + else: + format_str += "%d" + int_val = self.builder.ptrtoint(arg, ir.IntType(64), name="ptr2int") + trunc_val = self.builder.trunc(int_val, ir.IntType(32), name="trunc") + cast_args.append(trunc_val) + else: + format_str += "%d" + cast_args.append(arg) + if sep is not None and i < len(args) - 1: + format_str += sep + if end is not None: + format_str += end + string_type = ir.ArrayType(ir.IntType(8), len(format_str.encode('utf-8')) + 1) + string_const = ir.Constant(string_type, bytearray(format_str + '\x00', 'utf-8')) + global_var = ir.GlobalVariable(self.module, string_type, name=f"str_const_{self.string_const_counter}") + self.string_const_counter += 1 + global_var.initializer = string_const + global_var.linkage = 'internal' + format_ptr = self.builder.bitcast(global_var, ir.PointerType(ir.IntType(8))) + call_args = [format_ptr] + cast_args + printf_func = self.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + return self.builder.call(printf_func, call_args, name="call_printf") + + def _get_or_declare_func(self, name, func_type): + import re + for fname, fobj in self.functions.items(): + if fname == name: + return fobj + if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): + return fobj + func_decl = ir.Function(self.module, func_type, name=name) + self.functions[name] = func_decl + return func_decl + + def get_or_declare_c_func(self, name, fallback_type=None): + if name in self.functions: + return self.functions[name] + import re + for fname, fobj in self.functions.items(): + if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): + return fobj + stub_func_type = None + if hasattr(self, '_import_handler_ref') and self._import_handler_ref: + try: + stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self) + except Exception: + pass + if stub_func_type: + func_decl = ir.Function(self.module, stub_func_type, name=name) + self.functions[name] = func_decl + return func_decl + if fallback_type is not None: + func_decl = ir.Function(self.module, fallback_type, name=name) + self.functions[name] = func_decl + return func_decl + return None + + def emit_sizeof(self, type_name): + for class_name, struct_type in self.structs.items(): + if type_name == class_name: + size = self._get_struct_size(struct_type) + if size > 0: + return ir.Constant(ir.IntType(64), size) + return ir.Constant(ir.IntType(64), 4) diff --git a/lib/core/SymbolNode.py b/lib/core/SymbolNode.py new file mode 100644 index 0000000..1042448 --- /dev/null +++ b/lib/core/SymbolNode.py @@ -0,0 +1,207 @@ +from __future__ import annotations +from typing import Any, Dict, Optional, TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.Handles.HandlesBase import CTypeInfo + +from lib.includes import t + + +class SymbolNode: + """符号表节点,类似 AST 节点的树形结构 + + attributes 存储 CTypeInfo 对象,不再使用 TypeInfo + """ + + def __init__(self, name: str, NodeType: str, lineno: int = 0, file: str = '', parent: SymbolNode | None = None): + from lib.core.Handles.HandlesBase import CTypeInfo + self.name: str = name + self.type: str = NodeType + self.lineno: int = lineno + self.file: str = file + self.parent: SymbolNode | None = parent + self.children: Dict[str, SymbolNode] = {} + self.attributes: CTypeInfo = CTypeInfo() + self.attributes.Name = name + self.attributes.Lineno = lineno + + def get(self, key: str, default: Any = None) -> Any: + """获取属性值""" + if hasattr(self.attributes, key): + return getattr(self.attributes, key) + return self.attributes._extra.get(key, default) + + def set(self, key: str, value: Any): + """设置属性值""" + if hasattr(self.attributes, key): + attr = getattr(type(self.attributes), key, None) + if isinstance(attr, property) and attr.fset is None: + return + setattr(self.attributes, key, value) + else: + self.attributes._extra[key] = value + + def HasChild(self, name: str) -> bool: + """检查是否有子节点""" + return name in self.children + + def GetChild(self, name: str) -> Optional[SymbolNode]: + """获取子节点""" + return self.children.get(name) + + def AddChild(self, node: SymbolNode): + """添加子节点""" + node.parent = self + self.children[node.name] = node + + def RemoveChild(self, name: str) -> bool: + """删除子节点""" + if name in self.children: + del self.children[name] + return True + return False + + def find(self, path: str, separator: str = '.') -> Optional[SymbolNode]: + """根据路径查找节点,如 'test.ClassA'""" + parts = path.split(separator) + current = self + + for part in parts: + if current.HasChild(part): + current = current.GetChild(part) + else: + return None + + return current + + def ToDict(self) -> Dict[str, Any]: + """转换为字典格式""" + result = { + 'type': self.type, + 'lineno': self.lineno, + 'file': self.file, + **self.attributes.entry + } + + if self.children: + result['children'] = {name: child.ToDict() for name, child in self.children.items()} + + return result + + @classmethod + def FromDict(cls, name: str, data: Dict[str, Any]) -> SymbolNode: + """从字典创建节点(兼容性)""" + node = cls(name=name, NodeType=data.get('type', 'unknown')) + node.lineno = data.get('lineno', 0) + node.file = data.get('file', '') + + for key, value in data.items(): + if key not in ('type', 'lineno', 'file', 'children'): + node.set(key, value) + + if 'children' in data: + for ChildName, ChildData in data['children'].items(): + node.AddChild(cls.FromDict(ChildName, ChildData)) + + return node + + @classmethod + def CreateMember(cls, name: str, TypeName: str | None = None, TypeInfo: 'CTypeInfo | None' = None, IsPtr: bool = False, dims: list[int] | None = None, lineno: int = 0, file: str = '') -> SymbolNode: + """创建成员节点(工厂函数)""" + from lib.core.Handles.HandlesBase import CTypeInfo + node = cls(name=name, NodeType='member', lineno=lineno, file=file) + node.attributes = CTypeInfo() + node.attributes.Name = name + node.attributes.Lineno = lineno + if TypeInfo is not None: + node.attributes = TypeInfo + node.attributes.Name = name + node.attributes.Lineno = lineno + else: + if TypeName is not None: + node.attributes.BaseType = CTypeInfo.CreateFromTypeName(TypeName) + if IsPtr: + node.attributes.PtrCount = 1 + if dims: + node.attributes.ArrayDims = list(dims) + return node + + @classmethod + def CreateClass(cls, name: str, TypeKind: type, members: dict | None = None, lineno: int = 0, file: str = '', IsCpythonObject: bool = False, IsPacked: bool = False) -> SymbolNode: + """创建类节点(工厂函数)""" + from lib.core.Handles.HandlesBase import CTypeInfo + node = cls(name=name, NodeType=TypeKind, lineno=lineno, file=file) + node.attributes = CTypeInfo() + node.attributes.Name = name + node.attributes.Lineno = lineno + node.attributes.IsCpythonObject = IsCpythonObject + node.attributes.IsPacked = IsPacked + if members: + for MemberName, MemberInfo in members.items(): + if isinstance(MemberInfo, CTypeInfo): + node.attributes.Members[MemberName] = MemberInfo + elif isinstance(MemberInfo, dict): + CTypeMember = CTypeInfo() + type_str = MemberInfo.get('type', 'int') + is_ptr = MemberInfo.get('IsPtr', False) + if isinstance(type_str, str): + try: + resolved = CTypeInfo.FromTypeName(type_str) + if resolved and resolved.BaseType: + CTypeMember = resolved + else: + CTypeMember.BaseType = t.CInt() + except Exception: + CTypeMember.BaseType = t.CInt() + else: + CTypeMember.BaseType = t.CInt() + if is_ptr and not CTypeMember.IsPtr: + CTypeMember.PtrCount = max(CTypeMember.PtrCount, 1) + node.attributes.Members[MemberName] = CTypeMember + if TypeKind == 'struct': + node.attributes.IsStruct = True + elif TypeKind == 'enum': + node.attributes.IsEnum = True + elif TypeKind == 'union': + node.attributes.IsUnion = True + elif TypeKind == 'typedef': + node.attributes.IsTypedef = True + elif TypeKind == 'exception': + node.attributes.IsExceptionClass = True + return node + + @classmethod + def CreateTypedef(cls, name: str, OriginalType, members: dict | None = None, lineno: int = 0, file: str = '') -> SymbolNode: + from lib.core.Handles.HandlesBase import CTypeInfo + node = cls(name=name, NodeType='typedef', lineno=lineno, file=file) + node.attributes = CTypeInfo() + node.attributes.Name = name + node.attributes.Lineno = lineno + node.attributes.IsTypedef = True + if isinstance(OriginalType, CTypeInfo): + node.attributes.OriginalType = OriginalType + elif isinstance(OriginalType, str): + node.attributes.OriginalType = CTypeInfo.FromTypeName(OriginalType) if OriginalType else None + else: + node.attributes.OriginalType = OriginalType + return node + + @classmethod + def CreateAnonymous(cls, name: str, IsUnion: bool, members: dict, lineno: int = 0, file: str = '') -> SymbolNode: + """创建匿名类型节点(工厂函数)""" + from lib.core.Handles.HandlesBase import CTypeInfo + NodeType = t.CUnion if IsUnion else t.CStruct + node = cls(name=name, NodeType=NodeType, lineno=lineno, file=file) + node.attributes = CTypeInfo() + node.attributes.Name = name + node.attributes.Lineno = lineno + node.attributes.IsAnonymous = True + if IsUnion: + node.attributes.IsUnion = True + else: + node.attributes.IsStruct = True + return node + + @classmethod + def CreateModule(cls, name: str, lineno: int = 0, file: str = '') -> SymbolNode: + """创建模块节点(工厂函数)""" + return cls(name=name, NodeType='module', lineno=lineno, file=file) diff --git a/lib/core/SymbolTable.py b/lib/core/SymbolTable.py new file mode 100644 index 0000000..f669362 --- /dev/null +++ b/lib/core/SymbolTable.py @@ -0,0 +1,998 @@ +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.SymbolNode import SymbolNode +from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper +from lib.includes import t +from typing import Any, Dict, Iterator +import ast +import re + +def _IsTModuleType(TypeName: str) -> bool: + """检测类型名称是否是 t 模块中的类型(CType 或其他特殊类型)""" + if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'): + return True + TypeClass = getattr(t, TypeName, None) + if TypeClass and isinstance(TypeClass, type): + if issubclass(TypeClass, t.CType): + return True + FallbackClass = getattr(t, f'_{TypeName}', None) + if FallbackClass and isinstance(FallbackClass, type): + if issubclass(FallbackClass, t.CType): + return True + return False + +def _AnnotationContainsTType(node, TypeName: str) -> bool: + """检测 AST 节点中是否包含指定名称的 t 模块类型""" + if isinstance(node, ast.Attribute): + if (hasattr(node.value, 'id') and node.value.id == 't' and + node.attr == TypeName): + return True + elif isinstance(node, ast.BinOp): + return _AnnotationContainsTType(node.left, TypeName) or _AnnotationContainsTType(node.right, TypeName) + elif isinstance(node, ast.Call): + if _AnnotationContainsTType(node.func, TypeName): + return True + for arg in node.args: + if _AnnotationContainsTType(arg, TypeName): + return True + elif isinstance(node, ast.Subscript): + if _AnnotationContainsTType(node.value, TypeName): + return True + if _AnnotationContainsTType(node.slice, TypeName): + return True + return False + + +class SymbolTable: + def __init__(self, translator: "Translator"): + self.translator = translator + self._root = SymbolNode(name='root', NodeType='root') + + def clear(self): + self._root = SymbolNode(name='root', NodeType='root') + + def get(self, name: str, default=None) -> CTypeInfo: + node = self._FindNode(name) + if node: + return node.attributes + return default + + def set(self, name: str, value: Any): + self._InsertNode(name, value) + self._cached_len = -1 + + def update(self, symbols: Dict[str, Any]): + for name, value in symbols.items(): + self.set(name, value) + + def keys(self) -> Iterator[str]: + return self._CollectKeys(self._root) + + def values(self) -> Iterator[CTypeInfo]: + for node in self._CollectNodes(self._root): + yield node.attributes + + def items(self) -> Iterator[tuple[str, CTypeInfo]]: + for node in self._CollectNodes(self._root): + yield node.name, node.attributes + + def pop(self, name: str, *args) -> CTypeInfo: + node = self._FindNode(name) + if node and node.parent: + node.parent.RemoveChild(node.name) + return node.attributes + if args: + return args[0] + raise KeyError(name) + + def __getitem__(self, name: str) -> CTypeInfo: + node = self._FindNode(name) + if node: + return node.attributes + raise KeyError(name) + + def __setitem__(self, name: str, value: Any): + self.set(name, value) + + def __delitem__(self, name: str): + node = self._FindNode(name) + if node and node.parent: + node.parent.RemoveChild(node.name) + self._cached_len = -1 + else: + raise KeyError(name) + + def __contains__(self, name: str) -> bool: + return self._FindNode(name) is not None + + def __len__(self) -> int: + if not hasattr(self, '_cached_len') or self._cached_len < 0: + self._cached_len = sum(1 for _ in self._CollectNodes(self._root)) + return self._cached_len + + def __iter__(self) -> Iterator[str]: + return self.keys() + + def ToDict(self) -> Dict[str, Any]: + return self._root.ToDict() + + def FromDict(self, symbols: Dict[str, Any]): + self._root = SymbolNode.FromDict('root', symbols) + + def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]: + return self._LoadSymbolsFromFile(FullModulePath, asname, lineno) + + def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]: + from lib.core.Handles.HandlesTypeMerge import HandlesTypeMerge + import ast + + LoadedSymbols = [] + + try: + with open(FilePath, 'r', encoding='utf-8') as f: + ModuleCode = f.read() + ModuleTree = ast.parse(ModuleCode) + + ClassMembers = {} + AnonymousTypes = {} + + for node in ModuleTree.body: + if isinstance(node, ast.ClassDef): + ClassName = node.name + MembersInfo = {} + + def CollectMembers(ClassNode, prefix=''): + for item in ClassNode.body: + if isinstance(item, ast.AnnAssign): + if isinstance(item.target, ast.Name): + MemberName = item.target.id + FullName = f'{prefix}{MemberName}' if prefix else MemberName + MemberTypeInfo = CTypeInfo.FromNode(item.annotation, self.translator.SymbolTable) + if MemberTypeInfo is None: + MemberTypeInfo = CTypeInfo() + MemberTypeInfo.BaseType = t.CInt() + IsPtr = MemberTypeInfo.IsPtr + if isinstance(item.annotation, ast.BinOp): + AnnotationStr = ast.dump(item.annotation) + if 'CPtr' in AnnotationStr: + IsPtr = True + MembersInfo[FullName] = MemberTypeInfo.Copy() + elif isinstance(item, ast.ClassDef): + IsAnonymous = any( + any(_AnnotationContainsTType(base, 'Anonymous') for base in item.bases) + ) if item.bases else False + + if IsAnonymous: + IsUnion = any( + any(_AnnotationContainsTType(base, 'CUnion') for base in item.bases) + ) + + NestedMemberName = f'{prefix}{item.name}' if prefix else item.name + MembersInfo[NestedMemberName] = CTypeInfo() + MembersInfo[NestedMemberName].BaseType = f'union {item.name}' if IsUnion else f'struct {item.name}' + MembersInfo[NestedMemberName].PtrCount = 0 + MembersInfo[NestedMemberName].ArrayDims = [] + + NewPrefix = f'{prefix}{item.name}.' if prefix else f'{item.name}.' + CollectMembers(item, NewPrefix) + + AnonymousMembers = {} + for FullName, MemberInfo in MembersInfo.items(): + if FullName.startswith(f"{NestedMemberName}."): + MemberName = FullName[len(NestedMemberName) + 1:] + AnonymousMembers[MemberName] = MemberInfo + + if item.name not in AnonymousTypes: + AnonymousTypes[item.name] = { + 'IsUnion': IsUnion, + 'members': AnonymousMembers, + 'lineno': item.lineno + } + + CollectMembers(node) + ClassMembers[ClassName] = MembersInfo + + LoadedSymbols = [] + + prefixes = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix + + for prefix in prefixes: + for node in ModuleTree.body: + if isinstance(node, ast.ClassDef): + ClassName = node.name + MembersInfo = ClassMembers.get(ClassName, {}) + + TypeKind = 'struct' + IsCpythonObject = False + IsPacked = False + + if hasattr(node, 'decorator_list') and node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Attribute): + if (hasattr(decorator.value, 'id') and + decorator.value.id == 't' and + decorator.attr == 'Object'): + IsCpythonObject = True + break + elif isinstance(decorator, ast.Call): + if isinstance(decorator.func, ast.Attribute): + if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute': + for arg in decorator.args: + if isinstance(arg, ast.Attribute): + if isinstance(arg.value, ast.Attribute): + if hasattr(arg.value.value, 'id') and arg.value.value.id == 't' and arg.value.attr == 'attr' and arg.attr == 'packed': + IsPacked = True + + for base in node.bases: + if _AnnotationContainsTType(base, 'CUnion'): + TypeKind = 'union' + break + elif _AnnotationContainsTType(base, 'CEnum'): + TypeKind = 'enum' + break + elif _AnnotationContainsTType(base, 'CStruct'): + TypeKind = 'struct' + break + elif _AnnotationContainsTType(base, 'Object'): + IsCpythonObject = True + TypeKind = 'struct' + break + elif isinstance(base, ast.Name) and base.id == 'Exception': + TypeKind = 'exception' + break + elif isinstance(base, ast.Name): + base_entry = self.get(base.id) + if base_entry and hasattr(base_entry, 'IsExceptionClass') and base_entry.IsExceptionClass: + TypeKind = 'exception' + break + + if prefix == prefixes[0]: + self._InsertClassSymbol(ClassName, TypeKind, node.lineno, FilePath, MembersInfo, IsCpythonObject, IsPacked) + LoadedSymbols.append(ClassName) + + FullName = f"{prefix}.{ClassName}" + self._InsertClassSymbol(FullName, TypeKind, node.lineno, FilePath, MembersInfo, IsCpythonObject, IsPacked) + LoadedSymbols.append(FullName) + + if TypeKind == 'enum': + next_enum_value = 0 + for item in node.body: + if isinstance(item, ast.Assign): + if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): + MemberName = item.targets[0].id + if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + next_enum_value = item.value.value + 1 + else: + next_enum_value += 1 + if prefix == prefixes[0]: + self._InsertEnumMemberSymbol(MemberName, ClassName, item.lineno, FilePath) + LoadedSymbols.append(MemberName) + ClassMemberName = f"{ClassName}.{MemberName}" + self._InsertEnumMemberSymbol(ClassMemberName, ClassName, item.lineno, FilePath) + LoadedSymbols.append(ClassMemberName) + FullMemberName = f"{prefix}.{MemberName}" + self._InsertEnumMemberSymbol(FullMemberName, ClassName, item.lineno, FilePath) + LoadedSymbols.append(FullMemberName) + elif isinstance(item, ast.AnnAssign): + if isinstance(item.target, ast.Name): + MemberName = item.target.id + if item.value: + if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + next_enum_value = item.value.value + 1 + else: + next_enum_value += 1 + else: + next_enum_value += 1 + if prefix == prefixes[0]: + self._InsertEnumMemberSymbol(MemberName, ClassName, item.lineno, FilePath) + LoadedSymbols.append(MemberName) + ClassMemberName = f"{ClassName}.{MemberName}" + self._InsertEnumMemberSymbol(ClassMemberName, ClassName, item.lineno, FilePath) + LoadedSymbols.append(ClassMemberName) + FullMemberName = f"{prefix}.{MemberName}" + self._InsertEnumMemberSymbol(FullMemberName, ClassName, item.lineno, FilePath) + LoadedSymbols.append(FullMemberName) + + elif isinstance(node, ast.AnnAssign): + if isinstance(node.target, ast.Name): + VarName = node.target.id + HasCDefine = _AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False + HasPostdef = _AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False + HasCtypedef = _AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False + IsPostdefWithTypedef = HasPostdef and HasCtypedef + + if HasCDefine: + DefineValue = None + if node.value: + DefineValue = self._eval_const_expr(node.value) + if prefix == prefixes[0]: + self._InsertDefineSymbol(VarName, DefineValue, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertDefineSymbol(FullName, DefineValue, node.lineno, FilePath) + LoadedSymbols.append(FullName) + continue + + def FindBaseType(n): + if isinstance(n, ast.Attribute): + if hasattr(n.value, 'id') and n.value.id == 't': + if n.attr == 'CPtr': + return 'ptr' + return n.attr + elif isinstance(n, ast.Subscript): + if isinstance(n.value, ast.Attribute) and isinstance(n.value.value, ast.Name) and n.value.value.id == 't' and n.value.attr == 'Callable': + return 'Callable' + elif isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr): + LeftResult = FindBaseType(n.left) + if LeftResult == 'ptr': + RightResult = FindBaseType(n.right) + return (RightResult if RightResult and RightResult != 'ptr' else 'void') + ' *' + if LeftResult == 'Callable': + return 'Callable' + RightResult = FindBaseType(n.right) + if RightResult == 'ptr': + return (LeftResult if LeftResult and LeftResult != 'ptr' else 'void') + ' *' + if RightResult == 'Callable': + return 'Callable' + if LeftResult: + return LeftResult + if RightResult: + return RightResult + return None + + if IsPostdefWithTypedef: + def FindPostdefArg(n): + if isinstance(n, ast.Call): + if isinstance(n.func, ast.Attribute): + if hasattr(n.func.value, 'id') and n.func.value.id == 't' and n.func.attr == 'Postdefinition': + if n.args and isinstance(n.args[0], ast.Name): + return n.args[0].id + elif isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr): + LeftResult = FindPostdefArg(n.left) + if LeftResult: + return LeftResult + RightResult = FindPostdefArg(n.right) + if RightResult: + return RightResult + return None + + OriginalClass = FindPostdefArg(node.annotation) + if OriginalClass and OriginalClass in ClassMembers: + MembersInfo = ClassMembers[OriginalClass] + OriginalType_kind = 'struct' + if OriginalClass in self: + OrigTypeInfo = self[OriginalClass] + if OrigTypeInfo.TypeCls in (t.CStruct, t.CEnum, t.CUnion): + if OrigTypeInfo.TypeCls is t.CStruct: + OriginalType_kind = 'struct' + elif OrigTypeInfo.TypeCls is t.CEnum: + OriginalType_kind = 'enum' + elif OrigTypeInfo.TypeCls is t.CUnion: + OriginalType_kind = 'union' + + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, OriginalType_kind, OriginalClass, node.lineno, FilePath, MembersInfo) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, OriginalType_kind, OriginalClass, node.lineno, FilePath, MembersInfo) + LoadedSymbols.append(FullName) + else: + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) + LoadedSymbols.append(FullName) + elif HasCtypedef: + BaseTypeName = FindBaseType(node.annotation) + _TYPE_QUALIFIERS = {'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'} + if BaseTypeName == 'Callable': + OriginalType = CTypeInfo() + OriginalType.IsFuncPtr = True + OriginalType.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + OriginalType.FuncPtrParams = [] + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) + LoadedSymbols.append(FullName) + continue + elif BaseTypeName and BaseTypeName not in _TYPE_QUALIFIERS: + CName = CTypeHelper.GetCName(BaseTypeName) + if CName and CName != BaseTypeName: + OriginalType = CName + else: + OriginalType = BaseTypeName[1:] if BaseTypeName.startswith('C') else BaseTypeName + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) + LoadedSymbols.append(FullName) + else: + if node.value: + ValueBaseType = FindBaseType(node.value) + _PTR_MODIFIERS = {'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'} + if ValueBaseType and ValueBaseType not in _PTR_MODIFIERS: + CName = CTypeHelper.GetCName(ValueBaseType) + if CName and CName != ValueBaseType: + OriginalType = CName + else: + OriginalType = ValueBaseType[1:] if ValueBaseType.startswith('C') else ValueBaseType + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) + LoadedSymbols.append(FullName) + continue + if isinstance(node.value, ast.BinOp) and isinstance(node.value.op, ast.BitOr): + LeftType = self._ResolveTypedefValueType(node.value.left) + RightType = self._ResolveTypedefValueType(node.value.right) + IsPtrType = RightType == 'ptr' or LeftType == 'ptr' + if IsPtrType: + BaseName = LeftType if LeftType != 'ptr' else (RightType if RightType != 'ptr' else '') + if BaseName: + OriginalType = BaseName + ' *' + else: + OriginalType = 'void *' + elif LeftType: + OriginalType = LeftType + elif RightType: + OriginalType = RightType + if OriginalType: + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath) + LoadedSymbols.append(FullName) + continue + if isinstance(node.value, ast.Name): + RefName = node.value.id + if RefName in self: + RefInfo = self[RefName] + if RefInfo and RefInfo.IsTypedef and RefInfo.OriginalType: + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, 'typedef', RefInfo.OriginalType, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, 'typedef', RefInfo.OriginalType, node.lineno, FilePath) + LoadedSymbols.append(FullName) + continue + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) + LoadedSymbols.append(FullName) + else: + if prefix == prefixes[0]: + self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath) + LoadedSymbols.append(VarName) + FullName = f"{prefix}.{VarName}" + self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath) + LoadedSymbols.append(FullName) + + elif isinstance(node, ast.FunctionDef): + FuncName = node.name + RetType = self._GetFuncRetTypeStr(node.returns) + ParamTypes = [] + for arg in node.args.args: + if arg.annotation: + ParamTypes.append(self._GetFuncParamTypeStr(arg.annotation)) + else: + ParamTypes.append('i8*') + FuncIsVariadic = node.args.vararg is not None + FuncIsInline = self._CheckAnnotationHasCInline(node.returns) + if prefix == prefixes[0]: + self._InsertFuncSymbol(FuncName, RetType, ParamTypes, node.lineno, FilePath, FuncIsVariadic, FuncIsInline) + LoadedSymbols.append(FuncName) + FullName = f"{prefix}.{FuncName}" + self._InsertFuncSymbol(FullName, RetType, ParamTypes, node.lineno, FilePath, FuncIsVariadic, FuncIsInline) + LoadedSymbols.append(FullName) + + self._InsertModuleSymbol(prefix, lineno, FilePath) + + for AnonymousTypeName, AnonymousTypeData in AnonymousTypes.items(): + if prefix == prefixes[0]: + self._InsertAnonymousSymbol(AnonymousTypeName, AnonymousTypeData['IsUnion'], AnonymousTypeData['members'], AnonymousTypeData['lineno'], FilePath) + FullTypeName = f"{prefix}.{AnonymousTypeName}" + self._InsertAnonymousSymbol(FullTypeName, AnonymousTypeData['IsUnion'], AnonymousTypeData['members'], AnonymousTypeData['lineno'], FilePath) + + if LoadedSymbols: + pass + return LoadedSymbols + + except Exception as e: + import traceback + print(traceback.format_exc()) + print(f"[SymbolTable Error] Failed to load module: {FilePath} - {e}") + return [] + + def _GetLLVMTypeStr(self, node): + if node is None: + return 'i32' + if isinstance(node, ast.Name): + if node.id == 'str': + return 'i8*' + elif node.id == 'int': + return 'i32' + elif node.id == 'bool': + return 'i8' + elif node.id == 'float': + return 'double' + elif node.id == 'None': + return 'void' + elif node.id in ('UINT8PTR', 'INT8PTR', 'BYTEPTR'): + return 'i8*' + elif node.id in ('UINT16PTR', 'INT16PTR'): + return 'i16*' + elif node.id in ('UINT32PTR', 'INT32PTR'): + return 'i32*' + elif node.id in ('UINT64PTR', 'INT64PTR'): + return 'i64*' + else: + if node.id in self: + entry = self[node.id] + if entry and hasattr(entry, 'IsTypedef') and entry.IsTypedef and hasattr(entry, 'OriginalType') and entry.OriginalType: + if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr: + return 'i8*' + elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType: + return entry.OriginalType.ToString() + elif isinstance(entry.OriginalType, str): + return entry.OriginalType + return 'i32' + elif isinstance(node, ast.Attribute): + attr_name = node.attr if hasattr(node, 'attr') else '' + from lib.includes.t import CTypeRegistry + llvm_str = CTypeRegistry.NameToLLVM(attr_name) + if llvm_str is not None: + return llvm_str + if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'): + return '' + if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'): + return 'i8*' + if attr_name == 'CVoidPtr': + return 'i8*' + if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class: + return f'%struct.{attr_name}*' + if attr_name and attr_name not in CTypeRegistry._name_to_class: + return f'%struct.{attr_name}*' + return 'i32' + elif isinstance(node, ast.Subscript): + if isinstance(node.value, ast.Name) and node.value.id == 'tuple': + slice_node = node.slice + elem_types = [] + if isinstance(slice_node, ast.Tuple): + for elt in slice_node.elts: + elem_types.append(self._GetLLVMTypeStr(elt)) + else: + elem_types.append(self._GetLLVMTypeStr(slice_node)) + if elem_types: + return '{ ' + ', '.join(elem_types) + ' }' + if isinstance(node.value, ast.Name) and node.value.id == 'list': + slice_node = node.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: + elem_type = self._GetLLVMTypeStr(slice_node.elts[0]) + else: + elem_type = self._GetLLVMTypeStr(slice_node) + return elem_type + '*' + return 'i32' + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + left = self._GetLLVMTypeStr(node.left) + right = self._GetLLVMTypeStr(node.right) + if right and right.endswith('*'): + return right + if left and left.endswith('*'): + return left + if left and left not in ('i32', 'void', 'i64'): + return left + if right and right not in ('i32', 'void', 'i64'): + return right + return left if left else right + elif isinstance(node, ast.Constant): + if isinstance(node.value, bool): + return 'i8' + return 'i32' + elif isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if hasattr(node.func.value, 'id') and node.func.value.id == 't': + return self._GetLLVMTypeStr(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr)) + return 'i32' + return 'i32' + + def _GetFuncRetTypeStr(self, returns_node): + if returns_node is None: + return 'i32' + actual = returns_node + if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr): + left_str = self._GetLLVMTypeStr(returns_node.left) + right_str = self._GetLLVMTypeStr(returns_node.right) + if right_str and right_str.endswith('*'): + return right_str + if left_str and left_str.endswith('*'): + return left_str + if left_str and left_str not in ('i32', 'void', 'i64'): + return left_str + if right_str and right_str not in ('i32', 'void', 'i64'): + return right_str + return left_str + result = self._GetLLVMTypeStr(actual) + return result if result else 'i32' + + @staticmethod + def _CheckAnnotationHasCInline(annotation_node) -> bool: + if annotation_node is None: + return False + if isinstance(annotation_node, ast.Attribute): + if hasattr(annotation_node.value, 'id') and annotation_node.value.id == 't' and annotation_node.attr == 'CInline': + return True + if isinstance(annotation_node, ast.Name): + if annotation_node.id == 'CInline': + return True + if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): + return SymbolTable._CheckAnnotationHasCInline(annotation_node.left) or SymbolTable._CheckAnnotationHasCInline(annotation_node.right) + return False + + def _GetFuncParamTypeStr(self, annotation_node): + if annotation_node is None: + return 'i8*' + actual = annotation_node + if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): + left_str = self._GetLLVMTypeStr(annotation_node.left) + right_str = self._GetLLVMTypeStr(annotation_node.right) + if right_str and right_str.endswith('*'): + return right_str + if left_str and left_str.endswith('*'): + return left_str + if right_str and right_str not in ('i32', 'void', 'i64'): + return right_str + if left_str and left_str not in ('i32', 'void', 'i64'): + return left_str + if left_str and left_str.endswith('*'): + return left_str + return right_str if right_str else left_str + result = self._GetLLVMTypeStr(actual) + return result if result else 'i8*' + + def _ResolveTypedefValueType(self, node): + if node is None: + return '' + if isinstance(node, ast.Name): + if node.id in self: + Entry = self[node.id] + if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef and Entry.OriginalType: + return Entry.OriginalType + return '' + if isinstance(node, ast.Attribute): + if isinstance(node.value, ast.Name) and node.value.id == 't': + CName = CTypeHelper.GetCName(node.attr) + if CName and CName == '*': + return 'ptr' + if CName: + return CName + return '' + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + left_str = self._ResolveTypedefValueType(node.left) + right_str = self._ResolveTypedefValueType(node.right) + if right_str == 'ptr' or (right_str and right_str.endswith('*')): + base = left_str if left_str and left_str != 'ptr' else '' + return base + ' *' if base else 'void *' + if left_str == 'ptr' or (left_str and left_str.endswith('*')): + base = right_str if right_str and right_str != 'ptr' else '' + return base + ' *' if base else 'void *' + if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'): + return right_str + if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'): + return left_str + return left_str if left_str else right_str + return '' + + def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict, IsCpythonObject: bool, IsPacked: bool = False): + parts = FullName.split('.') + current = self._root + + for i, part in enumerate(parts[:-1]): + if not current.HasChild(part): + node = SymbolNode(name=part, NodeType='namespace') + current.AddChild(node) + current = current.GetChild(part) + + LastPart = parts[-1] + node = SymbolNode.CreateClass( + name=LastPart, + TypeKind=TypeKind, + members=members, + lineno=lineno, + file=FilePath, + IsCpythonObject=IsCpythonObject, + IsPacked=IsPacked + ) + current.AddChild(node) + + def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str): + from lib.core.Handles.HandlesBase import CTypeInfo + parts = FullName.split('.') + current = self._root + + for i, part in enumerate(parts[:-1]): + if not current.HasChild(part): + node = SymbolNode(name=part, NodeType='namespace') + current.AddChild(node) + current = current.GetChild(part) + + LastPart = parts[-1] + info = CTypeInfo() + info.IsEnumMember = True + info.EnumName = EnumName + info.Lineno = lineno + info.file = FilePath + node = SymbolNode(name=LastPart, NodeType='enum_member') + node.attributes = info + current.AddChild(node) + + def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None): + parts = FullName.split('.') + current = self._root + + for i, part in enumerate(parts[:-1]): + if not current.HasChild(part): + node = SymbolNode(name=part, NodeType='namespace') + current.AddChild(node) + current = current.GetChild(part) + + LastPart = parts[-1] + if isinstance(OriginalClass, CTypeInfo): + OriginalType = OriginalClass + elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass): + OriginalType = OriginalClass + if OriginalType == 'CVoid *': + OriginalType = 'void *' + elif OriginalType_kind == 'typedef' and OriginalClass == 'void': + OriginalType = 'void *' + elif OriginalType_kind == 'typedef' and OriginalClass: + OriginalType = OriginalClass + elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str): + OriginalType = f'{OriginalType_kind} {OriginalClass}' + else: + OriginalType = OriginalClass + node = SymbolNode.CreateTypedef( + name=LastPart, + OriginalType=OriginalType, + members=members, + lineno=lineno, + file=FilePath + ) + current.AddChild(node) + + def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str): + node = SymbolNode.CreateModule( + name=name, + lineno=lineno, + file=FilePath + ) + self._root.AddChild(node) + + def _InsertFuncSymbol(self, FullName: str, RetType, ParamTypes: list, lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False): + parts = FullName.split('.') + current = self._root + + for i, part in enumerate(parts[:-1]): + if not current.HasChild(part): + node = SymbolNode(name=part, NodeType='namespace') + current.AddChild(node) + current = current.GetChild(part) + + LastPart = parts[-1] + from lib.core.Handles.HandlesBase import CTypeInfo + info = CTypeInfo() + info.IsFunction = True + if isinstance(RetType, str): + info.FuncPtrReturn = CTypeInfo.FromTypeName(RetType) if RetType else CTypeInfo.VoidTypeInfo() + elif isinstance(RetType, CTypeInfo): + info.FuncPtrReturn = RetType + else: + info.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + info.FuncPtrParams = [(f'arg{i}', pt) for i, pt in enumerate(ParamTypes)] + info.IsVariadic = IsVariadic + info.IsInline = IsInline + if IsInline: + info.Storage = t.CInline() + info.Lineno = lineno + info.file = FilePath + node = SymbolNode(name=LastPart, NodeType='function') + node.attributes = info + current.AddChild(node) + + def _InsertDefineSymbol(self, FullName: str, DefineValue, lineno: int, FilePath: str): + parts = FullName.split('.') + current = self._root + + for i, part in enumerate(parts[:-1]): + if not current.HasChild(part): + node = SymbolNode(name=part, NodeType='namespace') + current.AddChild(node) + current = current.GetChild(part) + + LastPart = parts[-1] + from lib.core.Handles.HandlesBase import CTypeInfo + info = CTypeInfo() + info.IsDefine = True + info.DefineValue = DefineValue + info.Lineno = lineno + info.file = FilePath + node = SymbolNode(name=LastPart, NodeType='define') + node.attributes = info + current.AddChild(node) + + def _eval_const_expr(self, node): + """计算常量表达式的值""" + import ast + if isinstance(node, ast.Constant): + return node.value + elif isinstance(node, ast.BinOp): + left = self._eval_const_expr(node.left) + right = self._eval_const_expr(node.right) + if left is None or right is None: + return None + if isinstance(node.op, ast.Add): + return left + right + elif isinstance(node.op, ast.Sub): + return left - right + elif isinstance(node.op, ast.Mult): + return left * right + elif isinstance(node.op, ast.Div): + return left // right if isinstance(left, int) and isinstance(right, int) else left / right + elif isinstance(node.op, ast.FloorDiv): + return left // right + elif isinstance(node.op, ast.Mod): + return left % right + elif isinstance(node.op, ast.Pow): + return left ** right + elif isinstance(node.op, ast.LShift): + return left << right + elif isinstance(node.op, ast.RShift): + return left >> right + elif isinstance(node.op, ast.BitOr): + return left | right + elif isinstance(node.op, ast.BitXor): + return left ^ right + elif isinstance(node.op, ast.BitAnd): + return left & right + elif isinstance(node, ast.UnaryOp): + operand = self._eval_const_expr(node.operand) + if operand is None: + return None + if isinstance(node.op, ast.USub): + return -operand + elif isinstance(node.op, ast.UAdd): + return +operand + elif isinstance(node.op, ast.Invert): + return ~operand + elif isinstance(node, ast.Name): + # 引用其他常量 + if node.id in self: + info = self[node.id] + if hasattr(info, 'IsDefine') and info.IsDefine and hasattr(info, 'DefineValue') and info.DefineValue is not None: + return info.DefineValue + return None + + def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict, lineno: int, FilePath: str): + parts = FullName.split('.') + current = self._root + + for i, part in enumerate(parts[:-1]): + if not current.HasChild(part): + node = SymbolNode(name=part, NodeType='namespace') + current.AddChild(node) + current = current.GetChild(part) + + LastPart = parts[-1] + node = SymbolNode.CreateAnonymous( + name=LastPart, + IsUnion=IsUnion, + members=members, + lineno=lineno, + file=FilePath + ) + current.AddChild(node) + + def _FindNode(self, name: str) -> SymbolNode | None: + if '.' not in name: + return self._root.GetChild(name) + + parts = name.split('.') + current = self._root + + for part in parts: + if current.HasChild(part): + current = current.GetChild(part) + else: + return None + + return current + + def _InsertNode(self, name: str, attributes: dict | "CTypeInfo"): + from lib.core.Handles.HandlesBase import CTypeInfo + parts = name.split('.') + current = self._root + + for part in parts[:-1]: + if not current.HasChild(part): + node = SymbolNode(name=part, NodeType='namespace') + current.AddChild(node) + current = current.GetChild(part) + + LastPart = parts[-1] + + if isinstance(attributes, CTypeInfo): + node = SymbolNode(name=LastPart, NodeType='type', lineno=attributes.Lineno or 0) + node.attributes = attributes + current.AddChild(node) + return + + NodeType = attributes.get('type', 'unknown') + + # 根据节点类型使用相应的工厂函数 + if NodeType == 'member': + node = SymbolNode.CreateMember( + name=LastPart, + TypeName=attributes.get('type', ''), + IsPtr=attributes.get('IsPtr', False), + dims=attributes.get('dims', []), + lineno=attributes.get('lineno', 0), + file=attributes.get('file', '') + ) + elif NodeType == 'typedef': + node = SymbolNode.CreateTypedef( + name=LastPart, + OriginalType=attributes.get('OriginalType', ''), + members=attributes.get('members', None), + lineno=attributes.get('lineno', 0), + file=attributes.get('file', '') + ) + elif NodeType == 'module': + node = SymbolNode.CreateModule( + name=LastPart, + lineno=attributes.get('lineno', 0), + file=attributes.get('file', '') + ) + elif attributes.get('IsAnonymous'): + node = SymbolNode.CreateAnonymous( + name=LastPart, + IsUnion=NodeType == 'union', + members=attributes.get('members', {}), + lineno=attributes.get('lineno', 0), + file=attributes.get('file', '') + ) + else: + # 其他类型(struct, union, enum, function, variable 等) + node = SymbolNode.CreateClass( + name=LastPart, + TypeKind=NodeType, + members=attributes.get('members', None), + lineno=attributes.get('lineno', 0), + file=attributes.get('file', ''), + IsCpythonObject=attributes.get('IsCpythonObject', False) + ) + + # 设置其他属性 + for key, value in attributes.items(): + if key not in ('type', 'lineno', 'file', 'members', 'IsCpythonObject', 'IsAnonymous'): + node.set(key, value) + + current.AddChild(node) + + def _CollectKeys(self, node: SymbolNode) -> Iterator[str]: + for name, child in node.children.items(): + yield child.name + yield from self._CollectKeys(child) + + def _CollectNodes(self, node: SymbolNode) -> Iterator[SymbolNode]: + for child in node.children.values(): + yield child + yield from self._CollectNodes(child) diff --git a/lib/core/export_table.py b/lib/core/export_table.py new file mode 100644 index 0000000..e206be1 --- /dev/null +++ b/lib/core/export_table.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +""" +导出表模块 - 用于收集和存储文件的公开符号信息 +""" +from dataclasses import dataclass, field +from typing import Dict, List, Optional, Any + + +@dataclass +class EnumMember: + """枚举成员信息""" + name: str + value: int + lineno: int + + +@dataclass +class EnumInfo: + """枚举类型信息""" + name: str + members: List[EnumMember] = field(default_factory=list) + lineno: int = 0 + is_public: bool = True + + +@dataclass +class FunctionParam: + """函数参数信息""" + name: str + type_name: str + is_pointer: bool = False + + +@dataclass +class FunctionInfo: + """函数信息""" + name: str + return_type: str + params: List[FunctionParam] = field(default_factory=list) + lineno: int = 0 + is_public: bool = True + + +@dataclass +class StructMember: + """结构体成员信息""" + name: str + type_name: str + is_pointer: bool = False + array_size: Optional[int] = None + + +@dataclass +class StructInfo: + """结构体类型信息""" + name: str + members: List[StructMember] = field(default_factory=list) + lineno: int = 0 + is_public: bool = True + + +@dataclass +class TypedefInfo: + """类型别名信息""" + name: str + original_type: str + lineno: int = 0 + is_public: bool = True + + +@dataclass +class ExportTable: + """导出表 - 存储文件的所有公开符号""" + filename: str + enums: List[EnumInfo] = field(default_factory=list) + functions: List[FunctionInfo] = field(default_factory=list) + structs: List[StructInfo] = field(default_factory=list) + typedefs: List[TypedefInfo] = field(default_factory=list) + + def add_enum(self, name: str, lineno: int, is_public: bool = True) -> EnumInfo: + """添加枚举类型""" + enum_info = EnumInfo(name=name, lineno=lineno, is_public=is_public) + self.enums.append(enum_info) + return enum_info + + def add_function(self, name: str, return_type: str, lineno: int, is_public: bool = True) -> FunctionInfo: + """添加函数""" + func_info = FunctionInfo(name=name, return_type=return_type, lineno=lineno, is_public=is_public) + self.functions.append(func_info) + return func_info + + def add_struct(self, name: str, lineno: int, is_public: bool = True) -> StructInfo: + """添加结构体""" + struct_info = StructInfo(name=name, lineno=lineno, is_public=is_public) + self.structs.append(struct_info) + return struct_info + + def add_typedef(self, name: str, original_type: str, lineno: int, is_public: bool = True) -> TypedefInfo: + """添加类型别名""" + typedef_info = TypedefInfo(name=name, original_type=original_type, lineno=lineno, is_public=is_public) + self.typedefs.append(typedef_info) + return typedef_info + + def to_dict(self) -> Dict[str, Any]: + """转换为字典格式""" + return { + 'filename': self.filename, + 'enums': [ + { + 'name': enum.name, + 'lineno': enum.lineno, + 'is_public': enum.is_public, + 'members': [ + {'name': m.name, 'value': m.value, 'lineno': m.lineno} + for m in enum.members + ] + } + for enum in self.enums + ], + 'functions': [ + { + 'name': func.name, + 'return_type': func.return_type, + 'lineno': func.lineno, + 'is_public': func.is_public, + 'params': [ + {'name': p.name, 'type_name': p.type_name, 'is_pointer': p.is_pointer} + for p in func.params + ] + } + for func in self.functions + ], + 'structs': [ + { + 'name': struct.name, + 'lineno': struct.lineno, + 'is_public': struct.is_public, + 'members': [ + { + 'name': m.name, + 'type_name': m.type_name, + 'is_pointer': m.is_pointer, + 'array_size': m.array_size + } + for m in struct.members + ] + } + for struct in self.structs + ], + 'typedefs': [ + { + 'name': typedef.name, + 'original_type': typedef.original_type, + 'lineno': typedef.lineno, + 'is_public': typedef.is_public + } + for typedef in self.typedefs + ] + } + + def merge(self, other: 'ExportTable') -> None: + """合并另一个导出表""" + self.enums.extend(other.enums) + self.functions.extend(other.functions) + self.structs.extend(other.structs) + self.typedefs.extend(other.typedefs) + + def get_public_symbols(self) -> 'ExportTable': + """获取仅包含公开符号的导出表""" + result = ExportTable(filename=self.filename) + + result.enums = [e for e in self.enums if e.is_public] + result.functions = [f for f in self.functions if f.is_public] + result.structs = [s for s in self.structs if s.is_public] + result.typedefs = [t for t in self.typedefs if t.is_public] + + return result diff --git a/lib/core/logger.py b/lib/core/logger.py new file mode 100644 index 0000000..00752df --- /dev/null +++ b/lib/core/logger.py @@ -0,0 +1,297 @@ +""" +TransPyC 彩色日志系统 +支持终端颜色输出和日志文件转储 +""" + +import sys +import os +from datetime import datetime +from typing import Optional + +# ANSI 颜色代码 +class Colors: + RESET = '\033[0m' + BOLD = '\033[1m' + DIM = '\033[2m' + UNDERLINE = '\033[4m' + + # 前景色 + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + + # 高亮前景色 + BRIGHT_RED = '\033[91m' + BRIGHT_GREEN = '\033[92m' + BRIGHT_YELLOW = '\033[93m' + BRIGHT_BLUE = '\033[94m' + BRIGHT_MAGENTA = '\033[95m' + BRIGHT_CYAN = '\033[96m' + + # 背景色 + BG_RED = '\033[41m' + BG_GREEN = '\033[42m' + BG_YELLOW = '\033[43m' + BG_BLUE = '\033[44m' + BG_MAGENTA = '\033[45m' + BG_CYAN = '\033[46m' + + # 渐变颜色(用于详细日志) + GRAY = '\033[90m' + +# 检查是否支持颜色 +def supports_color(): + if not hasattr(sys.stdout, 'isatty'): + return False + if not sys.stdout.isatty(): + return False + if os.environ.get('NO_COLOR'): + return False + if os.environ.get('FORCE_COLOR'): + return True + return True + +# 全局颜色支持标志 +USE_COLORS = supports_color() + +# 日志级别 +class LogLevel: + DEBUG = 0 + INFO = 1 + WARNING = 2 + ERROR = 3 + CRITICAL = 4 + +class Logger: + def __init__(self, name: str = "TransPyC", log_file: Optional[str] = None, + level: int = LogLevel.INFO, use_colors: bool = True): + self.name = name + self.level = level + self.use_colors = use_colors and USE_COLORS + self.log_file = log_file + self.file_handler = None + + if log_file: + os.makedirs(os.path.dirname(os.path.abspath(log_file)), exist_ok=True) + self.file_handler = open(log_file, 'w', encoding='utf-8') + + # 进度跟踪 + self.current_phase = "" + self.total_items = 0 + self.current_item = 0 + + def _colorize(self, text: str, color: str) -> str: + if self.use_colors: + return f"{color}{text}{Colors.RESET}" + return text + + def _format_time(self) -> str: + return datetime.now().strftime("%H:%M:%S") + + def _write(self, message: str, level: str = ""): + # 输出到控制台 + print(message, file=sys.stdout) + sys.stdout.flush() + + # 输出到文件 + if self.file_handler: + # 文件输出不带颜色 + clean_msg = message + for color in vars(Colors).values(): + if isinstance(color, str) and color.startswith('\033'): + clean_msg = clean_msg.replace(color, '') + timestamp = self._format_time() + self.file_handler.write(f"[{timestamp}] {level} {clean_msg}\n") + self.file_handler.flush() + + def set_phase(self, phase: str, total: int = 0): + self.current_phase = phase + self.total_items = total + self.current_item = 0 + self.progress(phase, 0, total) + + def progress(self, message: str = "", current: int = 0, total: int = 0): + if total > 0: + self.total_items = total + if current > 0: + self.current_item = current + + if self.total_items > 0: + percent = (self.current_item / self.total_items) * 100 + bar_length = 30 + filled = int(bar_length * self.current_item / self.total_items) + bar = '█' * filled + '░' * (bar_length - filled) + status = f"[{self._colorize(bar, Colors.BLUE)}] {self.current_item}/{self.total_items} ({percent:.1f}%)" + else: + status = "" + + msg = f"{self._colorize('▶', Colors.BRIGHT_CYAN)} {self.current_phase}" + if status: + msg += f" {status}" + if message: + msg += f" - {message}" + + # 使用 \r 实现进度更新 + sys.stdout.write('\r' + msg) + sys.stdout.flush() + + def debug(self, message: str, category: str = ""): + if self.level > LogLevel.DEBUG: + return + + prefix = self._colorize("DEBUG", Colors.GRAY) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.GRAY)} {prefix}: {message}" + self._write(msg, "DEBUG") + + def info(self, message: str, category: str = ""): + prefix = self._colorize("INFO", Colors.GREEN) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.GREEN)} {prefix}: {message}" + self._write(msg, "INFO") + + def warning(self, message: str, category: str = ""): + prefix = self._colorize("WARN", Colors.BRIGHT_YELLOW) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.YELLOW)} {prefix}: {message}" + self._write(msg, "WARNING") + + def error(self, message: str, category: str = "", exception: Optional[Exception] = None): + prefix = self._colorize("ERROR", Colors.BRIGHT_RED) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.RED)} {prefix}: {message}" + if exception: + msg += f"\n{self._colorize('│', Colors.RED)} Exception: {type(exception).__name__}: {exception}" + self._write(msg, "ERROR") + + def critical(self, message: str, category: str = ""): + prefix = self._colorize("CRITICAL", Colors.BG_RED + Colors.WHITE + Colors.BOLD) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('╠', Colors.RED)} {prefix}: {message}" + self._write(msg, "CRITICAL") + + def success(self, message: str, category: str = ""): + prefix = self._colorize("SUCCESS", Colors.BRIGHT_GREEN) + if category: + prefix += f"[{self._colorize(category, Colors.CYAN)}]" + + msg = f"{self._colorize('├', Colors.GREEN)} {prefix}: {message}" + self._write(msg, "SUCCESS") + + def compile_error(self, message: str, file: str = "", line: int = 0, code: str = ""): + """编译错误格式化输出""" + header = self._colorize("编译错误", Colors.BG_RED + Colors.WHITE + Colors.BOLD) + + msg = f"\n{self._colorize('╔', Colors.RED)}{header}{self._colorize('╗', Colors.RED)}\n" + + if file and line > 0: + location = f"{self._colorize(file, Colors.CYAN)}:{self._colorize(str(line), Colors.YELLOW)}" + msg += f"{self._colorize('║', Colors.RED)} 位置:{location}\n" + + if code: + msg += f"{self._colorize('║', Colors.RED)} 代码:{self._colorize(code, Colors.WHITE)}\n" + + msg += f"{self._colorize('║', Colors.RED)} 错误:{self._colorize(message, Colors.BRIGHT_RED)}\n" + msg += f"{self._colorize('╚', Colors.RED)}{self._colorize('═' * 50, Colors.RED)}{self._colorize('╝', Colors.RED)}" + + self._write(msg, "ERROR") + + def compile_warning(self, message: str, file: str = "", line: int = 0, code: str = ""): + """编译警告格式化输出""" + header = self._colorize("警告", Colors.BG_YELLOW + Colors.BLACK) + + msg = f"\n{self._colorize('╔', Colors.YELLOW)}{header}{self._colorize('╗', Colors.YELLOW)}\n" + + if file and line > 0: + location = f"{self._colorize(file, Colors.CYAN)}:{self._colorize(str(line), Colors.YELLOW)}" + msg += f"{self._colorize('║', Colors.YELLOW)} 位置:{location}\n" + + if code: + msg += f"{self._colorize('║', Colors.YELLOW)} 代码:{self._colorize(code, Colors.WHITE)}\n" + + msg += f"{self._colorize('║', Colors.YELLOW)} 警告:{self._colorize(message, Colors.BRIGHT_YELLOW)}\n" + msg += f"{self._colorize('╚', Colors.YELLOW)}{self._colorize('═' * 50, Colors.YELLOW)}{self._colorize('╝', Colors.YELLOW)}" + + self._write(msg, "WARNING") + + def summary(self, stats: dict): + """输出编译摘要""" + header = self._colorize("编译摘要", Colors.BG_BLUE + Colors.WHITE + Colors.BOLD) + + msg = f"\n{self._colorize('╔', Colors.BLUE)}{header}{self._colorize('╗', Colors.BLUE)}\n" + + for key, value in stats.items(): + color = Colors.GREEN if value > 0 else Colors.WHITE + msg += f"{self._colorize('║', Colors.BLUE)} {key}: {self._colorize(str(value), color)}\n" + + msg += f"{self._colorize('╚', Colors.BLUE)}{self._colorize('═' * 50, Colors.BLUE)}{self._colorize('╝', Colors.BLUE)}" + + self._write(msg, "SUMMARY") + + def close(self): + if self.file_handler: + self.file_handler.close() + self.info(f"日志已保存到:{self.log_file}") + +# 全局日志实例 +_global_logger: Optional[Logger] = None + +def get_logger(name: str = "TransPyC", log_file: Optional[str] = None, + level: int = LogLevel.INFO, use_colors: bool = True) -> Logger: + global _global_logger + if _global_logger is None: + _global_logger = Logger(name, log_file, level, use_colors) + return _global_logger + +def set_logger(logger: Logger): + global _global_logger + _global_logger = logger + +# 便捷函数 +def debug(msg, category=""): + get_logger().debug(msg, category) + +def info(msg, category=""): + get_logger().info(msg, category) + +def warning(msg, category=""): + get_logger().warning(msg, category) + +def error(msg, category="", exception=None): + get_logger().error(msg, category, exception) + +def critical(msg, category=""): + get_logger().critical(msg, category) + +def success(msg, category=""): + get_logger().success(msg, category) + +def compile_error(msg, file="", line=0, code=""): + get_logger().compile_error(msg, file, line, code) + +def compile_warning(msg, file="", line=0, code=""): + get_logger().compile_warning(msg, file, line, code) + +def set_phase(phase, total=0): + get_logger().set_phase(phase, total) + +def progress(message="", current=0, total=0): + get_logger().progress(message, current, total) + +def summary(stats): + get_logger().summary(stats) diff --git a/lib/core/stub_generator.py b/lib/core/stub_generator.py new file mode 100644 index 0000000..76bd2e2 --- /dev/null +++ b/lib/core/stub_generator.py @@ -0,0 +1,733 @@ +#!/usr/bin/env python3 +""" +C/H 文件到 Python 存根文件生成器 + +将 C 头文件 (.h) 或 C 源文件 (.c) 转换为 Python 存根文件 (.pyi) +生成的 Python 代码使用 TransPyC 语法,包含类型注解 +""" + +import os +import re +from typing import List, Dict, Optional + + +class CTypeMapper: + + @classmethod + def _ResolveCNameToPyType(cls, c_type: str) -> str: + from lib.includes.t import CTypeRegistry + ctype_cls = CTypeRegistry.CNameToClass(c_type) + if ctype_cls is not None: + name = ctype_cls.__name__ + return f't.{name}' + resolved = CTypeRegistry.ResolveName(c_type) + if resolved is not None: + ctype_cls, _ = resolved + name = ctype_cls.__name__ + return f't.{name}' + _SPECIAL = { + 'signed': 't.CInt', 'unsigned': 't.CUnsigned', + 'signed char': 't.CChar', 'signed short': 't.CShort', + 'signed int': 't.CInt', 'signed long': 't.CLong', + '_Bool': 't.CBool', 'ssize_t': 't.CLong', + } + if c_type in _SPECIAL: + return _SPECIAL[c_type] + return c_type + + @classmethod + def MapType(cls, c_type: str, IsPtr: bool = False, IsArray: bool = False) -> str: + c_type = c_type.strip() + + IsConst = 'const ' in c_type + c_type = c_type.replace('const ', '').replace('const', '').strip() + IsVolatile = 'volatile ' in c_type + c_type = c_type.replace('volatile ', '').replace('volatile', '').strip() + IsStatic = 'static ' in c_type + c_type = c_type.replace('static ', '').replace('static', '').strip() + IsExtern = 'extern ' in c_type + c_type = c_type.replace('extern ', '').replace('extern', '').strip() + IsRegister = 'register ' in c_type + c_type = c_type.replace('register ', '').replace('register', '').strip() + IsInline = 'inline ' in c_type + c_type = c_type.replace('inline ', '').replace('inline', '').strip() + + PtrSuffix = '' + if IsPtr or c_type.endswith('*'): + PtrSuffix = ' | t.CPtr' + c_type = c_type.rstrip('*').strip() + + if c_type.startswith('struct '): + c_type = c_type[7:].strip() + elif c_type.startswith('union '): + c_type = c_type[6:].strip() + elif c_type.startswith('enum '): + c_type = c_type[5:].strip() + + PyType = cls._ResolveCNameToPyType(c_type) + + result = PyType + PtrSuffix + + if IsArray: + result += ' | t.CArrayPtr' + + return result + + +def _find_matching_brace(text: str, start: int) -> int: + depth = 0 + i = start + while i < len(text): + if text[i] == '{': + depth += 1 + elif text[i] == '}': + depth -= 1 + if depth == 0: + return i + elif text[i] == '"' or text[i] == "'": + quote = text[i] + i += 1 + while i < len(text) and text[i] != quote: + if text[i] == '\\': + i += 1 + i += 1 + elif text[i] == '/' and i + 1 < len(text) and text[i + 1] == '/': + while i < len(text) and text[i] != '\n': + i += 1 + continue + elif text[i] == '/' and i + 1 < len(text) and text[i + 1] == '*': + i += 2 + while i + 1 < len(text) and not (text[i] == '*' and text[i + 1] == '/'): + i += 1 + i += 1 + i += 1 + return -1 + + +def _strip_comments(content: str) -> str: + result = [] + i = 0 + while i < len(content): + if content[i] == '/' and i + 1 < len(content) and content[i + 1] == '/': + while i < len(content) and content[i] != '\n': + i += 1 + elif content[i] == '/' and i + 1 < len(content) and content[i + 1] == '*': + i += 2 + while i + 1 < len(content) and not (content[i] == '*' and content[i + 1] == '/'): + i += 1 + i += 2 + elif content[i] == '"' or content[i] == "'": + quote = content[i] + result.append(content[i]) + i += 1 + while i < len(content) and content[i] != quote: + if content[i] == '\\' and i + 1 < len(content): + result.append(content[i]) + i += 1 + result.append(content[i]) + i += 1 + if i < len(content): + result.append(content[i]) + i += 1 + else: + result.append(content[i]) + i += 1 + return ''.join(result) + + +def _strip_preprocessor_guards(content: str) -> str: + lines = content.split('\n') + filtered = [] + for line in lines: + stripped = line.strip() + if stripped.startswith('#ifndef') and '_H' in stripped.upper(): + continue + if stripped.startswith('#define') and '_H' in stripped.upper(): + continue + if stripped == '#endif': + continue + filtered.append(line) + return '\n'.join(filtered) + + +class CHeaderParser: + """C 头文件解析器""" + + def __init__(self): + self.defines: List[Dict] = [] + self.structs: Dict[str, Dict] = {} + self.enums: Dict[str, Dict] = {} + self.typedefs: Dict[str, str] = [] + self.functions: Dict[str, Dict] = {} + self.variables: Dict[str, Dict] = {} + self.unions: Dict[str, Dict] = {} + self.func_ptr_typedefs: Dict[str, Dict] = {} + self._typedef_struct_map: Dict[str, str] = {} + self._typedef_enum_map: Dict[str, str] = {} + self._typedef_union_map: Dict[str, str] = {} + + def ParseFile(self, FilePath: str) -> None: + with open(FilePath, 'r', encoding='utf-8') as f: + content = f.read() + self.ParseContent(content) + + def ParseContent(self, content: str) -> None: + content = _strip_comments(content) + content = _strip_preprocessor_guards(content) + self._ParseDefines(content) + self._ParseTypedefStructs(content) + self._ParseTypedefEnums(content) + self._ParseTypedefUnions(content) + self._ParseFuncPtrTypedefs(content) + self._ParseSimpleTypedefs(content) + self._ParseStandaloneStructs(content) + self._ParseStandaloneEnums(content) + self._ParseStandaloneUnions(content) + stripped = self._StripBodies(content) + self._ParseFunctions(stripped) + self._ParseVariables(stripped) + + def _StripBodies(self, content: str) -> str: + result = content + while True: + pos = result.find('{') + if pos < 0: + break + end = _find_matching_brace(result, pos) + if end < 0: + break + result = result[:pos] + result[end + 1:] + return result + + def _ParseDefines(self, content: str) -> None: + for match in re.finditer(r'#define\s+(\w+)(?:\s+(.+?))?\s*$', content, re.MULTILINE): + Name = match.group(1) + Value = match.group(2) + if Name.startswith('_') and Name.endswith('_'): + continue + if Name.startswith('__'): + continue + self.defines.append({ + 'name': Name, + 'value': Value.strip() if Value else None, + }) + + def _ParseTypedefStructs(self, content: str) -> None: + pattern = r'typedef\s+struct\s*(\w*)\s*\{' + for match in re.finditer(pattern, content): + brace_start = content.index('{', match.start()) + brace_end = _find_matching_brace(content, brace_start) + if brace_end < 0: + continue + body = content[brace_start + 1:brace_end] + rest = content[brace_end + 1:].lstrip() + AliasMatch = re.match(r'(\w+)\s*;', rest) + if not AliasMatch: + continue + AliasName = AliasMatch.group(1) + TagName = match.group(1) if match.group(1) else None + members = self._ParseStructMembers(body) + self.structs[AliasName] = { + 'name': AliasName, + 'tag': TagName, + 'members': members, + } + if TagName: + self._typedef_struct_map[TagName] = AliasName + + def _ParseTypedefEnums(self, content: str) -> None: + pattern = r'typedef\s+enum\s*(\w*)\s*\{' + for match in re.finditer(pattern, content): + brace_start = content.index('{', match.start()) + brace_end = _find_matching_brace(content, brace_start) + if brace_end < 0: + continue + body = content[brace_start + 1:brace_end] + rest = content[brace_end + 1:].lstrip() + AliasMatch = re.match(r'(\w+)\s*;', rest) + if not AliasMatch: + continue + AliasName = AliasMatch.group(1) + TagName = match.group(1) if match.group(1) else None + values = self._ParseEnumValues(body) + self.enums[AliasName] = { + 'name': AliasName, + 'tag': TagName, + 'values': values, + } + if TagName: + self._typedef_enum_map[TagName] = AliasName + + def _ParseTypedefUnions(self, content: str) -> None: + pattern = r'typedef\s+union\s*(\w*)\s*\{' + for match in re.finditer(pattern, content): + brace_start = content.index('{', match.start()) + brace_end = _find_matching_brace(content, brace_start) + if brace_end < 0: + continue + body = content[brace_start + 1:brace_end] + rest = content[brace_end + 1:].lstrip() + AliasMatch = re.match(r'(\w+)\s*;', rest) + if not AliasMatch: + continue + AliasName = AliasMatch.group(1) + TagName = match.group(1) if match.group(1) else None + members = self._ParseStructMembers(body) + self.unions[AliasName] = { + 'name': AliasName, + 'tag': TagName, + 'members': members, + } + if TagName: + self._typedef_union_map[TagName] = AliasName + + def _ParseFuncPtrTypedefs(self, content: str) -> None: + pattern = r'typedef\s+([\w\s\*]+?)\s*\(\s*\*\s*(\w+)\s*\)\s*\(([^)]*)\)\s*;' + for match in re.finditer(pattern, content): + ReturnType = match.group(1).strip() + Name = match.group(2) + ParamsStr = match.group(3).strip() + params = self._ParseFuncParams(ParamsStr) + self.func_ptr_typedefs[Name] = { + 'name': Name, + 'return_type': ReturnType, + 'params': params, + } + + def _ParseSimpleTypedefs(self, content: str) -> None: + stripped = self._StripBodies(content) + pattern = r'typedef\s+([\w\s\*]+?)\s+(\w+)\s*;' + for match in re.finditer(pattern, stripped): + BaseType = match.group(1).strip() + AliasName = match.group(2) + if AliasName in self.structs: + continue + if AliasName in self.enums: + continue + if AliasName in self.unions: + continue + if AliasName in self.func_ptr_typedefs: + continue + if BaseType.startswith('typedef'): + continue + self.typedefs.append({'name': AliasName, 'base': BaseType}) + + def _ParseStandaloneStructs(self, content: str) -> None: + pattern = r'(? None: + pattern = r'(? None: + pattern = r'(? None: + pattern = r'(?:(?:static|extern|inline)\s+)*([\w][\w\s\*]*?)\b(\w+)\s*\(([^)]*)\)\s*;' + for match in re.finditer(pattern, content): + ReturnType = match.group(1).strip() + FuncName = match.group(2) + ParamsStr = match.group(3).strip() + if FuncName in self.structs or FuncName in self.enums or FuncName in self.unions: + continue + if FuncName in self.func_ptr_typedefs: + continue + if FuncName in self.defines: + continue + if ReturnType in ('struct', 'union', 'enum', 'typedef'): + continue + if re.match(r'^\d', ReturnType): + continue + if not re.match(r'^[A-Za-z_]', FuncName): + continue + params = self._ParseFuncParams(ParamsStr) + self.functions[FuncName] = { + 'name': FuncName, + 'return_type': ReturnType, + 'params': params, + } + + def _ParseVariables(self, content: str) -> None: + pattern = r'(?:(?:static|extern|volatile|const)\s+)*([\w][\w\s\*]*?)\s+(\w+)\s*(?:\[(\d*)\])?\s*;' + for match in re.finditer(pattern, content): + TypeStr = match.group(1).strip() + VarName = match.group(2) + ArraySize = match.group(3) + if VarName in self.functions or VarName in self.structs or VarName in self.enums: + continue + if VarName in self.unions or VarName in self.func_ptr_typedefs: + continue + if VarName in self.defines: + continue + if TypeStr.startswith('typedef'): + continue + if TypeStr in ('struct', 'union', 'enum', 'typedef'): + continue + if re.match(r'^(if|else|while|for|return|switch|case|break|continue|do|goto)$', VarName): + continue + if not re.match(r'^[A-Za-z_]', VarName): + continue + IsPtr = '*' in TypeStr + IsArray = ArraySize is not None + self.variables[VarName] = { + 'name': VarName, + 'type': TypeStr, + 'is_ptr': IsPtr, + 'is_array': IsArray, + 'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None, + } + + def _ParseStructMembers(self, body: str) -> List[Dict]: + members = [] + for line in body.split(';'): + line = line.strip() + if not line: + continue + arr_match = re.match(r'([\w\s\*]+?)\s+(\w+)\s*\[(\d*)\]', line) + if arr_match: + MemberType = arr_match.group(1).strip() + MemberName = arr_match.group(2) + ArraySize = arr_match.group(3) + members.append({ + 'name': MemberName, + 'type': MemberType, + 'is_array': True, + 'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None, + }) + continue + ptr_match = re.match(r'([\w\s\*]+?)\s*\*\s*(\w+)', line) + if ptr_match: + MemberType = ptr_match.group(1).strip() + ' *' + MemberName = ptr_match.group(2) + members.append({ + 'name': MemberName, + 'type': MemberType, + 'is_ptr': True, + }) + continue + simple_match = re.match(r'([\w\s]+?)\s+(\w+)', line) + if simple_match: + MemberType = simple_match.group(1).strip() + MemberName = simple_match.group(2) + members.append({ + 'name': MemberName, + 'type': MemberType, + }) + return members + + def _ParseEnumValues(self, body: str) -> List[Dict]: + values = [] + for item in body.split(','): + item = item.strip() + if not item: + continue + eq_pos = item.find('=') + if eq_pos >= 0: + Name = item[:eq_pos].strip() + Value = item[eq_pos + 1:].strip() + else: + Name = item.strip() + Value = None + if Name and re.match(r'^[A-Za-z_]\w*$', Name): + values.append({'name': Name, 'value': Value}) + return values + + def _ParseFuncParams(self, params_str: str) -> List[Dict]: + params = [] + if not params_str or params_str.strip() == 'void' or params_str.strip() == '': + return params + for param in params_str.split(','): + param = param.strip() + if not param: + continue + func_ptr_match = re.match(r'([\w\s\*]+?)\s*\(\s*\*\s*(\w*)\s*\)\s*\([^)]*\)', param) + if func_ptr_match: + RetType = func_ptr_match.group(1).strip() + ParamName = func_ptr_match.group(2) or 'callback' + params.append({ + 'name': ParamName, + 'type': RetType + ' (*)', + 'is_func_ptr': True, + }) + continue + arr_match = re.match(r'([\w\s\*]+?)\s+(\w+)\s*\[\d*\]', param) + if arr_match: + ParamType = arr_match.group(1).strip() + ParamName = arr_match.group(2) + params.append({ + 'name': ParamName, + 'type': ParamType, + 'is_array': True, + }) + continue + tokens = param.split() + if len(tokens) >= 2: + LastToken = tokens[-1] + PtrCount = 0 + while LastToken.startswith('*'): + PtrCount += 1 + LastToken = LastToken[1:] + TypeTokens = tokens[:-1] + for _ in range(PtrCount): + TypeTokens.append('*') + ParamName = LastToken + ParamType = ' '.join(TypeTokens) + if not ParamName: + ParamName = 'arg' + ParamType = param + params.append({ + 'name': ParamName, + 'type': ParamType, + }) + elif len(tokens) == 1: + params.append({ + 'name': 'arg', + 'type': tokens[0], + }) + return params + + +class PythonStubGenerator: + """Python 存根文件生成器""" + + def __init__(self, parser: CHeaderParser): + self.parser = parser + self.OutputLines: List[str] = [] + + def generate(self, ModuleName: Optional[str] = None) -> str: + self.OutputLines = [] + self._AddHeader(ModuleName) + self._GenerateImports() + self._GenerateDefines() + self._GenerateFuncPtrTypedefs() + self._GenerateSimpleTypedefs() + self._GenerateStructs() + self._GenerateUnions() + self._GenerateEnums() + self._GenerateVariables() + self._GenerateFunctions() + return '\n'.join(self.OutputLines) + + def _AddHeader(self, ModuleName: Optional[str] = None) -> None: + self.OutputLines.append('"""') + self.OutputLines.append('Auto-generated Python stub file from C header') + if ModuleName: + self.OutputLines.append(f'Module: {ModuleName}') + self.OutputLines.append('"""') + self.OutputLines.append('') + + def _GenerateImports(self) -> None: + self.OutputLines.append('import t') + self.OutputLines.append('import c') + self.OutputLines.append('') + + def _GenerateDefines(self) -> None: + if not self.parser.defines: + return + for define in self.parser.defines: + Name = define['name'] + Value = define['value'] + if Value is not None: + self.OutputLines.append(f'{Name}: t.CDefine = {Value}') + else: + self.OutputLines.append(f'{Name}: t.CDefine') + self.OutputLines.append('') + + def _GenerateFuncPtrTypedefs(self) -> None: + if not self.parser.func_ptr_typedefs: + return + for Name, Info in self.parser.func_ptr_typedefs.items(): + RetType = CTypeMapper.MapType(Info['return_type']) + ParamTypes = [] + for p in Info['params']: + ParamTypes.append(CTypeMapper.MapType(p['type'])) + ParamStr = ', '.join(ParamTypes) if ParamTypes else '' + self.OutputLines.append(f'{Name}: t.CTypedef = t.Callable[[{ParamStr}], {RetType}]') + self.OutputLines.append('') + + def _GenerateSimpleTypedefs(self) -> None: + if not self.parser.typedefs: + return + for td in self.parser.typedefs: + AliasName = td['name'] + BaseType = td['base'] + PyType = CTypeMapper.MapType(BaseType) + self.OutputLines.append(f'{AliasName}: t.CTypedef | {PyType}') + self.OutputLines.append('') + + def _GenerateStructs(self) -> None: + if not self.parser.structs: + return + for StructName, StructInfo in self.parser.structs.items(): + self.OutputLines.append(f'@c.Attribute(t.attr.packed)') + self.OutputLines.append(f'class {StructName}(t.CStruct):') + if StructInfo['members']: + for member in StructInfo['members']: + MemberName = member['name'] + IsPtr = member.get('is_ptr', False) + IsArray = member.get('is_array', False) + ArraySize = member.get('array_size') + PyType = CTypeMapper.MapType(member['type'], IsPtr=IsPtr) + if IsArray and ArraySize is not None: + self.OutputLines.append(f' {MemberName}: list[{PyType}, {ArraySize}]') + elif IsArray: + self.OutputLines.append(f' {MemberName}: {PyType} | t.CArrayPtr') + else: + self.OutputLines.append(f' {MemberName}: {PyType}') + else: + self.OutputLines.append(' pass') + self.OutputLines.append('') + + def _GenerateUnions(self) -> None: + if not self.parser.unions: + return + for UnionName, UnionInfo in self.parser.unions.items(): + self.OutputLines.append(f'@c.Attribute(t.attr.packed)') + self.OutputLines.append(f'class {UnionName}(t.CUnion):') + if UnionInfo['members']: + for member in UnionInfo['members']: + PyType = CTypeMapper.MapType(member['type'], IsPtr=member.get('is_ptr', False)) + self.OutputLines.append(f' {member["name"]}: {PyType}') + else: + self.OutputLines.append(' pass') + self.OutputLines.append('') + + def _GenerateEnums(self) -> None: + if not self.parser.enums: + return + for EnumName, EnumInfo in self.parser.enums.items(): + self.OutputLines.append(f'class __{EnumName.lower()}(t.CEnum):') + if EnumInfo['values']: + for value in EnumInfo['values']: + if value['value'] is not None: + self.OutputLines.append(f' {value["name"]}: t.CDefine = {value["value"]}') + else: + self.OutputLines.append(f' {value["name"]}: t.CDefine') + else: + self.OutputLines.append(' pass') + self.OutputLines.append(f'{EnumName}: t.CTypedef = __{EnumName.lower()}') + self.OutputLines.append('') + + def _GenerateVariables(self) -> None: + if not self.parser.variables: + return + for VarName, VarInfo in self.parser.variables.items(): + PyType = CTypeMapper.MapType(VarInfo['type'], IsPtr=VarInfo['is_ptr'], IsArray=VarInfo['is_array']) + self.OutputLines.append(f'{VarName}: {PyType}') + self.OutputLines.append('') + + def _GenerateFunctions(self) -> None: + if not self.parser.functions: + return + for FuncName, FuncInfo in self.parser.functions.items(): + params = [] + for param in FuncInfo['params']: + if param.get('is_func_ptr'): + PyType = CTypeMapper.MapType(param['type']) + elif param.get('is_array'): + PyType = CTypeMapper.MapType(param['type'], IsPtr=True) + else: + PyType = CTypeMapper.MapType(param['type']) + params.append(f'{param["name"]}: {PyType}') + ParamStr = ', '.join(params) if params else '' + ReturnType = CTypeMapper.MapType(FuncInfo['return_type']) + self.OutputLines.append(f'def {FuncName}({ParamStr}) -> {ReturnType}: pass') + self.OutputLines.append('') + + +def GenerateStubFromC(InputFile: str, OutputFile: Optional[str] = None) -> str: + parser = CHeaderParser() + parser.ParseFile(InputFile) + generator = PythonStubGenerator(parser) + ModuleName = os.path.splitext(os.path.basename(InputFile))[0] + content = generator.generate(ModuleName) + if OutputFile: + with open(OutputFile, 'w', encoding='utf-8') as f: + f.write(content) + print(f"Generated: {OutputFile}") + return content + + +if __name__ == '__main__': + import sys + if len(sys.argv) >= 3: + GenerateStubFromC(sys.argv[1], sys.argv[2]) + elif len(sys.argv) == 2: + print(GenerateStubFromC(sys.argv[1])) + else: + test_code = ''' +struct memory_block { + uint64_t size; + uint8_t state; + uint8_t order; + struct memory_block *next; + struct memory_block *prev; +}; + +typedef struct memory_block memory_block_t; + +enum color_format { + COLOR_FORMAT_BGRA, + COLOR_FORMAT_RGBA, + COLOR_FORMAT_BGR, + COLOR_FORMAT_RGB +}; + +void *malloc(size_t size); +void free(void *ptr); +void *memcpy(void *dest, const void *src, size_t n); +''' + parser = CHeaderParser() + parser.ParseContent(test_code) + generator = PythonStubGenerator(parser) + print(generator.generate("test_header")) diff --git a/lib/core/translator.py b/lib/core/translator.py new file mode 100644 index 0000000..55b2455 --- /dev/null +++ b/lib/core/translator.py @@ -0,0 +1,1726 @@ +# 核心转换逻辑 +import ast +import sys +import os +import llvmlite.ir as ir +sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'lib', 'includes')) +from ..includes import c +from ..includes import t +from typing import Dict +from lib.utils.helpers import ( + DetectFileType +) +from lib.core.Handles import ( + IfHandle, ForHandle, WhileHandle, + AnnAssignHandle, + HandlesTypeMerge, ExprHandle, BodyHandle, + ReturnHandle, AssignHandle, AugAssignHandle, DeleteHandle, + WithHandle, TryHandle, AssertHandle, RaiseHandle, MatchHandle, + ExprUtils, ExprOpsHandle, ExprAttrHandle, ExprBuiltinHandle, + ExprAsmHandle, ExprFormatHandle, ExprLambdaHandle, ExprCallHandle, + CSpecialCallHandle, TSpecialCallHandle, + ClassHandle, + FunctionHandle, + ImportHandle +) +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.core.SymbolTable import SymbolTable +from lib.core.SymbolNode import SymbolNode +from lib.constants.config import mode as _config_mode +from lib.core.LlvmCodeGenerator import LlvmCodeGenerator + + +def _strict_log(logger, msg): + """在 strict 模式下记录异常日志""" + if _config_mode == "strict": + logger(msg) + + +class Translator: + """代码转换器""" + + def __init__(self): + self.VarScopes = [{}] # 跟踪变量作用域,第一个是全局作用域 + self.FunctionReturnTypes: Dict[str, CTypeInfo] = {} # 记录函数名和其返回类型 + self.CurrentCReturnTypes: list = None # 当前函数的 CReturn 类型列表 + self._CurrentCpythonObjectClass: str = None # 当前正在处理的 CPython 对象类名 + self.FunctionDefCache: dict = {} # 函数定义缓存 + self.OriginalLines = [] # 原始代码行 + self.Content = '' + self.DebugFile = None # 调试输出文件路径 + self.IsHeader = False # 是否生成头文件(仅处理定义、宏、导入等,忽略函数体) + self.AnnotationModules = set() # 注解模块集合,用于识别类型定义模块 + self.Warnings = [] # 警告日志 + self._error_stack = [] # 错误栈,按顺序收集错误位置 + self.Errors = [] # 错误日志 + self.SliceCount = 0 # 切片计数 + self.SliceInfos = [] # 切片信息列表 + self.SliceLevel = 3 # 切片优化级别 + self.GeneratedTypes = set() # 在当前代码中生成的类型(struct/typedef) + self.EmbeddedAssignments = {} # {ClassName: [var1, var2, ...]} 嵌入的实例化变量 + self.TypedefAssignments = {} # {ClassName: [(var1, IsPtr), ...]} 嵌入的 typedef/指针变量 + self.ChainAssignmentArrays = [] # 链式赋值数组形式 [(ClassName, VarName, ArraySize_node), ...] + self.tree = None # 保存解析后的 AST 树 + self.LibraryPaths = ['.'] # 库搜索路径列表,默认包含当前目录 + self.InClass = False # 是否正在处理 class 定义 + self._UserTypeModules = {} + self._source_module_sig_files = {} + self._global_function_default_args: dict = {} + self.exception_registry: dict = {} + self.exception_parents: dict = {} + self._next_exception_code: int = 100 + + # 导出表 + from lib.core.export_table import ExportTable + self.ExportTable = ExportTable(filename='') + + self.SymbolTable = SymbolTable(self) + self.IfHandler = IfHandle(self) + self.ForHandler = ForHandle(self) + self.WhileHandler = WhileHandle(self) + self.AnnAssignHandler = AnnAssignHandle(self) + self.TypeMergeHandler = HandlesTypeMerge(self) + self.ExprHandler = ExprHandle(self) + self.ExprUtils = ExprUtils(self) + self.ExprOpsHandle = ExprOpsHandle(self) + self.ExprAttrHandle = ExprAttrHandle(self) + self.ExprBuiltinHandle = ExprBuiltinHandle(self) + self.ExprAsmHandle = ExprAsmHandle(self) + self.ExprFormatHandle = ExprFormatHandle(self) + self.ExprLambdaHandle = ExprLambdaHandle(self) + self.ExprCallHandle = ExprCallHandle(self) + self.CSpecialCallHandle = CSpecialCallHandle(self) + self.TSpecialCallHandle = TSpecialCallHandle(self) + self.ClassHandler = ClassHandle(self) + self.FunctionHandler = FunctionHandle(self) + self.ImportHandler = ImportHandle(self) + self.BodyHandler = BodyHandle(self) + self.ReturnHandler = ReturnHandle(self) + self.AssignHandler = AssignHandle(self) + self.AugAssignHandler = AugAssignHandle(self) + self.DeleteHandler = DeleteHandle(self) + self.WithHandler = WithHandle(self) + self.TryHandler = TryHandle(self) + self.AssertHandler = AssertHandle(self) + self.RaiseHandler = RaiseHandle(self) + self.MatchHandler = MatchHandle(self) + + def LogWarning(self, message: str, LineNum: int = None): + """记录警告 + + Args: + message: 警告消息 + LineNum: 行号(可选) + """ + warning = f"Warning: {message}" + if LineNum is not None: + warning += f" (line {LineNum})" + self.Warnings.append(warning) + + def LogError(self, message: str, LineNum: int = None): + """记录错误 + + Args: + message: 错误消息 + LineNum: 行号 + """ + print(f"[ERROR] {message}") + entry = {'message': message, 'line': LineNum} + self.Errors.append(entry) + + # 检查 config 中是否有 debug 文件 + DebugFile = None + if hasattr(self, 'config') and self.config: + DebugFile = getattr(self.config, 'debug', None) + + if DebugFile: + with open(DebugFile, 'a', encoding='utf-8') as f: + line_info = f' line {LineNum}' if LineNum else '' + f.write(f'[ERROR]{line_info}: {message}\n') + + def _LoadAnnotationModule(self, ModuleName: str, library_name: str = None, parse_method: str = 'auto'): + """加载注解模块并将 CType 子类注册为 typedef + + 支持两种模式: + 1. AST 模式:如果 ModuleName 是文件路径,解析文件提取 CType + 2. importlib 模式:如果 ModuleName 是模块名,导入模块提取 CType + + Args: + ModuleName: 模块名或文件路径 + library_name: 手动指定的库名称,用于注册到符号表。如果为 None,则从 ModuleName 推断 + parse_method: 解析方法,可选值: + - 'auto': 自动检测(默认) + - 'file': 强制使用 AST 模式(文件路径) + - 'module': 强制使用 importlib 模式(模块名) + """ + import importlib + import importlib.util + import sys + import os + + CurrentDir = os.path.dirname(os.path.abspath(__file__)) + ProjectRoot = os.path.dirname(os.path.dirname(os.path.dirname(CurrentDir))) + if ProjectRoot not in sys.path: + sys.path.insert(0, ProjectRoot) + + def register_to_symboltable(module, lib_name: str = None, source_file: str = None): + """将模块中的 CType 子类和 CEnum 类注册到符号表""" + from lib.includes.t import CType, CEnum + count = 0 + for AttrName in dir(module): + attr = getattr(module, AttrName) + # 优先检查是否是 CEnum 子类(枚举) + if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum: + # 注册枚举类型 + EnumNode = SymbolNode.CreateClass( + name=AttrName, + TypeKind='enum', + lineno=0 + ) + EnumNode.set('enum_class', attr) + EnumNode.set('source', 'annotation_module') + EnumNode.set('library_name', lib_name) + EnumNode.set('file', source_file) + self.SymbolTable[AttrName] = EnumNode.attributes + if lib_name: + FullName = f'{lib_name}.{AttrName}' + full_EnumNode = SymbolNode.CreateClass( + name=FullName, + TypeKind='enum', + lineno=0 + ) + full_EnumNode.set('enum_class', attr) + full_EnumNode.set('source', 'annotation_module') + full_EnumNode.set('library_name', lib_name) + full_EnumNode.set('file', source_file) + self.SymbolTable[FullName] = full_EnumNode.attributes + # 枚举成员也需要注册 + for MemberName in dir(attr): + if not MemberName.startswith('_'): + member = getattr(attr, MemberName, None) + if isinstance(member, int): + MemberNode = CTypeInfo() + MemberNode.Name = MemberName + MemberNode.BaseType = t.CEnum(AttrName) + MemberNode.value = member + MemberNode.EnumName = AttrName + MemberNode.library_name = lib_name + MemberNode.IsEnumMember = True + self.SymbolTable[MemberName] = MemberNode + self.SymbolTable[f"{AttrName}.{MemberName}"] = MemberNode + self.SymbolTable[f"{AttrName}_{MemberName}"] = MemberNode + if lib_name: + self.SymbolTable[f"{lib_name}.{AttrName}.{MemberName}"] = MemberNode + self.SymbolTable[f"{lib_name}_{AttrName}_{MemberName}"] = MemberNode + count += 1 + # 检查是否是 CType 子类(typedef 别名) + elif isinstance(attr, type) and issubclass(attr, CType) and attr is not CType: + # 继承 CType 的类是类型别名(typedef),不是结构体 + # 使用手动指定的库名称作为前缀 + if lib_name: + FullName = f'{lib_name}.{AttrName}' + else: + FullName = AttrName + # 同时注册带前缀和不带前缀的名称(都是 typedef 别名) + TypedefNode = SymbolNode.CreateClass( + name=AttrName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', attr().CName) + TypedefNode.set('source', 'annotation_module') + TypedefNode.set('library_name', lib_name) + TypedefNode.set('file', source_file) + self.SymbolTable[AttrName] = TypedefNode.attributes + if lib_name and FullName != AttrName: + FullTypedef_node = SymbolNode.CreateClass( + name=FullName, + TypeKind='typedef', + lineno=0 + ) + FullTypedef_node.set('OriginalType', attr().CName) + FullTypedef_node.set('source', 'annotation_module') + FullTypedef_node.set('library_name', lib_name) + FullTypedef_node.set('file', source_file) + self.SymbolTable[FullName] = FullTypedef_node.attributes + count += 1 + # 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef) + elif AttrName.startswith('_') and len(AttrName) > 1: + PublicName = AttrName[1:] + PublicAttr = getattr(module, PublicName, None) + if PublicAttr is not None and not isinstance(attr, type): + continue + if isinstance(attr, type) and issubclass(attr, CType) and attr is not CType: + if PublicName not in self.SymbolTable: + if lib_name: + FullName = f'{lib_name}.{PublicName}' + else: + FullName = PublicName + TypedefNode = SymbolNode.CreateClass( + name=PublicName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', attr().CName) + TypedefNode.set('source', 'annotation_module') + TypedefNode.set('library_name', lib_name) + TypedefNode.set('file', source_file) + self.SymbolTable[PublicName] = TypedefNode.attributes + if lib_name and FullName != PublicName: + FullTypedef_node = SymbolNode.CreateClass( + name=FullName, + TypeKind='typedef', + lineno=0 + ) + FullTypedef_node.set('OriginalType', attr().CName) + FullTypedef_node.set('source', 'annotation_module') + FullTypedef_node.set('library_name', lib_name) + FullTypedef_node.set('file', source_file) + self.SymbolTable[FullName] = FullTypedef_node.attributes + count += 1 + return count + + # 确定解析方法 + use_file_mode = False + if parse_method == 'file': + use_file_mode = True + elif parse_method == 'module': + use_file_mode = False + else: # auto + use_file_mode = os.path.isfile(ModuleName) + + # 确定库名称 + lib_name = library_name + if lib_name is None: + if use_file_mode: + # 从文件路径推断库名称 + lib_name = os.path.splitext(os.path.basename(ModuleName))[0] + else: + # 模块名就是库名称 + lib_name = ModuleName + + # 根据解析方法加载模块 + if use_file_mode: + # AST 模式:使用 AST 解析文件,不执行代码 + try: + # 临时保存当前的 EmbeddedAssignments 和 TypedefAssignments + saved_embedded = self.EmbeddedAssignments.copy() + saved_typedef = self.TypedefAssignments.copy() + + # 清空 PD 收集(注解文件不应该收集 PD 语句) + self.EmbeddedAssignments = {} + self.TypedefAssignments = {} + + # 直接调用 ParsePythonFile 解析文件提取类型信息 + # 注意:这不会执行任何 Python 代码,只是解析 AST + # UpdateCurrentFile=False 表示不修改 CurrentFile + self.ParsePythonFile(ModuleName, UpdateCurrentFile=False) + + # 恢复主代码文件的 PD 收集 + self.EmbeddedAssignments = saved_embedded + self.TypedefAssignments = saved_typedef + + # 从文件名推断类型前缀(如 test_t -> test_t.xxx) + TypePrefix = lib_name + count = 0 + + # 检查符号表中新增的类型(注解文件解析后的所有 struct 类型) + # 需要检查这些类型是否继承自 CType,如果是则是 typedef 别名 + new_types = [] + for TypeName, TypeInfo in self.SymbolTable.items(): + if TypeInfo.IsStruct: + new_types.append(TypeName) + + # 再次遍历 AST,检测继承自 CType 的类 + try: + with open(ModuleName, 'r', encoding='utf-8') as f: + ann_content = f.read() + ann_tree = ast.parse(ann_content) + for node in ann_tree.body: + if isinstance(node, ast.ClassDef): + ClassName = node.name + # 检查是否有基类 + for base in node.bases: + if isinstance(base, ast.Name) and base.id == 'CType': + # 这个类继承自 CType,是 typedef 别名 + # 更新符号表中的类型为 typedef + if ClassName in self.SymbolTable: + TypedefNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')) + TypedefNode.set('source', 'annotation_module') + TypedefNode.set('is_ctype_subclass', True) + self.SymbolTable[ClassName] = TypedefNode.attributes + except Exception as e: + pass # 忽略解析错误 + + # 为所有新增的类型添加库前缀和 source 标记 + for TypeName in new_types: + # 添加带前缀的类型名 + FullName = f'{TypePrefix}.{TypeName}' + TypeInfo = self.SymbolTable[TypeName].copy() + TypeInfo['source'] = 'annotation_module' + TypeInfo['original_name'] = TypeName + self.SymbolTable[FullName] = TypeInfo + count += 1 + + # 再次遍历 AST,查找注解文件中的 typedef 语句(AnnAssign with t.CTypedef) + # 注意:必须在类定义处理完之后再处理 typedef + typedef_annots = [] + # 查找 CEnum 成员变量(AnnAssign with t.CEnum | t.State 或 t.CEnum) + cEnumMembers = [] + try: + with open(ModuleName, 'r', encoding='utf-8') as f: + ann_content = f.read() + ann_tree = ast.parse(ann_content) + for node in ann_tree.body: + # 检测 xxx: t.CEnum 形式的枚举成员变量 + if isinstance(node, ast.AnnAssign): + if isinstance(node.target, ast.Name) and node.annotation: + TargetName = node.target.id + # 检查注解是否是 BinOp (Union) 或直接是 Attribute + IsCenum = False + if isinstance(node.annotation, ast.BinOp): + # 检查是否包含 CEnum + annot_str = ast.dump(node.annotation) + if 'CEnum' in annot_str: + IsCenum = True + elif isinstance(node.annotation, ast.Attribute): + # 直接是 t.CEnum + if node.annotation.attr == t.CEnum.__name__: + IsCenum = True + + if IsCenum: + # 检查值是否是 Constant (枚举成员值) + if node.value and isinstance(node.value, ast.Constant): + value = node.value.value + else: + value = None + cEnumMembers.append((TargetName, value)) + except Exception as e: + pass # 忽略解析错误 + + # 处理 CEnum 成员变量 + for TargetName, value in cEnumMembers: + # 注册枚举成员 + MemberNode = CTypeInfo() + MemberNode.Name = TargetName + MemberNode.BaseType = t.CEnum(TypePrefix) + MemberNode.value = value + MemberNode.EnumName = TypePrefix + MemberNode.library_name = TypePrefix + MemberNode.IsEnumMember = True + self.SymbolTable[TargetName] = MemberNode + self.SymbolTable[f"{TypePrefix}.{TargetName}"] = MemberNode + self.SymbolTable[f"{TypePrefix}_{TargetName}"] = MemberNode + + try: + with open(ModuleName, 'r', encoding='utf-8') as f: + ann_content = f.read() + ann_tree = ast.parse(ann_content) + for node in ann_tree.body: + # 检测 xxx: t.CTypedef = xxx 形式的 typedef 语句 + if isinstance(node, ast.AnnAssign): + if isinstance(node.target, ast.Name) and node.annotation and node.value: + TargetName = node.target.id + # 检查注解是否是 t.CTypedef + if isinstance(node.annotation, ast.Attribute): + if isinstance(node.annotation.value, ast.Name): + if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef': + # 检查值是否是 Name + if isinstance(node.value, ast.Name): + original_name = node.value.id + typedef_annots.append((TargetName, original_name)) + except Exception as e: + pass # 忽略解析错误 + + # 处理 typedef 注解 + for TargetName, original_name in typedef_annots: + # 检查原始类型是否在符号表中(带前缀或不带前缀) + orig_with_prefix = f'{TypePrefix}.{original_name}' + if orig_with_prefix in self.SymbolTable: + # 添加带前缀的 typedef 别名 + FullTypedef_name = f'{TypePrefix}.{TargetName}' + TypedefNode = SymbolNode.CreateClass( + name=FullTypedef_name, + TypeKind='typedef', + lineno=0 + ) + orig_entry = self.SymbolTable.get(orig_with_prefix, {}) + orig_type_str = f'struct {original_name}' + if isinstance(orig_entry, dict): + if orig_entry.get('type') == 'typedef': + orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}') + elif orig_entry.get('type') == 'enum': + orig_type_str = f'enum {original_name}' + elif hasattr(orig_entry, 'IsTypedef') and orig_entry.IsTypedef: + orig_type_str = getattr(orig_entry, 'OriginalType', f'struct {original_name}') + elif hasattr(orig_entry, 'IsEnum') and orig_entry.IsEnum: + orig_type_str = f'enum {original_name}' + TypedefNode.set('OriginalType', orig_type_str) + TypedefNode.set('source', 'annotation_module') + TypedefNode.set('original_name', TargetName) + self.SymbolTable[FullTypedef_name] = TypedefNode.attributes + count += 1 + + self.AnnotationModules.add(lib_name) + return count + except Exception as e: + # 恢复 PD 收集 + self.EmbeddedAssignments = saved_embedded + self.TypedefAssignments = saved_typedef + self.LogWarning(f"AST模式加载注解模块失败: {ModuleName}, 错误: {e}") + return 0 + else: + # importlib 模式:导入模块 + try: + module = importlib.import_module(ModuleName) + count = register_to_symboltable(module, lib_name, None) + self.AnnotationModules.add(lib_name) + return count + except ImportError: + self.LogWarning(f"importlib模式加载注解模块失败: {ModuleName}") + return 0 + except Exception as e: + self.LogWarning(f"加载注解模块失败: {ModuleName}, 错误: {e}") + return 0 + + def _LoadAnnotationFiles(self, FilePaths: list): + """加载多个注解文件并注册到符号表 + + Args: + FilePaths: 文件路径列表,每个元素可以是: + - str: 文件路径或模块名 + - tuple: (path, options) 或 (path, library_name, parse_method) + """ + for item in FilePaths: + if isinstance(item, tuple): + if len(item) >= 3: + path, library_name, parse_method = item[:3] + count = self._LoadAnnotationModule(path, library_name, parse_method) + elif len(item) == 2: + path, library_name = item + count = self._LoadAnnotationModule(path, library_name, 'auto') + else: + count = self._LoadAnnotationModule(item) + else: + count = self._LoadAnnotationModule(item) + + # 别名,保持向后兼容 + LoadAnnotationFiles = _LoadAnnotationFiles + + def SetDebugFile(self, FilePath): + """设置调试输出文件""" + self.DebugFile = FilePath + + def DebugPrint(self, *args, **kwargs): + """输出调试信息到文件""" + if self.DebugFile: + with open(self.DebugFile, 'a', encoding='utf-8') as f: + print(*args, file=f, **kwargs) + + def ParseHelperFiles(self, HelperFiles, encoding='utf-8'): + """解析辅助文件,提取符号信息 + + 支持 .py, .c, .h 和 .symbin 文件 + """ + for FilePath in HelperFiles: + ext = DetectFileType(FilePath) + if ext == '.py': + self.ParsePythonFile(FilePath, encoding, UpdateCurrentFile=False) + elif ext == '.c': + pass # .c 文件解析已移除,不再使用旧的正则解析路径 + elif FilePath.endswith('.symbin'): + self.LoadSymbinFile(FilePath) + + def LoadSymbinFile(self, FilePath): + """从.symbin文件加载符号表 + + Args: + FilePath: .symbin文件路径 + """ + try: + with open(FilePath, 'rb') as f: + data = f.read() + + # 导入序列化函数(避免循环导入) + import sys + import os + import json + import struct + + # 解析二进制格式 + if len(data) < 4: + print(f"Warning: Invalid symbin file (too short): {FilePath}") + return + + # 解析4字节长度头(小端序) + length = struct.unpack(' 1: + # 第二个参数应该是一个列表 + dim_arg = PostdefNode.args[1] + if isinstance(dim_arg, ast.List): + for DimExpr in dim_arg.elts: + dimensions.append(DimExpr) + + # 如果没有从 Postdefinition 参数中获取维度,尝试从类型注解中的 Subscript 获取 + # 例如:memory_block_t[MAX_ORDER + 1] | t.CPtr + if not dimensions: + def extract_subscript_dims(node): + """递归提取 Subscript 节点的维度""" + dims = [] + if isinstance(node, ast.Subscript): + # 提取当前维度 + if isinstance(node.slice, ast.Constant): + dims.append(ast.Constant(value=node.slice.value)) + elif isinstance(node.slice, ast.Name): + dims.append(ast.Name(id=node.slice.id, ctx=ast.Load())) + elif isinstance(node.slice, ast.BinOp): + dims.append(node.slice) + # 递归提取更外层的维度 + dims.extend(extract_subscript_dims(node.value)) + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + # 处理 Type | t.CPtr 的情况,检查左侧 + dims.extend(extract_subscript_dims(node.left)) + return dims + + # 从注解中提取维度 + subscript_dims = extract_subscript_dims(annotation) + if subscript_dims: + # 反转维度顺序(从内到外) + dimensions = list(reversed(subscript_dims)) + + # 获取赋值值 + value = None + if hasattr(NextNode, 'value') and NextNode.value is not None: + value = NextNode.value + + # 添加到对应的 assignments + # 对于 t.Postdefinition(...),只有包含 CTypedef 或 CPtr 时才视为 typedef 类型 + if HasCtypedef or IsPtr: + if ClassKey not in self.TypedefAssignments: + self.TypedefAssignments[ClassKey] = [] + # 如果有维度信息,使用字典存储 + if dimensions: + self.TypedefAssignments[ClassKey].append({ + 'name': TargetName, + 'IsPtr': IsPtr, + 'dimensions': dimensions, + 'value': value + }) + else: + self.TypedefAssignments[ClassKey].append((TargetName, IsPtr)) + else: + if ClassKey not in self.EmbeddedAssignments: + self.EmbeddedAssignments[ClassKey] = [] + # 如果有维度信息,使用字典存储 + if dimensions: + self.EmbeddedAssignments[ClassKey].append({ + 'name': TargetName, + 'dimensions': dimensions, + 'value': value + }) + else: + self.EmbeddedAssignments[ClassKey].append(TargetName) + + # 检查是否有 __set_default__ 初始化 + if '__set_default__' in original_AnnotationStr: + self._handle_set_default_in_parse(ClassKey, TargetName, ClassName, NextNode) + j += 1 + continue + # 再处理旧格式:xxx: t.CTypedef = xxx 或 xxx: t.CPtr = xxx + # 注意:这种格式的 typedef 不应该被合并到结构体定义中, + # 而应该生成独立的 typedef 语句,所以不添加到 TypedefAssignments + elif NextNode.annotation and isinstance(NextNode.annotation, ast.Attribute): + if isinstance(NextNode.annotation.value, ast.Name): + annot_id = NextNode.annotation.value.id + annot_attr = NextNode.annotation.attr + if annot_id == 't' and NextNode.value: + if isinstance(NextNode.value, ast.Name): + ValueName = NextNode.value.id + if ValueName == ClassName: + # 检查是 CTypedef 还是 CPtr + if annot_attr == t.CPtr.__name__: + # t.CPtr 表示指针变量,加入 TypedefAssignments,设置 IsPtr=True + if ClassKey not in self.TypedefAssignments: + self.TypedefAssignments[ClassKey] = [] + self.TypedefAssignments[ClassKey].append((TargetName, True)) + j += 1 + continue + # 注意:t.CTypedef 不在这里处理,由 HandlesAnnAssign 生成独立的 typedef 语句 + # 如果不是特殊赋值,停止收集 + break + + i = j + continue + + i += 1 + + # 提取类定义(作为结构体) + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef): + ClassName = node.name + # 先把类名加入 GeneratedTypes,这样 GetTypeName 可以正确识别 + self.GeneratedTypes.add(ClassName) + + # 检测是否是 CEnum + IsCenum = False + for base in node.bases: + if isinstance(base, ast.Attribute): + BaseStr = ast.dump(base) + if 'CEnum' in BaseStr or 'REnum' in BaseStr: + IsCenum = True + break + elif isinstance(base, ast.Name): + if 'CEnum' in base.id or 'REnum' in base.id: + IsCenum = True + break + + # 检测是否有 @t.Object 装饰器或继承自 t.Object + IsCpythonObject = False + if hasattr(node, 'decorator_list') and node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Attribute): + if (hasattr(decorator.value, 'id') and + decorator.value.id == 't' and + decorator.attr == 'Object'): + IsCpythonObject = True + break + elif isinstance(decorator, ast.Call): + if isinstance(decorator.func, ast.Attribute): + if (hasattr(decorator.func.value, 'id') and + decorator.func.value.id == 't' and + decorator.func.attr == 'Object'): + IsCpythonObject = True + break + elif isinstance(decorator.func, ast.Name): + if decorator.func.id == 'Object': + IsCpythonObject = True + break + elif isinstance(decorator, ast.Name): + if decorator.id == 'Object': + IsCpythonObject = True + break + if not IsCpythonObject and hasattr(node, 'bases') and node.bases: + for base in node.bases: + if isinstance(base, ast.Attribute): + if (hasattr(base.value, 'id') and + base.value.id == 't' and + base.attr == 'Object'): + IsCpythonObject = True + break + elif isinstance(base, ast.Name): + if base.id == 'Object': + IsCpythonObject = True + break + + if IsCenum: + # 注册为 enum 类型 + EnumNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='enum', + lineno=0 + ) + EnumNode.set('file', '') + self.SymbolTable[ClassName] = EnumNode.attributes + + # 注册 enum 成员 + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + MemberName = item.target.id + MemberNode = CTypeInfo() + MemberNode.Name = MemberName + MemberNode.BaseType = t.CEnum(ClassName) + MemberNode.value = None + MemberNode.EnumName = ClassName + MemberNode.library_name = None + MemberNode.IsEnumMember = True + self.SymbolTable[MemberName] = MemberNode + self.SymbolTable[f"{ClassName}.{MemberName}"] = MemberNode + self.SymbolTable[f"{ClassName}_{MemberName}"] = MemberNode + + continue + + # 检测是否是 Anonymous + IsAnonymous = False + + # 提取结构体成员信息 + members = {} + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + VarName = item.target.id + try: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + IsPtr = TypeInfo.IsPtr + if not IsPtr: + if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): + LeftStr = ast.dump(item.annotation.left) + RightStr = ast.dump(item.annotation.right) + if 'CPtr' in LeftStr or 'CPtr' in RightStr: + IsPtr = True + dims = [] + if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): + if isinstance(item.annotation.value, ast.Name): + if item.annotation.value.id == 't': + if hasattr(item.annotation, 'slice'): + try: + dims.append(int(item.annotation.slice.value)) + except Exception as _e: + _strict_log(self.LogError, f"解析数组维度失败: {_e}") + pass + MemberInfo = TypeInfo.Copy() + if dims: + MemberInfo.ArrayDims = [str(d) for d in dims] + members[VarName] = MemberInfo + except Exception as _e: + _strict_log(self.LogError, f"解析结构体成员失败: {_e}") + pass + StructNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='struct', + members=members, + lineno=0, + IsCpythonObject=IsCpythonObject + ) + StructNode.set('file', '') + StructNode.set('IsAnonymous', IsAnonymous) + self.SymbolTable[ClassName] = StructNode.attributes + elif isinstance(node, ast.FunctionDef): + FuncName = node.name + FuncNode = SymbolNode.CreateClass( + name=FuncName, + TypeKind='function', + lineno=0 + ) + FuncNode.set('file', '') + self.SymbolTable[FuncName] = FuncNode.attributes + elif isinstance(node, ast.AnnAssign): + if isinstance(node.target, ast.Name): + VarName = node.target.id + # 检查是否是 t.CTypedef 格式,如果是则跳过(由 HandleClassDef 处理) + is_ctypedef = False + if node.annotation: + if isinstance(node.annotation, ast.Attribute): + if isinstance(node.annotation.value, ast.Name): + if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef': + is_ctypedef = True + elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.op, ast.BitOr): + def _has_ctype(ann): + if isinstance(ann, ast.Attribute): + return hasattr(ann.value, 'id') and ann.value.id == 't' and ann.attr == 'CTypedef' + if isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr): + return _has_ctype(ann.left) or _has_ctype(ann.right) + if isinstance(ann, ast.Subscript): + return _has_ctype(ann.value) + return False + if _has_ctype(node.annotation): + is_ctypedef = True + if not is_ctypedef: + IsPtr = False + if node.annotation: + try: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(node.annotation) + IsPtr = TypeInfo.IsPtr if TypeInfo else False + except Exception as _e: + _strict_log(self.LogError, f"获取类型信息失败(ParsePythonFile): {_e}") + pass + var_node = SymbolNode.CreateClass( + name=VarName, + TypeKind='variable', + lineno=0 + ) + var_node.set('IsPtr', IsPtr) + var_node.set('file', '') + self.SymbolTable[VarName] = var_node.attributes + except Exception as e: + print(f'Warning: Failed to parse Python file {FilePath}: {e}') + + # ParseCFile 已移除 - .h/.c 文件的旧正则解析路径不再使用 + # 类型解析现在直接通过 CTypeInfo 对象进行,不经过中间字符串格式 + + def GenerateLlvmDirect(self, Tree): + Gen = self.LlvmGen + + # 预扫描:为所有 -> str 注解的函数注册正确的返回类型 i8* + # 这样在类方法中调用这些函数时,前向声明会使用正确的类型 + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.FunctionDef): + if Node.returns and isinstance(Node.returns, ast.Name) and Node.returns.id == 'str': + Gen.known_return_types[Node.name] = ir.PointerType(ir.IntType(8)) + + # 首先收集所有 CDefine 常量,确保类定义中可以引用 + def _extract_call_const_val(node): + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if getattr(node.func.value, 'id', None) == 't': + if node.args and isinstance(node.args[0], ast.Constant): + return node.args[0].value + elif isinstance(node.func, ast.Name): + if node.args and isinstance(node.args[0], ast.Constant): + return node.args[0].value + return None + + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) + if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define': + val = None + if isinstance(Node.value, ast.Constant): + val = Node.value.value + else: + val = _extract_call_const_val(Node.value) + if val is not None: + if not hasattr(Gen, '_define_constants'): + Gen._define_constants = {} + Gen._define_constants[Node.target.id] = val + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + sym_info = _CTypeInfo() + sym_info.IsDefine = True + sym_info.DefineValue = val + self.SymbolTable[Node.target.id] = sym_info + elif isinstance(Node, ast.Assign): + for target in Node.targets: + if isinstance(target, ast.Name): + TypeInfo = None + if Node.type_comment: + try: + tc_ast = ast.parse(Node.type_comment, mode='eval') + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(tc_ast.body) + except Exception as _e: + _strict_log(self.LogError, f"解析类型注释失败: {_e}") + pass + if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define': + val = None + if isinstance(Node.value, ast.Constant): + val = Node.value.value + else: + val = _extract_call_const_val(Node.value) + if val is not None: + if not hasattr(Gen, '_define_constants'): + Gen._define_constants = {} + Gen._define_constants[target.id] = val + from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo + sym_info = _CTypeInfo() + sym_info.IsDefine = True + sym_info.DefineValue = val + self.SymbolTable[target.id] = sym_info + + # 预扫描所有顶层函数定义,填充 FunctionDefCache(不创建 LLVM 声明) + # 这样类方法编译时遇到未声明的函数可以按需前向声明 + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.FunctionDef): + FuncName = Node.name + if FuncName not in self.FunctionDefCache: + self.FunctionDefCache[FuncName] = Node + + # 首先处理所有导入语句,确保模块在类型解析前被加载 + for Node in ast.iter_child_nodes(Tree): + Gen._set_node_info(Node) + try: + if isinstance(Node, ast.Import): + self.ImportHandler._EmitImportDeclarationsLlvm(Node, Gen) + elif isinstance(Node, ast.ImportFrom): + self.ImportHandler._EmitImportFromDeclarationsLlvm(Node, Gen) + except Exception as e: + lineno = getattr(Node, 'lineno', 0) + source_line = Gen._get_source_line(lineno) + src_file = getattr(Gen, '_current_source_file', '') + src_path = src_file if src_file else 'unknown' + line_info = "源代码 (%s, line %d)" % (src_path, lineno) + if source_line: + line_info += ":\n %d | %s" % (lineno, source_line) + self._error_stack.append((type(e).__name__, str(e), line_info)) + + # 预创建全局变量(带初始化器),确保类方法编译时能引用全局数组等 + Gen._current_tree = Tree + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.AnnAssign): + self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) + elif isinstance(Node, ast.Assign): + self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) + + # 前向声明所有顶层函数,确保类方法编译时能找到这些函数 + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.FunctionDef): + self.FunctionHandler._EmitFunctionForwardDeclLlvm(Node, Gen) + + # 首先处理所有类定义(包括 CUnion),确保类型定义在使用前完成 + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.ClassDef): + self.ClassHandler._EmitClassLlvm(Node, Gen) + + Gen._generate_structs() + Gen._create_Vtable_globals() + + for Node in ast.iter_child_nodes(Tree): + Gen._set_node_info(Node) + try: + if isinstance(Node, ast.Import): + continue + elif isinstance(Node, ast.ImportFrom): + continue + elif isinstance(Node, ast.ClassDef): + continue + elif isinstance(Node, ast.FunctionDef): + self.FunctionHandler._EmitFunctionLlvm(Node, Gen) + elif isinstance(Node, ast.AnnAssign): + self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen) + elif isinstance(Node, ast.Assign): + self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen) + elif isinstance(Node, ast.If): + pass + elif isinstance(Node, ast.Expr): + self._HandleModuleLevelExprLlvm(Node, Gen) + except Exception as e: + lineno = getattr(Node, 'lineno', 0) + source_line = Gen._get_source_line(lineno) + src_file = getattr(Gen, '_current_source_file', '') + src_path = src_file if src_file else 'unknown' + line_info = "源代码 (%s, line %d)" % (src_path, lineno) + if source_line: + line_info += ":\n %d | %s" % (lineno, source_line) + self._error_stack.append((type(e).__name__, str(e), line_info)) + raise + Gen._set_Vtable_initializers() + # 执行 DecoratorPass:为带自定义装饰器的函数生成 wrapper + from lib.core.DecoratorPass import run as _run_decorator_pass + _run_decorator_pass(Gen) + ir_code = Gen.finalize() + return ir_code + + def _HandleModuleLevelExprLlvm(self, Node, Gen): + if not isinstance(Node.value, ast.Call): + return + call = Node.value + if not isinstance(call.func, ast.Attribute): + return + if not isinstance(call.func.value, ast.Name) or call.func.value.id != 'c': + return + func_name = call.func.attr + if func_name == 'LLVMIR': + self._HandleModuleLevelLLVMIR(call, Gen) + + def _HandleModuleLevelLLVMIR(self, Node, Gen): + if not Node.args: + return + first_arg = Node.args[0] + if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): + ir_text = first_arg.value + elif isinstance(first_arg, ast.JoinedStr): + parts = [] + for value in first_arg.values: + if isinstance(value, ast.Constant) and isinstance(value.value, str): + parts.append(value.value) + elif isinstance(value, ast.FormattedValue): + parts.append('') + ir_text = ''.join(parts) + else: + return + self._InsertModuleLevelLLVMIR(Gen, ir_text) + + def _InsertModuleLevelLLVMIR(self, Gen, ir_text): + import re + for line in ir_text.strip().split('\n'): + line = line.strip() + if not line: + continue + module_flags_match = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line) + if module_flags_match: + ref = module_flags_match.group(1) + if not hasattr(Gen, '_pending_module_flags'): + Gen._pending_module_flags = [] + Gen._pending_module_flags_refs = ref + continue + metadata_match = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line) + if metadata_match: + md_id = metadata_match.group(1) + md_body = metadata_match.group(2) + fields = [] + for field_str in re.split(r',\s*', md_body): + field_str = field_str.strip() + if not field_str: + continue + int_m = re.match(r'^i32\s+(\d+)$', field_str) + if int_m: + fields.append(ir.Constant(ir.IntType(32), int(int_m.group(1)))) + continue + str_m = re.match(r'^"([^"]*)"$', field_str) + if str_m: + fields.append(ir.MetaDataString(Gen.module, str_m.group(1))) + continue + mdstr_m = re.match(r'^!"([^"]*)"$', field_str) + if mdstr_m: + fields.append(ir.MetaDataString(Gen.module, mdstr_m.group(1))) + continue + int_m2 = re.match(r'^(\d+)$', field_str) + if int_m2: + fields.append(ir.Constant(ir.IntType(32), int(int_m2.group(1)))) + continue + ref_m = re.match(r'^(!\d+)$', field_str) + if ref_m: + fields.append(ref_m.group(1)) + continue + if fields: + if not hasattr(Gen, '_pending_metadata'): + Gen._pending_metadata = [] + Gen._pending_metadata.append((md_id, fields)) + continue + self._FlushModuleMetadata(Gen) + + def _FlushModuleMetadata(self, Gen): + if not hasattr(Gen, '_pending_metadata') or not Gen._pending_metadata: + return + md_map = {} + for md_id, fields in Gen._pending_metadata: + resolved = [] + for f in fields: + if isinstance(f, str) and f.startswith('!'): + ref = md_map.get(f) + if ref: + resolved.append(ref) + else: + resolved.append(f) + md_value = Gen.module.add_metadata(resolved) + md_map[md_id] = md_value + if hasattr(Gen, '_pending_module_flags_refs'): + ref = Gen._pending_module_flags_refs + md_node = md_map.get(ref) + if md_node: + Gen.module.add_named_metadata('llvm.module.flags', md_node) + Gen._pending_metadata = [] + Gen._pending_module_flags_refs = None + + def _BuildArrayInitConstants(self, value_node, ElemType, elem_type_node, ArrayCount, Gen): + from lib.core.Handles.HandlesAssign import AssignHandle + _zv = AssignHandle._zero_value(ElemType) + _fallback = _zv if _zv is not None else ir.Constant(ElemType, ir.Undefined) + if not isinstance(value_node, (ast.List, ast.Set)): + return None + if isinstance(ElemType, ir.ArrayType): + constants = [] + for elt in value_node.elts: + if isinstance(elt, (ast.List, ast.Set)): + inner_consts = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen) + if inner_consts: + try: + constants.append(ir.Constant(ElemType, inner_consts)) + except Exception: # fallback to _fallback on constant construction failure + constants.append(_fallback) + else: + constants.append(_fallback) + else: + constants.append(_fallback) + while len(constants) < ArrayCount: + constants.append(_fallback) + return constants[:ArrayCount] + StructName = None + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + StructName = elem_type_node.id + constants = [] + for elt in value_node.elts: + if StructName and isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == StructName: + const = self.ClassHandler._BuildStructConstant(elt, StructName, Gen) + if const: + constants.append(const) + else: + constants.append(_fallback) + elif isinstance(elt, ast.Constant): + const = self.ClassHandler._BuildScalarConstant(elt, ElemType) + if const: + constants.append(const) + else: + constants.append(_fallback) + elif isinstance(elt, ast.UnaryOp): + const = self.ClassHandler._BuildScalarConstant(elt, ElemType) + if const: + constants.append(const) + else: + constants.append(_fallback) + elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'chr': + if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, int): + try: + constants.append(ir.Constant(ElemType, elt.args[0].value & 0xFF)) + except Exception: # fallback to _fallback on constant construction failure + constants.append(_fallback) + else: + constants.append(_fallback) + elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'ord': + if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, str) and len(elt.args[0].value) == 1: + try: + constants.append(ir.Constant(ElemType, ord(elt.args[0].value))) + except Exception: # fallback to _fallback on constant construction failure + constants.append(_fallback) + else: + constants.append(_fallback) + else: + const_val = self._try_eval_const_call(elt, Gen) + if const_val is not None: + try: + constants.append(ir.Constant(ElemType, const_val)) + except Exception: # fallback to _fallback on constant construction failure + constants.append(_fallback) + else: + constants.append(_fallback) + while len(constants) < ArrayCount: + constants.append(_fallback) + return constants[:ArrayCount] + + def _try_eval_const_call(self, node, Gen): + import ast + if isinstance(node, ast.Call): + func_name = None + if isinstance(node.func, ast.Name): + func_name = node.func.id + elif isinstance(node.func, ast.Attribute): + func_name = node.func.attr + if func_name: + arg_vals = [] + for arg in node.args: + v = self._try_eval_const_expr(arg, Gen) + if v is None: + return None + arg_vals.append(v) + if func_name == 'COLOR_RGB' and len(arg_vals) == 3: + r, g, b = arg_vals + return (255 << 24) | (int(b) << 16) | (int(g) << 8) | int(r) + if func_name in Gen._define_constants: + return Gen._define_constants[func_name] + for key in Gen.functions: + if key.endswith(f'__{func_name}'): + return None + return None + return self._try_eval_const_expr(node, Gen) + + def _try_eval_const_expr(self, node, Gen): + import ast + if isinstance(node, ast.Constant): + return node.value + elif isinstance(node, ast.BinOp): + left = self._try_eval_const_expr(node.left, Gen) + right = self._try_eval_const_expr(node.right, Gen) + if left is None or right is None: + return None + if isinstance(node.op, ast.Add): + return left + right + elif isinstance(node.op, ast.Sub): + return left - right + elif isinstance(node.op, ast.Mult): + return left * right + elif isinstance(node.op, ast.LShift): + return left << right + elif isinstance(node.op, ast.RShift): + return left >> right + elif isinstance(node.op, ast.BitOr): + return left | right + elif isinstance(node.op, ast.BitAnd): + return left & right + elif isinstance(node.op, ast.BitXor): + return left ^ right + elif isinstance(node, ast.UnaryOp): + operand = self._try_eval_const_expr(node.operand, Gen) + if operand is None: + return None + if isinstance(node.op, ast.USub): + return -operand + elif isinstance(node.op, ast.Invert): + return ~operand + elif isinstance(node, ast.Name): + if node.id in getattr(Gen, '_define_constants', {}): + return Gen._define_constants[node.id] + return None + + def _BuildMultiDimArrayInitConstants(self, value_node, ArrayType, Gen): + from lib.core.Handles.HandlesAssign import AssignHandle + inner_type = ArrayType.element + count = ArrayType.count + elts = list(value_node.elts) if hasattr(value_node, 'elts') else [] + _zv = AssignHandle._zero_value(inner_type) + _fallback = _zv if _zv is not None else ir.Constant(inner_type, ir.Undefined) + constants = [] + for elt in elts: + if isinstance(inner_type, ir.ArrayType): + if isinstance(elt, (ast.List, ast.Set)): + inner_consts = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen) + if inner_consts: + constants.append(ir.Constant(inner_type, inner_consts)) + else: + constants.append(_fallback) + else: + constants.append(_fallback) + elif isinstance(elt, ast.Constant): + const = self.ClassHandler._BuildScalarConstant(elt, inner_type) + if const: + constants.append(const) + else: + constants.append(_fallback) + elif isinstance(elt, ast.UnaryOp): + const = self.ClassHandler._BuildScalarConstant(elt, inner_type) + if const: + constants.append(const) + else: + constants.append(_fallback) + else: + constants.append(_fallback) + while len(constants) < count: + constants.append(_fallback) + return constants[:count] + + def GenerateCCode(self, Tree, target='llvm'): + """生成代码 + + Args: + Tree: Python AST 树 + target: 目标代码类型,仅支持 'llvm' + + Returns: + 生成的代码字符串 + """ + self._generated_vars = set() + self.VarScopes = [{}] # 全局作用域 + + # 预扫描 import 语句,注册别名,确保类型解析时能正确解析模块别名 + if not getattr(self, '_import_aliases', None): + self._import_aliases = {} + if not getattr(self, '_imported_modules', None): + self._imported_modules = set() + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.Import): + for alias in Node.names: + name = alias.name + if name in ('c', 't'): + continue + self._imported_modules.add(name) + if alias.asname: + self._import_aliases[alias.asname] = name + elif isinstance(Node, ast.ImportFrom): + module_name = Node.module + if module_name and module_name not in ('c', 't'): + self._imported_modules.add(module_name) + for alias in Node.names: + if alias.asname: + self._import_aliases[alias.asname] = f"{module_name}.{alias.name}" + + for Node in ast.iter_child_nodes(Tree): + if isinstance(Node, ast.ClassDef): + ClassName = Node.name + + # 检查是否是特殊类型(枚举或联合体) + IsSpecialType = False + if Node.bases: + for base in Node.bases: + if hasattr(base, 'attr'): + if base.attr in ['CEnum', 'Enum', 'CUnion', 'REnum']: + IsSpecialType = True + break + elif hasattr(base, 'id'): + if base.id in ['CEnum', 'Enum', 'CUnion', 'REnum']: + IsSpecialType = True + break + + # 如果是特殊类型,跳过这里的处理(由 HandleClassDef 处理) + if IsSpecialType: + continue + + members = {} + IsTypedef = False + TypedefName = None + + if hasattr(Node, 'annotation') and Node.annotation: + try: + AnnotationStr = ast.dump(Node.annotation) + if 'CTypedef' in AnnotationStr: + IsTypedef = True + if isinstance(Node.annotation, ast.Call): + if Node.annotation.args: + if isinstance(Node.annotation.args[0], ast.Constant): + TypedefName = Node.annotation.args[0].value + except Exception: + pass + + if not IsTypedef: + for item in Node.body: + if isinstance(item, ast.Assign): + for target in item.targets: + if isinstance(target, ast.Name) and target.id == '__annotations__': + if isinstance(item.value, ast.Dict): + for key, value in zip(item.value.keys, item.value.values): + if isinstance(key, ast.Constant) and key.value == '__type__': + value_str = ast.dump(value) + if 'CTypedef' in value_str: + IsTypedef = True + if isinstance(value, ast.Call): + if value.args: + if isinstance(value.args[0], ast.Constant): + TypedefName = value.args[0].value + + if IsTypedef: + TypedefKey = TypedefName if TypedefName else ClassName + TypedefNode = SymbolNode.CreateClass( + name=TypedefKey, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'struct {ClassName}') + TypedefNode.set('IsComplete', True) + TypedefNode.set('file', '') + self.SymbolTable[TypedefKey] = TypedefNode.attributes + + for item in Node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + VarName = item.target.id + try: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + IsPtr = TypeInfo.IsPtr + if not IsPtr: + if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr): + LeftStr = ast.dump(item.annotation.left) + RightStr = ast.dump(item.annotation.right) + if 'CPtr' in LeftStr or 'CPtr' in RightStr: + IsPtr = True + dims = [] + if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant): + if isinstance(item.annotation.value, ast.Name): + if item.annotation.value.id == 't': + if hasattr(item.annotation, 'slice'): + try: + dims.append(int(item.annotation.slice.value)) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.LogWarning(f"异常被忽略: {_e}") + MemberInfo = TypeInfo.Copy() + if dims: + MemberInfo.ArrayDims = [str(d) for d in dims] + members[VarName] = MemberInfo + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.LogWarning(f"异常被忽略: {_e}") + + if not IsTypedef: + StructNode = SymbolNode.CreateClass( + name=ClassName, + TypeKind='struct', + members=members, + lineno=0 + ) + StructNode.set('file', '') + if ClassName in self.SymbolTable: + existing = self.SymbolTable[ClassName] + if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject: + StructNode.set('IsCpythonObject', True) + self.SymbolTable[ClassName] = StructNode.attributes + elif isinstance(Node, ast.FunctionDef): + FuncName = Node.name + FuncNode = SymbolNode.CreateClass( + name=FuncName, + TypeKind='function', + lineno=0 + ) + FuncNode.set('file', '') + self.SymbolTable[FuncName] = FuncNode.attributes + elif isinstance(Node, ast.AnnAssign): + if isinstance(Node.target, ast.Name): + VarName = Node.target.id + + VarType = 'unknown' + IsPtr = False + IsTypedef_assignment = False + + if Node.annotation: + try: + AnnotationStr = ast.dump(Node.annotation) + if 'CTypedef' in AnnotationStr: + IsTypedef_assignment = True + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.LogWarning(f"异常被忽略: {_e}") + + if IsTypedef_assignment and Node.value: + if isinstance(Node.value, ast.Name): + OriginalType = Node.value.id + if OriginalType in self.GeneratedTypes: + if OriginalType in self.SymbolTable: + OriginalInfo = self.SymbolTable[OriginalType] + if isinstance(OriginalInfo, dict): + actual_type = OriginalInfo.get('type', 'struct') + elif isinstance(OriginalInfo, CTypeInfo): + if OriginalInfo.IsEnum: + actual_type = 'enum' + elif OriginalInfo.IsTypedef: + actual_type = 'typedef' + elif OriginalInfo.IsStruct: + actual_type = 'struct' + else: + actual_type = 'struct' + else: + actual_type = 'struct' + if actual_type == 'enum': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'enum {OriginalType}') + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + elif actual_type == 'typedef': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + if isinstance(OriginalInfo, dict): + TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) + elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: + TypedefNode.set('OriginalType', OriginalInfo.OriginalType) + else: + TypedefNode.set('OriginalType', f'struct {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + else: + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'struct {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + continue + else: + if OriginalType in self.SymbolTable: + OriginalInfo = self.SymbolTable[OriginalType] + if isinstance(OriginalInfo, dict): + actual_type = OriginalInfo.get('type', 'struct') + elif isinstance(OriginalInfo, CTypeInfo): + if OriginalInfo.IsEnum: + actual_type = 'enum' + elif OriginalInfo.IsTypedef: + actual_type = 'typedef' + elif OriginalInfo.IsStruct: + actual_type = 'struct' + else: + actual_type = 'struct' + else: + actual_type = 'struct' + if actual_type == 'typedef': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + if isinstance(OriginalInfo, dict): + TypedefNode.set('OriginalType', OriginalInfo.get('OriginalType', f'struct {OriginalType}')) + elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType: + TypedefNode.set('OriginalType', OriginalInfo.OriginalType) + else: + TypedefNode.set('OriginalType', f'struct {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + if isinstance(OriginalInfo, dict): + OriginalInfo['skip_generation'] = True + continue + elif actual_type == 'struct': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'struct {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + if isinstance(OriginalInfo, dict): + OriginalInfo['skip_generation'] = True + continue + elif actual_type == 'enum': + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', f'enum {OriginalType}') + TypedefNode.set('PendingTypedef', True) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + if isinstance(OriginalInfo, dict): + OriginalInfo['skip_generation'] = True + continue + elif isinstance(Node.value, ast.Attribute): + from lib.core.Handles.HandlesBase import CTypeHelper + CName = CTypeHelper.GetCName(Node.value.attr) + if CName: + TypedefNode = SymbolNode.CreateClass( + name=VarName, + TypeKind='typedef', + lineno=0 + ) + TypedefNode.set('OriginalType', CName) + TypedefNode.set('file', '') + self.SymbolTable[VarName] = TypedefNode.attributes + self.GeneratedTypes.add(VarName) + continue + + if Node.annotation: + try: + TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation) + IsPtr = TypeInfo.IsPtr if TypeInfo else False + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + self.LogWarning(f"异常被忽略: {_e}") + var_node = SymbolNode.CreateClass( + name=VarName, + TypeKind='variable', + lineno=0 + ) + var_node.set('IsPtr', IsPtr) + var_node.set('file', '') + self.SymbolTable[VarName] = var_node.attributes + + self.LlvmGen = LlvmCodeGenerator( + triple=getattr(self, 'triple', None), + datalayout=getattr(self, 'datalayout', None), + ) + self.LlvmGen._Trans = self + self.LlvmGen._import_handler_ref = self.ImportHandler + if hasattr(self, '_module_sha1'): + self.LlvmGen.module_sha1 = self._module_sha1 + if hasattr(self, '_module_sha1_map'): + self.LlvmGen.module_sha1_map = self._module_sha1_map + if hasattr(self, '_struct_sha1_map'): + self.LlvmGen._struct_sha1_map = self._struct_sha1_map + if hasattr(self, '_temp_dir'): + self.LlvmGen._temp_dir = self._temp_dir + if hasattr(self, '_export_extern_funcs'): + self.LlvmGen._export_extern_funcs = self._export_extern_funcs + self.LlvmGen.setup_from_symbol_table(self.SymbolTable) + if hasattr(self, 'CurrentFile') and self.CurrentFile: + self.LlvmGen._set_source_info(self.CurrentFile) + + return self.GenerateLlvmDirect(Tree) + + def HandleExpr(self, Node, UseSingleQuote=False, VarType=None): + return self.ExprHandler.HandleExpr(Node, UseSingleQuote, VarType) diff --git a/lib/includes/c.py b/lib/includes/c.py new file mode 100644 index 0000000..e6fcc8c --- /dev/null +++ b/lib/includes/c.py @@ -0,0 +1,725 @@ +# C语法定义模块 + +import ast +import sys +import os +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) + +from . import t + +def _to_str(node): + if node is None: + return '' + if isinstance(node, str): + return node + if isinstance(node, list): + return ' && '.join([_to_str(n) for n in node]) + NodeType = type(node).__name__ + if NodeType == 'Constant': + return node.value + elif NodeType == 'ID': + return node.name + elif NodeType == 'BinaryOp': + left = _to_str(node.left) + right = _to_str(node.right) + return f'{left} {node.op} {right}' + elif NodeType == 'UnaryOp': + expr = _to_str(node.expr) + return f'{node.op}{expr}' + else: + return repr(node) + +class Asm: + @staticmethod + def _parse_asm_descr(expr): + """递归解析AST节点,确保获取t.ASM_DESCR的实际值,支持|组合 + 处理场景: + 1. t.ASM_DESCR.XXX → 取属性值 + 2. t.ASM_DESCR.XXX | t.ASM_DESCR.YYY → 拼接两个值 + 3. 常量字符串 → 直接返回 + """ + # 场景1:位或组合(XXX | YYY) + if isinstance(expr, ast.BinOp): + left_val = Asm._parse_asm_descr(expr.left) + right_val = Asm._parse_asm_descr(expr.right) + return left_val + right_val + + # 场景2:t.ASM_DESCR.XXX 多层属性访问 + elif isinstance(expr, ast.Attribute): + # 第一步:判断是否是 t.ASM_DESCR 的属性 + if isinstance(expr.value, ast.Attribute): + # 内层是 t.ASM_DESCR + if (isinstance(expr.value.value, ast.Name) and + expr.value.value.id == 't' and + expr.value.attr == 'ASM_DESCR'): + # 取 t.ASM_DESCR.XXX 的实际值 + AttrName = expr.attr + if hasattr(t.ASM_DESCR, AttrName): + return getattr(t.ASM_DESCR, AttrName, "") + + # 兼容 t.XXX 简化写法(如果有的话) + elif isinstance(expr.value, ast.Name) and expr.value.id == 't': + AttrName = expr.attr + if hasattr(t.ASM_DESCR, AttrName): + return getattr(t.ASM_DESCR, AttrName, "") + + # 场景3:直接传常量(如 "r"、"cc") + elif isinstance(expr, ast.Constant): + return expr.value + + # 其他场景返回空 + return "" + + @staticmethod + def _extract_val_expr(translator, expr_node): + """从AST表达式节点提取值表达式的字符串形式""" + val_ExprNode = translator.HandleExpr(expr_node)[0] + if isinstance(val_ExprNode, str): + return val_ExprNode + try: + return str(val_ExprNode) + except Exception as _e: + if __import__('lib.constants.config', fromlist=['mode']).mode == "strict": + import logging; logging.warning(f"异常被忽略: {_e}") + return '' + + @staticmethod + def _parse_asm_template(translator, args): + """解析f-string或常量模板字符串,返回(asm_code, output_ops, input_ops, operand_seq)""" + output_ops = [] + input_ops = [] + operand_seq = 0 + asm_code = "" + first_arg = args[0] + + if isinstance(first_arg, ast.JoinedStr): + asm_parts = [] + for part in first_arg.values: + if isinstance(part, ast.Constant): + asm_parts.append(part.value) + elif isinstance(part, ast.FormattedValue): + expr = part.value + if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute) and expr.func.value.id == 'c': + # 解析内联的AsmInp/AsmOut + call_node = expr + val_expr = Asm._extract_val_expr(translator, call_node.args[0]) if len(call_node.args)>=1 else "" + constraint = Asm._parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" + + if call_node.func.attr == 'AsmOut': + output_ops.append((val_expr, constraint)) + asm_parts.append(f"%{operand_seq}") + operand_seq += 1 + elif call_node.func.attr == 'AsmInp': + input_ops.append((val_expr, constraint)) + asm_parts.append(f"%{operand_seq}") + operand_seq += 1 + else: + asm_parts.append(translator.HandleExpr(expr)[0]) + asm_code = ''.join(asm_parts) + elif isinstance(first_arg, ast.Constant): + asm_code = first_arg.value + + return asm_code, output_ops, input_ops, operand_seq + + @staticmethod + def _parse_asm_operands(translator, args, keywords, output_ops, input_ops, operand_seq): + """解析位置参数和关键字参数中的输出/输入操作数""" + + def parse_operand(arg): + """解析 AsmInp/AsmOut 参数""" + if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute) and arg.func.value.id == 'c': + call_node = arg + val_expr = Asm._extract_val_expr(translator, call_node.args[0]) if len(call_node.args)>=1 else "" + constraint = Asm._parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" + + if call_node.func.attr == 'AsmOut': + return ('out', val_expr, constraint) + elif call_node.func.attr == 'AsmInp': + return ('in', val_expr, constraint) + return None + + # 处理位置参数中的操作数 + for arg in args[1:]: + result = parse_operand(arg) + if result: + direction, val_expr, constraint = result + if direction == 'out': + output_ops.append((val_expr, constraint)) + operand_seq += 1 + elif direction == 'in': + input_ops.append((val_expr, constraint)) + operand_seq += 1 + + # 处理关键字参数中的操作数 + for kw in keywords: + if kw.arg == 'out': + # 处理 out 关键字参数 (输出操作数) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + result = parse_operand(elt) + if result and result[0] == 'out': + output_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Call): + result = parse_operand(kw.value) + if result and result[0] == 'out': + output_ops.append((result[1], result[2])) + operand_seq += 1 + elif kw.arg == 'inp' or kw.arg == 'inputs': + # 处理 inp/inputs 关键字参数 (输入操作数,追加到f-string中已有输入之后) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + if isinstance(elt, ast.Tuple): + # 处理列表中的 (value, constraint) 元组格式 + if len(elt.elts) >= 2: + val_expr = Asm._extract_val_expr(translator, elt.elts[0]) if len(elt.elts) >= 1 else "" + constraint = Asm._parse_asm_descr(elt.elts[1]) + input_ops.append((val_expr, constraint)) + operand_seq += 1 + else: + result = parse_operand(elt) + if result and result[0] == 'in': + input_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Call): + result = parse_operand(kw.value) + if result and result[0] == 'in': + input_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Tuple): + # 处理 (value, constraint) 元组格式 + if len(kw.value.elts) >= 2: + val_expr = Asm._extract_val_expr(translator, kw.value.elts[0]) if len(kw.value.elts) >= 1 else "" + constraint = Asm._parse_asm_descr(kw.value.elts[1]) + input_ops.append((val_expr, constraint)) + operand_seq += 1 + + return output_ops, input_ops, operand_seq + + @staticmethod + def _parse_asm_clobbers(args, keywords): + """解析位置参数和关键字参数中的破坏列表""" + clobbers = [] + + # 处理位置参数中的破坏列表 + for arg in args[1:]: + if isinstance(arg, ast.List): + # 解析破坏列表(支持|组合) + for elt in arg.elts: + clobber_val = Asm._parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + + # 处理关键字参数中的破坏列表 + for kw in keywords: + if kw.arg == 'op': + # 处理 op 关键字参数 (clobber,破坏列表) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + clobber_val = Asm._parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + elif kw.arg == 'clobber': + # 处理 clobber 关键字参数 + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + clobber_val = Asm._parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + + return clobbers + + @staticmethod + def _generate_asm_code(asm_code, output_ops, input_ops, clobbers, asm_format): + """格式化汇编代码并生成最终的__asm__代码字符串""" + # 格式化汇编代码 + asm_lines = [line.strip() for line in asm_code.split('\n') if line.strip()] + formatted_asm = '\n '.join([f'"{line}\\n"' for line in asm_lines]) + + # 拼接约束字符串 + # 输出约束:如果约束已包含 = 或 +,直接使用;否则添加 = + def format_constraint(constraint, is_output=True): + if not constraint: + return "" + # 如果约束已包含修饰符,直接返回 + if '=' in constraint or '+' in constraint: + return constraint + # 否则添加适当的修饰符 + return ('=' if is_output else '') + constraint + + out_const = ', '.join([f'"{format_constraint(c, True)}"({v})' for v, c in output_ops]) if output_ops else "" + in_const = ', '.join([f'"{format_constraint(c, False)}"({v})' for v, c in input_ops]) if input_ops else "" + clobber_const = ', '.join([f'"{x}"' for x in clobbers]) if clobbers else "" + + # 构建约束部分:确保冒号格式正确 + constraint_parts = [] + # 输出约束 + if output_ops: + constraint_parts.append(f': {out_const}') + elif input_ops or clobbers: + constraint_parts.append(':') + + # 输入约束 + if input_ops: + constraint_parts.append(f': {in_const}') + elif clobbers: + constraint_parts.append(':') + + # 破坏列表 + if clobbers: + constraint_parts.append(f': {clobber_const}') + + constraint_str = ' '.join(constraint_parts) + + # 生成最终代码 + if asm_format == 'ARM': + # ARM 使用 .arch 指令和不同的内联汇编语法 + final_asm = f'__asm__ __volatile__ (\n {formatted_asm} {constraint_str});' + elif asm_format == 'AT&T': + # AT&T 语法不需要额外标记,GCC 默认就是 AT&T + final_asm = f'__asm__ __volatile__ (\n {formatted_asm} {constraint_str});' + else: + # Intel 语法需要 .intel_syntax 指令 + final_asm = f'__asm__ __volatile__ (".intel_syntax noprefix\\n\\t"\n {formatted_asm} ".att_syntax prefix" {constraint_str});' + return [final_asm] + + @staticmethod + def HandleCall(translator, args, keywords): + if not args: + return ['__asm__ volatile ("nop");'] + + # 解析模板 + asm_code, output_ops, input_ops, operand_seq = Asm._parse_asm_template(translator, args) + + # 解析操作数 + output_ops, input_ops, operand_seq = Asm._parse_asm_operands( + translator, args, keywords, output_ops, input_ops, operand_seq) + + # 解析破坏列表 + clobbers = Asm._parse_asm_clobbers(args, keywords) + + # 解析汇编格式 + asm_format = 'Intel' + for kw in keywords: + if kw.arg == 'format': + if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str): + asm_format = kw.value.value + + # 生成最终代码 + return Asm._generate_asm_code(asm_code, output_ops, input_ops, clobbers, asm_format) + +class AsmInp: + def __init__(self, value, constraint): + self.value = value + self.constraint = constraint + @staticmethod + def HandleCall(translator, args, keywords): + return [] + +class AsmOut: + def __init__(self, value, constraint): + self.value = value + self.constraint = constraint + @staticmethod + def HandleCall(translator, args, keywords): + return [] + +class NoBreak: + """ switch 分支无break """ + pass + +class Break: + """ switch 分支提前break """ + pass + +class Load: + """解引用a写入b,等价于 *b = *a,无拷贝副作用""" + def __init__(self, src, dst): + self.src = src + self.dst = dst + + @staticmethod + def HandleCall(translator, args, keywords): + if len(args) >= 2: + src = translator.HandleExpr(args[0])[0] + dst = translator.HandleExpr(args[1])[0] + return [f'*({dst}) = *({src})'] + return [] + + +class Addr: + """取地址""" + def __init__(self, addr): + self.addr = addr + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.Addr() 调用""" + if args: + expr = translator.HandleExpr(args[0])[0] + if isinstance(expr, str): + return [f'&{expr}'] + return [f'&{_to_str(expr)}'] + return ['0'] + + +class Deref: + """解引用""" + def __init__(self, ptr): + self.ptr = ptr + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.Deref() 调用""" + if args: + expr = translator.HandleExpr(args[0])[0] + if hasattr(expr, 'op') and expr.op == '*': + return [expr] + return [f'*({_to_str(expr)})'] + return ['0'] + + +class DerefAs: + """解引用写入,等价于 *ptr = value""" + def __init__(self, ptr, value): + self.ptr = ptr + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.DerefAs() 调用""" + if len(args) >= 2: + ptr = translator.HandleExpr(args[0])[0] + val = translator.HandleExpr(args[1])[0] + return [f'*({_to_str(ptr)}) = {_to_str(val)}'] + return [] + + +class Set: + """设置值""" + def __init__(self, key, value): + self.key = key + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.Set() 调用""" + if len(args) >= 2: + target = translator.HandleExpr(args[0])[0] + value = translator.HandleExpr(args[1])[0] + return [f'{_to_str(target)} = {_to_str(value)}'] + return [] + + +class CReturn: + """多返回值装饰器 + + 用于实现函数多返回值,通过匿名结构体返回实现。 + 例如:@c.CReturn(t.CInt, t.CInt) 表示函数返回两个 int 值。 + 等价于 -> tuple[t.CInt, t.CInt] 返回类型注解。 + + 规则: + 1. CReturn 中有几个类型就说明要返回几个值 + 2. 函数返回类型为匿名结构体 { type1, type2, ... } + 3. return 语句使用 insert_value 构建结构体 + 4. 调用处使用 extract_value 提取各字段 + """ + def __init__(self, *ReturnTypes): + self.ReturnTypes = ReturnTypes + + def __call__(self, func): + """装饰器调用""" + # 将返回类型信息附加到函数上 + func._CreturnTypes = self.ReturnTypes + return func + + +class CDefine: + """#define 宏定义""" + def __init__(self, name, value): + self.name = name + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CDefine() 调用""" + if len(args) >= 1: + if isinstance(args[0], ast.Constant): + name = args[0].value + else: + name = 'MACRO' + if len(args) >= 2: + value = translator.HandleExpr(args[1])[0] + return ['#define ' + str(name) + ' ' + _to_str(value)] + return ['#define ' + str(name)] + return [] + + +class CIfndef: + """#ifndef 条件编译""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CIfndef() 调用""" + if args: + condition = translator.HandleExpr(args[0])[0] + return ['#ifndef ' + _to_str(condition)] + return ['#if 0'] + +class CIfdef: + """#ifdef 条件编译""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CIfdef() 调用""" + if args: + condition = translator.HandleExpr(args[0])[0] + return ['#ifdef ' + _to_str(condition)] + return ['#if 0'] + +class CError: + """#error 错误信息""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CError() 调用""" + if args: + # 如果是字符串常量,保留引号 + if isinstance(args[0], ast.Constant) and isinstance(args[0].value, str): + return ['#error "' + args[0].value + '"'] + elif isinstance(args[0], ast.Str): + return ['#error "' + args[0].s + '"'] + else: + condition = translator.HandleExpr(args[0])[0] + return ['#error ' + _to_str(condition)] + return ['#error "Error: Condition is not met."'] + + +class TokenPast: + """## 连接符""" + def __init__(self, left, right): + self.left = left + self.right = right + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.TokenPast() 调用""" + if len(args) >= 2: + # 处理左操作数 - 去掉引号 + if isinstance(args[0], ast.Constant): + left = str(args[0].value) + elif isinstance(args[0], ast.Str): + left = str(args[0].s) + elif isinstance(args[0], ast.Name): + left = args[0].id + else: + left = _to_str(translator.HandleExpr(args[0])[0]) + + # 处理右操作数 - 去掉引号 + if isinstance(args[1], ast.Constant): + right = str(args[1].value) + elif isinstance(args[1], ast.Str): + right = str(args[1].s) + elif isinstance(args[1], ast.Name): + right = args[1].id + else: + right = _to_str(translator.HandleExpr(args[1])[0]) + + # 返回字符串,但用特殊标记包装,让 _AstNodeToStr 能正确处理 + result = left + ' ## ' + right + # 使用一个特殊的类来包装结果,让 _AstNodeToStr 直接返回其值 + class TokenPastResult: + def __init__(self, value): + self.value = value + def __str__(self): + return self.value + return [TokenPastResult(result)] + return [''] + + +class CIf: + """#if 条件编译""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CIf() 调用""" + if args: + condition = translator.HandleExpr(args[0])[0] + return ['#if ' + _to_str(condition)] + return ['#if 0'] + + +class CElif: + """#elif 条件编译""" + def __init__(self, condition): + self.condition = condition + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CElif() 调用""" + if args: + condition = translator.HandleExpr(args[0])[0] + return ['#elif ' + _to_str(condition)] + return ['#else'] + + +class CElse: + """#else 条件编译""" + def __init__(self): + pass + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CElse() 调用""" + return ['#else'] + + +class CEndif: + """#endif 条件编译""" + def __init__(self): + pass + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CEndif() 调用""" + return ['#endif'] + + +class CUndef: + """#undef 取消宏定义""" + def __init__(self, name): + self.name = name + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CUndef(name) 调用""" + import ast + if args: + arg = args[0] + if isinstance(arg, str): + name = arg + elif isinstance(arg, ast.Name): + name = arg.id + elif isinstance(arg, ast.Constant): + name = str(arg.value) + else: + name = str(arg) + return [f'#undef {name}'] + return ['#undef'] + + +class LLVMIR: + """内联 LLVM IR + + 用法: c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + 或: c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) + + c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 临时变量名 + c.LOut(expr) - 输出操作数,翻译后替换为对应的 LLVM 临时变量名 + """ + def __init__(self, ir_template, ret_type=None): + self.ir_template = ir_template + self.ret_type = ret_type + + @staticmethod + def HandleCall(translator, args, keywords): + return ['/* LLVMIR */'] + + +class LInp: + """LLVM IR 输入操作数标记 + + 用法: c.LInp(expr) - 标记 expr 为输入操作数 + 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 + """ + def __init__(self, value): + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + return [] + + +class LOut: + """LLVM IR 输出操作数标记 + + 用法: c.LOut(expr) - 标记 expr 为输出操作数 + 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 + """ + def __init__(self, value): + self.value = value + + @staticmethod + def HandleCall(translator, args, keywords): + return [] + + +class CPragma: + """#pragma 指令 + + 用于生成 C 语言的 #pragma 指令。 + 例如:c.CPragma("GCC diagnostic push") 生成 #pragma GCC diagnostic push + """ + def __init__(self, directive): + self.directive = directive + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 c.CPragma() 调用""" + if args: + arg = args[0] + if isinstance(arg, ast.Constant): + directive = arg.value + elif isinstance(arg, ast.Str): + directive = arg.s + else: + expr = translator.HandleExpr(arg)[0] + directive = _to_str(expr) + return [f'#pragma {directive}'] + return ['#pragma'] + + +# C 库类字典,用于 HandleCSpecialCall +Library_C = { + 'Asm': Asm, + 'Load': Load, + 'Addr': Addr, + 'Deref': Deref, + 'Set': Set, + 'AsmInp': AsmInp, + 'AsmOut': AsmOut, + 'CDefine': CDefine, + 'CIfndef': CIfndef, + 'CIfdef': CIfdef, + 'CIf': CIf, + 'CElif': CElif, + 'CElse': CElse, + 'CEndif': CEndif, + 'CUndef': CUndef, + 'CError': CError, + 'TokenPast': TokenPast, + 'CReturn': CReturn, + 'CPragma': CPragma, + 'LLVMIR': LLVMIR, + 'LInp': LInp, + 'LOut': LOut, +} + + +class Attribute: + """函数/变量属性装饰器""" + def __init__(self, *attrs): + self.attrs = attrs + + def __call__(self, func): + # 将属性附加到函数上 + func._c_attributes = self.attrs + return func diff --git a/lib/includes/t.py b/lib/includes/t.py new file mode 100644 index 0000000..450e83a --- /dev/null +++ b/lib/includes/t.py @@ -0,0 +1,1338 @@ +# 类型定义模块 + +import re +import types +from typing import TypeVar, Generic, TypeAlias + + +# ============================================================================= +# 类型映射常量 +# ============================================================================= + +# 类型映射常量(由 _build_type_maps() 在模块末尾自动生成) +_BASIC_TYPES_MAP = {} +_T_TYPE_PATTERNS = [] + +# 平台相关类型的默认 Size(可由 configure_platform 修改) +_LONG_SIZE = 64 +_UNSIGNED_LONG_SIZE = 64 +_WCHAR_T_SIZE = 32 +_SIZE_T_SIZE = 64 +_INTPTR_T_SIZE = 64 +_UINTPTR_T_SIZE = 64 +_PTRDIFF_T_SIZE = 64 + +def configure_platform(triple=None): + """根据目标三元组配置平台相关类型的大小 + + Args: + triple: LLVM 目标三元组字符串,如 'x86_64-pc-windows-gnu' + """ + global _LONG_SIZE, _UNSIGNED_LONG_SIZE, _WCHAR_T_SIZE + global _SIZE_T_SIZE, _INTPTR_T_SIZE, _UINTPTR_T_SIZE, _PTRDIFF_T_SIZE + if not triple: + return + triple_lower = triple.lower() + is_windows = any(k in triple_lower for k in ('windows', 'win32', 'mingw', 'msvc', 'cygwin')) + is_32bit = any(k in triple_lower for k in ('i386', 'i686')) + if is_windows: + _LONG_SIZE = 32 # Windows LLP64: long = 32 位 + _UNSIGNED_LONG_SIZE = 32 + _WCHAR_T_SIZE = 16 # Windows: wchar_t = 16 位 + if is_32bit: + _SIZE_T_SIZE = 32 + _INTPTR_T_SIZE = 32 + _UINTPTR_T_SIZE = 32 + _PTRDIFF_T_SIZE = 32 + +def _build_type_maps(): + global _BASIC_TYPES_MAP, _T_TYPE_PATTERNS + for _name in dir(): + _obj = eval(_name) + if isinstance(_obj, type) and issubclass(_obj, CType) and _obj is not CType: + try: + _inst = _obj() + _cname = getattr(_inst, 'CName', '') + if _cname and _obj.IsBasicType(): + _BASIC_TYPES_MAP[_cname] = _cname + _T_TYPE_PATTERNS.append((_name, _cname)) + except Exception: + pass + + +# ============================================================================= +# CType 基类 +# ============================================================================= + +class CType: + """C 类型基类""" + + PREFIX = 'prefix' + BASE = 'base' + POINTER = 'ptr' + ARRAY = 'array' + NAMED = 'named' + STORAGE_CLASS = 'storage_class' + TYPE_QUALIFIER = 'type_qualifier' + + position = frozenset({BASE}) # 类属性,支持联合类型如 BASE | SPECIAL + + def __init__(self, value=None, *types): + self.value = value + self.types = types + self.Name = '' + self.IsBasicType = False + self.IsPointer = False + self.IsSigned = None + self.Size = None + if not hasattr(self, 'CName'): + self.CName = '' + + def GetPositions(self) -> frozenset: + """获取 position 的 frozenset 形式""" + return self.position + + @classmethod + def HasPosition(cls, pos) -> bool: + """检查是否包含指定的位置""" + return pos in cls.position + + @classmethod + def IsNamed(cls) -> bool: + """检查是否是命名类型(struct/union/enum/typedef 等)""" + return cls.NAMED in cls.position + + @classmethod + def IsStorageClass(cls) -> bool: + """检查是否是存储类修饰符""" + return cls.STORAGE_CLASS in cls.position + + @classmethod + def IsTypeQualifier(cls) -> bool: + """检查是否是类型限定符""" + return cls.TYPE_QUALIFIER in cls.position + + @classmethod + def IsBasicType(cls) -> bool: + """检查是否是基本类型""" + return cls.BASE in cls.position + + @classmethod + def IsPrefix(cls) -> bool: + """检查是否是前缀类型""" + return cls.PREFIX in cls.position + + def rfind(self, s): + """注解""" + pass + + def get_position(self): + """获取类型在声明中的位置""" + return self.position + + def GetCName(self): + """获取 C 类型名称""" + return self.CName + + def __merge__(self, types): + return types + + def __or__(self, other): + return [self, other] + + def __set_default__(self, **kwargs): + """设置默认值/初始值,用于 static/global 变量的初始化 + + Args: + **kwargs: 成员名称和值的键值对 + + Returns: + 包含默认值信息的 CTypeDefault 对象 + """ + return CTypeDefault(self, **kwargs) + + @classmethod + def FromAnnotation(cls, AnnotationStr, TypeName=''): + """从类型注解字符串解析类型信息 + + Args: + AnnotationStr: 类型注解的字符串表示(ast.dump结果) + TypeName: 类型名称(可选) + + Returns: + CType 实例 + """ + ctype = cls() + + # 检查是否是基本类型 + if TypeName in _BASIC_TYPES_MAP: + ctype.IsBasicType = True + ctype.Name = _BASIC_TYPES_MAP[TypeName] + else: + for pattern, c_name in _T_TYPE_PATTERNS: + if pattern in AnnotationStr: + ctype.IsBasicType = True + ctype.Name = c_name + break + + # 检查是否包含指针 + if 'CPtr' in AnnotationStr: + ctype.IsPointer = True + + return ctype + + @classmethod + def FromTypeName(cls, TypeName): + """从类型名称创建 CType + + Args: + TypeName: 类型名称 + + Returns: + CType 实例 + """ + ctype = cls() + + if TypeName in _BASIC_TYPES_MAP: + ctype.IsBasicType = True + ctype.Name = _BASIC_TYPES_MAP[TypeName] + + return ctype + + def GetFullType(self, VarName='', ArraySizeStr=''): + """获取完整的类型声明字符串 + + Args: + VarName: 变量名 + ArraySizeStr: 数组大小字符串 + + Returns: + 完整的类型声明字符串 + """ + ptr_str = '*' if self.IsPointer else '' + if VarName: + return f'{self.Name}{ptr_str} {VarName}{ArraySizeStr}' + return f'{self.Name}{ptr_str}' + + def __repr__(self): + ptr_str = '*' if self.IsPointer else '' + return f'CType({self.Name}{ptr_str}, IsBasicType={self.IsBasicType})' + +class CChar(CType): + def __init__(self, value=None): + self.CName = 'char' + super().__init__(value) + self.IsSigned = True + self.Size = 8 + +class CInt(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int' + super().__init__(value) + self.IsSigned = True + self.Size = 32 + +class CShort(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'short' + super().__init__(value) + self.IsSigned = True + self.Size = 16 + +class CLong(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'long' + super().__init__(value) + self.IsSigned = True + self.Size = _LONG_SIZE + +class CFloat(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float' + super().__init__(value) + self.IsSigned = None + self.Size = 32 + +class CDouble(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'double' + super().__init__(value) + self.IsSigned = None + self.Size = 64 + +class CFloat8T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float8_t' + super().__init__(value) + self.IsSigned = None + self.Size = 8 + +class CFloat16T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float16_t' + super().__init__(value) + self.IsSigned = None + self.Size = 16 + +class CFloat32T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float32_t' + super().__init__(value) + self.IsSigned = None + self.Size = 32 + +class CFloat64T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float64_t' + super().__init__(value) + self.IsSigned = None + self.Size = 64 + +class CFloat128T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'float128_t' + super().__init__(value) + self.IsSigned = None + self.Size = 128 + +class CVoid(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'void' + super().__init__(value) + self.IsSigned = None + self.Size = 0 + +class CUnsigned(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned' + super().__init__(value) + self.IsSigned = False + self.Size = 32 + +class CUnsignedChar(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned char' + super().__init__(value) + self.IsSigned = False + self.Size = 8 + +class CUnsignedInt(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned int' + super().__init__(value) + self.IsSigned = False + self.Size = 32 + +class CUnsignedShort(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned short' + super().__init__(value) + self.IsSigned = False + self.Size = 16 + +class CUnsignedLong(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'unsigned long' + super().__init__(value) + self.IsSigned = False + self.Size = _UNSIGNED_LONG_SIZE + +class CSignedChar(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'signed char' + super().__init__(value) + self.IsSigned = True + self.Size = 8 + +class CStruct(CType): + position = frozenset({CType.BASE, CType.NAMED}) + def __init__(self, value=None, name=None): + self.name = name + self.CName = f'struct {name}' if name else 'struct' + super().__init__(value) + +class CUnion(CType): + position = frozenset({CType.BASE, CType.NAMED}) + def __init__(self, value=None): + self.CName = 'union' + super().__init__(value) + +class CEnum(CType): + position = frozenset({CType.BASE, CType.NAMED}) + def __init__(self, value=None): + self.CName = 'enum' + super().__init__(value) + +Enum = CEnum + +class REnum(CType): + position = frozenset({CType.BASE, CType.NAMED}) + tag: int = 0 # 无用,只是个标记 + def __init__(self, value=None): + self.CName = 'renum' + super().__init__(value) + +''' +class Object(CType): + """Python 对象类型,用于支持类方法外联函数""" + position = frozenset({CType.BASE, CType.NAMED}) + def __init__(self, value=None): + self.CName = 'struct' + super().__init__(value) + def __call__(self, cls): + return cls +''' +def Object(): + pass + +def CVTable(): + pass + +CTypedef = TypeAlias + +class _CTypedef(CType): + position = frozenset({CType.PREFIX, CType.NAMED}) + def __init__(self, value=None): + self.CName = 'typedef' + super().__init__(value) + + +class CAuto(CType): + position = frozenset({CType.PREFIX}) + def __init__(self, value=None): + self.CName = 'auto' + super().__init__(value) + +class CRegister(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'register' + super().__init__(value) + +class CStatic(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'static' + super().__init__(value) + +class CExtern(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'extern' + super().__init__(value) + +class CConst(CType): + position = frozenset({CType.PREFIX, CType.TYPE_QUALIFIER}) + def __init__(self, value=None): + self.CName = 'const' + super().__init__(value) + +class CInline(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'inline' + super().__init__(value) + +class CExport(CType): + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + def __init__(self, value=None): + self.CName = 'export' + super().__init__(value) + +class CVolatile(CType): + position = frozenset({CType.PREFIX, CType.TYPE_QUALIFIER}) + def __init__(self, value=None): + self.CName = 'volatile' + super().__init__(value) + +class CSizeT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'size_t' + super().__init__(value) + self.IsSigned = False + self.Size = _SIZE_T_SIZE + +class CInt8T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int8_t' + super().__init__(value) + self.IsSigned = True + self.Size = 8 + +class CInt16T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int16_t' + super().__init__(value) + self.IsSigned = True + self.Size = 16 + +class CInt32T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int32_t' + super().__init__(value) + self.IsSigned = True + self.Size = 32 + +class CInt64T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'int64_t' + super().__init__(value) + self.IsSigned = True + self.Size = 64 + +class CUInt8T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uint8_t' + super().__init__(value) + self.IsSigned = False + self.Size = 8 + +class CUInt16T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uint16_t' + super().__init__(value) + self.IsSigned = False + self.Size = 16 + +class CUInt32T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uint32_t' + super().__init__(value) + self.IsSigned = False + self.Size = 32 + +class CUInt64T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uint64_t' + super().__init__(value) + self.IsSigned = False + self.Size = 64 + +class CIntPtrT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'intptr_t' + super().__init__(value) + self.IsSigned = True + self.Size = _INTPTR_T_SIZE + +class CUIntPtrT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'uintptr_t' + super().__init__(value) + self.IsSigned = False + self.Size = _UINTPTR_T_SIZE + +class CPtrDiffT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'ptrdiff_t' + super().__init__(value) + self.IsSigned = True + self.Size = _PTRDIFF_T_SIZE + +class CWCharT(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'wchar_t' + super().__init__(value) + self.IsSigned = True + self.Size = _WCHAR_T_SIZE + +class CChar8T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'char8_t' + super().__init__(value) + self.IsSigned = False + self.Size = 8 + +class CChar16T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'char16_t' + super().__init__(value) + self.IsSigned = False + self.Size = 16 + +class CChar32T(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'char32_t' + super().__init__(value) + self.IsSigned = False + self.Size = 32 + +class CBool(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = 'bool' + super().__init__(value) + self.IsSigned = False + self.Size = 8 + +class CComplex(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = '_Complex' + super().__init__(value) + +class CImaginary(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = '_Imaginary' + super().__init__(value) + +T = TypeVar("T") +Callable = Generic[T] + +class CPtr(CType, Generic[T]): + position = frozenset({CType.POINTER}) + def __init__(self, value=None): + self.CName = '*' + super().__init__(value) + +class CTypeDefault(CType): + """用于存储 C 类型默认值/初始化的包装类 + + 当使用 t.CStatic.__set_default__(open=mouse_open, ...) 时创建 + """ + def __init__(self, BaseType, **kwargs): + super().__init__() + self.BaseType = BaseType + self.defaults = kwargs + self.CName = BaseType.CName if hasattr(BaseType, 'CName') else '' + self.position = BaseType.position if hasattr(BaseType, 'position') else CType.BASE + + def __repr__(self): + return f'CTypeDefault({self.BaseType}, {self.defaults})' + +class CArrayPtr(CType): + position = frozenset({CType.POINTER}) + def __init__(self, value=None): + self.CName = '(*)' # 特殊标记表示数组指针 + super().__init__(value) + +class CDefine(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = '#define' + super().__init__(value) + +class CPass(CType): + position = frozenset({CType.BASE}) + def __init__(self, value=None): + self.CName = '' + super().__init__(value) + +class State(CType): + """状态标记,用于仅声明不定义,等价于 CExport | CExtern""" + position = frozenset({CType.PREFIX, CType.STORAGE_CLASS}) + + @staticmethod + def HandleCall(translator, args, keywords): + """处理 t.State() 调用""" + return ['t.State'] + +class Postdefinition: + def __init__(self, c): + pass + +class Bit: + def __init__(self, i): + pass + +class BigEndian(CType): + """大端序(Big-Endian)字节序标记类 + + 用于标记结构体成员应使用大端序存储。 + 在小端序平台(如x86)上读取时,会自动进行字节交换。 + + 用法示例: + class MyStruct: + a: t.CInt | t.BigEndian # 大端序存储的整数 + """ + IsSigned = True + Size = 32 + Align = 32 + +class LittleEndian(CType): + """小端序(Little-Endian)字节序标记类 + + 用于标记结构体成员应使用小端序存储。 + 在小端序平台(如x86)上读取时,不需要进行字节交换。 + + 用法示例: + class MyStruct: + b: t.CInt | t.LittleEndian # 小端序存储的整数 + """ + IsSigned = True + Size = 32 + Align = 32 + +class ASM_DESCR: + """内嵌 ASM 破坏描述符类 + + 定义了所有可能的破坏描述符和约束字符,用于 GCC 内嵌汇编 + """ + # 操作数修饰符 + MODIFIER_OUTPUT = '=' # 输出操作数 + MODIFIER_READWRITE = '+' # 读写操作数 + MODIFIER_INPUT = '' # 输入操作数(默认) + MODIFIER_GLOBAL = '&' # 全局操作数 + + # 寄存器约束(32位命名) + REG_ANY = 'r' # 任何通用寄存器 + REG_EAX = 'a' # EAX/RAX 寄存器 + REG_EBX = 'b' # EBX/RBX 寄存器 + REG_ECX = 'c' # ECX/RCX 寄存器 + REG_EDX = 'd' # EDX/RDX 寄存器 + REG_ESI = 'S' # ESI/RSI 寄存器 + REG_EDI = 'D' # EDI/RDI 寄存器 + REG_STACK = 'q' # 任何通用寄存器(EAX, EBX, ECX, EDX) + REG_FLOAT = 'f' # 浮点寄存器 + REG_MMX = 'y' # MMX 寄存器 + REG_XMM = 'x' # XMM 寄存器 + + # 寄存器约束(64位命名,GCC约束字符与32位相同) + REG_RAX = 'a' # RAX 寄存器 + REG_RBX = 'b' # RBX 寄存器 + REG_RCX = 'c' # RCX 寄存器 + REG_RDX = 'd' # RDX 寄存器 + REG_RSI = 'S' # RSI 寄存器 + REG_RDI = 'D' # RDI 寄存器 + REG_R8 = 'r' # R8 寄存器(需通过r约束+显式指定) + REG_R9 = 'r' # R9 寄存器 + REG_R10 = 'r' # R10 寄存器 + REG_R11 = 'r' # R11 寄存器 + REG_R12 = 'r' # R12 寄存器 + REG_R13 = 'r' # R13 寄存器 + REG_R14 = 'r' # R14 寄存器 + REG_R15 = 'r' # R15 寄存器 + REG_RBP = 'r' # RBP 寄存器 + REG_RSP = 'r' # RSP 寄存器 + + # 内存约束 + MEMORY = 'm' # 内存操作数 + + # 立即数约束 + IMMEDIATE = 'i' # 立即数 + IMMEDIATE_CONST = 'n' # 常量立即数 + + # 综合约束 + ANY = 'g' # 任何通用寄存器、内存或立即数 + MEMORY_OR_REG = 'o' # 内存或寄存器 + + # 破坏描述符(clobber list) + CLOBBER_EAX = 'eax' # 破坏 EAX/RAX 寄存器 + CLOBBER_EBX = 'ebx' # 破坏 EBX/RBX 寄存器 + CLOBBER_ECX = 'ecx' # 破坏 ECX/RCX 寄存器 + CLOBBER_EDX = 'edx' # 破坏 EDX/RDX 寄存器 + CLOBBER_ESI = 'esi' # 破坏 ESI/RSI 寄存器 + CLOBBER_EDI = 'edi' # 破坏 EDI/RDI 寄存器 + CLOBBER_EBP = 'ebp' # 破坏 EBP/RBP 寄存器 + CLOBBER_ESP = 'esp' # 破坏 ESP/RSP 寄存器 + CLOBBER_AL = 'al' # 破坏 AL 寄存器(EAX/RAX 低8位) + CLOBBER_AH = 'ah' # 破坏 AH 寄存器(EAX/RAX 高8位) + CLOBBER_BL = 'bl' # 破坏 BL 寄存器(EBX/RBX 低8位) + CLOBBER_BH = 'bh' # 破坏 BH 寄存器(EBX/RBX 高8位) + CLOBBER_CL = 'cl' # 破坏 CL 寄存器(ECX/RCX 低8位) + CLOBBER_CH = 'ch' # 破坏 CH 寄存器(ECX/RCX 高8位) + CLOBBER_DL = 'dl' # 破坏 DL 寄存器(EDX/RDX 低8位) + CLOBBER_DH = 'dh' # 破坏 DH 寄存器(EDX/RDX 高8位) + CLOBBER_CC = 'cc' # 破坏条件代码寄存器(标志寄存器) + CLOBBER_MEMORY = 'memory' # 破坏内存(表示汇编代码修改了内存) + # 16 位寄存器破坏描述符 + CLOBBER_AX = 'ax' # 破坏 AX 寄存器 + CLOBBER_BX = 'bx' # 破坏 BX 寄存器 + CLOBBER_CX = 'cx' # 破坏 CX 寄存器 + CLOBBER_DX = 'dx' # 破坏 DX 寄存器 + CLOBBER_SI = 'si' # 破坏 SI 寄存器 + CLOBBER_DI = 'di' # 破坏 DI 寄存器 + CLOBBER_BP = 'bp' # 破坏 BP 寄存器 + + # 64位寄存器破坏描述符 + CLOBBER_RAX = 'rax' # 破坏 RAX 寄存器 + CLOBBER_RBX = 'rbx' # 破坏 RBX 寄存器 + CLOBBER_RCX = 'rcx' # 破坏 RCX 寄存器 + CLOBBER_RDX = 'rdx' # 破坏 RDX 寄存器 + CLOBBER_RSI = 'rsi' # 破坏 RSI 寄存器 + CLOBBER_RDI = 'rdi' # 破坏 RDI 寄存器 + CLOBBER_RBP = 'rbp' # 破坏 RBP 寄存器 + CLOBBER_RSP = 'rsp' # 破坏 RSP 寄存器 + CLOBBER_R8 = 'r8' # 破坏 R8 寄存器 + CLOBBER_R9 = 'r9' # 破坏 R9 寄存器 + CLOBBER_R10 = 'r10' # 破坏 R10 寄存器 + CLOBBER_R11 = 'r11' # 破坏 R11 寄存器 + CLOBBER_R12 = 'r12' # 破坏 R12 寄存器 + CLOBBER_R13 = 'r13' # 破坏 R13 寄存器 + CLOBBER_R14 = 'r14' # 破坏 R14 寄存器 + CLOBBER_R15 = 'r15' # 破坏 R15 寄存器 + + # 预定义的组合约束(32位命名) + OUTPUT_REG = '=r' # 输出操作数,使用任何通用寄存器 + OUTPUT_MEM = '=m' # 输出操作数,使用内存 + OUTPUT_EAX = '=a' # 输出操作数,使用 EAX/RAX 寄存器 + OUTPUT_EBX = '=b' # 输出操作数,使用 EBX/RBX 寄存器 + OUTPUT_ECX = '=c' # 输出操作数,使用 ECX/RCX 寄存器 + OUTPUT_EDX = '=d' # 输出操作数,使用 EDX/RDX 寄存器 + OUTPUT_ESI = '=S' # 输出操作数,使用 ESI/RSI 寄存器 + OUTPUT_EDI = '=D' # 输出操作数,使用 EDI/RDI 寄存器 + + # 预定义的组合约束(64位命名) + OUTPUT_RAX = '=a' # 输出操作数,使用 RAX 寄存器 + OUTPUT_RBX = '=b' # 输出操作数,使用 RBX 寄存器 + OUTPUT_RCX = '=c' # 输出操作数,使用 RCX 寄存器 + OUTPUT_RDX = '=d' # 输出操作数,使用 RDX 寄存器 + OUTPUT_RSI = '=S' # 输出操作数,使用 RSI 寄存器 + OUTPUT_RDI = '=D' # 输出操作数,使用 RDI 寄存器 + + INPUT_REG = 'r' # 输入操作数,使用任何通用寄存器 + INPUT_MEM = 'm' # 输入操作数,使用内存 + INPUT_EAX = 'a' # 输入操作数,使用 EAX/RAX 寄存器 + INPUT_EBX = 'b' # 输入操作数,使用 EBX/RBX 寄存器 + INPUT_ECX = 'c' # 输入操作数,使用 ECX/RCX 寄存器 + INPUT_EDX = 'd' # 输入操作数,使用 EDX/RDX 寄存器 + INPUT_ESI = 'S' # 输入操作数,使用 ESI/RSI 寄存器 + INPUT_EDI = 'D' # 输入操作数,使用 EDI/RDI 寄存器 + INPUT_IMM = 'i' # 输入操作数,使用立即数 + INPUT_ANY = 'g' # 输入操作数,使用任何通用寄存器、内存或立即数 + + # 输入约束(64位命名) + INPUT_RAX = 'a' # 输入操作数,使用 RAX 寄存器 + INPUT_RBX = 'b' # 输入操作数,使用 RBX 寄存器 + INPUT_RCX = 'c' # 输入操作数,使用 RCX 寄存器 + INPUT_RDX = 'd' # 输入操作数,使用 RDX 寄存器 + INPUT_RSI = 'S' # 输入操作数,使用 RSI 寄存器 + INPUT_RDI = 'D' # 输入操作数,使用 RDI 寄存器 + + # 所有单独约束字符列表 + ALL_CONSTRAINTS = [ + # 操作数修饰符 + MODIFIER_OUTPUT, MODIFIER_READWRITE, MODIFIER_INPUT, MODIFIER_GLOBAL, + + # 寄存器约束 + REG_ANY, REG_EAX, REG_EBX, REG_ECX, REG_EDX, REG_ESI, REG_EDI, + REG_STACK, REG_FLOAT, REG_MMX, REG_XMM, + + # 内存约束 + MEMORY, + + # 立即数约束 + IMMEDIATE, IMMEDIATE_CONST, + + # 综合约束 + ANY, MEMORY_OR_REG + ] + + # 所有破坏描述符列表 + ALL_CLOBBERS = [ + CLOBBER_EAX, CLOBBER_EBX, CLOBBER_ECX, CLOBBER_EDX, + CLOBBER_ESI, CLOBBER_EDI, CLOBBER_EBP, CLOBBER_ESP, + CLOBBER_CC, CLOBBER_MEMORY, + CLOBBER_RAX, CLOBBER_RBX, CLOBBER_RCX, CLOBBER_RDX, + CLOBBER_RSI, CLOBBER_RDI, CLOBBER_RBP, CLOBBER_RSP, + CLOBBER_R8, CLOBBER_R9, CLOBBER_R10, CLOBBER_R11, + CLOBBER_R12, CLOBBER_R13, CLOBBER_R14, CLOBBER_R15 + ] + + # 所有描述符列表 + ALL = ALL_CONSTRAINTS + ALL_CLOBBERS + + +# 定义 ASM_LIST,包含所有可能的汇编约束字符 +ASM_LIST = ASM_DESCR.ALL + + +class attr: + """C 语言 __attribute__ 属性操作类型""" + + @staticmethod + def noreturn(): + return "noreturn" + + @staticmethod + def format(printf, arg1, arg2): + return f"format({printf}, {arg1}, {arg2})" + + @staticmethod + def section(name): + return f'section("{name}")' + + @staticmethod + def aligned(bytes): + return f"aligned({bytes})" + + @staticmethod + def packed(): + return "packed" + + @staticmethod + def unused(): + return "unused" + + @staticmethod + def used(): + return "used" + + @staticmethod + def weak(): + return "weak" + + @staticmethod + def alias(name): + return f'alias("{name}")' + + @staticmethod + def visibility(type): + return f'visibility("{type}")' + + @staticmethod + def constructor(): + return "constructor" + + @staticmethod + def destructor(): + return "destructor" + + @staticmethod + def always_inline(): + return "always_inline" + + @staticmethod + def noinline(): + return "noinline" + + @staticmethod + def pure(): + return "pure" + + @staticmethod + def const(): + return "const" + + @staticmethod + def malloc(): + return "malloc" + + @staticmethod + def alloc_size(n): + return f"alloc_size({n})" + + @staticmethod + def warn_unused_result(): + return "warn_unused_result" + + @staticmethod + def deprecated(msg=None): + if msg: + return f'deprecated("{msg}")' + return "deprecated" + + @staticmethod + def fallthrough(): + return "fallthrough" + + @staticmethod + def likely(): + return "likely" + + @staticmethod + def unlikely(): + return "unlikely" + + @staticmethod + def hot(): + return "hot" + + @staticmethod + def cold(): + return "cold" + + @staticmethod + def interrupt(): + return "interrupt" + + @staticmethod + def naked(): + return "naked" + + @staticmethod + def sentinel(n=0): + return f"sentinel({n})" + + @staticmethod + def nonnull(*args): + if args: + return f"nonnull({', '.join(map(str, args))})" + return "nonnull" + + @staticmethod + def returns_nonnull(): + return "returns_nonnull" + + @staticmethod + def access(mode, *args): + return f"access({mode}, {', '.join(map(str, args))})" + + @staticmethod + def cleanup(func): + return f'cleanup({func})' + + @staticmethod + def transparent_union(): + return "transparent_union" + + @staticmethod + def mode(mode_name): + return f"mode({mode_name})" + + @staticmethod + def vector_size(bytes): + return f"vector_size({bytes})" + + @staticmethod + def target(string): + return f'target("{string}")' + + @staticmethod + def optimize(level): + return f'optimize("{level}")' + + @staticmethod + def no_instrument_function(): + return "no_instrument_function" + + @staticmethod + def no_sanitize(type): + return f"no_sanitize({type})" + + @staticmethod + def no_stack_protector(): + return "no_stack_protector" + + @staticmethod + def stack_protector(): + return "stack_protector" + + @staticmethod + def error(msg): + return f'error("{msg}")' + + @staticmethod + def warning(msg): + return f'warning("{msg}")' + + class llvm: + """LLVM 函数属性描述符 + + 用于在返回类型注解中指定 LLVM 函数属性。 + 例如: def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind: + """ + + class nobuiltin: + CName = '#attr.llvm.nobuiltin' + + class nounwind: + CName = '#attr.llvm.nounwind' + + class noredzone: + CName = '#attr.llvm.noredzone' + + class willreturn: + CName = '#attr.llvm.willreturn' + + class mustprogress: + CName = '#attr.llvm.mustprogress' + + class optnone: + CName = '#attr.llvm.optnone' + + class noinline: + CName = '#attr.llvm.noinline' + + class alwaysinline: + CName = '#attr.llvm.alwaysinline' + + class readnone: + CName = '#attr.llvm.readnone' + + class readonly: + CName = '#attr.llvm.readonly' + + class writeonly: + CName = '#attr.llvm.writeonly' + + class inaccessiblememonly: + CName = '#attr.llvm.inaccessiblememonly' + + class inaccessiblemem_or_argmemonly: + CName = '#attr.llvm.inaccessiblemem_or_argmemonly' + + +def NewCType(size, signed): + ct = CType() + ct.Size = size + ct.IsSigned = signed + return ct + +i1 = NewCType(1, True) +i8 = NewCType(8, True) +i16 = NewCType(16, True) +i32 = NewCType(32, True) +i64 = NewCType(64, True) + +u1 = NewCType(1, False) +u8 = NewCType(8, False) +u16 = NewCType(16, False) +u32 = NewCType(32, False) +u64 = NewCType(64, False) + + +class CTypeRegistry: + """基于 CType 元属性的类型注册表,替代手动映射表 + + 利用 CType 子类的 position/IsSigned/Size 元属性自动推导: + - LLVM IR 类型字符串 (如 'i32', 'double', 'i8*') + - C 类型名称 (如 'int', 'unsigned char', 'long long') + - Python CType 类引用 (如 t.CInt32T) + """ + + _name_to_class = None + _cname_to_class = None + + @classmethod + def _build(cls): + if cls._name_to_class is not None: + return + import sys + mod = sys.modules.get(__name__) + if mod is None: + return + cls._name_to_class = {} + cls._cname_to_class = {} + for name, obj in vars(mod).items(): + if not isinstance(obj, type) or not issubclass(obj, CType) or obj is CType: + continue + if obj in (CTypeDefault, BigEndian, LittleEndian): + continue + try: + inst = obj() + except Exception: + continue + pos = getattr(obj, 'position', frozenset()) + if CType.PREFIX in pos and CType.BASE not in pos: + continue + if CType.POINTER in pos and CType.BASE not in pos: + cls._name_to_class[name] = obj + continue + if getattr(inst, 'Size', None) is not None or getattr(inst, 'CName', ''): + cls._name_to_class[name] = obj + cname = getattr(inst, 'CName', '') + if cname and cname not in cls._cname_to_class: + cls._cname_to_class[cname] = obj + + @classmethod + def GetClassByName(cls, name: str): + """根据 Python 类名获取 CType 类 (如 'CInt32T' -> t.CInt32T)""" + cls._build() + return cls._name_to_class.get(name) + + @classmethod + def GetClassByCName(cls, cname: str): + """根据 C 类型名获取 CType 类 (如 'int32_t' -> t.CInt32T)""" + cls._build() + return cls._cname_to_class.get(cname) + + @staticmethod + def CTypeToLLVM(ctype_class) -> str: + """从 CType 类的元属性推导 LLVM IR 类型字符串 + + 规则: + - position 含 POINTER 且不含 BASE → 'i8*' + - position 含 PREFIX 且不含 BASE → '' (修饰符,无LLVM类型) + - Size == 0 且 IsSigned is None → 'void' + - IsSigned is None 且 Size > 0 → 浮点: half/float/double/fp128 + - IsSigned is True/False 且 Size > 0 → 整数: i{Size} + """ + if ctype_class is None: + return 'i8*' + pos = getattr(ctype_class, 'position', frozenset()) + if CType.POINTER in pos and CType.BASE not in pos: + return 'i8*' + if CType.PREFIX in pos and CType.BASE not in pos: + return '' + try: + inst = ctype_class() + except Exception: + return 'i8*' + size = getattr(inst, 'Size', None) + is_signed = getattr(inst, 'IsSigned', None) + if size is None or size == 0: + if is_signed is None: + return 'void' + return 'i8*' + if is_signed is None: + float_map = {8: 'half', 16: 'half', 32: 'float', 64: 'double', 128: 'fp128'} + return float_map.get(size, f'f{size}') + return f'i{size}' + + _llvm_to_ctype_cache = None + + @classmethod + def LLVMToCType(cls, llvm_str): + if cls._llvm_to_ctype_cache is None: + cls._build() + cls._llvm_to_ctype_cache = {} + for name, ctype_cls in cls._name_to_class.items(): + pos = getattr(ctype_cls, 'position', frozenset()) + if CType.PREFIX in pos and CType.BASE not in pos: + continue + llvm_key = cls.CTypeToLLVM(ctype_cls) + if llvm_key and llvm_key not in cls._llvm_to_ctype_cache: + cls._llvm_to_ctype_cache[llvm_key] = ctype_cls + return cls._llvm_to_ctype_cache.get(llvm_str) + + @staticmethod + def CTypeToCName(ctype_class) -> str: + """从 CType 类推导 C 类型名称 (用于 printf 格式化等) + + 规则: + - 优先使用 CName 属性 (如 'size_t', 'void', 'int32_t') + - IsSigned is None 且 Size > 0 → 浮点: float/double/long double + - IsSigned is True → 有符号整数: char/short/int/long long + - IsSigned is False → 无符号整数: unsigned char/unsigned short/unsigned int/unsigned long long + """ + if ctype_class is None: + return '' + try: + inst = ctype_class() + except Exception: + return '' + cname = getattr(inst, 'CName', None) + if cname: + return cname + size = getattr(inst, 'Size', None) + is_signed = getattr(inst, 'IsSigned', None) + if size is None: + return '' + if is_signed is None and size > 0: + float_cname = {32: 'float', 64: 'double', 128: 'long double'} + return float_cname.get(size, 'double') + int_cname_signed = {8: 'char', 16: 'short', 32: 'int', 64: 'long long'} + int_cname_unsigned = {8: 'unsigned char', 16: 'unsigned short', 32: 'unsigned int', 64: 'unsigned long long'} + if is_signed: + return int_cname_signed.get(size, 'int') + else: + return int_cname_unsigned.get(size, 'unsigned int') + + @classmethod + def NameToLLVM(cls, name: str) -> str: + """根据 Python 类型名推导 LLVM IR 类型 (如 'CFloat64T' -> 'double') + + 修饰符类型 (CConst, CStatic 等) 返回空字符串。 + 指针类型 (CPtr) 返回 'i8*'。 + 未知类型返回 None。 + """ + cls._build() + import sys + mod = sys.modules.get(__name__) + if mod and hasattr(mod, name): + obj = getattr(mod, name) + if isinstance(obj, type) and issubclass(obj, CType): + return cls.CTypeToLLVM(obj) + return None + + @classmethod + def NameToCName(cls, name: str) -> str: + """根据 Python 类型名推导 C 类型名 (如 'CInt32T' -> 'int')""" + ctype_class = cls.GetClassByName(name) + if ctype_class is not None: + return cls.CTypeToCName(ctype_class) + return None + + @classmethod + def CNameToClass(cls, cname: str): + """根据 C 类型名获取 CType 类 (如 'int32_t' -> t.CInt32T, 'unsigned char' -> t.CUnsignedChar)""" + cls._build() + return cls._cname_to_class.get(cname) + + @classmethod + def ResolveName(cls, name: str): + """解析类型名到 (CType类, 指针层级) + + 支持的格式: + - Python 类名: 'CInt32T' -> (t.CInt32T, 0) + - C 类型名: 'int32_t' -> (t.CInt32T, 0) + - stdint 大写别名: 'INT32' -> (t.CInt32T, 0) + - 指针别名: 'INT32PTR' -> (t.CInt32T, 1) + - 大写别名: 'BYTE' -> (t.CUnsignedChar, 0), 'DWORD' -> (t.CUInt32T, 0) + - 浮点别名: 'FLOAT64' -> (t.CFloat64T, 0) + - void指针: 'VOIDPTR' -> (t.CVoid, 1) + """ + cls._build() + direct = cls._name_to_class.get(name) + if direct is not None: + pos = getattr(direct, 'position', frozenset()) + ptr_level = 1 if CType.POINTER in pos and CType.BASE not in pos else 0 + return (direct, ptr_level) + cnameres = cls._cname_to_class.get(name) + if cnameres is not None: + return (cnameres, 0) + if name.endswith('PTR'): + base_name = name[:-3] + base_result = cls.ResolveName(base_name) + if base_result is not None: + return (base_result[0], base_result[1] + 1) + if name.startswith('FLOAT') and name[5:].isdigit(): + bits = int(name[5:]) + float_name = f'CFloat{bits}T' + float_cls = cls._name_to_class.get(float_name) + if float_cls is not None: + return (float_cls, 0) + _UPPER_ALIAS = { + 'BYTE': 'CUInt8T', 'INT8': 'CInt8T', 'UINT8': 'CUInt8T', + 'WORD': 'CUInt16T', 'INT16': 'CInt16T', 'UINT16': 'CUInt16T', + 'DWORD': 'CUInt32T', 'INT32': 'CInt32T', 'UINT32': 'CUInt32T', + 'UINT': 'CUnsignedInt', 'INT': 'CInt', + 'QWORD': 'CUInt64T', 'INT64': 'CInt64T', 'UINT64': 'CUInt64T', + 'INTPTR': 'CIntPtrT', 'UINTPTR': 'CUIntPtrT', + 'SIZE_T': 'CSizeT', 'SSIZE_T': 'CPtrDiffT', 'PTRDIFF_T': 'CPtrDiffT', + 'VOID': 'CVoid', + } + alias = _UPPER_ALIAS.get(name) + if alias: + alias_cls = cls._name_to_class.get(alias) + if alias_cls is not None: + return (alias_cls, 0) + return None + + +_build_type_maps() \ No newline at end of file diff --git a/lib/utils/helpers.py b/lib/utils/helpers.py new file mode 100644 index 0000000..5519a70 --- /dev/null +++ b/lib/utils/helpers.py @@ -0,0 +1,41 @@ +# 工具函数 + +import os +import subprocess +from lib.constants.config import ERROR_MESSAGES + + +def DetectFileType(FilePath): + """检测文件类型""" + _, ext = os.path.splitext(FilePath) + return ext.lower() + + +def ExecuteCommand(command, shell=True, CaptureOutput=True, text=True): + """执行命令""" + try: + result = subprocess.run( + command, + shell=shell, + check=True, + capture_output=CaptureOutput, + text=text + ) + return result + except subprocess.CalledProcessError as e: + print(f'{ERROR_MESSAGES["COMPILE_FAILED"]}: {e}') + if e.stderr: + print(f'Error output: {e.stderr}') + return None + + +def AppendFileContent(FilePath, content): + """追加文件内容""" + try: + with open(FilePath, 'a', encoding='utf-8') as f: + f.write(content) + f.write('\n') + return True + except Exception as e: + print(f'Failed to append to file {FilePath}: {e}') + return False diff --git a/pt b/pt new file mode 100644 index 0000000..6acf50e --- /dev/null +++ b/pt @@ -0,0 +1,121 @@ +用Python做一个适用于 自制操作系统 的 编译器,用于实现Python转C,使用ast抽象语法树的解析转换文件内容(C到Python用pycparser) + +需要达到一下要求: + 1.不需要支持第三方或自带的模块 + 2.需要支持全部内部的定义方法,包括关键字,比如if for while break continue等,语句判断需要支持and or not is == != >= <= > < 等。 + 3.需要支持乘法、除法加法减法和异或计算。 + 3.True 和 False 通过定义宏1/0实现。 + 4.class转换比较复杂(支持面向对象),而且不能使用任何库,转换为C的类内常量和类外函数,Python通过映射表映射到函数上。 + 5.你需要书写c.py和t.py,如果有导入xxx的库名为c或t直接忽略,这是py2c的内部语义库。 + 其它所有import xxx或from xxx import xxx统一都翻译为#include xxx + 注意不能忽略,只有c和t可以忽略,其它的都要翻译为#include xxx,并且注释上原语句,在再次Python化时就可以直接套用原语句了 + 6.import 只需要 include对应的文件,import的文件应该已经一起被翻译成c或h了, + 从别的模块导入的函数需要去掉模块名称,而且要加上namespce处理,注意代码缩进。 + 7.注意函数调用和结构体实例化的实现,还有value和key不准变成None。 + 8.请你实现,并且注意C的极端小众的表达,并想好如何在Python中语义化表达,比如asm,range简化,class简化,typedef 和其后缀,指针操作,define,宏。 + 9.有一些C中的极端语句,Python无法语义化,比如asm,指针操作等指令。 + 提供一个扩展库c.pyi,py2c在转化时直接忽略import c等相关语句,将c.*比如c.asm("""""", *args, ...)直接转为C asm具体语义, + 比如 asm volatile ( + "movb $0x0e, %%ah\n" + "int $0x10\n" + : : "a"(c) + );这种语句和类似特殊语句的实现 + 10.支持双向转换(py->c,c->py),对于不知道含义的函数就当没看见就好了,直接按照通用语义转换。 + 11.支持内存地址硬编码赋值等(c.py) + 12.强制类型转换赋值 + 13.区分class xxx()和class xxx(c.class_point),普通结构体和结构体指针 + 14.支持结构体成员嵌套访问 + 15.支持结构体数组+指针索引访问,实现结构体数组的Python语义映射(l: c.class_list = []) + 16.static 关键字支持(i: t.Static | t.CInt) + 17.支持栈指针直接操作,ESP,语义映射 + 18.支持宏常量强制类型转换(依赖c.py) + 19.支持高级位运算和多层嵌套逻辑或位运算组合 + 20.对于#define宏,使用t.CDefine(t.CType)作为类型表示 + 21.对于仅声明暂不定义的量,用xxx: xxx = c.State + 22.对于Python的函数,要求其返回值和参数必须注解,def example(e1: t.CType) -> t.CType: xxx + 这样才能正确转换为C函数,比如def xxx(e1: t.CChar) -> t.CInt: xxx转为int xxx(char e1) {xxx}。 + 若函数无返回值,可以写 def xxx(e1: t.CChar) -> None: xxx或def xxx(e1: t.CChar) -> t.CVoid: xxx 或不进行注解 +对于语法,需要写在c.py。 +对于类型,需要写在t.py,比如c_int、c_char等,而不是直接写int,不然会出现冲突。 +c.py和t.py的定义都需要写元数据以及语法定义,通过元数据和元函数来实现具体的语法定义,以便于扩展,比如 +class CInt(t.CType): + def __init__(self): + self.CName = 'int' + super().__init__() + def ... + 23.对于C->Py和Py->C的翻译,更多地通过c.py和t.py中t.CType和c.CGrammar来实现,也就是在通过ast或pycparser解析后, + 如果可以的话把数据类型交给t.CType委托处理,语法给c.CGrammar委托处理,而不是硬编码在Py2C主程序中。 + 24.禁止使用硬编码来偷懒! +对于需要多个类型的情况,比如 static char *str = "hello"; +在 Python 中仅需定义 str: t.CStatic | t.Char | t.Ptr = "hello"; +无需定义 t.CStaticCharPtr 这种复杂的类型,直接用 t.CStatic | t.Char | t.Ptr 即可。 +允许使用元函数修改多种类型的组合方式,比如 +class CStatic(t.CType): + def __init__(self): + self.CName = 'static char *' + super().__init__() + def __merge__(self, types: list): + # 此处 types 为多个父为 t.Ctypes,比如 [t.CStatic, t.Char, t.Ptr] + # 在此处我需要返回我修改后的 types,比如假设我与 t.Ptr 冲突(实际上并不冲突,只是作示例),那就返回 [t.CStatic, t.Char] + if t.Ptr in types: + types.remove(t.Ptr) + return types +以此类推,支持更多种类型。 +你需要默认支持的类型: +char +int +short +long +float +double +void +unsigned char +unsigned int +unsigned short +unsigned long +signed char +struct +union +enum +typedef +auto +register +static +extern +const +volatile +size_t +int8_t +int16_t +int32_t +int64_t +uint8_t +uint16_t +uint32_t +uint64_t +intptr_t +uintptr_t +ptrdiff_t +wchar_t +char16_t +char32_t +bool +_Complex +_Imaginary + +注意,转换后的python或c需要符合其语法规范,不能有语法错误。 +还有就是,C中的所有函数,都请你当作普通函数(定义在其它h文件),也就是不需要考虑函数的定义和实现。 +如果有-wh参数,后面会带着几个h文件,也就是这些函数的定义,你可以进行参考,如果没有就算了,按默认方法处理。 +代码格式要求:所有命名都使用帕斯卡命名法,首字母大写,缩写大写,不需要注释,最简代码,但人类可读。 +你可以写一个入口程序,再写多个小库在./lib中,来降低复杂度,./lib文件夹已创建,无需检查。 +禁止使用硬编码偷懒! + +执行方法: +python TransPyC.py -f test.py -o test.c +python TransPyC.py -f test.c -o test2.py -wh test.h +仅需一个Python文件 + +然后你需要尝试将test.c转为test.py并验证是否正确,再将test.py转为test2.c并验证是否和test.c语义相同。 +test.c已存在,这是一个略微复杂的操作系统C程序,需要你进行完整转换。 +我已经给了你example_test.py,作为目标转换结果的参考。 +中文输出 \ No newline at end of file diff --git a/rp.py b/rp.py new file mode 100644 index 0000000..72de661 --- /dev/null +++ b/rp.py @@ -0,0 +1,80 @@ +import os + +# 目录定义 +ROOT_DIR = r"./lib/" +EXTRA_FILES = [ + "./TransPyC.py", + "./StubGen.py", + "./Projectrans.py" +] + +def snake_to_upper_camel(s: str) -> str: + if not s: + return s + + if s.startswith('_'): + first = '_' + rest = s[1:] + else: + first = '' + rest = s + + parts = rest.split('_') + pascal = ''.join(part.capitalize() for part in parts) + return first + pascal + +while True: + old_str = input("请输入原蛇形字符串:").strip() + new_input = input("替换内容(留空自动转大驼峰):").strip() + + if not old_str: + print("错误:原字符串不能为空\n") + continue + + total_mod = 0 + + # ====================== 1. 处理 lib 下所有 .py ====================== + for root, _, files in os.walk(ROOT_DIR): + for file in files: + if file.endswith(".py"): + file_path = os.path.join(root, file) + try: + with open(file_path, "r", encoding="utf-8") as f: + content = f.read() + + if new_input == "": + replace_target = snake_to_upper_camel(old_str) + new_content = content.replace(old_str, replace_target) + else: + new_content = content.replace(old_str, new_input) + + if new_content != content: + with open(file_path, "w", encoding="utf-8") as f: + f.write(new_content) + print(f"已修改:{file_path}") + total_mod += 1 + except Exception as err: + print(f"异常 {file_path}:{err}") + + # ====================== 2. 处理根目录下 3 个指定文件 ====================== + for file_path in EXTRA_FILES: + if os.path.exists(file_path): + try: + with open(file_path, "r", encoding="utf-8") as f: + content = f.read() + + if new_input == "": + replace_target = snake_to_upper_camel(old_str) + new_content = content.replace(old_str, replace_target) + else: + new_content = content.replace(old_str, new_input) + + if new_content != content: + with open(file_path, "w", encoding="utf-8") as f: + f.write(new_content) + print(f"已修改:{file_path}") + total_mod += 1 + except Exception as err: + print(f"异常 {file_path}:{err}") + + print(f"\n处理完成,共计修改 {total_mod} 个文件\n") \ No newline at end of file diff --git a/t.py b/t.py new file mode 100644 index 0000000..38e7cfc --- /dev/null +++ b/t.py @@ -0,0 +1 @@ +from lib.includes.t import * \ No newline at end of file diff --git a/temp_error.txt b/temp_error.txt new file mode 100644 index 0000000..cdcc976 --- /dev/null +++ b/temp_error.txt @@ -0,0 +1 @@ +[编译终止] 1 个文件翻译失败 diff --git a/temp_error2.txt b/temp_error2.txt new file mode 100644 index 0000000..cdcc976 --- /dev/null +++ b/temp_error2.txt @@ -0,0 +1 @@ +[编译终止] 1 个文件翻译失败 diff --git a/test.py b/test.py new file mode 100644 index 0000000..a6cb74c --- /dev/null +++ b/test.py @@ -0,0 +1,172 @@ +#include +from stdint import * +#include +#include +#include +import t, c + +MAX_INSN_LEN: t.CDefine = 15 # x86_64 最长指令 15 字节 +TABLE_SIZE: t.CDefine = 256 + +# 指令名表( opcode → 指令名 ) +opcode_table: t.CConst | list[str, TABLE_SIZE] +def opcode_init(): + global opcode_table + opcode_table[0x00] = "add"; opcode_table[0x01] = "add"; opcode_table[0x02] = "add"; opcode_table[0x03] = "add" + opcode_table[0x04] = "add"; opcode_table[0x05] = "add"; opcode_table[0x08] = "or"; opcode_table [0x09] = "or" + opcode_table[0x0A] = "or"; opcode_table [0x0B] = "or"; opcode_table [0x0C] = "or"; opcode_table [0x0D] = "or" + opcode_table[0x10] = "adc"; opcode_table[0x11] = "adc"; opcode_table[0x12] = "adc"; opcode_table[0x13] = "adc" + opcode_table[0x14] = "adc"; opcode_table[0x15] = "adc"; opcode_table[0x18] = "sbb"; opcode_table[0x19] = "sbb" + opcode_table[0x1A] = "sbb"; opcode_table[0x1B] = "sbb"; opcode_table[0x1C] = "sbb"; opcode_table[0x1D] = "sbb" + opcode_table[0x20] = "and"; opcode_table[0x21] = "and"; opcode_table[0x22] = "and"; opcode_table[0x23] = "and" + opcode_table[0x24] = "and"; opcode_table[0x25] = "and"; opcode_table[0x28] = "sub"; opcode_table[0x29] = "sub" + opcode_table[0x2A] = "sub"; opcode_table[0x2B] = "sub"; opcode_table[0x2C] = "sub"; opcode_table[0x2D] = "sub" + opcode_table[0x30] = "xor"; opcode_table[0x31] = "xor"; opcode_table[0x32] = "xor"; opcode_table[0x33] = "xor" + opcode_table[0x34] = "xor"; opcode_table[0x35] = "xor"; opcode_table[0x38] = "cmp"; opcode_table[0x39] = "cmp" + opcode_table[0x3A] = "cmp"; opcode_table[0x3B] = "cmp"; opcode_table[0x3C] = "cmp"; opcode_table[0x3D] = "cmp" + opcode_table[0x40] = "rex"; opcode_table[0x41] = "rex.b"; opcode_table[0x42] = "rex.x"; opcode_table[0x43] = "rex.xb" + opcode_table[0x44] = "rex.r"; opcode_table[0x45] = "rex.rb"; opcode_table[0x46] = "rex.rx"; opcode_table[0x47] = "rex.rxb" + opcode_table[0x48] = "rex.w"; opcode_table[0x49] = "rex.wb"; opcode_table[0x4A] = "rex.wx"; opcode_table[0x4B] = "rex.wxb" + opcode_table[0x4C] = "rex.wr"; opcode_table[0x4D] = "rex.wrb"; opcode_table[0x4E] = "rex.wrx"; opcode_table[0x4F] = "rex.wrxb" + opcode_table[0x50] = "push"; opcode_table[0x51] = "push"; opcode_table[0x52] = "push"; opcode_table[0x53] = "push" + opcode_table[0x54] = "push"; opcode_table[0x55] = "push"; opcode_table[0x56] = "push"; opcode_table[0x57] = "push" + opcode_table[0x58] = "pop"; opcode_table[0x59] = "pop"; opcode_table[0x5A] = "pop"; opcode_table[0x5B] = "pop" + opcode_table[0x5C] = "pop"; opcode_table[0x5D] = "pop"; opcode_table[0x5E] = "pop"; opcode_table[0x5F] = "pop" + opcode_table[0x66] = "opsize"; opcode_table[0x67] = "addrsize" + opcode_table[0x70] = "jo"; opcode_table [0x71] = "jno"; opcode_table[0x72] = "jb"; opcode_table [0x73] = "jnb" + opcode_table[0x74] = "jz"; opcode_table [0x75] = "jnz"; opcode_table[0x76] = "jbe"; opcode_table[0x77] = "ja" + opcode_table[0x78] = "js"; opcode_table [0x79] = "jns"; opcode_table[0x7A] = "jp"; opcode_table [0x7B] = "jnp" + opcode_table[0x7C] = "jl"; opcode_table [0x7D] = "jge"; opcode_table[0x7E] = "jle"; opcode_table[0x7F] = "jg" + opcode_table[0x80] = "alu"; opcode_table[0x81] = "alu"; opcode_table[0x83] = "alu", + opcode_table[0x88] = "mov"; opcode_table[0x89] = "mov"; opcode_table[0x8A] = "mov"; opcode_table[0x8B] = "mov" + opcode_table[0x90] = "nop" + opcode_table[0xB8] = "mov"; opcode_table[0xB9] = "mov"; opcode_table[0xBA] = "mov"; opcode_table[0xBB] = "mov" + opcode_table[0xBC] = "mov"; opcode_table[0xBD] = "mov"; opcode_table[0xBE] = "mov"; opcode_table[0xBF] = "mov" + opcode_table[0xC3] = "ret"; opcode_table[0xC9] = "leave"; opcode_table[0xCB] = "retf"; opcode_table[0xCD] = "int" + opcode_table[0xE8] = "call"; opcode_table[0xE9] = "jmp"; opcode_table[0xEB] = "jmp" + opcode_table[0xFF] = "push/call" + + +# 64位通用寄存器表 +reg64_table: t.CConst | list[str, 16] = [ + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +] + +class insn: + bytes: list[UINT8, MAX_INSN_LEN]; + length: UINT8 + addr: t.CUInt64T + mnemonic: t.CConst | str + opstr: list[t.CChar, 64] + +# 解析 MOD-R/M 字节 +@c.CReturn(t.CInt, t.CInt, t.CInt) +def decode_modrm(modrm: UINT8): + # mod, reg, rm + return ((modrm >> 6) & 3), ((modrm >> 3) & 7), ((modrm >> 0) & 7) + +# 反汇编单条 x86_64 指令 +def disassemble_x86_64(code: t.CConst | UINT8PTR, addr: UINT64, out: insn | t.CPtr) -> t.CInt: + memset(out, 0, insn.__sizeof__()) + length: UINT8 = 1 # code[length++] + op: UINT8 = code[0] + out.addr = addr + out.mnemonic = opcode_table[op] if opcode_table[op] else "db" + out.bytes[0] = op + + # 单字节指令(nop / ret / 等) + if op == 0x90 or op == 0xC3 or op == 0xCB or op == 0xC9: + out.length = length + return 1 + + # 跳转/调用(E8/E9/EB) + if op == 0xE8 or op == 0xE9 or op == 0xEB: + off: INT32 + if op == 0xEB: + off = INT8(code[length]) + length += 1 + else: + off = c.Deref(INT32PTR(c.Addr(code[length]))) + length += 4 + snprintf(out.opstr, out.opstr.__sizeof__(), "0x%lx", addr + length + off) + out.length = length + return 1 + + # 条件跳转(70~7F) + if (op & 0xF0) == 0x70: + off: INT8 = code[length] + length += 1 + snprintf(out.opstr, out.opstr.__sizeof__(), "0x%lx", addr + length + off) + out.length = length + return 1 + + # MOV r64, imm64(B8~BF) + if (op & 0xF8) == 0xB8: + reg: int = op & 7 + imm: UINT64 = c.Deref(UINT64PTR(c.Addr(code[length]))) + length += 8 + snprintf(out.opstr, out.opstr.__sizeof__(), "%s, 0x%lx", reg64_table[reg], imm) + out.length = length + return 1 + + # 带 MOD-R/M 的指令(88/89/8A/8B/00~03 等) + if ((op & 0xC7) == 0x00 or (op & 0xC7) == 0x08 or + (op & 0xC7) == 0x10 or (op & 0xC7) == 0x18 or + (op & 0xC7) == 0x20 or (op & 0xC7) == 0x28 or + (op & 0xC7) == 0x30 or (op & 0xC7) == 0x38 or + op == 0x88 or op == 0x89 or op == 0x8A or op == 0x8B): + modrm: UINT8 = code[length] + length += 1 + length += 1 + mod: int + reg: int + rm: int + reg, rm, mod = decode_modrm(modrm) + snprintf(out.opstr, out.opstr.__sizeof__(), "%s, %s", reg64_table[reg], reg64_table[rm]) + out.length = length + return 1 + + # 未完全解码 → 按原始字节输出 + snprintf(out.opstr, out.opstr.__sizeof__(), "0x%02x", op); + out.length = length + return 1 + + +# 反汇编整个裸二进制文件 +def disassemble_file(): + # 这就是你的裸机二进制! + code: list[UINT8, None] = [ + 0x90, # nop + 0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00, # mov rax, 1 + 0xC3 # ret + ] + code_length: t.CSizeT = code.__sizeof__() + base_addr: UINT64 = 0x1000 + + print(";; x86_64 内嵌二进制反汇编\n") + print(";; 地址 指令字节 汇编\n") + + i: t.CSizeT = 0 + for i in range(code_length): + _insn: insn + disassemble_x86_64(code + i, base_addr + i, c.Addr(_insn)) + + # 打印地址 + printf("%08lx ", insn.addr) + + # 打印字节 + for j in range(_insn.length): + printf("%02x ", insn.bytes[j]) + for j in range(_insn.length, 10): + printf(" ") + + # 打印指令 + printf("%-6s %s\n", insn.mnemonic, insn.opstr); + + i += insn.length + +def main() -> int: + opcode_init() + disassemble_file() + return 0 diff --git a/test_debug.py b/test_debug.py new file mode 100644 index 0000000..3546fbc --- /dev/null +++ b/test_debug.py @@ -0,0 +1,32 @@ +import sys, ast +sys.path.insert(0, '.') +from lib.includes.t import CTypeRegistry +CTypeRegistry._build() + +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.core.Handles.HandlesTypeMerge import TypeMergeHandler +from lib.includes import t + +class MockTrans: + SymbolTable = {} + +trans = MockTrans() +handler = TypeMergeHandler(trans) + +# Parse "t.CVoid | t.CPtr" +code = "t.CVoid | t.CPtr" +tree = ast.parse(code, mode='eval') +binop = tree.body + +result = handler.MergeTypes(binop) +if result: + print(f'MergeTypes(t.CVoid | t.CPtr):') + print(f' BaseType: {result.BaseType}') + print(f' PtrCount: {result.PtrCount}') + print(f' IsVoid: {result.IsVoid}') + print(f' IsPtr: {result.IsPtr}') + print(f' IsTypedef: {result.IsTypedef}') + print(f' Name: {result.Name}') + print(f' ToString: {result.ToString()}') +else: + print('MergeTypes returned None') diff --git a/test_regex.py b/test_regex.py new file mode 100644 index 0000000..ac04290 --- /dev/null +++ b/test_regex.py @@ -0,0 +1,24 @@ +import re + +name = '1347c4edf991da6f.Widget' +ir_text = '%1347c4edf991da6f.Widget = type { i8*, i32, i32, i32, i32, i32, i8*, i32, i32, i32 }' +pattern = r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)' +print('Pattern:', pattern) +m = re.search(pattern, ir_text) +if m: + print('Match:', m.group(0)) +else: + print('No match') + +result = re.sub(pattern, r'%"' + name + r'"', ir_text) +print('Result:', result) + +ir_text2 = '%"1347c4edf991da6f.Widget" = type { i8*, i32, i32, i32, i32, i32, i8*, i32, i32, i32 }' +m2 = re.search(pattern, ir_text2) +if m2: + print('Match2:', m2.group(0)) +else: + print('No match2') + +result2 = re.sub(pattern, r'%"' + name + r'"', ir_text2) +print('Result2:', result2) diff --git a/test_sret b/test_sret new file mode 100644 index 0000000..6cf51f7 --- /dev/null +++ b/test_sret @@ -0,0 +1,27 @@ +=== AST Tree (Compact) === +Module(body=[Import(names=[alias(name='t'), alias(name='c')]), FunctionDef(name='get_rect', args=arguments(posonlyargs=[], args=[arg(arg='style', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())), arg(arg='th', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())), arg(arg='wx', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())), arg(arg='wy', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())), arg(arg='ww', annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()))], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='btn_w', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=10), simple=1), AnnAssign(target=Name(id='btn_h', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=10), simple=1), AnnAssign(target=Name(id='btn_x', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=BinOp(left=BinOp(left=Name(id='wx', ctx=Load()), op=Add(), right=Name(id='ww', ctx=Load())), op=Sub(), right=Name(id='btn_w', ctx=Load())), op=Sub(), right=Constant(value=4)), simple=1), AnnAssign(target=Name(id='btn_y', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=Name(id='wy', ctx=Load()), op=Add(), right=BinOp(left=BinOp(left=Name(id='th', ctx=Load()), op=Sub(), right=Name(id='btn_h', ctx=Load())), op=FloorDiv(), right=Constant(value=2))), simple=1), AnnAssign(target=Name(id='max_bx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=Name(id='btn_x', ctx=Load()), op=Sub(), right=Constant(value=2)), simple=1), AnnAssign(target=Name(id='min_bx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=BinOp(left=Name(id='max_bx', ctx=Load()), op=Sub(), right=Constant(value=2)), simple=1), Return(value=Tuple(elts=[Name(id='btn_w', ctx=Load()), Name(id='btn_h', ctx=Load()), Name(id='btn_x', ctx=Load()), Name(id='btn_y', ctx=Load()), Name(id='max_bx', ctx=Load()), Name(id='min_bx', ctx=Load())], ctx=Load()))], decorator_list=[Call(func=Attribute(value=Name(id='c', ctx=Load()), attr='CReturn', ctx=Load()), args=[Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())], keywords=[])], returns=Subscript(value=Name(id='tuple', ctx=Load()), slice=Tuple(elts=[Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load())], ctx=Load()), ctx=Load()), type_params=[]), FunctionDef(name='main', args=arguments(posonlyargs=[], args=[], kwonlyargs=[], kw_defaults=[], defaults=[]), body=[AnnAssign(target=Name(id='bw', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='bh', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='bx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='by', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='mbx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), AnnAssign(target=Name(id='mnbx', ctx=Store()), annotation=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), value=Constant(value=0), simple=1), Assign(targets=[Tuple(elts=[Name(id='bw', ctx=Store()), Name(id='bh', ctx=Store()), Name(id='bx', ctx=Store()), Name(id='by', ctx=Store()), Name(id='mbx', ctx=Store()), Name(id='mnbx', ctx=Store())], ctx=Store())], value=Call(func=Name(id='get_rect', ctx=Load()), args=[Constant(value=1), Constant(value=30), Constant(value=100), Constant(value=200), Constant(value=800)], keywords=[])), Expr(value=Call(func=Name(id='printf', ctx=Load()), args=[Constant(value='btn_w=%d btn_h=%d btn_x=%d btn_y=%d max_bx=%d min_bx=%d\n'), Name(id='bw', ctx=Load()), Name(id='bh', ctx=Load()), Name(id='bx', ctx=Load()), Name(id='by', ctx=Load()), Name(id='mbx', ctx=Load()), Name(id='mnbx', ctx=Load())], keywords=[])), Return(value=Constant(value=0))], decorator_list=[], returns=Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=Load()), type_params=[])], type_ignores=[]) + +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t +[GetCTypeInfo] Node type: Attribute, dump: Attribute(value=Name(id='t', ctx=Load()), attr='CInt', ctx=L... +[GetCTypeInfo-Attribute] 查询: 'CInt' ModulePath: t diff --git a/wiki/01-overview.md b/wiki/01-overview.md new file mode 100644 index 0000000..9b328f9 --- /dev/null +++ b/wiki/01-overview.md @@ -0,0 +1,355 @@ +# 01 - 语言概述与编译流程 + +## 语言定位 + +`Viper` 是一种 **系统级编程语言**,其语法基于 `Python`,但编译目标为 `LLVM IR`,最终生成原生机器码。`Viper` 不是 `Python` 的超集或子集,也不是"`C` 的语法糖"——它是一门拥有独立类型系统、独立编译模型、独立模块体系的语言。`Viper` 选择 `Python` 语法作为表达形式,是因为 `Python` 的 `AST` 可被标准库直接解析,从而将编译器的精力集中在语义翻译而非词法/语法分析上。同时也是因为 `Python` 是人类公认的可读性最高的语言。 + +而实际上,下文中所有提到的 `C` 语言都是为了便于使用 `C` 的底层开发者理解。由于历史原因,在旧版本中我们使用 `C` 来作为中间语言,如同旧版本的 `C++` 一样,但现在 `target="c"` 的路径已经完全删除,`C` 路径永久不再受维护。 + +### 核心设计决策 + +1. **Python 语法,LLVM 语义**:源文件是完全合法的 `Python` 语法,但通过 `t` 模块的类型注解系统赋予完全不同的语义 —— `t.CInt` 不是 `Python` 的 `int`,而是 `LLVM` 的 `i32` +2. **类型注解即编译指令**:Viper 的类型注解不是可选的提示,而是编译器生成 `LLVM IR` 的决定性依据。`x: t.CInt` 生成 `i32`,`x: t.CInt | t.CPtr` 生成 `i32*`,但无注解时会自动推导,详见下文。 +3. **两阶段编译**:先从源文件提取声明接口(`.pyi` + `.stub.ll`),再使用声明接口翻译源文件为含代码的 `.ll`。这是 `Viper` 区别于简单"`Python` 转 `C`"工具的关键架构 +4. **`SHA1` 命名空间**:每个源文件按内容 `SHA1` 哈希命名,非导出函数和结构体自动加上 `SHA1` 前缀,从根本上消除跨模块的符号冲突 +5. **万物皆数据**:为便于底层开发,实际上所有的变量和类型一般并不适用于鸭子类型,但在语义层面我们会尽可能贴近鸭子类型。 + +### 与 `Python` 的关系 + +| 特性 | `Python` | `Viper` | +|------|--------|-------| +| 类型系统 | 动态类型 | 静态类型(通过 `t` 模块注解,编译时确定) | +| 内存管理 | `GC` 自动回收 | 手动管理,无 `GC`,无运行时 | +| 运行时 | 解释执行 + 字节码 | 编译为原生机器码(通过 `LLVM`) | +| 对象模型 | 万物皆对象 | 仅 `@t.Object` 类有对象语义,`@t.CVTable` 为多态,普通 `class` 仅为结构体布局 | +| 标准库 | `Python` 标准库 | `Viper` 标准库(`includes/`)+ `ViperOS SDK` | +| 空值 | `None` | `None`(编译为 `NULL`/零值) | +| 模块系统 | 运行时 `import` | 编译时解析,插入 `.stub.ll`,`SHA1` 命名空间隔离 | + +### 与 C 的关系 + +Viper 编译后的代码在底层等价于 `C` 编译后的机器码(都经过 LLVM),但 Viper 在语言层面提供了 C 所没有的能力: + +- **SHA1 命名空间**:自动消除符号冲突,无需手动管理 `static`/命名前缀 +- **类型组合语法**:`t.CConst | t.CInt | t.CPtr` 比 `const int*` 更具组合性 +- **声明式内联汇编**:`c.Asm(f"mov {c.AsmOut(x, t.ASM_DESCR.OUTPUT_REG)}, rdi")` 比裸 `__asm__` 更安全,也更具可读性。 +- **结构化预处理**:`c.CIfdef`/`c.CEndif()` 替代 `#ifdef`/`#endif`。 +- **面向对象**:`@t.Object` + `@t.CVTable` 提供 `vtable` 支持的 `OOP` +- **存根驱动的模块系统**:`.pyi` 存根文件实现跨模块类型解析,无需头文件 +- **更多内容**:额外更多的不依赖操作系统的函数和语法 + +## 两阶段编译流程 + +Viper 的编译由 `Projectrans.py` 驱动,分为两个阶段。这是 Viper 编译模型的核心,理解两阶段编译是理解 `t.CDefine`、`t.CExport`、`t.CInline` 等关键概念的前提。 + +``` +源文件 (.py) ────────────────────────────────────────────────────── + │ │ + │ ┌─────────────── 阶段一:声明提取 ───────────────┐ │ + │ │ │ │ + │ │ 1. 计算源文件 SHA1 │ │ + │ │ 2. 生成 .pyi(签名存根) │ │ + │ │ 3. 构建结构体注册表 │ │ + │ │ 4. 生成 .stub.ll(LLVM IR 声明) │ │ + │ │ │ │ + │ └────────────────────────────────────────────────┘ │ + │ │ + │ ┌─────────────── 阶段二:代码翻译 ───────────────┐ │ + │ │ │ │ + │ │ 1. 加载所有 .pyi 和 .stub.ll │ │ + │ │ 2. 构建共享符号表 │ │ + │ │ 3. 收集内联函数符号 │ │ + │ │ 4. 翻译源文件 → .ll(含代码) │ │ + │ │ 5. llc 编译 → .o(目标文件) │ │ + │ │ 6. ld.lld 链接 → 可执行文件 │ │ + │ │ │ │ + │ └────────────────────────────────────────────────┘ │ + │ │ + └──────────────────────────────────────────────────────────────┘ +``` + +### 阶段一:声明提取(Phase1Generator) + +阶段一的目标是从每个源文件提取**声明接口**,使其他模块在阶段二翻译时能够正确解析跨模块引用。 + +#### 步骤 1:可达文件发现与拓扑排序 + +从入口文件(`main.py` 或 `project.json` 指定)出发,通过 `import` 语句递归遍历,找出所有可达的 `.py` 源文件。然后对文件进行拓扑排序,确保被依赖的模块先被处理。 + +``` +main.py → import serial → import drivers.serial.uart.serial → ... +``` + +#### 步骤 2:生成 `.pyi` 签名存根 + +对每个源文件,计算其内容的 SHA1 哈希(16位),然后调用 `PythonToStubConverter` 生成签名存根文件 `.pyi`。 + +**SHA1 计算方式**: +```python +sha1 = hashlib.sha1(content.encode('utf-8')).hexdigest()[:16] +``` + +**存根文件的内容规则**: + +| 源文件元素 | 存根文件中的表示 | +|-----------|----------------| +| `t.CDefine` 常量 | 保留原样(含赋值):`MAX_SIZE: t.CDefine = 1024` | +| `t.CDefine` 函数(返回 `t.CDefine` 的函数) | 保留完整函数体(宏展开需要) | +| 普通函数 | 仅保留签名,添加 `| c.State`:`def foo(x: t.CInt) -> t.CVoid | c.State: pass` | +| 类定义 | 保留成员类型注解和方法签名 | +| 全局变量 | 添加 `t.CExtern`:`x: t.CExtern | t.CInt` | +| `c.CIfdef`/`c.CEndif()` 等预处理指令 | 保留原样 | +| `import` 语句 | 保留原样 | + +**关键设计**:`t.CDefine` 常量和 `t.CDefine` 函数在存根中**保留完整定义**(包括赋值和函数体),因为它们是编译时常量/宏,其他模块引用时需要完整展开。普通函数只保留签名并标记 `c.State`(仅声明),因为函数体在阶段二生成。 + + +#### 步骤 3:构建结构体注册表 + +扫描所有已生成的 `.pyi` 文件,提取: +- **结构体名称集合**:所有非枚举、非异常的 `class` 定义 +- **枚举名称集合**:继承 `t.CEnum` 的类 +- **异常名称集合**:继承 `Exception` 的类 +- **结构体→SHA1 映射**:记录每个结构体定义在哪个模块中 + +这个注册表用于阶段一的声明生成和阶段二的类型解析,确保跨模块的结构体引用使用正确的 SHA1 命名空间。 + +#### 步骤 4:生成 `.stub.ll` LLVM IR 声明 + +对每个 `.pyi` 文件,由 `DeclarationGenerator` 生成对应的 LLVM IR 声明文件 `.stub.ll`。 + +**声明生成规则**: + +| 元素 | 生成的 LLVM IR | +|------|---------------| +| 普通函数 | `declare void @".foo"(i32)` — 非 CExport 函数加 SHA1 前缀 | +| CExport 函数 | `declare i32 @main()` — CExport 函数不加前缀,全局可见 | +| 结构体 | `%".ClassName" = type { i32, i32* }` — 类型名加 SHA1 前缀 | +| 全局变量 | `@varname = external global i32` | +| `t.CDefine` 常量 | **不生成声明**(编译时常量,直接内联展开) | +| `t.CTypedef` 别名 | **不生成声明**(类型别名,在类型解析时展开) | +| 枚举 | 为每个枚举成员生成 `@__config_EnumName_member = external global i32` | + +**增量编译**:如果 `.pyi` 或 `.stub.ll` 已存在,则跳过生成(缓存命中)。只有源文件内容变化导致 SHA1 变化时才重新生成。 + +### 阶段二:代码翻译(Phase2Translator) + +阶段二使用阶段一生成的声明接口,将源文件翻译为包含完整代码的 LLVM IR。 + +#### 步骤 1:加载声明接口 + +加载 `temp/` 目录中所有的 `.pyi` 和 `.stub.ll` 文件,构建: +- `sig_files`:SHA1 → `.pyi` 文件路径映射 +- `stub_files`:SHA1 → `.stub.ll` 文件路径映射 +- `sha1_map`:SHA1 → 源文件相对路径映射 + +#### 步骤 2:构建共享符号表 + +一次性构建所有文件共享的符号表数据,避免每个文件重复加载。将所有 `.pyi` 存根和 `.stub.ll` 声明中的类型信息注册到统一的 `SymbolTable` 中。 + +#### 步骤 3:收集内联函数符号 + +扫描 `includes/` 目录中被引用的模块,收集标记为 `t.CInline` 的函数。内联函数的完整 AST body 被保存,在翻译调用点时直接展开。值得注意的是,和 C 语言不同,`t.CInline` 不是优化建议,而是强制性的。 + +#### 步骤 4:翻译源文件 + +对每个源文件,使用 `TransPyC` 翻译器将 Python AST 翻译为 LLVM IR: +1. 将对应模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部 +2. 所有被引用模块的 `.stub.ll` 声明也被嵌入 +3. 翻译 AST 节点为 LLVM IR 指令 +4. 输出 `.ll` 文件 + +#### 步骤 5:编译与链接 + +- `llc`:将每个 `.ll` 编译为 `.o` 目标文件 +- `ld.lld`:将所有 `.o` 链接为最终可执行文件 + +## SHA1 命名空间机制 + +SHA1 命名空间是 Viper 解决跨模块符号冲突的核心机制。 + +### 问题 + +在 C 语言中,多个模块可能定义同名函数或结构体,导致链接时符号冲突。C 的解决方案是 `static`(限制可见性)和命名前缀(手动避免冲突)。 + +### Viper 的解决方案 + +Viper 使用源文件内容的 SHA1 哈希作为命名空间前缀: + +``` +源文件 A.py(SHA1 = a1b2c3d4e5f6g7h8)中定义: + class Point: x: t.CInt; y: t.CInt + def draw(p: Point) -> t.CVoid: ... + +源文件 B.py(SHA1 = i9j0k1l2m3n4o5p6)中也定义: + class Point: x: t.CFloat; y: t.CFloat # 不同的结构体! + def draw(p: Point) -> t.CVoid: ... + +编译后: + A.py 的结构体 → %"a1b2c3d4e5f6g7h8.Point" = type { i32, i32 } + A.py 的函数 → declare void @"a1b2c3d4e5f6g7h8.draw"(%"a1b2c3d4e5f6g7h8.Point"*) + + B.py 的结构体 → %"i9j0k1l2m3n4o5p6.Point" = type { float, float } + B.py 的函数 → declare void @"i9j0k1l2m3n4o5p6.draw"(%"i9j0k1l2m3n4o5p6.Point"*) +``` + +**没有符号冲突**——即使两个模块定义了同名类型和函数,它们的 LLVM IR 符号也是不同的。即便有两个内容完全相同的文件也不会冲突,他们会被识别为同一个文件,然后进行单次编译。 + +### SHA1 前缀的豁免:`t.CExport` + +标记为 `t.CExport` 的函数**不加 SHA1 前缀**,保持原始函数名。这是模块向外部暴露 API/ABI 的机制: + +```python +# main.py — 入口函数,必须全局可见 +def main() -> t.CInt | t.CExport: + return 0 + +# 编译后:define i32 @main() — 无 SHA1 前缀 +``` + +```python +# serial.py — 驱动接口,对外暴露 +def init() -> t.CVoid | t.CExport: + serial_puts("init\n") + +# 编译后:define void @init() — 无 SHA1 前缀,其他模块可直接调用 +``` + +### SHA1 与增量编译 + +SHA1 同时服务于增量编译: +- 源文件内容不变 → SHA1 不变 → `.pyi` 和 `.stub.ll` 缓存命中,跳过阶段一 +- 源文件内容变化 → SHA1 变化 → 重新生成声明接口 +- `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,供阶段二加载 + +理论上,如果一个未经变动的模块的依赖路径上存在变动的模块,暂时的方法是将其简单做 SHA1 替换,暨将旧 SHA1 替换为新 SHA1,但不适用于签名改变的情况,不过签名改变这个未经变动的模块必然也需要改变,但是由于宏展开的存在,不能完全保证不会发生错误情况。且依赖路径的 SHA1 替换成功性未经完整测试,可能出现未定义行为。 + +## `t.CDefine` 深度解析 + +`t.CDefine` 是 Viper 中最特殊的类型——它不是数据类型,而是**编译时元指令**,控制编译器的代码生成行为。 + +### `t.CDefine` 常量 + +```python +MAX_SIZE: t.CDefine = 1024 +PAGE_SIZE: t.CDefine = 4096 +FA_READ: t.CDefine = 0x01 +CPU_FEATURE_FPU: t.CDefine = (1 << 0) +``` + +**编译行为**: +1. **阶段一**:存根生成器保留 `t.CDefine` 常量的完整定义(包括赋值值),因为其他模块可能引用此常量 +2. **阶段一**:`.stub.ll` 声明生成器**跳过** `t.CDefine` 常量,不生成 `external global` 声明 +3. **阶段二**:翻译器遇到 `t.CDefine` 常量的引用时,直接内联其值,不生成任何加载指令 + +这意味着 `t.CDefine` 常量在 LLVM IR 层面**不存在**——它们在编译时被完全展开,等价于 C 的 `#define` 宏。 + +### `t.CDefine` 函数 + +当函数的返回类型注解包含 `t.CDefine` 时,该函数被编译器视为**宏函数**: + +```python +def MAKE_FLAG(bit) -> t.CDefine: + return (1 << bit) + +def GET_PAGE_ORDER(size) -> t.CDefine: + return size // PAGE_SIZE +``` + +**编译行为**: +1. **阶段一**:存根生成器保留 `t.CDefine` 函数的**完整函数体**(不像普通函数那样只保留签名) +2. **阶段二**:翻译器遇到 `t.CDefine` 函数的调用时,将调用内联展开为函数体的计算结果 + +`t.CDefine` 函数在 LLVM IR 中**不生成函数定义**——它们是纯粹的编译时宏。 + +### `t.CDefine` 与类型组合 + +`t.CDefine` 可以与具体类型组合使用,为常量指定底层类型: + +```python +CODE_SEG: t.CDefine | t.CUInt16T = 0x08 +DATA_SEG: t.CDefine | t.CUInt16T = 0x10 +``` + +这表示常量在类型检查时被视为 `t.CUInt16T`(`uint16_t`),但在代码生成时仍然内联展开。 + +## `t.CExport` 深度解析 + +`t.CExport` 控制函数的符号可见性,是 SHA1 命名空间的豁免机制。 + +### 语义 + +| 修饰 | LLVM IR 函数名 | 链接可见性 | 用途 | +|------|---------------|-----------|------| +| 无修饰 | `@.funcname` | 模块内部 | 模块私有函数 | +| `t.CExport` | `@funcname` | 全局可见 | 对外暴露的 API | +| `t.CExtern` | `@funcname`(仅声明) | 外部定义 | 引用外部函数 | + +### 使用场景 + +```python +# 入口函数 — 必须全局可见,链接器需要找到它 +def _start() -> t.CInt | t.CExport: + return kernel_main() + +# 驱动接口 — 其他模块/应用需要调用 +def init() -> t.CVoid | t.CExport: + uart_init() + +# 内部辅助函数 — 不需要全局可见,自动加 SHA1 前缀 +def _helper() -> t.CInt: + return 42 +``` + +### `t.CExport` 在存根中的表现 + +在 `.pyi` 存根文件中,`t.CExport` 函数与普通函数一样只保留签名(添加 `c.State`,表示单纯声明),但 `t.CExport` 标记被保留在返回类型注解中。阶段一的 `DeclarationGenerator` 检查 `t.CExport` 标记来决定是否添加 SHA1 前缀。 + +## `t.CInline` 深度解析 + +`t.CInline` 标记函数为内联函数,编译器在调用点直接展开函数体。 + +### 语义 + +```python +def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline: + return a + b +``` + +**编译行为**: +1. **阶段二预收集**:`_collect_inline_symbols` 扫描 `includes/` 目录中被引用的模块,收集所有 `t.CInline` 函数的 AST body +2. **翻译时展开**:遇到内联函数调用时,将函数体的 AST 直接嵌入调用点,替换参数为实际值 +3. **不生成独立函数**:内联函数不生成 LLVM IR 函数定义(除非也被非内联调用) + +### `t.CInline` 与 `t.CDefine` 函数的区别 + +| 特性 | `t.CInline` | `t.CDefine` 函数 | +|------|------------|-----------------| +| 展开时机 | 阶段二翻译时 | 阶段二翻译时 | +| 类型检查 | 完整的参数和返回类型检查 | 返回类型为宏,类型检查较弱 | +| 存根表示 | 签名 + `c.State` | 完整函数体 | +| LLVM IR | 可能生成函数定义(如果有非内联调用) | 不生成函数定义 | +| 适用场景 | 性能关键的短函数 | 编译时常量和宏计算 | + +## 目标平台 + +默认目标三元组:`x86_64-none-elf` + +数据布局:`e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128` + +## Hello World 示例 + +```python +import t, c + +def main() -> t.CInt | t.CExport: + print("Hello, ViperOS!\n") + return 0 +``` + +编译流程: + +1. **阶段一**:计算 `main.py` 的 SHA1,生成 `.pyi` 存根(`def main() -> t.CInt | t.CExport | c.State: pass`),生成 `.stub.ll` 声明(`declare i32 @main()`,因为是 CExport 不加前缀) +2. **阶段二**:翻译 `main.py` 为 `.ll`,嵌入 `print` 对应的 `puts`/`printf` 声明,生成 `define i32 @main()` 函数体 +3. **编译**:`llc` 将 `.ll` 编译为 `.o` +4. **链接**:`ld.lld` 链接为可执行文件 diff --git a/wiki/02-type-system.md b/wiki/02-type-system.md new file mode 100644 index 0000000..212f441 --- /dev/null +++ b/wiki/02-type-system.md @@ -0,0 +1,605 @@ +# 02 - 类型系统 + +Viper 的类型系统通过 `t` 模块提供,所有类型注解继承 `t.CType` 。大都以 `t.C{TypeName:PascalCase}`为类型,类型注解是 Viper 的核心机制,决定了变量的内存布局、大小和对齐方式。 + +## 基本类型 + +### 整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CChar` | `char` | 8 | 是 | +| `t.CShort` | `short` | 16 | 是 | +| `t.CInt` | `int` | 32 | 是 | +| `t.CLong` | `long` | 64 | 是 | +| `t.CUnsignedChar` | `unsigned char` | 8 | 否 | +| `t.CUnsignedShort` | `unsigned short` | 16 | 否 | +| `t.CUnsigned` / `t.CUnsignedInt` | `unsigned int` | 32 | 否 | +| `t.CUnsignedLong` | `unsigned long` | 64 | 否 | +| `t.CSignedChar` | `signed char` | 8 | 是 | + +值得注意的是,t.CUnsigned 一般不单独使用,而是配合其它有符号类型,替换表示无符号,比如 `t.CUnsigned | t.CInt`,由于为了便于使用一些常用类型,则将其组合为常用的 `t.CUnginedInt` 等。 + +### 固定宽度整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CInt8T` | `int8_t` | 8 | 是 | +| `t.CInt16T` | `int16_t` | 16 | 是 | +| `t.CInt32T` | `int32_t` | 32 | 是 | +| `t.CInt64T` | `int64_t` | 64 | 是 | +| `t.CUInt8T` | `uint8_t` | 8 | 否 | +| `t.CUInt16T` | `uint16_t` | 16 | 否 | +| `t.CUInt32T` | `uint32_t` | 32 | 否 | +| `t.CUInt64T` | `uint64_t` | 64 | 否 | + +### 最小宽度整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CIntLeast8T` | `int_least8_t` | ≥8 | 是 | +| `t.CIntLeast16T` | `int_least16_t` | ≥16 | 是 | +| `t.CIntLeast32T` | `int_least32_t` | ≥32 | 是 | +| `t.CIntLeast64T` | `int_least64_t` | ≥64 | 是 | +| `t.CUIntLeast8T` | `uint_least8_t` | ≥8 | 否 | +| `t.CUIntLeast16T` | `uint_least16_t` | ≥16 | 否 | +| `t.CUIntLeast32T` | `uint_least32_t` | ≥32 | 否 | +| `t.CUIntLeast64T` | `uint_least64_t` | ≥64 | 否 | + +### 最快最小宽度整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CIntFast8T` | `int_fast8_t` | ≥8 | 是 | +| `t.CIntFast16T` | `int_fast16_t` | ≥16 | 是 | +| `t.CIntFast32T` | `int_fast32_t` | ≥32 | 是 | +| `t.CIntFast64T` | `int_fast64_t` | ≥64 | 是 | +| `t.CUIntFast8T` | `uint_fast8_t` | ≥8 | 否 | +| `t.CUIntFast16T` | `uint_fast16_t` | ≥16 | 否 | +| `t.CUIntFast32T` | `uint_fast32_t` | ≥32 | 否 | +| `t.CUIntFast64T` | `uint_fast64_t` | ≥64 | 否 | + +### 最大宽度整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CIntMaxT` | `intmax_t` | ≥64 | 是 | +| `t.CUIntMaxT` | `uintmax_t` | ≥64 | 否 | + +### stdint 短名别名 + +通过 `import stdint` 引入,这些短名是上述类型的 `t.CTypedef` 别名,便于在系统编程场景中快速使用。允许直接使用 `from stdint import *` 来直接使用。 + +#### 基本类型短名 + +| 短名 | 等价展开 | 说明 | +|------|---------|------| +| `stdint.INT` | `t.CInt` | - | +| `stdint.UINT` | `t.CUnsignedInt` | - | +| `stdint.BOOL` | `t.CInt` | 1 为真,0 为假 | +| `stdint.SHORT` | `t.CShort` | - | +| `stdint.USHORT` | `t.CUnsignedShort` | - | +| `stdint.LONG` | `t.CLong` | - | +| `stdint.ULONG` | `t.CUnsignedLong` | - | +| `stdint.LONGLONG` | `t.CLong \| t.CLong` | - | +| `stdint.ULONGLONG` | `t.CUnsignedLong \| t.CLong` | - | +| `stdint.FLOAT` | `t.CFloat` | - | +| `stdint.DOUBLE` | `t.CDouble` | - | + +#### 固定宽度短名 + +| 短名 | 等价展开 | +|------|---------| +| `stdint.INT8` | `t.CInt8T` | +| `stdint.INT16` | `t.CInt16T` | +| `stdint.INT32` | `t.CInt32T` | +| `stdint.INT64` | `t.CInt64T` | +| `stdint.UINT8` | `t.CUInt8T` | +| `stdint.UINT16` | `t.CUInt16T` | +| `stdint.UINT32` | `t.CUInt32T` | +| `stdint.UINT64` | `t.CUInt64T` | + +#### 字节与字短名 + +| 短名 | 等价展开 | 说明 | +|------|---------|------| +| `stdint.BYTE` | `t.CUnsignedChar` | 8 位无符号 | +| `stdint.WORD` | `t.CUInt16T` | 16 位无符号 | +| `stdint.DWORD` | `t.CUInt32T` | 32 位无符号 | +| `stdint.QWORD` | `t.CUInt64T` | 64 位无符号 | + +#### 字符类型短名 + +| 短名 | 等价展开 | 说明 | +|------|---------|------| +| `stdint.TCHAR` | `t.CChar` | - | +| `stdint.CHARLIST` | `str \| t.CPtr` / `list[str, None]` | - | +| `stdint.WCHAR` | `stdint.WORD` | UTF-16 代码单元 | +| `stdint.CHAR8` | `t.CChar8T` | - | +| `stdint.CHAR16` | `t.CChar16T` | - | +| `stdint.CHAR32` | `t.CChar32T` | - | + +#### 指针短名 + +| 短名 | 等价展开 | +|------|---------| +| `stdint.INTPTR` | `t.CInt \| t.CPtr` | +| `stdint.UINTPTR` | `t.CUnsignedInt \| t.CPtr` | +| `stdint.BYTEPTR` | `stdint.BYTE \| t.CPtr` | +| `stdint.SHORTPTR` | `t.CShort \| t.CPtr` | +| `stdint.USHORTPTR` | `t.CUnsignedShort \| t.CPtr` | +| `stdint.WCHARPTR` | `stdint.WORD \| t.CPtr` | +| `stdint.VOIDPTR` | `t.CVoid \| t.CPtr` | +| `stdint.INT8PTR` | `t.CInt8T \| t.CPtr` | +| `stdint.INT16PTR` | `t.CInt16T \| t.CPtr` | +| `stdint.INT32PTR` | `t.CInt32T \| t.CPtr` | +| `stdint.INT64PTR` | `t.CInt64T \| t.CPtr` | +| `stdint.UINT8PTR` | `t.CUInt8T \| t.CPtr` | +| `stdint.UINT16PTR` | `t.CUInt16T \| t.CPtr` | +| `stdint.UINT32PTR` | `t.CUInt32T \| t.CPtr` | +| `stdint.UINT64PTR` | `t.CUInt64T \| t.CPtr` | +| `stdint.CHAR8PTR` | `t.CChar8T \| t.CPtr` | +| `stdint.CHAR16PTR` | `t.CChar16T \| t.CPtr` | +| `stdint.CHAR32PTR` | `t.CChar32T \| t.CPtr` | + +#### 平台特定短名 + +| 短名 | 等价展开 | 说明 | +|------|---------|------| +| `stdint.FSIZE_t` | `stdint.DWORD` | 文件大小 | +| `stdint.LBA_t` | `stdint.DWORD` | 逻辑块地址 | + +### 平台相关类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CSizeT` | `size_t` | 64 | 否 | +| `t.CIntPtrT` | `intptr_t` | 64 | 是 | +| `t.CUIntPtrT` | `uintptr_t` | 64 | 否 | +| `t.CPtrDiffT` | `ptrdiff_t` | 64 | 是 | + +### stdint 短名别名 + +Viper 在 `stdint` 模块中提供了更简短的类型别名,通过 `t.CTypedef` 映射到对应的完整类型。使用时需 `import stdint`。 + +#### 固定宽度整数短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `INT8` | `t.CInt8T` | `int8_t` | +| `INT16` | `t.CInt16T` | `int16_t` | +| `INT32` | `t.CInt32T` | `int32_t` | +| `INT64` | `t.CInt64T` | `int64_t` | +| `UINT8` | `t.CUInt8T` | `uint8_t` | +| `UINT16` | `t.CUInt16T` | `uint16_t` | +| `UINT32` | `t.CUInt32T` | `uint32_t` | +| `UINT64` | `t.CUInt64T` | `uint64_t` | + +#### 固定宽度指针短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `INT8PTR` | `t.CInt8T \| t.CPtr` | `int8_t*` | +| `INT16PTR` | `t.CInt16T \| t.CPtr` | `int16_t*` | +| `INT32PTR` | `t.CInt32T \| t.CPtr` | `int32_t*` | +| `INT64PTR` | `t.CInt64T \| t.CPtr` | `int64_t*` | +| `UINT8PTR` | `t.CUInt8T \| t.CPtr` | `uint8_t*` | +| `UINT16PTR` | `t.CUInt16T \| t.CPtr` | `uint16_t*` | +| `UINT32PTR` | `t.CUInt32T \| t.CPtr` | `uint32_t*` | +| `UINT64PTR` | `t.CUInt64T \| t.CPtr` | `uint64_t*` | + +#### 字符类型短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `CHAR8` | `t.CChar8T` | `char8_t` | +| `CHAR16` | `t.CChar16T` | `char16_t` | +| `CHAR32` | `t.CChar32T` | `char32_t` | +| `CHAR8PTR` | `t.CChar8T \| t.CPtr` | `char8_t*` | +| `CHAR16PTR` | `t.CChar16T \| t.CPtr` | `char16_t*` | +| `CHAR32PTR` | `t.CChar32T \| t.CPtr` | `char32_t*` | + +#### 基本类型短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `INT` | `t.CInt` | `int` | +| `UINT` | `t.CUnsignedInt` | `unsigned int` | +| `BOOL` | `t.CInt` | `int`(0/1) | +| `SHORT` | `t.CShort` | `short` | +| `USHORT` | `t.CUnsignedShort` | `unsigned short` | +| `LONG` | `t.CLong` | `long` | +| `ULONG` | `t.CUnsignedLong` | `unsigned long` | +| `LONGLONG` | `t.CLong \| t.CLong` | `long long` | +| `ULONGLONG` | `t.CUnsignedLong \| t.CLong` | `unsigned long long` | +| `FLOAT` | `t.CFloat` | `float` | +| `DOUBLE` | `t.CDouble` | `double` | + +#### 平台 / Windows 风格短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `BYTE` | `t.CUnsignedChar` | `unsigned char`(8位) | +| `BYTEPTR` | `BYTE \| t.CPtr` | `unsigned char*` | +| `WORD` | `t.CUInt16T` | `uint16_t`(16位) | +| `DWORD` | `t.CUInt32T` | `uint32_t`(32位) | +| `QWORD` | `t.CUInt64T` | `uint64_t`(64位) | +| `INTPTR` | `t.CInt \| t.CPtr` | `int*` | +| `UINTPTR` | `t.CUnsignedInt \| t.CPtr` | `unsigned int*` | +| `SHORTPTR` | `t.CShort \| t.CPtr` | `short*` | +| `USHORTPTR` | `t.CUnsignedShort \| t.CPtr` | `unsigned short*` | +| `VOIDPTR` | `t.CVoid \| t.CPtr` | `void*` | +| `TCHAR` | `t.CChar` | `char` | +| `WCHAR` | `WORD` | `uint16_t`(UTF-16) | +| `WCHARPTR` | `WORD \| t.CPtr` | `uint16_t*`(UTF-16) | +| `CHARLIST` | `str \| t.CPtr` | `char*` | +| `FSIZE_t` | `DWORD` | `uint32_t` | +| `LBA_t` | `DWORD` | `uint32_t` | + +### 浮点类型 + +| Viper 类型 | C 等价 | 大小(位) | +|------------|--------|-----------| +| `t.CFloat` | `float` | 32 | +| `t.CDouble` | `double` | 64 | + +### 其他基本类型 + +| Viper 类型 | C 等价 | 说明 | +|------------|--------|------| +| `t.CVoid` | `void` | 空类型 | +| `t.CBool` | `bool` | 布尔类型(8位) | +| `t.CWCharT` | `wchar_t` | 宽字符(32位) | +| `t.CChar8T` | `char8_t` | UTF-8 字符(8位,无符号) | +| `t.CChar16T` | `char16_t` | UTF-16 字符(16位,无符号) | +| `t.CChar32T` | `char32_t` | UTF-32 字符(32位,无符号) | + +### Python 便捷映射类型 +| Python 类型| Viper 类型 | Viper 值 | +|--------|--------|------| +|`int`|`t.CInt`|-| +|`float`|`t.CFloat`|-| +|`str`|`t.CChar \| t.CPtr`|-| +|`bool`|`t.CBool`|-| +|`True`|`t.CBool`|`1`| +|`False`|`t.CBool`|`0`| +|`None`|`NULL`|`t.CIntPtr(0)`| + +对于 t.py 和 c.py 的引用,必须使用 import,不能使用 from ... import ...,也不能使用 as,因为这两者都是直接以字符串识别的。 + +## 类型组合 + +Viper 使用 Python 的 `|` 来组合类型修饰符(TypeUnion),其仅在左值注解中有效,其它位置均为位或语义(至少重载前是这样的),这是 Viper 最重要的语法特性之一。 + +### 指针类型 + +使用 `t.CPtr` 表示指针,通过 `|` 与基本类型组合: + +```python +x: t.CInt | t.CPtr # int* — 指向 int 的指针 +p: t.CVoid | t.CPtr # void* — 通用指针 +s: t.CChar | t.CPtr # char* — 字符串指针 +pp: t.CInt | t.CPtr | t.CPtr # int** — 指向指针的指针 +``` + +等价 C 代码: +```c +int* x; +void* p; +char* s; +int** pp; +``` + +同时,指针也可以用 `Ptr[T]` 的方法表示,但在 Viper 中不太推荐,虽然说这样做一直是类似工程的常见用法,但是如果此处 `T` 是一个多态,同时我们想要复用 Python 的高亮插件,插件无法识别 `Ptr[T]` 的属性取值,但是对于 `T | Ptr` 可以。 + +```python +x: t.CPtr[t.CInt] +p: t.CPtr[t.CVoid] +s: t.CPtr[t.CChar] +pp: t.CPtr[t.CPtr[t.CInt]] +pp2: t.CInt | t.CPtr[t.CPtr] # 同时也可以这么表示 +``` + +等价 C 代码: + +```c +int* x; +void* p; +char* s: +int** pp; +int** pp2; +``` + +### 类型限定符组合 + +```python +x: t.CConst | t.CInt # const int +p: t.CConst | t.CChar | t.CPtr # const char* +``` + +### 存储类组合 + +```python +x: t.CStatic | t.CInt # static int +f: t.CExtern | t.CInt # extern int(声明其存在于外部) +``` + +### 函数返回类型组合 + +```python +def foo() -> t.CInt | t.CExport: # 导出函数,返回 int + return 0 + +def bar() -> t.CVoid | t.CExtern: # 外部函数声明 + pass +``` + +## 数组类型 + +使用 Python 的 `list[ElementType, Size]` 语法表示固定大小数组(通常的,这用于栈上和 BSS 段上): + +```python +buf: list[t.CChar, 64] # char buf[64] +ids: list[t.CInt, 10] # int ids[10] +matrix: list[t.CFloat, 16] # float matrix[16] +entries: list[idt_entry, 256] # struct idt_entry entries[256] +s: list[t.CChar, None] # 自推长度 char s[]; +``` + +等价 C 代码: +```c +char buf[64]; +int ids[10]; +float matrix[16]; +struct idt_entry entries[256]; +``` + +### 数组指针和函数指针 + +```python +lp: list[t.CInt, 12] | t.CPtr +vp: t.Callable[[t.CInt, t.CInt], t.CInt] = x # 其中 t.Callable = typing.Callable,可以直接使用。 +``` + +## 结构体类型 + +使用 `class` 定义结构体,成员通过类型注解声明: + +```python +class point: + x: t.CInt + y: t.CInt +``` + +等价 C 代码: +```c +struct point { + int x; + int y; +}; +``` + +### 带指针成员的结构体 + +```python +class node: + value: t.CInt + next: node | t.CPtr # struct node* next +``` + +### 匿名结构体成员(❌) + +> WARNING: **警告:** 由于 Viper 在声明结构体,枚举等处不需要关键字,因此 `t.Anonymouse` 是不需要使用的。此关键字不再维护,强行使用可能导致未定义行为。 + +继承 `t.Anonymous` 的类作为匿名成员嵌入: + +```python +class header(t.Anonymous): + magic: t.CUInt32T + version: t.CUInt32T + +class packet: + header # 匿名嵌入,可直接访问 packet.magic + length: t.CUInt32T +``` + +### 字节序标记 + +> WARNING: **警告:** 此关键字是实验性的。未经充分测试,不当使用可能导致未定义行为。 + +使用 `t.BigEndian` 或 `t.LittleEndian` 标记成员的字节序: + +```python +class network_packet: + length: t.CUInt16T | t.BigEndian # 大端序存储 + type: t.CUInt8T # 默认小端序 +``` + +## 联合体类型 + +继承 `t.CUnion` 定义联合体: + +```python +class value(t.CUnion): + ival: t.CInt + fval: t.CFloat + pval: t.CVoid | t.CPtr +``` + +等价 C 代码: +```c +union value { + int ival; + float fval; + void* pval; +}; +``` + +## 枚举类型 + +继承 `t.CEnum` 定义枚举: + +```python +class color(t.CEnum): + RED: t.CEnum = 0 + GREEN: t.CEnum = 1 + BLUE: t.CEnum = 2 +``` + +等价 C 代码: +```c +enum color { + RED = 0, + GREEN = 1, + BLUE = 2 +}; +``` + +枚举成员可直接使用名称: + +```python +c: t.CInt = color.RED +``` + +## Typedef + +使用 `t.CTypedef` 创建类型别名: + +```python +irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] # typedef int (*irq_handler_t)(); +``` + +或通过注解赋值: + +```python +MyStruct: t.CTypedef = original_struct # typedef struct original_struct MyStruct; +``` + +更推荐通过后者的形式,前者编译器不一定能够识别到注解是对 t.CTypedef 的,还是后面的注解的,而且容易触发未定义行为。 + +## 强制类型转换 +在 Viper 中的强制类型转换有些不同,强制类型转换有两种方案,都是基于 `t.CType` 的用法,符合 Python 本意。 +对于原先就继承自 `t.CType` 的类型来说,可以直接使用 call 的方法进行类型转换,比如 +```python +x: t.CChar | t.CPtr = "Hello" +t.CVoid(x, t.CPtr) +``` +其中用法为 `t.CType(x, ...)`,此处...可以是其它的 `t.CType` 或将要提到的 `Typedef`,将其视为组合类型对 `x` 进行强制转换。 + +额外补充一句,对于比较,四则运算,可以不使用强制类型转换,而是依靠隐式类型转换,但如果是严谨数学计算,推荐还是强制类型转换避免判断出错。 + +此外,若将一个不同类型的右值赋值到左值,则会隐式将右值转换为左值的类型。 + +如果你不喜欢 `t.CVoid(x, t.CPtr)` 的方法,认为这将 `void` 和 `ptr` 分开,不便于理解,那么还有一个方法,即将二者打包为一个 Typedef,即: +```python +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +``` +则如果你想,你可以直接通过 call 的方式进行强转,比如: +```python +y: VOIDPTR = VOIDPTR(x) +``` + +## 宏定义常量 + +使用 `t.CDefine` 定义编译时常量。`t.CDefine` 不是数据类型,而是编译时元指令——标记为 `t.CDefine` 的常量在 LLVM IR 中不生成任何全局变量,而是在引用处直接内联展开。详见 [01-overview.md 中 t.CDefine 深度解析](01-overview.md#tcdefine-深度解析)。 + +```python +MAX_SIZE: t.CDefine = 1024 +PAGE_SIZE: t.CDefine = 4096 +FA_READ: t.CDefine = 0x01 +``` + +语义上等价于 C 的 `#define`: +```c +#define MAX_SIZE 1024 +#define PAGE_SIZE 4096 +#define FA_READ 0x01 +``` + +宏定义支持表达式: + +```python +CPU_FEATURE_FPU: t.CDefine = (1 << 0) +CPU_FEATURE_APIC: t.CDefine = (1 << 6) +``` + +宏定义也可与类型组合使用: + +```python +CODE_SEG: t.CDefine | t.CUInt16T = 0x08 +``` + +## 位域 + +使用 `t.Bit(n)` 定义位域成员: + +```python +class flags: + a: t.CUInt32T | t.Bit[1] # 此处,如果存入 2,二进制是 10,会被截断为 0 + b: t.CUInt32T | t.Bit[3] + c: t.CUInt32T | t.Bit[4] +``` + +## LLVM IR 类型简写 + +Viper 提供了 LLVM IR 级别的类型简写: + +```python +i1 # 1位整数 +i8 # 8位有符号整数 +i16 # 16位有符号整数 +i32 # 32位有符号整数 +i64 # 64位有符号整数 +u1 # 1位无符号整数 +u8 # 8位无符号整数 +u16 # 16位无符号整数 +u32 # 32位无符号整数 +u64 # 64位无符号整数 +``` + +仍然通过 `t.x` 的方式调用,比如 `t.i1` 等。 + +## `__attribute__` 属性 + +通过 `t.attr` 命名空间访问 GCC `__attribute__` 属性: + +```python +t.attr.packed() # __attribute__((packed)) +t.attr.aligned(16) # __attribute__((aligned(16))) +t.attr.section(".text.startup") # __attribute__((section(".text.startup"))) +t.attr.always_inline() # __attribute__((always_inline)) +t.attr.noinline() # __attribute__((noinline)) +t.attr.noreturn() # __attribute__((noreturn)) +t.attr.weak() # __attribute__((weak)) +t.attr.unused() # __attribute__((unused)) +t.attr.constructor() # __attribute__((constructor)) +t.attr.destructor() # __attribute__((destructor)) +t.attr.deprecated("use X") # __attribute__((deprecated("use X"))) +``` + +### LLVM 函数属性 + +通过 `t.attr.llvm` 命名空间指定 LLVM 函数属性: + +```python +t.attr.llvm.nobuiltin +t.attr.llvm.nounwind +t.attr.llvm.noredzone +t.attr.llvm.willreturn +t.attr.llvm.mustprogress +t.attr.llvm.optnone +t.attr.llvm.noinline +t.attr.llvm.alwaysinline +t.attr.llvm.readnone +t.attr.llvm.readonly +t.attr.llvm.writeonly +t.attr.llvm.inaccessiblememonly +t.attr.llvm.inaccessiblemem_or_argmemonly +``` + +在函数返回类型注解中使用: + +```python +def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind: + return 0 +``` diff --git a/wiki/03-variables.md b/wiki/03-variables.md new file mode 100644 index 0000000..684e8d1 --- /dev/null +++ b/wiki/03-variables.md @@ -0,0 +1,177 @@ +# 03 - 变量声明与赋值 + +Viper 的变量声明使用 Python 的类型注解语法,通过 `t` 模块指定 C 级别的类型信息。 + +## 带注解的变量声明 + +使用 `变量名: 类型` 语法声明变量: + +```python +x: t.CInt = 0 # int x = 0; +y: t.CUInt32T = 42 # uint32_t y = 42; +name: list[t.CChar, 64] # char name[64]; +ptr: t.CVoid | t.CPtr # void* ptr; +msg: t.CConst | str = "Hello" # const char* msg = "Hello"; +``` + +### 无初始值的声明 + +未赋值的变量声明会生成零初始化的变量,此处是未定义行为,即在不同环境位置可能会覆盖0,也可能不会,最好预先复制或用 memset 清除: + +```python +count: t.CInt # int count = 0; +buffer: list[t.CChar, 256] # char buffer[256] = {0}; +``` + +### 延迟赋值 + +变量可以先声明后赋值: + +```python +x: t.CInt +x = 10 +``` + +### 指针变量 + +```python +p: t.CInt | t.CPtr # int* p; +fb: t.CVoid | t.CPtr # void* fb; +str_ptr: t.CConst | t.CChar | t.CPtr # const char* str_ptr; +``` + +### 指针变量的特殊初始化 + +使用 `t.CVoid(0, t.CPtr)` 初始化指针为 NULL: + +```python +p: t.CVoid | t.CPtr = t.CVoid(0, t.CPtr) # void* p = NULL; +``` + +或使用 `None`: + +```python +p: t.CVoid | t.CPtr = None # void* p = NULL; +``` + +## 普通赋值 + +```python +x: t.CInt = 0 +x = 42 # x = 42; +``` + +## 增强赋值 + +支持所有 Python 增强赋值运算符: + +```python +x: t.CInt = 0 +x += 1 # x += 1; +x -= 1 # x -= 1; +x *= 2 # x *= 2; +x //= 3 # x /= 3; (整数除法) +x %= 5 # x %= 5; +x <<= 1 # x <<= 1; +x >>= 1 # x >>= 1; +x |= 0xFF # x |= 0xFF; +x &= 0x0F # x &= 0x0F; +x ^= 0xAA # x ^= 0xAA; +``` + +## 全局变量 + +模块顶层声明的变量即为全局变量: + +```python +kbd_tid: t.CInt = -1 # 全局 int kbd_tid = -1; +BootInfo: bootinfo | t.CPtr # 全局 struct bootinfo* BootInfo; +``` + +### 静态全局变量 + +```python +x: t.CStatic | t.CInt = 0 # static int x = 0; +``` + +### 外部声明 + +```python +x: t.CExtern | t.CInt # extern int x; +``` + +## 常量定义 + +使用 `t.CDefine` 定义编译时常量。`t.CDefine` 不是数据类型,而是编译时元指令——常量在 LLVM IR 中不生成全局变量,而是在引用处直接内联展开。详见 [01-overview.md 中 t.CDefine 深度解析](01-overview.md#tcdefine-深度解析)。 + +```python +MAX_SIZE: t.CDefine = 1024 +PAGE_SIZE: t.CDefine = 4096 +FA_READ: t.CDefine = 0x01 +FA_WRITE: t.CDefine = 0x02 +``` + +## 字符串常量 + +Viper 中的字符串字面量编译为 C 的字符串常量(`const char*`): + +```python +msg: t.CConst | str = "Hello, World!" +serial.puts(msg) +``` + +也可以直接传递字符串字面量: + +```python +serial.puts("Hello, World!") +``` + +## 类型转换 + +使用类型构造函数进行显式类型转换: + +```python +x: t.CInt = 42 +y: t.CUInt32T = t.CUInt32T(x) # (uint32_t)x +f: t.CFloat = float(x) # (float)x +i: t.CInt = int(f) # (int)f +``` + +### 指针类型转换 + +```python +ptr: t.CVoid | t.CPtr = some_ptr +int_val: t.CUInt64T = t.CUInt64T(ptr) # (uint64_t)ptr — 指针转整数 +``` + +## 结构体实例化 + +> 此处不理解参见 ([05-classes.md 中 结构体实例化与初始化](05-classes.md#结构体实例化与初始化)) + +直接使用类名作为构造函数: + +```python +info: fat32_types.fat32_fileinfo +dp: fat32_types.fat32_dirobj +``` + +带初始化的实例化: + +```python +obj: MyClass = MyClass(arg1, arg2) +``` + +使用 `c.Addr` 获取实例指针: + +```python +obj_ptr: MyClass | t.CPtr = c.Addr(MyClass(arg1, arg2)) +``` + +## delete 语句 + +`del` 语句可用于调用对象的 `__del__` 或 `__delete__` 方法: + +```python +del obj # 调用 obj.__del__() 或 obj.__delete__() +del arr[idx] # 调用 arr.__delitem__(idx) +``` diff --git a/wiki/04-functions.md b/wiki/04-functions.md new file mode 100644 index 0000000..48da6aa --- /dev/null +++ b/wiki/04-functions.md @@ -0,0 +1,254 @@ +# 04 - 函数定义与调用 + +Viper 的函数定义使用 Python 的 `def` 语法,通过类型注解指定参数类型和返回类型。 + +## 基本函数定义 + +```python +def add(a: t.CInt, b: t.CInt) -> t.CInt: + return a + b +``` + +等价 C 代码: +```c +int add(int a, int b) { + return a + b; +} +``` + +## 无返回值函数 + +```python +def print_msg(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid: + serial.puts(msg) +``` + +等价 C 代码: +```c +void print_msg(const char* msg) { + serial_puts(msg); +} +``` + +## 函数修饰符 + +通过返回类型的 `|` 组合添加函数修饰符: + +### 导出函数 + +` t.CExport` 控制函数的符号可见性——标记为 `t.CExport` 的函数不加 SHA1 前缀,全局可见。详见 [01-overview.md 中 t.CExport 深度解析](01-overview.md#tcexport-深度解析)。 + +```python +def _start() -> t.CInt | t.CExport: + return 0 +``` + +### 外部函数声明 + +使用 `c.State` 表示仅声明不定义: + +```python +def isr0() -> t.CExtern | t.CVoid | c.State: pass +def isr1() -> t.CExtern | t.CVoid | c.State: pass +``` + +等价 C 代码: +```c +extern void isr0(); +extern void isr1(); +``` + +### 内联函数 + +`t.CInline` 标记函数为内联函数,编译器在调用点直接展开函数体。详见 [01-overview.md 中 t.CInline 深度解析](01-overview.md#tcinline-深度解析)。 + +```python +def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline: + return a + b +``` + +### 宏函数 + +当函数返回类型注解包含 `t.CDefine` 时,该函数被视为宏函数,不生成 LLVM IR 函数定义,在调用处内联展开。详见 [01-overview.md 中 t.CDefine 函数](01-overview.md#tcdefine-函数)。 + +```python +def MAKE_FLAG(bit) -> t.CDefine: + return (1 << bit) +``` + +### 静态函数 + +```python +def helper() -> t.CVoid | t.CStatic: + pass +``` + +## 函数属性装饰器 + +使用 `@c.Attribute` 添加 GCC `__attribute__` 属性: + +```python +@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16)) +def _start() -> t.CInt: + return 0 +``` + +等价 C 代码: +```c +__attribute__((section(".text.startup"), aligned(16))) +int _start() { + return 0; +} +``` + +### 常用属性组合 + +```python +@c.Attribute(t.attr.always_inline()) +def hot_path() -> t.CInt: + return 0 + +@c.Attribute(t.attr.noreturn()) +def panic(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid: + serial.puts(msg) + while True: pass + +@c.Attribute(t.attr.packed) +``` + +## LLVM 函数属性 + +在返回类型注解中通过 `t.attr.llvm` 指定 LLVM 属性: + +```python +def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind: + return 0 +``` + +## 多返回值(CReturn) + +使用 `@c.CReturn` 装饰器实现多返回值,通过指针参数实现: + +```python +@c.CReturn(t.CInt, t.CInt) +def divmod(a: t.CInt, b: t.CInt) -> t.CVoid: + q: t.CInt = a // b + r: t.CInt = a % b + return q, r +``` + +规则: +1. `CReturn` 中的类型数量决定返回值个数 +2. 自动为每个返回类型添加指针参数(`t.CInt` → `t.CInt | t.CPtr`) +3. 参数名自动生成为 `__ReturnValue0__`、`__ReturnValue1__` 等 +4. 调用处自动传参 `&xxx` +5. 必须使用左右值赋值,返回值不能直接传入函数。 + +## 指针参数 + +```python +def read_data(buf: t.CChar | t.CPtr, size: t.CSizeT) -> t.CInt: + pass +``` + +等价 C 代码: +```c +int read_data(char* buf, size_t size); +``` + +### 输出参数模式 + +使用 `c.Addr` 传递变量地址作为输出参数: + +```python +res: t.CInt = fat32.opendir("/", c.Addr(dp)) +``` + +等价 C 代码: +```c +int res = fat32_opendir("/", &dp); +``` + +后续会使用隐式左值获取来减少 `c.Addr` 的直接使用。 + +## 函数指针类型 + +使用 `t.Callable` 定义函数指针类型: + +```python +irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] +``` + +等价 C 代码: +```c +typedef int (*irq_handler_t)(); +``` + +带参数的函数指针: + +```python +callback_t: t.Callable[[t.CInt, t.CInt], t.CVoid] +``` + +## 默认参数 + +Viper 支持函数默认参数值: + +```python +def create_window(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | str = "Window") -> t.CInt: + pass +``` + +## return 语句 + +```python +return 0 # return 0; +return # return; (void 函数) +return a, b # 多返回值(需配合 @c.CReturn) +``` + +## 全局变量声明 + +函数外的变量声明为全局变量,函数内通过 `global` 关键字访问: + +```python +BootInfo: bootinfo | t.CPtr + +def init() -> t.CVoid: + global BootInfo + BootInfo = saved_rdi +``` + +支持 func-in-func 嵌套函数。 + +## Call Func 函数调用 + +函数调用最好通过顺序调用来实现 + +```python +def add(x: int, y: int, z: int): + return (x + y) * z + +def main() -> int | t.CExport: + print(add(1, 2, 3)) # (1 + 2) * 3 = 9 +``` + +这也是 C 中的标准实现方法,但实际上,你也可以乱序传参。 + +```python +# 仍然用刚才的 add 举例 +def main() -> int | t.CExport: + print(add(z=3, x=1, y=2)) # (1 + 2) * 3 = 9 +``` + +乱序传参或带参传参对于结构体的初始化同样有效。同时,你也能够给函数指定默认值。 + +```python +def add(x: int, y: int, z: int = 1): + return (x + y) * z + +def main() -> int | t.CExport: + print(add(1, 2)) # (1 + 2) * 1 = 3 +``` + +在结构体中也可以指定默认值。 diff --git a/wiki/05-classes.md b/wiki/05-classes.md new file mode 100644 index 0000000..6f69a50 --- /dev/null +++ b/wiki/05-classes.md @@ -0,0 +1,190 @@ +# 05 - 类与数据布局 + +Viper 中的 `class` 有两种用途:定义**数据布局**(结构体/联合体/枚举,本章内容),以及定义**面向对象的对象类型**(见 [06-oop.md](06-oop.md))。 + +## 结构体定义 + +普通 `class` 定义编译为 LLVM 结构体类型: + +```python +class point: + x: t.CInt + y: t.CInt +``` + +在 C 中: +```c +struct point { + int x; + int y; +}; +``` + +在 LLVM IR 中: +```llvm +%".point" = type { i32, i32 } +``` + +### 带属性的结构体 + +```python +@c.Attribute(t.attr.packed) +class idt_entry: + base_low: t.CUInt16T + selector: t.CUInt16T + ist_attr: t.CUInt8T + type_attr: t.CUInt8T + base_middle: t.CUInt16T + base_high: t.CUInt32T + reserved1: t.CUInt32T +``` + +### 结构体数组 + +```python +idt: list[idt_entry, 256] = [] +``` + +### 结构体指针成员 + +```python +class node: + value: t.CInt + next: node | t.CPtr # 指向自身的指针(有向图链表) +``` + +### 结构体实例化与初始化 + +```python +entry: idt_entry = idt_entry() +``` + +或带构造函数: + +```python +mousepoint = Point(x=1, y=2) +``` + +乱序传参或带参传参对于结构体的初始化同样有效: + +```python +entry: idt_entry = idt_entry(selector=0x08, base_low=0x0000) +``` + +也可以给结构体成员指定默认值: + +```python +class config: + width: t.CInt = 640 + height: t.CInt = 480 + depth: t.CInt = 32 +``` + +使用 `c.Addr` 获取实例指针: + +```python +obj_ptr: MyClass | t.CPtr = c.Addr(MyClass(arg1, arg2)) +``` + +### 匿名结构体成员(❌) + +> WARNING: **警告:** 由于 Viper 在声明结构体,枚举等处不需要关键字,因此 `t.Anonymouse` 是不需要使用的。此关键字不再维护,强行使用可能导致未定义行为。 + +继承 `t.Anonymous` 的类作为匿名成员嵌入: + +```python +class header(t.Anonymous): + magic: t.CUInt32T + version: t.CUInt32T + +class packet: + header # 匿名嵌入,可直接访问 packet.magic + length: t.CUInt32T +``` + +### 字节序标记 + +> WARNING: **警告:** 此关键字是实验性的。未经充分测试,不当使用可能导致未定义行为。 + +使用 `t.BigEndian` 或 `t.LittleEndian` 标记成员的字节序: + +```python +class network_packet: + length: t.CUInt16T | t.BigEndian # 大端序存储 + type: t.CUInt8T # 默认小端序 +``` + +## 联合体 + +继承 `t.CUnion` 定义联合体: + +```python +class value(t.CUnion): + ival: t.CInt + fval: t.CFloat + pval: t.CVoid | t.CPtr +``` + +等价 C 代码: +```c +union value { + int ival; + float fval; + void* pval; +}; +``` + +## 枚举 + +继承 `t.CEnum` 定义枚举: + +```python +class color(t.CEnum): + RED: t.CEnum = 0 + GREEN: t.CEnum = 1 + BLUE: t.CEnum = 2 +``` + +等价 C 代码: +```c +enum color { + RED = 0, + GREEN = 1, + BLUE = 2 +}; +``` + +枚举成员可直接使用名称: + +```python +c: t.CInt = color.RED +``` + +## Typedef + +使用 `t.CTypedef` 创建类型别名: + +```python +irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] # typedef int (*irq_handler_t)(); +``` + +或通过注解赋值: + +```python +MyStruct: t.CTypedef = original_struct # typedef struct original_struct MyStruct; +``` + +更推荐通过后者的形式,前者编译器不一定能够识别到注解是对 `t.CTypedef` 的,还是后面的注解的,而且容易触发未定义行为。 + +## 位域 + +使用 `t.Bit(n)` 定义位域成员: + +```python +class flags: + a: t.CUInt32T | t.Bit[1] + b: t.CUInt32T | t.Bit[3] + c: t.CUInt32T | t.Bit[4] +``` + +注意:如果存入超出位域宽度的值,会被截断。例如 `a` 为 1 位,存入 2(二进制 `10`)会被截断为 0。 diff --git a/wiki/06-oop.md b/wiki/06-oop.md new file mode 100644 index 0000000..35d81fe --- /dev/null +++ b/wiki/06-oop.md @@ -0,0 +1,611 @@ +# 06 - 面向对象与运算符重载 + +Viper 中的 `class` 有两种语义:**数据布局**(结构体/联合体/枚举,见 [05-classes.md](05-classes.md))和**面向对象**。面向对象特性通过 `@t.Object` 装饰器启用,多态通过 `@t.CVTable` 装饰器启用。 + +## `@t.Object` 面向对象 + +使用 `@t.Object` 装饰器启用面向对象特性,类将拥有成员方法、运算符重载、属性装饰器等 OOP 支持。编译器也会自动识别:如果结构体内有函数定义,会自动使用 `@t.Object` 行为,但在实际工程中更推荐明确标记,避免未定义行为。 + +### 基本定义 + +```python +@t.Object +class ViperKernel: + BootInfo: bootinfo | t.CPtr + VGA: vga._VGAScreenDriver | t.CPtr + VGA_drv: vga._VGAScreenDriver + + def __init__(self): + self.BootInfo = BootInfo + serial.init() + serial.puts("ViperOS VKernel Test\n") +``` + +避免在 `__init__` 中使用 `return`,虽然不会报错,但是你永远无法获得 `return` 的结果,如果需要提前结束代码流,`return` 也不失为一种办法。 + +### 成员方法 + +```python +@t.Object +class Sheet: + id: t.CInt + x: t.CInt + y: t.CInt + w: t.CInt + h: t.CInt + + def __init__(self, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt): + self.x = x + self.y = y + self.w = w + self.h = h + + def MoveTo(self, nx: t.CInt, ny: t.CInt): + self.x = nx + self.y = ny + + def Resize(self, nw: t.CInt, nh: t.CInt): + self.w = nw + self.h = nh +``` + +### 方法调用 + +```python +sheet: Sheet = Sheet(0, 0, 640, 480) +sheet.MoveTo(100, 100) +sheet.Resize(800, 600) +``` + +### 属性装饰器 + +支持 Python 的 `@property` 和 `@xxx.setter` 装饰器: + +> `@xxx.setter` 和自定义装饰器正在试验阶段,尽可能不要使用 + +```python +@t.Object +class MyObj: + _value: t.CInt + + @property + def value(self) -> t.CInt: + return self._value + + @value.setter + def value(self, v: t.CInt): + self._value = v +``` + +### 静态方法 + +```python +@staticmethod +def _yield(): + pass +``` + +### 对象指针与解引用 + +`@t.Object` 的实例通常通过指针操作: + +```python +obj_ptr: MyClass | t.CPtr = c.Addr(MyClass()) +obj: MyClass = c.Deref(obj_ptr) +``` + +### 成员访问 + +通过 `self` 访问成员变量和方法: + +```python +def method(self) -> t.CVoid: + self.x = 10 + y: t.CInt = self.y + self.DoSomething() +``` + +### 内嵌对象 + +`@t.Object` 可以包含其他对象实例(非指针): + +```python +@t.Object +class Sheet: + _surf_obj: gfx.Surface + _renderer_obj: gfx.Renderer + surf: gfx.Surface | t.CPtr + renderer: gfx.Renderer | t.CPtr + + def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: t.CInt, h: t.CInt): + self._surf_obj = gfx.Surface(fb, zb, w, h) + self.surf = c.Addr(self._surf_obj) + self._renderer_obj = gfx.Renderer(self.surf) + self.renderer = c.Addr(self._renderer_obj) +``` + +### `__before_init__` 方法 + +`@t.Object` 或 `@t.CVTable` 类自动生成 `__before_init__` 方法声明,用于在 `__init__` 之前初始化 vtable: + +```llvm +declare void @".ClassName.__before_init__"(%".ClassName"*) +``` + +值得注意的是,`__before_init__` 并不帮忙初始化内存,而只是初始化虚表等准备工作,实际上,我们更希望用户能自己管理内存。实验性阶段内容中,我们通过内存池机制来帮助用户管理碎片化内容,包括部分小的结构体,但较大内容最好还是由用户手动处理。 + +## `@t.CVTable` 虚函数表与多态 + +> 尽可能避免使用 `self[0]` 来获取结构体成员,其不稳定,也不要手动操作虚表。 + +使用 `@t.CVTable` 装饰器可以启用虚函数表支持。启用后,结构体第一个成员自动插入 `i8*` 类型的 vtable 指针。`@t.CVTable` 的操作必须配合 `@t.Object`,但有时编译器会自动识别是否存在结构体内函数,自动使用 `@t.Object`。 + +### 基本定义 + +```python +@t.Object +@t.CVTable +class Base: + def __init__(self): + pass + def method(self) -> t.CInt: + return 0 +``` + +在 LLVM IR 中,`@t.CVTable` 类的结构体类型自动插入 vtable 指针: + +```llvm +%".Base" = type { i8*, i32 } +``` + +同时,编译器会生成全局 vtable 变量: + +```llvm +@".Base_Vtable" = internal global [1 x i8*] zeroinitializer +``` + +### 继承与多态 + +虚表可以帮你使用继承语法实现多态: + +```python +@t.Object +@t.CVTable +class Base: + def __init__(self): + pass + def method(self) -> t.CInt: + return 0 + +@t.Object +@t.CVTable +class M1(Base): + def method(self) -> t.CInt: + return 1 +``` + +当 M1 被初始化时,VTable 会自动修改,这点和 C++ 相同,尽可能避免直接操作 VTable。 + +继承时,子类会自动继承父类的成员变量和方法。子类重写父类方法时,vtable 中对应位置的函数指针被子类方法替换,实现多态。 + +### VTable 运行时修改 + +如果需要临时构造一个额外的 `Base` 结构体,还可以使用: + +```python +@t.Object +@t.CVTable +class Base: + def __init__(self): + pass + def method(self) -> t.CInt: + return 0 + +def __method1(self) -> t.CInt: + return 1 + +def main() -> t.CInt | t.CExport: + b: Base = Base() + b.method = __method1 +``` + +启用 `VTable` 的表中,允许直接修改内部函数为函数指针,在底层,此操作将修改 `VTable` 来达成目的。编译器会检测当前 vtable 是否与类 vtable 相同,如果相同则创建 vtable 的副本(memcpy),避免修改影响所有实例。 + +### 虚方法调度机制 + +虚方法调用的核心流程: + +1. 从对象指针 GEP 获取第 0 个 slot(vtable 指针) +2. 加载 vtable 指针 +3. bitcast 为 `[N x i8*]*` 类型 +4. GEP 获取方法索引处的函数指针 +5. 加载函数指针 +6. bitcast 为正确的函数指针类型 +7. 间接调用 + +## 继承 + +### 结构体成员继承 + +当子类继承父类(父类在 `Gen.class_members` 中存在)时: + +- 父类的成员变量被继承到子类(排在子类成员之前) +- 父类的默认值也被继承 +- 父类的方法被继承(重命名为 `子类名.方法名`) + +```python +@t.Object +class Animal: + name: list[t.CChar, 32] + age: t.CInt + + def __init__(self, age: t.CInt): + self.age = age + + def Speak(self) -> t.CVoid: + serial.puts("...\n") + +@t.Object +class Dog(Animal): + breed: t.CInt + + def Speak(self) -> t.CVoid: + serial.puts("Woof!\n") +``` + +### 异常类继承 + +Viper 支持异常类的继承,用于 `try/except` 的异常匹配: + +```python +class MyError(Exception): + pass + +class SpecificError(MyError): + pass +``` + +详见 [09-exceptions.md](09-exceptions.md)。 + +## 运算符重载 + +`@t.Object` 类支持运算符重载。编译器在遇到运算符时,首先检查左操作数是否为结构体类型,如果是则尝试调用对应的 dunder 方法。 + +### 算术运算符重载 + +| 运算符 | Dunder 方法 | 示例 | +|--------|------------|------| +| `+` | `__add__` | `a + b` → `a.__add__(b)` | +| `-` | `__sub__` | `a - b` → `a.__sub__(b)` | +| `*` | `__mul__` | `a * b` → `a.__mul__(b)` | +| `/` | `__truediv__` | `a / b` → `a.__truediv__(b)` | +| `//` | `__floordiv__` | `a // b` → `a.__floordiv__(b)` | +| `%` | `__mod__` | `a % b` → `a.__mod__(b)` | +| `**` | `__pow__` | `a ** b` → `a.__pow__(b)` | + +示例: + +```python +@t.Object +class Vec2: + x: t.CFloat + y: t.CFloat + + def __init__(self, x: t.CFloat, y: t.CFloat): + self.x = x + self.y = y + + def __add__(self, other: Vec2) -> Vec2: + result: Vec2 = Vec2(0.0, 0.0) + result.x = self.x + other.x + result.y = self.y + other.y + return result + + def __mul__(self, scalar: t.CFloat) -> Vec2: + result: Vec2 = Vec2(0.0, 0.0) + result.x = self.x * scalar + result.y = self.y * scalar + return result +``` + +### 增量赋值运算符重载 + +| 增量运算符 | 优先 Dunder | 回退 Dunder | +|-----------|------------|------------| +| `+=` | `__iadd__` | `__add__` | +| `-=` | `__isub__` | `__sub__` | +| `*=` | `__imul__` | `__mul__` | +| `/=` | `__itruediv__` | `__truediv__` | +| `//=` | `__ifloordiv__` | `__floordiv__` | +| `%=` | `__imod__` | `__mod__` | +| `**=` | `__ipow__` | `__pow__` | + +如果未定义增量版本(如 `__iadd__`),编译器自动回退到普通版本(如 `__add__`)。 + +### 比较运算符重载 + +> **实验性**:以下比较运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。定义它们不会报错,但比较运算不会自动调用。 + +| 运算符 | Dunder 方法 | 状态 | +|--------|------------|------| +| `==` | `__eq__` | 仅类型推断识别 | +| `!=` | `__ne__` | 仅类型推断识别 | +| `<` | `__lt__` | 仅类型推断识别 | +| `<=` | `__le__` | 仅类型推断识别 | +| `>` | `__gt__` | 仅类型推断识别 | +| `>=` | `__ge__` | 仅类型推断识别 | + +### 反向运算符重载 + +> **实验性**:以下反向运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。 + +| Dunder 方法 | 预期语义 | 状态 | +|------------|---------|------| +| `__radd__` | 右操作数加法 | 仅类型推断识别 | +| `__rsub__` | 右操作数减法 | 仅类型推断识别 | +| `__rmul__` | 右操作数乘法 | 仅类型推断识别 | +| `__rtruediv__` | 右操作数真除法 | 仅类型推断识别 | +| `__rfloordiv__` | 右操作数整除 | 仅类型推断识别 | +| `__rmod__` | 右操作数取模 | 仅类型推断识别 | +| `__rpow__` | 右操作数幂运算 | 仅类型推断识别 | + +### 一元运算符重载 + +> **实验性**:以下一元运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。 + +| 运算符 | Dunder 方法 | 状态 | +|--------|------------|------| +| `-a` | `__neg__` | 仅类型推断识别 | +| `+a` | `__pos__` | 仅类型推断识别 | + +## 可调用对象 `__call__` + +```python +@t.Object +class Counter: + value: t.CInt + + def __init__(self): + self.value = 0 + + def __call__(self) -> t.CInt: + self.value += 1 + return self.value + +c: Counter = Counter() +x: t.CInt = c() # x = 1 +y: t.CInt = c() # y = 2 +``` + +## 下标访问重载 + +### `__getitem__` — 读取 + +```python +def __getitem__(self, key: t.CInt) -> t.CInt: + return self.data[key] +``` + +### `__setitem__` — 赋值 + +```python +def __setitem__(self, key: t.CInt, value: t.CInt): + self.data[key] = value +``` + +### `__delitem__` — 删除 + +```python +def __delitem__(self, key: t.CInt): + pass +``` + +## 布尔转换 `__bool__` + +```python +@t.Object +class Buffer: + size: t.CInt + data: list[t.CChar, 1024] + + def __bool__(self) -> t.CBool: + return self.size > 0 + +buf: Buffer = Buffer() +if buf: + serial.puts("buffer is not empty\n") +``` + +## 长度 `__len__` + +```python +@t.Object +class Buffer: + size: t.CInt + + def __len__(self) -> t.CInt: + return self.size + +buf: Buffer = Buffer() +n: t.CInt = len(buf) +``` + +## 字符串转换 `__str__` + +```python +@t.Object +class Point: + x: t.CInt + y: t.CInt + + def __str__(self) -> t.CConst | t.CChar | t.CPtr: + return "Point" + +p: Point = Point(1, 2) +print(p) # 调用 p.__str__() +``` + +## 绝对值 `__abs__` + +```python +@t.Object +class SignedValue: + val: t.CInt + + def __abs__(self) -> t.CInt: + if self.val < 0: + return -self.val + return self.val + +sv: SignedValue = SignedValue() +sv.val = -42 +a: t.CInt = abs(sv) # a = 42 +``` + +## 迭代器协议 + +Viper 的迭代器协议与 Python 相同,但 `__next__` 的实现方式通过 `StopIteration` 异常来结束。 + +### `__iter__` 和 `__next__` + +```python +@t.Object +class IntRange: + start: t.CInt + end: t.CInt + current: t.CInt + + def __init__(self, start: t.CInt, end: t.CInt): + self.start = start + self.end = end + self.current = start + + def __iter__(self): + return self + + def __next__(self, stop_flag) -> t.CInt: + if self.current >= self.end: + raise StopIteration + val: t.CInt = self.current + self.current += 1 + return val +``` + +### for 循环使用 + +```python +r: IntRange = IntRange(0, 10) +for i in r: + print(i) +``` + +编译器生成的等价逻辑: + +```c +IntRange r = IntRange_init(0, 10); +IntRange iter = IntRange___iter__(&r); +while (1) { + i1 stop_flag = 0; + int i = IntRange___next__(&iter, &stop_flag); + if (stop_flag == 1) break; + print_int(i); +} +``` + +## 上下文管理器 + +`with` 语句要求对象实现 `__enter__` 和 `__exit__` 方法: + +```python +@t.Object +class File: + fd: t.CInt + path: t.CConst | t.CChar | t.CPtr + + def __init__(self, path: t.CConst | t.CChar | t.CPtr, flags: t.CInt): + self.path = path + self.fd = -1 + + def __enter__(self): + self.fd = fat32.open(self.path, self.flags) + return self + + def __exit__(self): + fat32.close(self.fd) + + def read(self) -> t.CInt: + return fat32.read(self.fd) +``` + +使用方式: + +```python +with File("/test.txt", FA_READ) as f: + data: t.CInt = f.read() +``` + +编译器会自动保证 `__exit__` 在 `with` 块结束时被调用。 + +## 析构 `__del__` / `__delete__` + +```python +del obj # 调用 obj.__del__() 或 obj.__delete__() +del arr[idx] # 调用 arr.__delitem__(idx) +``` + +## Dunder 方法完整参考 + +### 已实现自动调度的 Dunder 方法 + +| Dunder 方法 | 触发语法 | 说明 | +|------------|---------|------| +| `__init__` | `ClassName(args)` | 构造函数 | +| `__before_init__` | 自动生成 | vtable 初始化,在 `__init__` 之前执行 | +| `__add__` | `a + b` | 加法 | +| `__sub__` | `a - b` | 减法 | +| `__mul__` | `a * b` | 乘法 | +| `__truediv__` | `a / b` | 真除法 | +| `__floordiv__` | `a // b` | 整除 | +| `__mod__` | `a % b` | 取模 | +| `__pow__` | `a ** b` | 幂运算 | +| `__iadd__` | `a += b` | 增量加法(回退到 `__add__`) | +| `__isub__` | `a -= b` | 增量减法(回退到 `__sub__`) | +| `__imul__` | `a *= b` | 增量乘法(回退到 `__mul__`) | +| `__itruediv__` | `a /= b` | 增量真除法(回退到 `__truediv__`) | +| `__ifloordiv__` | `a //= b` | 增量整除(回退到 `__floordiv__`) | +| `__imod__` | `a %= b` | 增量取模(回退到 `__mod__`) | +| `__ipow__` | `a **= b` | 增量幂运算(回退到 `__pow__`) | +| `__call__` | `obj(args)` | 可调用对象 | +| `__getitem__` | `obj[key]` | 下标读取 | +| `__setitem__` | `obj[key] = value` | 下标赋值 | +| `__delitem__` | `del obj[key]` | 下标删除 | +| `__bool__` | `if obj:` | 布尔转换 | +| `__len__` | `len(obj)` | 长度 | +| `__str__` | `str(obj)` / `print(obj)` | 字符串转换 | +| `__abs__` | `abs(obj)` | 绝对值 | +| `__iter__` | `for x in obj:` | 获取迭代器 | +| `__next__` | `for x in obj:` | 获取下一个值(标志位方式) | +| `__enter__` | `with obj as x:` | 上下文管理器进入 | +| `__exit__` | `with obj as x:` | 上下文管理器退出 | +| `__del__` | `del obj` | 析构 | +| `__delete__` | `del obj` | 删除描述符 | + +### 声明支持但未实现自动调度的 Dunder 方法 + +| Dunder 方法 | 预期触发语法 | 当前状态 | +|------------|------------|---------| +| `__eq__` | `a == b` | 仅类型推断识别,比较运算不自动调度 | +| `__ne__` | `a != b` | 同上 | +| `__lt__` | `a < b` | 同上 | +| `__le__` | `a <= b` | 同上 | +| `__gt__` | `a > b` | 同上 | +| `__ge__` | `a >= b` | 同上 | +| `__neg__` | `-a` | 仅类型推断识别,一元负号不自动调度 | +| `__pos__` | `+a` | 同上 | +| `__radd__` | 右操作数加法 | 仅类型推断识别 | +| `__rsub__` | 右操作数减法 | 同上 | +| `__rmul__` | 右操作数乘法 | 同上 | +| `__rtruediv__` | 右操作数真除法 | 同上 | +| `__rfloordiv__` | 右操作数整除 | 同上 | +| `__rmod__` | 右操作数取模 | 同上 | +| `__rpow__` | 右操作数幂运算 | 同上 | diff --git a/wiki/07-control-flow.md b/wiki/07-control-flow.md new file mode 100644 index 0000000..6115aee --- /dev/null +++ b/wiki/07-control-flow.md @@ -0,0 +1,256 @@ +# 07 - 控制流 + +Viper 支持 Python 风格的控制流语句,编译为 LLVM IR 的基本块和分支指令。 + +## 条件语句 + +### if / elif / else + +```python +if x > 0: + y = 1 +elif x == 0: + y = 0 +else: + y = -1 +``` + +等价 C 代码: +```c +if (x > 0) { + y = 1; +} else if (x == 0) { + y = 0; +} else { + y = -1; +} +``` + +### 条件表达式 + +```python +is_dir: t.CInt = 1 if (info.attr & AM_DIR) else 0 +``` + +等价 C 代码: +```c +int is_dir = (info.attr & AM_DIR) ? 1 : 0; +``` + +### None 检查 + +```python +if BootInfo != None: + paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize) +else: + paging.init(0, 0) +``` + +等价 C 代码: +```c +if (BootInfo != NULL) { + paging_init(BootInfo->MemmapAddr, BootInfo->MemmapSize); +} else { + paging_init(0, 0); +} +``` + +## 循环语句 + +### while 循环 + +```python +i: t.CInt = 0 +while i < 10: + buf[i] = 0 + i += 1 +``` + +等价 C 代码: +```c +int i = 0; +while (i < 10) { + buf[i] = 0; + i += 1; +} +``` + +### while-else + +```python +while i < count: + if found: + break +else: + serial.puts("not found\n") +``` + +`else` 块在循环正常结束(非 `break` 退出)时执行。 + +### 无限循环 + +```python +while True: + sched.Scheduler._yield() +``` + +等价 C 代码: +```c +while (1) { + scheduler_yield(); +} +``` + +### for 循环(range)(关于 for 循环的更多用法,参见 [06-oop.md 中 迭代器协议](06-oop.md#迭代器协议)) + +```python +for i in range(10): + buf[i] = 0 + +for i in range(5, 10): + buf[i] = 0 + +for i in range(0, 100, 2): + buf[i] = 0 +``` + +等价 C 代码: +```c +for (int i = 0; i < 10; i++) { + buf[i] = 0; +} + +for (int i = 5; i < 10; i++) { + buf[i] = 0; +} + +for (int i = 0; i < 100; i += 2) { + buf[i] = 0; +} +``` + +### for 循环(迭代器) + +如果类实现了 `__iter__` 和 `__next__` 方法,可以使用 `for ... in` 迭代: + +```python +container: Iter = Iter() +for item in container: + process(item) +``` + +### for-else + +```python +for i in range(count): + if items[i] == target: + break +else: + serial.puts("not found\n") +``` + +### break 和 continue + +```python +while True: + if done: + break + if skip: + continue + process() +``` + +## match 语句 + +Viper 支持 Python 3.10+ 的 `match` 语句,编译为 C 的 `switch` 语句: + +```python +match self.ctype: + case UI_LABEL: + self.RenderLabel(sh) + case UI_BUTTON: + self.RenderButton(sh) + case UI_PANEL: + self.RenderPanel(sh) + case _: + pass +``` + +等价 C 代码: +```c +switch (self->ctype) { + case UI_LABEL: + self_RenderLabel(self, sh); + break; + case UI_BUTTON: + self_RenderButton(self, sh); + break; + case UI_PANEL: + self_RenderPanel(self, sh); + break; + default: + break; +} +``` + +### match 值匹配 + +```python +match code: + case 0: + serial.puts("OK\n") + case 1: + serial.puts("Error\n") + case _: + serial.puts("Unknown\n") +``` + +### match 或模式 + +```python +match value: + case 1 | 2 | 3: + serial.puts("small\n") + case _: + serial.puts("other\n") +``` + +### fallthrough(无 break) + +默认每个 `case` 自动添加 `break`。如需 fallthrough,使用 `c.NoBreak`: + +```python +match value: + case 1: + do_one() + c.NoBreak + case 2: + do_two() +``` + +如果需要提前 break,需要使用 `c.Break()`,因为在 `Python` 中,`match` 分支不支持直接使用 `break`。 + +## assert 语句 +> 避免使用此语句,此语句未经充分测试,在多数情况下,编译器不知道如何展示结果。 + +```python +assert ptr != None, "null pointer" +``` + +编译为条件检查和错误报告。 + +## with 语句 + +`with` 语句用于资源管理,要求对象实现 `__enter__` 和 `__exit__` 方法: + +```python +with File("/test.txt", FA_READ) as f: + data: t.CInt = f.read() +``` + +等价 C 代码: +```c +File* f = File_enter(File_new("/test.txt", FA_READ)); +int data = File_read(f); +File_exit(f); +``` diff --git a/wiki/08-c-operations.md b/wiki/08-c-operations.md new file mode 100644 index 0000000..6bad6a0 --- /dev/null +++ b/wiki/08-c-operations.md @@ -0,0 +1,250 @@ +# 08 - C 语言操作 + +Viper 通过 `c` 模块提供对 C 语言底层特性的访问,包括指针操作、内联汇编、预处理指令等。 + +## 指针操作 + +### 取地址 `c.Addr` + +```python +x: t.CInt = 42 +p: t.CInt | t.CPtr = c.Addr(x) # int* p = &x; +``` + +对结构体成员取地址: + +```python +res: t.CInt = fat32.opendir("/", c.Addr(dp)) # res = fat32_opendir("/", &dp); +``` + +对数组取地址: + +```python +viperlib.snprintf(c.Addr(buf), 64, "hello %d", 42) # snprintf(&buf, 64, "hello %d", 42); +``` + +### 解引用 `c.Deref` + +```python +ptr: Sheet | t.CPtr = c.Addr(sheet_obj) +obj: Sheet = c.Deref(ptr) # struct Sheet obj = *ptr; +``` + +### 内存拷贝 `c.Load` + +```python +c.Load(ptr, value) # *ptr = *value; +``` + +### 解引用赋值 `c.DerefAs` + +```python +c.DerefAs(ptr, value) # *ptr = value; +``` + + +### 赋值 `c.Set` + +```python +c.Set(target, value) # target = value; +``` + +## 内联汇编 `c.Asm` + +Viper 提供了声明式的内联汇编语法,编译为 GCC 风格的 `__asm__ __volatile__` 语句。 + +### 基本用法 + +```python +c.Asm("nop") # __asm__ __volatile__("nop"); +``` + +### 带操作数的汇编 + +使用 f-string 和 `c.AsmInp` / `c.AsmOut` 标记操作数: + +```python +saved_rdi: t.CUnsignedLong +c.Asm(f"mov {c.AsmOut(saved_rdi, t.ASM_DESCR.OUTPUT_REG)}, rdi", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI]) +``` + +等价 C 代码: +```c +__asm__ __volatile__( + "mov %0, rdi" + : "=r"(saved_rdi) + : + : "memory", "rdi" +); +``` + +### 输入操作数 `c.AsmInp` + +```python +msg: t.CConst | t.CChar | t.CPtr = "Hello" +c.Asm(f"mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)}", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX]) +``` + +### 完整示例 + +```python +c.Asm(f"""mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)} + call {c.AsmInp(log_info_fn, t.ASM_DESCR.REG_ANY)}""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, + t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX, + t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI, + t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9, + t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11]) +``` + +### ASM_DESCR 约束字符 + +#### 操作数修饰符 + +| 常量 | 值 | 说明 | +|------|----|------| +| `MODIFIER_OUTPUT` | `=` | 输出操作数 | +| `MODIFIER_READWRITE` | `+` | 读写操作数 | +| `MODIFIER_INPUT` | `` | 输入操作数(默认) | +| `MODIFIER_GLOBAL` | `&` | 全局操作数 | + +#### 寄存器约束 + +| 常量 | 值 | 说明 | +|------|----|------| +| `REG_ANY` | `r` | 任何通用寄存器 | +| `REG_EAX` / `REG_RAX` | `a` | EAX/RAX | +| `REG_EBX` / `REG_RBX` | `b` | EBX/RBX | +| `REG_ECX` / `REG_RCX` | `c` | ECX/RCX | +| `REG_EDX` / `REG_RDX` | `d` | EDX/RDX | +| `REG_ESI` / `REG_RSI` | `S` | ESI/RSI | +| `REG_EDI` / `REG_RDI` | `D` | EDI/RDI | +| `REG_XMM` | `x` | XMM 寄存器 | + +#### 内存与立即数 + +| 常量 | 值 | 说明 | +|------|----|------| +| `MEMORY` | `m` | 内存操作数 | +| `IMMEDIATE` | `i` | 立即数 | +| `ANY` | `g` | 通用寄存器/内存/立即数 | + +#### 预定义组合约束 + +| 常量 | 值 | 说明 | +|------|----|------| +| `OUTPUT_REG` | `=r` | 输出,通用寄存器 | +| `OUTPUT_MEM` | `=m` | 输出,内存 | +| `OUTPUT_EAX` | `=a` | 输出,EAX/RAX | +| `INPUT_REG` | `r` | 输入,通用寄存器 | +| `INPUT_MEM` | `m` | 输入,内存 | +| `INPUT_IMM` | `i` | 输入,立即数 | + +#### 破坏描述符 + +| 常量 | 说明 | +|------|------| +| `CLOBBER_EAX` / `CLOBBER_RAX` | 破坏 EAX/RAX | +| `CLOBBER_EBX` / `CLOBBER_RBX` | 破坏 EBX/RBX | +| `CLOBBER_ECX` / `CLOBBER_RCX` | 破坏 ECX/RCX | +| `CLOBBER_EDX` / `CLOBBER_RDX` | 破坏 EDX/RDX | +| `CLOBBER_ESI` / `CLOBBER_RSI` | 破坏 ESI/RSI | +| `CLOBBER_EDI` / `CLOBBER_RDI` | 破坏 EDI/RDI | +| `CLOBBER_CC` | 破坏条件码(标志寄存器) | +| `CLOBBER_MEMORY` | 破坏内存 | +| `CLOBBER_R8` ~ `CLOBBER_R15` | 破坏 R8~R15 | + +## 预处理指令 + +Viper 通过 `c` 模块的函数调用实现 C 预处理指令。 + +### #define + +```python +c.CDefine("MAX_SIZE", 1024) # #define MAX_SIZE 1024 +``` + +上述方法容易引起未定义行为,至少是不便于理解,更常用的方式是使用类型注解: + +```python +MAX_SIZE: t.CDefine = 1024 # #define MAX_SIZE 1024 +``` + +### 条件编译 + +```python +c.CIfndef(HEADER_H) # #ifndef HEADER_H +c.CDefine(HEADER_H) # #define HEADER_H +c.CEndif() # #endif +``` + +```python +c.CIfdef(DEBUG) # #ifdef DEBUG +c.CEndif() # #endif +``` + +```python +c.CIf(VERSION > 2) # #if VERSION > 2 +c.CElif(VERSION > 1) # #elif VERSION > 1 +c.CElse() # #else +c.CEndif() # #endif +``` + +### #undef + +```python +c.Undef(MACRO_NAME) # #undef MACRO_NAME +``` + +### #error + +```python +c.CError("Platform not supported") # #error "Platform not supported" +``` + +### #pragma +> 此关键字已不再支持 +```python +c.CPragma("GCC diagnostic push") # #pragma GCC diagnostic push +``` + +### ## 连接符 +> 此方法可能已经不再支持 +```python +c.TokenPast("PREFIX_", "NAME") # PREFIX_ ## NAME +``` + +由于编译器设计,以及不需要像 `C` 一样做大量字符替换,对于上述所有的条件宏都远比 `C` 差,实际工程中不推荐使用条件宏,后期将完善宏的设计,引入模板等。 + +## 仅声明 `c.State` + +`c.State` 用于声明但不定义函数或变量: + +```python +def isr0() -> t.CExtern | t.CVoid | c.State: pass # extern void isr0(); +``` + +## LLVM IR 内联 + +### c.LLVMIR + +直接嵌入 LLVM IR 指令来实现高效且跨平台的汇编操作: + +```python +c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) +``` + +### c.LInp / c.LOut + +标记 LLVM IR 的输入/输出操作数: + +```python +c.LInp(expr) # 输入操作数 +c.LOut(expr) # 输出操作数 +``` + +## 运算符重载 + +`@t.Object` 类支持运算符重载,详见 [06-oop.md 中 运算符重载](06-oop.md#运算符重载)。 diff --git a/wiki/09-exceptions.md b/wiki/09-exceptions.md new file mode 100644 index 0000000..7f93516 --- /dev/null +++ b/wiki/09-exceptions.md @@ -0,0 +1,186 @@ +# 09 - 异常处理 + +Viper 支持 Python 风格的 `try/except/finally` 异常处理,编译为基于 jmp_buf 和错误码的 C 级别异常处理机制。 + +## 异常处理机制 + +Viper 的异常处理不使用 C++ 风格的零开销异常,而是通过函数参数传递错误码和错误消息实现。编译器自动为可能抛出异常的函数添加 `__eh_msg_out__` 和 `__eh_code_out__` 参数。 + +## try / except + +```python +try: + result = risky_operation() +except ValueError: + serial.puts("ValueError occurred\n") +except OSError: + serial.puts("OSError occurred\n") +except Exception: + serial.puts("Unknown error\n") +``` + +### 内置异常类型 + +Viper 预定义了以下异常类型及其错误码: + +| 异常类型 | 错误码 | +|---------|--------| +| `ValueError` | 1 | +| `TypeError` | 2 | +| `RuntimeError` | 3 | +| `ZeroDivisionError` | 4 | +| `IndexError` | 5 | +| `KeyError` | 6 | +| `IOError` | 7 | +| `OSError` | 8 | +| `AssertionError` | 9 | +| `Exception` | 99 | + +### 自定义异常 + +```python +class DiskFullError(Exception): + pass + +class ReadOnlyError(DiskFullError): + pass +``` + +自定义异常会自动分配递增的错误码(从 100 开始),并支持继承匹配。 + +### 多异常捕获 + +```python +try: + result = operation() +except (ValueError, TypeError): + serial.puts("Value or Type error\n") +``` + +### 获取异常信息 + +```python +try: + result = operation() +except Exception as e: + serial.puts("Error occurred\n") +``` + +## try / finally + +```python +try: + result = operation() +finally: + cleanup() +``` + +`finally` 块无论是否发生异常都会执行。 + +## try / except / finally + +```python +try: + result = operation() +except ValueError: + handle_value_error() +finally: + cleanup() +``` + +## raise 语句 + +### 抛出异常 + +```python +raise ValueError("invalid value") +``` + +### 抛出自定义异常 + +```python +raise MyCustomError("something went wrong") +``` + +### 重新抛出异常 + +```python +raise +``` + +### StopIteration + +`StopIteration` 有特殊处理,用于迭代器协议: + +```python +raise StopIteration +``` + +## 异常处理的编译实现 + +### 函数签名变换 + +可能抛出异常的函数会自动添加错误输出参数: + +```python +def risky_operation() -> t.CInt: + if error: + raise ValueError("bad value") + return 0 +``` + +编译后等价于: + +```c +int risky_operation(char** __eh_msg_out__, int* __eh_code_out__) { + if (error) { + *__eh_code_out__ = 1; // ValueError code + *__eh_msg_out__ = "bad value"; + return 0; + } + return 0; +} +``` + +### 调用点变换 + +```python +try: + result = risky_operation() +except ValueError: + handle_error() +``` + +编译后等价于: + +```c +char* __eh_msg = NULL; +int __eh_code = 0; +int result = risky_operation(&__eh_msg, &__eh_code); +if (__eh_msg != NULL) { + if (__eh_code == 1) { // ValueError + handle_error(); + } +} +``` + +## 异常继承匹配 + +异常匹配支持继承体系。捕获父类异常时,子类异常也会被匹配: + +```python +class FileSystemError(Exception): + pass + +class FileNotFoundError(FileSystemError): + pass + +class PermissionError(FileSystemError): + pass + +try: + operation() +except FileSystemError: + # 也会捕获 FileNotFoundError 和 PermissionError + handle_fs_error() +``` diff --git a/wiki/10-imports.md b/wiki/10-imports.md new file mode 100644 index 0000000..9711a8a --- /dev/null +++ b/wiki/10-imports.md @@ -0,0 +1,191 @@ +# 10 - 模块与导入系统 + +Viper 的模块系统基于 Python 的 `import` 语法,但编译时通过 TransPyC 的符号表和类型系统实现跨模块的类型解析。 + +## 导入语法 + +### 标准导入 + +```python +import t, c # Viper 内置类型和操作模块 +import asm # 汇编辅助模块 +import string # 字符串操作模块 +``` + +### 模块导入 + +```python +import bootinfo +import intr +import platform.pch as pch +import drivers.serial.uart.serial as serial +``` + +### from 导入 + +```python +from stdint import * # 导入所有 stdint 类型别名 +from drivers.video.vesafb.vga import _VGAScreenDriver +``` + +### 相对导入 + +```python +from . import submodule +from .. import parent_module +``` + +## 特殊模块 + +### `t` 模块 + +类型定义模块,提供所有 C 类型对应的 Viper 类型。每个 Viper 文件通常都需要导入: + +```python +import t +``` + +### `c` 模块 + +C 语言操作模块,提供指针操作、内联汇编、预处理指令等: + +```python +import c +``` + +### `asm` 模块 + +汇编辅助模块,提供常用汇编指令的封装: + +```python +import asm + +asm.sti() # __asm__ __volatile__("sti"); +asm.hlt() # __asm__ __volatile__("hlt"); +asm.cli() # __asm__ __volatile__("cli"); +asm.nop() # __asm__ __volatile__("nop"); +asm.BSSClean() # 清零 BSS 段 +``` + +### `string` 模块 + +字符串/内存操作模块,对应 C 标准库的 `string.h`: +> string 部分使用 x86_64 专有汇编进行加速,因此某些函数在其它架构可能需要手动重新编写。 + +```python +import string + +string.memset(c.Addr(buf), 0, 64) # memset(&buf, 0, 64); +string.memcpy(dst, src, size) # memcpy(dst, src, size); +string.memmove(dst, src, size) # memmove(dst, src, size); +string.memcmp(a, b, size) # memcmp(a, b, size); +string.strcmp(a, b) # strcmp(a, b); +string.strcpy(dst, src) # strcpy(dst, src); +``` + +### `stdint` 模块 + +提供 C `stdint.h` 中的类型别名: + +```python +from stdint import * + +# 提供以下类型别名: +# UINT8PTR, UINT16PTR, UINT32PTR, UINT64PTR +# INT8PTR, INT16PTR, INT32PTR, INT64PTR +# 等等 +``` + +### `viperlib` 模块 + +ViperOS 标准库,提供常用 C 库函数: + +```python +import viperlib + +viperlib.snprintf(c.Addr(buf), 64, "value=%d", 42) # snprintf(&buf, 64, "value=%d", 42); +``` + +### `vpsdk` 模块 + +> vpsdk 模块 专供于基于 Viper 开发的示例操作系统 ViperOS,不可用于其它平台,且需要特殊配置。 + +ViperOS 应用 SDK,提供系统调用和窗口管理: + +```python +import vpsdk.window as window +import vpsdk.process as process +import vpsdk.dynlib as dynlib +import vpsdk.syscall as syscall +``` + +## 模块解析流程 + +### 编译时模块加载 + +Viper 的 `import` 是编译时操作,不涉及运行时模块加载。完整的模块解析流程与两阶段编译紧密耦合: + +1. **阶段一**:从入口文件出发,通过 `import` 语句递归发现所有可达的源文件 +2. **阶段一**:对每个源文件生成 `.pyi` 签名存根和 `.stub.ll` LLVM IR 声明 +3. **阶段二**:加载所有 `.pyi` 和 `.stub.ll`,构建共享符号表 +4. **阶段二**:翻译源文件时,通过符号表解析跨模块的类型和函数引用 +5. **阶段二**:将被引用模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部 + +### 类型存根文件(.pyi) + +`.pyi` 文件是模块的声明接口,由 `PythonToStubConverter` 在阶段一生成。存根文件的内容规则: + +| 元素 | 存根表示 | +|------|---------| +| `t.CDefine` 常量 | 保留完整定义(含赋值) | +| `t.CDefine` 函数 | 保留完整函数体 | +| 普通函数 | 仅签名 + `c.State` | +| 全局变量 | 添加 `t.CExtern` | +| 类定义 | 保留成员类型注解和方法签名 | + +存根文件还自动添加宏守卫(`c.CIfndef`/`c.CEndif()`),防止重复包含。 + +### SHA1 命名空间与导入 + +每个模块的函数和结构体在 LLVM IR 中自动加上 SHA1 前缀,消除跨模块符号冲突。只有标记为 `t.CExport` 的函数保持原始名称。详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。 + +### 符号表 + +所有模块的类型信息统一存储在 `SymbolTable` 中,包含: +- 结构体/联合体/枚举定义 +- 函数签名 +- 全局变量 +- typedef 别名 +- `t.CDefine` 常量 + +### 跨模块类型引用 + +```python +# 在 fat32_types.py 中定义 +class fat32_fileinfo: + fname: list[t.CChar, 13] + attr: t.CUInt8T + file_size: t.CUInt32T + +# 在其他模块中引用 +import fat32_types +info: fat32_types.fat32_fileinfo +``` + +跨模块引用的结构体在 LLVM IR 中使用 SHA1 前缀的类型名: +```llvm +%".fat32_fileinfo" = type { [13 x i8], i8, i32 } +``` + +## 项目 includes 配置 + +在 `project.json` 中配置模块搜索路径: + +```json +{ + "includes": ["../.."], + "source_dir": "./Kernel" +} +``` + +编译器会在 `includes` 指定的目录中搜索导入的模块。 diff --git a/wiki/11-builtins.md b/wiki/11-builtins.md new file mode 100644 index 0000000..877b367 --- /dev/null +++ b/wiki/11-builtins.md @@ -0,0 +1,204 @@ +# 11 - 内置函数与运算符 + +Viper 支持 Python 内置函数和运算符,编译为对应的 C/LLVM 操作。 + +## 内置函数 + +### print + +```python +print("Hello, World!") # 调用 puts 或 printf +print(x, y) # 多参数输出 +``` + +### len + +```python +n: t.CInt = len(array) # 获取数组长度(编译时常量) +``` + +### sizeof + +```python +s: t.CSizeT = sizeof(t.CInt) # sizeof(int) +s: t.CSizeT = obj.__sizeof__() # sizeof(obj) +``` + +### abs + +```python +a: t.CInt = abs(x) # abs(x) +``` + +### int / float / bool + +```python +i: t.CInt = int(3.14) # (int)3.14 +f: t.CFloat = float(42) # (float)42 +b: t.CBool = bool(x) # x != 0 +``` + +### min / max + +```python +m: t.CInt = min(a, b) # a < b ? a : b +m: t.CInt = max(a, b) # a > b ? a : b +``` + +### chr / ord + +```python +c: t.CChar = chr(65) # 'A' (整数转字符) +n: t.CInt = ord('A') # 65 (字符转整数) +``` + +### range + +用于 `for` 循环: + +```python +for i in range(10): pass # for (int i = 0; i < 10; i++) +for i in range(5, 10): pass # for (int i = 5; i < 10; i++) +for i in range(0, 10, 2): pass # for (int i = 0; i < 10; i += 2) +``` + +## 运算符 + +### 算术运算符 + +| Viper | C 等价 | 说明 | +|-------|--------|------| +| `a + b` | `a + b` | 加法 | +| `a - b` | `a - b` | 减法 | +| `a * b` | `a * b` | 乘法 | +| `a / b` | `a / b` | 浮点除法 | +| `a // b` | `a / b` | 整数除法 | +| `a % b` | `a % b` | 取模 | +| `a ** b` | `pow(a, b)` | 幂运算 | +| `-a` | `-a` | 取负 | +| `+a` | `+a` | 正号 | + +### 位运算符 + +| Viper | C 等价 | 说明 | +|-------|--------|------| +| `a & b` | `a & b` | 按位与 | +| `a \| b` | `a \| b` | 按位或 | +| `a ^ b` | `a ^ b` | 按位异或 | +| `~a` | `~a` | 按位取反 | +| `a << n` | `a << n` | 左移 | +| `a >> n` | `a >> n` | 右移 | + +> **注意**:`|` 运算符在类型注解中表示类型组合,在表达式中表示按位或。编译器根据上下文区分。 + +### 比较运算符 + +| Viper | C 等价 | 说明 | +|-------|--------|------| +| `a == b` | `a == b` | 等于 | +| `a != b` | `a != b` | 不等于 | +| `a < b` | `a < b` | 小于 | +| `a > b` | `a > b` | 大于 | +| `a <= b` | `a <= b` | 小于等于 | +| `a >= b` | `a >= b` | 大于等于 | + +### 逻辑运算符 + +| Viper | C 等价 | 说明 | +|-------|--------|------| +| `a and b` | `a && b` | 逻辑与 | +| `a or b` | `a \|\| b` | 逻辑或 | +| `not a` | `!a` | 逻辑非 | + +### 增强赋值运算符 + +| Viper | C 等价 | +|-------|--------| +| `a += b` | `a += b` | +| `a -= b` | `a -= b` | +| `a *= b` | `a *= b` | +| `a //= b` | `a /= b` | +| `a %= b` | `a %= b` | +| `a <<= b` | `a <<= b` | +| `a >>= b` | `a >>= b` | +| `a &= b` | `a &= b` | +| `a \|= b` | `a \|= b` | +| `a ^= b` | `a ^= b` | + +## 类型自动转换 + +Viper 在算术运算中自动进行类型提升: + +1. **整数宽度提升**:较窄的整数类型自动扩展为较宽的类型 + - 有符号类型使用符号扩展(`sext`) + - 无符号类型使用零扩展(`zext`) + +2. **整数到浮点**:整数与浮点数运算时,整数自动转换为浮点 + +3. **浮点精度提升**:`float` 与 `double` 运算时,`float` 提升为 `double` + +## 指针算术 + +指针与整数的加法支持自动计算偏移: + +```python +buf: t.CUInt32T | t.CPtr +buf[i] = value # buf[i] = value; (自动计算偏移) +``` + +## 数组下标 + +```python +buf: list[t.CChar, 64] +buf[0] = 'H' # buf[0] = 'H'; +buf[i] = value # buf[i] = value; + +info.fname[0] # info.fname[0] (结构体数组成员访问) +``` + +## 成员访问 + +```python +obj.x # obj.x (直接成员) +obj.method() # obj.method() (方法调用) +ptr.x # ptr->x (指针自动解引用) +``` + +## 字符串字面量 + +字符串字面量编译为 C 字符串常量(`const char*`),其为只读: + +```python +serial.puts("Hello") # 传递 const char* +``` + +### 字符串索引 + +```python +msg: t.CConst | str = "Hello" +serial.puts(c.Addr(msg[4])) # 访问 msg[4] 的地址,输出 'o' +``` + +## C 标准库函数 + +Viper 内置支持以下 C 标准库函数的直接调用: + +| 函数 | 签名 | +|------|------| +| `strlen(s)` | `size_t strlen(const char* s)` | +| `memset(s, c, n)` | `void* memset(void* s, int c, size_t n)` | +| `memcpy(d, s, n)` | `void* memcpy(void* d, const void* s, size_t n)` | +| `memmove(d, s, n)` | `void* memmove(void* d, const void* s, size_t n)` | +| `memcmp(a, b, n)` | `int memcmp(const void* a, const void* b, size_t n)` | +| `strcmp(a, b)` | `int strcmp(const char* a, const char* b)` | +| `strncmp(a, b, n)` | `int strncmp(const char* a, const char* b, size_t n)` | +| `strcpy(d, s)` | `char* strcpy(char* d, const char* s)` | +| `strncpy(d, s, n)` | `char* strncpy(char* d, const char* s, size_t n)` | +| `strcat(d, s)` | `char* strcat(char* d, const char* s)` | +| `puts(s)` | `int puts(const char* s)` | +| `atoi(s)` | `int atoi(const char* s)` | +| `atol(s)` | `long atol(const char* s)` | +| `abs(x)` | `int abs(int x)` | +| `labs(x)` | `long labs(long x)` | + +部分模式比如裸机没有 libc,则不能使用这些函数,即使环境满足,Viper 标准库也可能和 C 标准库冲突。 diff --git a/wiki/12-project.md b/wiki/12-project.md new file mode 100644 index 0000000..f289240 --- /dev/null +++ b/wiki/12-project.md @@ -0,0 +1,252 @@ +# 12 - 项目配置与构建 + +Viper 项目使用 `project.json` 配置文件管理编译和链接参数。 + +## project.json 结构 + +```json +{ + "name": "Kernel", + "version": "1.0.0", + "source_dir": "./Kernel", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-mtriple=x86_64-none-elf", "-relocation-model=static", "-O2"] + }, + "linker": { + "cmd": "ld.lld.exe", + "flags": [ + "-m", "elf_x86_64", + "-T", "linker.ld", + "--oformat", "elf64-x86-64", + "--strip-all" + ], + "output": "kernel.bin" + }, + "includes": ["../../includes"], + "target": { + "triple": "x86_64-none-elf", + "datalayout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} +``` + +## 配置项说明 + +### 基本信息字段 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `name` | string | 项目名称 | +| `version` | string | 项目版本 | +| `source_dir` | string | 源代码目录(相对于 project.json 所在目录) | +| `temp_dir` | string | 临时文件目录(存放 .pyi 存根等) | +| `output_dir` | string | 输出文件目录 | + +### 编译器配置 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `compiler.cmd` | string | 编译器命令(通常为 `llc`) | +| `compiler.flags` | string[] | 编译器标志 | + +常用 `llc` 标志: +- `-filetype=obj`:输出目标文件 +- `-mtriple=x86_64-none-elf`:目标三元组 +- `-relocation-model=static`:静态重定位 +- `-O2`:优化级别 + +### 链接器配置 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `linker.cmd` | string | 链接器命令(通常为 `ld.lld.exe`) | +| `linker.flags` | string[] | 链接器标志 | +| `linker.output` | string | 输出文件名 | + +常用 `ld.lld` 标志: +- `-m elf_x86_64`:ELF x86_64 格式 +- `-T linker.ld`:链接脚本 +- `--oformat elf64-x86-64`:输出 ELF 格式 +- `--oformat binary`:输出原始二进制(用于内核) +- `--strip-all`:去除所有符号信息 + +### 目标平台配置 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `target.triple` | string | LLVM 目标三元组 | +| `target.datalayout` | string | LLVM 数据布局字符串 | + +默认值: +- triple: `x86_64-none-elf` +- datalayout: `e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128` + +### 包含路径 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `includes` | string[] | 模块搜索路径列表 | + +### 编译选项 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `options.slice_level` | int | 切片优化级别(0-3) | +| `options.target` | string | 编译目标(目前仅支持 `llvm`) | +| `options.strict_mode` | bool | 严格模式 | + +## 切片优化级别 + +| 级别 | 名称 | 说明 | +|------|------|------| +| `0` | `no_optimize` | 无优化 | +| `1` | `conservative` | 保守优化 | +| `2` | `moderate` | 适度优化 | +| `3` | `aggressive` | 激进优化(默认) | +| `s` | `size` | 体积优化 | + +## 项目结构示例 + +### 内核项目 + +``` +VKernel/ +├── project.json # 项目配置 +├── linker.ld # 链接脚本 +├── Kernel/ # 源代码目录 +│ ├── main.py # 内核入口 +│ ├── bootinfo.py +│ ├── intr/ +│ │ ├── gdt.py +│ │ ├── idt.py +│ │ └── syscall.py +│ ├── drivers/ +│ │ ├── serial/ +│ │ ├── video/ +│ │ ├── storage/ +│ │ └── ... +│ └── ... +├── temp/ # 临时文件(自动生成) +│ ├── .pyi # 签名存根(阶段一生成) +│ ├── .stub.ll # LLVM IR 声明(阶段一生成) +│ └── _sha1_map.txt # SHA1→源文件路径映射 +└── output/ # 输出文件(自动生成) + ├── kernel.bin # 内核二进制 + ├── *.deps.json # 依赖信息 + └── linker.ld # 生成的链接脚本 +``` + +### 应用项目 + +``` +HelloWorld/ +├── project.json # 项目配置 +├── linker.ld # 链接脚本 +├── main.py # 应用入口 +├── temp/ # 临时文件 +└── output/ # 输出文件 + └── helloworld.elf # ELF 可执行文件 +``` + +### 库项目 + +``` +SerialLogger/ +├── project.json # 项目配置 +├── linker.ld # 链接脚本 +├── serial_logger.py # 库源码 +├── temp/ # 临时文件 +└── output/ # 输出文件 +``` + +## 链接脚本 + +ViperOS 使用自定义链接脚本控制内存布局: + +```ld +ENTRY(_start) + +SECTIONS +{ + . = 0x100000; /* 加载地址 */ + + .text : { + *(.text.startup) + *(.text*) + } + + .rodata : { + *(.rodata*) + } + + .data : { + *(.data*) + } + + .bss : { + *(.bss*) + *(COMMON) + } +} +``` + +## 编译命令 + +TransPyC 编译器的基本用法(注:适用于单个文件,而不适用于工程): + +```bash +python TransPyC.py -f InputFile -o OutputFile [options] +``` + +### 命令行参数 + +| 参数 | 说明 | +|------|------| +| `-f` | 输入文件路径 | +| `-o` | 输出文件路径 | +| `-wh` | 头文件列表 | +| `-debug` | 调试输出文件 | +| `-cc` | 编译命令 | +| `-cflags` | 编译标志 | +| `-run` | 编译后运行 | +| `-args` | 运行参数 | +| `-h` | 辅助文件(C 或 Python) | + +工程编译使用: +```bash +python Projectrans.py xxx.json +``` +即可 + +## 增量编译 + +TransPyC 支持基于 SHA1 的增量编译,与两阶段编译模型紧密耦合: + +### 阶段一增量 + +- 每个源文件按内容计算 SHA1 哈希(16位) +- 如果 `.pyi` 和 `.stub.ll` 已存在,则跳过生成(缓存命中) +- 只有源文件内容变化导致 SHA1 变化时才重新生成声明接口 +- `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,格式为 `:` + +### 阶段二增量 + +- 阶段二加载 `temp/_sha1_map.txt` 重建 SHA1 映射 +- 过滤掉不在当前 SHA1 映射中的旧 `.pyi` 和 `.stub.ll` 文件 +- 共享符号表一次性构建,避免每个文件重复加载 + +### SHA1 命名空间与增量编译的协同 + +SHA1 同时服务于命名空间隔离和增量编译: +- **命名空间**:非 `t.CExport` 函数和结构体使用 SHA1 前缀,消除符号冲突 +- **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成 + +详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。 diff --git a/wiki/all.md b/wiki/all.md new file mode 100644 index 0000000..4b80528 --- /dev/null +++ b/wiki/all.md @@ -0,0 +1,3555 @@ +# 01 - 语言概述与编译流程 + +## 语言定位 + +`Viper` 是一种 **系统级编程语言**,其语法基于 `Python`,但编译目标为 `LLVM IR`,最终生成原生机器码。`Viper` 不是 `Python` 的超集或子集,也不是"`C` 的语法糖"——它是一门拥有独立类型系统、独立编译模型、独立模块体系的语言。`Viper` 选择 `Python` 语法作为表达形式,是因为 `Python` 的 `AST` 可被标准库直接解析,从而将编译器的精力集中在语义翻译而非词法/语法分析上。同时也是因为 `Python` 是人类公认的可读性最高的语言。 + +而实际上,下文中所有提到的 `C` 语言都是为了便于使用 `C` 的底层开发者理解。由于历史原因,在旧版本中我们使用 `C` 来作为中间语言,如同旧版本的 `C++` 一样,但现在 `target="c"` 的路径已经完全删除,`C` 路径永久不再受维护。 + +### 核心设计决策 + +1. **Python 语法,LLVM 语义**:源文件是完全合法的 `Python` 语法,但通过 `t` 模块的类型注解系统赋予完全不同的语义 —— `t.CInt` 不是 `Python` 的 `int`,而是 `LLVM` 的 `i32` +2. **类型注解即编译指令**:Viper 的类型注解不是可选的提示,而是编译器生成 `LLVM IR` 的决定性依据。`x: t.CInt` 生成 `i32`,`x: t.CInt | t.CPtr` 生成 `i32*`,但无注解时会自动推导,详见下文。 +3. **两阶段编译**:先从源文件提取声明接口(`.pyi` + `.stub.ll`),再使用声明接口翻译源文件为含代码的 `.ll`。这是 `Viper` 区别于简单"`Python` 转 `C`"工具的关键架构 +4. **`SHA1` 命名空间**:每个源文件按内容 `SHA1` 哈希命名,非导出函数和结构体自动加上 `SHA1` 前缀,从根本上消除跨模块的符号冲突 +5. **万物皆数据**:为便于底层开发,实际上所有的变量和类型一般并不适用于鸭子类型,但在语义层面我们会尽可能贴近鸭子类型。 + +### 与 `Python` 的关系 + +| 特性 | `Python` | `Viper` | +|------|--------|-------| +| 类型系统 | 动态类型 | 静态类型(通过 `t` 模块注解,编译时确定) | +| 内存管理 | `GC` 自动回收 | 手动管理,无 `GC`,无运行时 | +| 运行时 | 解释执行 + 字节码 | 编译为原生机器码(通过 `LLVM`) | +| 对象模型 | 万物皆对象 | 仅 `@t.Object` 类有对象语义,`@t.CVTable` 为多态,普通 `class` 仅为结构体布局 | +| 标准库 | `Python` 标准库 | `Viper` 标准库(`includes/`)+ `ViperOS SDK` | +| 空值 | `None` | `None`(编译为 `NULL`/零值) | +| 模块系统 | 运行时 `import` | 编译时解析,插入 `.stub.ll`,`SHA1` 命名空间隔离 | + +### 与 C 的关系 + +Viper 编译后的代码在底层等价于 `C` 编译后的机器码(都经过 LLVM),但 Viper 在语言层面提供了 C 所没有的能力: + +- **SHA1 命名空间**:自动消除符号冲突,无需手动管理 `static`/命名前缀 +- **类型组合语法**:`t.CConst | t.CInt | t.CPtr` 比 `const int*` 更具组合性 +- **声明式内联汇编**:`c.Asm(f"mov {c.AsmOut(x, t.ASM_DESCR.OUTPUT_REG)}, rdi")` 比裸 `__asm__` 更安全,也更具可读性。 +- **结构化预处理**:`c.CIfdef`/`c.CEndif()` 替代 `#ifdef`/`#endif`。 +- **面向对象**:`@t.Object` + `@t.CVTable` 提供 `vtable` 支持的 `OOP` +- **存根驱动的模块系统**:`.pyi` 存根文件实现跨模块类型解析,无需头文件 +- **更多内容**:额外更多的不依赖操作系统的函数和语法 + +## 两阶段编译流程 + +Viper 的编译由 `Projectrans.py` 驱动,分为两个阶段。这是 Viper 编译模型的核心,理解两阶段编译是理解 `t.CDefine`、`t.CExport`、`t.CInline` 等关键概念的前提。 + +``` +源文件 (.py) ────────────────────────────────────────────────────── + │ │ + │ ┌─────────────── 阶段一:声明提取 ───────────────┐ │ + │ │ │ │ + │ │ 1. 计算源文件 SHA1 │ │ + │ │ 2. 生成 .pyi(签名存根) │ │ + │ │ 3. 构建结构体注册表 │ │ + │ │ 4. 生成 .stub.ll(LLVM IR 声明) │ │ + │ │ │ │ + │ └────────────────────────────────────────────────┘ │ + │ │ + │ ┌─────────────── 阶段二:代码翻译 ───────────────┐ │ + │ │ │ │ + │ │ 1. 加载所有 .pyi 和 .stub.ll │ │ + │ │ 2. 构建共享符号表 │ │ + │ │ 3. 收集内联函数符号 │ │ + │ │ 4. 翻译源文件 → .ll(含代码) │ │ + │ │ 5. llc 编译 → .o(目标文件) │ │ + │ │ 6. ld.lld 链接 → 可执行文件 │ │ + │ │ │ │ + │ └────────────────────────────────────────────────┘ │ + │ │ + └──────────────────────────────────────────────────────────────┘ +``` + +### 阶段一:声明提取(Phase1Generator) + +阶段一的目标是从每个源文件提取**声明接口**,使其他模块在阶段二翻译时能够正确解析跨模块引用。 + +#### 步骤 1:可达文件发现与拓扑排序 + +从入口文件(`main.py` 或 `project.json` 指定)出发,通过 `import` 语句递归遍历,找出所有可达的 `.py` 源文件。然后对文件进行拓扑排序,确保被依赖的模块先被处理。 + +``` +main.py → import serial → import drivers.serial.uart.serial → ... +``` + +#### 步骤 2:生成 `.pyi` 签名存根 + +对每个源文件,计算其内容的 SHA1 哈希(16位),然后调用 `PythonToStubConverter` 生成签名存根文件 `.pyi`。 + +**SHA1 计算方式**: +```python +sha1 = hashlib.sha1(content.encode('utf-8')).hexdigest()[:16] +``` + +**存根文件的内容规则**: + +| 源文件元素 | 存根文件中的表示 | +|-----------|----------------| +| `t.CDefine` 常量 | 保留原样(含赋值):`MAX_SIZE: t.CDefine = 1024` | +| `t.CDefine` 函数(返回 `t.CDefine` 的函数) | 保留完整函数体(宏展开需要) | +| 普通函数 | 仅保留签名,添加 `| c.State`:`def foo(x: t.CInt) -> t.CVoid | c.State: pass` | +| 类定义 | 保留成员类型注解和方法签名 | +| 全局变量 | 添加 `t.CExtern`:`x: t.CExtern | t.CInt` | +| `c.CIfdef`/`c.CEndif()` 等预处理指令 | 保留原样 | +| `import` 语句 | 保留原样 | + +**关键设计**:`t.CDefine` 常量和 `t.CDefine` 函数在存根中**保留完整定义**(包括赋值和函数体),因为它们是编译时常量/宏,其他模块引用时需要完整展开。普通函数只保留签名并标记 `c.State`(仅声明),因为函数体在阶段二生成。 + + +#### 步骤 3:构建结构体注册表 + +扫描所有已生成的 `.pyi` 文件,提取: +- **结构体名称集合**:所有非枚举、非异常的 `class` 定义 +- **枚举名称集合**:继承 `t.CEnum` 的类 +- **异常名称集合**:继承 `Exception` 的类 +- **结构体→SHA1 映射**:记录每个结构体定义在哪个模块中 + +这个注册表用于阶段一的声明生成和阶段二的类型解析,确保跨模块的结构体引用使用正确的 SHA1 命名空间。 + +#### 步骤 4:生成 `.stub.ll` LLVM IR 声明 + +对每个 `.pyi` 文件,由 `DeclarationGenerator` 生成对应的 LLVM IR 声明文件 `.stub.ll`。 + +**声明生成规则**: + +| 元素 | 生成的 LLVM IR | +|------|---------------| +| 普通函数 | `declare void @".foo"(i32)` — 非 CExport 函数加 SHA1 前缀 | +| CExport 函数 | `declare i32 @main()` — CExport 函数不加前缀,全局可见 | +| 结构体 | `%".ClassName" = type { i32, i32* }` — 类型名加 SHA1 前缀 | +| 全局变量 | `@varname = external global i32` | +| `t.CDefine` 常量 | **不生成声明**(编译时常量,直接内联展开) | +| `t.CTypedef` 别名 | **不生成声明**(类型别名,在类型解析时展开) | +| 枚举 | 为每个枚举成员生成 `@__config_EnumName_member = external global i32` | + +**增量编译**:如果 `.pyi` 或 `.stub.ll` 已存在,则跳过生成(缓存命中)。只有源文件内容变化导致 SHA1 变化时才重新生成。 + +### 阶段二:代码翻译(Phase2Translator) + +阶段二使用阶段一生成的声明接口,将源文件翻译为包含完整代码的 LLVM IR。 + +#### 步骤 1:加载声明接口 + +加载 `temp/` 目录中所有的 `.pyi` 和 `.stub.ll` 文件,构建: +- `sig_files`:SHA1 → `.pyi` 文件路径映射 +- `stub_files`:SHA1 → `.stub.ll` 文件路径映射 +- `sha1_map`:SHA1 → 源文件相对路径映射 + +#### 步骤 2:构建共享符号表 + +一次性构建所有文件共享的符号表数据,避免每个文件重复加载。将所有 `.pyi` 存根和 `.stub.ll` 声明中的类型信息注册到统一的 `SymbolTable` 中。 + +#### 步骤 3:收集内联函数符号 + +扫描 `includes/` 目录中被引用的模块,收集标记为 `t.CInline` 的函数。内联函数的完整 AST body 被保存,在翻译调用点时直接展开。值得注意的是,和 C 语言不同,`t.CInline` 不是优化建议,而是强制性的。 + +#### 步骤 4:翻译源文件 + +对每个源文件,使用 `TransPyC` 翻译器将 Python AST 翻译为 LLVM IR: +1. 将对应模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部 +2. 所有被引用模块的 `.stub.ll` 声明也被嵌入 +3. 翻译 AST 节点为 LLVM IR 指令 +4. 输出 `.ll` 文件 + +#### 步骤 5:编译与链接 + +- `llc`:将每个 `.ll` 编译为 `.o` 目标文件 +- `ld.lld`:将所有 `.o` 链接为最终可执行文件 + +## SHA1 命名空间机制 + +SHA1 命名空间是 Viper 解决跨模块符号冲突的核心机制。 + +### 问题 + +在 C 语言中,多个模块可能定义同名函数或结构体,导致链接时符号冲突。C 的解决方案是 `static`(限制可见性)和命名前缀(手动避免冲突)。 + +### Viper 的解决方案 + +Viper 使用源文件内容的 SHA1 哈希作为命名空间前缀: + +``` +源文件 A.py(SHA1 = a1b2c3d4e5f6g7h8)中定义: + class Point: x: t.CInt; y: t.CInt + def draw(p: Point) -> t.CVoid: ... + +源文件 B.py(SHA1 = i9j0k1l2m3n4o5p6)中也定义: + class Point: x: t.CFloat; y: t.CFloat # 不同的结构体! + def draw(p: Point) -> t.CVoid: ... + +编译后: + A.py 的结构体 → %"a1b2c3d4e5f6g7h8.Point" = type { i32, i32 } + A.py 的函数 → declare void @"a1b2c3d4e5f6g7h8.draw"(%"a1b2c3d4e5f6g7h8.Point"*) + + B.py 的结构体 → %"i9j0k1l2m3n4o5p6.Point" = type { float, float } + B.py 的函数 → declare void @"i9j0k1l2m3n4o5p6.draw"(%"i9j0k1l2m3n4o5p6.Point"*) +``` + +**没有符号冲突**——即使两个模块定义了同名类型和函数,它们的 LLVM IR 符号也是不同的。即便有两个内容完全相同的文件也不会冲突,他们会被识别为同一个文件,然后进行单次编译。 + +### SHA1 前缀的豁免:`t.CExport` + +标记为 `t.CExport` 的函数**不加 SHA1 前缀**,保持原始函数名。这是模块向外部暴露 API/ABI 的机制: + +```python +# main.py — 入口函数,必须全局可见 +def main() -> t.CInt | t.CExport: + return 0 + +# 编译后:define i32 @main() — 无 SHA1 前缀 +``` + +```python +# serial.py — 驱动接口,对外暴露 +def init() -> t.CVoid | t.CExport: + serial_puts("init\n") + +# 编译后:define void @init() — 无 SHA1 前缀,其他模块可直接调用 +``` + +### SHA1 与增量编译 + +SHA1 同时服务于增量编译: +- 源文件内容不变 → SHA1 不变 → `.pyi` 和 `.stub.ll` 缓存命中,跳过阶段一 +- 源文件内容变化 → SHA1 变化 → 重新生成声明接口 +- `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,供阶段二加载 + +理论上,如果一个未经变动的模块的依赖路径上存在变动的模块,暂时的方法是将其简单做 SHA1 替换,暨将旧 SHA1 替换为新 SHA1,但不适用于签名改变的情况,不过签名改变这个未经变动的模块必然也需要改变,但是由于宏展开的存在,不能完全保证不会发生错误情况。且依赖路径的 SHA1 替换成功性未经完整测试,可能出现未定义行为。 + +## `t.CDefine` 深度解析 + +`t.CDefine` 是 Viper 中最特殊的类型——它不是数据类型,而是**编译时元指令**,控制编译器的代码生成行为。 + +### `t.CDefine` 常量 + +```python +MAX_SIZE: t.CDefine = 1024 +PAGE_SIZE: t.CDefine = 4096 +FA_READ: t.CDefine = 0x01 +CPU_FEATURE_FPU: t.CDefine = (1 << 0) +``` + +**编译行为**: +1. **阶段一**:存根生成器保留 `t.CDefine` 常量的完整定义(包括赋值值),因为其他模块可能引用此常量 +2. **阶段一**:`.stub.ll` 声明生成器**跳过** `t.CDefine` 常量,不生成 `external global` 声明 +3. **阶段二**:翻译器遇到 `t.CDefine` 常量的引用时,直接内联其值,不生成任何加载指令 + +这意味着 `t.CDefine` 常量在 LLVM IR 层面**不存在**——它们在编译时被完全展开,等价于 C 的 `#define` 宏。 + +### `t.CDefine` 函数 + +当函数的返回类型注解包含 `t.CDefine` 时,该函数被编译器视为**宏函数**: + +```python +def MAKE_FLAG(bit) -> t.CDefine: + return (1 << bit) + +def GET_PAGE_ORDER(size) -> t.CDefine: + return size // PAGE_SIZE +``` + +**编译行为**: +1. **阶段一**:存根生成器保留 `t.CDefine` 函数的**完整函数体**(不像普通函数那样只保留签名) +2. **阶段二**:翻译器遇到 `t.CDefine` 函数的调用时,将调用内联展开为函数体的计算结果 + +`t.CDefine` 函数在 LLVM IR 中**不生成函数定义**——它们是纯粹的编译时宏。 + +### `t.CDefine` 与类型组合 + +`t.CDefine` 可以与具体类型组合使用,为常量指定底层类型: + +```python +CODE_SEG: t.CDefine | t.CUInt16T = 0x08 +DATA_SEG: t.CDefine | t.CUInt16T = 0x10 +``` + +这表示常量在类型检查时被视为 `t.CUInt16T`(`uint16_t`),但在代码生成时仍然内联展开。 + +## `t.CExport` 深度解析 + +`t.CExport` 控制函数的符号可见性,是 SHA1 命名空间的豁免机制。 + +### 语义 + +| 修饰 | LLVM IR 函数名 | 链接可见性 | 用途 | +|------|---------------|-----------|------| +| 无修饰 | `@.funcname` | 模块内部 | 模块私有函数 | +| `t.CExport` | `@funcname` | 全局可见 | 对外暴露的 API | +| `t.CExtern` | `@funcname`(仅声明) | 外部定义 | 引用外部函数 | + +### 使用场景 + +```python +# 入口函数 — 必须全局可见,链接器需要找到它 +def _start() -> t.CInt | t.CExport: + return kernel_main() + +# 驱动接口 — 其他模块/应用需要调用 +def init() -> t.CVoid | t.CExport: + uart_init() + +# 内部辅助函数 — 不需要全局可见,自动加 SHA1 前缀 +def _helper() -> t.CInt: + return 42 +``` + +### `t.CExport` 在存根中的表现 + +在 `.pyi` 存根文件中,`t.CExport` 函数与普通函数一样只保留签名(添加 `c.State`,表示单纯声明),但 `t.CExport` 标记被保留在返回类型注解中。阶段一的 `DeclarationGenerator` 检查 `t.CExport` 标记来决定是否添加 SHA1 前缀。 + +## `t.CInline` 深度解析 + +`t.CInline` 标记函数为内联函数,编译器在调用点直接展开函数体。 + +### 语义 + +```python +def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline: + return a + b +``` + +**编译行为**: +1. **阶段二预收集**:`_collect_inline_symbols` 扫描 `includes/` 目录中被引用的模块,收集所有 `t.CInline` 函数的 AST body +2. **翻译时展开**:遇到内联函数调用时,将函数体的 AST 直接嵌入调用点,替换参数为实际值 +3. **不生成独立函数**:内联函数不生成 LLVM IR 函数定义(除非也被非内联调用) + +### `t.CInline` 与 `t.CDefine` 函数的区别 + +| 特性 | `t.CInline` | `t.CDefine` 函数 | +|------|------------|-----------------| +| 展开时机 | 阶段二翻译时 | 阶段二翻译时 | +| 类型检查 | 完整的参数和返回类型检查 | 返回类型为宏,类型检查较弱 | +| 存根表示 | 签名 + `c.State` | 完整函数体 | +| LLVM IR | 可能生成函数定义(如果有非内联调用) | 不生成函数定义 | +| 适用场景 | 性能关键的短函数 | 编译时常量和宏计算 | + +## 目标平台 + +默认目标三元组:`x86_64-none-elf` + +数据布局:`e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128` + +## Hello World 示例 + +```python +import t, c + +def main() -> t.CInt | t.CExport: + print("Hello, ViperOS!\n") + return 0 +``` + +编译流程: + +1. **阶段一**:计算 `main.py` 的 SHA1,生成 `.pyi` 存根(`def main() -> t.CInt | t.CExport | c.State: pass`),生成 `.stub.ll` 声明(`declare i32 @main()`,因为是 CExport 不加前缀) +2. **阶段二**:翻译 `main.py` 为 `.ll`,嵌入 `print` 对应的 `puts`/`printf` 声明,生成 `define i32 @main()` 函数体 +3. **编译**:`llc` 将 `.ll` 编译为 `.o` +4. **链接**:`ld.lld` 链接为可执行文件 + + +# 02 - 类型系统 + +Viper 的类型系统通过 `t` 模块提供,所有类型注解继承 `t.CType` 。大都以 `t.C{TypeName:PascalCase}`为类型,类型注解是 Viper 的核心机制,决定了变量的内存布局、大小和对齐方式。 + +## 基本类型 + +### 整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CChar` | `char` | 8 | 是 | +| `t.CShort` | `short` | 16 | 是 | +| `t.CInt` | `int` | 32 | 是 | +| `t.CLong` | `long` | 64 | 是 | +| `t.CUnsignedChar` | `unsigned char` | 8 | 否 | +| `t.CUnsignedShort` | `unsigned short` | 16 | 否 | +| `t.CUnsigned` / `t.CUnsignedInt` | `unsigned int` | 32 | 否 | +| `t.CUnsignedLong` | `unsigned long` | 64 | 否 | +| `t.CSignedChar` | `signed char` | 8 | 是 | + +值得注意的是,t.CUnsigned 一般不单独使用,而是配合其它有符号类型,替换表示无符号,比如 `t.CUnsigned | t.CInt`,由于为了便于使用一些常用类型,则将其组合为常用的 `t.CUnginedInt` 等。 + +### 固定宽度整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CInt8T` | `int8_t` | 8 | 是 | +| `t.CInt16T` | `int16_t` | 16 | 是 | +| `t.CInt32T` | `int32_t` | 32 | 是 | +| `t.CInt64T` | `int64_t` | 64 | 是 | +| `t.CUInt8T` | `uint8_t` | 8 | 否 | +| `t.CUInt16T` | `uint16_t` | 16 | 否 | +| `t.CUInt32T` | `uint32_t` | 32 | 否 | +| `t.CUInt64T` | `uint64_t` | 64 | 否 | + +### 最小宽度整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CIntLeast8T` | `int_least8_t` | ≥8 | 是 | +| `t.CIntLeast16T` | `int_least16_t` | ≥16 | 是 | +| `t.CIntLeast32T` | `int_least32_t` | ≥32 | 是 | +| `t.CIntLeast64T` | `int_least64_t` | ≥64 | 是 | +| `t.CUIntLeast8T` | `uint_least8_t` | ≥8 | 否 | +| `t.CUIntLeast16T` | `uint_least16_t` | ≥16 | 否 | +| `t.CUIntLeast32T` | `uint_least32_t` | ≥32 | 否 | +| `t.CUIntLeast64T` | `uint_least64_t` | ≥64 | 否 | + +### 最快最小宽度整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CIntFast8T` | `int_fast8_t` | ≥8 | 是 | +| `t.CIntFast16T` | `int_fast16_t` | ≥16 | 是 | +| `t.CIntFast32T` | `int_fast32_t` | ≥32 | 是 | +| `t.CIntFast64T` | `int_fast64_t` | ≥64 | 是 | +| `t.CUIntFast8T` | `uint_fast8_t` | ≥8 | 否 | +| `t.CUIntFast16T` | `uint_fast16_t` | ≥16 | 否 | +| `t.CUIntFast32T` | `uint_fast32_t` | ≥32 | 否 | +| `t.CUIntFast64T` | `uint_fast64_t` | ≥64 | 否 | + +### 最大宽度整数类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CIntMaxT` | `intmax_t` | ≥64 | 是 | +| `t.CUIntMaxT` | `uintmax_t` | ≥64 | 否 | + +### stdint 短名别名 + +通过 `import stdint` 引入,这些短名是上述类型的 `t.CTypedef` 别名,便于在系统编程场景中快速使用。允许直接使用 `from stdint import *` 来直接使用。 + +#### 基本类型短名 + +| 短名 | 等价展开 | 说明 | +|------|---------|------| +| `stdint.INT` | `t.CInt` | - | +| `stdint.UINT` | `t.CUnsignedInt` | - | +| `stdint.BOOL` | `t.CInt` | 1 为真,0 为假 | +| `stdint.SHORT` | `t.CShort` | - | +| `stdint.USHORT` | `t.CUnsignedShort` | - | +| `stdint.LONG` | `t.CLong` | - | +| `stdint.ULONG` | `t.CUnsignedLong` | - | +| `stdint.LONGLONG` | `t.CLong \| t.CLong` | - | +| `stdint.ULONGLONG` | `t.CUnsignedLong \| t.CLong` | - | +| `stdint.FLOAT` | `t.CFloat` | - | +| `stdint.DOUBLE` | `t.CDouble` | - | + +#### 固定宽度短名 + +| 短名 | 等价展开 | +|------|---------| +| `stdint.INT8` | `t.CInt8T` | +| `stdint.INT16` | `t.CInt16T` | +| `stdint.INT32` | `t.CInt32T` | +| `stdint.INT64` | `t.CInt64T` | +| `stdint.UINT8` | `t.CUInt8T` | +| `stdint.UINT16` | `t.CUInt16T` | +| `stdint.UINT32` | `t.CUInt32T` | +| `stdint.UINT64` | `t.CUInt64T` | + +#### 字节与字短名 + +| 短名 | 等价展开 | 说明 | +|------|---------|------| +| `stdint.BYTE` | `t.CUnsignedChar` | 8 位无符号 | +| `stdint.WORD` | `t.CUInt16T` | 16 位无符号 | +| `stdint.DWORD` | `t.CUInt32T` | 32 位无符号 | +| `stdint.QWORD` | `t.CUInt64T` | 64 位无符号 | + +#### 字符类型短名 + +| 短名 | 等价展开 | 说明 | +|------|---------|------| +| `stdint.TCHAR` | `t.CChar` | - | +| `stdint.CHARLIST` | `str \| t.CPtr` / `list[str, None]` | - | +| `stdint.WCHAR` | `stdint.WORD` | UTF-16 代码单元 | +| `stdint.CHAR8` | `t.CChar8T` | - | +| `stdint.CHAR16` | `t.CChar16T` | - | +| `stdint.CHAR32` | `t.CChar32T` | - | + +#### 指针短名 + +| 短名 | 等价展开 | +|------|---------| +| `stdint.INTPTR` | `t.CInt \| t.CPtr` | +| `stdint.UINTPTR` | `t.CUnsignedInt \| t.CPtr` | +| `stdint.BYTEPTR` | `stdint.BYTE \| t.CPtr` | +| `stdint.SHORTPTR` | `t.CShort \| t.CPtr` | +| `stdint.USHORTPTR` | `t.CUnsignedShort \| t.CPtr` | +| `stdint.WCHARPTR` | `stdint.WORD \| t.CPtr` | +| `stdint.VOIDPTR` | `t.CVoid \| t.CPtr` | +| `stdint.INT8PTR` | `t.CInt8T \| t.CPtr` | +| `stdint.INT16PTR` | `t.CInt16T \| t.CPtr` | +| `stdint.INT32PTR` | `t.CInt32T \| t.CPtr` | +| `stdint.INT64PTR` | `t.CInt64T \| t.CPtr` | +| `stdint.UINT8PTR` | `t.CUInt8T \| t.CPtr` | +| `stdint.UINT16PTR` | `t.CUInt16T \| t.CPtr` | +| `stdint.UINT32PTR` | `t.CUInt32T \| t.CPtr` | +| `stdint.UINT64PTR` | `t.CUInt64T \| t.CPtr` | +| `stdint.CHAR8PTR` | `t.CChar8T \| t.CPtr` | +| `stdint.CHAR16PTR` | `t.CChar16T \| t.CPtr` | +| `stdint.CHAR32PTR` | `t.CChar32T \| t.CPtr` | + +#### 平台特定短名 + +| 短名 | 等价展开 | 说明 | +|------|---------|------| +| `stdint.FSIZE_t` | `stdint.DWORD` | 文件大小 | +| `stdint.LBA_t` | `stdint.DWORD` | 逻辑块地址 | + +### 平台相关类型 + +| Viper 类型 | C 等价 | 大小(位) | 有符号 | +|------------|--------|-----------|--------| +| `t.CSizeT` | `size_t` | 64 | 否 | +| `t.CIntPtrT` | `intptr_t` | 64 | 是 | +| `t.CUIntPtrT` | `uintptr_t` | 64 | 否 | +| `t.CPtrDiffT` | `ptrdiff_t` | 64 | 是 | + +### stdint 短名别名 + +Viper 在 `stdint` 模块中提供了更简短的类型别名,通过 `t.CTypedef` 映射到对应的完整类型。使用时需 `import stdint`。 + +#### 固定宽度整数短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `INT8` | `t.CInt8T` | `int8_t` | +| `INT16` | `t.CInt16T` | `int16_t` | +| `INT32` | `t.CInt32T` | `int32_t` | +| `INT64` | `t.CInt64T` | `int64_t` | +| `UINT8` | `t.CUInt8T` | `uint8_t` | +| `UINT16` | `t.CUInt16T` | `uint16_t` | +| `UINT32` | `t.CUInt32T` | `uint32_t` | +| `UINT64` | `t.CUInt64T` | `uint64_t` | + +#### 固定宽度指针短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `INT8PTR` | `t.CInt8T \| t.CPtr` | `int8_t*` | +| `INT16PTR` | `t.CInt16T \| t.CPtr` | `int16_t*` | +| `INT32PTR` | `t.CInt32T \| t.CPtr` | `int32_t*` | +| `INT64PTR` | `t.CInt64T \| t.CPtr` | `int64_t*` | +| `UINT8PTR` | `t.CUInt8T \| t.CPtr` | `uint8_t*` | +| `UINT16PTR` | `t.CUInt16T \| t.CPtr` | `uint16_t*` | +| `UINT32PTR` | `t.CUInt32T \| t.CPtr` | `uint32_t*` | +| `UINT64PTR` | `t.CUInt64T \| t.CPtr` | `uint64_t*` | + +#### 字符类型短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `CHAR8` | `t.CChar8T` | `char8_t` | +| `CHAR16` | `t.CChar16T` | `char16_t` | +| `CHAR32` | `t.CChar32T` | `char32_t` | +| `CHAR8PTR` | `t.CChar8T \| t.CPtr` | `char8_t*` | +| `CHAR16PTR` | `t.CChar16T \| t.CPtr` | `char16_t*` | +| `CHAR32PTR` | `t.CChar32T \| t.CPtr` | `char32_t*` | + +#### 基本类型短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `INT` | `t.CInt` | `int` | +| `UINT` | `t.CUnsignedInt` | `unsigned int` | +| `BOOL` | `t.CInt` | `int`(0/1) | +| `SHORT` | `t.CShort` | `short` | +| `USHORT` | `t.CUnsignedShort` | `unsigned short` | +| `LONG` | `t.CLong` | `long` | +| `ULONG` | `t.CUnsignedLong` | `unsigned long` | +| `LONGLONG` | `t.CLong \| t.CLong` | `long long` | +| `ULONGLONG` | `t.CUnsignedLong \| t.CLong` | `unsigned long long` | +| `FLOAT` | `t.CFloat` | `float` | +| `DOUBLE` | `t.CDouble` | `double` | + +#### 平台 / Windows 风格短名 + +| 短名 | 等价 Viper 类型 | C 等价 | +|------|----------------|--------| +| `BYTE` | `t.CUnsignedChar` | `unsigned char`(8位) | +| `BYTEPTR` | `BYTE \| t.CPtr` | `unsigned char*` | +| `WORD` | `t.CUInt16T` | `uint16_t`(16位) | +| `DWORD` | `t.CUInt32T` | `uint32_t`(32位) | +| `QWORD` | `t.CUInt64T` | `uint64_t`(64位) | +| `INTPTR` | `t.CInt \| t.CPtr` | `int*` | +| `UINTPTR` | `t.CUnsignedInt \| t.CPtr` | `unsigned int*` | +| `SHORTPTR` | `t.CShort \| t.CPtr` | `short*` | +| `USHORTPTR` | `t.CUnsignedShort \| t.CPtr` | `unsigned short*` | +| `VOIDPTR` | `t.CVoid \| t.CPtr` | `void*` | +| `TCHAR` | `t.CChar` | `char` | +| `WCHAR` | `WORD` | `uint16_t`(UTF-16) | +| `WCHARPTR` | `WORD \| t.CPtr` | `uint16_t*`(UTF-16) | +| `CHARLIST` | `str \| t.CPtr` | `char*` | +| `FSIZE_t` | `DWORD` | `uint32_t` | +| `LBA_t` | `DWORD` | `uint32_t` | + +### 浮点类型 + +| Viper 类型 | C 等价 | 大小(位) | +|------------|--------|-----------| +| `t.CFloat` | `float` | 32 | +| `t.CDouble` | `double` | 64 | + +### 其他基本类型 + +| Viper 类型 | C 等价 | 说明 | +|------------|--------|------| +| `t.CVoid` | `void` | 空类型 | +| `t.CBool` | `bool` | 布尔类型(8位) | +| `t.CWCharT` | `wchar_t` | 宽字符(32位) | +| `t.CChar8T` | `char8_t` | UTF-8 字符(8位,无符号) | +| `t.CChar16T` | `char16_t` | UTF-16 字符(16位,无符号) | +| `t.CChar32T` | `char32_t` | UTF-32 字符(32位,无符号) | + +### Python 便捷映射类型 +| Python 类型| Viper 类型 | Viper 值 | +|--------|--------|------| +|`int`|`t.CInt`|-| +|`float`|`t.CFloat`|-| +|`str`|`t.CChar \| t.CPtr`|-| +|`bool`|`t.CBool`|-| +|`True`|`t.CBool`|`1`| +|`False`|`t.CBool`|`0`| +|`None`|`NULL`|`t.CIntPtr(0)`| + +对于 t.py 和 c.py 的引用,必须使用 import,不能使用 from ... import ...,也不能使用 as,因为这两者都是直接以字符串识别的。 + +## 类型组合 + +Viper 使用 Python 的 `|` 来组合类型修饰符(TypeUnion),其仅在左值注解中有效,其它位置均为位或语义(至少重载前是这样的),这是 Viper 最重要的语法特性之一。 + +### 指针类型 + +使用 `t.CPtr` 表示指针,通过 `|` 与基本类型组合: + +```python +x: t.CInt | t.CPtr # int* — 指向 int 的指针 +p: t.CVoid | t.CPtr # void* — 通用指针 +s: t.CChar | t.CPtr # char* — 字符串指针 +pp: t.CInt | t.CPtr | t.CPtr # int** — 指向指针的指针 +``` + +等价 C 代码: +```c +int* x; +void* p; +char* s; +int** pp; +``` + +同时,指针也可以用 `Ptr[T]` 的方法表示,但在 Viper 中不太推荐,虽然说这样做一直是类似工程的常见用法,但是如果此处 `T` 是一个多态,同时我们想要复用 Python 的高亮插件,插件无法识别 `Ptr[T]` 的属性取值,但是对于 `T | Ptr` 可以。 + +```python +x: t.CPtr[t.CInt] +p: t.CPtr[t.CVoid] +s: t.CPtr[t.CChar] +pp: t.CPtr[t.CPtr[t.CInt]] +pp2: t.CInt | t.CPtr[t.CPtr] # 同时也可以这么表示 +``` + +等价 C 代码: + +```c +int* x; +void* p; +char* s: +int** pp; +int** pp2; +``` + +### 类型限定符组合 + +```python +x: t.CConst | t.CInt # const int +p: t.CConst | t.CChar | t.CPtr # const char* +``` + +### 存储类组合 + +```python +x: t.CStatic | t.CInt # static int +f: t.CExtern | t.CInt # extern int(声明其存在于外部) +``` + +### 函数返回类型组合 + +```python +def foo() -> t.CInt | t.CExport: # 导出函数,返回 int + return 0 + +def bar() -> t.CVoid | t.CExtern: # 外部函数声明 + pass +``` + +## 数组类型 + +使用 Python 的 `list[ElementType, Size]` 语法表示固定大小数组(通常的,这用于栈上和 BSS 段上): + +```python +buf: list[t.CChar, 64] # char buf[64] +ids: list[t.CInt, 10] # int ids[10] +matrix: list[t.CFloat, 16] # float matrix[16] +entries: list[idt_entry, 256] # struct idt_entry entries[256] +s: list[t.CChar, None] # 自推长度 char s[]; +``` + +等价 C 代码: +```c +char buf[64]; +int ids[10]; +float matrix[16]; +struct idt_entry entries[256]; +``` + +### 数组指针和函数指针 + +```python +lp: list[t.CInt, 12] | t.CPtr +vp: t.Callable[[t.CInt, t.CInt], t.CInt] = x # 其中 t.Callable = typing.Callable,可以直接使用。 +``` + +## 结构体类型 + +使用 `class` 定义结构体,成员通过类型注解声明: + +```python +class point: + x: t.CInt + y: t.CInt +``` + +等价 C 代码: +```c +struct point { + int x; + int y; +}; +``` + +### 带指针成员的结构体 + +```python +class node: + value: t.CInt + next: node | t.CPtr # struct node* next +``` + +### 匿名结构体成员(❌) + +> WARNING: **警告:** 由于 Viper 在声明结构体,枚举等处不需要关键字,因此 `t.Anonymouse` 是不需要使用的。此关键字不再维护,强行使用可能导致未定义行为。 + +继承 `t.Anonymous` 的类作为匿名成员嵌入: + +```python +class header(t.Anonymous): + magic: t.CUInt32T + version: t.CUInt32T + +class packet: + header # 匿名嵌入,可直接访问 packet.magic + length: t.CUInt32T +``` + +### 字节序标记 + +> WARNING: **警告:** 此关键字是实验性的。未经充分测试,不当使用可能导致未定义行为。 + +使用 `t.BigEndian` 或 `t.LittleEndian` 标记成员的字节序: + +```python +class network_packet: + length: t.CUInt16T | t.BigEndian # 大端序存储 + type: t.CUInt8T # 默认小端序 +``` + +## 联合体类型 + +继承 `t.CUnion` 定义联合体: + +```python +class value(t.CUnion): + ival: t.CInt + fval: t.CFloat + pval: t.CVoid | t.CPtr +``` + +等价 C 代码: +```c +union value { + int ival; + float fval; + void* pval; +}; +``` + +## 枚举类型 + +继承 `t.CEnum` 定义枚举: + +```python +class color(t.CEnum): + RED: t.CEnum = 0 + GREEN: t.CEnum = 1 + BLUE: t.CEnum = 2 +``` + +等价 C 代码: +```c +enum color { + RED = 0, + GREEN = 1, + BLUE = 2 +}; +``` + +枚举成员可直接使用名称: + +```python +c: t.CInt = color.RED +``` + +## Typedef + +使用 `t.CTypedef` 创建类型别名: + +```python +irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] # typedef int (*irq_handler_t)(); +``` + +或通过注解赋值: + +```python +MyStruct: t.CTypedef = original_struct # typedef struct original_struct MyStruct; +``` + +更推荐通过后者的形式,前者编译器不一定能够识别到注解是对 t.CTypedef 的,还是后面的注解的,而且容易触发未定义行为。 + +## 强制类型转换 +在 Viper 中的强制类型转换有些不同,强制类型转换有两种方案,都是基于 `t.CType` 的用法,符合 Python 本意。 +对于原先就继承自 `t.CType` 的类型来说,可以直接使用 call 的方法进行类型转换,比如 +```python +x: t.CChar | t.CPtr = "Hello" +t.CVoid(x, t.CPtr) +``` +其中用法为 `t.CType(x, ...)`,此处...可以是其它的 `t.CType` 或将要提到的 `Typedef`,将其视为组合类型对 `x` 进行强制转换。 + +额外补充一句,对于比较,四则运算,可以不使用强制类型转换,而是依靠隐式类型转换,但如果是严谨数学计算,推荐还是强制类型转换避免判断出错。 + +此外,若将一个不同类型的右值赋值到左值,则会隐式将右值转换为左值的类型。 + +如果你不喜欢 `t.CVoid(x, t.CPtr)` 的方法,认为这将 `void` 和 `ptr` 分开,不便于理解,那么还有一个方法,即将二者打包为一个 Typedef,即: +```python +VOIDPTR: t.CTypedef = t.CVoid | t.CPtr +``` +则如果你想,你可以直接通过 call 的方式进行强转,比如: +```python +y: VOIDPTR = VOIDPTR(x) +``` + +## 宏定义常量 + +使用 `t.CDefine` 定义编译时常量。`t.CDefine` 不是数据类型,而是编译时元指令——标记为 `t.CDefine` 的常量在 LLVM IR 中不生成任何全局变量,而是在引用处直接内联展开。详见 [01-overview.md 中 t.CDefine 深度解析](01-overview.md#tcdefine-深度解析)。 + +```python +MAX_SIZE: t.CDefine = 1024 +PAGE_SIZE: t.CDefine = 4096 +FA_READ: t.CDefine = 0x01 +``` + +语义上等价于 C 的 `#define`: +```c +#define MAX_SIZE 1024 +#define PAGE_SIZE 4096 +#define FA_READ 0x01 +``` + +宏定义支持表达式: + +```python +CPU_FEATURE_FPU: t.CDefine = (1 << 0) +CPU_FEATURE_APIC: t.CDefine = (1 << 6) +``` + +宏定义也可与类型组合使用: + +```python +CODE_SEG: t.CDefine | t.CUInt16T = 0x08 +``` + +## 位域 + +使用 `t.Bit(n)` 定义位域成员: + +```python +class flags: + a: t.CUInt32T | t.Bit[1] # 此处,如果存入 2,二进制是 10,会被截断为 0 + b: t.CUInt32T | t.Bit[3] + c: t.CUInt32T | t.Bit[4] +``` + +## LLVM IR 类型简写 + +Viper 提供了 LLVM IR 级别的类型简写: + +```python +i1 # 1位整数 +i8 # 8位有符号整数 +i16 # 16位有符号整数 +i32 # 32位有符号整数 +i64 # 64位有符号整数 +u1 # 1位无符号整数 +u8 # 8位无符号整数 +u16 # 16位无符号整数 +u32 # 32位无符号整数 +u64 # 64位无符号整数 +``` + +仍然通过 `t.x` 的方式调用,比如 `t.i1` 等。 + +## `__attribute__` 属性 + +通过 `t.attr` 命名空间访问 GCC `__attribute__` 属性: + +```python +t.attr.packed() # __attribute__((packed)) +t.attr.aligned(16) # __attribute__((aligned(16))) +t.attr.section(".text.startup") # __attribute__((section(".text.startup"))) +t.attr.always_inline() # __attribute__((always_inline)) +t.attr.noinline() # __attribute__((noinline)) +t.attr.noreturn() # __attribute__((noreturn)) +t.attr.weak() # __attribute__((weak)) +t.attr.unused() # __attribute__((unused)) +t.attr.constructor() # __attribute__((constructor)) +t.attr.destructor() # __attribute__((destructor)) +t.attr.deprecated("use X") # __attribute__((deprecated("use X"))) +``` + +### LLVM 函数属性 + +通过 `t.attr.llvm` 命名空间指定 LLVM 函数属性: + +```python +t.attr.llvm.nobuiltin +t.attr.llvm.nounwind +t.attr.llvm.noredzone +t.attr.llvm.willreturn +t.attr.llvm.mustprogress +t.attr.llvm.optnone +t.attr.llvm.noinline +t.attr.llvm.alwaysinline +t.attr.llvm.readnone +t.attr.llvm.readonly +t.attr.llvm.writeonly +t.attr.llvm.inaccessiblememonly +t.attr.llvm.inaccessiblemem_or_argmemonly +``` + +在函数返回类型注解中使用: + +```python +def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind: + return 0 +``` + + +# 03 - 变量声明与赋值 + +Viper 的变量声明使用 Python 的类型注解语法,通过 `t` 模块指定 C 级别的类型信息。 + +## 带注解的变量声明 + +使用 `变量名: 类型` 语法声明变量: + +```python +x: t.CInt = 0 # int x = 0; +y: t.CUInt32T = 42 # uint32_t y = 42; +name: list[t.CChar, 64] # char name[64]; +ptr: t.CVoid | t.CPtr # void* ptr; +msg: t.CConst | str = "Hello" # const char* msg = "Hello"; +``` + +### 无初始值的声明 + +未赋值的变量声明会生成零初始化的变量,此处是未定义行为,即在不同环境位置可能会覆盖0,也可能不会,最好预先复制或用 memset 清除: + +```python +count: t.CInt # int count = 0; +buffer: list[t.CChar, 256] # char buffer[256] = {0}; +``` + +### 延迟赋值 + +变量可以先声明后赋值: + +```python +x: t.CInt +x = 10 +``` + +### 指针变量 + +```python +p: t.CInt | t.CPtr # int* p; +fb: t.CVoid | t.CPtr # void* fb; +str_ptr: t.CConst | t.CChar | t.CPtr # const char* str_ptr; +``` + +### 指针变量的特殊初始化 + +使用 `t.CVoid(0, t.CPtr)` 初始化指针为 NULL: + +```python +p: t.CVoid | t.CPtr = t.CVoid(0, t.CPtr) # void* p = NULL; +``` + +或使用 `None`: + +```python +p: t.CVoid | t.CPtr = None # void* p = NULL; +``` + +## 普通赋值 + +```python +x: t.CInt = 0 +x = 42 # x = 42; +``` + +## 增强赋值 + +支持所有 Python 增强赋值运算符: + +```python +x: t.CInt = 0 +x += 1 # x += 1; +x -= 1 # x -= 1; +x *= 2 # x *= 2; +x //= 3 # x /= 3; (整数除法) +x %= 5 # x %= 5; +x <<= 1 # x <<= 1; +x >>= 1 # x >>= 1; +x |= 0xFF # x |= 0xFF; +x &= 0x0F # x &= 0x0F; +x ^= 0xAA # x ^= 0xAA; +``` + +## 全局变量 + +模块顶层声明的变量即为全局变量: + +```python +kbd_tid: t.CInt = -1 # 全局 int kbd_tid = -1; +BootInfo: bootinfo | t.CPtr # 全局 struct bootinfo* BootInfo; +``` + +### 静态全局变量 + +```python +x: t.CStatic | t.CInt = 0 # static int x = 0; +``` + +### 外部声明 + +```python +x: t.CExtern | t.CInt # extern int x; +``` + +## 常量定义 + +使用 `t.CDefine` 定义编译时常量。`t.CDefine` 不是数据类型,而是编译时元指令——常量在 LLVM IR 中不生成全局变量,而是在引用处直接内联展开。详见 [01-overview.md 中 t.CDefine 深度解析](01-overview.md#tcdefine-深度解析)。 + +```python +MAX_SIZE: t.CDefine = 1024 +PAGE_SIZE: t.CDefine = 4096 +FA_READ: t.CDefine = 0x01 +FA_WRITE: t.CDefine = 0x02 +``` + +## 字符串常量 + +Viper 中的字符串字面量编译为 C 的字符串常量(`const char*`): + +```python +msg: t.CConst | str = "Hello, World!" +serial.puts(msg) +``` + +也可以直接传递字符串字面量: + +```python +serial.puts("Hello, World!") +``` + +## 类型转换 + +使用类型构造函数进行显式类型转换: + +```python +x: t.CInt = 42 +y: t.CUInt32T = t.CUInt32T(x) # (uint32_t)x +f: t.CFloat = float(x) # (float)x +i: t.CInt = int(f) # (int)f +``` + +### 指针类型转换 + +```python +ptr: t.CVoid | t.CPtr = some_ptr +int_val: t.CUInt64T = t.CUInt64T(ptr) # (uint64_t)ptr — 指针转整数 +``` + +## 结构体实例化 + +> 此处不理解参见 ([05-classes.md 中 结构体实例化与初始化](05-classes.md#结构体实例化与初始化)) + +直接使用类名作为构造函数: + +```python +info: fat32_types.fat32_fileinfo +dp: fat32_types.fat32_dirobj +``` + +带初始化的实例化: + +```python +obj: MyClass = MyClass(arg1, arg2) +``` + +使用 `c.Addr` 获取实例指针: + +```python +obj_ptr: MyClass | t.CPtr = c.Addr(MyClass(arg1, arg2)) +``` + +## delete 语句 + +`del` 语句可用于调用对象的 `__del__` 或 `__delete__` 方法: + +```python +del obj # 调用 obj.__del__() 或 obj.__delete__() +del arr[idx] # 调用 arr.__delitem__(idx) +``` + + +# 04 - 函数定义与调用 + +Viper 的函数定义使用 Python 的 `def` 语法,通过类型注解指定参数类型和返回类型。 + +## 基本函数定义 + +```python +def add(a: t.CInt, b: t.CInt) -> t.CInt: + return a + b +``` + +等价 C 代码: +```c +int add(int a, int b) { + return a + b; +} +``` + +## 无返回值函数 + +```python +def print_msg(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid: + serial.puts(msg) +``` + +等价 C 代码: +```c +void print_msg(const char* msg) { + serial_puts(msg); +} +``` + +## 函数修饰符 + +通过返回类型的 `|` 组合添加函数修饰符: + +### 导出函数 + +` t.CExport` 控制函数的符号可见性——标记为 `t.CExport` 的函数不加 SHA1 前缀,全局可见。详见 [01-overview.md 中 t.CExport 深度解析](01-overview.md#tcexport-深度解析)。 + +```python +def _start() -> t.CInt | t.CExport: + return 0 +``` + +### 外部函数声明 + +使用 `c.State` 表示仅声明不定义: + +```python +def isr0() -> t.CExtern | t.CVoid | c.State: pass +def isr1() -> t.CExtern | t.CVoid | c.State: pass +``` + +等价 C 代码: +```c +extern void isr0(); +extern void isr1(); +``` + +### 内联函数 + +`t.CInline` 标记函数为内联函数,编译器在调用点直接展开函数体。详见 [01-overview.md 中 t.CInline 深度解析](01-overview.md#tcinline-深度解析)。 + +```python +def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline: + return a + b +``` + +### 宏函数 + +当函数返回类型注解包含 `t.CDefine` 时,该函数被视为宏函数,不生成 LLVM IR 函数定义,在调用处内联展开。详见 [01-overview.md 中 t.CDefine 函数](01-overview.md#tcdefine-函数)。 + +```python +def MAKE_FLAG(bit) -> t.CDefine: + return (1 << bit) +``` + +### 静态函数 + +```python +def helper() -> t.CVoid | t.CStatic: + pass +``` + +## 函数属性装饰器 + +使用 `@c.Attribute` 添加 GCC `__attribute__` 属性: + +```python +@c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16)) +def _start() -> t.CInt: + return 0 +``` + +等价 C 代码: +```c +__attribute__((section(".text.startup"), aligned(16))) +int _start() { + return 0; +} +``` + +### 常用属性组合 + +```python +@c.Attribute(t.attr.always_inline()) +def hot_path() -> t.CInt: + return 0 + +@c.Attribute(t.attr.noreturn()) +def panic(msg: t.CConst | t.CChar | t.CPtr) -> t.CVoid: + serial.puts(msg) + while True: pass + +@c.Attribute(t.attr.packed) +``` + +## LLVM 函数属性 + +在返回类型注解中通过 `t.attr.llvm` 指定 LLVM 属性: + +```python +def foo() -> t.CInt | t.attr.llvm.nobuiltin | t.attr.llvm.nounwind: + return 0 +``` + +## 多返回值(CReturn) + +使用 `@c.CReturn` 装饰器实现多返回值,通过指针参数实现: + +```python +@c.CReturn(t.CInt, t.CInt) +def divmod(a: t.CInt, b: t.CInt) -> t.CVoid: + q: t.CInt = a // b + r: t.CInt = a % b + return q, r +``` + +规则: +1. `CReturn` 中的类型数量决定返回值个数 +2. 自动为每个返回类型添加指针参数(`t.CInt` → `t.CInt | t.CPtr`) +3. 参数名自动生成为 `__ReturnValue0__`、`__ReturnValue1__` 等 +4. 调用处自动传参 `&xxx` +5. 必须使用左右值赋值,返回值不能直接传入函数。 + +## 指针参数 + +```python +def read_data(buf: t.CChar | t.CPtr, size: t.CSizeT) -> t.CInt: + pass +``` + +等价 C 代码: +```c +int read_data(char* buf, size_t size); +``` + +### 输出参数模式 + +使用 `c.Addr` 传递变量地址作为输出参数: + +```python +res: t.CInt = fat32.opendir("/", c.Addr(dp)) +``` + +等价 C 代码: +```c +int res = fat32_opendir("/", &dp); +``` + +后续会使用隐式左值获取来减少 `c.Addr` 的直接使用。 + +## 函数指针类型 + +使用 `t.Callable` 定义函数指针类型: + +```python +irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] +``` + +等价 C 代码: +```c +typedef int (*irq_handler_t)(); +``` + +带参数的函数指针: + +```python +callback_t: t.Callable[[t.CInt, t.CInt], t.CVoid] +``` + +## 默认参数 + +Viper 支持函数默认参数值: + +```python +def create_window(x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, title: t.CConst | str = "Window") -> t.CInt: + pass +``` + +## return 语句 + +```python +return 0 # return 0; +return # return; (void 函数) +return a, b # 多返回值(需配合 @c.CReturn) +``` + +## 全局变量声明 + +函数外的变量声明为全局变量,函数内通过 `global` 关键字访问: + +```python +BootInfo: bootinfo | t.CPtr + +def init() -> t.CVoid: + global BootInfo + BootInfo = saved_rdi +``` + +支持 func-in-func 嵌套函数。 + +## Call Func 函数调用 + +函数调用最好通过顺序调用来实现 + +```python +def add(x: int, y: int, z: int): + return (x + y) * z + +def main() -> int | t.CExport: + print(add(1, 2, 3)) # (1 + 2) * 3 = 9 +``` + +这也是 C 中的标准实现方法,但实际上,你也可以乱序传参。 + +```python +# 仍然用刚才的 add 举例 +def main() -> int | t.CExport: + print(add(z=3, x=1, y=2)) # (1 + 2) * 3 = 9 +``` + +乱序传参或带参传参对于结构体的初始化同样有效。同时,你也能够给函数指定默认值。 + +```python +def add(x: int, y: int, z: int = 1): + return (x + y) * z + +def main() -> int | t.CExport: + print(add(1, 2)) # (1 + 2) * 1 = 3 +``` + +在结构体中也可以指定默认值。 + + +# 05 - 类与数据布局 + +Viper 中的 `class` 有两种用途:定义**数据布局**(结构体/联合体/枚举,本章内容),以及定义**面向对象的对象类型**(见 [06-oop.md](06-oop.md))。 + +## 结构体定义 + +普通 `class` 定义编译为 LLVM 结构体类型: + +```python +class point: + x: t.CInt + y: t.CInt +``` + +在 C 中: +```c +struct point { + int x; + int y; +}; +``` + +在 LLVM IR 中: +```llvm +%".point" = type { i32, i32 } +``` + +### 带属性的结构体 + +```python +@c.Attribute(t.attr.packed) +class idt_entry: + base_low: t.CUInt16T + selector: t.CUInt16T + ist_attr: t.CUInt8T + type_attr: t.CUInt8T + base_middle: t.CUInt16T + base_high: t.CUInt32T + reserved1: t.CUInt32T +``` + +### 结构体数组 + +```python +idt: list[idt_entry, 256] = [] +``` + +### 结构体指针成员 + +```python +class node: + value: t.CInt + next: node | t.CPtr # 指向自身的指针(有向图链表) +``` + +### 结构体实例化与初始化 + +```python +entry: idt_entry = idt_entry() +``` + +或带构造函数: + +```python +mousepoint = Point(x=1, y=2) +``` + +乱序传参或带参传参对于结构体的初始化同样有效: + +```python +entry: idt_entry = idt_entry(selector=0x08, base_low=0x0000) +``` + +也可以给结构体成员指定默认值: + +```python +class config: + width: t.CInt = 640 + height: t.CInt = 480 + depth: t.CInt = 32 +``` + +使用 `c.Addr` 获取实例指针: + +```python +obj_ptr: MyClass | t.CPtr = c.Addr(MyClass(arg1, arg2)) +``` + +### 匿名结构体成员(❌) + +> WARNING: **警告:** 由于 Viper 在声明结构体,枚举等处不需要关键字,因此 `t.Anonymouse` 是不需要使用的。此关键字不再维护,强行使用可能导致未定义行为。 + +继承 `t.Anonymous` 的类作为匿名成员嵌入: + +```python +class header(t.Anonymous): + magic: t.CUInt32T + version: t.CUInt32T + +class packet: + header # 匿名嵌入,可直接访问 packet.magic + length: t.CUInt32T +``` + +### 字节序标记 + +> WARNING: **警告:** 此关键字是实验性的。未经充分测试,不当使用可能导致未定义行为。 + +使用 `t.BigEndian` 或 `t.LittleEndian` 标记成员的字节序: + +```python +class network_packet: + length: t.CUInt16T | t.BigEndian # 大端序存储 + type: t.CUInt8T # 默认小端序 +``` + +## 联合体 + +继承 `t.CUnion` 定义联合体: + +```python +class value(t.CUnion): + ival: t.CInt + fval: t.CFloat + pval: t.CVoid | t.CPtr +``` + +等价 C 代码: +```c +union value { + int ival; + float fval; + void* pval; +}; +``` + +## 枚举 + +继承 `t.CEnum` 定义枚举: + +```python +class color(t.CEnum): + RED: t.CEnum = 0 + GREEN: t.CEnum = 1 + BLUE: t.CEnum = 2 +``` + +等价 C 代码: +```c +enum color { + RED = 0, + GREEN = 1, + BLUE = 2 +}; +``` + +枚举成员可直接使用名称: + +```python +c: t.CInt = color.RED +``` + +## Typedef + +使用 `t.CTypedef` 创建类型别名: + +```python +irq_handler_t: t.CTypedef | t.Callable[[], t.CInt] # typedef int (*irq_handler_t)(); +``` + +或通过注解赋值: + +```python +MyStruct: t.CTypedef = original_struct # typedef struct original_struct MyStruct; +``` + +更推荐通过后者的形式,前者编译器不一定能够识别到注解是对 `t.CTypedef` 的,还是后面的注解的,而且容易触发未定义行为。 + +## 位域 + +使用 `t.Bit(n)` 定义位域成员: + +```python +class flags: + a: t.CUInt32T | t.Bit[1] + b: t.CUInt32T | t.Bit[3] + c: t.CUInt32T | t.Bit[4] +``` + +注意:如果存入超出位域宽度的值,会被截断。例如 `a` 为 1 位,存入 2(二进制 `10`)会被截断为 0。 + + +# 06 - 面向对象与运算符重载 + +Viper 中的 `class` 有两种语义:**数据布局**(结构体/联合体/枚举,见 [05-classes.md](05-classes.md))和**面向对象**。面向对象特性通过 `@t.Object` 装饰器启用,多态通过 `@t.CVTable` 装饰器启用。 + +## `@t.Object` 面向对象 + +使用 `@t.Object` 装饰器启用面向对象特性,类将拥有成员方法、运算符重载、属性装饰器等 OOP 支持。编译器也会自动识别:如果结构体内有函数定义,会自动使用 `@t.Object` 行为,但在实际工程中更推荐明确标记,避免未定义行为。 + +### 基本定义 + +```python +@t.Object +class ViperKernel: + BootInfo: bootinfo | t.CPtr + VGA: vga._VGAScreenDriver | t.CPtr + VGA_drv: vga._VGAScreenDriver + + def __init__(self): + self.BootInfo = BootInfo + serial.init() + serial.puts("ViperOS VKernel Test\n") +``` + +避免在 `__init__` 中使用 `return`,虽然不会报错,但是你永远无法获得 `return` 的结果,如果需要提前结束代码流,`return` 也不失为一种办法。 + +### 成员方法 + +```python +@t.Object +class Sheet: + id: t.CInt + x: t.CInt + y: t.CInt + w: t.CInt + h: t.CInt + + def __init__(self, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt): + self.x = x + self.y = y + self.w = w + self.h = h + + def MoveTo(self, nx: t.CInt, ny: t.CInt): + self.x = nx + self.y = ny + + def Resize(self, nw: t.CInt, nh: t.CInt): + self.w = nw + self.h = nh +``` + +### 方法调用 + +```python +sheet: Sheet = Sheet(0, 0, 640, 480) +sheet.MoveTo(100, 100) +sheet.Resize(800, 600) +``` + +### 属性装饰器 + +支持 Python 的 `@property` 和 `@xxx.setter` 装饰器: + +> `@xxx.setter` 和自定义装饰器正在试验阶段,尽可能不要使用 + +```python +@t.Object +class MyObj: + _value: t.CInt + + @property + def value(self) -> t.CInt: + return self._value + + @value.setter + def value(self, v: t.CInt): + self._value = v +``` + +### 静态方法 + +```python +@staticmethod +def _yield(): + pass +``` + +### 对象指针与解引用 + +`@t.Object` 的实例通常通过指针操作: + +```python +obj_ptr: MyClass | t.CPtr = c.Addr(MyClass()) +obj: MyClass = c.Deref(obj_ptr) +``` + +### 成员访问 + +通过 `self` 访问成员变量和方法: + +```python +def method(self) -> t.CVoid: + self.x = 10 + y: t.CInt = self.y + self.DoSomething() +``` + +### 内嵌对象 + +`@t.Object` 可以包含其他对象实例(非指针): + +```python +@t.Object +class Sheet: + _surf_obj: gfx.Surface + _renderer_obj: gfx.Renderer + surf: gfx.Surface | t.CPtr + renderer: gfx.Renderer | t.CPtr + + def __init__(self, fb: UINT32PTR, zb: float | t.CPtr, w: t.CInt, h: t.CInt): + self._surf_obj = gfx.Surface(fb, zb, w, h) + self.surf = c.Addr(self._surf_obj) + self._renderer_obj = gfx.Renderer(self.surf) + self.renderer = c.Addr(self._renderer_obj) +``` + +### `__before_init__` 方法 + +`@t.Object` 或 `@t.CVTable` 类自动生成 `__before_init__` 方法声明,用于在 `__init__` 之前初始化 vtable: + +```llvm +declare void @".ClassName.__before_init__"(%".ClassName"*) +``` + +值得注意的是,`__before_init__` 并不帮忙初始化内存,而只是初始化虚表等准备工作,实际上,我们更希望用户能自己管理内存。实验性阶段内容中,我们通过内存池机制来帮助用户管理碎片化内容,包括部分小的结构体,但较大内容最好还是由用户手动处理。 + +## `@t.CVTable` 虚函数表与多态 + +> 尽可能避免使用 `self[0]` 来获取结构体成员,其不稳定,也不要手动操作虚表。 + +使用 `@t.CVTable` 装饰器可以启用虚函数表支持。启用后,结构体第一个成员自动插入 `i8*` 类型的 vtable 指针。`@t.CVTable` 的操作必须配合 `@t.Object`,但有时编译器会自动识别是否存在结构体内函数,自动使用 `@t.Object`。 + +### 基本定义 + +```python +@t.Object +@t.CVTable +class Base: + def __init__(self): + pass + def method(self) -> t.CInt: + return 0 +``` + +在 LLVM IR 中,`@t.CVTable` 类的结构体类型自动插入 vtable 指针: + +```llvm +%".Base" = type { i8*, i32 } +``` + +同时,编译器会生成全局 vtable 变量: + +```llvm +@".Base_Vtable" = internal global [1 x i8*] zeroinitializer +``` + +### 继承与多态 + +虚表可以帮你使用继承语法实现多态: + +```python +@t.Object +@t.CVTable +class Base: + def __init__(self): + pass + def method(self) -> t.CInt: + return 0 + +@t.Object +@t.CVTable +class M1(Base): + def method(self) -> t.CInt: + return 1 +``` + +当 M1 被初始化时,VTable 会自动修改,这点和 C++ 相同,尽可能避免直接操作 VTable。 + +继承时,子类会自动继承父类的成员变量和方法。子类重写父类方法时,vtable 中对应位置的函数指针被子类方法替换,实现多态。 + +### VTable 运行时修改 + +如果需要临时构造一个额外的 `Base` 结构体,还可以使用: + +```python +@t.Object +@t.CVTable +class Base: + def __init__(self): + pass + def method(self) -> t.CInt: + return 0 + +def __method1(self) -> t.CInt: + return 1 + +def main() -> t.CInt | t.CExport: + b: Base = Base() + b.method = __method1 +``` + +启用 `VTable` 的表中,允许直接修改内部函数为函数指针,在底层,此操作将修改 `VTable` 来达成目的。编译器会检测当前 vtable 是否与类 vtable 相同,如果相同则创建 vtable 的副本(memcpy),避免修改影响所有实例。 + +### 虚方法调度机制 + +虚方法调用的核心流程: + +1. 从对象指针 GEP 获取第 0 个 slot(vtable 指针) +2. 加载 vtable 指针 +3. bitcast 为 `[N x i8*]*` 类型 +4. GEP 获取方法索引处的函数指针 +5. 加载函数指针 +6. bitcast 为正确的函数指针类型 +7. 间接调用 + +## 继承 + +### 结构体成员继承 + +当子类继承父类(父类在 `Gen.class_members` 中存在)时: + +- 父类的成员变量被继承到子类(排在子类成员之前) +- 父类的默认值也被继承 +- 父类的方法被继承(重命名为 `子类名.方法名`) + +```python +@t.Object +class Animal: + name: list[t.CChar, 32] + age: t.CInt + + def __init__(self, age: t.CInt): + self.age = age + + def Speak(self) -> t.CVoid: + serial.puts("...\n") + +@t.Object +class Dog(Animal): + breed: t.CInt + + def Speak(self) -> t.CVoid: + serial.puts("Woof!\n") +``` + +### 异常类继承 + +Viper 支持异常类的继承,用于 `try/except` 的异常匹配: + +```python +class MyError(Exception): + pass + +class SpecificError(MyError): + pass +``` + +详见 [09-exceptions.md](09-exceptions.md)。 + +## 运算符重载 + +`@t.Object` 类支持运算符重载。编译器在遇到运算符时,首先检查左操作数是否为结构体类型,如果是则尝试调用对应的 dunder 方法。 + +### 算术运算符重载 + +| 运算符 | Dunder 方法 | 示例 | +|--------|------------|------| +| `+` | `__add__` | `a + b` → `a.__add__(b)` | +| `-` | `__sub__` | `a - b` → `a.__sub__(b)` | +| `*` | `__mul__` | `a * b` → `a.__mul__(b)` | +| `/` | `__truediv__` | `a / b` → `a.__truediv__(b)` | +| `//` | `__floordiv__` | `a // b` → `a.__floordiv__(b)` | +| `%` | `__mod__` | `a % b` → `a.__mod__(b)` | +| `**` | `__pow__` | `a ** b` → `a.__pow__(b)` | + +示例: + +```python +@t.Object +class Vec2: + x: t.CFloat + y: t.CFloat + + def __init__(self, x: t.CFloat, y: t.CFloat): + self.x = x + self.y = y + + def __add__(self, other: Vec2) -> Vec2: + result: Vec2 = Vec2(0.0, 0.0) + result.x = self.x + other.x + result.y = self.y + other.y + return result + + def __mul__(self, scalar: t.CFloat) -> Vec2: + result: Vec2 = Vec2(0.0, 0.0) + result.x = self.x * scalar + result.y = self.y * scalar + return result +``` + +### 增量赋值运算符重载 + +| 增量运算符 | 优先 Dunder | 回退 Dunder | +|-----------|------------|------------| +| `+=` | `__iadd__` | `__add__` | +| `-=` | `__isub__` | `__sub__` | +| `*=` | `__imul__` | `__mul__` | +| `/=` | `__itruediv__` | `__truediv__` | +| `//=` | `__ifloordiv__` | `__floordiv__` | +| `%=` | `__imod__` | `__mod__` | +| `**=` | `__ipow__` | `__pow__` | + +如果未定义增量版本(如 `__iadd__`),编译器自动回退到普通版本(如 `__add__`)。 + +### 比较运算符重载 + +> **实验性**:以下比较运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。定义它们不会报错,但比较运算不会自动调用。 + +| 运算符 | Dunder 方法 | 状态 | +|--------|------------|------| +| `==` | `__eq__` | 仅类型推断识别 | +| `!=` | `__ne__` | 仅类型推断识别 | +| `<` | `__lt__` | 仅类型推断识别 | +| `<=` | `__le__` | 仅类型推断识别 | +| `>` | `__gt__` | 仅类型推断识别 | +| `>=` | `__ge__` | 仅类型推断识别 | + +### 反向运算符重载 + +> **实验性**:以下反向运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。 + +| Dunder 方法 | 预期语义 | 状态 | +|------------|---------|------| +| `__radd__` | 右操作数加法 | 仅类型推断识别 | +| `__rsub__` | 右操作数减法 | 仅类型推断识别 | +| `__rmul__` | 右操作数乘法 | 仅类型推断识别 | +| `__rtruediv__` | 右操作数真除法 | 仅类型推断识别 | +| `__rfloordiv__` | 右操作数整除 | 仅类型推断识别 | +| `__rmod__` | 右操作数取模 | 仅类型推断识别 | +| `__rpow__` | 右操作数幂运算 | 仅类型推断识别 | + +### 一元运算符重载 + +> **实验性**:以下一元运算符 dunder 方法在编译器中被识别,但尚未实现自动调度。 + +| 运算符 | Dunder 方法 | 状态 | +|--------|------------|------| +| `-a` | `__neg__` | 仅类型推断识别 | +| `+a` | `__pos__` | 仅类型推断识别 | + +## 可调用对象 `__call__` + +```python +@t.Object +class Counter: + value: t.CInt + + def __init__(self): + self.value = 0 + + def __call__(self) -> t.CInt: + self.value += 1 + return self.value + +c: Counter = Counter() +x: t.CInt = c() # x = 1 +y: t.CInt = c() # y = 2 +``` + +## 下标访问重载 + +### `__getitem__` — 读取 + +```python +def __getitem__(self, key: t.CInt) -> t.CInt: + return self.data[key] +``` + +### `__setitem__` — 赋值 + +```python +def __setitem__(self, key: t.CInt, value: t.CInt): + self.data[key] = value +``` + +### `__delitem__` — 删除 + +```python +def __delitem__(self, key: t.CInt): + pass +``` + +## 布尔转换 `__bool__` + +```python +@t.Object +class Buffer: + size: t.CInt + data: list[t.CChar, 1024] + + def __bool__(self) -> t.CBool: + return self.size > 0 + +buf: Buffer = Buffer() +if buf: + serial.puts("buffer is not empty\n") +``` + +## 长度 `__len__` + +```python +@t.Object +class Buffer: + size: t.CInt + + def __len__(self) -> t.CInt: + return self.size + +buf: Buffer = Buffer() +n: t.CInt = len(buf) +``` + +## 字符串转换 `__str__` + +```python +@t.Object +class Point: + x: t.CInt + y: t.CInt + + def __str__(self) -> t.CConst | t.CChar | t.CPtr: + return "Point" + +p: Point = Point(1, 2) +print(p) # 调用 p.__str__() +``` + +## 绝对值 `__abs__` + +```python +@t.Object +class SignedValue: + val: t.CInt + + def __abs__(self) -> t.CInt: + if self.val < 0: + return -self.val + return self.val + +sv: SignedValue = SignedValue() +sv.val = -42 +a: t.CInt = abs(sv) # a = 42 +``` + +## 迭代器协议 + +Viper 的迭代器协议与 Python 相同,但 `__next__` 的实现方式通过 `StopIteration` 异常来结束。 + +### `__iter__` 和 `__next__` + +```python +@t.Object +class IntRange: + start: t.CInt + end: t.CInt + current: t.CInt + + def __init__(self, start: t.CInt, end: t.CInt): + self.start = start + self.end = end + self.current = start + + def __iter__(self): + return self + + def __next__(self, stop_flag) -> t.CInt: + if self.current >= self.end: + raise StopIteration + val: t.CInt = self.current + self.current += 1 + return val +``` + +### for 循环使用 + +```python +r: IntRange = IntRange(0, 10) +for i in r: + print(i) +``` + +编译器生成的等价逻辑: + +```c +IntRange r = IntRange_init(0, 10); +IntRange iter = IntRange___iter__(&r); +while (1) { + i1 stop_flag = 0; + int i = IntRange___next__(&iter, &stop_flag); + if (stop_flag == 1) break; + print_int(i); +} +``` + +## 上下文管理器 + +`with` 语句要求对象实现 `__enter__` 和 `__exit__` 方法: + +```python +@t.Object +class File: + fd: t.CInt + path: t.CConst | t.CChar | t.CPtr + + def __init__(self, path: t.CConst | t.CChar | t.CPtr, flags: t.CInt): + self.path = path + self.fd = -1 + + def __enter__(self): + self.fd = fat32.open(self.path, self.flags) + return self + + def __exit__(self): + fat32.close(self.fd) + + def read(self) -> t.CInt: + return fat32.read(self.fd) +``` + +使用方式: + +```python +with File("/test.txt", FA_READ) as f: + data: t.CInt = f.read() +``` + +编译器会自动保证 `__exit__` 在 `with` 块结束时被调用。 + +## 析构 `__del__` / `__delete__` + +```python +del obj # 调用 obj.__del__() 或 obj.__delete__() +del arr[idx] # 调用 arr.__delitem__(idx) +``` + +## Dunder 方法完整参考 + +### 已实现自动调度的 Dunder 方法 + +| Dunder 方法 | 触发语法 | 说明 | +|------------|---------|------| +| `__init__` | `ClassName(args)` | 构造函数 | +| `__before_init__` | 自动生成 | vtable 初始化,在 `__init__` 之前执行 | +| `__add__` | `a + b` | 加法 | +| `__sub__` | `a - b` | 减法 | +| `__mul__` | `a * b` | 乘法 | +| `__truediv__` | `a / b` | 真除法 | +| `__floordiv__` | `a // b` | 整除 | +| `__mod__` | `a % b` | 取模 | +| `__pow__` | `a ** b` | 幂运算 | +| `__iadd__` | `a += b` | 增量加法(回退到 `__add__`) | +| `__isub__` | `a -= b` | 增量减法(回退到 `__sub__`) | +| `__imul__` | `a *= b` | 增量乘法(回退到 `__mul__`) | +| `__itruediv__` | `a /= b` | 增量真除法(回退到 `__truediv__`) | +| `__ifloordiv__` | `a //= b` | 增量整除(回退到 `__floordiv__`) | +| `__imod__` | `a %= b` | 增量取模(回退到 `__mod__`) | +| `__ipow__` | `a **= b` | 增量幂运算(回退到 `__pow__`) | +| `__call__` | `obj(args)` | 可调用对象 | +| `__getitem__` | `obj[key]` | 下标读取 | +| `__setitem__` | `obj[key] = value` | 下标赋值 | +| `__delitem__` | `del obj[key]` | 下标删除 | +| `__bool__` | `if obj:` | 布尔转换 | +| `__len__` | `len(obj)` | 长度 | +| `__str__` | `str(obj)` / `print(obj)` | 字符串转换 | +| `__abs__` | `abs(obj)` | 绝对值 | +| `__iter__` | `for x in obj:` | 获取迭代器 | +| `__next__` | `for x in obj:` | 获取下一个值(标志位方式) | +| `__enter__` | `with obj as x:` | 上下文管理器进入 | +| `__exit__` | `with obj as x:` | 上下文管理器退出 | +| `__del__` | `del obj` | 析构 | +| `__delete__` | `del obj` | 删除描述符 | + +### 声明支持但未实现自动调度的 Dunder 方法 + +| Dunder 方法 | 预期触发语法 | 当前状态 | +|------------|------------|---------| +| `__eq__` | `a == b` | 仅类型推断识别,比较运算不自动调度 | +| `__ne__` | `a != b` | 同上 | +| `__lt__` | `a < b` | 同上 | +| `__le__` | `a <= b` | 同上 | +| `__gt__` | `a > b` | 同上 | +| `__ge__` | `a >= b` | 同上 | +| `__neg__` | `-a` | 仅类型推断识别,一元负号不自动调度 | +| `__pos__` | `+a` | 同上 | +| `__radd__` | 右操作数加法 | 仅类型推断识别 | +| `__rsub__` | 右操作数减法 | 同上 | +| `__rmul__` | 右操作数乘法 | 同上 | +| `__rtruediv__` | 右操作数真除法 | 同上 | +| `__rfloordiv__` | 右操作数整除 | 同上 | +| `__rmod__` | 右操作数取模 | 同上 | +| `__rpow__` | 右操作数幂运算 | 同上 | + + +# 07 - 控制流 + +Viper 支持 Python 风格的控制流语句,编译为 LLVM IR 的基本块和分支指令。 + +## 条件语句 + +### if / elif / else + +```python +if x > 0: + y = 1 +elif x == 0: + y = 0 +else: + y = -1 +``` + +等价 C 代码: +```c +if (x > 0) { + y = 1; +} else if (x == 0) { + y = 0; +} else { + y = -1; +} +``` + +### 条件表达式 + +```python +is_dir: t.CInt = 1 if (info.attr & AM_DIR) else 0 +``` + +等价 C 代码: +```c +int is_dir = (info.attr & AM_DIR) ? 1 : 0; +``` + +### None 检查 + +```python +if BootInfo != None: + paging.init(BootInfo.MemmapAddr, BootInfo.MemmapSize) +else: + paging.init(0, 0) +``` + +等价 C 代码: +```c +if (BootInfo != NULL) { + paging_init(BootInfo->MemmapAddr, BootInfo->MemmapSize); +} else { + paging_init(0, 0); +} +``` + +## 循环语句 + +### while 循环 + +```python +i: t.CInt = 0 +while i < 10: + buf[i] = 0 + i += 1 +``` + +等价 C 代码: +```c +int i = 0; +while (i < 10) { + buf[i] = 0; + i += 1; +} +``` + +### while-else + +```python +while i < count: + if found: + break +else: + serial.puts("not found\n") +``` + +`else` 块在循环正常结束(非 `break` 退出)时执行。 + +### 无限循环 + +```python +while True: + sched.Scheduler._yield() +``` + +等价 C 代码: +```c +while (1) { + scheduler_yield(); +} +``` + +### for 循环(range)(关于 for 循环的更多用法,参见 [06-oop.md 中 迭代器协议](06-oop.md#迭代器协议)) + +```python +for i in range(10): + buf[i] = 0 + +for i in range(5, 10): + buf[i] = 0 + +for i in range(0, 100, 2): + buf[i] = 0 +``` + +等价 C 代码: +```c +for (int i = 0; i < 10; i++) { + buf[i] = 0; +} + +for (int i = 5; i < 10; i++) { + buf[i] = 0; +} + +for (int i = 0; i < 100; i += 2) { + buf[i] = 0; +} +``` + +### for 循环(迭代器) + +如果类实现了 `__iter__` 和 `__next__` 方法,可以使用 `for ... in` 迭代: + +```python +container: Iter = Iter() +for item in container: + process(item) +``` + +### for-else + +```python +for i in range(count): + if items[i] == target: + break +else: + serial.puts("not found\n") +``` + +### break 和 continue + +```python +while True: + if done: + break + if skip: + continue + process() +``` + +## match 语句 + +Viper 支持 Python 3.10+ 的 `match` 语句,编译为 C 的 `switch` 语句: + +```python +match self.ctype: + case UI_LABEL: + self.RenderLabel(sh) + case UI_BUTTON: + self.RenderButton(sh) + case UI_PANEL: + self.RenderPanel(sh) + case _: + pass +``` + +等价 C 代码: +```c +switch (self->ctype) { + case UI_LABEL: + self_RenderLabel(self, sh); + break; + case UI_BUTTON: + self_RenderButton(self, sh); + break; + case UI_PANEL: + self_RenderPanel(self, sh); + break; + default: + break; +} +``` + +### match 值匹配 + +```python +match code: + case 0: + serial.puts("OK\n") + case 1: + serial.puts("Error\n") + case _: + serial.puts("Unknown\n") +``` + +### match 或模式 + +```python +match value: + case 1 | 2 | 3: + serial.puts("small\n") + case _: + serial.puts("other\n") +``` + +### fallthrough(无 break) + +默认每个 `case` 自动添加 `break`。如需 fallthrough,使用 `c.NoBreak`: + +```python +match value: + case 1: + do_one() + c.NoBreak + case 2: + do_two() +``` + +如果需要提前 break,需要使用 `c.Break()`,因为在 `Python` 中,`match` 分支不支持直接使用 `break`。 + +## assert 语句 +> 避免使用此语句,此语句未经充分测试,在多数情况下,编译器不知道如何展示结果。 + +```python +assert ptr != None, "null pointer" +``` + +编译为条件检查和错误报告。 + +## with 语句 + +`with` 语句用于资源管理,要求对象实现 `__enter__` 和 `__exit__` 方法: + +```python +with File("/test.txt", FA_READ) as f: + data: t.CInt = f.read() +``` + +等价 C 代码: +```c +File* f = File_enter(File_new("/test.txt", FA_READ)); +int data = File_read(f); +File_exit(f); +``` + + +# 08 - C 语言操作 + +Viper 通过 `c` 模块提供对 C 语言底层特性的访问,包括指针操作、内联汇编、预处理指令等。 + +## 指针操作 + +### 取地址 `c.Addr` + +```python +x: t.CInt = 42 +p: t.CInt | t.CPtr = c.Addr(x) # int* p = &x; +``` + +对结构体成员取地址: + +```python +res: t.CInt = fat32.opendir("/", c.Addr(dp)) # res = fat32_opendir("/", &dp); +``` + +对数组取地址: + +```python +viperlib.snprintf(c.Addr(buf), 64, "hello %d", 42) # snprintf(&buf, 64, "hello %d", 42); +``` + +### 解引用 `c.Deref` + +```python +ptr: Sheet | t.CPtr = c.Addr(sheet_obj) +obj: Sheet = c.Deref(ptr) # struct Sheet obj = *ptr; +``` + +### 内存拷贝 `c.Load` + +```python +c.Load(ptr, value) # *ptr = *value; +``` + +### 解引用赋值 `c.DerefAs` + +```python +c.DerefAs(ptr, value) # *ptr = value; +``` + + +### 赋值 `c.Set` + +```python +c.Set(target, value) # target = value; +``` + +## 内联汇编 `c.Asm` + +Viper 提供了声明式的内联汇编语法,编译为 GCC 风格的 `__asm__ __volatile__` 语句。 + +### 基本用法 + +```python +c.Asm("nop") # __asm__ __volatile__("nop"); +``` + +### 带操作数的汇编 + +使用 f-string 和 `c.AsmInp` / `c.AsmOut` 标记操作数: + +```python +saved_rdi: t.CUnsignedLong +c.Asm(f"mov {c.AsmOut(saved_rdi, t.ASM_DESCR.OUTPUT_REG)}, rdi", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RDI]) +``` + +等价 C 代码: +```c +__asm__ __volatile__( + "mov %0, rdi" + : "=r"(saved_rdi) + : + : "memory", "rdi" +); +``` + +### 输入操作数 `c.AsmInp` + +```python +msg: t.CConst | t.CChar | t.CPtr = "Hello" +c.Asm(f"mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)}", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX]) +``` + +### 完整示例 + +```python +c.Asm(f"""mov rdi, {c.AsmInp(msg, t.ASM_DESCR.REG_ANY)} + call {c.AsmInp(log_info_fn, t.ASM_DESCR.REG_ANY)}""", + op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX, + t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX, + t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_RSI, + t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9, + t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11]) +``` + +### ASM_DESCR 约束字符 + +#### 操作数修饰符 + +| 常量 | 值 | 说明 | +|------|----|------| +| `MODIFIER_OUTPUT` | `=` | 输出操作数 | +| `MODIFIER_READWRITE` | `+` | 读写操作数 | +| `MODIFIER_INPUT` | `` | 输入操作数(默认) | +| `MODIFIER_GLOBAL` | `&` | 全局操作数 | + +#### 寄存器约束 + +| 常量 | 值 | 说明 | +|------|----|------| +| `REG_ANY` | `r` | 任何通用寄存器 | +| `REG_EAX` / `REG_RAX` | `a` | EAX/RAX | +| `REG_EBX` / `REG_RBX` | `b` | EBX/RBX | +| `REG_ECX` / `REG_RCX` | `c` | ECX/RCX | +| `REG_EDX` / `REG_RDX` | `d` | EDX/RDX | +| `REG_ESI` / `REG_RSI` | `S` | ESI/RSI | +| `REG_EDI` / `REG_RDI` | `D` | EDI/RDI | +| `REG_XMM` | `x` | XMM 寄存器 | + +#### 内存与立即数 + +| 常量 | 值 | 说明 | +|------|----|------| +| `MEMORY` | `m` | 内存操作数 | +| `IMMEDIATE` | `i` | 立即数 | +| `ANY` | `g` | 通用寄存器/内存/立即数 | + +#### 预定义组合约束 + +| 常量 | 值 | 说明 | +|------|----|------| +| `OUTPUT_REG` | `=r` | 输出,通用寄存器 | +| `OUTPUT_MEM` | `=m` | 输出,内存 | +| `OUTPUT_EAX` | `=a` | 输出,EAX/RAX | +| `INPUT_REG` | `r` | 输入,通用寄存器 | +| `INPUT_MEM` | `m` | 输入,内存 | +| `INPUT_IMM` | `i` | 输入,立即数 | + +#### 破坏描述符 + +| 常量 | 说明 | +|------|------| +| `CLOBBER_EAX` / `CLOBBER_RAX` | 破坏 EAX/RAX | +| `CLOBBER_EBX` / `CLOBBER_RBX` | 破坏 EBX/RBX | +| `CLOBBER_ECX` / `CLOBBER_RCX` | 破坏 ECX/RCX | +| `CLOBBER_EDX` / `CLOBBER_RDX` | 破坏 EDX/RDX | +| `CLOBBER_ESI` / `CLOBBER_RSI` | 破坏 ESI/RSI | +| `CLOBBER_EDI` / `CLOBBER_RDI` | 破坏 EDI/RDI | +| `CLOBBER_CC` | 破坏条件码(标志寄存器) | +| `CLOBBER_MEMORY` | 破坏内存 | +| `CLOBBER_R8` ~ `CLOBBER_R15` | 破坏 R8~R15 | + +## 预处理指令 + +Viper 通过 `c` 模块的函数调用实现 C 预处理指令。 + +### #define + +```python +c.CDefine("MAX_SIZE", 1024) # #define MAX_SIZE 1024 +``` + +上述方法容易引起未定义行为,至少是不便于理解,更常用的方式是使用类型注解: + +```python +MAX_SIZE: t.CDefine = 1024 # #define MAX_SIZE 1024 +``` + +### 条件编译 + +```python +c.CIfndef(HEADER_H) # #ifndef HEADER_H +c.CDefine(HEADER_H) # #define HEADER_H +c.CEndif() # #endif +``` + +```python +c.CIfdef(DEBUG) # #ifdef DEBUG +c.CEndif() # #endif +``` + +```python +c.CIf(VERSION > 2) # #if VERSION > 2 +c.CElif(VERSION > 1) # #elif VERSION > 1 +c.CElse() # #else +c.CEndif() # #endif +``` + +### #undef + +```python +c.Undef(MACRO_NAME) # #undef MACRO_NAME +``` + +### #error + +```python +c.CError("Platform not supported") # #error "Platform not supported" +``` + +### #pragma +> 此关键字已不再支持 +```python +c.CPragma("GCC diagnostic push") # #pragma GCC diagnostic push +``` + +### ## 连接符 +> 此方法可能已经不再支持 +```python +c.TokenPast("PREFIX_", "NAME") # PREFIX_ ## NAME +``` + +由于编译器设计,以及不需要像 `C` 一样做大量字符替换,对于上述所有的条件宏都远比 `C` 差,实际工程中不推荐使用条件宏,后期将完善宏的设计,引入模板等。 + +## 仅声明 `c.State` + +`c.State` 用于声明但不定义函数或变量: + +```python +def isr0() -> t.CExtern | t.CVoid | c.State: pass # extern void isr0(); +``` + +## LLVM IR 内联 + +### c.LLVMIR + +直接嵌入 LLVM IR 指令来实现高效且跨平台的汇编操作: + +```python +c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt) +``` + +### c.LInp / c.LOut + +标记 LLVM IR 的输入/输出操作数: + +```python +c.LInp(expr) # 输入操作数 +c.LOut(expr) # 输出操作数 +``` + +## 运算符重载 + +`@t.Object` 类支持运算符重载,详见 [06-oop.md 中 运算符重载](06-oop.md#运算符重载)。 + + +# 09 - 异常处理 + +Viper 支持 Python 风格的 `try/except/finally` 异常处理,编译为基于 jmp_buf 和错误码的 C 级别异常处理机制。 + +## 异常处理机制 + +Viper 的异常处理不使用 C++ 风格的零开销异常,而是通过函数参数传递错误码和错误消息实现。编译器自动为可能抛出异常的函数添加 `__eh_msg_out__` 和 `__eh_code_out__` 参数。 + +## try / except + +```python +try: + result = risky_operation() +except ValueError: + serial.puts("ValueError occurred\n") +except OSError: + serial.puts("OSError occurred\n") +except Exception: + serial.puts("Unknown error\n") +``` + +### 内置异常类型 + +Viper 预定义了以下异常类型及其错误码: + +| 异常类型 | 错误码 | +|---------|--------| +| `ValueError` | 1 | +| `TypeError` | 2 | +| `RuntimeError` | 3 | +| `ZeroDivisionError` | 4 | +| `IndexError` | 5 | +| `KeyError` | 6 | +| `IOError` | 7 | +| `OSError` | 8 | +| `AssertionError` | 9 | +| `Exception` | 99 | + +### 自定义异常 + +```python +class DiskFullError(Exception): + pass + +class ReadOnlyError(DiskFullError): + pass +``` + +自定义异常会自动分配递增的错误码(从 100 开始),并支持继承匹配。 + +### 多异常捕获 + +```python +try: + result = operation() +except (ValueError, TypeError): + serial.puts("Value or Type error\n") +``` + +### 获取异常信息 + +```python +try: + result = operation() +except Exception as e: + serial.puts("Error occurred\n") +``` + +## try / finally + +```python +try: + result = operation() +finally: + cleanup() +``` + +`finally` 块无论是否发生异常都会执行。 + +## try / except / finally + +```python +try: + result = operation() +except ValueError: + handle_value_error() +finally: + cleanup() +``` + +## raise 语句 + +### 抛出异常 + +```python +raise ValueError("invalid value") +``` + +### 抛出自定义异常 + +```python +raise MyCustomError("something went wrong") +``` + +### 重新抛出异常 + +```python +raise +``` + +### StopIteration + +`StopIteration` 有特殊处理,用于迭代器协议: + +```python +raise StopIteration +``` + +## 异常处理的编译实现 + +### 函数签名变换 + +可能抛出异常的函数会自动添加错误输出参数: + +```python +def risky_operation() -> t.CInt: + if error: + raise ValueError("bad value") + return 0 +``` + +编译后等价于: + +```c +int risky_operation(char** __eh_msg_out__, int* __eh_code_out__) { + if (error) { + *__eh_code_out__ = 1; // ValueError code + *__eh_msg_out__ = "bad value"; + return 0; + } + return 0; +} +``` + +### 调用点变换 + +```python +try: + result = risky_operation() +except ValueError: + handle_error() +``` + +编译后等价于: + +```c +char* __eh_msg = NULL; +int __eh_code = 0; +int result = risky_operation(&__eh_msg, &__eh_code); +if (__eh_msg != NULL) { + if (__eh_code == 1) { // ValueError + handle_error(); + } +} +``` + +## 异常继承匹配 + +异常匹配支持继承体系。捕获父类异常时,子类异常也会被匹配: + +```python +class FileSystemError(Exception): + pass + +class FileNotFoundError(FileSystemError): + pass + +class PermissionError(FileSystemError): + pass + +try: + operation() +except FileSystemError: + # 也会捕获 FileNotFoundError 和 PermissionError + handle_fs_error() +``` + + +# 10 - 模块与导入系统 + +Viper 的模块系统基于 Python 的 `import` 语法,但编译时通过 TransPyC 的符号表和类型系统实现跨模块的类型解析。 + +## 导入语法 + +### 标准导入 + +```python +import t, c # Viper 内置类型和操作模块 +import asm # 汇编辅助模块 +import string # 字符串操作模块 +``` + +### 模块导入 + +```python +import bootinfo +import intr +import platform.pch as pch +import drivers.serial.uart.serial as serial +``` + +### from 导入 + +```python +from stdint import * # 导入所有 stdint 类型别名 +from drivers.video.vesafb.vga import _VGAScreenDriver +``` + +### 相对导入 + +```python +from . import submodule +from .. import parent_module +``` + +## 特殊模块 + +### `t` 模块 + +类型定义模块,提供所有 C 类型对应的 Viper 类型。每个 Viper 文件通常都需要导入: + +```python +import t +``` + +### `c` 模块 + +C 语言操作模块,提供指针操作、内联汇编、预处理指令等: + +```python +import c +``` + +### `asm` 模块 + +汇编辅助模块,提供常用汇编指令的封装: + +```python +import asm + +asm.sti() # __asm__ __volatile__("sti"); +asm.hlt() # __asm__ __volatile__("hlt"); +asm.cli() # __asm__ __volatile__("cli"); +asm.nop() # __asm__ __volatile__("nop"); +asm.BSSClean() # 清零 BSS 段 +``` + +### `string` 模块 + +字符串/内存操作模块,对应 C 标准库的 `string.h`: +> string 部分使用 x86_64 专有汇编进行加速,因此某些函数在其它架构可能需要手动重新编写。 + +```python +import string + +string.memset(c.Addr(buf), 0, 64) # memset(&buf, 0, 64); +string.memcpy(dst, src, size) # memcpy(dst, src, size); +string.memmove(dst, src, size) # memmove(dst, src, size); +string.memcmp(a, b, size) # memcmp(a, b, size); +string.strcmp(a, b) # strcmp(a, b); +string.strcpy(dst, src) # strcpy(dst, src); +``` + +### `stdint` 模块 + +提供 C `stdint.h` 中的类型别名: + +```python +from stdint import * + +# 提供以下类型别名: +# UINT8PTR, UINT16PTR, UINT32PTR, UINT64PTR +# INT8PTR, INT16PTR, INT32PTR, INT64PTR +# 等等 +``` + +### `viperlib` 模块 + +ViperOS 标准库,提供常用 C 库函数: + +```python +import viperlib + +viperlib.snprintf(c.Addr(buf), 64, "value=%d", 42) # snprintf(&buf, 64, "value=%d", 42); +``` + +### `vpsdk` 模块 + +> vpsdk 模块 专供于基于 Viper 开发的示例操作系统 ViperOS,不可用于其它平台,且需要特殊配置。 + +ViperOS 应用 SDK,提供系统调用和窗口管理: + +```python +import vpsdk.window as window +import vpsdk.process as process +import vpsdk.dynlib as dynlib +import vpsdk.syscall as syscall +``` + +## 模块解析流程 + +### 编译时模块加载 + +Viper 的 `import` 是编译时操作,不涉及运行时模块加载。完整的模块解析流程与两阶段编译紧密耦合: + +1. **阶段一**:从入口文件出发,通过 `import` 语句递归发现所有可达的源文件 +2. **阶段一**:对每个源文件生成 `.pyi` 签名存根和 `.stub.ll` LLVM IR 声明 +3. **阶段二**:加载所有 `.pyi` 和 `.stub.ll`,构建共享符号表 +4. **阶段二**:翻译源文件时,通过符号表解析跨模块的类型和函数引用 +5. **阶段二**:将被引用模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部 + +### 类型存根文件(.pyi) + +`.pyi` 文件是模块的声明接口,由 `PythonToStubConverter` 在阶段一生成。存根文件的内容规则: + +| 元素 | 存根表示 | +|------|---------| +| `t.CDefine` 常量 | 保留完整定义(含赋值) | +| `t.CDefine` 函数 | 保留完整函数体 | +| 普通函数 | 仅签名 + `c.State` | +| 全局变量 | 添加 `t.CExtern` | +| 类定义 | 保留成员类型注解和方法签名 | + +存根文件还自动添加宏守卫(`c.CIfndef`/`c.CEndif()`),防止重复包含。 + +### SHA1 命名空间与导入 + +每个模块的函数和结构体在 LLVM IR 中自动加上 SHA1 前缀,消除跨模块符号冲突。只有标记为 `t.CExport` 的函数保持原始名称。详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。 + +### 符号表 + +所有模块的类型信息统一存储在 `SymbolTable` 中,包含: +- 结构体/联合体/枚举定义 +- 函数签名 +- 全局变量 +- typedef 别名 +- `t.CDefine` 常量 + +### 跨模块类型引用 + +```python +# 在 fat32_types.py 中定义 +class fat32_fileinfo: + fname: list[t.CChar, 13] + attr: t.CUInt8T + file_size: t.CUInt32T + +# 在其他模块中引用 +import fat32_types +info: fat32_types.fat32_fileinfo +``` + +跨模块引用的结构体在 LLVM IR 中使用 SHA1 前缀的类型名: +```llvm +%".fat32_fileinfo" = type { [13 x i8], i8, i32 } +``` + +## 项目 includes 配置 + +在 `project.json` 中配置模块搜索路径: + +```json +{ + "includes": ["../.."], + "source_dir": "./Kernel" +} +``` + +编译器会在 `includes` 指定的目录中搜索导入的模块。 + + +# 11 - 内置函数与运算符 + +Viper 支持 Python 内置函数和运算符,编译为对应的 C/LLVM 操作。 + +## 内置函数 + +### print + +```python +print("Hello, World!") # 调用 puts 或 printf +print(x, y) # 多参数输出 +``` + +### len + +```python +n: t.CInt = len(array) # 获取数组长度(编译时常量) +``` + +### sizeof + +```python +s: t.CSizeT = sizeof(t.CInt) # sizeof(int) +s: t.CSizeT = obj.__sizeof__() # sizeof(obj) +``` + +### abs + +```python +a: t.CInt = abs(x) # abs(x) +``` + +### int / float / bool + +```python +i: t.CInt = int(3.14) # (int)3.14 +f: t.CFloat = float(42) # (float)42 +b: t.CBool = bool(x) # x != 0 +``` + +### min / max + +```python +m: t.CInt = min(a, b) # a < b ? a : b +m: t.CInt = max(a, b) # a > b ? a : b +``` + +### chr / ord + +```python +c: t.CChar = chr(65) # 'A' (整数转字符) +n: t.CInt = ord('A') # 65 (字符转整数) +``` + +### range + +用于 `for` 循环: + +```python +for i in range(10): pass # for (int i = 0; i < 10; i++) +for i in range(5, 10): pass # for (int i = 5; i < 10; i++) +for i in range(0, 10, 2): pass # for (int i = 0; i < 10; i += 2) +``` + +## 运算符 + +### 算术运算符 + +| Viper | C 等价 | 说明 | +|-------|--------|------| +| `a + b` | `a + b` | 加法 | +| `a - b` | `a - b` | 减法 | +| `a * b` | `a * b` | 乘法 | +| `a / b` | `a / b` | 浮点除法 | +| `a // b` | `a / b` | 整数除法 | +| `a % b` | `a % b` | 取模 | +| `a ** b` | `pow(a, b)` | 幂运算 | +| `-a` | `-a` | 取负 | +| `+a` | `+a` | 正号 | + +### 位运算符 + +| Viper | C 等价 | 说明 | +|-------|--------|------| +| `a & b` | `a & b` | 按位与 | +| `a \| b` | `a \| b` | 按位或 | +| `a ^ b` | `a ^ b` | 按位异或 | +| `~a` | `~a` | 按位取反 | +| `a << n` | `a << n` | 左移 | +| `a >> n` | `a >> n` | 右移 | + +> **注意**:`|` 运算符在类型注解中表示类型组合,在表达式中表示按位或。编译器根据上下文区分。 + +### 比较运算符 + +| Viper | C 等价 | 说明 | +|-------|--------|------| +| `a == b` | `a == b` | 等于 | +| `a != b` | `a != b` | 不等于 | +| `a < b` | `a < b` | 小于 | +| `a > b` | `a > b` | 大于 | +| `a <= b` | `a <= b` | 小于等于 | +| `a >= b` | `a >= b` | 大于等于 | + +### 逻辑运算符 + +| Viper | C 等价 | 说明 | +|-------|--------|------| +| `a and b` | `a && b` | 逻辑与 | +| `a or b` | `a \|\| b` | 逻辑或 | +| `not a` | `!a` | 逻辑非 | + +### 增强赋值运算符 + +| Viper | C 等价 | +|-------|--------| +| `a += b` | `a += b` | +| `a -= b` | `a -= b` | +| `a *= b` | `a *= b` | +| `a //= b` | `a /= b` | +| `a %= b` | `a %= b` | +| `a <<= b` | `a <<= b` | +| `a >>= b` | `a >>= b` | +| `a &= b` | `a &= b` | +| `a \|= b` | `a \|= b` | +| `a ^= b` | `a ^= b` | + +## 类型自动转换 + +Viper 在算术运算中自动进行类型提升: + +1. **整数宽度提升**:较窄的整数类型自动扩展为较宽的类型 + - 有符号类型使用符号扩展(`sext`) + - 无符号类型使用零扩展(`zext`) + +2. **整数到浮点**:整数与浮点数运算时,整数自动转换为浮点 + +3. **浮点精度提升**:`float` 与 `double` 运算时,`float` 提升为 `double` + +## 指针算术 + +指针与整数的加法支持自动计算偏移: + +```python +buf: t.CUInt32T | t.CPtr +buf[i] = value # buf[i] = value; (自动计算偏移) +``` + +## 数组下标 + +```python +buf: list[t.CChar, 64] +buf[0] = 'H' # buf[0] = 'H'; +buf[i] = value # buf[i] = value; + +info.fname[0] # info.fname[0] (结构体数组成员访问) +``` + +## 成员访问 + +```python +obj.x # obj.x (直接成员) +obj.method() # obj.method() (方法调用) +ptr.x # ptr->x (指针自动解引用) +``` + +## 字符串字面量 + +字符串字面量编译为 C 字符串常量(`const char*`),其为只读: + +```python +serial.puts("Hello") # 传递 const char* +``` + +### 字符串索引 + +```python +msg: t.CConst | str = "Hello" +serial.puts(c.Addr(msg[4])) # 访问 msg[4] 的地址,输出 'o' +``` + +## C 标准库函数 + +Viper 内置支持以下 C 标准库函数的直接调用: + +| 函数 | 签名 | +|------|------| +| `strlen(s)` | `size_t strlen(const char* s)` | +| `memset(s, c, n)` | `void* memset(void* s, int c, size_t n)` | +| `memcpy(d, s, n)` | `void* memcpy(void* d, const void* s, size_t n)` | +| `memmove(d, s, n)` | `void* memmove(void* d, const void* s, size_t n)` | +| `memcmp(a, b, n)` | `int memcmp(const void* a, const void* b, size_t n)` | +| `strcmp(a, b)` | `int strcmp(const char* a, const char* b)` | +| `strncmp(a, b, n)` | `int strncmp(const char* a, const char* b, size_t n)` | +| `strcpy(d, s)` | `char* strcpy(char* d, const char* s)` | +| `strncpy(d, s, n)` | `char* strncpy(char* d, const char* s, size_t n)` | +| `strcat(d, s)` | `char* strcat(char* d, const char* s)` | +| `puts(s)` | `int puts(const char* s)` | +| `atoi(s)` | `int atoi(const char* s)` | +| `atol(s)` | `long atol(const char* s)` | +| `abs(x)` | `int abs(int x)` | +| `labs(x)` | `long labs(long x)` | + +部分模式比如裸机没有 libc,则不能使用这些函数,即使环境满足,Viper 标准库也可能和 C 标准库冲突。 + + +# 12 - 项目配置与构建 + +Viper 项目使用 `project.json` 配置文件管理编译和链接参数。 + +## project.json 结构 + +```json +{ + "name": "Kernel", + "version": "1.0.0", + "source_dir": "./Kernel", + "temp_dir": "./temp", + "output_dir": "./output", + "compiler": { + "cmd": "llc", + "flags": ["-filetype=obj", "-mtriple=x86_64-none-elf", "-relocation-model=static", "-O2"] + }, + "linker": { + "cmd": "ld.lld.exe", + "flags": [ + "-m", "elf_x86_64", + "-T", "linker.ld", + "--oformat", "elf64-x86-64", + "--strip-all" + ], + "output": "kernel.bin" + }, + "includes": ["../../includes"], + "target": { + "triple": "x86_64-none-elf", + "datalayout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + }, + "options": { + "slice_level": 3, + "target": "llvm", + "strict_mode": true + } +} +``` + +## 配置项说明 + +### 基本信息字段 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `name` | string | 项目名称 | +| `version` | string | 项目版本 | +| `source_dir` | string | 源代码目录(相对于 project.json 所在目录) | +| `temp_dir` | string | 临时文件目录(存放 .pyi 存根等) | +| `output_dir` | string | 输出文件目录 | + +### 编译器配置 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `compiler.cmd` | string | 编译器命令(通常为 `llc`) | +| `compiler.flags` | string[] | 编译器标志 | + +常用 `llc` 标志: +- `-filetype=obj`:输出目标文件 +- `-mtriple=x86_64-none-elf`:目标三元组 +- `-relocation-model=static`:静态重定位 +- `-O2`:优化级别 + +### 链接器配置 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `linker.cmd` | string | 链接器命令(通常为 `ld.lld.exe`) | +| `linker.flags` | string[] | 链接器标志 | +| `linker.output` | string | 输出文件名 | + +常用 `ld.lld` 标志: +- `-m elf_x86_64`:ELF x86_64 格式 +- `-T linker.ld`:链接脚本 +- `--oformat elf64-x86-64`:输出 ELF 格式 +- `--oformat binary`:输出原始二进制(用于内核) +- `--strip-all`:去除所有符号信息 + +### 目标平台配置 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `target.triple` | string | LLVM 目标三元组 | +| `target.datalayout` | string | LLVM 数据布局字符串 | + +默认值: +- triple: `x86_64-none-elf` +- datalayout: `e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128` + +### 包含路径 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `includes` | string[] | 模块搜索路径列表 | + +### 编译选项 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `options.slice_level` | int | 切片优化级别(0-3) | +| `options.target` | string | 编译目标(目前仅支持 `llvm`) | +| `options.strict_mode` | bool | 严格模式 | + +## 切片优化级别 + +| 级别 | 名称 | 说明 | +|------|------|------| +| `0` | `no_optimize` | 无优化 | +| `1` | `conservative` | 保守优化 | +| `2` | `moderate` | 适度优化 | +| `3` | `aggressive` | 激进优化(默认) | +| `s` | `size` | 体积优化 | + +## 项目结构示例 + +### 内核项目 + +``` +VKernel/ +├── project.json # 项目配置 +├── linker.ld # 链接脚本 +├── Kernel/ # 源代码目录 +│ ├── main.py # 内核入口 +│ ├── bootinfo.py +│ ├── intr/ +│ │ ├── gdt.py +│ │ ├── idt.py +│ │ └── syscall.py +│ ├── drivers/ +│ │ ├── serial/ +│ │ ├── video/ +│ │ ├── storage/ +│ │ └── ... +│ └── ... +├── temp/ # 临时文件(自动生成) +│ ├── .pyi # 签名存根(阶段一生成) +│ ├── .stub.ll # LLVM IR 声明(阶段一生成) +│ └── _sha1_map.txt # SHA1→源文件路径映射 +└── output/ # 输出文件(自动生成) + ├── kernel.bin # 内核二进制 + ├── *.deps.json # 依赖信息 + └── linker.ld # 生成的链接脚本 +``` + +### 应用项目 + +``` +HelloWorld/ +├── project.json # 项目配置 +├── linker.ld # 链接脚本 +├── main.py # 应用入口 +├── temp/ # 临时文件 +└── output/ # 输出文件 + └── helloworld.elf # ELF 可执行文件 +``` + +### 库项目 + +``` +SerialLogger/ +├── project.json # 项目配置 +├── linker.ld # 链接脚本 +├── serial_logger.py # 库源码 +├── temp/ # 临时文件 +└── output/ # 输出文件 +``` + +## 链接脚本 + +ViperOS 使用自定义链接脚本控制内存布局: + +```ld +ENTRY(_start) + +SECTIONS +{ + . = 0x100000; /* 加载地址 */ + + .text : { + *(.text.startup) + *(.text*) + } + + .rodata : { + *(.rodata*) + } + + .data : { + *(.data*) + } + + .bss : { + *(.bss*) + *(COMMON) + } +} +``` + +## 编译命令 + +TransPyC 编译器的基本用法(注:适用于单个文件,而不适用于工程): + +```bash +python TransPyC.py -f InputFile -o OutputFile [options] +``` + +### 命令行参数 + +| 参数 | 说明 | +|------|------| +| `-f` | 输入文件路径 | +| `-o` | 输出文件路径 | +| `-wh` | 头文件列表 | +| `-debug` | 调试输出文件 | +| `-cc` | 编译命令 | +| `-cflags` | 编译标志 | +| `-run` | 编译后运行 | +| `-args` | 运行参数 | +| `-h` | 辅助文件(C 或 Python) | + +工程编译使用: +```bash +python Projectrans.py xxx.json +``` +即可 + +## 增量编译 + +TransPyC 支持基于 SHA1 的增量编译,与两阶段编译模型紧密耦合: + +### 阶段一增量 + +- 每个源文件按内容计算 SHA1 哈希(16位) +- 如果 `.pyi` 和 `.stub.ll` 已存在,则跳过生成(缓存命中) +- 只有源文件内容变化导致 SHA1 变化时才重新生成声明接口 +- `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,格式为 `:` + +### 阶段二增量 + +- 阶段二加载 `temp/_sha1_map.txt` 重建 SHA1 映射 +- 过滤掉不在当前 SHA1 映射中的旧 `.pyi` 和 `.stub.ll` 文件 +- 共享符号表一次性构建,避免每个文件重复加载 + +### SHA1 命名空间与增量编译的协同 + +SHA1 同时服务于命名空间隔离和增量编译: +- **命名空间**:非 `t.CExport` 函数和结构体使用 SHA1 前缀,消除符号冲突 +- **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成 + +详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。 + +