From 14ff9d109f5322d25e350f7cc14a49eaad22bb11 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 17 Aug 2026 11:01:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=8E=20TransPyC=20=E4=B8=BB=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E4=B8=AD=E5=88=86=E7=A6=BB=20VRTE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __builtin.py.bak | 425 +++++ _dict.vp | 271 ++++ _fakeduck.vp | 320 ++++ _list.vp | 90 ++ _variant.vp | 64 + _withcontent.vp | 75 + argparse.vp | 460 ++++++ asm.vp | 153 ++ ast/__init__.vp | 115 ++ ast/astaux.vp | 337 ++++ ast/base.vp | 504 ++++++ ast/exprs.vp | 1239 +++++++++++++++ ast/lexer.vp | 773 +++++++++ ast/match.vp | 363 +++++ ast/parser.vp | 2749 +++++++++++++++++++++++++++++++++ ast/stmts.vp | 1157 ++++++++++++++ ast/tokens.vp | 404 +++++ atom.vp | 41 + base64.vp | 80 + binascii.vp | 349 +++++ builtins.vp | 13 + condition.vp | 52 + ctraits.vpi | 19 + event.vp | 36 + hashlib/__init__.vp | 4 + hashlib/__md5.vp | 132 ++ hashlib/__sha1.vp | 120 ++ hashlib/__sha256.vp | 124 ++ hashlib/__sha512.vp | 149 ++ hashtable.vp | 242 +++ hello.vp | 5 + json/__init__.vp | 237 +++ json/__parser.vp | 291 ++++ json/__writer.vp | 119 ++ linkedlist.vp | 479 ++++++ llvmlite/README.md | 301 ++++ llvmlite/__builder.vp | 1827 ++++++++++++++++++++++ llvmlite/__function.vp | 811 ++++++++++ llvmlite/__init__.vp | 423 +++++ llvmlite/__module.vp | 638 ++++++++ llvmlite/__types.vp | 765 +++++++++ llvmlite/__values.vp | 234 +++ llvmlite/__verify.vp | 403 +++++ lock.vp | 38 + memhub.vp | 823 ++++++++++ numpy/__init__.vp | 1163 ++++++++++++++ os/__init__.vp | 134 ++ os/_posix.vp | 190 +++ os/_win32.vp | 234 +++ os/path.vp | 316 ++++ platmacro.vp | 57 + posix.vp | 265 ++++ requests.vp | 360 +++++ rwlock.vp | 46 + shutil.vp | 283 ++++ socket.vp | 454 ++++++ spinlock.vp | 16 + stdarg.vp | 9 + stdint.vp | 133 ++ stdio.vp | 11 + stdlib.vp | 10 + string.vp | 417 +++++ subprocess.vp | 196 +++ sys.vp | 200 +++ testcheck.vp | 71 + this.vp | 39 + vector.vp | 65 + viperio.vp | 59 + viperlib.vp | 1375 +++++++++++++++++ vipermath.vp | 544 +++++++ vipersimd.vp | 492 ++++++ viperstring.vp | 1 + vqt6 copy/CMakeLists.txt | 110 ++ vqt6 copy/README.md | 90 ++ vqt6 copy/__init__.vp | 208 +++ vqt6 copy/_bridge.h | 151 ++ vqt6 copy/_bridge_core.cpp | 433 ++++++ vqt6 copy/_bridge_gui.cpp | 868 +++++++++++ vqt6 copy/_bridge_gui.h | 231 +++ vqt6 copy/_bridge_network.cpp | 519 +++++++ vqt6 copy/_bridge_network.h | 137 ++ vqt6 copy/_bridge_widgets.cpp | 1745 +++++++++++++++++++++ vqt6 copy/_bridge_widgets.h | 432 ++++++ vqt6 copy/_qtcore.vp | 157 ++ vqt6 copy/_qtgui.vp | 237 +++ vqt6 copy/_qtnetwork.vp | 184 +++ vqt6 copy/_qtwidgets.vp | 478 ++++++ vqt6 copy/_types.vp | 186 +++ vqt6/CMakeLists.txt | 110 ++ vqt6/README.md | 90 ++ vqt6/__init__.vp | 208 +++ vqt6/_bridge.h | 151 ++ vqt6/_bridge_core.cpp | 433 ++++++ vqt6/_bridge_gui.cpp | 868 +++++++++++ vqt6/_bridge_gui.h | 231 +++ vqt6/_bridge_network.cpp | 519 +++++++ vqt6/_bridge_network.h | 137 ++ vqt6/_bridge_widgets.cpp | 1745 +++++++++++++++++++++ vqt6/_bridge_widgets.h | 432 ++++++ vqt6/_qtcore.vp | 157 ++ vqt6/_qtgui.vp | 237 +++ vqt6/_qtnetwork.vp | 184 +++ vqt6/_qtwidgets.vp | 478 ++++++ vqt6/_types.vp | 186 +++ vrandom.vp | 379 +++++ vthreading.vp | 102 ++ w32/fileio.vp | 389 +++++ w32/win32base.vp | 80 + w32/win32console.vp | 111 ++ w32/win32file.vp | 143 ++ w32/win32memory.vp | 64 + w32/win32process.vp | 112 ++ w32/win32sync.vp | 65 + w32/winsock2.vp | 104 ++ zlib/__init__.vp | 1 + zlib/pyzlib.vp | 697 +++++++++ zlib/zchecksum.vp | 89 ++ zlib/zdef.vp | 287 ++++ zlib/zdeflate.vp | 434 ++++++ zlib/zhuff.vp | 357 +++++ zlib/zinflate.vp | 456 ++++++ 121 files changed, 41596 insertions(+) create mode 100644 __builtin.py.bak create mode 100644 _dict.vp create mode 100644 _fakeduck.vp create mode 100644 _list.vp create mode 100644 _variant.vp create mode 100644 _withcontent.vp create mode 100644 argparse.vp create mode 100644 asm.vp create mode 100644 ast/__init__.vp create mode 100644 ast/astaux.vp create mode 100644 ast/base.vp create mode 100644 ast/exprs.vp create mode 100644 ast/lexer.vp create mode 100644 ast/match.vp create mode 100644 ast/parser.vp create mode 100644 ast/stmts.vp create mode 100644 ast/tokens.vp create mode 100644 atom.vp create mode 100644 base64.vp create mode 100644 binascii.vp create mode 100644 builtins.vp create mode 100644 condition.vp create mode 100644 ctraits.vpi create mode 100644 event.vp create mode 100644 hashlib/__init__.vp create mode 100644 hashlib/__md5.vp create mode 100644 hashlib/__sha1.vp create mode 100644 hashlib/__sha256.vp create mode 100644 hashlib/__sha512.vp create mode 100644 hashtable.vp create mode 100644 hello.vp create mode 100644 json/__init__.vp create mode 100644 json/__parser.vp create mode 100644 json/__writer.vp create mode 100644 linkedlist.vp create mode 100644 llvmlite/README.md create mode 100644 llvmlite/__builder.vp create mode 100644 llvmlite/__function.vp create mode 100644 llvmlite/__init__.vp create mode 100644 llvmlite/__module.vp create mode 100644 llvmlite/__types.vp create mode 100644 llvmlite/__values.vp create mode 100644 llvmlite/__verify.vp create mode 100644 lock.vp create mode 100644 memhub.vp create mode 100644 numpy/__init__.vp create mode 100644 os/__init__.vp create mode 100644 os/_posix.vp create mode 100644 os/_win32.vp create mode 100644 os/path.vp create mode 100644 platmacro.vp create mode 100644 posix.vp create mode 100644 requests.vp create mode 100644 rwlock.vp create mode 100644 shutil.vp create mode 100644 socket.vp create mode 100644 spinlock.vp create mode 100644 stdarg.vp create mode 100644 stdint.vp create mode 100644 stdio.vp create mode 100644 stdlib.vp create mode 100644 string.vp create mode 100644 subprocess.vp create mode 100644 sys.vp create mode 100644 testcheck.vp create mode 100644 this.vp create mode 100644 vector.vp create mode 100644 viperio.vp create mode 100644 viperlib.vp create mode 100644 vipermath.vp create mode 100644 vipersimd.vp create mode 100644 viperstring.vp create mode 100644 vqt6 copy/CMakeLists.txt create mode 100644 vqt6 copy/README.md create mode 100644 vqt6 copy/__init__.vp create mode 100644 vqt6 copy/_bridge.h create mode 100644 vqt6 copy/_bridge_core.cpp create mode 100644 vqt6 copy/_bridge_gui.cpp create mode 100644 vqt6 copy/_bridge_gui.h create mode 100644 vqt6 copy/_bridge_network.cpp create mode 100644 vqt6 copy/_bridge_network.h create mode 100644 vqt6 copy/_bridge_widgets.cpp create mode 100644 vqt6 copy/_bridge_widgets.h create mode 100644 vqt6 copy/_qtcore.vp create mode 100644 vqt6 copy/_qtgui.vp create mode 100644 vqt6 copy/_qtnetwork.vp create mode 100644 vqt6 copy/_qtwidgets.vp create mode 100644 vqt6 copy/_types.vp create mode 100644 vqt6/CMakeLists.txt create mode 100644 vqt6/README.md create mode 100644 vqt6/__init__.vp create mode 100644 vqt6/_bridge.h create mode 100644 vqt6/_bridge_core.cpp create mode 100644 vqt6/_bridge_gui.cpp create mode 100644 vqt6/_bridge_gui.h create mode 100644 vqt6/_bridge_network.cpp create mode 100644 vqt6/_bridge_network.h create mode 100644 vqt6/_bridge_widgets.cpp create mode 100644 vqt6/_bridge_widgets.h create mode 100644 vqt6/_qtcore.vp create mode 100644 vqt6/_qtgui.vp create mode 100644 vqt6/_qtnetwork.vp create mode 100644 vqt6/_qtwidgets.vp create mode 100644 vqt6/_types.vp create mode 100644 vrandom.vp create mode 100644 vthreading.vp create mode 100644 w32/fileio.vp create mode 100644 w32/win32base.vp create mode 100644 w32/win32console.vp create mode 100644 w32/win32file.vp create mode 100644 w32/win32memory.vp create mode 100644 w32/win32process.vp create mode 100644 w32/win32sync.vp create mode 100644 w32/winsock2.vp create mode 100644 zlib/__init__.vp create mode 100644 zlib/pyzlib.vp create mode 100644 zlib/zchecksum.vp create mode 100644 zlib/zdef.vp create mode 100644 zlib/zdeflate.vp create mode 100644 zlib/zhuff.vp create mode 100644 zlib/zinflate.vp diff --git a/__builtin.py.bak b/__builtin.py.bak new file mode 100644 index 0000000..8795ba4 --- /dev/null +++ b/__builtin.py.bak @@ -0,0 +1,425 @@ +# GCC/Clang Built-in Function Declarations +# All functions are declared only (t.State equivalent to CExtern | CExport); implementations are provided by compiler/runtime +import t + + +# ============================================================ +# Random Number Generation (RDRAND / RDSEED) +# ============================================================ + +def __builtin_ia32_rdrand16_step(p: t.CUInt16T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdrand32_step(p: t.CUInt32T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdrand64_step(p: t.CUInt64T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdseed16_step(p: t.CUInt16T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdseed32_step(p: t.CUInt32T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_rdseed64_step(p: t.CUInt64T | t.CPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# Time-Stamp Counter (RDTSC / RDTSCP) +# ============================================================ + +def __builtin_ia32_rdtsc() -> t.CUInt64T | t.State: pass +def __builtin_ia32_rdtscp(p: t.CUInt32T | t.CPtr) -> t.CUInt64T | t.State: pass +def __builtin_ia32_rdpmc(counter: t.CUInt32T) -> t.CUInt64T | t.State: pass + + +# ============================================================ +# CPUID +# ============================================================ + +def __builtin_ia32_cpuid(level: t.CUInt32T, a: t.CUInt32T | t.CPtr, b: t.CUInt32T | t.CPtr, c: t.CUInt32T | t.CPtr, d: t.CUInt32T | t.CPtr) -> t.CUInt32T | t.State: pass +def __builtin_ia32_cpuid_count(level: t.CUInt32T, count: t.CUInt32T, a: t.CUInt32T | t.CPtr, b: t.CUInt32T | t.CPtr, c: t.CUInt32T | t.CPtr, d: t.CUInt32T | t.CPtr) -> t.CUInt32T | t.State: pass + + +# ============================================================ +# Memory Barriers (Fence) +# ============================================================ + +def __builtin_ia32_lfence() -> t.State: pass +def __builtin_ia32_mfence() -> t.State: pass +def __builtin_ia32_sfence() -> t.State: pass +def __builtin_ia32_pause() -> t.State: pass + + +# ============================================================ +# Bit Manipulation (POPCNT / BSF / BSR / TZCNT / LZCNT / BEXTR / PDEP / PEXT / ANDN) +# ============================================================ + +def __builtin_ia32_popcntsi(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_ia32_popcntdi(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_ia32_popcntqi(x: t.CUInt64T) -> t.CInt | t.State: pass + +def __builtin_ia32_bsfsi(src: t.CUInt32T, dst: t.CUInt32T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_bsrsi(src: t.CUInt32T, dst: t.CUInt32T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_bsfqi(src: t.CUInt64T, dst: t.CUInt64T | t.CPtr) -> t.CInt | t.State: pass +def __builtin_ia32_bsrqi(src: t.CUInt64T, dst: t.CUInt64T | t.CPtr) -> t.CInt | t.State: pass + +def __builtin_ia32_tzcntsi(x: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_tzcntdi(x: t.CUInt64T) -> t.CUInt64T | t.State: pass +def __builtin_ia32_lzcntsi(x: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_lzcntdi(x: t.CUInt64T) -> t.CUInt64T | t.State: pass + +def __builtin_ia32_bextrsi(src: t.CUInt32T, start: t.CUInt32T, len: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_bextrdi(src: t.CUInt64T, start: t.CUInt32T, len: t.CUInt32T) -> t.CUInt64T | t.State: pass + +def __builtin_ia32_pdep_si(src: t.CUInt32T, mask: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_pext_si(src: t.CUInt32T, mask: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_pdep_di(src: t.CUInt64T, mask: t.CUInt64T) -> t.CUInt64T | t.State: pass +def __builtin_ia32_pext_di(src: t.CUInt64T, mask: t.CUInt64T) -> t.CUInt64T | t.State: pass + +def __builtin_ia32_andn_si(a: t.CUInt32T, b: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_andn_di(a: t.CUInt64T, b: t.CUInt64T) -> t.CUInt64T | t.State: pass + + +# ============================================================ +# Byte Swap (BSWAP) +# ============================================================ + +def __builtin_bswap16(x: t.CUInt16T) -> t.CUInt16T | t.State: pass +def __builtin_bswap32(x: t.CUInt32T) -> t.CUInt32T | t.State: pass +def __builtin_bswap64(x: t.CUInt64T) -> t.CUInt64T | t.State: pass + + +# ============================================================ +# Cache Operations +# ============================================================ + +def __builtin_ia32_clflush(p: t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_clflushopt(p: t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_clwb(p: t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_clzero() -> t.State: pass + + +# ============================================================ +# Prefetch +# ============================================================ + +def __builtin_prefetch(addr: t.CConst | t.CPtr, rw: t.CInt = 0, locality: t.CInt = 3) -> t.State: pass +def __builtin_ia32_prefetch0(p: t.CChar | t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_prefetch1(p: t.CChar | t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_prefetch2(p: t.CChar | t.CConst | t.CPtr) -> t.State: pass +def __builtin_ia32_prefetchnta(p: t.CChar | t.CConst | t.CPtr) -> t.State: pass + + +# ============================================================ +# Non-Temporal Stores +# ============================================================ + +def __builtin_ia32_movnti(p: t.CUInt32T | t.CPtr, val: t.CUInt32T) -> t.State: pass +def __builtin_ia32_movnti64(p: t.CUInt64T | t.CPtr, val: t.CUInt64T) -> t.State: pass +def __builtin_ia32_movntdq(p: t.CPtr, val: t.CPtr) -> t.State: pass +def __builtin_ia32_movntps(p: t.CFloat | t.CPtr, val: t.CFloat) -> t.State: pass +def __builtin_ia32_movntpd(p: t.CDouble | t.CPtr, val: t.CDouble) -> t.State: pass + + +# ============================================================ +# I/O Port Operations +# ============================================================ + +def __builtin_ia32_inb(port: t.CUInt16T) -> t.CUInt8T | t.State: pass +def __builtin_ia32_inw(port: t.CUInt16T) -> t.CUInt16T | t.State: pass +def __builtin_ia32_inl(port: t.CUInt16T) -> t.CUInt32T | t.State: pass +def __builtin_ia32_outb(val: t.CUInt8T, port: t.CUInt16T) -> t.State: pass +def __builtin_ia32_outw(val: t.CUInt16T, port: t.CUInt16T) -> t.State: pass +def __builtin_ia32_outl(val: t.CUInt32T, port: t.CUInt16T) -> t.State: pass + + +# ============================================================ +# Model-Specific Registers (MSR) +# ============================================================ + +def __builtin_ia32_rdmsr(msr: t.CUInt32T, val: t.CUInt64T | t.CPtr) -> t.State: pass +def __builtin_ia32_wrmsr(msr: t.CUInt32T, val: t.CUInt64T) -> t.State: pass + + +# ============================================================ +# System Instructions +# ============================================================ + +def __builtin_ia32_hlt() -> t.State: pass +def __builtin_ia32_invd() -> t.State: pass +def __builtin_ia32_wbinvd() -> t.State: pass +def __builtin_ia32_invlpg(p: t.CPtr) -> t.State: pass +def __builtin_ia32_clts() -> t.State: pass +def __builtin_ia32_cli() -> t.State: pass +def __builtin_ia32_sti() -> t.State: pass +def __builtin_ia32_int3() -> t.State: pass +def __builtin_ia32_int(n: t.CUInt8T) -> t.State: pass +def __builtin_ia32_ud2() -> t.State: pass + + +# ============================================================ +# Descriptor Tables (GDT / IDT / LDT / TR) +# ============================================================ + +def __builtin_ia32_lgdt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_sgdt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_lidt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_sidt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_lldt(sel: t.CUInt32T) -> t.State: pass +def __builtin_ia32_sldt(p: t.CPtr) -> t.State: pass +def __builtin_ia32_ltr(sel: t.CUInt32T) -> t.State: pass +def __builtin_ia32_str(p: t.CPtr) -> t.State: pass + + +# ============================================================ +# Control Registers (CR / MSW) +# ============================================================ + +def __builtin_ia32_lmsw(val: t.CUInt32T) -> t.State: pass +def __builtin_ia32_smsw(p: t.CPtr) -> t.State: pass + + +# ============================================================ +# Monitor / MWAIT +# ============================================================ + +def __builtin_ia32_monitor(p: t.CPtr, extensions: t.CUInt32T, hints: t.CUInt32T) -> t.State: pass +def __builtin_ia32_mwait(extensions: t.CUInt32T, hints: t.CUInt32T) -> t.State: pass + + +# ============================================================ +# XSAVE State Operations +# ============================================================ + +def __builtin_ia32_xsave(p: t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xrstor(p: t.CConst | t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xsaveopt(p: t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xsavec(p: t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xrstors(p: t.CConst | t.CPtr, mask: t.CUInt64T) -> t.State: pass +def __builtin_ia32_xsaves(p: t.CPtr, mask: t.CUInt64T) -> t.State: pass + + +# ============================================================ +# Generic Built-in Functions +# ============================================================ + +def __builtin_expect(exp: t.CLong, c: t.CLong) -> t.CLong | t.State: pass +def __builtin_unreachable() -> t.State: pass +def __builtin_trap() -> t.State: pass +def __builtin_abort() -> t.State: pass +def __builtin_assume_aligned(addr: t.CConst | t.CPtr, align: t.CSizeT, *args) -> t.CPtr | t.State: pass +def __builtin_constant_p(expr: t.CVoid) -> t.CInt | t.State: pass +def __builtin_types_compatible_p(t1: t.CVoid, t2: t.CVoid) -> t.CInt | t.State: pass +def __builtin_choose_expr(const_exp: t.CUInt32T, exp1: t.CVoid, exp2: t.CVoid) -> t.CPtr | t.State: pass +def __builtin_offsetof(typ: t.CVoid, member: t.CVoid) -> t.CSizeT | t.State: pass +def __builtin_function_start(func: t.CPtr) -> t.CPtr | t.State: pass + + +# ============================================================ +# Variable Arguments (VaList) +# ============================================================ + +def __builtin_va_start(va: t.CPtr, *args) -> t.State: pass +def __builtin_va_end(va: t.CPtr) -> t.State: pass +def __builtin_va_arg(va: t.CPtr, typ: t.CVoid) -> t.State: pass +def __builtin_va_copy(dst: t.CPtr, src: t.CConst | t.CPtr) -> t.State: pass + + +# ============================================================ +# Stack & Call Information +# ============================================================ + +def __builtin_return_address(level: t.CUInt32T) -> t.CPtr | t.State: pass +def __builtin_frame_address(level: t.CUInt32T) -> t.CPtr | t.State: pass +def __builtin_alloca(size: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_alloca_with_align(size: t.CSizeT, alignment: t.CSizeT) -> t.CPtr | t.State: pass + + +# ============================================================ +# Memory Operations +# ============================================================ + +def __builtin_memcpy(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_memset(s: t.CPtr, c: t.CInt, n: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_memmove(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_memcmp(s1: t.CConst | t.CPtr, s2: t.CConst | t.CPtr, n: t.CSizeT) -> t.CInt | t.State: pass +def __builtin_mempcpy(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin_memchr(s: t.CConst | t.CPtr, c: t.CInt, n: t.CSizeT) -> t.CPtr | t.State: pass + + +# ============================================================ +# String Operations +# ============================================================ + +def __builtin_strcpy(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strncpy(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, n: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strcat(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strncat(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, n: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strlen(s: t.CChar | t.CConst | t.CPtr) -> t.CSizeT | t.State: pass +def __builtin_strcmp(s1: t.CChar | t.CConst | t.CPtr, s2: t.CChar | t.CConst | t.CPtr) -> t.CInt | t.State: pass +def __builtin_strncmp(s1: t.CChar | t.CConst | t.CPtr, s2: t.CChar | t.CConst | t.CPtr, n: t.CSizeT) -> t.CInt | t.State: pass +def __builtin_strchr(s: t.CChar | t.CConst | t.CPtr, c: t.CInt) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strrchr(s: t.CChar | t.CConst | t.CPtr, c: t.CInt) -> t.CChar | t.CPtr | t.State: pass +def __builtin_strstr(haystack: t.CChar | t.CConst | t.CPtr, needle: t.CChar | t.CConst | t.CPtr) -> t.CChar | t.CPtr | t.State: pass + + +# ============================================================ +# Math Built-in Functions +# ============================================================ + +def __builtin_sqrt(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_sqrtf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_sqrtl(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_pow(x: t.CDouble, y: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_powf(x: t.CFloat, y: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_sin(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_sinf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_cos(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_cosf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_tan(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_tanf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_atan(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_atan2(y: t.CDouble, x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_exp(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_log(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_log2(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_log10(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_fabs(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_fabsf(x: t.CFloat) -> t.CFloat | t.State: pass +def __builtin_abs(x: t.CInt) -> t.CInt | t.State: pass +def __builtin_labs(x: t.CLong) -> t.CLong | t.State: pass +def __builtin_llabs(x: t.CInt64T) -> t.CInt64T | t.State: pass +def __builtin_fma(x: t.CDouble, y: t.CDouble, z: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_fmod(x: t.CDouble, y: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_floor(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_ceil(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_trunc(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_round(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_nearbyint(x: t.CDouble) -> t.CDouble | t.State: pass +def __builtin_rint(x: t.CDouble) -> t.CDouble | t.State: pass + + +# ============================================================ +# Bit Counting Builtins +# ============================================================ + +def __builtin_ffs(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_clz(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_ctz(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_popcount(x: t.CUInt32T) -> t.CInt | t.State: pass +def __builtin_parity(x: t.CUInt32T) -> t.CInt | t.State: pass + +def __builtin_ffsl(x: t.CULong) -> t.CInt | t.State: pass +def __builtin_clzl(x: t.CULong) -> t.CInt | t.State: pass +def __builtin_ctzl(x: t.CULong) -> t.CInt | t.State: pass +def __builtin_popcountl(x: t.CULong) -> t.CInt | t.State: pass +def __builtin_parityl(x: t.CULong) -> t.CInt | t.State: pass + +def __builtin_ffsll(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_clzll(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_ctzll(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_popcountll(x: t.CUInt64T) -> t.CInt | t.State: pass +def __builtin_parityll(x: t.CUInt64T) -> t.CInt | t.State: pass + + +# ============================================================ +# Object Size Checking +# ============================================================ + +def __builtin_object_size(ptr: t.CConst | t.CPtr, typ: t.CInt) -> t.CSizeT | t.State: pass +def __builtin_dynamic_object_size(ptr: t.CConst | t.CPtr, typ: t.CInt) -> t.CSizeT | t.State: pass + +def __builtin___memcpy_chk(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin___memmove_chk(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin___memset_chk(s: t.CPtr, c: t.CInt, n: t.CSizeT, objsize: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin___mempcpy_chk(dst: t.CPtr, src: t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CPtr | t.State: pass +def __builtin___strcpy_chk(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, objsize: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin___strncpy_chk(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin___strcat_chk(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, objsize: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin___strncat_chk(dst: t.CChar | t.CPtr, src: t.CChar | t.CConst | t.CPtr, n: t.CSizeT, objsize: t.CSizeT) -> t.CChar | t.CPtr | t.State: pass +def __builtin___snprintf_chk(s: t.CChar | t.CPtr, maxlen: t.CSizeT, flag: t.CInt, slen: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.State: pass +def __builtin___sprintf_chk(s: t.CChar | t.CPtr, flag: t.CInt, slen: t.CSizeT, fmt: t.CChar | t.CConst | t.CPtr, *args) -> t.CInt | t.State: pass + + +# ============================================================ +# Floating-Point Classification +# ============================================================ + +def __builtin_isnan(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isinf(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isinf_sign(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isfinite(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isnormal(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_signbit(x: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isgreater(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isgreaterequal(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isless(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_islessequal(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_islessgreater(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass +def __builtin_isunordered(x: t.CDouble, y: t.CDouble) -> t.CInt | t.State: pass + + +# ============================================================ +# Special Floating-Point Values +# ============================================================ + +def __builtin_nan(s: t.CChar | t.CConst | t.CPtr) -> t.CDouble | t.State: pass +def __builtin_nanf(s: t.CChar | t.CConst | t.CPtr) -> t.CFloat | t.State: pass +def __builtin_nanl(s: t.CChar | t.CConst | t.CPtr) -> t.CDouble | t.State: pass +def __builtin_nans(s: t.CChar | t.CConst | t.CPtr) -> t.CDouble | t.State: pass +def __builtin_nansf(s: t.CChar | t.CConst | t.CPtr) -> t.CFloat | t.State: pass +def __builtin_inf() -> t.CDouble | t.State: pass +def __builtin_inff() -> t.CFloat | t.State: pass +def __builtin_infl() -> t.CDouble | t.State: pass +def __builtin_huge_val() -> t.CDouble | t.State: pass +def __builtin_huge_valf() -> t.CFloat | t.State: pass +def __builtin_huge_vall() -> t.CDouble | t.State: pass +def __builtin_inf_sign() -> t.CInt | t.State: pass + + +# ============================================================ +# Type Conversion & Overflow Checking +# ============================================================ + +def __builtin_add_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_sub_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_mul_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_sadd_overflow(a: t.CInt64T, b: t.CInt64T, res: t.CInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_ssub_overflow(a: t.CInt64T, b: t.CInt64T, res: t.CInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_smul_overflow(a: t.CInt64T, b: t.CInt64T, res: t.CInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_uadd_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_usub_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass +def __builtin_umul_overflow(a: t.CUInt64T, b: t.CUInt64T, res: t.CUInt64T | t.CPtr) -> t.CBool | t.State: pass + + +# ============================================================ +# MMX / SSE State Management +# ============================================================ + +def __builtin_ia32_emms() -> t.State: pass +def __builtin_ia32_femms() -> t.State: pass + + +# ============================================================ +# Enqueue Commands (ENQCMD) +# ============================================================ + +def __builtin_ia32_enqcmd(dst: t.CPtr, src: t.CConst | t.CPtr) -> t.CBool | t.State: pass +def __builtin_ia32_enqcmds(dst: t.CPtr, src: t.CConst | t.CPtr) -> t.CBool | t.State: pass + + +# ============================================================ +# User-Level Monitor & Wait (UMWAIT / UMONITOR / TPAUSE) +# ============================================================ + +def __builtin_ia32_umonitor(p: t.CPtr) -> t.State: pass +def __builtin_ia32_umwait(extensions: t.CUInt32T, counter: t.CUInt64T) -> t.CUInt8T | t.State: pass +def __builtin_ia32_tpause(extensions: t.CUInt32T, counter: t.CUInt64T) -> t.CUInt8T | t.State: pass + + +# ============================================================ +# Access Control (CLAC / STAC) +# ============================================================ + +def __builtin_ia32_clac() -> t.State: pass +def __builtin_ia32_stac() -> t.State: pass + + +# ============================================================ +# TLB Invalidation (INVLPG Variants) +# ============================================================ + +def __builtin_ia32_invlpgb(aux: t.CUInt64T, pcid: t.CUInt64T) -> t.State: pass +def __builtin_ia32_tlbsync() -> t.State: pass \ No newline at end of file diff --git a/_dict.vp b/_dict.vp new file mode 100644 index 0000000..b8002e2 --- /dev/null +++ b/_dict.vp @@ -0,0 +1,271 @@ +import t, c +import memhub +import string +import json +from stdint import * + +# Variant type tags (consistent with _variant.py) +VARIANT_NONE: t.CDefine = 0 # Untyped / null value +VARIANT_INT: t.CDefine = 1 # int (i64) +VARIANT_FLOAT: t.CDefine = 2 # float (f32) +VARIANT_DOUBLE: t.CDefine = 3 # double (f64) +VARIANT_STR: t.CDefine = 4 # str (i8*) +VARIANT_DICT: t.CDefine = 5 # dict* +VARIANT_LIST: t.CDefine = 6 # list* +VARIANT_BOOL: t.CDefine = 7 # bool (i1/i32) +VARIANT_PTR: t.CDefine = 8 # Custom pointer type + +# Variant structure size: vtype(i32, 4 bytes) + padding(4 bytes) + ptr(i8*, 8 bytes) = 16 bytes +_VARIANT_SIZE: t.CDefine = 16 + + +class dict: + """Heap-allocated dynamic dictionary container based on mbuddy allocator. + Key type is fixed to str (i8*), values are stored as Variant (type tag + untyped pointer). + Supports nested dict/list structures and JSON serialization. + + Usage: + mb: memhub.MemBuddy = memhub.MemBuddy(arena, arena_size) + d: dict = dict(mb) + d.set_int("x", 42) + p: t.CPtr = d["x"] + v: int = c.Deref(p) + + # Nested dict + inner: dict = dict(mb) + inner.set_int("a", 1) + d.set_dict("sub", inner) + sub: dict = c.Deref(d["sub"]) + av: int = c.Deref(sub["a"]) + """ + __keys__: t.CPtr + __values__: t.CPtr + __count__: t.CSizeT = 0 + __capacity__: t.CSizeT = 8 + __mbuddy__: memhub.MemBuddy | t.CPtr + __iter_index__: t.CSizeT = 0 + + def __new__(self, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr: + # Heap allocation for dict object + return mb.alloc(dict.__sizeof__()) + + def __init__(self, mb: memhub.MemBuddy | t.CPtr): + self.__mbuddy__ = mb + self.__keys__ = mb.alloc(self.__capacity__ * 8) + self.__values__ = mb.alloc(self.__capacity__ * _VARIANT_SIZE) + + def __len__(self) -> t.CSizeT: + return self.__count__ + + def _find(self, key: str) -> t.CSizeT: + """Find index of target key; returns __count__ if not found""" + for i in range(self.__count__): + key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + i * 8) + if string.strcmp(key_ptr[0], key) == 0: return i + return self.__count__ + + def __getitem__(self, key: str) -> t.CPtr: + """Return untyped pointer to value. Use c.Deref to resolve the actual value. + Example: p: t.CPtr = d["x"]; v: int = c.Deref(p)""" + idx: t.CSizeT = self._find(key) + if idx >= self.__count__: return None + # Variant.ptr is located at offset 8 within Variant structure + val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8) + return val_ptr[0] + + def __setitem__(self, key: str, val: t.CNeedPtr): + """Store value as VARIANT_PTR. Address is automatically resolved via t.CNeedPtr. + Note: Lifecycle of the data pointed to by val is managed by caller. + Use typed methods such as set_int / set_str for persistent storage.""" + self._set_variant_raw(key, VARIANT_PTR, val) + + def _set_variant_raw(self, key: str, vtype: t.CInt, ptr: t.CPtr): + """Internal method: store Variant entry (vtype + ptr). No automatic address resolution.""" + idx: t.CSizeT = self._find(key) + if idx < self.__count__: + # Update existing key + vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE) + vtype_ptr[0] = vtype + val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8) + val_ptr[0] = ptr + return + if self.__count__ >= self.__capacity__: + new_cap: t.CSizeT = self.__capacity__ * 2 + new_keys: t.CPtr = self.__mbuddy__.alloc(new_cap * 8) + new_values: t.CPtr = self.__mbuddy__.alloc(new_cap * _VARIANT_SIZE) + if new_keys is None or new_values is None: return + string.memcpy(new_keys, self.__keys__, self.__count__ * 8) + string.memcpy(new_values, self.__values__, self.__count__ * _VARIANT_SIZE) + self.__keys__ = new_keys + self.__values__ = new_values + self.__capacity__ = new_cap + key_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__keys__) + self.__count__ * 8) + key_ptr[0] = key + vtype_ptr: t.CInt | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + self.__count__ * _VARIANT_SIZE) + vtype_ptr[0] = vtype + val_ptr: str | t.CPtr = t.CPtr(t.CUInt64T(self.__values__) + self.__count__ * _VARIANT_SIZE + 8) + val_ptr[0] = ptr + self.__count__ += 1 + + # ============================================================ + # Typed setters — allocate persistent storage inside __mbuddy__ + # ============================================================ + + def set_int(self, key: str, val: int): + """Store integer value (VARIANT_INT). Value is copied to persistent storage within __mbuddy__.""" + storage: t.CPtr = self.__mbuddy__.alloc(8) + int_ptr: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + int_ptr[0] = val + self._set_variant_raw(key, VARIANT_INT, storage) + + def set_str(self, key: str, val: str): + """Store string value (VARIANT_STR). Raw string pointer is stored directly.""" + self._set_variant_raw(key, VARIANT_STR, val) + + def set_float(self, key: str, val: float): + """Store float value (VARIANT_FLOAT). Value is copied to persistent storage within __mbuddy__.""" + storage: t.CPtr = self.__mbuddy__.alloc(8) + float_ptr: float | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + float_ptr[0] = val + self._set_variant_raw(key, VARIANT_FLOAT, storage) + + def set_double(self, key: str, val: t.CDouble): + """Store double value (VARIANT_DOUBLE). Value is copied to persistent storage within __mbuddy__.""" + storage: t.CPtr = self.__mbuddy__.alloc(8) + dbl_ptr: t.CDouble | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + dbl_ptr[0] = val + self._set_variant_raw(key, VARIANT_DOUBLE, storage) + + def set_dict(self, key: str, val: dict | t.CPtr): + """Store nested dictionary pointer (VARIANT_DICT).""" + self._set_variant_raw(key, VARIANT_DICT, val) + + def set_list(self, key: str, val: t.CPtr): + """Store nested list pointer (VARIANT_LIST).""" + self._set_variant_raw(key, VARIANT_LIST, val) + + def set_bool(self, key: str, val: t.CInt): + """Store boolean value (VARIANT_BOOL). Value is copied to persistent storage within __mbuddy__.""" + storage: t.CPtr = self.__mbuddy__.alloc(8) + bool_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + bool_ptr[0] = val + self._set_variant_raw(key, VARIANT_BOOL, storage) + + # ============================================================ + # Query methods + # ============================================================ + + def get_vtype(self, key: str) -> t.CInt: + """Return Variant type tag associated with specified key.""" + idx: t.CSizeT = self._find(key) + if idx >= self.__count__: + return VARIANT_NONE + vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE, t.CPtr) + return vtype_ptr[0] + + def get(self, key: str, default: t.CPtr) -> t.CPtr: + """Return value pointer; return default pointer if key does not exist.""" + idx: t.CSizeT = self._find(key) + if idx >= self.__count__: + return default + val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8, t.CPtr) + return val_ptr[0] + + def contains(self, key: str) -> t.CInt: + """Check whether target key exists.""" + idx: t.CSizeT = self._find(key) + if idx < self.__count__: + return 1 + return 0 + + def __iter__(self) -> dict | t.CPtr: + self.__iter_index__ = 0 + return self + + def __next__(self) -> str: + if self.__iter_index__ >= self.__count__: + raise StopIteration + idx: t.CSizeT = self.__iter_index__ + self.__iter_index__ = idx + 1 + key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + idx * 8, t.CPtr) + return key_ptr[0] + + # ============================================================ + # JSON utilities: serialization / deserialization via includes/json library + # ============================================================ + + def to_json(self, pool: memhub.MemManager | t.CPtr) -> json.JsonValue | t.CPtr: + """Convert dict instance to JsonValue object (JSON_OBJECT). + Automatically select corresponding JSON value type according to Variant tag.""" + obj: json.JsonValue | t.CPtr = json.object(pool) + i: t.CSizeT = 0 + while i < self.__count__: + key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + i * 8, t.CPtr) + vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE, t.CPtr) + val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE + 8, t.CPtr) + vt: t.CInt = vtype_ptr[0] + vp: t.CPtr = val_ptr[0] + jv: json.JsonValue | t.CPtr = json.null(pool) + if jv != None: + if vt == VARIANT_INT: + jv.vtype = 2 # JSON_INT + ip: int | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr) + jv.int_val = ip[0] + elif vt == VARIANT_STR: + jv.vtype = 4 # JSON_STRING + jv.str_val = vp + elif vt == VARIANT_BOOL: + jv.vtype = 1 # JSON_BOOL + bp: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr) + jv.bool_val = bp[0] + elif vt == VARIANT_FLOAT: + jv.vtype = 3 # JSON_FLOAT + fp: float | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr) + jv.float_val = fp[0] + elif vt == VARIANT_PTR: + # Fallback: treat raw pointer as integer + jv.vtype = 2 # JSON_INT + ip: int | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr) + jv.int_val = ip[0] + json.object_set(pool, obj, key_ptr[0], jv) + i += 1 + return obj + + def from_json(self, pool: memhub.MemManager | t.CPtr, root: json.JsonValue | t.CPtr): + """Populate dict from JsonValue object. + Extract values and store them as matching Variant types based on JSON type tag.""" + if root == None: + return + if root.vtype != 6: # JSON_OBJECT + return + cur: json.JsonValue | t.CPtr = root.child + while cur != None: + if cur.key != None: + if cur.vtype == 2: # JSON_INT + storage: t.CPtr = self.__mbuddy__.alloc(8) + ip: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + ip[0] = cur.int_val + self._set_variant_raw(cur.key, VARIANT_INT, storage) + elif cur.vtype == 4: # JSON_STRING + self._set_variant_raw(cur.key, VARIANT_STR, cur.str_val) + elif cur.vtype == 1: # JSON_BOOL + storage: t.CPtr = self.__mbuddy__.alloc(8) + bp: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + bp[0] = cur.bool_val + self._set_variant_raw(cur.key, VARIANT_BOOL, storage) + elif cur.vtype == 3: # JSON_FLOAT + storage: t.CPtr = self.__mbuddy__.alloc(8) + fp: float | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + fp[0] = cur.float_val + self._set_variant_raw(cur.key, VARIANT_FLOAT, storage) + cur = cur.next + + def dumps(self, pool: memhub.MemManager | t.CPtr) -> str: + """Serialize dict to JSON string.""" + obj: json.JsonValue | t.CPtr = self.to_json(pool) + return json.write(pool, obj, False) + + def loads(self, pool: memhub.MemManager | t.CPtr, json_str: str): + """Parse JSON string and populate dict instance.""" + root: json.JsonValue | t.CPtr = json.parse(pool, json_str) + self.from_json(pool, root) diff --git a/_fakeduck.vp b/_fakeduck.vp new file mode 100644 index 0000000..2f45393 --- /dev/null +++ b/_fakeduck.vp @@ -0,0 +1,320 @@ +import t +import memhub +import string + + +class _Type: + def type_id(self) -> int: + return 99 + + +class _str: + # Compile-time metadata: declares that this class attempts to retrieve the __mbuddy__ field from the with context + # (optional; no error will be raised if the field cannot be located) + __requires__: list[str] = ['__mbuddy__'] + __data__: str + __mbuddy__: memhub.MemBuddy | t.CPtr + + def upper(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + for i, ch in enumerate(src): + if ch >= 97: + if ch <= 122: + buf[i] = ch - 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def lower(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + for i, ch in enumerate(src): + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def capitalize(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + first: bool = True + for i, ch in enumerate(src): + if first: + first = False + if ch >= 97: + if ch <= 122: + buf[i] = ch - 32 + else: + buf[i] = ch + else: + buf[i] = ch + else: + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def swapcase(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + for i, ch in enumerate(src): + if ch >= 97: + if ch <= 122: + buf[i] = ch - 32 + else: + buf[i] = ch + else: + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def title(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + prev_alpha: bool = False + for i, ch in enumerate(src): + cur_alpha: bool = False + if ch >= 65: + if ch <= 90: + cur_alpha = True + else: + if ch >= 97: + if ch <= 122: + cur_alpha = True + if cur_alpha: + if prev_alpha: + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + else: + if ch >= 97: + if ch <= 122: + buf[i] = ch - 32 + else: + buf[i] = ch + else: + buf[i] = ch + else: + buf[i] = ch + prev_alpha = cur_alpha + buf[length] = 0 + return str(buf) + + def casefold(self) -> str: + src: str = self.__data__ + length: t.CSizeT = len(src) + buf: bytes = self.__mbuddy__.alloc(length + 1) + if buf == None: return self.__data__ + for i, ch in enumerate(src): + if ch >= 65: + if ch <= 90: + buf[i] = ch + 32 + else: + buf[i] = ch + else: + buf[i] = ch + buf[length] = 0 + return str(buf) + + def isupper(self) -> bool: + src: str = self.__data__ + has_alpha: bool = False + for ch in src: + if ch >= 65: + if ch <= 90: + has_alpha = True + else: + if ch >= 97: + if ch <= 122: + return False + return has_alpha + + def islower(self) -> bool: + src: str = self.__data__ + has_alpha: bool = False + for ch in src: + if ch >= 97: + if ch <= 122: + has_alpha = True + if ch >= 65: + if ch <= 90: + return False + return has_alpha + + def isalpha(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + cur_alpha: bool = False + if ch >= 65: + if ch <= 90: + cur_alpha = True + else: + if ch >= 97: + if ch <= 122: + cur_alpha = True + if not cur_alpha: + return False + return has_char + + def isdigit(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + if ch >= 48: + if ch > 57: + return False + else: + return False + return has_char + + def isalnum(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + ok: bool = False + if ch >= 48: + if ch <= 57: + ok = True + if not ok: + if ch >= 65: + if ch <= 90: + ok = True + else: + if ch >= 97: + if ch <= 122: + ok = True + if not ok: + return False + return has_char + + def isspace(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + is_space: bool = False + if ch == 32 or ch == 9 or ch == 10 or ch == 13 or ch == 11 or ch == 12: + is_space = True + if not is_space: + return False + return has_char + + def isascii(self) -> bool: + src: str = self.__data__ + has_char: bool = False + for ch in src: + has_char = True + if ch > 127: return False + return has_char + + def istitle(self) -> bool: + src: str = self.__data__ + has_char: bool = False + prev_alpha: bool = False + for ch in src: + has_char = True + cur_alpha: bool = False + if ch >= 65: + if ch <= 90: + cur_alpha = True + else: + if ch >= 97: + if ch <= 122: + cur_alpha = True + if cur_alpha: + if not prev_alpha: + if ch >= 97: + if ch <= 122: + return False + else: + if ch >= 65: + if ch <= 90: + return False + prev_alpha = cur_alpha + return has_char + + def split(self, delimiter: str) -> list[str]: + result = list[str](self.__mbuddy__) + src: str = self.__data__ + length: t.CSizeT = len(src) + delim_len: t.CSizeT = string.strlen(delimiter) + start: t.CSizeT = 0 + i: t.CSizeT = 0 + cur: str = src + sub_len: t.CSizeT = 0 + sub: bytes = None + src_off: bytes = None + term: bytes = None + if delim_len == 0: + sub_len = length + sub = self.__mbuddy__.alloc(sub_len + 1) + if sub != None: + src_off = bytes(t.CUInt64T(src) + start) + string.memcpy(sub, src_off, sub_len) + term = sub + term[sub_len] = 0 + result.append(str(sub)) + return result + while i + delim_len <= length: + if string.strncmp(cur, delimiter, delim_len) == 0: + sub_len = i - start + sub = self.__mbuddy__.alloc(sub_len + 1) + if sub != None: + src_off = bytes(t.CUInt64T(src) + start) + string.memcpy(sub, src_off, sub_len) + term = sub + term[sub_len] = 0 + result.append(str(sub)) + start = i + delim_len + cur += delim_len + i += delim_len + else: + cur += 1 + i += 1 + sub_len = length - start + sub = self.__mbuddy__.alloc(sub_len + 1) + if sub != None: + src_off = bytes(t.CUInt64T(src) + start) + string.memcpy(sub, src_off, sub_len) + term = sub + term[sub_len] = 0 + result.append(str(sub)) + return result diff --git a/_list.vp b/_list.vp new file mode 100644 index 0000000..5e60cf6 --- /dev/null +++ b/_list.vp @@ -0,0 +1,90 @@ +import t, c +import memhub +import string +from stdint import * + + +class list[T]: + """Heap-allocated dynamic list container backed by memhub.MemManager polymorphic allocator. + + Usage: + pool: memhub.MemManager = memhub.MemBuddy(arena, arena_size) + nums: list[int] = list[int](pool) + nums.append(42) + x: int = nums.get(0) + + For pointer types (e.g. AST | t.CPtr), pass elem_size=8 to avoid object slicing: + lst: list[AST | t.CPtr] = list[AST | t.CPtr](pool, 8) + """ + __data__: t.CVoid | t.CPtr + __count__: t.CSizeT + __capacity__: t.CSizeT + __pool__: memhub.MemManager | t.CPtr + __elem_size__: t.CSizeT + __iter_index__: t.CSizeT + + def __new__(self, pool: memhub.MemManager | t.CPtr, elem_size: t.CSizeT = 0): + ret = pool.alloc(48) + return ret + + def __init__(self, pool: memhub.MemManager | t.CPtr, elem_size: t.CSizeT = 0): + self.__pool__ = pool + self.__count__ = 0 + self.__capacity__ = 8 + if elem_size == 0: + self.__elem_size__ = T.__sizeof__() + else: + self.__elem_size__ = elem_size + self.__data__ = pool.alloc(self.__capacity__ * self.__elem_size__) + self.__iter_index__ = 0 + + def __len__(self) -> t.CSizeT: + return self.__count__ + + def append(self, item: T): + if self.__count__ >= self.__capacity__: + new_cap: t.CSizeT = self.__capacity__ * 2 + new_data: t.CPtr = self.__pool__.alloc(new_cap * self.__elem_size__) + if new_data == None: return + string.memcpy(new_data, self.__data__, self.__count__ * self.__elem_size__) + self.__data__ = new_data + self.__capacity__ = new_cap + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + self.__count__ * self.__elem_size__) + elem_ptr[0] = item + self.__count__ += 1 + + def get(self, index: t.CSizeT) -> T: + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) + return elem_ptr[0] + + def __getitem__(self, index: t.CSizeT) -> T: + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) + return elem_ptr[0] + + def set(self, index: t.CSizeT, value: T): + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) + elem_ptr[0] = value + + def __setitem__(self, index: t.CSizeT, value: T): + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + index * self.__elem_size__) + elem_ptr[0] = value + + def pop(self) -> T: + self.__count__ -= 1 + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + self.__count__ * self.__elem_size__) + return elem_ptr[0] + + def clear(self): + self.__count__ = 0 + + def __iter__(self) -> list[T] | t.CPtr: + self.__iter_index__ = 0 + return self + + def __next__(self) -> T: + if self.__iter_index__ >= self.__count__: + raise StopIteration + idx: t.CSizeT = self.__iter_index__ + self.__iter_index__ = idx + 1 + elem_ptr: T | t.CPtr = t.CPtr(t.CUInt64T(self.__data__) + idx * self.__elem_size__) + return elem_ptr[0] diff --git a/_variant.vp b/_variant.vp new file mode 100644 index 0000000..31273dc --- /dev/null +++ b/_variant.vp @@ -0,0 +1,64 @@ +import t, c +from stdint import * + +# Variant type tags (fixed enumeration + custom pointer type) +VARIANT_NONE: t.CDefine = 0 # Untyped / null value +VARIANT_INT: t.CDefine = 1 # int (i64) +VARIANT_FLOAT: t.CDefine = 2 # float (f32) +VARIANT_DOUBLE: t.CDefine = 3 # double (f64) +VARIANT_STR: t.CDefine = 4 # str (i8*) +VARIANT_DICT: t.CDefine = 5 # dict* +VARIANT_LIST: t.CDefine = 6 # list* +VARIANT_BOOL: t.CDefine = 7 # bool (i1/i32) +VARIANT_PTR: t.CDefine = 8 # Custom pointer type + + +class Variant: + """Generic variant type storing a type tag and untyped pointer. + Used for universal object storage inside dict/list, supports nesting and JSON serialization. + + Usage: + v: Variant = Variant(VARIANT_INT, t.CNeedPtr(42)) + v2: Variant = Variant(VARIANT_STR, t.CNeedPtr("hello")) + + # Retrieve value + ptr: t.CPtr = v.ptr + i: int = c.Deref(ptr) + """ + vtype: int + ptr: t.CPtr + + def __init__(self, vtype: int, val: t.CNeedPtr): + """Construct Variant instance. + t.CNeedPtr automatically obtains address of val (non-pointer values will be allocated on stack and stored). + Note: The lifecycle of val is managed by the caller; Variant only stores a pointer reference. + """ + self.vtype = vtype + self.ptr = val + + def is_none(self) -> int: + return self.vtype == VARIANT_NONE + + def is_int(self) -> int: + return self.vtype == VARIANT_INT + + def is_float(self) -> int: + return self.vtype == VARIANT_FLOAT + + def is_double(self) -> int: + return self.vtype == VARIANT_DOUBLE + + def is_str(self) -> int: + return self.vtype == VARIANT_STR + + def is_dict(self) -> int: + return self.vtype == VARIANT_DICT + + def is_list(self) -> int: + return self.vtype == VARIANT_LIST + + def is_bool(self) -> int: + return self.vtype == VARIANT_BOOL + + def is_ptr(self) -> int: + return self.vtype == VARIANT_PTR diff --git a/_withcontent.vp b/_withcontent.vp new file mode 100644 index 0000000..4bd7bd7 --- /dev/null +++ b/_withcontent.vp @@ -0,0 +1,75 @@ +import t, c +from stdint import * +from w32.win32process import TlsAlloc, TlsGetValue, TlsSetValue +import stdlib +import stdio +import string + + +# Maximum provider stack depth (compiler verifies sufficiency; increase if needed) +_MAX_PROVIDER_DEPTH: t.CDefine = 32 + + +@t.Object +class _ProviderStack: + """Provider stack, stores pairs of field names and pointers.""" + names: t.CArray[VOIDPTR, 32] + ptrs: t.CArray[VOIDPTR, 32] + top: UINT64 + + +# TLS index (global; all threads share the same index) +_tls_index: ULONG = 0 + + +@t.TLS +def _init_tls(): + """Initialize TLS index (executes once; subsequent calls are skipped).""" + global _tls_index + # 双保险:TPV 已正式实现 @t.TLS(函数级一次性守卫,首次执行后置 + # __tls_init_done 标志,后续调用直接返回),此判重守卫保留以兼容 + # 尚未重建的旧 TPV.exe。_tls_index 初始为 0(TlsAlloc 成功不会返回 0)。 + if _tls_index == 0: + _tls_index = TlsAlloc() + + +def _get_stack() -> _ProviderStack | t.CPtr: + """Obtain current thread's provider stack. Allocate one if none exists.""" + _init_tls() + stack: _ProviderStack | t.CPtr = TlsGetValue(_tls_index) + if stack == None: + stack = stdlib.malloc(_ProviderStack.__sizeof__()) + string.memset(stack, 0, _ProviderStack.__sizeof__()) + TlsSetValue(_tls_index, stack) + return stack + + +def _push_provider(field_name: str, ptr: t.CPtr): + """Push a provider (field_name, ptr) onto the stack.""" + stack: _ProviderStack | t.CPtr = _get_stack() + if stack.top >= _MAX_PROVIDER_DEPTH: + stdio.printf("[with] ERROR: provider stack overflow (depth=%lu, max=%d), field '%s' not injected\n", stack.top, _MAX_PROVIDER_DEPTH, field_name) + return + stack.names[stack.top] = field_name + stack.ptrs[stack.top] = ptr + stack.top = stack.top + 1 + + +def _pop_provider(): + """Pop the top provider entry from the stack.""" + stack: _ProviderStack | t.CPtr = _get_stack() + if stack.top > 0: + stack.top = stack.top - 1 + + +def _find_provider(field_name: str) -> t.CPtr: + """Search for matching field_name starting from stack top. + Return associated pointer, or NULL if no match found.""" + stack: _ProviderStack | t.CPtr = _get_stack() + for i in range(stack.top - 1, -1, -1): + # 字段名用 strcmp 内容比较:编译器对每次 create_global_string 生成 + # 独立的字符串常量(TPV 不去重),push/find 的指针地址不同, + # 指针 == 永假会导致 provider 匹配失败(__mbuddy__ 注入不上)。 + if string.strcmp((str)(stack.names[i]), field_name) == 0: + return stack.ptrs[i] + return None \ No newline at end of file diff --git a/argparse.vp b/argparse.vp new file mode 100644 index 0000000..1e8bdd7 --- /dev/null +++ b/argparse.vp @@ -0,0 +1,460 @@ +import t, c +import string +import memhub +import stdio +import hashtable + + +# ============================================================ +# argparse.vp — Command line argument parsing library, inspired by Python argparse +# +# Usage: +# argparse._mbuddy = mb +# parser = argparse.ArgumentParser("myprog", "A test", pool=mb) +# parser.add_argument("--input", "-i", arg_type=argparse.STRING, +# required=True, help="input file") +# parser.add_argument("--count", "-c", arg_type=argparse.INT, +# default=0, help="repeat count") +# parser.add_argument("--verbose", "-v", action=argparse.STORE_TRUE, +# help="verbose mode") +# parser.add_argument("output", arg_type=argparse.STRING, +# help="output path") +# args = parser.parse_args(argc, argv) +# if args is not None: +# inp: str = args.get_str("input") +# cnt: int = args.get_int("count") +# verb: bool = args.get_bool("verbose") +# out: str = args.get_str("output") +# argparse.release(args) +# ============================================================ + +# Type constants +STRING: t.CDefine = 0 +INT: t.CDefine = 1 +BOOL: t.CDefine = 2 + +# Action constants +STORE: t.CDefine = 0 +STORE_TRUE: t.CDefine = 1 +STORE_FALSE: t.CDefine = 2 +COUNT: t.CDefine = 3 + +# Limits +MAX_ARGS: t.CDefine = 32 + +# Module-level membuddy pointer (assigned inside main by user) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================ +# Argument — Argument definition structure +# ============================================================ + +class Argument: + name: str # "--input" or positional "output" + short_name: str # "-i" or null + help_text: str # Help description text + arg_type: int # STRING, INT, BOOL + action: int # STORE, STORE_TRUE, STORE_FALSE, COUNT + default_int: int # Default value for integer types + default_str: str # Default value for string types + required: bool # Whether this argument is mandatory + is_positional: bool # True for positional parameters + dest: str # Lookup key ("--input" → "input") + + +# ============================================================ +# ParsedArgs — Parsing result container +# ============================================================ + +class ParsedArgs: + _ht: hashtable.HashTable | t.CPtr + __mbuddy__: memhub.MemBuddy | t.CPtr + + def __new__(self, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr: + return mb.alloc(16) + + def __init__(self, mb: memhub.MemBuddy | t.CPtr): + self.__mbuddy__ = mb + self._ht = hashtable.HashTable(mb) + + def get_str(self, name: str) -> str: + """Fetch string value. Returns None if key not found.""" + if self._ht.__contains__(name) == 0: + return None + r: str = self._ht[name] + return r + + def get_int(self, name: str) -> int: + """Fetch integer value. Returns 0 if key not found.""" + if self._ht.__contains__(name) == 0: + return 0 + ptr: t.CPtr = self._ht[name] + return c.Deref(t.CInt(t.CUInt64T(ptr), t.CPtr)) + + def get_bool(self, name: str) -> bool: + """Fetch boolean value. Returns false if key not found.""" + if self._ht.__contains__(name) == 0: + return False + ptr: t.CPtr = self._ht[name] + return c.Deref(t.CInt(t.CUInt64T(ptr), t.CPtr)) != 0 + + def has(self, name: str) -> bool: + """Check whether specified key exists.""" + return self._ht.__contains__(name) != 0 + + def _set_str(self, name: str, val: str): + self._ht.set_str(name, val) + + def _set_int(self, name: str, val: int): + self._ht.set_int(name, val) + + def _set_bool(self, name: str, val: bool): + if val: + self._ht.set_int(name, 1) + else: + self._ht.set_int(name, 0) + + +# ============================================================ +# ArgumentParser — Command line argument parser +# ============================================================ + +class ArgumentParser: + _prog: str + _description: str + _args: Argument | t.CPtr + _arg_count: int + __mbuddy__: memhub.MemBuddy | t.CPtr + + def __new__(self, prog: str = "", description: str = "", + pool: memhub.MemBuddy | t.CPtr = None) -> t.CPtr: + mb: memhub.MemBuddy | t.CPtr = pool + if mb is None: + mb = _mbuddy + ret: t.CPtr = mb.alloc(40) + return ret + + def __init__(self, prog: str = "", description: str = "", + pool: memhub.MemBuddy | t.CPtr = None): + mb: memhub.MemBuddy | t.CPtr = pool + if mb is None: + mb = _mbuddy + self.__mbuddy__ = mb + self._prog = prog + self._description = description + self._arg_count = 0 + self._args = mb.alloc(MAX_ARGS * Argument.__sizeof__()) + + def add_argument(self, name: str = "", short: str = None, + arg_type: int = 0, default: int = 0, + default_str: str = None, required: bool = False, + action: int = 0, help: str = None): + """Register a command line argument. + + Args: + name: Argument name ("--input" or positional "output") + short: Short option ("-i"), optional + arg_type: Data type (STRING/INT/BOOL) + default: Default integer value + default_str: Default string value + required: Mandatory flag + action: Action mode (STORE/STORE_TRUE/STORE_FALSE/COUNT) + help: Help description text + """ + if self._arg_count >= MAX_ARGS: + return + idx: int = self._arg_count + arg: Argument | t.CPtr = t.CPtr(t.CUInt64T(self._args) + idx * Argument.__sizeof__()) + arg.name = name + arg.short_name = short + arg.help_text = help + arg.arg_type = arg_type + arg.action = action + arg.default_int = default + arg.default_str = default_str + arg.required = required + # Determine positional flag + if name is not None and name[0] != '-': + arg.is_positional = True + arg.dest = name + else: + arg.is_positional = False + if name is not None and name[0] == '-' and name[1] == '-': + arg.dest = name + 2 + else: + arg.dest = name + 1 + self._arg_count = idx + 1 + + def _get_arg(self, idx: int) -> Argument | t.CPtr: + return t.CPtr(t.CUInt64T(self._args) + idx * Argument.__sizeof__()) + + def _find_long(self, token: str) -> int: + """Exact match for long option name""" + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if string.strcmp(arg.name, token) == 0: + return i + i += 1 + return -1 + + def _find_long_prefix(self, token: str) -> int: + """Match prefix for --name=value syntax""" + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + name_len: int = string.strlen(arg.name) + if string.strncmp(token, arg.name, name_len) == 0: + if token[name_len] == '=': + return i + i += 1 + return -1 + + def _find_short(self, token: str) -> int: + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if arg.short_name is not None: + if string.strcmp(arg.short_name, token) == 0: + return i + i += 1 + return -1 + + def _find_positional(self, pos_idx: int) -> int: + count: int = 0 + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if arg.is_positional: + if count == pos_idx: + return i + count += 1 + i += 1 + return -1 + + def _store_value(self, args: ParsedArgs | t.CPtr, + arg: Argument | t.CPtr, value: str): + if arg.arg_type == INT: + args._set_int(arg.dest, string.atoi(value)) + elif arg.arg_type == STRING: + args._set_str(arg.dest, value) + elif arg.arg_type == BOOL: + v: int = string.atoi(value) + args._set_bool(arg.dest, v != 0) + + def _apply_action(self, args: ParsedArgs | t.CPtr, arg: Argument | t.CPtr): + if arg.action == STORE_TRUE: + args._set_bool(arg.dest, True) + elif arg.action == STORE_FALSE: + args._set_bool(arg.dest, False) + elif arg.action == COUNT: + cur: int = args.get_int(arg.dest) + args._set_int(arg.dest, cur + 1) + + def parse_args(self, argc: int, argv: str | t.CPtr) -> ParsedArgs | t.CPtr: + """Parse command line arguments. + + Args: + argc: Argument count + argv: Argument array (char**, argv[0] = program name) + Returns: + Pointer to ParsedArgs; returns None on failure + """ + if self.__mbuddy__ is None: + return None + + args: ParsedArgs | t.CPtr = ParsedArgs(self.__mbuddy__) + if args is None: + return None + # Initialize default values + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if arg.action == STORE: + if arg.arg_type == INT: + args._set_int(arg.dest, arg.default_int) + elif arg.arg_type == STRING: + args._set_str(arg.dest, arg.default_str) + elif arg.action == STORE_TRUE: + args._set_bool(arg.dest, False) + elif arg.action == STORE_FALSE: + args._set_bool(arg.dest, True) + elif arg.action == COUNT: + args._set_int(arg.dest, 0) + i += 1 + + # Traverse argv + idx: int = 1 + pos_idx: int = 0 + token: str = None + found: int = 0 + arg: Argument | t.CPtr = None + value: str = None + entry: str | t.CPtr = None + + while idx < argc: + entry = t.CPtr(t.CUInt64T(argv) + idx * 8) + token = entry[0] + if token is None: + break + + # "--" terminator: all subsequent tokens become positional arguments + if token[0] == '-' and token[1] == '-' and token[2] == 0: + idx += 1 + while idx < argc: + entry = t.CPtr(t.CUInt64T(argv) + idx * 8) + token = entry[0] + found = self._find_positional(pos_idx) + if found < 0: + stdio.printf("error: unexpected argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + self._store_value(args, arg, token) + pos_idx += 1 + idx += 1 + break + + # Long option --name or --name=value + if token[0] == '-' and token[1] == '-': + has_eq: bool = False + p: str = token + while p[0] != 0: + if p[0] == '=': + has_eq = True + break + p += 1 + + if has_eq: + # --name=value syntax + found = self._find_long_prefix(token) + if found < 0: + stdio.printf("error: unrecognized argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + arg_name_len: int = string.strlen(arg.name) + value = token + arg_name_len + 1 + self._store_value(args, arg, value) + idx += 1 + else: + # --name with value in next token or flag action + found = self._find_long(token) + if found < 0: + stdio.printf("error: unrecognized argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + if arg.action == STORE: + if idx + 1 >= argc: + stdio.printf("error: %s requires a value\n", arg.name) + release(args) + return None + entry = t.CPtr(t.CUInt64T(argv) + (idx + 1) * 8) + value = entry[0] + self._store_value(args, arg, value) + idx += 2 + else: + self._apply_action(args, arg) + idx += 1 + + # Short option -x + elif token[0] == '-': + found = self._find_short(token) + if found < 0: + stdio.printf("error: unrecognized argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + if arg.action == STORE: + if idx + 1 >= argc: + stdio.printf("error: %s requires a value\n", arg.name) + release(args) + return None + entry = t.CPtr(t.CUInt64T(argv) + (idx + 1) * 8) + value = entry[0] + self._store_value(args, arg, value) + idx += 2 + else: + self._apply_action(args, arg) + idx += 1 + + # Positional argument + else: + found = self._find_positional(pos_idx) + if found < 0: + stdio.printf("error: unexpected argument '%s'\n", token) + release(args) + return None + arg = self._get_arg(found) + self._store_value(args, arg, token) + pos_idx += 1 + idx += 1 + + # Validate required arguments + i = 0 + while i < self._arg_count: + arg = self._get_arg(i) + if arg.required: + if not args.has(arg.dest): + stdio.printf("error: missing required argument '%s'\n", arg.name) + release(args) + return None + i += 1 + + return args + + def print_help(self): + """Print complete help message""" + stdio.printf("usage: %s [options]\n", self._prog) + if self._description is not None and self._description[0] != 0: + stdio.printf("\n%s\n", self._description) + stdio.printf("\npositional arguments:\n") + i: int = 0 + while i < self._arg_count: + arg: Argument | t.CPtr = self._get_arg(i) + if arg.is_positional: + ht: str = arg.help_text + if ht is None: + ht = "" + stdio.printf(" %-20s %s\n", arg.name, ht) + i += 1 + stdio.printf("\noptional arguments:\n") + i = 0 + while i < self._arg_count: + arg = self._get_arg(i) + if not arg.is_positional: + ht: str = arg.help_text + if ht is None: + ht = "" + if arg.short_name is not None: + stdio.printf(" %s, %-18s %s\n", arg.short_name, arg.name, ht) + else: + stdio.printf(" %-22s %s\n", arg.name, ht) + i += 1 + + def print_usage(self): + """Print brief usage summary""" + stdio.printf("usage: %s [options]\n", self._prog) + + +# ============================================================ +# release — Release ParsedArgs and all internal resources +# ============================================================ + +def release(args: ParsedArgs | t.CPtr): + """Free ParsedArgs object and its inner HashTable resources.""" + if args is None: + return + if args.__mbuddy__ is None: + return + if args._ht is not None: + # 用临时变量拆分链式属性访问,避免 args._ht.__slots__ 跨模块类型推断失败 + # 注意:类型注解必须用 hashtable.HashTable(带模块前缀), + # 否则编译器无法解析 HashTable 类型,导致 ht.__slots__ 属性访问失败 + ht: hashtable.HashTable | t.CPtr = args._ht + if ht.__slots__ is not None: + args.__mbuddy__.free(ht.__slots__) + args.__mbuddy__.free(t.CVoid(t.CUInt64T(ht), t.CPtr)) + args.__mbuddy__.free(t.CVoid(t.CUInt64T(args), t.CPtr)) diff --git a/asm.vp b/asm.vp new file mode 100644 index 0000000..ef64063 --- /dev/null +++ b/asm.vp @@ -0,0 +1,153 @@ +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 pause(): + c.Asm("pause", op=[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/ast/__init__.vp b/ast/__init__.vp new file mode 100644 index 0000000..5f2a60a --- /dev/null +++ b/ast/__init__.vp @@ -0,0 +1,115 @@ +import t, c +from stdint import * +import memhub +import string + +# Import submodule +from .tokens import ( + Token, TokenType, Keyword, TokOp, _init_tables, +) +# Common Section: Base Classes, Enums, Constants, Helper Functions, Dump +from .base import ( + AST, Stmt, ExprNode, ASTKind, ASTCtx, OpKind, ASTFlag, + # Constants + CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR, + FLAG_IS_ASYNC, FLAG_SIMPLE, FLAG_HAS_STAR, + # Helper Functions + _init_ast, _copy_str, _set_pos, _inherit_pos, _set_parent_list, + _binop_from_op, _augop_from_op, _cmpop_from_op, + _emit, _emit_str, _emit_int, _dump_list, + dump, _op_name, +) +# Statement Nodes: Module, Expression, Interactive, FunctionType +from .stmts import ( + # Module Layer + Module, Expression, Interactive, FunctionType, + # Statement + FunctionDef, ClassDef, Return, Delete, Assign, AugAssign, AnnAssign, + For, While, If, With, Raise, Try, Assert, Global, Nonlocal, + Pass, Break, Continue, Expr, Import, ImportFrom, Match, +) +# Expression Nodes: BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set +from .exprs import ( + # Expression Layer + BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set, + ListComp, SetComp, DictComp, GeneratorExp, + Await, Yield, YieldFrom, FormattedValue, JoinedStr, + Constant, NamedExpr, Attribute, Subscript, Starred, Name, + List, Tuple, Slice, + Call, Compare, OpNode, +) +# Auxiliary Nodes +from .astaux import ( + ExceptHandler, Arguments, Arg, Keyword, Alias, WithItem, + Comprehension, +) +# Pattern Matching +from .match import ( + MatchCase, MatchValue, MatchSingleton, MatchSequence, + MatchMapping, MatchClass, MatchStar, MatchAs, MatchOr, +) +# from .visitor import ASTVisitor +from .lexer import Lexer, _lexer_init, tokenize, new_lexer +from .parser import Parser, _parser_init, parse_tokens, new_parser +from .parser import _parse_test +from .parser import _dbg_lookup_lit_val, _dbg_lit_found +from .parser import get_parse_err_line, get_parse_err_col, get_parse_err_msg + +# ============================================================ +# Global Memory Pool Pointer (follows project rules: declare _mbuddy) +# User initializes in main: ast._mbuddy = memhub.MemBuddy(arena, size) +# ============================================================ +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================ +# Common API: parse +# ============================================================ + +def parse(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr: + """Parse Python source code, return the AST Module node. + + Parameters: + src: NUL source code string, terminated with NUL + pool: memhub.MemManager instance, to allocate AST nodes + + Returns: + AST Module node, or None + """ + if src is None or pool is None: + return None + _init_tables(pool) + lx: Lexer | t.CPtr = new_lexer(pool) + if lx is None: + return None + _lexer_init(lx, src, pool) + tokens: Token | t.CPtr = tokenize(lx) + if tokens is None: + return None + tree: AST | t.CPtr = parse_tokens(pool, tokens) + return tree + + +def parse_expression(src: str, pool: memhub.MemManager | t.CPtr) -> AST | t.CPtr: + """Parse a single expression, return the Expression node. + + Parameters: + src: NUL expression string, terminated with NUL + pool: memhub.MemManager instance, to allocate AST nodes + + Returns: + Expression node, or None + """ + if src is None or pool is None: + return None + _init_tables(pool) + lx: Lexer | t.CPtr = new_lexer(pool) + if lx is None: return None + _lexer_init(lx, src, pool) + tokens: Token | t.CPtr = tokenize(lx) + if tokens is None: return None + ps: Parser | t.CPtr = new_parser(pool) + if ps is None: return None + _parser_init(ps, tokens, pool) + body: AST | t.CPtr = _parse_test(ps) + return Expression(pool, body) diff --git a/ast/astaux.vp b/ast/astaux.vp new file mode 100644 index 0000000..3c51a00 --- /dev/null +++ b/ast/astaux.vp @@ -0,0 +1,337 @@ +import t, c +from stdint import * +import memhub +import string +from .base import ( + AST, ASTKind, + _init_ast, _copy_str, _set_parent_list, + _emit, _emit_str, _emit_int, _dump_list, +) + + +# ============================================================ +# ExceptHandler Node +# ============================================================ + +class ExceptHandler(AST): + """ExceptHandler(type: AST, name: str)""" + type: AST | t.CPtr + name: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, + type: AST | t.CPtr, name: str): + ptr: ExceptHandler | t.CPtr = pool.alloc(ExceptHandler.__sizeof__()) + if ptr: + string.memset(ptr, 0, ExceptHandler.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + type: AST | t.CPtr, name: str): + _init_ast(self, pool, 0, 0) + self.type = type + self.name = _copy_str(pool, name) + + def kind(self) -> t.CInt: + return ASTKind.ExceptHandler + + def type_name(self) -> str: + return "ExceptHandler" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "ExceptHandler(type=") + if self.type is not None: + pos = self.type.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "', body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Arguments Node +# ============================================================ + +class Arguments(AST): + """Arguments(args: list[AST | CPtr], vararg: AST, kwarg: AST, + defaults: list[AST | CPtr], kw_defaults: list[AST | CPtr])""" + args: list[AST | t.CPtr] | t.CPtr + vararg: AST | t.CPtr + kwarg: AST | t.CPtr + defaults: list[AST | t.CPtr] | t.CPtr + kw_defaults: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + args: list[AST | t.CPtr] | t.CPtr, + vararg: AST | t.CPtr, kwarg: AST | t.CPtr, + defaults: list[AST | t.CPtr] | t.CPtr, + kw_defaults: list[AST | t.CPtr] | t.CPtr): + ptr: Arguments | t.CPtr = pool.alloc(Arguments.__sizeof__()) + if ptr: + string.memset(ptr, 0, Arguments.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + args: list[AST | t.CPtr] | t.CPtr, + vararg: AST | t.CPtr, kwarg: AST | t.CPtr, + defaults: list[AST | t.CPtr] | t.CPtr, + kw_defaults: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.args = args + self.vararg = vararg + self.kwarg = kwarg + self.defaults = defaults + self.kw_defaults = kw_defaults + _set_parent_list(args, self) + _set_parent_list(defaults, self) + _set_parent_list(kw_defaults, self) + + def kind(self) -> t.CInt: + return ASTKind.Arguments + + def type_name(self) -> str: + return "Arguments" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Arguments(args=") + pos = _dump_list(self.args, buf, size, pos) + pos = _emit(buf, size, pos, ", vararg=") + if self.vararg is not None: + pos = self.vararg.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", kwarg=") + if self.kwarg is not None: + pos = self.kwarg.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", defaults=") + pos = _dump_list(self.defaults, buf, size, pos) + pos = _emit(buf, size, pos, ", kw_defaults=") + pos = _dump_list(self.kw_defaults, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Arg Node +# ============================================================ + +class Arg(AST): + """Arg(arg: str, annotation: AST)""" + arg: str + annotation: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + arg: str, annotation: AST | t.CPtr): + ptr: Arg | t.CPtr = pool.alloc(Arg.__sizeof__()) + if ptr: + string.memset(ptr, 0, Arg.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + arg: str, annotation: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.arg = _copy_str(pool, arg) + self.annotation = annotation + + def kind(self) -> t.CInt: + return ASTKind.Arg + + def type_name(self) -> str: + return "Arg" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Arg(arg='") + pos = _emit_str(buf, size, pos, self.arg) + pos = _emit(buf, size, pos, "', annotation=") + if self.annotation is not None: + pos = self.annotation.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Keyword Node +# ============================================================ + +class Keyword(AST): + """Keyword(arg: str, value: AST)""" + arg: str + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + arg: str, value: AST | t.CPtr): + ptr: Keyword | t.CPtr = pool.alloc(Keyword.__sizeof__()) + if ptr: + string.memset(ptr, 0, Keyword.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + arg: str, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.arg = _copy_str(pool, arg) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Keyword + + def type_name(self) -> str: + return "Keyword" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Keyword(arg='") + pos = _emit_str(buf, size, pos, self.arg) + pos = _emit(buf, size, pos, "', value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Alias Node +# ============================================================ + +class Alias(AST): + """Alias(name: str, asname: str)""" + name: str + asname: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, + name: str, asname: str): + ptr: Alias | t.CPtr = pool.alloc(Alias.__sizeof__()) + if ptr: + string.memset(ptr, 0, Alias.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + name: str, asname: str): + _init_ast(self, pool, 0, 0) + self.name = _copy_str(pool, name) + self.asname = _copy_str(pool, asname) + + def kind(self) -> t.CInt: + return ASTKind.Alias + + def type_name(self) -> str: + return "Alias" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Alias(name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "', asname='") + pos = _emit_str(buf, size, pos, self.asname) + pos = _emit(buf, size, pos, "')") + return pos + + +# ============================================================ +# WithItem Node +# ============================================================ + +class WithItem(AST): + """WithItem(context_expr: AST, optional_vars: AST)""" + context_expr: AST | t.CPtr + optional_vars: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + context_expr: AST | t.CPtr, optional_vars: AST | t.CPtr): + ptr: WithItem | t.CPtr = pool.alloc(WithItem.__sizeof__()) + if ptr: + string.memset(ptr, 0, WithItem.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + context_expr: AST | t.CPtr, optional_vars: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.context_expr = context_expr + self.optional_vars = optional_vars + + def kind(self) -> t.CInt: + return ASTKind.WithItem + + def type_name(self) -> str: + return "WithItem" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "WithItem(context_expr=") + if self.context_expr is not None: + pos = self.context_expr.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", optional_vars=") + if self.optional_vars is not None: + pos = self.optional_vars.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Comprehension Node +# ============================================================ + +class Comprehension(AST): + """Comprehension(target: AST, iter: AST, ifs: list[AST | CPtr], is_async: CInt)""" + target: AST | t.CPtr + iter: AST | t.CPtr + ifs: list[AST | t.CPtr] | t.CPtr + is_async: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, iter: AST | t.CPtr, + ifs: list[AST | t.CPtr] | t.CPtr, is_async: t.CInt): + ptr: Comprehension | t.CPtr = pool.alloc(Comprehension.__sizeof__()) + if ptr: + string.memset(ptr, 0, Comprehension.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, iter: AST | t.CPtr, + ifs: list[AST | t.CPtr] | t.CPtr, is_async: t.CInt): + _init_ast(self, pool, 0, 0) + self.target = target + self.iter = iter + self.ifs = ifs + self.is_async = is_async + _set_parent_list(ifs, self) + + def kind(self) -> t.CInt: + return ASTKind.Comprehension + + def type_name(self) -> str: + return "Comprehension" + + def dump(self, buf: bytes, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Comprehension(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", iter=") + if self.iter is not None: + pos = self.iter.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", ifs=") + pos = _dump_list(self.ifs, buf, size, pos) + pos = _emit(buf, size, pos, ", is_async=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.is_async)) + pos = _emit(buf, size, pos, ")") + return pos diff --git a/ast/base.vp b/ast/base.vp new file mode 100644 index 0000000..fcf145e --- /dev/null +++ b/ast/base.vp @@ -0,0 +1,504 @@ +import t, c +from stdint import * +import memhub +import string +import viperlib +from .tokens import TokOp + + +# ============================================================ +# ASTKind - Node type enum (kind() virtual function return value) +# ============================================================ + +class ASTKind(t.CEnum): + # Core 15 nodes + Module: t.State + FunctionDef: t.State + ClassDef: t.State + Assign: t.State + If: t.State + For: t.State + While: t.State + Return: t.State + Expr: t.State + Name: t.State + Constant: t.State + BinOp: t.State + UnaryOp: t.State + Call: t.State + Compare: t.State + # Module Layer + Expression: t.State + Interactive: t.State + FunctionType: t.State + # Statement + Delete: t.State + AugAssign: t.State + AnnAssign: t.State + With: t.State + Raise: t.State + Try: t.State + Assert: t.State + Global: t.State + Nonlocal: t.State + Pass: t.State + Break: t.State + Continue: t.State + Import: t.State + ImportFrom: t.State + Match: t.State + # Expression Layer + BoolOp: t.State + Lambda: t.State + IfExp: t.State + Dict: t.State + Set: t.State + ListComp: t.State + SetComp: t.State + DictComp: t.State + GeneratorExp: t.State + Await: t.State + Yield: t.State + YieldFrom: t.State + FormattedValue: t.State + JoinedStr: t.State + Attribute: t.State + Subscript: t.State + Starred: t.State + List: t.State + Tuple: t.State + Slice: t.State + NamedExpr: t.State + # Auxiliary Nodes + ExceptHandler: t.State + Arguments: t.State + Arg: t.State + Keyword: t.State + Alias: t.State + WithItem: t.State + Comprehension: t.State + OpNode: t.State + # Pattern Matching + MatchCase: t.State + MatchValue: t.State + MatchSingleton: t.State + MatchSequence: t.State + MatchMapping: t.State + MatchClass: t.State + MatchStar: t.State + MatchAs: t.State + MatchOr: t.State + + +# ============================================================ +# ASTCtx - Name context (Load/Store/Del) +# ============================================================ + +class ASTCtx(t.CEnum): + Load: t.State + Store: t.State + Del: t.State + + +# ============================================================ +# OpKind - Operator enum (BinOp/UnaryOp/Compare) +# ============================================================ + +class OpKind(t.CEnum): + # Binary arithmetic operators + Add: t.State + Sub: t.State + Mult: t.State + MatMult: t.State + Div: t.State + Mod: t.State + Pow: t.State + LShift: t.State + RShift: t.State + BitOr: t.State + BitXor: t.State + BitAnd: t.State + FloorDiv: t.State + # Boolean operators + And: t.State + Or: t.State + # Comparison operators + Eq: t.State + Ne: t.State + Lt: t.State + Le: t.State + Gt: t.State + Ge: t.State + Is: t.State + IsNot: t.State + In: t.State + NotIn: t.State + # Unary operators + Not: t.State + UAdd: t.State + USub: t.State + Invert: t.State + # None + NoneOp: t.State + + +# Constant subtype identifiers +CONST_INT: t.CDefine = 1 +CONST_FLOAT: t.CDefine = 2 +CONST_STR: t.CDefine = 3 +CONST_BOOL: t.CDefine = 4 +CONST_NONE: t.CDefine = 5 +CONST_CHAR: t.CDefine = 6 + +# Node flags +FLAG_IS_ASYNC: t.CDefine = 1 +FLAG_SIMPLE: t.CDefine = 2 +FLAG_HAS_STAR: t.CDefine = 4 +FLAG_IS_EXTERN: t.CDefine = 8 + + +# ============================================================ +# ASTFlag - Node flags enum +# ============================================================ + +class ASTFlag(t.CEnum): + IsAsync: t.State + Simple: t.State + HasStar: t.State + + +# ============================================================ +# Helper Functions +# ============================================================ + +def _copy_str(pool: memhub.MemManager | t.CPtr, src: str) -> str: + """Allocate and copy a C string from pool.""" + if src is None: return None + slen: t.CSizeT = string.strlen(src) + buf: str = pool.alloc(slen + 1) + if buf is None: return None + string.memcpy(buf, src, slen + 1) + return buf + + +def _set_pos(node: AST | t.CPtr, lineno: t.CInt, col_offset: t.CInt, + end_lineno: t.CInt, end_col_offset: t.CInt): + if node is None: return + node.lineno = lineno + node.col_offset = col_offset + node.end_lineno = end_lineno + node.end_col_offset = end_col_offset + + +def _inherit_pos(node: AST | t.CPtr, ref: AST | t.CPtr): + if node is None or ref is None: return + node.lineno = ref.lineno + node.col_offset = ref.col_offset + node.end_lineno = ref.end_lineno + node.end_col_offset = ref.end_col_offset + + +def _init_ast(node: AST | t.CPtr, pool: memhub.MemManager | t.CPtr, + lineno: t.CInt, col: t.CInt): + """Initialize AST base fields.""" + node.parent = None + node.pool = pool + node.lineno = lineno + node.col_offset = col + node.end_lineno = lineno + node.end_col_offset = col + node.children = None + + +def _set_parent_list(lst: list[AST | t.CPtr] | t.CPtr, parent: AST | t.CPtr): + """Set list children parent pointers.""" + if lst is None: return + n: t.CSizeT = lst.__len__() + i: t.CSizeT = 0 + while i < n: + child: AST | t.CPtr = lst.get(i) + if child is not None: + child.parent = parent + i += 1 + + +def _append_child(lst: list[AST | t.CPtr] | t.CPtr, node: AST | t.CPtr, + pool: memhub.MemManager | t.CPtr): + """Append child nodes to a list (module-level function, to avoid conflicts with the AST.append method name). + + Call this function within the AST.append method to bypass the compiler mistaking list.append for a virtual function call to AST.append when doing type inference.""" + if lst is None or node is None: + return + lst.append(node) + + +# ============================================================ +# Operator Mapping: TokOp -> OpKind +# ============================================================ + +def _binop_from_op(op_id: t.CInt) -> t.CInt: + if op_id == TokOp.Plus: return OpKind.Add + if op_id == TokOp.Minus: return OpKind.Sub + if op_id == TokOp.Star: return OpKind.Mult + if op_id == TokOp.At: return OpKind.MatMult + if op_id == TokOp.Slash: return OpKind.Div + if op_id == TokOp.Percent: return OpKind.Mod + if op_id == TokOp.StarStar: return OpKind.Pow + if op_id == TokOp.LtLt: return OpKind.LShift + if op_id == TokOp.GtGt: return OpKind.RShift + if op_id == TokOp.VBar: return OpKind.BitOr + if op_id == TokOp.Caret: return OpKind.BitXor + if op_id == TokOp.Amp: return OpKind.BitAnd + if op_id == TokOp.DSlash: return OpKind.FloorDiv + return OpKind.NoneOp + + +def _augop_from_op(op_id: t.CInt) -> t.CInt: + if op_id == TokOp.PlusEq: return OpKind.Add + if op_id == TokOp.MinusEq: return OpKind.Sub + if op_id == TokOp.StarEq: return OpKind.Mult + if op_id == TokOp.AtEq: return OpKind.MatMult + if op_id == TokOp.SlashEq: return OpKind.Div + if op_id == TokOp.PercentEq: return OpKind.Mod + if op_id == TokOp.StarEqEq: return OpKind.Pow + if op_id == TokOp.LtLtEq: return OpKind.LShift + if op_id == TokOp.GtGtEq: return OpKind.RShift + if op_id == TokOp.VBarEq: return OpKind.BitOr + if op_id == TokOp.CaretEq: return OpKind.BitXor + if op_id == TokOp.AmpEq: return OpKind.BitAnd + if op_id == TokOp.DSlashEq: return OpKind.FloorDiv + return OpKind.NoneOp + + +def _cmpop_from_op(op_id: t.CInt) -> t.CInt: + if op_id == TokOp.EqEq: return OpKind.Eq + if op_id == TokOp.ExclaimEq: return OpKind.Ne + if op_id == TokOp.Less: return OpKind.Lt + if op_id == TokOp.LessEq: return OpKind.Le + if op_id == TokOp.Greater: return OpKind.Gt + if op_id == TokOp.GreaterEq: return OpKind.Ge + return OpKind.NoneOp + + +# ============================================================ +# dump Helper Functions +# ============================================================ + +def _emit(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT, + text: str) -> t.CSizeT: + """Append literal to buf+pos.""" + if buf is None or pos >= size: + return pos + cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos) + rem: t.CSizeT = size - pos + n: t.CInt = viperlib.snprintf(cur, rem, "%s", text) + if n < 0: + return pos + return pos + t.CSizeT(n) + + +def _emit_str(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT, + text: str) -> t.CSizeT: + """Append a string value to buf pos (using %s format)""" + if buf is None or pos >= size: + return pos + cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos) + rem: t.CSizeT = size - pos + n: t.CInt = viperlib.snprintf(cur, rem, "%s", text) + if n < 0: + return pos + return pos + t.CSizeT(n) + + +def _emit_int(buf: t.CChar | t.CPtr, size: t.CSizeT, pos: t.CSizeT, + val: t.CInt64T) -> t.CSizeT: + """Append an integer value to buf pos (using %lld format).""" + if buf is None or pos >= size: + return pos + cur: t.CChar | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(buf) + pos) + rem: t.CSizeT = size - pos + n: t.CInt = viperlib.snprintf(cur, rem, "%lld", val) + if n < 0: + return pos + return pos + t.CSizeT(n) + + +def _op_name(op: t.CInt) -> str: + """Return the string name of an OpKind.""" + if op == OpKind.Add: return "Add" + if op == OpKind.Sub: return "Sub" + if op == OpKind.Mult: return "Mult" + if op == OpKind.MatMult: return "MatMult" + if op == OpKind.Div: return "Div" + if op == OpKind.Mod: return "Mod" + if op == OpKind.Pow: return "Pow" + if op == OpKind.LShift: return "LShift" + if op == OpKind.RShift: return "RShift" + if op == OpKind.BitOr: return "BitOr" + if op == OpKind.BitXor: return "BitXor" + if op == OpKind.BitAnd: return "BitAnd" + if op == OpKind.FloorDiv: return "FloorDiv" + if op == OpKind.And: return "And" + if op == OpKind.Or: return "Or" + if op == OpKind.Eq: return "Eq" + if op == OpKind.Ne: return "Ne" + if op == OpKind.Lt: return "Lt" + if op == OpKind.Le: return "Le" + if op == OpKind.Gt: return "Gt" + if op == OpKind.Ge: return "Ge" + if op == OpKind.Is: return "Is" + if op == OpKind.IsNot: return "IsNot" + if op == OpKind.In: return "In" + if op == OpKind.NotIn: return "NotIn" + if op == OpKind.Not: return "Not" + if op == OpKind.UAdd: return "UAdd" + if op == OpKind.USub: return "USub" + if op == OpKind.Invert: return "Invert" + return "NoneOp" + + +def _dump_list(lst: list[AST | t.CPtr] | t.CPtr, buf: t.CChar | t.CPtr, + size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT: + """Traverse a list[AST | CPtr] container, polymorphically dump each element.""" + if lst is None: + pos = _emit(buf, size, pos, "[]") + return pos + pos = _emit(buf, size, pos, "[") + n: t.CSizeT = lst.__len__() + i: t.CSizeT = 0 + while i < n: + if i > 0: + pos = _emit(buf, size, pos, ", ") + child: AST | t.CPtr = lst.get(i) + if child is not None: + pos = child.dump(buf, size, pos) + i += 1 + pos = _emit(buf, size, pos, "]") + return pos + + +def _dump_op_list(lst: t.CPtr, buf: t.CChar | t.CPtr, + size: t.CSizeT, pos: t.CSizeT) -> t.CSizeT: + """Traverse a list[CInt] (OpKind values), output a list of op names.""" + if lst is None: + pos = _emit(buf, size, pos, "[]") + return pos + ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(lst) + pos = _emit(buf, size, pos, "[") + n: t.CSizeT = ops_list.__len__() + i: t.CSizeT = 0 + while i < n: + if i > 0: + pos = _emit(buf, size, pos, ", ") + op: t.CInt = ops_list.get(i) + pos = _emit(buf, size, pos, _op_name(op)) + i += 1 + pos = _emit(buf, size, pos, "]") + return pos + + +# ============================================================ +# AST - Polymorphic Base Class + +# @t.CVTable enables vtable, supporting virtual functions like kind()/type_name()/dump()/accept() +# Child nodes are stored in a list[AST | CPtr] container (O(1) random access, more efficient than linked lists) +# The parent field maintains a pointer to the parent (used for upward traversal) +# ============================================================ + +@t.CVTable +class AST: + """AST node base class. All specific node classes inherit from this. + + Fields: + parent: Pointer to the parent node (for upward traversal) + pool: Allocator (used for allocating child nodes/strings) + lineno/col_offset: Starting position + end_lineno/end_col_offset: Ending position + children: List of child nodes (body block, added via append) + """ + parent: AST | t.CPtr + pool: memhub.MemManager | t.CPtr + lineno: t.CInt + col_offset: t.CInt + end_lineno: t.CInt + end_col_offset: t.CInt + children: list[AST | t.CPtr] | t.CPtr + + def kind(self) -> t.CInt: + """Returns the node type (ASTKind value), overridden by subclasses""" + return 0 + + def type_name(self) -> str: + """Return the node type name, subclasses override""" + return "AST" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + """Polymorphic dump: subclasses override to define custom format. Returns the written pos""" + return pos + + def accept(self, visitor: t.CPtr): + """Visitor pattern entry point: subclasses override to dispatch to ASTVisitor in the visitor pattern. + Current implementation is empty. override this method to dispatch to visitor.visit_X(self)""" + pass + + def append(self, node: AST | t.CPtr): + """Append node to the children list. + + Used for parser to build statement blocks: module.append(stmt), if_node.append(stmt), etc. + The children list is lazily initialized on first call. + + Note: list[AST|CPtr] is currently stored by value (compiler limitation), so you must set + node.parent before appending, so the parent in the copy is correct.""" + if self is None or node is None: + return + if self.children is None: + self.children = list[AST | t.CPtr](self.pool, 8) + node.parent = self + _append_child(self.children, node, self.pool) + + +# ============================================================ +# Stmt - Statement Base Class +# +# 所有语句节点(Assign/If/For/While/Return/...)继承 Stmt。 +# isinstance(node, ast.Stmt) 可在运行时区分"语句"与"表达式" +# (依赖 TPV isinstance 子类集合判定 + 三层 vtable 继承)。 +# 不 override kind()(继承 AST 的 0),具体节点各自返回 ASTKind 值。 +# ============================================================ + +@t.CVTable +class Stmt(AST): + """语句节点基类(Assign/If/For/While/Return/...)""" + + +# ============================================================ +# ExprNode - Expression Base Class +# +# 所有表达式节点(Name/Constant/Call/BinOp/...)继承 ExprNode。 +# isinstance(node, ast.ExprNode) 可在运行时区分"表达式"与"语句"。 +# +# 命名说明:不能叫 Expr——ASTKind.Expr(base.vp L23)与 stmts.vp 的 +# Expr 类已是"表达式语句"(Expression Statement)的既有语义。 +# ============================================================ + +@t.CVTable +class ExprNode(AST): + """表达式节点基类(Name/Constant/Call/BinOp/...)""" + + +# ============================================================ +# Module dump function (for ast.dump(node, buf, size)) +# ============================================================ + +def dump(node: AST | t.CPtr, buf: t.CChar | t.CPtr, size: t.CSizeT): + """Serialize AST node to buf (with capacity size)""" + if node is None or buf is None or size == 0: + return + buf[0] = '\0' + final_pos: t.CSizeT = node.dump(buf, size, 0) + # NUL-terminate to prevent printf overflow + if final_pos < size: + buf[final_pos] = '\0' + else: + buf[size - 1] = '\0' diff --git a/ast/exprs.vp b/ast/exprs.vp new file mode 100644 index 0000000..366fffc --- /dev/null +++ b/ast/exprs.vp @@ -0,0 +1,1239 @@ +import t, c +from stdint import * +import memhub +import string +from .base import ( + AST, ExprNode, ASTKind, ASTCtx, OpKind, + _init_ast, _copy_str, _set_parent_list, + _emit, _emit_str, _emit_int, _dump_list, _dump_op_list, _op_name, + CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR +) + + +# ============================================================ +# Name node +# ============================================================ + +class Name(ExprNode): + """Name(id: str, ctx: ASTCtx)""" + id: str + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + id: str, ctx: t.CInt): + ptr: Name | t.CPtr = pool.alloc(Name.__sizeof__()) + if ptr: + string.memset(ptr, 0, Name.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + id: str, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.id = _copy_str(pool, id) + self.ctx = ctx + + def kind(self) -> t.CInt: + return ASTKind.Name + + def type_name(self) -> str: + return "Name" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Name(id='") + pos = _emit_str(buf, size, pos, self.id) + pos = _emit(buf, size, pos, "', ctx=") + if self.ctx == ASTCtx.Load: + pos = _emit(buf, size, pos, "Load") + elif self.ctx == ASTCtx.Store: + pos = _emit(buf, size, pos, "Store") + else: + pos = _emit(buf, size, pos, "Del") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Constant nodes (subtype marked by const_kind) +# ============================================================ + +class Constant(ExprNode): + """Constant(int_val/float_val/str_val, const_kind)""" + int_val: t.CInt64T + float_val: t.CDouble + str_val: str + const_kind: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + const_kind: t.CInt, int_val: t.CInt64T, + float_val: t.CDouble, str_val: str, + lineno: t.CInt, col: t.CInt): + ptr: Constant | t.CPtr = pool.alloc(Constant.__sizeof__()) + if ptr: + string.memset(ptr, 0, Constant.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + const_kind: t.CInt, int_val: t.CInt64T, + float_val: t.CDouble, str_val: str, + lineno: t.CInt, col: t.CInt): + _init_ast(self, pool, lineno, col) + self.const_kind = const_kind + self.int_val = int_val + self.float_val = float_val + if str_val is not None: + self.str_val = _copy_str(pool, str_val) + else: + self.str_val = None + + def kind(self) -> t.CInt: + return ASTKind.Constant + + def type_name(self) -> str: + return "Constant" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Constant(value=") + if self.const_kind == CONST_INT: + pos = _emit_int(buf, size, pos, self.int_val) + elif self.const_kind == CONST_FLOAT: + pos = _emit(buf, size, pos, "") + elif self.const_kind == CONST_STR: + pos = _emit(buf, size, pos, "'") + if self.str_val is not None: + pos = _emit_str(buf, size, pos, self.str_val) + else: + pos = _emit(buf, size, pos, "(null)") + pos = _emit(buf, size, pos, "'") + elif self.const_kind == CONST_CHAR: + # Single character → display as character ASCII value + pos = _emit(buf, size, pos, "char(") + pos = _emit_int(buf, size, pos, self.int_val) + pos = _emit(buf, size, pos, ")") + elif self.const_kind == CONST_BOOL: + if self.int_val != 0: + pos = _emit(buf, size, pos, "True") + else: + pos = _emit(buf, size, pos, "False") + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# BinOp Node +# ============================================================ + +class BinOp(ExprNode): + """BinOp(left: AST, op: OpKind, right: AST)""" + left: AST | t.CPtr + op: t.CInt + right: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + left: AST | t.CPtr, op: t.CInt, right: AST | t.CPtr): + ptr: BinOp | t.CPtr = pool.alloc(BinOp.__sizeof__()) + if ptr: + string.memset(ptr, 0, BinOp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + left: AST | t.CPtr, op: t.CInt, right: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.left = left + self.op = op + self.right = right + + def kind(self) -> t.CInt: + return ASTKind.BinOp + + def type_name(self) -> str: + return "BinOp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "BinOp(left=") + if self.left is not None: + pos = self.left.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ", right=") + if self.right is not None: + pos = self.right.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# UnaryOp Node +# ============================================================ + +class UnaryOp(ExprNode): + """UnaryOp(op: OpKind, operand: AST)""" + op: t.CInt + operand: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + op: t.CInt, operand: AST | t.CPtr): + ptr: UnaryOp | t.CPtr = pool.alloc(UnaryOp.__sizeof__()) + if ptr: + string.memset(ptr, 0, UnaryOp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + op: t.CInt, operand: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.op = op + self.operand = operand + + def kind(self) -> t.CInt: + return ASTKind.UnaryOp + + def type_name(self) -> str: + return "UnaryOp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "UnaryOp(op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ", operand=") + if self.operand is not None: + pos = self.operand.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Compare Node +# ============================================================ + +class Compare(ExprNode): + """Compare(left: AST, ops: list[CInt], comparators: list[AST | CPtr])""" + left: AST | t.CPtr + ops: t.CPtr + comparators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + left: AST | t.CPtr, + ops: t.CPtr, + comparators: list[AST | t.CPtr] | t.CPtr): + ptr: Compare | t.CPtr = pool.alloc(Compare.__sizeof__()) + if ptr: + string.memset(ptr, 0, Compare.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + left: AST | t.CPtr, + ops: t.CPtr, + comparators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.left = left + self.ops = ops + self.comparators = comparators + _set_parent_list(comparators, self) + + def kind(self) -> t.CInt: + return ASTKind.Compare + + def type_name(self) -> str: + return "Compare" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Compare(left=") + if self.left is not None: + pos = self.left.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", ops=") + pos = _dump_op_list(self.ops, buf, size, pos) + pos = _emit(buf, size, pos, ", comparators=") + pos = _dump_list(self.comparators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Call Node +# ============================================================ + +class Call(ExprNode): + """Call(func: AST, args: list[AST | CPtr], keywords: list[AST | CPtr])""" + func: AST | t.CPtr + args: list[AST | t.CPtr] | t.CPtr + keywords: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + func: AST | t.CPtr, + args: list[AST | t.CPtr] | t.CPtr, + keywords: list[AST | t.CPtr] | t.CPtr): + ptr: Call | t.CPtr = pool.alloc(Call.__sizeof__()) + if ptr: + string.memset(ptr, 0, Call.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + func: AST | t.CPtr, + args: list[AST | t.CPtr] | t.CPtr, + keywords: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.func = func + self.args = args + self.keywords = keywords + _set_parent_list(args, self) + _set_parent_list(keywords, self) + + def kind(self) -> t.CInt: + return ASTKind.Call + + def type_name(self) -> str: + return "Call" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Call(func=") + if self.func is not None: + pos = self.func.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", args=") + pos = _dump_list(self.args, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# BoolOp Node +# ============================================================ + +class BoolOp(ExprNode): + """BoolOp(op: CInt, values: list[AST | CPtr])""" + op: t.CInt + values: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + op: t.CInt, + values: list[AST | t.CPtr] | t.CPtr): + ptr: BoolOp | t.CPtr = pool.alloc(BoolOp.__sizeof__()) + if ptr: + string.memset(ptr, 0, BoolOp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + op: t.CInt, + values: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.op = op + self.values = values + _set_parent_list(values, self) + + def kind(self) -> t.CInt: + return ASTKind.BoolOp + + def type_name(self) -> str: + return "BoolOp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "BoolOp(op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ", values=") + pos = _dump_list(self.values, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Lambda Node +# ============================================================ + +class Lambda(ExprNode): + """Lambda(args: AST, body: AST)""" + args: AST | t.CPtr + body: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + args: AST | t.CPtr, body: AST | t.CPtr): + ptr: Lambda | t.CPtr = pool.alloc(Lambda.__sizeof__()) + if ptr: + string.memset(ptr, 0, Lambda.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + args: AST | t.CPtr, body: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.args = args + self.body = body + + def kind(self) -> t.CInt: + return ASTKind.Lambda + + def type_name(self) -> str: + return "Lambda" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Lambda(args=") + if self.args is not None: + pos = self.args.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + if self.body is not None: + pos = self.body.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# IfExp Node +# ============================================================ + +class IfExp(ExprNode): + """IfExp(test: AST, body: AST, orelse: AST)""" + test: AST | t.CPtr + body: AST | t.CPtr + orelse: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, body: AST | t.CPtr, + orelse: AST | t.CPtr): + ptr: IfExp | t.CPtr = pool.alloc(IfExp.__sizeof__()) + if ptr: + string.memset(ptr, 0, IfExp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, body: AST | t.CPtr, + orelse: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.test = test + self.body = body + self.orelse = orelse + + def kind(self) -> t.CInt: + return ASTKind.IfExp + + def type_name(self) -> str: + return "IfExp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "IfExp(test=") + if self.test is not None: + pos = self.test.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + if self.body is not None: + pos = self.body.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", orelse=") + if self.orelse is not None: + pos = self.orelse.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Dict Node +# ============================================================ + +class Dict(ExprNode): + """Dict(keys: list[AST | CPtr], values: list[AST | CPtr])""" + keys: list[AST | t.CPtr] | t.CPtr + values: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + keys: list[AST | t.CPtr] | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr): + ptr: Dict | t.CPtr = pool.alloc(Dict.__sizeof__()) + if ptr: + string.memset(ptr, 0, Dict.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + keys: list[AST | t.CPtr] | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.keys = keys + self.values = values + _set_parent_list(keys, self) + _set_parent_list(values, self) + + def kind(self) -> t.CInt: + return ASTKind.Dict + + def type_name(self) -> str: + return "Dict" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Dict(keys=") + pos = _dump_list(self.keys, buf, size, pos) + pos = _emit(buf, size, pos, ", values=") + pos = _dump_list(self.values, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Set Node +# ============================================================ + +class Set(ExprNode): + """Set(elts: list[AST | CPtr])""" + elts: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr): + ptr: Set | t.CPtr = pool.alloc(Set.__sizeof__()) + if ptr: + string.memset(ptr, 0, Set.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.elts = elts + _set_parent_list(elts, self) + + def kind(self) -> t.CInt: + return ASTKind.Set + + def type_name(self) -> str: + return "Set" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Set(elts=") + pos = _dump_list(self.elts, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# ListComp Node +# ============================================================ + +class ListComp(ExprNode): + """ListComp(elt: AST, generators: list[AST | CPtr])""" + elt: AST | t.CPtr + generators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + ptr: ListComp | t.CPtr = pool.alloc(ListComp.__sizeof__()) + if ptr: + string.memset(ptr, 0, ListComp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.elt = elt + self.generators = generators + _set_parent_list(generators, self) + + def kind(self) -> t.CInt: + return ASTKind.ListComp + + def type_name(self) -> str: + return "ListComp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "ListComp(elt=") + if self.elt is not None: + pos = self.elt.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", generators=") + pos = _dump_list(self.generators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# SetComp Node +# ============================================================ + +class SetComp(ExprNode): + """SetComp(elt: AST, generators: list[AST | CPtr])""" + elt: AST | t.CPtr + generators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + ptr: SetComp | t.CPtr = pool.alloc(SetComp.__sizeof__()) + if ptr: + string.memset(ptr, 0, SetComp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.elt = elt + self.generators = generators + _set_parent_list(generators, self) + + def kind(self) -> t.CInt: + return ASTKind.SetComp + + def type_name(self) -> str: + return "SetComp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "SetComp(elt=") + if self.elt is not None: + pos = self.elt.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", generators=") + pos = _dump_list(self.generators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# DictComp Node +# ============================================================ + +class DictComp(ExprNode): + """DictComp(key: AST, value: AST, generators: list[AST | CPtr])""" + key: AST | t.CPtr + value: AST | t.CPtr + generators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + key: AST | t.CPtr, value: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + ptr: DictComp | t.CPtr = pool.alloc(DictComp.__sizeof__()) + if ptr: + string.memset(ptr, 0, DictComp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + key: AST | t.CPtr, value: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.key = key + self.value = value + self.generators = generators + _set_parent_list(generators, self) + + def kind(self) -> t.CInt: + return ASTKind.DictComp + + def type_name(self) -> str: + return "DictComp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "DictComp(key=") + if self.key is not None: + pos = self.key.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", generators=") + pos = _dump_list(self.generators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# GeneratorExp Node +# ============================================================ + +class GeneratorExp(ExprNode): + """GeneratorExp(elt: AST, generators: list[AST | CPtr])""" + elt: AST | t.CPtr + generators: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + ptr: GeneratorExp | t.CPtr = pool.alloc(GeneratorExp.__sizeof__()) + if ptr: + string.memset(ptr, 0, GeneratorExp.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elt: AST | t.CPtr, + generators: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.elt = elt + self.generators = generators + _set_parent_list(generators, self) + + def kind(self) -> t.CInt: + return ASTKind.GeneratorExp + + def type_name(self) -> str: + return "GeneratorExp" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "GeneratorExp(elt=") + if self.elt is not None: + pos = self.elt.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", generators=") + pos = _dump_list(self.generators, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Await Node +# ============================================================ + +class Await(ExprNode): + """Await(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: Await | t.CPtr = pool.alloc(Await.__sizeof__()) + if ptr: + string.memset(ptr, 0, Await.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Await + + def type_name(self) -> str: + return "Await" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Await(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Yield Node +# ============================================================ + +class Yield(ExprNode): + """Yield(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: Yield | t.CPtr = pool.alloc(Yield.__sizeof__()) + if ptr: + string.memset(ptr, 0, Yield.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Yield + + def type_name(self) -> str: + return "Yield" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Yield(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# YieldFrom Node +# ============================================================ + +class YieldFrom(ExprNode): + """YieldFrom(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: YieldFrom | t.CPtr = pool.alloc(YieldFrom.__sizeof__()) + if ptr: + string.memset(ptr, 0, YieldFrom.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.YieldFrom + + def type_name(self) -> str: + return "YieldFrom" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "YieldFrom(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# FormattedValue Node +# ============================================================ + +class FormattedValue(ExprNode): + """FormattedValue(value: AST, conversion: CInt, format_spec: AST)""" + value: AST | t.CPtr + conversion: t.CInt + format_spec: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, conversion: t.CInt, + format_spec: AST | t.CPtr): + ptr: FormattedValue | t.CPtr = pool.alloc(FormattedValue.__sizeof__()) + if ptr: + string.memset(ptr, 0, FormattedValue.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, conversion: t.CInt, + format_spec: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + self.conversion = conversion + self.format_spec = format_spec + + def kind(self) -> t.CInt: + return ASTKind.FormattedValue + + def type_name(self) -> str: + return "FormattedValue" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "FormattedValue(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", conversion=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.conversion)) + pos = _emit(buf, size, pos, ", format_spec=") + if self.format_spec is not None: + pos = self.format_spec.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# JoinedStr Node +# ============================================================ + +class JoinedStr(ExprNode): + """JoinedStr(values: list[AST | CPtr])""" + values: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr): + ptr: JoinedStr | t.CPtr = pool.alloc(JoinedStr.__sizeof__()) + if ptr: + string.memset(ptr, 0, JoinedStr.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.values = values + _set_parent_list(values, self) + + def kind(self) -> t.CInt: + return ASTKind.JoinedStr + + def type_name(self) -> str: + return "JoinedStr" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "JoinedStr(values=") + pos = _dump_list(self.values, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Attribute Node +# ============================================================ + +class Attribute(ExprNode): + """Attribute(value: AST, attr: str, ctx: CInt)""" + value: AST | t.CPtr + attr: str + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, attr: str, ctx: t.CInt): + ptr: Attribute | t.CPtr = pool.alloc(Attribute.__sizeof__()) + if ptr: + string.memset(ptr, 0, Attribute.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, attr: str, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.value = value + self.attr = _copy_str(pool, attr) + self.ctx = ctx + + def kind(self) -> t.CInt: + return ASTKind.Attribute + + def type_name(self) -> str: + return "Attribute" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Attribute(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", attr='") + pos = _emit_str(buf, size, pos, self.attr) + pos = _emit(buf, size, pos, "', ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Subscript Node +# ============================================================ + +class Subscript(ExprNode): + """Subscript(value: AST, slice: AST, ctx: CInt)""" + value: AST | t.CPtr + slice: AST | t.CPtr + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, slice: AST | t.CPtr, ctx: t.CInt): + ptr: Subscript | t.CPtr = pool.alloc(Subscript.__sizeof__()) + if ptr: + string.memset(ptr, 0, Subscript.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, slice: AST | t.CPtr, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.value = value + self.slice = slice + self.ctx = ctx + + def kind(self) -> t.CInt: + return ASTKind.Subscript + + def type_name(self) -> str: + return "Subscript" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Subscript(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", slice=") + if self.slice is not None: + pos = self.slice.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Starred Node +# ============================================================ + +class Starred(ExprNode): + """Starred(value: AST, ctx: CInt)""" + value: AST | t.CPtr + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, ctx: t.CInt): + ptr: Starred | t.CPtr = pool.alloc(Starred.__sizeof__()) + if ptr: + string.memset(ptr, 0, Starred.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + value: AST | t.CPtr, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.value = value + self.ctx = ctx + + def kind(self) -> t.CInt: + return ASTKind.Starred + + def type_name(self) -> str: + return "Starred" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Starred(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# List Node +# ============================================================ + +class List(ExprNode): + """List(elts: list[AST | CPtr], ctx: CInt)""" + elts: list[AST | t.CPtr] | t.CPtr + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr, ctx: t.CInt): + ptr: List | t.CPtr = pool.alloc(List.__sizeof__()) + if ptr: + string.memset(ptr, 0, List.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.elts = elts + self.ctx = ctx + _set_parent_list(elts, self) + + def kind(self) -> t.CInt: + return ASTKind.List + + def type_name(self) -> str: + return "List" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "List(elts=") + pos = _dump_list(self.elts, buf, size, pos) + pos = _emit(buf, size, pos, ", ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Tuple Node +# ============================================================ + +class Tuple(ExprNode): + """Tuple(elts: list[AST | CPtr], ctx: CInt)""" + elts: list[AST | t.CPtr] | t.CPtr + ctx: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr, ctx: t.CInt): + ptr: Tuple | t.CPtr = pool.alloc(Tuple.__sizeof__()) + if ptr: + string.memset(ptr, 0, Tuple.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + elts: list[AST | t.CPtr] | t.CPtr, ctx: t.CInt): + _init_ast(self, pool, 0, 0) + self.elts = elts + self.ctx = ctx + _set_parent_list(elts, self) + + def kind(self) -> t.CInt: + return ASTKind.Tuple + + def type_name(self) -> str: + return "Tuple" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Tuple(elts=") + pos = _dump_list(self.elts, buf, size, pos) + pos = _emit(buf, size, pos, ", ctx=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.ctx)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Slice Node +# ============================================================ + +class Slice(ExprNode): + """Slice(lower: AST, upper: AST, step: AST)""" + lower: AST | t.CPtr + upper: AST | t.CPtr + step: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + lower: AST | t.CPtr, upper: AST | t.CPtr, + step: AST | t.CPtr): + ptr: Slice | t.CPtr = pool.alloc(Slice.__sizeof__()) + if ptr: + string.memset(ptr, 0, Slice.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + lower: AST | t.CPtr, upper: AST | t.CPtr, + step: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.lower = lower + self.upper = upper + self.step = step + + def kind(self) -> t.CInt: + return ASTKind.Slice + + def type_name(self) -> str: + return "Slice" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Slice(lower=") + if self.lower is not None: + pos = self.lower.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", upper=") + if self.upper is not None: + pos = self.upper.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", step=") + if self.step is not None: + pos = self.step.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# NamedExpr Node +# ============================================================ + +class NamedExpr(ExprNode): + """NamedExpr(target: AST, value: AST)""" + target: AST | t.CPtr + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, value: AST | t.CPtr): + ptr: NamedExpr | t.CPtr = pool.alloc(NamedExpr.__sizeof__()) + if ptr: + string.memset(ptr, 0, NamedExpr.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.target = target + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.NamedExpr + + def type_name(self) -> str: + return "NamedExpr" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "NamedExpr(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# OpNode Node +# ============================================================ + +class OpNode(AST): + """OpNode(op: CInt)""" + op: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, op: t.CInt): + ptr: OpNode | t.CPtr = pool.alloc(OpNode.__sizeof__()) + if ptr: + string.memset(ptr, 0, OpNode.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, op: t.CInt): + _init_ast(self, pool, 0, 0) + self.op = op + + def kind(self) -> t.CInt: + return ASTKind.OpNode + + def type_name(self) -> str: + return "OpNode" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "OpNode(op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ")") + return pos diff --git a/ast/lexer.vp b/ast/lexer.vp new file mode 100644 index 0000000..2b82bb8 --- /dev/null +++ b/ast/lexer.vp @@ -0,0 +1,773 @@ +import t, c +from stdint import * +import memhub +import string +from .tokens import ( + Token, TokenType, TokOp, _init_tables, _kw_lookup, _op_head, + OpEntry, new_token, token_set_str, token_set_str_literal, +) + + +# Maximum Indentation Stack Depth +LEXER_MAX_INDENT: t.CDefine = 256 + + +# ============================================================ +# Lexer State Structure +# ============================================================ +class Lexer: + src: str # Source code (NUL-terminated) + pos: t.CSizeT # Current position + len: t.CSizeT # Source code length + lineno: t.CInt # Current line number (1-based) + col: t.CInt # Current column number (0-based) + pool: memhub.MemManager | t.CPtr # Memory pool + indent_stack: t.CInt | t.CPtr # Indent stack (int array, allocated from pool) + indent_top: t.CInt # Stack top (-1 for empty stack) + paren_depth: t.CInt # Paren depth (>0 for no TokenType.NewLine) + tokens_head: Token | t.CPtr # token list head + tokens_tail: Token | t.CPtr # token list tail + at_line_start: t.CInt # 1=line start (need indent) + error_count: t.CInt # Error count + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Lexer | t.CPtr = pool.alloc(Lexer.__sizeof__()) + if ptr: + string.memset(ptr, 0, Lexer.__sizeof__()) + return ptr + + +def new_lexer(pool: memhub.MemManager | t.CPtr) -> Lexer | t.CPtr: + """Allocate from the pool and return a Lexer (cross-module safe wrapper)""" + return Lexer(pool) + + +def _lexer_init(lx: Lexer | t.CPtr, src: str, + pool: memhub.MemManager | t.CPtr): + """Initialize Lexer""" + if lx == None: return + lx.src = src + lx.pos = 0 + lx.len = string.strlen(src) if src != None else 0 + lx.lineno = 1 + lx.col = 0 + lx.pool = pool + # Allocate indentation stack + lx.indent_stack = pool.alloc(LEXER_MAX_INDENT * 8) + if lx.indent_stack != None: + string.memset(lx.indent_stack, 0, LEXER_MAX_INDENT * 8) + lx.indent_top = -1 + # Push 0 (base indent) + if lx.indent_stack != None: + lx.indent_stack[0] = 0 + lx.indent_top = 0 + lx.paren_depth = 0 + lx.tokens_head = None + lx.tokens_tail = None + lx.at_line_start = 1 + lx.error_count = 0 + _init_tables(pool) + + +# ============================================================ +# Auxiliary Functions +# ============================================================ + +def _peek(lx: Lexer | t.CPtr, offset: t.CSizeT) -> t.CChar: + """Peek character at position pos+offset, return '\0' if out of bounds""" + p: t.CSizeT = lx.pos + offset + if p >= lx.len: + return '\0' + return lx.src[p] + + +def _peek_cur(lx: Lexer | t.CPtr) -> t.CChar: + if lx.pos >= lx.len: + return '\0' + return lx.src[lx.pos] + + +def _advance(lx: Lexer | t.CPtr) -> t.CChar: + """Advance one character, return the character""" + if lx.pos >= lx.len: + return '\0' + ch: t.CChar = lx.src[lx.pos] + lx.pos += 1 + if ch == '\n': + lx.lineno += 1 + lx.col = 0 + else: + lx.col += 1 + return ch + + +def _is_alpha(ch: t.CChar) -> t.CInt: + if ch >= 'a' and ch <= 'z': return 1 + if ch >= 'A' and ch <= 'Z': return 1 + if ch == '_': return 1 + return 0 + + +def _is_digit(ch: t.CChar) -> t.CInt: + if ch >= '0' and ch <= '9': return 1 + return 0 + + +def _is_alnum(ch: t.CChar) -> t.CInt: + if _is_alpha(ch): return 1 + if _is_digit(ch): return 1 + return 0 + + +def _is_hex(ch: t.CChar) -> t.CInt: + if ch >= '0' and ch <= '9': return 1 + if ch >= 'a' and ch <= 'f': return 1 + if ch >= 'A' and ch <= 'F': return 1 + return 0 + + +def _is_space(ch: t.CChar) -> t.CInt: + if ch == ' ': return 1 + if ch == '\t': return 1 + if ch == '\f': return 1 + if ch == '\v': return 1 + if ch == '\r': return 1 + return 0 + + +def _emit(lx: Lexer | t.CPtr, tok: Token | t.CPtr): + """Append token to token list""" + if tok == None: return + if lx.tokens_head == None: + lx.tokens_head = tok + lx.tokens_tail = tok + else: + lx.tokens_tail.next = tok + lx.tokens_tail = tok + + +def _make_op_token(lx: Lexer | t.CPtr, op_id: t.CInt, length: t.CInt, + lineno: t.CInt, col: t.CInt) -> Token | t.CPtr: + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Op, lineno, col) + if tok == None: return None + tok.op_subtype = op_id + tok.end_col_offset = col + length + return tok + + +# ============================================================ +# Indent Handling +# ============================================================ + +def _handle_indent(lx: Lexer | t.CPtr): + """Handle line start indent, generate TokenType.Indent/TokenType.Dedent. + Skip empty lines and comment lines.""" + # Skip empty lines and comment lines + while lx.pos < lx.len: + # Save line start position for non-empty lines + line_start_pos: t.CSizeT = lx.pos + line_start_col: t.CInt = lx.col + # Skip whitespace, not across lines + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == ' ' or ch == '\t' or ch == '\f' or ch == '\v': + lx.pos += 1 + lx.col += 1 + elif ch == '\r': + # CRLF line end \r, skip \n to trigger empty line processing + lx.pos += 1 + else: + break + if lx.pos >= lx.len: + break + ch = lx.src[lx.pos] + if ch == '\n': + # Empty line, skip + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue + if ch == '\r': + # CRLF line end \r, skip \n to trigger empty line processing + lx.pos += 1 + if lx.pos < lx.len and lx.src[lx.pos] == '\n': + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue + if ch == '#': + # Comment line, skip to end of line + while lx.pos < lx.len and lx.src[lx.pos] != '\n': + lx.pos += 1 + continue + # Non-empty line: backtrack to line start to allow indent calculation + lx.pos = line_start_pos + lx.col = line_start_col + break + + if lx.pos >= lx.len: + # End of file, no indent to handle + lx.at_line_start = 0 + return + + # Calculate current line indent + indent: t.CInt = 0 + save_pos: t.CSizeT = lx.pos + save_col: t.CInt = lx.col + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == ' ': + indent += 1 + lx.pos += 1 + lx.col += 1 + elif ch == '\t': + indent += 8 - (indent % 8) + lx.pos += 1 + lx.col += 1 + else: + break + + # If line end (empty line), skip indent calculation + if lx.pos < lx.len: + ch = lx.src[lx.pos] + if ch == '\n' or ch == '\r' or ch == '#': + # Empty line or comment line, backtrack position to allow loop to handle indent + lx.pos = save_pos + lx.col = save_col + lx.at_line_start = 0 + return + + # Compare indent with top of indent stack + top_indent: t.CInt = lx.indent_stack[lx.indent_top] + if indent > top_indent: + # TokenType.Indent + if lx.indent_top + 1 >= LEXER_MAX_INDENT: + lx.error_count += 1 + return + lx.indent_top += 1 + lx.indent_stack[lx.indent_top] = indent + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Indent, lx.lineno, 0) + _emit(lx, tok) + else: + while indent < lx.indent_stack[lx.indent_top] and lx.indent_top > 0: + lx.indent_top -= 1 + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Dedent, lx.lineno, 0) + _emit(lx, tok) + lx.at_line_start = 0 + + +# ============================================================ +# Identifier/Keyword Handling +# ============================================================ + +def _read_name(lx: Lexer | t.CPtr): + start: t.CSizeT = lx.pos + start_lineno: t.CInt = lx.lineno + start_col: t.CInt = lx.col + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_alnum(ch): + lx.pos += 1 + lx.col += 1 + else: + break + length: t.CSizeT = lx.pos - start + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Name, start_lineno, start_col) + if tok == None: return + token_set_str(lx.pool, tok, lx.src, start, length) + tok.end_lineno = lx.lineno + tok.end_col_offset = start_col + t.CInt(length) + # Look up keyword if any + kw_id: t.CInt = _kw_lookup(tok.str_val) + if kw_id: + tok.kw_subtype = kw_id + _emit(lx, tok) + + +# ============================================================ +# Number Handling +# ============================================================ + +def _read_number(lx: Lexer | t.CPtr): + start: t.CSizeT = lx.pos + start_lineno: t.CInt = lx.lineno + start_col: t.CInt = lx.col + is_float: t.CInt = 0 + is_complex: t.CInt = 0 + + ch0: t.CChar = lx.src[lx.pos] + # Handle 0x/0o/0b prefix + if ch0 == '0' and lx.pos + 1 < lx.len: + ch1: t.CChar = lx.src[lx.pos + 1] + if ch1 == 'x' or ch1 == 'X': + lx.pos += 2 + lx.col += 2 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_hex(ch) or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + _emit_number(lx, start, start_lineno, start_col, 0, 0, 0) + return + if ch1 == 'o' or ch1 == 'O': + lx.pos += 2 + lx.col += 2 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch >= '0' and ch <= '7': + lx.pos += 1 + lx.col += 1 + elif ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + _emit_number(lx, start, start_lineno, start_col, 0, 0, 0) + return + if ch1 == 'b' or ch1 == 'B': + lx.pos += 2 + lx.col += 2 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == '0' or ch == '1' or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + _emit_number(lx, start, start_lineno, start_col, 0, 0, 0) + return + + # Decimal integer/float + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_digit(ch) or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + + # Decimal part + if lx.pos < lx.len and lx.src[lx.pos] == '.': + is_float = 1 + lx.pos += 1 + lx.col += 1 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_digit(ch) or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + + # Exponent part + if lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == 'e' or ch == 'E': + is_float = 1 + lx.pos += 1 + lx.col += 1 + if lx.pos < lx.len: + ch = lx.src[lx.pos] + if ch == '+' or ch == '-': + lx.pos += 1 + lx.col += 1 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if _is_digit(ch) or ch == '_': + lx.pos += 1 + lx.col += 1 + else: + break + + # Complex suffix part + if lx.pos < lx.len and lx.src[lx.pos] == 'j': + is_complex = 1 + is_float = 1 + lx.pos += 1 + lx.col += 1 + + _emit_number(lx, start, start_lineno, start_col, is_float, is_complex, 0) + + +def _emit_number(lx: Lexer | t.CPtr, start: t.CSizeT, + start_lineno: t.CInt, start_col: t.CInt, + is_float: t.CInt, is_complex: t.CInt, is_hex: t.CInt): + length: t.CSizeT = lx.pos - start + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Number, start_lineno, start_col) + if tok == None: return + token_set_str(lx.pool, tok, lx.src, start, length) + tok.is_float = is_float + tok.is_complex = is_complex + tok.end_lineno = lx.lineno + tok.end_col_offset = start_col + t.CInt(length) + # Parse number + if is_float: + tok.float_val = string.atof(tok.str_val) + else: + tok.int_val = string.atoll(tok.str_val) + _emit(lx, tok) + + +# ============================================================ +# String Handling +# ============================================================ + +def _read_string(lx: Lexer | t.CPtr): + """Read string literal. + Supports prefixes: r, b, u, f, rb, br, rf, fr (case insensitive) + Supports quotes: ', ", ''', + Later we need to support string prefixes like i16/i24""" + start_lineno: t.CInt = lx.lineno + start_col: t.CInt = lx.col + prefix_start: t.CSizeT = lx.pos + + # Read prefix (r/b/u/f) + is_raw: t.CInt = 0 + is_bytes: t.CInt = 0 + is_fstring: t.CInt = 0 + while lx.pos < lx.len: + ch: t.CChar = lx.src[lx.pos] + if ch == 'r' or ch == 'R': + is_raw = 1 + lx.pos += 1 + lx.col += 1 + elif ch == 'b' or ch == 'B': + is_bytes = 1 + lx.pos += 1 + lx.col += 1 + elif ch == 'u' or ch == 'U': + lx.pos += 1 + lx.col += 1 + elif ch == 'f' or ch == 'F': + is_fstring = 1 + lx.pos += 1 + lx.col += 1 + else: + break + + if lx.pos >= lx.len: + lx.error_count += 1 + return + + # Determine quote type + quote: t.CChar = lx.src[lx.pos] + if quote != '\'' and quote != '"': + lx.error_count += 1 + return + + # Check triple quote + is_triple: t.CInt = 0 + if lx.pos + 2 < lx.len: + if lx.src[lx.pos] == quote and lx.src[lx.pos + 1] == quote and lx.src[lx.pos + 2] == quote: + is_triple = 1 + + content_start: t.CSizeT = lx.pos + if is_triple: + lx.pos += 3 + lx.col += 3 + else: + lx.pos += 1 + lx.col += 1 + + # Read string content + content_buf_start: t.CSizeT = lx.pos + while lx.pos < lx.len: + ch = lx.src[lx.pos] + if is_triple: + if ch == quote: + if lx.pos + 2 < lx.len: + if lx.src[lx.pos + 1] == quote and lx.src[lx.pos + 2] == quote: + break + elif lx.pos + 2 == lx.len: + break + if ch == '\\': + lx.pos += 1 + lx.col += 1 + if lx.pos < lx.len: + if lx.src[lx.pos] == '\n': + lx.lineno += 1 + lx.col = 0 + lx.pos += 1 + lx.col += 1 + continue + if ch == '\n': + lx.lineno += 1 + lx.col = 0 + lx.pos += 1 + lx.col += 1 + else: + if ch == quote: + break + if ch == '\n': + # Single quote string cannot span multiple lines (unless continued) + lx.error_count += 1 + return + if ch == '\\' and not is_raw: + lx.pos += 1 + lx.col += 1 + if lx.pos < lx.len: + lx.pos += 1 + lx.col += 1 + continue + lx.pos += 1 + lx.col += 1 + + content_end: t.CSizeT = lx.pos + # Skip the closing quote + if is_triple: + if lx.pos + 2 < lx.len: + lx.pos += 3 + lx.col += 3 + else: + lx.pos = lx.len + else: + if lx.pos < lx.len: + lx.pos += 1 + lx.col += 1 + + # Create token + tok: Token | t.CPtr = new_token(lx.pool, TokenType.String, start_lineno, start_col) + if tok == None: return + content_len: t.CSizeT = content_end - content_buf_start + # esc_len: Actual bytes after escaping (used to check single character) + esc_len: t.CSizeT = content_len + + # Handle escape sequences (non-raw strings) + if is_raw == 0 and content_len > 0: + # Allocate conversion buffer (max case: each char is plain, no extension) + conv_buf: str = lx.pool.alloc(content_len + 1) + if conv_buf == None: + token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len) + else: + wpos: t.CSizeT = 0 + rpos: t.CSizeT = 0 + while rpos < content_len: + ch: t.CChar = lx.src[content_buf_start + rpos] + if ch == '\\' and rpos + 1 < content_len: + rpos += 1 + next_ch: t.CChar = lx.src[content_buf_start + rpos] + if next_ch == 'n': + conv_buf[wpos] = '\n' + elif next_ch == 't': + conv_buf[wpos] = '\t' + elif next_ch == 'r': + conv_buf[wpos] = '\r' + elif next_ch == 'f': + conv_buf[wpos] = '\f' + elif next_ch == 'v': + conv_buf[wpos] = '\v' + elif next_ch == 'a': + conv_buf[wpos] = '\a' + elif next_ch == 'b': + conv_buf[wpos] = '\b' + elif next_ch == '\\': + conv_buf[wpos] = '\\' + elif next_ch == '\'': + conv_buf[wpos] = '\'' + elif next_ch == '"': + conv_buf[wpos] = '"' + elif next_ch == '0': + conv_buf[wpos] = '\0' + else: + # Unknown escape sequence, keep original (includes \xNN) + conv_buf[wpos] = '\\' + wpos += 1 + conv_buf[wpos] = next_ch + wpos += 1 + rpos += 1 + else: + conv_buf[wpos] = ch + wpos += 1 + rpos += 1 + conv_buf[wpos] = '\0' + token_set_str_literal(lx.pool, tok, conv_buf) + esc_len = wpos + else: + token_set_str(lx.pool, tok, lx.src, content_buf_start, content_len) + tok.end_lineno = lx.lineno + tok.end_col_offset = lx.col + # flags field: bit0=raw, bit1=bytes, bit2=fstring, bit3=triple, bit4=dquote, bit5=single char candidate + if is_raw: tok.kw_subtype = tok.kw_subtype | 1 + if is_bytes: tok.kw_subtype = tok.kw_subtype | 2 + if is_fstring: tok.kw_subtype = tok.kw_subtype | 4 + if is_triple: tok.kw_subtype = tok.kw_subtype | 8 + # bit4 (16) = double quote=single quote + if quote == '"': tok.kw_subtype = tok.kw_subtype | 16 + # bit5 (32) = single-character candidate (not triple quotes, not f-string, exactly 1 byte after escaping) + # Used for CONST_CHAR checks to prevent '0' and other NUL bytes from being mistaken as empty strings by strlen + if is_triple == 0 and is_fstring == 0 and esc_len == 1: + tok.kw_subtype = tok.kw_subtype | 32 + _emit(lx, tok) + + +# ============================================================ +# Operator Matching +# ============================================================ + +def _read_operator(lx: Lexer | t.CPtr): + """Greedy match operator""" + start_lineno: t.CInt = lx.lineno + start_col: t.CInt = lx.col + remaining: t.CSizeT = lx.len - lx.pos + + # Traverse operator table, find longest match + best_entry: OpEntry | t.CPtr = None + best_len: t.CInt = 0 + cur: OpEntry | t.CPtr = _op_head + while cur != None: + if cur.length <= t.CInt(remaining): + # Compare cur.name with src[pos:pos+cur.length] + match: t.CInt = 1 + i: t.CSizeT = 0 + while i < t.CSizeT(cur.length): + if lx.src[lx.pos + i] != cur.name[i]: + match = 0 + break + i += 1 + if match: + if cur.length > best_len: + best_len = cur.length + best_entry = cur + cur = cur.next + + if best_entry == None: + # Unknown character, report error and skip + lx.error_count += 1 + lx.pos += 1 + lx.col += 1 + return + + # Update parenthesis depth + if best_entry.op_id == TokOp.LPar or best_entry.op_id == TokOp.Lsqb or best_entry.op_id == TokOp.LBrace: + lx.paren_depth += 1 + elif best_entry.op_id == TokOp.RPar or best_entry.op_id == TokOp.Rsqb or best_entry.op_id == TokOp.RBrace: + if lx.paren_depth > 0: + lx.paren_depth -= 1 + + tok: Token | t.CPtr = _make_op_token(lx, best_entry.op_id, best_entry.length, + start_lineno, start_col) + if tok == None: return + token_set_str(lx.pool, tok, lx.src, lx.pos, t.CSizeT(best_len)) + lx.pos += t.CSizeT(best_len) + lx.col += best_len + _emit(lx, tok) + + +# ============================================================ +# Main Lexical Analysis Entry Point +# ============================================================ + +def tokenize(lx: Lexer | t.CPtr) -> Token | t.CPtr: + """Execute tokenization, return token list head""" + if lx == None: return None + while lx.pos < lx.len: + # Handle line start indent + if lx.at_line_start and lx.paren_depth == 0: + _handle_indent(lx) + if lx.pos >= lx.len: + break + + ch: t.CChar = _peek_cur(lx) + if ch == '\0': + break + + # New line + if ch == '\n': + if lx.paren_depth > 0: + # # In bi brackets, generates TokenType.Nl + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Nl, lx.lineno, lx.col) + _emit(lx, tok) + else: + # Logical new line + tok: Token | t.CPtr = new_token(lx.pool, TokenType.NewLine, lx.lineno, lx.col) + _emit(lx, tok) + lx.at_line_start = 1 + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue + + # Backslash continuation line + # 支持 LF 与 CRLF(Windows 文件行尾):CRLF 下 `\` 后是 '\r'(非 '\n'), + # 只查 '\n' 会失效 → `\` 被当未知字符跳过、'\n' 产生 NEWLINE → 表达式 + # 中断(VpiReader.vp L324 `or \` 行尾续行根因,CRLF 文件)。 + if ch == '\\' and lx.pos + 1 < lx.len: + if lx.src[lx.pos + 1] == '\n': + lx.pos += 2 + lx.lineno += 1 + lx.col = 0 + continue + if lx.src[lx.pos + 1] == '\r': + # \ + \r\n:跳 \、\r、\n + lx.pos += 2 + if lx.pos < lx.len and lx.src[lx.pos] == '\n': + lx.pos += 1 + lx.lineno += 1 + lx.col = 0 + continue + + # Whitespace + if _is_space(ch): + lx.pos += 1 + lx.col += 1 + continue + + # Comment + if ch == '#': + while lx.pos < lx.len and lx.src[lx.pos] != '\n': + lx.pos += 1 + continue + + # String prefixes (like r"...") or strings + if ch == '\'' or ch == '"': + _read_string(lx) + continue + # A string prefix letter followed by a quote (must be checked before _is_alpha, otherwise f/r/b/u will be treated as TokenType.Name) + if (ch == 'r' or ch == 'R' or ch == 'b' or ch == 'B' or + ch == 'u' or ch == 'U' or ch == 'f' or ch == 'F'): + if lx.pos + 1 < lx.len: + ch1: t.CChar = lx.src[lx.pos + 1] + if ch1 == '\'' or ch1 == '"': + _read_string(lx) + continue + # Double prefixes like rb, br, rf, fr + if lx.pos + 2 < lx.len: + ch2: t.CChar = lx.src[lx.pos + 2] + if ((ch1 == 'r' or ch1 == 'R' or ch1 == 'b' or ch1 == 'B' or + ch1 == 'f' or ch1 == 'F' or ch1 == 'u' or ch1 == 'U') and + (ch2 == '\'' or ch2 == '"')): + _read_string(lx) + continue + + # Identifier/keyword + if _is_alpha(ch): + _read_name(lx) + continue + + # Number + if _is_digit(ch): + _read_number(lx) + continue + + # Operator + _read_operator(lx) + + # End of file: generate TokenType.NewLine (if there's content) + if lx.tokens_tail != None: + if lx.tokens_tail.type != TokenType.NewLine and lx.tokens_tail.type != TokenType.Nl: + tok: Token | t.CPtr = new_token(lx.pool, TokenType.NewLine, lx.lineno, lx.col) + _emit(lx, tok) + + # Generate remaining remaining TokenType.Dedent + while lx.indent_top > 0: + lx.indent_top -= 1 + tok: Token | t.CPtr = new_token(lx.pool, TokenType.Dedent, lx.lineno, 0) + _emit(lx, tok) + + # TokenType.EndMarker + tok: Token | t.CPtr = new_token(lx.pool, TokenType.EndMarker, lx.lineno, 0) + _emit(lx, tok) + + return lx.tokens_head diff --git a/ast/match.vp b/ast/match.vp new file mode 100644 index 0000000..7e78378 --- /dev/null +++ b/ast/match.vp @@ -0,0 +1,363 @@ +import t, c +from stdint import * +import memhub +import string +from .base import ( + AST, ASTKind, + _init_ast, _copy_str, _set_parent_list, + _emit, _emit_str, _emit_int, _dump_list, +) + + +# ============================================================ +# MatchCase 节点Node +# ============================================================ + +class MatchCase(AST): + """MatchCase(pattern: AST, guard: AST)""" + pattern: AST | t.CPtr + guard: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + pattern: AST | t.CPtr, guard: AST | t.CPtr): + ptr: MatchCase | t.CPtr = pool.alloc(MatchCase.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchCase.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + pattern: AST | t.CPtr, guard: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.pattern = pattern + self.guard = guard + + def kind(self) -> t.CInt: + return ASTKind.MatchCase + + def type_name(self) -> str: + return "MatchCase" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchCase(pattern=") + if self.pattern is not None: + pos = self.pattern.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", guard=") + if self.guard is not None: + pos = self.guard.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchValue Node +# ============================================================ + +class MatchValue(AST): + """MatchValue(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: MatchValue | t.CPtr = pool.alloc(MatchValue.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchValue.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.MatchValue + + def type_name(self) -> str: + return "MatchValue" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchValue(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchSingleton Node +# ============================================================ + +class MatchSingleton(AST): + """MatchSingleton(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: MatchSingleton | t.CPtr = pool.alloc(MatchSingleton.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchSingleton.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.MatchSingleton + + def type_name(self) -> str: + return "MatchSingleton" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchSingleton(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchSequence Node +# ============================================================ + +class MatchSequence(AST): + """MatchSequence(patterns: list[AST | t.CPtr])""" + patterns: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr): + ptr: MatchSequence | t.CPtr = pool.alloc(MatchSequence.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchSequence.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.patterns = patterns + _set_parent_list(patterns, self) + + def kind(self) -> t.CInt: + return ASTKind.MatchSequence + + def type_name(self) -> str: + return "MatchSequence" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchSequence(patterns=") + pos = _dump_list(self.patterns, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchMapping Node +# ============================================================ + +class MatchMapping(AST): + """MatchMapping(keys: list[AST | t.CPtr], patterns: list[AST | t.CPtr], rest: str)""" + keys: list[AST | t.CPtr] | t.CPtr + patterns: list[AST | t.CPtr] | t.CPtr + rest: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, + keys: list[AST | t.CPtr] | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr, + rest: str): + ptr: MatchMapping | t.CPtr = pool.alloc(MatchMapping.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchMapping.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + keys: list[AST | t.CPtr] | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr, + rest: str): + _init_ast(self, pool, 0, 0) + self.keys = keys + self.patterns = patterns + self.rest = _copy_str(pool, rest) + _set_parent_list(keys, self) + _set_parent_list(patterns, self) + + def kind(self) -> t.CInt: + return ASTKind.MatchMapping + + def type_name(self) -> str: + return "MatchMapping" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchMapping(keys=") + pos = _dump_list(self.keys, buf, size, pos) + pos = _emit(buf, size, pos, ", patterns=") + pos = _dump_list(self.patterns, buf, size, pos) + pos = _emit(buf, size, pos, ", rest='") + pos = _emit_str(buf, size, pos, self.rest) + pos = _emit(buf, size, pos, "')") + return pos + + +# ============================================================ +# MatchClass Node +# ============================================================ + +class MatchClass(AST): + """MatchClass(cls: AST, patterns: list[AST | t.CPtr], + kwd_attrs: list[AST | t.CPtr], kwd_patterns: list[AST | t.CPtr])""" + cls: AST | t.CPtr + patterns: list[AST | t.CPtr] | t.CPtr + kwd_attrs: list[AST | t.CPtr] | t.CPtr + kwd_patterns: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + cls: AST | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr, + kwd_attrs: list[AST | t.CPtr] | t.CPtr, + kwd_patterns: list[AST | t.CPtr] | t.CPtr): + ptr: MatchClass | t.CPtr = pool.alloc(MatchClass.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchClass.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + cls: AST | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr, + kwd_attrs: list[AST | t.CPtr] | t.CPtr, + kwd_patterns: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.cls = cls + self.patterns = patterns + self.kwd_attrs = kwd_attrs + self.kwd_patterns = kwd_patterns + _set_parent_list(patterns, self) + _set_parent_list(kwd_attrs, self) + _set_parent_list(kwd_patterns, self) + + def kind(self) -> t.CInt: + return ASTKind.MatchClass + + def type_name(self) -> str: + return "MatchClass" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchClass(cls=") + if self.cls is not None: + pos = self.cls.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", patterns=") + pos = _dump_list(self.patterns, buf, size, pos) + pos = _emit(buf, size, pos, ", kwd_attrs=") + pos = _dump_list(self.kwd_attrs, buf, size, pos) + pos = _emit(buf, size, pos, ", kwd_patterns=") + pos = _dump_list(self.kwd_patterns, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# MatchStar Node +# ============================================================ + +class MatchStar(AST): + """MatchStar(name: str)""" + name: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, name: str): + ptr: MatchStar | t.CPtr = pool.alloc(MatchStar.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchStar.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, name: str): + _init_ast(self, pool, 0, 0) + self.name = _copy_str(pool, name) + + def kind(self) -> t.CInt: + return ASTKind.MatchStar + + def type_name(self) -> str: + return "MatchStar" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchStar(name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "')") + return pos + + +# ============================================================ +# MatchAs Node +# ============================================================ + +class MatchAs(AST): + """MatchAs(pattern: AST, name: str)""" + pattern: AST | t.CPtr + name: str + + def __new__(self, pool: memhub.MemManager | t.CPtr, + pattern: AST | t.CPtr, name: str): + ptr: MatchAs | t.CPtr = pool.alloc(MatchAs.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchAs.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + pattern: AST | t.CPtr, name: str): + _init_ast(self, pool, 0, 0) + self.pattern = pattern + self.name = _copy_str(pool, name) + + def kind(self) -> t.CInt: + return ASTKind.MatchAs + + def type_name(self) -> str: + return "MatchAs" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchAs(pattern=") + if self.pattern is not None: + pos = self.pattern.dump(buf, size, pos) + pos = _emit(buf, size, pos, ", name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "')") + return pos + + +# ============================================================ +# MatchOr Node +# ============================================================ + +class MatchOr(AST): + """MatchOr(patterns: list[AST | t.CPtr])""" + patterns: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr): + ptr: MatchOr | t.CPtr = pool.alloc(MatchOr.__sizeof__()) + if ptr: + string.memset(ptr, 0, MatchOr.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + patterns: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.patterns = patterns + _set_parent_list(patterns, self) + + def kind(self) -> t.CInt: + return ASTKind.MatchOr + + def type_name(self) -> str: + return "MatchOr" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "MatchOr(patterns=") + pos = _dump_list(self.patterns, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos diff --git a/ast/parser.vp b/ast/parser.vp new file mode 100644 index 0000000..3f49e0e --- /dev/null +++ b/ast/parser.vp @@ -0,0 +1,2749 @@ +import t, c +from stdint import * +import memhub +import string +import stdio +import stdlib +from .tokens import (Token, TokenType, Keyword, TokOp) +from .base import ( + AST, ASTCtx, ASTKind, OpKind, ASTFlag, + _set_pos, _binop_from_op, _augop_from_op, _cmpop_from_op, _copy_str, _inherit_pos, + _init_ast, + CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR, + FLAG_IS_ASYNC, FLAG_IS_EXTERN, +) +from .exprs import ( + BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set, + ListComp, SetComp, DictComp, GeneratorExp, + Await, Yield, YieldFrom, FormattedValue, JoinedStr, + Constant, NamedExpr, Attribute, Subscript, Starred, Name, + List, Tuple, Slice, Call, Compare, OpNode, +) +from .stmts import ( + Module, Expression, Interactive, FunctionType, + FunctionDef, ClassDef, Return, Delete, Assign, AugAssign, AnnAssign, + For, While, If, With, Raise, Try, Assert, Global, Nonlocal, + Pass, Break, Continue, Expr, Import, ImportFrom, Match, +) +from .astaux import ( + ExceptHandler, Arguments, Arg, Keyword as KwNode, Alias, WithItem, Comprehension, +) +from .match import ( + MatchCase, MatchValue, MatchSingleton, MatchSequence, + MatchMapping, MatchClass, MatchStar, MatchAs, MatchOr, +) +from .lexer import Lexer, _lexer_init, tokenize, new_lexer + + +# ============================================================ +# Parser State +# ============================================================ +class Parser: + tokens: Token | t.CPtr # token linked list head + cur: Token | t.CPtr # current token + pool: memhub.MemManager | t.CPtr # memory pool + error_count: t.CInt # error count + pending_decorators: list[AST | t.CPtr] | t.CPtr # pending decorators list + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Parser | t.CPtr = pool.alloc(Parser.__sizeof__()) + if ptr: + string.memset(ptr, 0, Parser.__sizeof__()) + return ptr + + +def new_parser(pool: memhub.MemManager | t.CPtr) -> Parser | t.CPtr: + """Allocate from the pool and return the Parser (cross-module safe wrapper)""" + return Parser(pool) + + +def _parser_init(ps: Parser | t.CPtr, tokens: Token | t.CPtr, + pool: memhub.MemManager | t.CPtr): + if ps is None: return + ps.tokens = tokens + ps.cur = tokens + ps.pool = pool + ps.error_count = 0 + ps.pending_decorators = None + + +# ============================================================ +# Token Navigation Helpers +# ============================================================ + +def _advance(ps: Parser | t.CPtr): + """Advance to the next token""" + if ps.cur is None: return + if ps.cur.next is not None: + ps.cur = ps.cur.next + + +def _cur_type(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return TokenType.EndMarker + return ps.cur.type + + +def _cur_op(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return 0 + return ps.cur.op_subtype + + +def _cur_kw(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return 0 + return ps.cur.kw_subtype + + +def _is_funcdef_kw(ps: Parser | t.CPtr, kw: t.CInt) -> int: + """判断当前 token 是否为函数定义关键字(def 及其别名 fn/fun/func/function, + 以及 extern 声明关键字) + + def 是硬关键字直接判定;fn/fun/func/function/extern 是软关键字, + 仅当下一个 token 是 Name 且再下一个是 '('(或泛型 '[T]' 前的 '[')时 + 判定为函数定义。extern 还允许 'extern def A(...)' 形式(下一个是 def)。 + 否则按普通标识符处理,兼容既有代码把 func 用作 + 字段/参数名(如 AST 节点 func 字段、Call.func 注解 `func: AST | t.CPtr`)。 + """ + if kw == Keyword.Def: + return 1 + if kw == Keyword.Extern: + # extern def A(...) 或 extern A(...)(extern 后是 def 或 Name+'(/'[') + nxt: Token | t.CPtr = ps.cur.next + if nxt is None: + return 0 + if nxt.kw_subtype == Keyword.Def: + return 1 + if nxt.type != TokenType.Name: + return 0 + nxt2: Token | t.CPtr = nxt.next + if nxt2 is None: + return 0 + if nxt2.type == TokenType.Op \ + and (nxt2.op_subtype == TokOp.LPar or nxt2.op_subtype == TokOp.Lsqb): + return 1 + return 0 + if kw == Keyword.Fn or kw == Keyword.Fun \ + or kw == Keyword.Func or kw == Keyword.Function: + # 软关键字 lookahead: 下个是 Name,再下个是 '(' 或 '[T...]' 泛型参数(PEP 695) + nxt: Token | t.CPtr = ps.cur.next + if nxt is None: + return 0 + if nxt.type != TokenType.Name: + return 0 + nxt2: Token | t.CPtr = nxt.next + if nxt2 is None: + return 0 + if nxt2.type == TokenType.Op \ + and (nxt2.op_subtype == TokOp.LPar or nxt2.op_subtype == TokOp.Lsqb): + return 1 + return 0 + return 0 + + +def _is_match_stmt(ps: Parser | t.CPtr) -> int: + """match 是软关键字(CPython 3.10+):lookahead 判断是否为 match 语句 + + match 后直接跟 ':'(变量注解,如 lexer.vp 的 `match: t.CInt = 1`)、 + '='(赋值,如 `match = 0`)、换行/文件尾 → 按普通标识符; + 否则扫描至行尾,在括号深度 0 处出现 ':' → match 语句(subject 后必须冒号)。 + case/type 同理为软关键字(case 仅在 match 套件内消费,type 无语句分发)。 + """ + nxt: Token | t.CPtr = ps.cur.next + if nxt is None: + return 0 + if nxt.type == TokenType.NewLine or nxt.type == TokenType.EndMarker: + return 0 + if nxt.type == TokenType.Op: + if nxt.op_subtype == TokOp.Colon: + return 0 + if nxt.op_subtype == TokOp.Equal: + return 0 + walk: Token | t.CPtr = nxt + depth: t.CInt = 0 + while walk is not None: + if walk.type == TokenType.NewLine or walk.type == TokenType.EndMarker: + return 0 + if walk.type == TokenType.Op: + wop: t.CInt = walk.op_subtype + if wop == TokOp.LPar or wop == TokOp.Lsqb or wop == TokOp.LBrace: + depth += 1 + elif wop == TokOp.RPar or wop == TokOp.Rsqb or wop == TokOp.RBrace: + if depth > 0: + depth -= 1 + elif wop == TokOp.Colon and depth == 0: + return 1 + walk = walk.next + return 0 + + +# 解析错误位置与消息(fail-fast 仿 Python SyntaxError 报告,首次错误记录) +_g_parse_err_line: t.CInt = 0 +_g_parse_err_col: t.CInt = 0 +_g_parse_err_msg: str = None + + +def _record_parse_err(ps: Parser | t.CPtr): + """记录首个解析错误的位置与消息(只记录第一次,后续错误不覆盖)""" + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + if _g_parse_err_line != 0: + return + _g_parse_err_line = _cur_lineno(ps) + _g_parse_err_col = _cur_col(ps) + err_s: str = _cur_str(ps) + if err_s is None: + err_s = "(none)" + # 消息文本用 stdlib 拷贝(token 的 str_val 在 pool 中,生命周期覆盖本次编译但保险起见独立存储) + buf_m: str = stdlib.malloc(128) + if buf_m is not None: + stdio.snprintf(buf_m, 128, "意外的 token '%s'", err_s) + _g_parse_err_msg = buf_m + else: + _g_parse_err_msg = err_s + + +def get_parse_err_line() -> t.CInt: + """获取最近一次解析错误的行号(0=无错误)""" + return _g_parse_err_line + + +def get_parse_err_col() -> t.CInt: + """获取最近一次解析错误的列号(0=无错误)""" + return _g_parse_err_col + + +def get_parse_err_msg() -> str: + """获取最近一次解析错误的错误消息(仿 Python SyntaxError 消息文本)""" + return _g_parse_err_msg + + +def _cur_str(ps: Parser | t.CPtr) -> str: + if ps.cur is None: return None + return ps.cur.str_val + + +def _cur_lineno(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return 0 + return ps.cur.lineno + + +def _cur_col(ps: Parser | t.CPtr) -> t.CInt: + if ps.cur is None: return 0 + return ps.cur.col_offset + + +def _skip_nl(ps: Parser | t.CPtr): + """Skip TokenType.Nl token""" + while ps.cur is not None and ps.cur.type == TokenType.Nl: + ps.cur = ps.cur.next + + +def _skip_nls_and_newlines(ps: Parser | t.CPtr): + """Skip TokenType.Nl and TokenType.NewLine (used for line continuation)""" + while ps.cur is not None: + if ps.cur.type == TokenType.Nl or ps.cur.type == TokenType.NewLine: + ps.cur = ps.cur.next + else: + break + + +def _expect_type(ps: Parser | t.CPtr, ttype: t.CInt) -> t.CInt: + """Expect the current token to be of the specified type, advance and return 1, otherwise return 0""" + if _cur_type(ps) == ttype: + _advance(ps) + return 1 + _record_parse_err(ps) + ps.error_count += 1 + return 0 + + +def _expect_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt: + """Expecting the current one to be some operator""" + if _cur_type(ps) == TokenType.Op and _cur_op(ps) == op_id: + _advance(ps) + return 1 + _record_parse_err(ps) + ps.error_count += 1 + return 0 + + +def _match_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt: + """Check but not consume the current token""" + if _cur_type(ps) == TokenType.Op and _cur_op(ps) == op_id: + return 1 + return 0 + + +def _accept_op(ps: Parser | t.CPtr, op_id: t.CInt) -> t.CInt: + """If match, consume and return 1""" + if _match_op(ps, op_id): + _advance(ps) + return 1 + return 0 + + +# ============================================================ +# Constant Construction Helper (New API: Constant directly accepts lineno/col) +# ============================================================ + +def _new_const_int(pool: memhub.MemManager | t.CPtr, val: t.CInt64T, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + return Constant(pool, CONST_INT, val, 0.0, None, lineno, col) + + +def _new_const_float(pool: memhub.MemManager | t.CPtr, val: t.CDouble, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + global _g_dbg_pts, _g_dbg_vals, _g_dbg_cnt + new_c: Constant | t.CPtr = Constant(pool, CONST_FLOAT, 0, val, None, lineno, col) + # 把数字文本存到 str_val(stdlib 分配,绕开 pool 对 float_val 字段的覆写) + # REG-SRC 用 string.atof(str_val) 恢复原始值 + lit_txt: str = stdlib.malloc(64) + if lit_txt is not None: + stdio.snprintf(lit_txt, 64, "%.17g", val) + new_c.str_val = lit_txt + # 记录浮点节点 ptr→val 到 stdlib 表(构造时值正确,供 REG-SRC 查表绕开 pool 覆写) + # 表满时重置:旧记录对应已翻译完的文件,从当前节点重新记录 + if _g_dbg_pts is None: + _g_dbg_pts = stdlib.malloc(4096 * 8) + _g_dbg_vals = stdlib.malloc(4096 * 8) + _g_dbg_cnt = 0 + elif _g_dbg_cnt >= 4096: + _g_dbg_cnt = 0 + if _g_dbg_pts is not None and _g_dbg_vals is not None: + _g_dbg_pts[_g_dbg_cnt] = t.CUInt64T(new_c) + _g_dbg_vals[_g_dbg_cnt] = val + _g_dbg_cnt += 1 + return new_c + + +# 浮点节点构造值表(stdlib 分配,避免污染 pool) +_g_dbg_pts: t.CUInt64T | t.CPtr = None +_g_dbg_vals: t.CDouble | t.CPtr = None +_g_dbg_cnt: int = 0 +# 最近一次 _dbg_lookup_lit_val 是否命中 +_g_dbg_lit_found: int = 0 + + +def _dbg_lookup_lit_val(ptr: t.CUInt64T) -> double: + """查浮点节点构造值表:返回 ptr 节点的原始构造值(未命中返回 0 并置 found=0) + + 用于绕开 pool 分配对 AST float_val 字段的覆写(构造时值正确,读取时可能被覆写)。 + """ + global _g_dbg_lit_found + _g_dbg_lit_found = 0 + if _g_dbg_pts is None or _g_dbg_vals is None: + return 0.0 + i: t.CSizeT = 0 + while i < _g_dbg_cnt: + if _g_dbg_pts[i] == ptr: + _g_dbg_lit_found = 1 + return _g_dbg_vals[i] + i += 1 + return 0.0 + + +def _dbg_lit_found() -> int: + """检查最近一次 _dbg_lookup_lit_val 是否命中""" + return _g_dbg_lit_found + + +def _new_const_str(pool: memhub.MemManager | t.CPtr, val: str, + lineno: t.CInt, col: t.CInt, + is_dquote: t.CInt = 1, + is_triple: t.CInt = 0, + is_char: t.CInt = 0) -> AST | t.CPtr: + """Create a string/character constant node + + is_dquote: 0 = single quote, non-0 = double quote (default double quote) + is_triple: non-0 = triple-quoted string + is_char: non-0 = single-character candidate (lexer has confirmed that after escaping it's exactly 1 byte, including '0') + Semantic distinctions: + - 'x' (single quote, single character, not triple-quoted) → CONST_CHAR (i8 value) + - "x" (double quote, includes 0 terminator) → CONST_STR (i8* pointer, i8 x 2) + - 'ab' (single quotes, multiple characters) → CONST_STR (i8* pointer) + - '''x''' / \"\"\"x\"\"\" (triple quotes) → CONST_STR (i8* pointer) + - '' / "" (empty string) → CONST_STR (i8* pointer) + """ + # Single quotes, non-triple quotes, single-character candidates marked by lexer → CONST_CHAR + # Mark with is_char instead of strlen(val), because '0' becomes a NUL byte after escaping, strlen would return 0 + if is_dquote == 0 and is_triple == 0 and is_char != 0: + # Single quote # Single character → CONST_CHAR, int_val stores the character's ASCII value + # val[0] is a legal value of 0 even if it's NUL + ch_val: t.CInt64T = val[0] + return Constant(pool, CONST_CHAR, ch_val, 0.0, val, lineno, col) + # Other situations → CONST_STR + return Constant(pool, CONST_STR, 0, 0.0, val, lineno, col) + + +def _new_const_bool(pool: memhub.MemManager | t.CPtr, val: t.CInt, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + return Constant(pool, CONST_BOOL, val, 0.0, None, lineno, col) + + +def _new_const_none(pool: memhub.MemManager | t.CPtr, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + return Constant(pool, CONST_NONE, 0, 0.0, None, lineno, col) + + +# ============================================================ +# ctx Helper (Recursive Fixing Store Context) +# ============================================================ + +def _set_ctx(node: AST | t.CPtr, ctx: t.CInt): + """Set ctx field of node (based on kind conversion)""" + if node is None: return + k: t.CInt = node.kind() + if k == ASTKind.Name: + nm: Name | t.CPtr = (Name | t.CPtr)(node) + nm.ctx = ctx + elif k == ASTKind.Attribute: + at: Attribute | t.CPtr = (Attribute | t.CPtr)(node) + at.ctx = ctx + elif k == ASTKind.Subscript: + sb: Subscript | t.CPtr = (Subscript | t.CPtr)(node) + sb.ctx = ctx + elif k == ASTKind.Tuple: + tp: Tuple | t.CPtr = (Tuple | t.CPtr)(node) + tp.ctx = ctx + elif k == ASTKind.List: + ls: List | t.CPtr = (List | t.CPtr)(node) + ls.ctx = ctx + elif k == ASTKind.Starred: + st: Starred | t.CPtr = (Starred | t.CPtr)(node) + st.ctx = ctx + + +def _fix_store_ctx(node: AST | t.CPtr): + """Fix ctx of store targets to be Store""" + if node is None: return + _set_ctx(node, ASTCtx.Store) + k: t.CInt = node.kind() + if k == ASTKind.Tuple or k == ASTKind.List: + tp_elts: list[AST | t.CPtr] | t.CPtr = None + if k == ASTKind.Tuple: + tp: Tuple | t.CPtr = (Tuple | t.CPtr)(node) + tp_elts = tp.elts + else: + ls: List | t.CPtr = (List | t.CPtr)(node) + tp_elts = ls.elts + if tp_elts is not None: + n: t.CSizeT = tp_elts.__len__() + i: t.CSizeT = 0 + while i < n: + cur: AST | t.CPtr = tp_elts.get(i) + _fix_store_ctx(cur) + i += 1 + elif k == ASTKind.Starred: + st2: Starred | t.CPtr = (Starred | t.CPtr)(node) + _fix_store_ctx(st2.value) + + +# ============================================================ +# Expression Parser +# ============================================================ + +def _parse_expr(ps: Parser | t.CPtr) -> AST | t.CPtr: + """expr: yield_expr | namedexpr_test""" + if _cur_kw(ps) == Keyword.Yield: + return _parse_yield(ps) + return _parse_namedexpr(ps) + + +def _parse_namedexpr(ps: Parser | t.CPtr) -> AST | t.CPtr: + """namedexpr_test: test [':=' test]""" + left: AST | t.CPtr = _parse_test(ps) + if left is None: return None + if _match_op(ps, TokOp.ColonEq): + _advance(ps) + right: AST | t.CPtr = _parse_test(ps) + node: AST | t.CPtr = NamedExpr(ps.pool, left, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + return left + + +def _parse_test(ps: Parser | t.CPtr) -> AST | t.CPtr: + """test: or_test ['if' or_test 'else' test] | lambdef""" + if _cur_kw(ps) == Keyword.Lambda: + return _parse_lambda(ps) + left: AST | t.CPtr = _parse_or_test(ps) + if left is None: return None + if _cur_kw(ps) == Keyword.If: + _advance(ps) + test: AST | t.CPtr = _parse_or_test(ps) + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + orelse: AST | t.CPtr = _parse_test(ps) + node: AST | t.CPtr = IfExp(ps.pool, test, left, orelse) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + ps.error_count += 1 + return left + return left + + +def _parse_lambda(ps: Parser | t.CPtr) -> AST | t.CPtr: + """lambdef: 'lambda' [varargslist] ':' test""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # lambda + args: AST | t.CPtr = None + if not _match_op(ps, TokOp.Colon): + args = _parse_varargslist(ps, 1) + if not _expect_op(ps, TokOp.Colon): + return None + body: AST | t.CPtr = _parse_test(ps) + node: AST | t.CPtr = Lambda(ps.pool, args, body) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_or_test(ps: Parser | t.CPtr) -> AST | t.CPtr: + """or_test: and_test ('or' and_test)*""" + left: AST | t.CPtr = _parse_and_test(ps) + if left is None: return None + # 括号内行首 or((A\n or B)):or 前的 NL 在此跳过,否则 or_test 返回后 + # 上层 _expect_op(RPar) 遇到 or 报"意外的 token 'or'" + # (CallGenMixin.vp L7918 跨模块调用检查根因;ClassGenMixin L1988 等 + # 括号内换行行首 or 同理,按解析顺序未暴露)。 + _skip_nl(ps) + if _cur_kw(ps) == Keyword.Or: + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + values.append(left) + while _cur_kw(ps) == Keyword.Or: + _advance(ps) + _skip_nl(ps) # 括号内跨行: a or\n b + right: AST | t.CPtr = _parse_and_test(ps) + if right is None: break + values.append(right) + node: AST | t.CPtr = BoolOp(ps.pool, OpKind.Or, values) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + return left + + +def _parse_and_test(ps: Parser | t.CPtr) -> AST | t.CPtr: + """and_test: not_test ('and' not_test)*""" + left: AST | t.CPtr = _parse_not_test(ps) + if left is None: return None + # 括号内行首 and((A\n and B)):同 or_test 修复(or 前跳 NL) + _skip_nl(ps) + if _cur_kw(ps) == Keyword.And: + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + values.append(left) + while _cur_kw(ps) == Keyword.And: + _advance(ps) + _skip_nl(ps) # 括号内跨行: a and\n b + right: AST | t.CPtr = _parse_not_test(ps) + if right is None: break + values.append(right) + node: AST | t.CPtr = BoolOp(ps.pool, OpKind.And, values) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + return left + + +def _parse_not_test(ps: Parser | t.CPtr) -> AST | t.CPtr: + """not_test: 'not' not_test | comparison""" + if _cur_kw(ps) == Keyword.Not: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + operand: AST | t.CPtr = _parse_not_test(ps) + node: AST | t.CPtr = UnaryOp(ps.pool, OpKind.Not, operand) + _set_pos(node, lineno, col, 0, 0) + return node + return _parse_comparison(ps) + + +def _parse_comparison(ps: Parser | t.CPtr) -> AST | t.CPtr: + """comparison: bitor_expr (comp_op bitor_expr)* + + Single comparison design: a < b → Compare(left=a, op=Lt, right=b) + Chained comparison a < b < c → BoolOp(And, [Compare(a,<,b), Compare(b,<,c)]) + """ + left: AST | t.CPtr = _parse_bitor(ps) + if left is None: return None + + op_id: t.CInt = _match_comp_op(ps) + if op_id == OpKind.NoneOp: + return left + _advance_comp_op(ps) + _skip_nl(ps) # 括号内跨行: a ==\n b + right: AST | t.CPtr = _parse_bitor(ps) + # Single comparison: construct ops and comparators list + ops: list[t.CInt] | t.CPtr = list[t.CInt](ps.pool, 8) + ops.append(op_id) + comparators: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + comparators.append(right) + first_cmp: AST | t.CPtr = Compare(ps.pool, left, ops, comparators) + _set_pos(first_cmp, left.lineno, left.col_offset, 0, 0) + + # Check chained comparison + next_op: t.CInt = _match_comp_op(ps) + if next_op == OpKind.NoneOp: + return first_cmp + + # Single comparison with chained conditions: a < b < c → BoolOp(And, [Compare(a,<,b), Compare(b,<,c), ...]) + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + values.append(first_cmp) + cur_left: AST | t.CPtr = right + while next_op != OpKind.NoneOp: + _advance_comp_op(ps) + _skip_nl(ps) # 括号内跨行链式比较 + cur_right: AST | t.CPtr = _parse_bitor(ps) + ops2: list[t.CInt] | t.CPtr = list[t.CInt](ps.pool, 8) + ops2.append(next_op) + comparators2: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + comparators2.append(cur_right) + cmp: AST | t.CPtr = Compare(ps.pool, cur_left, ops2, comparators2) + _set_pos(cmp, cur_left.lineno, cur_left.col_offset, 0, 0) + values.append(cmp) + cur_left = cur_right + next_op = _match_comp_op(ps) + node: AST | t.CPtr = BoolOp(ps.pool, OpKind.And, values) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + return node + + +def _match_comp_op(ps: Parser | t.CPtr) -> t.CInt: + """Check if the current one is a comparison operator, return OP_* or OpKind.NoneOp""" + if _cur_type(ps) == TokenType.Op: + op_id: t.CInt = _cur_op(ps) + if op_id == TokOp.EqEq: return OpKind.Eq + if op_id == TokOp.ExclaimEq: return OpKind.Ne + if op_id == TokOp.Less: return OpKind.Lt + if op_id == TokOp.LessEq: return OpKind.Le + if op_id == TokOp.Greater: return OpKind.Gt + if op_id == TokOp.GreaterEq: return OpKind.Ge + if _cur_kw(ps) == Keyword.Is: + if ps.cur.next is not None and ps.cur.next.type == TokenType.Name and ps.cur.next.kw_subtype == Keyword.Not: + return OpKind.IsNot + return OpKind.Is + if _cur_kw(ps) == Keyword.Not: + if ps.cur.next is not None and ps.cur.next.kw_subtype == Keyword.In: + return OpKind.NotIn + if _cur_kw(ps) == Keyword.In: + return OpKind.In + return OpKind.NoneOp + + +def _advance_comp_op(ps: Parser | t.CPtr): + """Consume comparison operator token""" + if _cur_type(ps) == TokenType.Op: + _advance(ps) + return + if _cur_kw(ps) == Keyword.Is: + _advance(ps) + if _cur_kw(ps) == Keyword.Not: + _advance(ps) + return + if _cur_kw(ps) == Keyword.Not: + _advance(ps) + if _cur_kw(ps) == Keyword.In: + _advance(ps) + return + if _cur_kw(ps) == Keyword.In: + _advance(ps) + + +def _parse_bitor(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_bitxor(ps) + if left is None: return None + while _match_op(ps, TokOp.VBar): + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_bitxor(ps) + node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitOr, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_bitxor(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_bitand(ps) + if left is None: return None + while _match_op(ps, TokOp.Caret): + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_bitand(ps) + node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitXor, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_bitand(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_shift(ps) + if left is None: return None + while _match_op(ps, TokOp.Amp): + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_shift(ps) + node: AST | t.CPtr = BinOp(ps.pool, left, OpKind.BitAnd, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_shift(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_arith(ps) + if left is None: return None + while _match_op(ps, TokOp.LtLt) or _match_op(ps, TokOp.GtGt): + op_token: t.CInt = _cur_op(ps) + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_arith(ps) + ast_op: t.CInt = OpKind.LShift + if op_token == TokOp.GtGt: + ast_op = OpKind.RShift + node: AST | t.CPtr = BinOp(ps.pool, left, ast_op, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_arith(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_term(ps) + if left is None: return None + while _match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus): + op_token: t.CInt = _cur_op(ps) + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_term(ps) + ast_op: t.CInt = OpKind.Add + if op_token == TokOp.Minus: + ast_op = OpKind.Sub + node: AST | t.CPtr = BinOp(ps.pool, left, ast_op, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_term(ps: Parser | t.CPtr) -> AST | t.CPtr: + left: AST | t.CPtr = _parse_factor(ps) + if left is None: return None + while True: + op_token: t.CInt = 0 + if _match_op(ps, TokOp.Star): op_token = TokOp.Star + elif _match_op(ps, TokOp.Slash): op_token = TokOp.Slash + elif _match_op(ps, TokOp.DSlash): op_token = TokOp.DSlash + elif _match_op(ps, TokOp.Percent): op_token = TokOp.Percent + elif _match_op(ps, TokOp.At): op_token = TokOp.At + if op_token == 0: break + _advance(ps) + _skip_nl(ps) + right: AST | t.CPtr = _parse_factor(ps) + ast_op: t.CInt = _binop_from_op(op_token) + node: AST | t.CPtr = BinOp(ps.pool, left, ast_op, right) + _set_pos(node, left.lineno, left.col_offset, 0, 0) + left = node + return left + + +def _parse_factor(ps: Parser | t.CPtr) -> AST | t.CPtr: + """factor: '+' factor | '-' factor | '~' factor | power""" + if _match_op(ps, TokOp.Plus) or _match_op(ps, TokOp.Minus) or _match_op(ps, TokOp.Tilde): + op_token: t.CInt = _cur_op(ps) + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + operand: AST | t.CPtr = _parse_factor(ps) + ast_op: t.CInt = OpKind.UAdd + if op_token == TokOp.Minus: + ast_op = OpKind.USub + elif op_token == TokOp.Tilde: + ast_op = OpKind.Invert + node: AST | t.CPtr = UnaryOp(ps.pool, ast_op, operand) + _set_pos(node, lineno, col, 0, 0) + return node + return _parse_power(ps) + + +def _parse_power(ps: Parser | t.CPtr) -> AST | t.CPtr: + """power: await_expr ['**' factor] | atom_expr ['**' factor]""" + base: AST | t.CPtr = _parse_atom_expr(ps) + if base is None: return None + if _match_op(ps, TokOp.StarStar): + _advance(ps) + exp: AST | t.CPtr = _parse_factor(ps) + node: AST | t.CPtr = BinOp(ps.pool, base, OpKind.Pow, exp) + _set_pos(node, base.lineno, base.col_offset, 0, 0) + return node + return base + + +def _parse_atom_expr(ps: Parser | t.CPtr) -> AST | t.CPtr: + """atom_expr: ['await'] atom trailer*""" + if _cur_kw(ps) == Keyword.Await: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + inner: AST | t.CPtr = _parse_atom_expr(ps) + node: AST | t.CPtr = Await(ps.pool, inner) + _set_pos(node, lineno, col, 0, 0) + return node + base: AST | t.CPtr = _parse_atom(ps) + if base is None: return None + # trailer loop + while True: + if _match_op(ps, TokOp.Dot): + _advance(ps) + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + break + attr_name: str = _cur_str(ps) + attr_lineno: t.CInt = _cur_lineno(ps) + attr_col: t.CInt = _cur_col(ps) + _advance(ps) + ctx: t.CInt = ASTCtx.Load + if _match_op(ps, TokOp.Equal): + ctx = ASTCtx.Store + elif _match_op(ps, TokOp.PlusEq) or _match_op(ps, TokOp.MinusEq): + ctx = ASTCtx.Store + base = Attribute(ps.pool, base, attr_name, ctx) + _set_pos(base, attr_lineno, attr_col, 0, 0) + elif _match_op(ps, TokOp.LPar): + base = _parse_call(ps, base) + elif _match_op(ps, TokOp.Lsqb): + base = _parse_subscript(ps, base) + else: + break + return base + + +def _parse_call(ps: Parser | t.CPtr, func: AST | t.CPtr) -> AST | t.CPtr: + """Parse function call trailer. Both args and keywords are lists.""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # ( + _skip_nls_and_newlines(ps) # Skip the line break after '(' + args: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + keywords: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + + if not _match_op(ps, TokOp.RPar): + while True: + # **expr + if _match_op(ps, TokOp.StarStar): + _advance(ps) + _skip_nls_and_newlines(ps) + val: AST | t.CPtr = _parse_expr(ps) + kw: AST | t.CPtr = KwNode(ps.pool, None, val) + _set_pos(kw, _cur_lineno(ps), _cur_col(ps), 0, 0) + keywords.append(kw) + # *expr + elif _match_op(ps, TokOp.Star): + _advance(ps) + _skip_nls_and_newlines(ps) + val = _parse_expr(ps) + star: AST | t.CPtr = Starred(ps.pool, val, ASTCtx.Load) + _set_pos(star, val.lineno, val.col_offset, 0, 0) + args.append(star) + # keyword = expr + elif _cur_type(ps) == TokenType.Name: + if ps.cur.next is not None and ps.cur.next.type == TokenType.Op and ps.cur.next.op_subtype == TokOp.Equal: + kw_name: str = _cur_str(ps) + kw_lineno: t.CInt = _cur_lineno(ps) + kw_col: t.CInt = _cur_col(ps) + _advance(ps) # name + _advance(ps) # = + _skip_nls_and_newlines(ps) + val = _parse_expr(ps) + kw = KwNode(ps.pool, kw_name, val) + _set_pos(kw, kw_lineno, kw_col, 0, 0) + keywords.append(kw) + else: + val = _parse_expr(ps) + args.append(val) + else: + val = _parse_expr(ps) + args.append(val) + _skip_nls_and_newlines(ps) # Skip the line break after the parameter + if not _accept_op(ps, TokOp.Comma): + break + _skip_nls_and_newlines(ps) # Skip the line break after the comma + _skip_nls_and_newlines(ps) # Skip the line break before ')' + _expect_op(ps, TokOp.RPar) + node: AST | t.CPtr = Call(ps.pool, func, args, keywords) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_subscript(ps: Parser | t.CPtr, value: AST | t.CPtr) -> AST | t.CPtr: + """Parse subscript trailer.""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # [ + _skip_nl(ps) + slice_node: AST | t.CPtr = _parse_slice(ps) + _expect_op(ps, TokOp.Rsqb) + ctx: t.CInt = ASTCtx.Load + if _match_op(ps, TokOp.Equal): + ctx = ASTCtx.Store + node: AST | t.CPtr = Subscript(ps.pool, value, slice_node, ctx) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_slice(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parse slice: [expr] ':' [expr] [':' [expr]] | expr | expr, expr, ...""" + lower: AST | t.CPtr = None + if not _match_op(ps, TokOp.Colon): + lower = _parse_expr(ps) + + # Check if there’s a comma (tuple syntax: a[x, y, ...]) + if _match_op(ps, TokOp.Comma): + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + if lower is not None: + elts.append(lower) + while _accept_op(ps, TokOp.Comma): + if _match_op(ps, TokOp.Rsqb): + break # Trailing comma + elem: AST | t.CPtr = _parse_expr(ps) + if elem is not None: + elts.append(elem) + lineno: t.CInt = 0 + if lower is not None: + lineno = lower.lineno + node: AST | t.CPtr = Tuple(ps.pool, elts, ASTCtx.Load) + _set_pos(node, lineno, 0, 0, 0) + return node + + if _match_op(ps, TokOp.Colon): + _advance(ps) + upper: AST | t.CPtr = None + if not _match_op(ps, TokOp.Colon) and not _match_op(ps, TokOp.Rsqb): + upper = _parse_expr(ps) + step: AST | t.CPtr = None + if _accept_op(ps, TokOp.Colon): + if not _match_op(ps, TokOp.Rsqb): + step = _parse_expr(ps) + lineno: t.CInt = 0 + if lower is not None: + lineno = lower.lineno + elif upper is not None: + lineno = upper.lineno + else: + lineno = _cur_lineno(ps) + node: AST | t.CPtr = Slice(ps.pool, lower, upper, step) + _set_pos(node, lineno, 0, 0, 0) + return node + return lower + + +def _parse_atom(ps: Parser | t.CPtr) -> AST | t.CPtr: + """atom: the smallest unit of expression""" + ttype: t.CInt = _cur_type(ps) + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + + if ttype == TokenType.Name: + kw: t.CInt = _cur_kw(ps) + if kw == Keyword.True_: + _advance(ps) + return _new_const_bool(ps.pool, 1, lineno, col) + if kw == Keyword.False_: + _advance(ps) + return _new_const_bool(ps.pool, 0, lineno, col) + if kw == Keyword.None_: + _advance(ps) + return _new_const_none(ps.pool, lineno, col) + name_str: str = _cur_str(ps) + _advance(ps) + node: AST | t.CPtr = Name(ps.pool, name_str, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + + if ttype == TokenType.Number: + tok: Token | t.CPtr = ps.cur + _advance(ps) + if tok.is_float: + return _new_const_float(ps.pool, tok.float_val, lineno, col) + return _new_const_int(ps.pool, tok.int_val, lineno, col) + + if ttype == TokenType.String: + sval: str = _cur_str(ps) + is_fstr: t.CInt = ps.cur.kw_subtype & 4 + is_triple: t.CInt = ps.cur.kw_subtype & 8 + is_dquote: t.CInt = ps.cur.kw_subtype & 16 + is_char: t.CInt = ps.cur.kw_subtype & 32 + _advance(ps) + node: AST | t.CPtr + if is_fstr: + node = _parse_fstring(ps, sval, lineno, col) + else: + node = _new_const_str(ps.pool, sval, lineno, col, is_dquote, is_triple, is_char) + # Python 相邻字符串字面量隐式拼接:"a" "b" → "ab" + # Nl 是括号内换行 token(允许括号内跨行拼接);语句级换行是 NewLine,不跳过 + while True: + _skip_nl(ps) + if _cur_type(ps) != TokenType.String: + break + n_sval: str = _cur_str(ps) + n_fstr: t.CInt = ps.cur.kw_subtype & 4 + n_triple: t.CInt = ps.cur.kw_subtype & 8 + n_dquote: t.CInt = ps.cur.kw_subtype & 16 + n_char: t.CInt = ps.cur.kw_subtype & 32 + _advance(ps) + n_node: AST | t.CPtr + if n_fstr: + n_node = _parse_fstring(ps, n_sval, lineno, col) + else: + n_node = _new_const_str(ps.pool, n_sval, lineno, col, n_dquote, n_triple, n_char) + node = _concat_str_nodes(ps.pool, node, n_node) + return node + + if _match_op(ps, TokOp.Ellipsis): + _advance(ps) + return _new_const_none(ps.pool, lineno, col) + + if _match_op(ps, TokOp.LPar): + return _parse_paren(ps) + if _match_op(ps, TokOp.Lsqb): + return _parse_list(ps) + if _match_op(ps, TokOp.LBrace): + return _parse_brace(ps) + + ps.error_count += 1 + return None + + +def _parse_paren(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parenthesis expressions: () | (expr) | (expr,) | (expr, ...) | (yield)""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # ( + _skip_nl(ps) # Skip the line break after '(' (multi-line tuple) + if _match_op(ps, TokOp.RPar): + _advance(ps) + # Empty tuple + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: AST | t.CPtr = Tuple(ps.pool, empty, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + # yield + if _cur_kw(ps) == Keyword.Yield: + y: AST | t.CPtr = _parse_yield(ps) + _expect_op(ps, TokOp.RPar) + return y + first: AST | t.CPtr = _parse_expr(ps) + if _match_op(ps, TokOp.Comma): + # Tuple + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) + if _match_op(ps, TokOp.RPar): + break + e: AST | t.CPtr = _parse_expr(ps) + elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾(多行元组) + _expect_op(ps, TokOp.RPar) + node = Tuple(ps.pool, elts, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + _skip_nl(ps) # (expr\n) 单表达式括号跨行收尾 + _expect_op(ps, TokOp.RPar) + # Check for generator expression + if _cur_kw(ps) == Keyword.For: + return _parse_comprehension(ps, first, ASTKind.GeneratorExp, lineno, col) + return first + + +def _parse_list(ps: Parser | t.CPtr) -> AST | t.CPtr: + """List expressions: [] | [expr_list] | [expr_list comp_for]""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # [ + _skip_nl(ps) # Skip the line break after '[' (multi-line list) + if _match_op(ps, TokOp.Rsqb): + _advance(ps) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: AST | t.CPtr = List(ps.pool, empty, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + first: AST | t.CPtr = _parse_expr(ps) + if _cur_kw(ps) == Keyword.For: + node = _parse_comprehension(ps, first, ASTKind.ListComp, lineno, col) + _expect_op(ps, TokOp.Rsqb) + return node + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) + if _match_op(ps, TokOp.Rsqb): + break + e: AST | t.CPtr = _parse_expr(ps) + elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾(base64.vp 多行列表) + _expect_op(ps, TokOp.Rsqb) + node = List(ps.pool, elts, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_brace(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Brace expressions: {} | {set_items} | {dict_items} | {comp_for}""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # { + _skip_nl(ps) # Skip the line break after '{' (multi-line dict) + if _match_op(ps, TokOp.RBrace): + _advance(ps) + empty_k: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + empty_v: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: AST | t.CPtr = Dict(ps.pool, empty_k, empty_v) + _set_pos(node, lineno, col, 0, 0) + return node + first: AST | t.CPtr = _parse_expr(ps) + # dict: key: value + if _match_op(ps, TokOp.Colon): + _advance(ps) + val: AST | t.CPtr = _parse_expr(ps) + if _cur_kw(ps) == Keyword.For: + # dict comprehension + gens: list[AST | t.CPtr] | t.CPtr = _parse_comp_for(ps) + node = DictComp(ps.pool, first, val, gens) + _set_pos(node, lineno, col, 0, 0) + _expect_op(ps, TokOp.RBrace) + return node + keys: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + keys.append(first) + values.append(val) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) + if _match_op(ps, TokOp.RBrace): + break + k: AST | t.CPtr = _parse_expr(ps) + _expect_op(ps, TokOp.Colon) + v: AST | t.CPtr = _parse_expr(ps) + keys.append(k) + values.append(v) + _skip_nl(ps) # 末元素无尾逗号时收尾 + _expect_op(ps, TokOp.RBrace) + node = Dict(ps.pool, keys, values) + _set_pos(node, lineno, col, 0, 0) + return node + # set + if _cur_kw(ps) == Keyword.For: + node = _parse_comprehension(ps, first, ASTKind.SetComp, lineno, col) + _expect_op(ps, TokOp.RBrace) + return node + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) # 括号内跨行集合字面量 + if _match_op(ps, TokOp.RBrace): + break + e: AST | t.CPtr = _parse_expr(ps) + elts.append(e) + _skip_nl(ps) # 末元素无尾逗号时收尾 + _expect_op(ps, TokOp.RBrace) + node = Set(ps.pool, elts) + _set_pos(node, lineno, col, 0, 0) + return node + + +# ============================================================ +# f-string parsing +# ============================================================ + +def _parse_sub_expr(ps: Parser | t.CPtr, src: str) -> AST | t.CPtr: + """Create a sub-lexer and parser to parse expressions (used for {expr} inside f-strings)""" + pool: memhub.MemManager | t.CPtr = ps.pool + lx: Lexer | t.CPtr = new_lexer(pool) + if lx is None: return None + _lexer_init(lx, src, pool) + tokens: Token | t.CPtr = tokenize(lx) + if tokens is None: return None + sub_ps: Parser | t.CPtr = new_parser(pool) + if sub_ps is None: return None + _parser_init(sub_ps, tokens, pool) + return _parse_test(sub_ps) + + +def _append_str_value(pool: memhub.MemManager | t.CPtr, + values: list[AST | t.CPtr] | t.CPtr, + node: AST | t.CPtr): + """将字符串节点展开加入 values(JoinedStr 展开其 values,其余直接追加)""" + if node is None: + return + if node.kind() == ASTKind.JoinedStr: + js_val: JoinedStr | t.CPtr = (JoinedStr | t.CPtr)(node) + if js_val.values is not None: + n_v: t.CSizeT = js_val.values.__len__() + i_v: t.CSizeT + for i_v in range(n_v): + values.append(js_val.values.get(i_v)) + else: + values.append(node) + + +def _concat_str_nodes(pool: memhub.MemManager | t.CPtr, + a: AST | t.CPtr, b: AST | t.CPtr) -> AST | t.CPtr: + """合并相邻字符串字面量节点(Python 隐式拼接 "a" "b" → "ab") + + 纯常量字符串直接拼接文本;涉及 f-string(JoinedStr/FormattedValue)时 + 合并到 JoinedStr 的 values 列表。 + """ + if a is None: + return b + if b is None: + return a + # 两个都是常量字符串 → 直接拼接文本 + if a.kind() == ASTKind.Constant and b.kind() == ASTKind.Constant: + ca_c: Constant | t.CPtr = (Constant | t.CPtr)(a) + cb_c: Constant | t.CPtr = (Constant | t.CPtr)(b) + if ca_c.const_kind == CONST_STR and cb_c.const_kind == CONST_STR \ + and ca_c.str_val is not None and cb_c.str_val is not None: + la_c: t.CSizeT = string.strlen(ca_c.str_val) + lb_c: t.CSizeT = string.strlen(cb_c.str_val) + buf_c: str = pool.alloc(la_c + lb_c + 1) + if buf_c is not None: + string.memcpy(buf_c, ca_c.str_val, la_c) + string.memcpy(buf_c + la_c, cb_c.str_val, lb_c + 1) + return _new_const_str(pool, buf_c, a.lineno, a.col_offset, 0, 0, 0) + # 涉及 f-string → 合并到 JoinedStr + values_c: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](pool, 8) + _append_str_value(pool, values_c, a) + _append_str_value(pool, values_c, b) + if values_c.__len__() == 1: + return values_c.get(0) + node_c: AST | t.CPtr = JoinedStr(pool, values_c) + _set_pos(node_c, a.lineno, a.col_offset, 0, 0) + return node_c + + +def _parse_fstring(ps: Parser | t.CPtr, content: str, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """Parse f-string content, building JoinedStr or FormattedValue nodes""" + pool: memhub.MemManager | t.CPtr = ps.pool + values: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](pool, 8) + i: t.CSizeT = 0 + content_len: t.CSizeT = string.strlen(content) + # Literal text buffer for f-string content + lit_buf: str = pool.alloc(content_len + 1) + if lit_buf is None: return None + lit_pos: t.CSizeT = 0 + + while i < content_len: + ch: t.CChar = content[i] + if ch == '{': + # {{ → Literal { + if i + 1 < content_len and content[i + 1] == '{': + lit_buf[lit_pos] = '{' + lit_pos += 1 + i += 2 + continue + # Refresh literal buffer + if lit_pos > 0: + lit_buf[lit_pos] = '\0' + lit_node: AST | t.CPtr = _new_const_str(pool, lit_buf, lineno, col) + values.append(lit_node) + lit_buf = pool.alloc(content_len + 1) + if lit_buf is None: break + lit_pos = 0 + # Find matching closing '}' while tracking nested '{}' and string literals inside the f-string + j: t.CSizeT = i + 1 + depth: t.CInt = 1 + conv_pos: t.CSizeT = 0 + fmt_pos: t.CSizeT = 0 + while j < content_len and depth > 0: + c: t.CChar = content[j] + if c == '{': + depth += 1 + elif c == '}': + depth -= 1 + if depth == 0: + break + elif depth == 1: + if c == '!' and conv_pos == 0 and fmt_pos == 0: + if j + 1 < content_len: + nc: t.CChar = content[j + 1] + if nc == 's' or nc == 'r' or nc == 'a': + if j + 2 < content_len: + after: t.CChar = content[j + 2] + if after == ':' or after == '}': + conv_pos = j + elif j + 2 == content_len: + conv_pos = j + elif c == ':' and fmt_pos == 0: + fmt_pos = j + j += 1 + if depth != 0: + ps.error_count += 1 + break + # Extract expression text + expr_end: t.CSizeT = j + if conv_pos > 0: + expr_end = conv_pos + elif fmt_pos > 0: + expr_end = fmt_pos + expr_len: t.CSizeT = expr_end - i - 1 + if expr_len == 0: + ps.error_count += 1 + i = j + 1 + continue + expr_buf: str = pool.alloc(expr_len + 1) + if expr_buf is None: break + string.memcpy(expr_buf, content + i + 1, expr_len) + expr_buf[expr_len] = '\0' + # Parse expression text + expr_node: AST | t.CPtr = _parse_sub_expr(ps, expr_buf) + # Conversion specifier + conversion: t.CInt = -1 + if conv_pos > 0: + conv_char: t.CChar = content[conv_pos + 1] + if conv_char == 's': + conversion = 115 + elif conv_char == 'r': + conversion = 114 + elif conv_char == 'a': + conversion = 97 + # Format specifier + format_spec: AST | t.CPtr = None + if fmt_pos > 0: + spec_len: t.CSizeT = j - fmt_pos - 1 + if spec_len > 0: + spec_buf: str = pool.alloc(spec_len + 1) + if spec_buf is not None: + string.memcpy(spec_buf, content + fmt_pos + 1, spec_len) + spec_buf[spec_len] = '\0' + format_spec = _new_const_str(pool, spec_buf, lineno, col) + fv: AST | t.CPtr = FormattedValue(pool, expr_node, conversion, format_spec) + _set_pos(fv, lineno, col, 0, 0) + values.append(fv) + i = j + 1 + elif ch == '}': + if i + 1 < content_len and content[i + 1] == '}': + lit_buf[lit_pos] = '}' + lit_pos += 1 + i += 2 + else: + ps.error_count += 1 + i += 1 + else: + lit_buf[lit_pos] = ch + lit_pos += 1 + i += 1 + + # Refresh remaining literal buffer + if lit_pos > 0: + lit_buf[lit_pos] = '\0' + lit_node2: AST | t.CPtr = _new_const_str(pool, lit_buf, lineno, col) + values.append(lit_node2) + + # If no content, return empty string + if values.__len__() == 0: + return _new_const_str(pool, "", lineno, col) + # If only one FormattedValue and no literal, return FormattedValue + if values.__len__() == 1: + first: AST | t.CPtr = values.get(0) + if first.kind() == ASTKind.FormattedValue: + return first + node: AST | t.CPtr = JoinedStr(pool, values) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_comprehension(ps: Parser | t.CPtr, elt: AST | t.CPtr, + vtype: t.CInt, lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """General comprehension: elt comp_for""" + gens: list[AST | t.CPtr] | t.CPtr = _parse_comp_for(ps) + node: AST | t.CPtr = None + if vtype == ASTKind.ListComp: + node = ListComp(ps.pool, elt, gens) + elif vtype == ASTKind.SetComp: + node = SetComp(ps.pool, elt, gens) + else: + node = GeneratorExp(ps.pool, elt, gens) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_comp_for(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr: + """comp_for: ['async'] 'for' exprlist 'in' or_test [comp_if] (comp_for)* + Returns generators list。""" + gens: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while True: + is_async: t.CInt = 0 + if _cur_kw(ps) == Keyword.Async: + is_async = 1 + _advance(ps) + if _cur_kw(ps) != Keyword.For: + break + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + target: AST | t.CPtr = _parse_target_list(ps) + if _cur_kw(ps) != Keyword.In: + ps.error_count += 1 + break + _advance(ps) + iter_: AST | t.CPtr = _parse_or_test(ps) + # Collect ifs to list + ifs: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while _cur_kw(ps) == Keyword.If: + _advance(ps) + cond: AST | t.CPtr = _parse_or_test(ps) + ifs.append(cond) + comp: AST | t.CPtr = Comprehension(ps.pool, target, iter_, ifs, is_async) + _set_pos(comp, lineno, col, 0, 0) + gens.append(comp) + return gens + + +def _parse_target_list(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parse assignment target list (comma-separated)""" + first: AST | t.CPtr = _parse_target(ps) + if _match_op(ps, TokOp.Comma): + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + if _cur_kw(ps) == Keyword.In: + break + e: AST | t.CPtr = _parse_target(ps) + elts.append(e) + node: AST | t.CPtr = Tuple(ps.pool, elts, ASTCtx.Store) + _set_pos(node, first.lineno, first.col_offset, 0, 0) + return node + return first + + +def _parse_target(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parse assignment target""" + if _match_op(ps, TokOp.Star): + _advance(ps) + inner: AST | t.CPtr = _parse_atom_expr(ps) + node: AST | t.CPtr = Starred(ps.pool, inner, ASTCtx.Store) + _set_pos(node, inner.lineno, inner.col_offset, 0, 0) + return node + if _match_op(ps, TokOp.LPar): + _advance(ps) + _skip_nl(ps) + t_: AST | t.CPtr = _parse_target_list(ps) + _skip_nl(ps) + _expect_op(ps, TokOp.RPar) + return t_ + if _match_op(ps, TokOp.Lsqb): + _advance(ps) + _skip_nl(ps) + first: AST | t.CPtr = _parse_target(ps) + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + while _accept_op(ps, TokOp.Comma): + _skip_nl(ps) + if _match_op(ps, TokOp.Rsqb): + break + e: AST | t.CPtr = _parse_target(ps) + elts.append(e) + _expect_op(ps, TokOp.Rsqb) + node = List(ps.pool, elts, ASTCtx.Store) + _set_pos(node, first.lineno, first.col_offset, 0, 0) + return node + # Normal atom_expr, ctx=Store + node = _parse_atom_expr(ps) + if node is not None: + _set_ctx(node, ASTCtx.Store) + return node + + +def _parse_yield(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # yield + if _cur_kw(ps) == Keyword.From: + _advance(ps) + val: AST | t.CPtr = _parse_expr(ps) + node: AST | t.CPtr = YieldFrom(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + val2: AST | t.CPtr = None + if not _match_op(ps, TokOp.RPar) and _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + if _cur_type(ps) == TokenType.Op and (_cur_op(ps) == TokOp.Comma or _cur_op(ps) == TokOp.Rsqb): + pass + else: + val2 = _parse_test(ps) + node = Yield(ps.pool, val2) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_varargslist(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CPtr: + """Parse function parameter list + New API: args/defaults/kw_defaults are lists, vararg/kwarg are fields.""" + args: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + vararg: AST | t.CPtr = None + kwarg: AST | t.CPtr = None + defaults: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + kw_defaults: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + + while True: + _skip_nl(ps) + if _match_op(ps, TokOp.RPar): + break + # *args 或 * (kwonly separated) + if _match_op(ps, TokOp.Star): + _advance(ps) + _skip_nl(ps) + if _cur_type(ps) == TokenType.Name: + vararg = _parse_arg_def(ps, is_lambda) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + continue + # **kwargs + if _match_op(ps, TokOp.StarStar): + _advance(ps) + _skip_nl(ps) + kwarg = _parse_arg_def(ps, is_lambda) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + continue + # / Delimiter (posonly end)— New API: posonly/regular are not distinguished + if _match_op(ps, TokOp.Slash): + _advance(ps) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + continue + # Normal parameter + a: AST | t.CPtr = _parse_arg_def(ps, is_lambda) + if a is None: break + args.append(a) + if _match_op(ps, TokOp.Equal): + _advance(ps) + d: AST | t.CPtr = _parse_test(ps) + defaults.append(d) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + return Arguments(ps.pool, args, vararg, kwarg, defaults, kw_defaults) + + +def _parse_arg_def(ps: Parser | t.CPtr, is_lambda: t.CInt = 0) -> AST | t.CPtr: + """arg: TokenType.Name [':' annotation]""" + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return None + name_str: str = _cur_str(ps) + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + annotation: AST | t.CPtr = None + if is_lambda == 0: + if _accept_op(ps, TokOp.Colon): + annotation = _parse_test(ps) + result: AST | t.CPtr = Arg(ps.pool, name_str, annotation) + _set_pos(result, lineno, col, 0, 0) + return result + + +# ============================================================ +# Statement parsing (Design: directly append to parent, do not return a list) +# ============================================================ + +def _parse_suite_into_children(ps: Parser | t.CPtr, parent: AST | t.CPtr): + """Parse statement suite, directly append to parent's children. + suite: TokenType.NewLine TokenType.Indent stmt+ TokenType.Dedent | simple_stmt""" + _skip_nl(ps) + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + _skip_nl(ps) + if _cur_type(ps) != TokenType.Indent: + ps.error_count += 1 + return + _advance(ps) + sidx: t.CInt = 0 + while _cur_type(ps) != TokenType.Dedent and _cur_type(ps) != TokenType.EndMarker: + sidx += 1 + # Decorator (class body methods can have decorators) + if _match_op(ps, TokOp.At): + ps.pending_decorators = _parse_decorators(ps) + before_cur: Token | t.CPtr = ps.cur + _parse_statement_into(ps, parent) + # Defensive: if parse did not advance token, force advance to avoid infinite loop + if ps.cur is before_cur: + ps.error_count += 1 + _advance(ps) + _skip_nl(ps) + _expect_type(ps, TokenType.Dedent) + return + # Single-line suite + _parse_simple_stmt_into(ps, parent) + + +def _parse_statement_into(ps: Parser | t.CPtr, parent: AST | t.CPtr): + """Parse statement (compound or simple), append to the parent.""" + ttype: t.CInt = _cur_type(ps) + kw: t.CInt = _cur_kw(ps) + if ttype == TokenType.Name: + if kw == Keyword.If or kw == Keyword.While or kw == Keyword.For or kw == Keyword.Try: + stmt: AST | t.CPtr = _parse_compound(ps) + if stmt is not None: + parent.append(stmt) + return + if kw == Keyword.With or _is_funcdef_kw(ps, kw) != 0 or kw == Keyword.Class: + stmt = _parse_compound(ps) + if stmt is not None: + parent.append(stmt) + return + if (kw == Keyword.Match and _is_match_stmt(ps) != 0) or kw == Keyword.Async: + stmt = _parse_compound(ps) + if stmt is not None: + parent.append(stmt) + return + _parse_simple_stmt_into(ps, parent) + + +def _parse_simple_stmt_into(ps: Parser | t.CPtr, parent: AST | t.CPtr): + """simple_stmt: small_stmt (';' small_stmt)* [';'] TokenType.NewLine""" + first: AST | t.CPtr = _parse_small_stmt(ps) + if first is not None: + parent.append(first) + while _accept_op(ps, TokOp.Semi): + if _cur_type(ps) == TokenType.NewLine or _cur_type(ps) == TokenType.EndMarker: + break + s: AST | t.CPtr = _parse_small_stmt(ps) + if s is None: break + parent.append(s) + # 先跳过 Nl(括号内换行,如多行函数调用参数间的换行,属合法 token) + _skip_nl(ps) + # 语句结束检查:simple_stmt 必须以换行/文件尾结束。 + # 残留 token(如相邻表达式 `func12344444 avg3(...)` 被静默拆成多条语句、 + # `def` 缺失的关键字函数定义残留)是语法错误(fail-fast),禁止静默, + # 并仿 Python 报告错误位置(SyntaxError at line/col)。 + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + _record_parse_err(ps) + err_str: str = _cur_str(ps) + if err_str is None: + err_str = "(none)" + # 定位:从链表头找 cur,记录前一个 token 与下一个 token 的上下文 + prev_tok: Token | t.CPtr = None + walk_tok: Token | t.CPtr = ps.tokens + while walk_tok is not None and walk_tok is not ps.cur: + prev_tok = walk_tok + walk_tok = walk_tok.next + pv_str: str = "(head)" + pv_line: t.CInt = 0 + pv_col: t.CInt = 0 + if prev_tok is not None: + pv_str = prev_tok.str_val + pv_line = prev_tok.lineno + pv_col = prev_tok.col_offset + nxt_tok: Token | t.CPtr = ps.cur.next + nxt_str: str = "(none)" + nxt_line: t.CInt = 0 + nxt_col: t.CInt = 0 + if nxt_tok is not None: + nxt_str = nxt_tok.str_val + nxt_line = nxt_tok.lineno + nxt_col = nxt_tok.col_offset + stdio.printf("[AST] SyntaxError: line %d col %d (end %d %d), 意外的 token '%s' (type=%d) | prev='%s' (line %d col %d) | next='%s' (line %d col %d)\n", + _g_parse_err_line, _g_parse_err_col, ps.cur.end_lineno, ps.cur.end_col_offset, + err_str, _cur_type(ps), + pv_str, pv_line, pv_col, + nxt_str, nxt_line, nxt_col) + ps.error_count += 1 + return + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + + +def _parse_small_stmt(ps: Parser | t.CPtr) -> AST | t.CPtr: + """small_stmt: various simple statements""" + kw: t.CInt = _cur_kw(ps) + if kw == Keyword.Pass: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + node: AST | t.CPtr = Pass(ps.pool) + _set_pos(node, lineno, col, 0, 0) + return node + if kw == Keyword.Break: + lineno = _cur_lineno(ps) + col = _cur_col(ps) + _advance(ps) + node = Break(ps.pool) + _set_pos(node, lineno, col, 0, 0) + return node + if kw == Keyword.Continue: + lineno = _cur_lineno(ps) + col = _cur_col(ps) + _advance(ps) + node = Continue(ps.pool) + _set_pos(node, lineno, col, 0, 0) + return node + if kw == Keyword.Return: + return _parse_return(ps) + if kw == Keyword.Raise: + return _parse_raise(ps) + if kw == Keyword.Global: + return _parse_global(ps) + if kw == Keyword.Nonlocal: + return _parse_nonlocal(ps) + if kw == Keyword.Import: + return _parse_import(ps) + if kw == Keyword.From: + return _parse_from_import(ps) + if kw == Keyword.Del: + return _parse_del(ps) + if kw == Keyword.Assert: + return _parse_assert(ps) + if kw == Keyword.Yield: + return _parse_expr_stmt(ps, _parse_yield(ps)) + # Expression statement / assignment / augassign / annassign + return _parse_expr_stmt(ps, None) + + +def _maybe_tuple(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr: + """If there is a comma after first, collect the comma-separated expressions into a Tuple.""" + if first is None: return None + if not _match_op(ps, TokOp.Comma): + return first + lineno: t.CInt = first.lineno + col: t.CInt = first.col_offset + elts: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elts.append(first) + _accept_op(ps, TokOp.Comma) + while True: + tt: t.CInt = _cur_type(ps) + if tt == TokenType.NewLine or tt == TokenType.EndMarker: + break + if tt == TokenType.Op: + op: t.CInt = _cur_op(ps) + if op == TokOp.Equal or op == TokOp.Semi: + break + e: AST | t.CPtr = _parse_expr(ps) + if e is None: break + elts.append(e) + if not _accept_op(ps, TokOp.Comma): + break + node: AST | t.CPtr = Tuple(ps.pool, elts, ASTCtx.Load) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_testlist(ps: Parser | t.CPtr) -> AST | t.CPtr: + """Parse a comma-separated list of expressions, if there’s more than one, form a tuple.""" + first: AST | t.CPtr = _parse_expr(ps) + return _maybe_tuple(ps, first) + + +def _parse_expr_stmt(ps: Parser | t.CPtr, first: AST | t.CPtr) -> AST | t.CPtr: + """Expression statement, handle assignment/augassign/annassign""" + if first is None: + first = _parse_testlist(ps) + else: + first = _maybe_tuple(ps, first) + if first is None: + return None + lineno: t.CInt = first.lineno + col: t.CInt = first.col_offset + # Assignment + if _match_op(ps, TokOp.Equal): + targets: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + targets.append(first) + _fix_store_ctx(first) + value: AST | t.CPtr = None + accept_result: t.CInt = _accept_op(ps, TokOp.Equal) + while accept_result: + v: AST | t.CPtr = _parse_testlist(ps) + if v is None: break + if value is not None: + targets.append(value) + _fix_store_ctx(value) + value = v + accept_result = _accept_op(ps, TokOp.Equal) + node: AST | t.CPtr = Assign(ps.pool, targets, value) + _set_pos(node, lineno, col, 0, 0) + return node + # augassign + if _cur_type(ps) == TokenType.Op: + op_id: t.CInt = _cur_op(ps) + aug_op: t.CInt = _augop_from_op(op_id) + if aug_op != OpKind.NoneOp: + _advance(ps) + value2: AST | t.CPtr = _parse_testlist(ps) + _fix_store_ctx(first) + node2: AST | t.CPtr = AugAssign(ps.pool, first, aug_op, value2) + _set_pos(node2, lineno, col, 0, 0) + return node2 + # annassign: target ':' annotation [= value] + if _match_op(ps, TokOp.Colon): + _advance(ps) + annotation: AST | t.CPtr = _parse_test(ps) + value3: AST | t.CPtr = None + if _accept_op(ps, TokOp.Equal): + value3 = _parse_testlist(ps) + if ps.pool is None: + return None + _fix_store_ctx(first) + if ps.pool is None: + return None + node3: AST | t.CPtr = AnnAssign(ps.pool, first, annotation, value3, 1) + _set_pos(node3, lineno, col, 0, 0) + return node3 + # Expression statement + node4: AST | t.CPtr = Expr(ps.pool, first) + _set_pos(node4, lineno, col, 0, 0) + return node4 + + +def _parse_return(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + val: AST | t.CPtr = None + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker and _cur_type(ps) != TokenType.Op: + val = _parse_testlist(ps) + elif _cur_type(ps) == TokenType.Op and _cur_op(ps) != TokOp.Semi: + val = _parse_testlist(ps) + node: AST | t.CPtr = Return(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_raise(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + exc: AST | t.CPtr = None + cause: AST | t.CPtr = None + if _cur_type(ps) != TokenType.NewLine and _cur_type(ps) != TokenType.EndMarker: + exc = _parse_test(ps) + if _cur_kw(ps) == Keyword.From: + _advance(ps) + cause = _parse_test(ps) + node: AST | t.CPtr = Raise(ps.pool, exc, cause) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_global(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + if _cur_type(ps) == TokenType.Name: + n: AST | t.CPtr = Name(ps.pool, _cur_str(ps), ASTCtx.Store) + _set_pos(n, _cur_lineno(ps), _cur_col(ps), 0, 0) + names.append(n) + _advance(ps) + while _accept_op(ps, TokOp.Comma): + if _cur_type(ps) != TokenType.Name: break + n = Name(ps.pool, _cur_str(ps), ASTCtx.Store) + _set_pos(n, _cur_lineno(ps), _cur_col(ps), 0, 0) + names.append(n) + _advance(ps) + node: AST | t.CPtr = Global(ps.pool, names) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_nonlocal(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + if _cur_type(ps) == TokenType.Name: + n: AST | t.CPtr = Name(ps.pool, _cur_str(ps), ASTCtx.Store) + _set_pos(n, _cur_lineno(ps), _cur_col(ps), 0, 0) + names.append(n) + _advance(ps) + while _accept_op(ps, TokOp.Comma): + if _cur_type(ps) != TokenType.Name: break + n = Name(ps.pool, _cur_str(ps), ASTCtx.Store) + _set_pos(n, _cur_lineno(ps), _cur_col(ps), 0, 0) + names.append(n) + _advance(ps) + node: AST | t.CPtr = Nonlocal(ps.pool, names) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_import(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + names: list[AST | t.CPtr] | t.CPtr = _parse_alias_list(ps) + node: AST | t.CPtr = Import(ps.pool, names) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_from_import(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + # Parse module (possibly with dots) + level: t.CInt = 0 + while _match_op(ps, TokOp.Dot): + level += 1 + _advance(ps) + while _match_op(ps, TokOp.Ellipsis): + level += 3 + _advance(ps) + module_name: str = None + # The token type for keywords (like import) is also Name, so they must be excluded using kw_subtype, + # otherwise the `import` in `from . import` would be mistakenly treated as a module_name. + # Note: only `import` itself should be excluded. Module names can be keywords (like in `from .match import ...`, + # where match is a Viper match statement keyword), requiring NotKeyword would cause + # `from .match import` to fail parsing and the dependency scan would miss that module. + if _cur_type(ps) == TokenType.Name and _cur_kw(ps) != Keyword.Import: + module_name = _cur_str(ps) + _advance(ps) + while _match_op(ps, TokOp.Dot): + _advance(ps) + if _cur_type(ps) == TokenType.Name and _cur_kw(ps) == Keyword.NotKeyword: + next_name: str = _cur_str(ps) + mlen: t.CInt = string.strlen(module_name) + nlen: t.CInt = string.strlen(next_name) + new_mod: str = ps.pool.alloc(mlen + 1 + nlen + 1) + if new_mod is not None: + string.strcpy(new_mod, module_name) + new_mod[mlen] = '.' + string.strcpy(new_mod + mlen + 1, next_name) + module_name = new_mod + _advance(ps) + if _cur_kw(ps) != Keyword.Import: + ps.error_count += 1 + return None + _advance(ps) + _skip_nl(ps) + # import * + if _match_op(ps, TokOp.Star): + _advance(ps) + star_alias: AST | t.CPtr = Alias(ps.pool, "*", None) + _set_pos(star_alias, lineno, col, 0, 0) + star_names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + star_names.append(star_alias) + node: AST | t.CPtr = ImportFrom(ps.pool, module_name, star_names, level) + _set_pos(node, lineno, col, 0, 0) + return node + # ( names ) or names + if _match_op(ps, TokOp.LPar): + _advance(ps) + _skip_nl(ps) + names: list[AST | t.CPtr] | t.CPtr = _parse_alias_list(ps) + _skip_nl(ps) + _expect_op(ps, TokOp.RPar) + else: + names = _parse_alias_list(ps) + node: AST | t.CPtr = ImportFrom(ps.pool, module_name, names, level) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_alias_list(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr: + """Parse alias list.""" + names: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while True: + if _cur_type(ps) != TokenType.Name: + break + name_str: str = _cur_str(ps) + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + # dotted name + while _match_op(ps, TokOp.Dot): + _advance(ps) + if _cur_type(ps) == TokenType.Name: + next_n: str = _cur_str(ps) + nmlen: t.CInt = string.strlen(name_str) + nxtlen: t.CInt = string.strlen(next_n) + new_name: str = ps.pool.alloc(nmlen + 1 + nxtlen + 1) + if new_name is not None: + string.strcpy(new_name, name_str) + new_name[nmlen] = '.' + string.strcpy(new_name + nmlen + 1, next_n) + name_str = new_name + _advance(ps) + asname: str = None + if _cur_kw(ps) == Keyword.As: + _advance(ps) + if _cur_type(ps) == TokenType.Name: + asname = _cur_str(ps) + _advance(ps) + a: AST | t.CPtr = Alias(ps.pool, name_str, asname) + _set_pos(a, lineno, col, 0, 0) + names.append(a) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) + return names + + +def _parse_del(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + targets: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while True: + t_: AST | t.CPtr = _parse_atom_expr(ps) + if t_ is None: break + _set_ctx(t_, ASTCtx.Del) + targets.append(t_) + if not _accept_op(ps, TokOp.Comma): + break + node: AST | t.CPtr = Delete(ps.pool, targets) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_assert(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + test: AST | t.CPtr = _parse_test(ps) + msg: AST | t.CPtr = None + if _accept_op(ps, TokOp.Comma): + msg = _parse_test(ps) + node: AST | t.CPtr = Assert(ps.pool, test, msg) + _set_pos(node, lineno, col, 0, 0) + return node + + +# ============================================================ +# Compound statements +# ============================================================ + +def _parse_compound(ps: Parser | t.CPtr) -> AST | t.CPtr: + kw: t.CInt = _cur_kw(ps) + if kw == Keyword.If: + return _parse_if(ps) + if kw == Keyword.While: + return _parse_while(ps) + if kw == Keyword.For: + return _parse_for(ps, 0) + if kw == Keyword.Try: + return _parse_try(ps) + if kw == Keyword.With: + return _parse_with(ps, 0) + if _is_funcdef_kw(ps, kw) != 0: + return _parse_funcdef(ps, 0) + if kw == Keyword.Class: + return _parse_classdef(ps) + if kw == Keyword.Async: + _advance(ps) + if _is_funcdef_kw(ps, _cur_kw(ps)) != 0: + return _parse_funcdef(ps, 1) + if _cur_kw(ps) == Keyword.For: + return _parse_for(ps, 1) + if _cur_kw(ps) == Keyword.With: + return _parse_with(ps, 1) + ps.error_count += 1 + return None + if kw == Keyword.Match and _is_match_stmt(ps) != 0: + return _parse_match(ps) + ps.error_count += 1 + return None + + +def _parse_if(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # if + test: AST | t.CPtr = _parse_test(ps) + _expect_op(ps, TokOp.Colon) + # First construct with empty orelse, then fill it in later + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: If | t.CPtr = If(ps.pool, test, empty) + _parse_suite_into_children(ps, node) + orelse: list[AST | t.CPtr] | t.CPtr = _parse_if_tail(ps) + node.orelse = orelse + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_if_tail(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr: + """Parse elif/else chain and return orelse list. + + elif: orelse = list containing single If node (nested) + else: orelse = statement list + """ + if _cur_kw(ps) == Keyword.Elif: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) + elif_test: AST | t.CPtr = _parse_test(ps) + _expect_op(ps, TokOp.Colon) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + elif_node: If | t.CPtr = If(ps.pool, elif_test, empty) + _parse_suite_into_children(ps, elif_node) + elif_orelse: list[AST | t.CPtr] | t.CPtr = _parse_if_tail(ps) + elif_node.orelse = elif_orelse + _set_pos(elif_node, lineno, col, 0, 0) + orelse: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + orelse.append(elif_node) + return orelse + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch) + return scratch.children + return list[AST | t.CPtr](ps.pool, 8) # 空 list + + +# ============================================================ +# Parsing Compound Statements (Continued) +# ============================================================ + +def _parse_while(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # while + test: AST | t.CPtr = _parse_test(ps) + _expect_op(ps, TokOp.Colon) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: While | t.CPtr = While(ps.pool, test, empty) + _parse_suite_into_children(ps, node) + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch) + node.orelse = scratch.children + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_for(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # for + target: AST | t.CPtr = _parse_target_list(ps) + if _cur_kw(ps) != Keyword.In: + ps.error_count += 1 + return None + _advance(ps) + iter_: AST | t.CPtr = _parse_or_test(ps) + _expect_op(ps, TokOp.Colon) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: For | t.CPtr = For(ps.pool, target, iter_, empty, is_async) + _fix_store_ctx(target) + _parse_suite_into_children(ps, node) + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch) + node.orelse = scratch.children + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_try(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # try + _expect_op(ps, TokOp.Colon) + empty: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: Try | t.CPtr = Try(ps.pool, empty, empty, empty) + _parse_suite_into_children(ps, node) + # handlers (except) + handlers: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while _cur_kw(ps) == Keyword.Except: + h: AST | t.CPtr = _parse_except_handler(ps) + if h is not None: + handlers.append(h) + node.handlers = handlers + # else + if _cur_kw(ps) == Keyword.Else: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch) + node.orelse = scratch.children + # finally + if _cur_kw(ps) == Keyword.Finally: + _advance(ps) + _expect_op(ps, TokOp.Colon) + scratch2: Module | t.CPtr = Module(ps.pool) + _parse_suite_into_children(ps, scratch2) + node.finalbody = scratch2.children + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_except_handler(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # except + type_: AST | t.CPtr = None + name: str = None + if _cur_op(ps) != TokOp.Colon: + type_ = _parse_test(ps) + if _cur_kw(ps) == Keyword.As: + _advance(ps) + if _cur_type(ps) == TokenType.Name: + name = _cur_str(ps) + _advance(ps) + _expect_op(ps, TokOp.Colon) + node: AST | t.CPtr = ExceptHandler(ps.pool, type_, name) + _parse_suite_into_children(ps, node) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_with(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # with + items: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + # items + while True: + item: AST | t.CPtr = _parse_with_item(ps) + if item is None: break + items.append(item) + if not _accept_op(ps, TokOp.Comma): + break + # Check if we can continue with a newline (with (...): form) + if _cur_type(ps) == TokenType.NewLine or _cur_type(ps) == TokenType.Nl: + break + _expect_op(ps, TokOp.Colon) + node: With | t.CPtr = With(ps.pool, items, is_async) + _parse_suite_into_children(ps, node) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_with_item(ps: Parser | t.CPtr) -> AST | t.CPtr: + """with_item: test ['as' expr]""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + context_expr: AST | t.CPtr = _parse_or_test(ps) + if context_expr is None: return None + optional_vars: AST | t.CPtr = None + if _cur_kw(ps) == Keyword.As: + _advance(ps) + optional_vars = _parse_target(ps) + _fix_store_ctx(optional_vars) + node: AST | t.CPtr = WithItem(ps.pool, context_expr, optional_vars) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_funcdef(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + is_extern_fd: t.CInt = 0 + if _cur_kw(ps) == Keyword.Extern: + # extern 声明:extern [def] A(...) [-> T] [": pass" 可选] + is_extern_fd = 1 + _advance(ps) # extern + if _cur_kw(ps) == Keyword.Def: + _advance(ps) + else: + _advance(ps) # def / fn / ... + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return None + name: str = _cur_str(ps) + _advance(ps) + # PEP 695 泛型函数类型参数: def add[T](a: T, b: T) — 解析并存入 type_params。 + # (与 class 解析器一致;之前缺失此处理导致 _expect_op(Colon) 失败、函数体被 + # 误提升到模块级——b = Box(42) 被当作模块级全局注册,函数内赋值误报 + # "需用 global 声明"。翻译时 type_params 映射到 int 兜底。) + type_params_fd: list[str] | t.CPtr = None + if _accept_op(ps, TokOp.Lsqb): + type_params_fd = list[str](ps.pool, 8) + while not _match_op(ps, TokOp.Rsqb): + if _cur_type(ps) == TokenType.EndMarker: + break + if _cur_type(ps) == TokenType.Name: + tp_name_fd: str = _cur_str(ps) + _advance(ps) + # 跳过可选 bound/约束: [T: bound] 或 [T: (A, B)] + if _match_op(ps, TokOp.Colon): + _advance(ps) + _parse_test(ps) + type_params_fd.append(tp_name_fd) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.Rsqb) + args: AST | t.CPtr = None + if _accept_op(ps, TokOp.LPar): + args = _parse_varargslist(ps, 0) + _expect_op(ps, TokOp.RPar) + returns: AST | t.CPtr = None + if _accept_op(ps, TokOp.RArrow): + returns = _parse_test(ps) + if is_extern_fd: + # extern 声明:返回注解改写为 <原类型> | t.State,复用既有 + # State/外部 C 函数识别路径(vpi 注解含 "State" → 定义端裸名 + 不生成函数体) + state_attr_fd: AST | t.CPtr = Attribute(ps.pool, + Name(ps.pool, "t", ASTCtx.Load), + "State", ASTCtx.Load) + if returns != None: + returns = BinOp(ps.pool, returns, OpKind.BitOr, state_attr_fd) + else: + returns = state_attr_fd + dec_list: list[AST | t.CPtr] | t.CPtr = ps.pending_decorators + ps.pending_decorators = None + node: FunctionDef | t.CPtr = FunctionDef(ps.pool, name, args, dec_list, returns, is_async, type_params_fd) + if is_extern_fd: + node.flags = node.flags | FLAG_IS_EXTERN + if is_extern_fd == 0 or _match_op(ps, TokOp.Colon): + _expect_op(ps, TokOp.Colon) + _parse_suite_into_children(ps, node) + # extern 无 ': pass' 形式(extern A(...) -> int):body 为空,仅声明 + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_classdef(ps: Parser | t.CPtr) -> AST | t.CPtr: + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # class + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return None + name: str = _cur_str(ps) + _advance(ps) + # Parse type parameters [T] or [T, U] (PEP 695 generic class syntax) + type_params: list[str] | t.CPtr = None + if _accept_op(ps, TokOp.Lsqb): + type_params = list[str](ps.pool, 8) + while not _match_op(ps, TokOp.Rsqb): + if _cur_type(ps) == TokenType.EndMarker: break + if _cur_type(ps) == TokenType.Name: + tp_name: str = _cur_str(ps) + _advance(ps) + # Skip optional bound/constraint: [T: bound] or [T: (A, B)] + if _match_op(ps, TokOp.Colon): + _advance(ps) + _parse_test(ps) + type_params.append(tp_name) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.Rsqb) + bases: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + keywords: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + # bases / keywords + if _accept_op(ps, TokOp.LPar): + while not _match_op(ps, TokOp.RPar): + # 基类括号内跨行(class X(A,\n B):):逗号后换行在此跳过, + # 否则 cur=NL 非 Name/Comma → break → _expect_op(RPar) 报 + # "意外的 token"(Generator.vp L34 多继承跨行根因) + _skip_nl(ps) + if _cur_type(ps) == TokenType.EndMarker: break + # base 或 keyword=value + if _cur_type(ps) == TokenType.Name: + # Parse as expression, if followed by '=', then as keyword=value + e: AST | t.CPtr = _parse_or_test(ps) + if _match_op(ps, TokOp.Equal): + _advance(ps) + v: AST | t.CPtr = _parse_test(ps) + kw_node: AST | t.CPtr = KwNode(ps.pool, e, v) + keywords.append(kw_node) + else: + bases.append(e) + if not _accept_op(ps, TokOp.Comma): + break + _skip_nl(ps) # 末基类后换行收尾(class X(A,\n B):) + _expect_op(ps, TokOp.RPar) + _expect_op(ps, TokOp.Colon) + dec_list: list[AST | t.CPtr] | t.CPtr = ps.pending_decorators + ps.pending_decorators = None + node: ClassDef | t.CPtr = ClassDef(ps.pool, name, bases, keywords, dec_list, type_params) + _parse_suite_into_children(ps, node) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_match(ps: Parser | t.CPtr) -> AST | t.CPtr: + """match statement: match subject ':' NewLine Indent case+ Dedent""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # match + subject: AST | t.CPtr = _parse_test(ps) + _expect_op(ps, TokOp.Colon) + cases: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + node: AST | t.CPtr = Match(ps.pool, subject, cases) + # Parsing body: Same NewLine/Indent/Dedent pattern as _parse_suite_into_children, + # but parses case clauses into a cases list instead of normal statements into children + _skip_nl(ps) + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + _skip_nl(ps) + if _cur_type(ps) == TokenType.Indent: + _advance(ps) + while _cur_type(ps) != TokenType.Dedent and _cur_type(ps) != TokenType.EndMarker: + if _cur_kw(ps) == Keyword.Case: + case_node: AST | t.CPtr = _parse_match_case(ps) + if case_node is not None: + cases.append(case_node) + else: + _advance(ps) # Skip non-case token to avoid infinite loop + _expect_type(ps, TokenType.Dedent) + _set_pos(node, lineno, col, 0, 0) + return node + + +# ============================================================ +# Match pattern parsing +# ============================================================ + +def _make_name_ast(pool: memhub.MemManager | t.CPtr, node: Name | t.CPtr) -> AST | t.CPtr: + # Analysis: "Convert Name* to AST* (Solving the TransPyC Type Inference Problem)" + return node + + +def _parse_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr: + """pattern: or_pattern ['as' NAME] + or_pattern: closed_pattern ('|' closed_pattern)*""" + pat: AST | t.CPtr = _parse_closed_pattern(ps) + if pat is None: return None + # OR pattern + if _match_op(ps, TokOp.VBar): + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + patterns.append(pat) + while _accept_op(ps, TokOp.VBar): + p: AST | t.CPtr = _parse_closed_pattern(ps) + if p is not None: + patterns.append(p) + or_node: AST | t.CPtr = MatchOr(ps.pool, patterns) + _set_pos(or_node, pat.lineno, pat.col_offset, 0, 0) + pat = or_node + # AS pattern + if _cur_kw(ps) == Keyword.As: + _advance(ps) + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + return pat + name_str: str = _cur_str(ps) + _advance(ps) + as_node: AST | t.CPtr = MatchAs(ps.pool, pat, name_str) + _set_pos(as_node, pat.lineno, pat.col_offset, 0, 0) + return as_node + return pat + + +def _parse_closed_pattern(ps: Parser | t.CPtr) -> AST | t.CPtr: + """closed_pattern: literal | capture | wildcard | value | group | sequence | mapping | class""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + ttype: t.CInt = _cur_type(ps) + val: AST | t.CPtr + node: AST | t.CPtr + tok: Token | t.CPtr + sval: str + + # Number literal pattern + if ttype == TokenType.Number: + tok = ps.cur + _advance(ps) + if tok.is_float: + val = _new_const_float(ps.pool, tok.float_val, lineno, col) + else: + val = _new_const_int(ps.pool, tok.int_val, lineno, col) + node = MatchValue(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + + # String literal pattern + if ttype == TokenType.String: + sval = _cur_str(ps) + is_dquote_m: t.CInt = ps.cur.kw_subtype & 16 + _advance(ps) + val = _new_const_str(ps.pool, sval, lineno, col, is_dquote_m) + node = MatchValue(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + + # Negative number literal pattern: -1, -1.5 + if _match_op(ps, TokOp.Minus): + _advance(ps) + if _cur_type(ps) == TokenType.Number: + tok = ps.cur + _advance(ps) + if tok.is_float: + val = _new_const_float(ps.pool, -tok.float_val, lineno, col) + else: + val = _new_const_int(ps.pool, -tok.int_val, lineno, col) + node = MatchValue(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + ps.error_count += 1 + return None + + # Name: None/True/False/_ /capture/value/class + if ttype == TokenType.Name: + kw: t.CInt = _cur_kw(ps) + # None/True/False → MatchSingleton + if kw == Keyword.None_ or kw == Keyword.True_ or kw == Keyword.False_: + _advance(ps) + if kw == Keyword.None_: + val = _new_const_none(ps.pool, lineno, col) + elif kw == Keyword.True_: + val = _new_const_bool(ps.pool, 1, lineno, col) + else: + val = _new_const_bool(ps.pool, 0, lineno, col) + node = MatchSingleton(ps.pool, val) + _set_pos(node, lineno, col, 0, 0) + return node + name_str: str = _cur_str(ps) + # Wildcard pattern: _ + if string.strcmp(name_str, "_") == 0: + _advance(ps) + node = MatchAs(ps.pool, None, None) + _set_pos(node, lineno, col, 0, 0) + return node + _advance(ps) + # Check dotted name(value pattern 或 class pattern) + if _match_op(ps, TokOp.Dot): + name_node: Name | t.CPtr = Name(ps.pool, name_str, ASTCtx.Load) + _set_pos(name_node, lineno, col, 0, 0) + base: AST | t.CPtr = _make_name_ast(ps.pool, name_node) + while _match_op(ps, TokOp.Dot): + _advance(ps) + if _cur_type(ps) != TokenType.Name: + ps.error_count += 1 + break + attr_name: str = _cur_str(ps) + attr_lineno: t.CInt = _cur_lineno(ps) + attr_col: t.CInt = _cur_col(ps) + _advance(ps) + base = Attribute(ps.pool, base, attr_name, ASTCtx.Load) + _set_pos(base, attr_lineno, attr_col, 0, 0) + # class pattern: dotted.name(...) + if _match_op(ps, TokOp.LPar): + return _parse_class_pattern(ps, base, lineno, col) + # value pattern: dotted.name + node = MatchValue(ps.pool, base) + _set_pos(node, lineno, col, 0, 0) + return node + # class pattern: Name(...) + if _match_op(ps, TokOp.LPar): + cls_node: Name | t.CPtr = Name(ps.pool, name_str, ASTCtx.Load) + _set_pos(cls_node, lineno, col, 0, 0) + cls: AST | t.CPtr = _make_name_ast(ps.pool, cls_node) + return _parse_class_pattern(ps, cls, lineno, col) + # capture pattern: NAME + node = MatchAs(ps.pool, None, name_str) + _set_pos(node, lineno, col, 0, 0) + return node + + # group pattern / sequence pattern (tuple): (...) + if _match_op(ps, TokOp.LPar): + _advance(ps) + inner: AST | t.CPtr = _parse_pattern(ps) + if _accept_op(ps, TokOp.Comma): + # sequence pattern (tuple) + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + if inner is not None: + patterns.append(inner) + while not _match_op(ps, TokOp.RPar) and _cur_type(ps) != TokenType.EndMarker: + p: AST | t.CPtr = _parse_pattern(ps) + if p is not None: + patterns.append(p) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.RPar) + node = MatchSequence(ps.pool, patterns) + _set_pos(node, lineno, col, 0, 0) + return node + _expect_op(ps, TokOp.RPar) + return inner # group pattern + + # sequence pattern (list): [...] + if _match_op(ps, TokOp.Lsqb): + return _parse_sequence_pattern(ps, TokOp.Rsqb, lineno, col) + + # mapping pattern: {...} + if _match_op(ps, TokOp.LBrace): + return _parse_mapping_pattern(ps, lineno, col) + + ps.error_count += 1 + return None + + +def _parse_sequence_pattern(ps: Parser | t.CPtr, close_op: t.CInt, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """sequence_pattern: '[' [pattern_list] ']'""" + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + _advance(ps) # [ + while not _match_op(ps, close_op) and _cur_type(ps) != TokenType.EndMarker: + # *name (star pattern) + if _match_op(ps, TokOp.Star): + _advance(ps) + if _cur_type(ps) == TokenType.Name: + star_name: str = _cur_str(ps) + _advance(ps) + star_node: AST | t.CPtr + if string.strcmp(star_name, "_") == 0: + star_node = MatchStar(ps.pool, None) + else: + star_node = MatchStar(ps.pool, star_name) + _set_pos(star_node, lineno, col, 0, 0) + patterns.append(star_node) + else: + p: AST | t.CPtr = _parse_pattern(ps) + if p is not None: + patterns.append(p) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, close_op) + node: AST | t.CPtr = MatchSequence(ps.pool, patterns) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_mapping_pattern(ps: Parser | t.CPtr, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """mapping_pattern: '{' [items] '}' + items: key ':' pattern (',' key ':' pattern)* [',' '**' NAME] | '**' NAME""" + keys: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + rest: str = None + node: AST | t.CPtr + key: AST | t.CPtr + val_pat: AST | t.CPtr + _advance(ps) # { + if _match_op(ps, TokOp.RBrace): + _advance(ps) + node = MatchMapping(ps.pool, keys, patterns, rest) + _set_pos(node, lineno, col, 0, 0) + return node + while _cur_type(ps) != TokenType.EndMarker: + if _match_op(ps, TokOp.StarStar): + _advance(ps) + if _cur_type(ps) == TokenType.Name: + rest = _cur_str(ps) + _advance(ps) + break + key = _parse_expr(ps) + _expect_op(ps, TokOp.Colon) + val_pat = _parse_pattern(ps) + if key is not None: + keys.append(key) + if val_pat is not None: + patterns.append(val_pat) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.RBrace) + node = MatchMapping(ps.pool, keys, patterns, rest) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_class_pattern(ps: Parser | t.CPtr, cls: AST | t.CPtr, + lineno: t.CInt, col: t.CInt) -> AST | t.CPtr: + """class_pattern: cls '(' [pattern_list] ')' + pattern_list: positional_pattern (',' positional_pattern)* + [',' keyword_pattern]* | keyword_pattern (',' keyword_pattern)* + keyword_pattern: NAME '=' pattern""" + patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + kwd_attrs: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + kwd_patterns: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + p: AST | t.CPtr + _advance(ps) # ( + if not _match_op(ps, TokOp.RPar): + while _cur_type(ps) != TokenType.EndMarker: + # keyword pattern: NAME '=' pattern + if _cur_type(ps) == TokenType.Name and ps.cur is not None: + nxt: Token | t.CPtr = ps.cur.next + if nxt is not None and nxt.type == TokenType.Op and nxt.op_subtype == TokOp.Equal: + attr_name: str = _cur_str(ps) + _advance(ps) # NAME + _advance(ps) # = + kwd_pat: AST | t.CPtr = _parse_pattern(ps) + attr_n: Name | t.CPtr = Name(ps.pool, attr_name, ASTCtx.Load) + _set_pos(attr_n, lineno, col, 0, 0) + attr_node: AST | t.CPtr = _make_name_ast(ps.pool, attr_n) + kwd_attrs.append(attr_node) + if kwd_pat is not None: + kwd_patterns.append(kwd_pat) + else: + p = _parse_pattern(ps) + if p is not None: + patterns.append(p) + else: + p = _parse_pattern(ps) + if p is not None: + patterns.append(p) + if not _accept_op(ps, TokOp.Comma): + break + _expect_op(ps, TokOp.RPar) + node: AST | t.CPtr = MatchClass(ps.pool, cls, patterns, kwd_attrs, kwd_patterns) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_match_case(ps: Parser | t.CPtr) -> AST | t.CPtr: + """case pattern [if guard] ':' suite""" + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # case + guard: AST | t.CPtr = None + pattern: AST | t.CPtr = _parse_pattern(ps) + if _cur_kw(ps) == Keyword.If: + _advance(ps) + guard = _parse_or_test(ps) + _expect_op(ps, TokOp.Colon) + node: AST | t.CPtr = MatchCase(ps.pool, pattern, guard) + _parse_suite_into_children(ps, node) + _set_pos(node, lineno, col, 0, 0) + return node + + +def _parse_decorators(ps: Parser | t.CPtr) -> list[AST | t.CPtr] | t.CPtr: + """解析装饰器链,返回 list。""" + decs: list[AST | t.CPtr] | t.CPtr = list[AST | t.CPtr](ps.pool, 8) + while _match_op(ps, TokOp.At): + lineno: t.CInt = _cur_lineno(ps) + col: t.CInt = _cur_col(ps) + _advance(ps) # @ + expr: AST | t.CPtr = _parse_namedexpr(ps) + _skip_nl(ps) + if _cur_type(ps) == TokenType.NewLine: + _advance(ps) + decs.append(expr) + return decs + + +# ============================================================ +# Module entry +# ============================================================ + +def _parse_module_body(ps: Parser | t.CPtr, module_node: AST | t.CPtr): + """解析模块体,append 到 module_node。""" + _skip_nl(ps) + stmt_idx: t.CInt = 0 + while _cur_type(ps) != TokenType.EndMarker: + stmt_idx += 1 + # Decorator + if _match_op(ps, TokOp.At): + ps.pending_decorators = _parse_decorators(ps) + # Record current token pointer to check for infinite loop + before_cur: Token | t.CPtr = ps.cur + _parse_statement_into(ps, module_node) + # Defense: If parsing doesn't advance the token (like when _parse_atom encounters an unrecognized token and returns None), + # force it to move forward to avoid an infinite loop in the main loop; accumulate error_count for the caller to diagnose + if ps.cur is before_cur: + ps.error_count += 1 + _advance(ps) + _skip_nl(ps) + + +def parse_tokens(pool: memhub.MemManager | t.CPtr, + tokens: Token | t.CPtr) -> AST | t.CPtr: + """Parse an AST Module from a token list.""" + if pool is None or tokens is None: + return None + global _g_parse_err_line, _g_parse_err_col, _g_parse_err_msg + _g_parse_err_line = 0 + _g_parse_err_col = 0 + _g_parse_err_msg = None + ps: Parser | t.CPtr = new_parser(pool) + if ps is None: return None + _parser_init(ps, tokens, pool) + module_node: Module | t.CPtr = Module(pool) + _parse_module_body(ps, module_node) + # fail-fast: 解析出错(error_count > 0)时返回 None,由调用方(TPV 等)报错终止, + # 避免错误代码静默编译(如 `func12344444 avg3(...)` 缺 def 关键字的函数定义残留)。 + if ps.error_count > 0: + return None + return module_node diff --git a/ast/stmts.vp b/ast/stmts.vp new file mode 100644 index 0000000..569646a --- /dev/null +++ b/ast/stmts.vp @@ -0,0 +1,1157 @@ +import t, c +from stdint import * +import memhub +import string +from .base import ( + AST, Stmt, ASTKind, ASTCtx, OpKind, + _init_ast, _copy_str, _set_parent_list, + _emit, _emit_str, _emit_int, _dump_list, + FLAG_IS_ASYNC, +) + + +# ============================================================ +# Module Node +# ============================================================ + +@t.CVTable +class Module(AST): + """Module(children: list[AST | t.CPtr])""" + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Module | t.CPtr = pool.alloc(Module.__sizeof__()) + if ptr: + string.memset(ptr, 0, Module.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr): + _init_ast(self, pool, 0, 0) + + def kind(self) -> t.CInt: + return ASTKind.Module + + def type_name(self) -> str: + return "Module" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Module(body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Assign Node +# ============================================================ + +class Assign(Stmt): + """Assign(targets: list[AST | t.CPtr], value: AST)""" + targets: list[AST | t.CPtr] | t.CPtr + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + targets: list[AST | t.CPtr] | t.CPtr, value: AST | t.CPtr): + ptr: Assign | t.CPtr = pool.alloc(Assign.__sizeof__()) + if ptr: + string.memset(ptr, 0, Assign.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + targets: list[AST | t.CPtr] | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.targets = targets + self.value = value + _set_parent_list(targets, self) + + def kind(self) -> t.CInt: + return ASTKind.Assign + + def type_name(self) -> str: + return "Assign" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Assign(targets=") + pos = _dump_list(self.targets, buf, size, pos) + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# If Node +# ============================================================ + +class If(Stmt): + """If(test: AST, orelse: list[AST | t.CPtr])""" + test: AST | t.CPtr + orelse: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr): + ptr: If | t.CPtr = pool.alloc(If.__sizeof__()) + if ptr: + string.memset(ptr, 0, If.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.test = test + self.orelse = orelse + _set_parent_list(orelse, self) + + def kind(self) -> t.CInt: + return ASTKind.If + + def type_name(self) -> str: + return "If" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "If(test=") + if self.test is not None: + pos = self.test.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ", orelse=") + pos = _dump_list(self.orelse, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# For Node +# ============================================================ + +class For(Stmt): + """For(target: AST, iter: AST, orelse: list[AST | t.CPtr], is_async: CInt)""" + target: AST | t.CPtr + iter: AST | t.CPtr + orelse: list[AST | t.CPtr] | t.CPtr + flags: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, iter: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr, + is_async: t.CInt): + ptr: For | t.CPtr = pool.alloc(For.__sizeof__()) + if ptr: + string.memset(ptr, 0, For.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, iter: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr, + is_async: t.CInt): + _init_ast(self, pool, 0, 0) + self.target = target + self.iter = iter + self.orelse = orelse + if is_async: + self.flags = FLAG_IS_ASYNC + else: + self.flags = 0 + _set_parent_list(orelse, self) + + def kind(self) -> t.CInt: + return ASTKind.For + + def type_name(self) -> str: + return "For" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "For(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", iter=") + if self.iter is not None: + pos = self.iter.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# While Node +# ============================================================ + +class While(Stmt): + """While(test: AST, orelse: list[AST | t.CPtr])""" + test: AST | t.CPtr + orelse: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr): + ptr: While | t.CPtr = pool.alloc(While.__sizeof__()) + if ptr: + string.memset(ptr, 0, While.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.test = test + self.orelse = orelse + _set_parent_list(orelse, self) + + def kind(self) -> t.CInt: + return ASTKind.While + + def type_name(self) -> str: + return "While" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "While(test=") + if self.test is not None: + pos = self.test.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Return Node +# ============================================================ + +class Return(Stmt): + """Return(value: AST | None)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: Return | t.CPtr = pool.alloc(Return.__sizeof__()) + if ptr: + string.memset(ptr, 0, Return.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Return + + def type_name(self) -> str: + return "Return" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Return(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Expr Node (expression statement) +# ============================================================ + +class Expr(Stmt): + """Expr(value: AST)""" + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + ptr: Expr | t.CPtr = pool.alloc(Expr.__sizeof__()) + if ptr: + string.memset(ptr, 0, Expr.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.Expr + + def type_name(self) -> str: + return "Expr" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Expr(value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# FunctionDef Node +# ============================================================ + +class FunctionDef(Stmt): + """FunctionDef(name: str, args: AST, + decorator_list: list[AST | t.CPtr], returns: AST, flags: CInt, + type_params: list[str] | t.CPtr = None) + + type_params: 泛型函数类型参数名列表(PEP 695 def f[T](...): 中的 [T]), + None 表示非泛型函数。""" + name: str + args: AST | t.CPtr + decorator_list: list[AST | t.CPtr] | t.CPtr + returns: AST | t.CPtr + flags: t.CInt + type_params: list[str] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + name: str, args: AST | t.CPtr, + decorator_list: list[AST | t.CPtr] | t.CPtr, + returns: AST | t.CPtr, is_async: t.CInt): + ptr: FunctionDef | t.CPtr = pool.alloc(FunctionDef.__sizeof__()) + if ptr: + string.memset(ptr, 0, FunctionDef.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + name: str, args: AST | t.CPtr, + decorator_list: list[AST | t.CPtr] | t.CPtr, + returns: AST | t.CPtr, is_async: t.CInt, + type_params: list[str] | t.CPtr = None): + _init_ast(self, pool, 0, 0) + self.name = _copy_str(pool, name) + self.args = args + self.decorator_list = decorator_list + self.returns = returns + self.type_params = type_params + if is_async: + self.flags = FLAG_IS_ASYNC + else: + self.flags = 0 + _set_parent_list(decorator_list, self) + + def kind(self) -> t.CInt: + return ASTKind.FunctionDef + + def type_name(self) -> str: + return "FunctionDef" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "FunctionDef(name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "', args=") + if self.args is not None: + pos = self.args.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ", decorator_list=") + pos = _dump_list(self.decorator_list, buf, size, pos) + pos = _emit(buf, size, pos, ", returns=") + if self.returns is not None: + pos = self.returns.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Expression Node +# ============================================================ + +class Expression(AST): + """Expression(body: AST)""" + body: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + body: AST | t.CPtr): + ptr: Expression | t.CPtr = pool.alloc(Expression.__sizeof__()) + if ptr: + string.memset(ptr, 0, Expression.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + body: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.body = body + + def kind(self) -> t.CInt: + return ASTKind.Expression + + def type_name(self) -> str: + return "Expression" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Expression(body=") + if self.body is not None: + pos = self.body.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Interactive Node +# ============================================================ + +class Interactive(AST): + """Interactive(body: AST)""" + body: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + body: AST | t.CPtr): + ptr: Interactive | t.CPtr = pool.alloc(Interactive.__sizeof__()) + if ptr: + string.memset(ptr, 0, Interactive.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + body: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.body = body + + def kind(self) -> t.CInt: + return ASTKind.Interactive + + def type_name(self) -> str: + return "Interactive" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Interactive(body=") + if self.body is not None: + pos = self.body.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# FunctionType Node +# ============================================================ + +class FunctionType(AST): + """FunctionType(argtypes: list[AST | t.CPtr], returns: AST)""" + argtypes: list[AST | t.CPtr] | t.CPtr + returns: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + argtypes: list[AST | t.CPtr] | t.CPtr, + returns: AST | t.CPtr): + ptr: FunctionType | t.CPtr = pool.alloc(FunctionType.__sizeof__()) + if ptr: + string.memset(ptr, 0, FunctionType.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + argtypes: list[AST | t.CPtr] | t.CPtr, + returns: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.argtypes = argtypes + self.returns = returns + + def kind(self) -> t.CInt: + return ASTKind.FunctionType + + def type_name(self) -> str: + return "FunctionType" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "FunctionType(argtypes=") + pos = _dump_list(self.argtypes, buf, size, pos) + pos = _emit(buf, size, pos, ", returns=") + if self.returns is not None: + pos = self.returns.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# ClassDef Node +# ============================================================ + +class ClassDef(Stmt): + """ClassDef(name: str, bases: list[AST | t.CPtr], keywords: list[AST | t.CPtr], + decorator_list: list[AST | t.CPtr], type_params: list[str] | t.CPtr) + + type_params: 泛型类型参数名列表(PEP 695 class list[T]: 中的 [T]), + None 表示非泛型类。""" + name: str + bases: list[AST | t.CPtr] | t.CPtr + keywords: list[AST | t.CPtr] | t.CPtr + decorator_list: list[AST | t.CPtr] | t.CPtr + type_params: list[str] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + name: str, + bases: list[AST | t.CPtr] | t.CPtr, + keywords: list[AST | t.CPtr] | t.CPtr, + decorator_list: list[AST | t.CPtr] | t.CPtr, + type_params: list[str] | t.CPtr = None): + ptr: ClassDef | t.CPtr = pool.alloc(ClassDef.__sizeof__()) + if ptr: + string.memset(ptr, 0, ClassDef.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + name: str, + bases: list[AST | t.CPtr] | t.CPtr, + keywords: list[AST | t.CPtr] | t.CPtr, + decorator_list: list[AST | t.CPtr] | t.CPtr, + type_params: list[str] | t.CPtr = None): + _init_ast(self, pool, 0, 0) + self.name = _copy_str(pool, name) + self.bases = bases + self.keywords = keywords + self.decorator_list = decorator_list + self.type_params = type_params + _set_parent_list(decorator_list, self) + + def kind(self) -> t.CInt: + return ASTKind.ClassDef + + def type_name(self) -> str: + return "ClassDef" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "ClassDef(name='") + pos = _emit_str(buf, size, pos, self.name) + pos = _emit(buf, size, pos, "', bases=") + pos = _dump_list(self.bases, buf, size, pos) + pos = _emit(buf, size, pos, ", keywords=") + pos = _dump_list(self.keywords, buf, size, pos) + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ", decorator_list=") + pos = _dump_list(self.decorator_list, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Delete Node +# ============================================================ + +class Delete(Stmt): + """Delete(targets: list[AST | t.CPtr])""" + targets: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + targets: list[AST | t.CPtr] | t.CPtr): + ptr: Delete | t.CPtr = pool.alloc(Delete.__sizeof__()) + if ptr: + string.memset(ptr, 0, Delete.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + targets: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.targets = targets + _set_parent_list(targets, self) + + def kind(self) -> t.CInt: + return ASTKind.Delete + + def type_name(self) -> str: + return "Delete" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Delete(targets=") + pos = _dump_list(self.targets, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# AugAssign Node +# ============================================================ + +class AugAssign(Stmt): + """AugAssign(target: AST, op: CInt, value: AST)""" + target: AST | t.CPtr + op: t.CInt + value: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, op: t.CInt, value: AST | t.CPtr): + ptr: AugAssign | t.CPtr = pool.alloc(AugAssign.__sizeof__()) + if ptr: + string.memset(ptr, 0, AugAssign.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, op: t.CInt, value: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.target = target + self.op = op + self.value = value + + def kind(self) -> t.CInt: + return ASTKind.AugAssign + + def type_name(self) -> str: + return "AugAssign" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "AugAssign(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", op=") + pos = _emit(buf, size, pos, _op_name(self.op)) + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# AnnAssign Node +# ============================================================ + +class AnnAssign(Stmt): + """AnnAssign(target: AST, annotation: AST, value: AST, simple: CInt)""" + target: AST | t.CPtr + annotation: AST | t.CPtr + value: AST | t.CPtr + simple: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, annotation: AST | t.CPtr, + value: AST | t.CPtr, simple: t.CInt): + ptr: AnnAssign | t.CPtr = pool.alloc(AnnAssign.__sizeof__()) + if ptr: + string.memset(ptr, 0, AnnAssign.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + target: AST | t.CPtr, annotation: AST | t.CPtr, + value: AST | t.CPtr, simple: t.CInt): + _init_ast(self, pool, 0, 0) + self.target = target + self.annotation = annotation + self.value = value + self.simple = simple + + def kind(self) -> t.CInt: + return ASTKind.AnnAssign + + def type_name(self) -> str: + return "AnnAssign" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "AnnAssign(target=") + if self.target is not None: + pos = self.target.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", annotation=") + if self.annotation is not None: + pos = self.annotation.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", value=") + if self.value is not None: + pos = self.value.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", simple=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.simple)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# With Node +# ============================================================ + +class With(Stmt): + """With(items: list[AST | t.CPtr], is_async: CInt)""" + items: list[AST | t.CPtr] | t.CPtr + flags: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + items: list[AST | t.CPtr] | t.CPtr, + is_async: t.CInt): + ptr: With | t.CPtr = pool.alloc(With.__sizeof__()) + if ptr: + string.memset(ptr, 0, With.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + items: list[AST | t.CPtr] | t.CPtr, + is_async: t.CInt): + _init_ast(self, pool, 0, 0) + self.items = items + if is_async: + self.flags = FLAG_IS_ASYNC + else: + self.flags = 0 + _set_parent_list(items, self) + + def kind(self) -> t.CInt: + return ASTKind.With + + def type_name(self) -> str: + return "With" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "With(items=") + pos = _dump_list(self.items, buf, size, pos) + pos = _emit(buf, size, pos, ", body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Raise Node +# ============================================================ + +class Raise(Stmt): + """Raise(exc: AST, cause: AST)""" + exc: AST | t.CPtr + cause: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + exc: AST | t.CPtr, cause: AST | t.CPtr): + ptr: Raise | t.CPtr = pool.alloc(Raise.__sizeof__()) + if ptr: + string.memset(ptr, 0, Raise.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + exc: AST | t.CPtr, cause: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.exc = exc + self.cause = cause + + def kind(self) -> t.CInt: + return ASTKind.Raise + + def type_name(self) -> str: + return "Raise" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Raise(exc=") + if self.exc is not None: + pos = self.exc.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", cause=") + if self.cause is not None: + pos = self.cause.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Try Node +# ============================================================ + +class Try(Stmt): + """Try(handlers: list[AST | t.CPtr], + orelse: list[AST | t.CPtr], finalbody: list[AST | t.CPtr])""" + handlers: list[AST | t.CPtr] | t.CPtr + orelse: list[AST | t.CPtr] | t.CPtr + finalbody: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + handlers: list[AST | t.CPtr] | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr, + finalbody: list[AST | t.CPtr] | t.CPtr): + ptr: Try | t.CPtr = pool.alloc(Try.__sizeof__()) + if ptr: + string.memset(ptr, 0, Try.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + handlers: list[AST | t.CPtr] | t.CPtr, + orelse: list[AST | t.CPtr] | t.CPtr, + finalbody: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.handlers = handlers + self.orelse = orelse + self.finalbody = finalbody + _set_parent_list(handlers, self) + _set_parent_list(orelse, self) + _set_parent_list(finalbody, self) + + def kind(self) -> t.CInt: + return ASTKind.Try + + def type_name(self) -> str: + return "Try" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Try(body=") + pos = _dump_list(self.children, buf, size, pos) + pos = _emit(buf, size, pos, ", handlers=") + pos = _dump_list(self.handlers, buf, size, pos) + pos = _emit(buf, size, pos, ", orelse=") + pos = _dump_list(self.orelse, buf, size, pos) + pos = _emit(buf, size, pos, ", finalbody=") + pos = _dump_list(self.finalbody, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Assert Node +# ============================================================ + +class Assert(Stmt): + """Assert(test: AST, msg: AST)""" + test: AST | t.CPtr + msg: AST | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, msg: AST | t.CPtr): + ptr: Assert | t.CPtr = pool.alloc(Assert.__sizeof__()) + if ptr: + string.memset(ptr, 0, Assert.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + test: AST | t.CPtr, msg: AST | t.CPtr): + _init_ast(self, pool, 0, 0) + self.test = test + self.msg = msg + + def kind(self) -> t.CInt: + return ASTKind.Assert + + def type_name(self) -> str: + return "Assert" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Assert(test=") + if self.test is not None: + pos = self.test.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", msg=") + if self.msg is not None: + pos = self.msg.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Global Node +# ============================================================ + +class Global(Stmt): + """Global(names: list[AST | t.CPtr])""" + names: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + ptr: Global | t.CPtr = pool.alloc(Global.__sizeof__()) + if ptr: + string.memset(ptr, 0, Global.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.names = names + _set_parent_list(names, self) + + def kind(self) -> t.CInt: + return ASTKind.Global + + def type_name(self) -> str: + return "Global" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Global(names=") + pos = _dump_list(self.names, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Nonlocal Node +# ============================================================ + +class Nonlocal(Stmt): + """Nonlocal(names: list[AST | t.CPtr])""" + names: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + ptr: Nonlocal | t.CPtr = pool.alloc(Nonlocal.__sizeof__()) + if ptr: + string.memset(ptr, 0, Nonlocal.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.names = names + _set_parent_list(names, self) + + def kind(self) -> t.CInt: + return ASTKind.Nonlocal + + def type_name(self) -> str: + return "Nonlocal" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Nonlocal(names=") + pos = _dump_list(self.names, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Pass Node +# ============================================================ + +class Pass(Stmt): + """Pass()""" + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Pass | t.CPtr = pool.alloc(Pass.__sizeof__()) + if ptr: + string.memset(ptr, 0, Pass.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr): + _init_ast(self, pool, 0, 0) + + def kind(self) -> t.CInt: + return ASTKind.Pass + + def type_name(self) -> str: + return "Pass" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Pass()") + return pos + + +# ============================================================ +# Break Node +# ============================================================ + +class Break(Stmt): + """Break()""" + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Break | t.CPtr = pool.alloc(Break.__sizeof__()) + if ptr: + string.memset(ptr, 0, Break.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr): + _init_ast(self, pool, 0, 0) + + def kind(self) -> t.CInt: + return ASTKind.Break + + def type_name(self) -> str: + return "Break" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Break()") + return pos + + +# ============================================================ +# Continue Node +# ============================================================ + +class Continue(Stmt): + """Continue()""" + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: Continue | t.CPtr = pool.alloc(Continue.__sizeof__()) + if ptr: + string.memset(ptr, 0, Continue.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr): + _init_ast(self, pool, 0, 0) + + def kind(self) -> t.CInt: + return ASTKind.Continue + + def type_name(self) -> str: + return "Continue" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Continue()") + return pos + + +# ============================================================ +# Import Node +# ============================================================ + +class Import(Stmt): + """Import(names: list[AST | t.CPtr])""" + names: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + ptr: Import | t.CPtr = pool.alloc(Import.__sizeof__()) + if ptr: + string.memset(ptr, 0, Import.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + names: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.names = names + _set_parent_list(names, self) + + def kind(self) -> t.CInt: + return ASTKind.Import + + def type_name(self) -> str: + return "Import" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Import(names=") + pos = _dump_list(self.names, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# ImportFrom Node +# ============================================================ + +class ImportFrom(Stmt): + """ImportFrom(module: str, names: list[AST | t.CPtr], level: CInt)""" + module: str + names: list[AST | t.CPtr] | t.CPtr + level: t.CInt + + def __new__(self, pool: memhub.MemManager | t.CPtr, + module: str, + names: list[AST | t.CPtr] | t.CPtr, + level: t.CInt): + ptr: ImportFrom | t.CPtr = pool.alloc(ImportFrom.__sizeof__()) + if ptr: + string.memset(ptr, 0, ImportFrom.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + module: str, + names: list[AST | t.CPtr] | t.CPtr, + level: t.CInt): + _init_ast(self, pool, 0, 0) + self.module = _copy_str(pool, module) + self.names = names + self.level = level + _set_parent_list(names, self) + + def kind(self) -> t.CInt: + return ASTKind.ImportFrom + + def type_name(self) -> str: + return "ImportFrom" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "ImportFrom(module='") + pos = _emit_str(buf, size, pos, self.module) + pos = _emit(buf, size, pos, "', names=") + pos = _dump_list(self.names, buf, size, pos) + pos = _emit(buf, size, pos, ", level=") + pos = _emit_int(buf, size, pos, t.CInt64T(self.level)) + pos = _emit(buf, size, pos, ")") + return pos + + +# ============================================================ +# Match Node +# ============================================================ + +class Match(Stmt): + """Match(subject: AST, cases: list[AST | t.CPtr])""" + subject: AST | t.CPtr + cases: list[AST | t.CPtr] | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, + subject: AST | t.CPtr, + cases: list[AST | t.CPtr] | t.CPtr): + ptr: Match | t.CPtr = pool.alloc(Match.__sizeof__()) + if ptr: + string.memset(ptr, 0, Match.__sizeof__()) + return ptr + + def __init__(self, pool: memhub.MemManager | t.CPtr, + subject: AST | t.CPtr, + cases: list[AST | t.CPtr] | t.CPtr): + _init_ast(self, pool, 0, 0) + self.subject = subject + self.cases = cases + _set_parent_list(cases, self) + + def kind(self) -> t.CInt: + return ASTKind.Match + + def type_name(self) -> str: + return "Match" + + def dump(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pos: t.CSizeT) -> t.CSizeT: + pos = _emit(buf, size, pos, "Match(subject=") + if self.subject is not None: + pos = self.subject.dump(buf, size, pos) + else: + pos = _emit(buf, size, pos, "None") + pos = _emit(buf, size, pos, ", cases=") + pos = _dump_list(self.cases, buf, size, pos) + pos = _emit(buf, size, pos, ")") + return pos diff --git a/ast/tokens.vp b/ast/tokens.vp new file mode 100644 index 0000000..d9c07c5 --- /dev/null +++ b/ast/tokens.vp @@ -0,0 +1,404 @@ +import t, c +from stdint import * +import memhub +import string + + +# ============================================================ +# Token type enumeration (refer to CPython Lib/token.py) +# Organized as a type-safe enum using t.CEnum; old names XXX retained as compatible aliases +# ============================================================ + +class TokenType(t.CEnum): + EndMarker: t.State + NewLine: t.State + Indent: t.State + Dedent: t.State + Name: t.State + Number: t.State + String: t.State + FStringStart: t.State + FStringMiddle: t.State + FStringEnd: t.State + Op: t.State + Nl: t.State + Comment: t.State + Encoding: t.State + + +# ============================================================ +# Keyword enumeration (refer to CPython Lib/keyword.py) +# Organized as a type-safe enum using t.CEnum; old names KW_XXX are kept as compatible aliases +# NotKeyword(0) represents a non-keyword (sentinel to avoid conflict between False_=0 and kw_subtype=0) +# ============================================================ + +class Keyword(t.CEnum): + NotKeyword: t.State + False_: t.State + None_: t.State + True_: t.State + And: t.State + As: t.State + Assert: t.State + Async: t.State + Await: t.State + Break: t.State + Class: t.State + Continue: t.State + Def: t.State + Del: t.State + Elif: t.State + Else: t.State + Except: t.State + Finally: t.State + For: t.State + From: t.State + Global: t.State + If: t.State + Import: t.State + In: t.State + Is: t.State + Lambda: t.State + Nonlocal: t.State + Not: t.State + Or: t.State + Pass: t.State + Raise: t.State + Return: t.State + Try: t.State + While: t.State + With: t.State + Yield: t.State + Match: t.State + Case: t.State + Type: t.State + # def 的别名关键字(fn/fun/func/function,语义与 def 完全相同) + Fn: t.State + Fun: t.State + Func: t.State + Function: t.State + # extern 函数声明关键字(FFI,等价 t.State 标记;软判定见 _is_funcdef_kw) + Extern: t.State + + +# ============================================================ +# Operator/Separator Enumeration +# Organized as a type-safe enum using t.CEnum; old names OP_XXX retained as compatible aliases +# Stored in the token.op_subtype field +# ============================================================ + +class TokOp(t.CEnum): + LPar: t.State # ( + RPar: t.State # ) + Lsqb: t.State # [ + Rsqb: t.State # ] + LBrace: t.State # { + RBrace: t.State # } + Comma: t.State # , + Colon: t.State # : + Dot: t.State # . + Semi: t.State # ; + At: t.State # @ + Equal: t.State # = + RArrow: t.State # -> + PlusEq: t.State # += + MinusEq: t.State # -= + StarEq: t.State # *= + SlashEq: t.State # /= + DSlashEq: t.State # //= + PercentEq: t.State # %= + AtEq: t.State # @= + AmpEq: t.State # &= + VBarEq: t.State # |= + CaretEq: t.State # ^= + GtGtEq: t.State # >>= + LtLtEq: t.State # <<= + StarEqEq: t.State # **= + DSlash: t.State # // + StarStar: t.State # ** + LtLt: t.State # << + GtGt: t.State # >> + LessEq: t.State # <= + GreaterEq: t.State # >= + EqEq: t.State # == + ExclaimEq: t.State # != + Less: t.State # < + Greater: t.State # > + Plus: t.State # + + Minus: t.State # - + Star: t.State # * + Slash: t.State # / + Percent: t.State # % + Amp: t.State # & + VBar: t.State # | + Caret: t.State # ^ + Tilde: t.State # ~ + ColonEq: t.State # := + Ellipsis: t.State # ... + Bang: t.State # !(Non-standard, used for parsing tolerance) + + +# ============================================================ +# Token stucture +# ============================================================ +class Token: + type: t.CInt # Token type (TokenType.EndMarker / TokenType.NewLine / TokenType.Name / ...) + op_subtype: t.CInt # Operator subtype (OP_*). Only valid when type == TokenType.Op + kw_subtype: t.CInt # Keyword subtype (KW_*). Only valid when type == TokenType.Name and it is a keyword + str_val: str # Token text (NUL‑terminated, allocated from pool) + int_val: t.CInt64T # Integer value (used by TokenType.Number) + float_val: t.CDouble # Floating‑point value (used by TokenType.Number) + is_float: t.CInt # 1 = floating‑point number, 0 = integer + is_complex: t.CInt # 1 = complex number, 0 = real number + lineno: t.CInt # Starting line number + col_offset: t.CInt # Starting column offset + end_lineno: t.CInt # Ending line number + end_col_offset: t.CInt # Ending column offset + next: Token | t.CPtr # Next token in linked list + + def __new__(self, pool: memhub.MemManager | t.CPtr): + """Allocate zero‑initialized Token struct memory from mpool""" + ptr: Token | t.CPtr = pool.alloc(Token.__sizeof__()) + if ptr: + string.memset(ptr, 0, Token.__sizeof__()) + return ptr + + +# ============================================================ +# Keyword lookup table +# Since TransPyC has no dict literals, implemented with linked lists +# ============================================================ +class KwEntry: + name: str + kw_id: t.CInt + next: KwEntry | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: KwEntry | t.CPtr = pool.alloc(KwEntry.__sizeof__()) + if ptr: + string.memset(ptr, 0, KwEntry.__sizeof__()) + return ptr + + +# Global keyword linked list head (lazy initialization) +_kw_head: KwEntry | t.CPtr = None +_kw_pool: memhub.MemManager | t.CPtr = None + + +def _kw_intern(pool: memhub.MemManager | t.CPtr, name: str, kw_id: t.CInt): + """Register keyword name in the linked list""" + global _kw_head + entry: KwEntry | t.CPtr = KwEntry(pool) + if entry == None: return + slen: t.CSizeT = string.strlen(name) + buf: str = pool.alloc(slen + 1) + if buf == None: return + string.memcpy(buf, name, slen + 1) + entry.name = buf + entry.kw_id = kw_id + entry.next = _kw_head + _kw_head = entry + + +def _kw_lookup(name: str) -> t.CInt: + """Look up keyword name in the linked list, return the kw_id (0 if not keyword)""" + cur: KwEntry | t.CPtr = _kw_head + while cur != None: + if string.strcmp(cur.name, name) == 0: + return cur.kw_id + cur = cur.next + return 0 + + +def _init_keywords(pool: memhub.MemManager | t.CPtr): + """Initialize keyword linked list (only once)""" + global _kw_head, _kw_pool + if _kw_head != None: return + _kw_pool = pool + _kw_intern(pool, "False", Keyword.False_) + _kw_intern(pool, "None", Keyword.None_) + _kw_intern(pool, "True", Keyword.True_) + _kw_intern(pool, "and", Keyword.And) + _kw_intern(pool, "as", Keyword.As) + _kw_intern(pool, "assert", Keyword.Assert) + _kw_intern(pool, "async", Keyword.Async) + _kw_intern(pool, "await", Keyword.Await) + _kw_intern(pool, "break", Keyword.Break) + _kw_intern(pool, "class", Keyword.Class) + _kw_intern(pool, "continue", Keyword.Continue) + _kw_intern(pool, "def", Keyword.Def) + _kw_intern(pool, "del", Keyword.Del) + _kw_intern(pool, "elif", Keyword.Elif) + _kw_intern(pool, "else", Keyword.Else) + _kw_intern(pool, "except", Keyword.Except) + _kw_intern(pool, "finally", Keyword.Finally) + _kw_intern(pool, "for", Keyword.For) + _kw_intern(pool, "from", Keyword.From) + _kw_intern(pool, "global", Keyword.Global) + _kw_intern(pool, "if", Keyword.If) + _kw_intern(pool, "import", Keyword.Import) + _kw_intern(pool, "in", Keyword.In) + _kw_intern(pool, "is", Keyword.Is) + _kw_intern(pool, "lambda", Keyword.Lambda) + _kw_intern(pool, "nonlocal", Keyword.Nonlocal) + _kw_intern(pool, "not", Keyword.Not) + _kw_intern(pool, "or", Keyword.Or) + _kw_intern(pool, "pass", Keyword.Pass) + _kw_intern(pool, "raise", Keyword.Raise) + _kw_intern(pool, "return", Keyword.Return) + _kw_intern(pool, "try", Keyword.Try) + _kw_intern(pool, "while", Keyword.While) + _kw_intern(pool, "with", Keyword.With) + _kw_intern(pool, "yield", Keyword.Yield) + _kw_intern(pool, "match", Keyword.Match) + _kw_intern(pool, "case", Keyword.Case) + _kw_intern(pool, "type", Keyword.Type) + # def 的别名关键字(fn/fun/func/function,语义与 def 完全相同) + _kw_intern(pool, "fn", Keyword.Fn) + _kw_intern(pool, "fun", Keyword.Fun) + _kw_intern(pool, "func", Keyword.Func) + _kw_intern(pool, "function", Keyword.Function) + _kw_intern(pool, "extern", Keyword.Extern) + + +# ============================================================ +# Operator lookup table +# Since TransPyC doesn't have dict, use an array with linear search +# Operators are sorted by descending length for greedy matching +# ============================================================ +class OpEntry: + name: str # Operator text (e.g. "==", "+=") + op_id: t.CInt + length: t.CInt + next: OpEntry | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr): + ptr: OpEntry | t.CPtr = pool.alloc(OpEntry.__sizeof__()) + if ptr: + string.memset(ptr, 0, OpEntry.__sizeof__()) + return ptr + + +_op_head: OpEntry | t.CPtr = None + + +def _op_intern(pool: memhub.MemManager | t.CPtr, name: str, op_id: t.CInt): + global _op_head + slen: t.CSizeT = string.strlen(name) + entry: OpEntry | t.CPtr = OpEntry(pool) + if entry == None: return + buf: str = pool.alloc(slen + 1) + if buf == None: return + string.memcpy(buf, name, slen + 1) + entry.name = buf + entry.op_id = op_id + entry.length = t.CInt(slen) + entry.next = _op_head + _op_head = entry + + +def _init_operators(pool: memhub.MemManager | t.CPtr): + """Initialize the operator table (register in descending length order for easy greedy matching)""" + global _op_head + if _op_head != None: return + # 3-character operators + _op_intern(pool, "**=", TokOp.StarEqEq) + _op_intern(pool, "//=", TokOp.DSlashEq) + _op_intern(pool, ">>=", TokOp.GtGtEq) + _op_intern(pool, "<<=", TokOp.LtLtEq) + _op_intern(pool, "...", TokOp.Ellipsis) + # 2-character operators + _op_intern(pool, "->", TokOp.RArrow) + _op_intern(pool, "+=", TokOp.PlusEq) + _op_intern(pool, "-=", TokOp.MinusEq) + _op_intern(pool, "*=", TokOp.StarEq) + _op_intern(pool, "/=", TokOp.SlashEq) + _op_intern(pool, "%=", TokOp.PercentEq) + _op_intern(pool, "@=", TokOp.AtEq) + _op_intern(pool, "&=", TokOp.AmpEq) + _op_intern(pool, "|=", TokOp.VBarEq) + _op_intern(pool, "^=", TokOp.CaretEq) + _op_intern(pool, "//", TokOp.DSlash) + _op_intern(pool, "**", TokOp.StarStar) + _op_intern(pool, "<<", TokOp.LtLt) + _op_intern(pool, ">>", TokOp.GtGt) + _op_intern(pool, "<=", TokOp.LessEq) + _op_intern(pool, ">=", TokOp.GreaterEq) + _op_intern(pool, "==", TokOp.EqEq) + _op_intern(pool, "!=", TokOp.ExclaimEq) + _op_intern(pool, ":=", TokOp.ColonEq) + # 1-character operators + _op_intern(pool, "(", TokOp.LPar) + _op_intern(pool, ")", TokOp.RPar) + _op_intern(pool, "[", TokOp.Lsqb) + _op_intern(pool, "]", TokOp.Rsqb) + _op_intern(pool, "{", TokOp.LBrace) + _op_intern(pool, "}", TokOp.RBrace) + _op_intern(pool, ",", TokOp.Comma) + _op_intern(pool, ":", TokOp.Colon) + _op_intern(pool, ".", TokOp.Dot) + _op_intern(pool, ";", TokOp.Semi) + _op_intern(pool, "@", TokOp.At) + _op_intern(pool, "=", TokOp.Equal) + _op_intern(pool, "<", TokOp.Less) + _op_intern(pool, ">", TokOp.Greater) + _op_intern(pool, "+", TokOp.Plus) + _op_intern(pool, "-", TokOp.Minus) + _op_intern(pool, "*", TokOp.Star) + _op_intern(pool, "/", TokOp.Slash) + _op_intern(pool, "%", TokOp.Percent) + _op_intern(pool, "&", TokOp.Amp) + _op_intern(pool, "|", TokOp.VBar) + _op_intern(pool, "^", TokOp.Caret) + _op_intern(pool, "~", TokOp.Tilde) + + +def _init_tables(pool: memhub.MemManager | t.CPtr): + """Initialize all lookup tables (idempotent)""" + _init_keywords(pool) + _init_operators(pool) + + +# ============================================================ +# Token creation helper functions +# ============================================================ + +def new_token(pool: memhub.MemManager | t.CPtr, ttype: t.CInt, lineno: t.CInt, + col_offset: t.CInt) -> Token | t.CPtr: + """Create a new empty Token and fill in fields later""" + tok: Token | t.CPtr = Token(pool) + if tok == None: return None + tok.type = ttype + tok.lineno = lineno + tok.col_offset = col_offset + tok.end_lineno = lineno + tok.end_col_offset = col_offset + return tok + + +def token_set_str(pool: memhub.MemManager | t.CPtr, tok: Token | t.CPtr, + src: str, start: t.CSizeT, length: t.CSizeT): + """Copy text from src[start:start + length] to token.str_val + + Note: When length == 0, still allocate 1 byte for NUL, so that an empty string is distinguished from a NULL pointer. + """ + if tok == None: return + buf: str = pool.alloc(length + 1) + if buf == None: return + i: t.CSizeT = 0 + while i < length: + buf[i] = src[start + i] + i += 1 + buf[length] = '\0' + tok.str_val = buf + + +def token_set_str_literal(pool: memhub.MemManager | t.CPtr, tok: Token | t.CPtr, + text: str): + """Copy a C string to token.str_val""" + if tok == None or text == None: return + slen: t.CSizeT = string.strlen(text) + buf: str = pool.alloc(slen + 1) + if buf == None: return + string.memcpy(buf, text, slen + 1) + tok.str_val = buf diff --git a/atom.vp b/atom.vp new file mode 100644 index 0000000..6c58de9 --- /dev/null +++ b/atom.vp @@ -0,0 +1,41 @@ +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: + result: t.CUInt8T = 1 + c.Asm(f"""mov al, 1 + xchg byte ptr [{c.AsmInp(ptr, t.ASM_DESCR.REG_ANY)}], al + mov $0, al""", + out = [c.AsmOut(result, t.ASM_DESCR.OUTPUT_REG)], + 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: + 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: + c.Asm("mfence", op=[t.ASM_DESCR.CLOBBER_MEMORY]) + + +def __atomic_signal_fence(order: t.CInt) -> t.CVoid: + pass + + +def __atomic_always_lock_free(size: t.CSizeT, ptr: t.CVoid | t.CPtr) -> t.CBool: + return t.CBool(1) + + +def __atomic_is_lock_free(size: t.CSizeT, ptr: t.CVoid | t.CPtr) -> t.CBool: + return t.CBool(1) diff --git a/base64.vp b/base64.vp new file mode 100644 index 0000000..0dfc962 --- /dev/null +++ b/base64.vp @@ -0,0 +1,80 @@ +import t, c + + +# ============================================== +# Base64 Encoder & Decoder, pure bare-metal implementation +# ============================================== +# Base64 encoding lookup table +b64_tab: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +# Base64 反向解码表,映射字符到索引值 +b64_dec_tab: t.CArray[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 encoding +# * @param s: Input binary data +# * @param out: Output buffer for Base64 string +# * @retval Length of encoded string +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 + # Process input in groups of 3 bytes, produce 4 Base64 characters + for i in range(0, length, 3): + # Assemble 24-bit chunk + 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)) + # Split into four 6-bit values for table lookup + 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' # Null terminator for C-style string + return j + + +# * @brief Base64 decoding +# * @param s: Base64 encoded string +# * @param out: Output binary buffer +# * @retval Length of decoded binary data +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 + # Restore 3 bytes from every 4 Base64 characters + for i in range(0, length, 4): + if s[i] == '=': + break + val = 0 + # Parse 6-bit values sequentially + 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) + # Write recovered bytes + 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/binascii.vp b/binascii.vp new file mode 100644 index 0000000..31e81ee --- /dev/null +++ b/binascii.vp @@ -0,0 +1,349 @@ +import t, c +import stdlib + + +HEX_CHARS: t.CArray[t.CChar, None] = "0123456789abcdef" +HEX_VALS: t.CArray[t.CInt, 256] + +B64_CHARS: t.CArray[t.CChar, None] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +B64_VALS: t.CArray[t.CInt, 256] + +HQX_CHARS: t.CArray[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: t.CArray[t.CInt, 256] + +UU_CHARS: t.CArray[t.CChar, None] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + +CRC32_TABLE: t.CArray[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: t.CArray[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(stdlib.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(stdlib.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: + stdlib.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) -> bytes: + 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(stdlib.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(stdlib.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(stdlib.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(stdlib.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(stdlib.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(stdlib.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/builtins.vp b/builtins.vp new file mode 100644 index 0000000..5296c61 --- /dev/null +++ b/builtins.vp @@ -0,0 +1,13 @@ +import t + +# ============================================================ +# 内置函数(Python 语义,自动与 builtins 关联,无需显式 import) +# ord: 字符 → ASCII 码(int) +# chr: ASCII 码 → 字符(t.CChar) +# ============================================================ + +def ord(s: t.CChar) -> int: + return s + +def chr(i: int) -> t.CChar: + return i diff --git a/condition.vp b/condition.vp new file mode 100644 index 0000000..96b7d9e --- /dev/null +++ b/condition.vp @@ -0,0 +1,52 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32sync import ( + CRITICAL_SECTION, + InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection, + InitializeConditionVariable, SleepConditionVariableCS, + WakeConditionVariable, WakeAllConditionVariable +) + + +class Condition: + """Windows condition variable backed primitive, internally bundled with CRITICAL_SECTION. + + Usage: + cond: Condition = Condition() + with cond: + while not ready: + cond.wait() + cond.notify() + """ + cond_var: VOIDPTR + cs: CRITICAL_SECTION + + def __init__(self): + InitializeCriticalSection(c.Addr(self.cs)) + InitializeConditionVariable(c.Addr(self.cond_var)) + + def wait(self, timeout_ms: ULONG = INFINITE) -> BOOL: + return SleepConditionVariableCS(c.Addr(self.cond_var), c.Addr(self.cs), timeout_ms) + + def notify(self): + WakeConditionVariable(c.Addr(self.cond_var)) + + def notify_all(self): + WakeAllConditionVariable(c.Addr(self.cond_var)) + + def acquire(self): + EnterCriticalSection(c.Addr(self.cs)) + + def release(self): + LeaveCriticalSection(c.Addr(self.cs)) + + def __enter__(self) -> 'Condition' | t.CPtr: + self.acquire() + return self + + def __exit__(self): + self.release() + + def delete(self): + DeleteCriticalSection(c.Addr(self.cs)) diff --git a/ctraits.vpi b/ctraits.vpi new file mode 100644 index 0000000..52da5b9 --- /dev/null +++ b/ctraits.vpi @@ -0,0 +1,19 @@ +"""ctraits — Compile-time type trait library + +Provides compile-time type predicates with no runtime code generated. +All functions are evaluated exclusively at compile time and can be combined with conditional compilation constructs such as c.CIf. +""" +import t + +def isptr(x: t.CType) -> bool: + """Compile-time predicate to determine whether the type of x is a pointer. + + Returns True if x is a pointer type (ptr_count > 0); otherwise returns False. + Can be used alongside c.CIf to implement conditional compilation. + + Example: + if c.CIf(ctraits.isptr(my_var)): + # This branch compiles only when my_var is a pointer type + ... + """ + pass \ No newline at end of file diff --git a/event.vp b/event.vp new file mode 100644 index 0000000..103d51b --- /dev/null +++ b/event.vp @@ -0,0 +1,36 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32sync import CreateEventA, SetEvent, ResetEvent, WaitForSingleObject + + +@t.Object +class Event: + """Windows Event-based event object, supports manual-reset and auto-reset modes. + + Usage: + evt: Event = Event(FALSE, FALSE) + evt.set() + evt.wait() + """ + handle: HANDLE + manual_reset: BOOL + + def __init__(self, manual_reset: BOOL = FALSE, initial_state: BOOL = FALSE): + self.manual_reset = manual_reset + self.handle = CreateEventA(NULL, manual_reset, initial_state, NULL) + + def set(self): + SetEvent(self.handle) + + def clear(self): + ResetEvent(self.handle) + + def is_set(self) -> BOOL: + return WaitForSingleObject(self.handle, 0) == WAIT_OBJECT_0 + + def wait(self, timeout_ms: ULONG = INFINITE) -> BOOL: + return WaitForSingleObject(self.handle, timeout_ms) == WAIT_OBJECT_0 + + def close(self): + CloseHandle(self.handle) diff --git a/hashlib/__init__.vp b/hashlib/__init__.vp new file mode 100644 index 0000000..3ee2214 --- /dev/null +++ b/hashlib/__init__.vp @@ -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/hashlib/__md5.vp b/hashlib/__md5.vp new file mode 100644 index 0000000..d98680f --- /dev/null +++ b/hashlib/__md5.vp @@ -0,0 +1,132 @@ +import string +import t, c + + +# ============================================== +# MD5 hash algorithm +# ============================================== +MD5_BLOCK_LEN: t.CDefine = 64 # Group block size +MD5_DIGEST_LEN: t.CDefine = 16 # Digest output length + +# MD5 four-round nonlinear functions +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) +# Circular left shift +def md5_rotl(x: t.CUInt32T, n: t.CInt) -> t.CUInt32T: return (x << n) | (x >> (32 - n)) + +# MD5 constant table +md5_T: t.CArray[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: t.CArray[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 context structure +# ============================================================ +@t.Object +class md5: + state: t.CArray[t.CUInt32T, 4] # 4 32-bit state registers + count: t.CUInt64T # processed bits + buf: t.CArray[t.CUInt8T, MD5_BLOCK_LEN] # Group buffer + # Initialize MD5 context + def __init__(self): + string.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 single-group compression transform + 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: t.CArray[t.CUInt32T, 16] + # Byte order 32-bit words + 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-round 51 iterations + 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]) + # 4-round 51 iterations + for i in range(16, 32): + tmp: t.CUInt32T = md5_G(b, c, d) + a + md5_T[i] + w[(5 * i + 1) % 16] + a = d; d = c; c = b + b += md5_rotl(tmp, md5_S[i]) + for i in range(32, 48): + tmp: t.CUInt32T = md5_H(b, c, d) + a + md5_T[i] + w[(3 * i + 5) % 16] + a = d; d = c; c = b + b += md5_rotl(tmp, md5_S[i]) + for i in range(48, 64): + tmp: t.CUInt32T = md5_I(b, c, d) + a + md5_T[i] + w[(7 * i + 0) % 16] + a = d; d = c; c = b + b += md5_rotl(tmp, md5_S[i]) + # Accumulate to state registers + self.state[0] += a + self.state[1] += b + self.state[2] += c + self.state[3] += d + # Batch input data + 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 % MD5_BLOCK_LEN + self.count += length + if idx > 0: + left: t.CSizeT = MD5_BLOCK_LEN - idx + if length >= left: + string.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: + string.memcpy(self.buf + idx, data, length) + # End calculation, output 16-byte digest + def final(self, out: t.CArray[t.CUInt8T, MD5_DIGEST_LEN]): + idx: t.CSizeT = self.count % MD5_BLOCK_LEN + # Pad 0x80 end + self.buf[idx] = 0x80 + idx += 1 + # If space is not enough, compress once + if idx > MD5_BLOCK_LEN - 8: + string.memset(self.buf + idx, 0, MD5_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + # Pad 0 to end 8 bytes + string.memset(self.buf + idx, 0, MD5_BLOCK_LEN - 8 - idx) + # Write total bit count + 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) + # State registers to little-endian byte output output + 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/hashlib/__sha1.vp b/hashlib/__sha1.vp new file mode 100644 index 0000000..fdd28ae --- /dev/null +++ b/hashlib/__sha1.vp @@ -0,0 +1,120 @@ +import string +import t, c + + + +# ============================================== +# SHA1 Hash Algorithm +# ============================================== +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)) +# 3-round logical functions +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 Context +@t.Object +class sha1: + state: t.CArray[t.CUInt32T, 5] + count: t.CUInt64T + buf: t.CArray[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 + # Single-group compression transform + def transform(self, block: t.CUInt8T | t.CPtr): + w: t.CArray[t.CUInt32T, 80] + data: t.CUInt8T | t.CPtr = block + # First 16 words + 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)) + # Extend to 80 words + 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-round iterations + 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: + string.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: + string.memcpy(self.buf + idx, data, length) + def final(self, out: t.CArray[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 big-endian write length + for i in range(8): + self.buf[SHA1_BLOCK_LEN - 8 + i] = (bits >> (56 - i * 8)) & 0xFF + self.transform(self.buf) + # State registers to big-endian byte output output output + 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/hashlib/__sha256.vp b/hashlib/__sha256.vp new file mode 100644 index 0000000..4330bd5 --- /dev/null +++ b/hashlib/__sha256.vp @@ -0,0 +1,124 @@ +import t, c +import string + + +# ============================================== +# SHA256 Hash Algorithm +# ============================================== +SHA256_BLOCK_LEN: t.CDefine = 64 +SHA256_DIGEST_LEN: t.CDefine = 32 + +# SHA256 Constants K +sha256_K: t.CArray[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 Auxiliary Functions +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 Context +@t.Object +class sha256: + state: t.CArray[t.CUInt32T, 8] + count: t.CUInt64T + buf: t.CArray[t.CUInt8T, SHA256_BLOCK_LEN] + def __init__(self): + string.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 + # string.memset(self.buf, 0, SHA256_BLOCK_LEN) + # SHA256 single-group compression transform + def transform(self, block: t.CUInt8T | t.CPtr): + w: t.CArray[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 )) + # Extend to 64 words + 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-round iterations + 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 + # Accumulate to state registers + 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: + string.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: + string.memcpy(self.buf + idx, data, length) + def final(self, out: t.CArray[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: + string.memset(self.buf + idx, 0, SHA256_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + string.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) + # Byte order 32-bit words + 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/hashlib/__sha512.vp b/hashlib/__sha512.vp new file mode 100644 index 0000000..cbcec85 --- /dev/null +++ b/hashlib/__sha512.vp @@ -0,0 +1,149 @@ +import t, c +import string + + +# ============================================== +# SHA512 Hash Algorithm +# ============================================== +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: t.CArray[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: t.CArray[t.CUInt64T, 8] + count: t.CArray[t.CUInt64T, 2] + buf: t.CArray[t.CUInt8T, SHA512_BLOCK_LEN] + def __init__(self): + string.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: t.CArray[t.CUInt8T, SHA512_BLOCK_LEN]): + w: t.CArray[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: + string.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: + string.memcpy(self.buf + idx, data, length) + def final(self, out: t.CArray[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: + string.memset(self.buf + idx, 0, SHA512_BLOCK_LEN - idx) + self.transform(self.buf) + idx = 0 + string.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/hashtable.vp b/hashtable.vp new file mode 100644 index 0000000..99a190f --- /dev/null +++ b/hashtable.vp @@ -0,0 +1,242 @@ +# hashtable - Open-addressing hash table library +# Linear probing for collision resolution, supports auto-resizing and tombstone deletion +# Key type fixed as str (i8*), value type is void* (generic pointer) +import t, c +import string +import memhub +import stdio +from stdint import * + +# Empty slot marker (hash == 0) +_HT_EMPTY: t.CDefine = 0 +# Tombstone slot marker (hash == 1) +_HT_TOMBSTONE: t.CDefine = 1 +# Default initial capacity (must be power of two) +_HT_INIT_CAP: t.CDefine = 16 +# Slot memory layout: hash(8) + key pointer(8) + value pointer(8) = 24 bytes +_HT_SLOT_SIZE: t.CDefine = 24 +# FNV-1a 64-bit constants +_FNV_OFFSET: t.CUInt64T = 0xcbf29ce484222325 +_FNV_PRIME: t.CUInt64T = 0x100000001b3 + + +def _fnv1a_hash(key: str) -> t.CUInt64T: + """FNV-1a 64-bit hash function.""" + h: t.CUInt64T = _FNV_OFFSET + k: str = key + while k[0] != 0: + h = h ^ t.CUInt64T(k[0]) + h = h * _FNV_PRIME + k += 1 + # Ensure h >= 2 (avoids empty slot marker 0 and tombstone marker 1) + if h < 2: + h = 2 + return h + + +class HashTable: + """Open-addressing hash table using linear probing for collision resolution. + + Key type fixed as str (i8*), value type is void* (generic pointer). + Memory is managed via the mbuddy allocator. Automatically resizes when load factor exceeds 0.75. + + Usage: + mb: memhub.MemBuddy = memhub.MemBuddy(arena, arena_size) + ht: HashTable = HashTable(mb) + ht.set_int("x", 42) + p: t.CPtr = ht["x"] + v: int = c.Deref(p) + """ + __slots__: t.CVoid | t.CPtr # Base address of slot array + __count__: t.CSizeT = 0 # Number of occupied entries + __capacity__: t.CSizeT = 16 # Total slot count (power of two) + __tombstones__: t.CSizeT = 0 # Tombstone entry count + __mbuddy__: memhub.MemBuddy | t.CPtr + __iter_index__: t.CSizeT = 0 + + def __new__(self, mb: memhub.MemBuddy | t.CPtr) -> t.CPtr: + # Heap-allocate HashTable object (6 fields × 8 bytes = 48 bytes) + return mb.alloc(48) + + def __init__(self, mb: memhub.MemBuddy | t.CPtr): + self.__mbuddy__ = mb + self.__capacity__ = _HT_INIT_CAP + self.__count__ = 0 + self.__tombstones__ = 0 + self.__slots__ = mb.alloc(self.__capacity__ * _HT_SLOT_SIZE) + # Initialize all slots to empty (hash = 0) + string.memset(self.__slots__, 0, self.__capacity__ * _HT_SLOT_SIZE) + + def _slot_hash(self, idx: t.CSizeT) -> t.CUInt64T: + """Read hash value from target slot.""" + ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE) + return ptr[0] + + def _slot_key(self, idx: t.CSizeT) -> str: + """Read key pointer from target slot.""" + ptr: str | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 8) + return ptr[0] + + def _slot_value(self, idx: t.CSizeT) -> t.CPtr: + """Read value pointer from target slot.""" + ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 16) + return ptr[0] + + def _set_slot(self, idx: t.CSizeT, h: t.CUInt64T, key: str, val: t.CPtr): + """Assign three fields of the target slot.""" + h_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE) + h_ptr[0] = h + k_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 8) + k_ptr[0] = key + v_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE + 16) + v_ptr[0] = val + + def _find_slot(self, key: str, h: t.CUInt64T) -> t.CSizeT: + """Locate slot index for key insertion or lookup. + + Returns: Index of matching key if found; otherwise returns index of first usable empty/tombstone slot. + """ + mask: t.CSizeT = self.__capacity__ - 1 + idx: t.CSizeT = t.CSizeT(h) & mask + first_tombstone: t.CSizeT = self.__capacity__ + i: t.CSizeT = 0 + while i < self.__capacity__: + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY: + if first_tombstone < self.__capacity__: + return first_tombstone + return idx + if sh == _HT_TOMBSTONE: + if first_tombstone >= self.__capacity__: + first_tombstone = idx + else: + if sh == h: + sk: str = self._slot_key(idx) + if string.strcmp(sk, key) == 0: + return idx + idx = (idx + 1) & mask + i += 1 + if first_tombstone < self.__capacity__: + return first_tombstone + return self.__capacity__ + + def _resize(self, new_cap: t.CSizeT): + """Resize table and rehash all entries.""" + old_slots: t.CVoid | t.CPtr = self.__slots__ + old_cap: t.CSizeT = self.__capacity__ + new_slots: t.CVoid | t.CPtr = self.__mbuddy__.alloc(new_cap * _HT_SLOT_SIZE) + if new_slots == None: + return + string.memset(new_slots, 0, new_cap * _HT_SLOT_SIZE) + self.__slots__ = new_slots + self.__capacity__ = new_cap + self.__count__ = 0 + self.__tombstones__ = 0 + i: t.CSizeT = 0 + while i < old_cap: + old_h_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(old_slots) + i * _HT_SLOT_SIZE) + h: t.CUInt64T = old_h_ptr[0] + if h != _HT_EMPTY and h != _HT_TOMBSTONE: + old_k_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(old_slots) + i * _HT_SLOT_SIZE + 8) + old_v_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(old_slots) + i * _HT_SLOT_SIZE + 16) + k: str = old_k_ptr[0] + v: t.CPtr = old_v_ptr[0] + idx: t.CSizeT = self._find_slot(k, h) + self._set_slot(idx, h, k, v) + self.__count__ += 1 + i += 1 + + def __setitem__(self, key: str, val: t.CNeedPtr): + """Insert or update key-value pair. val automatically decays to pointer (t.CNeedPtr: no conversion if already pointer).""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + if sh == _HT_TOMBSTONE: + self.__tombstones__ -= 1 + self._set_slot(idx, h, key, val) + self.__count__ += 1 + # Resize when load factor > 0.75 + load: t.CSizeT = self.__count__ + self.__tombstones__ + if load * 4 >= self.__capacity__ * 3: + self._resize(self.__capacity__ * 2) + else: + self._set_slot(idx, h, key, val) + + def __getitem__(self, key: str) -> t.CPtr: + """Lookup key and return value pointer. Returns None if key not found.""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return None + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + return None + v: t.CPtr = self._slot_value(idx) + return v + + def __contains__(self, key: str) -> t.CInt: + """Check whether key exists in table.""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return 0 + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + return 0 + return 1 + + def __delitem__(self, key: str) -> t.CInt: + """Delete entry by key. Return 1 on success, 0 if key not present.""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return 0 + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + return 0 + h_ptr: t.CUInt64T | t.CPtr = (t.CVoid | t.CPtr)(t.CUInt64T(self.__slots__) + idx * _HT_SLOT_SIZE) + h_ptr[0] = _HT_TOMBSTONE + self.__count__ -= 1 + self.__tombstones__ += 1 + return 1 + + def __len__(self) -> t.CSizeT: + return self.__count__ + + def __iter__(self) -> HashTable | t.CPtr: + self.__iter_index__ = 0 + return self + + def __next__(self) -> str: + while self.__iter_index__ < self.__capacity__: + idx: t.CSizeT = self.__iter_index__ + self.__iter_index__ = idx + 1 + sh: t.CUInt64T = self._slot_hash(idx) + if sh != _HT_EMPTY and sh != _HT_TOMBSTONE: + return self._slot_key(idx) + raise StopIteration + + def get(self, key: str, default: t.CPtr) -> t.CPtr: + """Return value pointer; return default pointer if key not found.""" + h: t.CUInt64T = _fnv1a_hash(key) + idx: t.CSizeT = self._find_slot(key, h) + if idx >= self.__capacity__: + return default + sh: t.CUInt64T = self._slot_hash(idx) + if sh == _HT_EMPTY or sh == _HT_TOMBSTONE: + return default + return self._slot_value(idx) + + def set_int(self, key: str, val: int): + """Store integer value. Value is copied into mbuddy-managed storage.""" + storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8) + int_ptr: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr) + int_ptr[0] = val + self[key] = storage + + def set_str(self, key: str, val: str): + """Store string value. Directly store the string pointer.""" + self[key] = val diff --git a/hello.vp b/hello.vp new file mode 100644 index 0000000..248bb67 --- /dev/null +++ b/hello.vp @@ -0,0 +1,5 @@ +import stdio + + +def helloworld(): + stdio.printf("Hello, world!\n") diff --git a/json/__init__.vp b/json/__init__.vp new file mode 100644 index 0000000..b937cea --- /dev/null +++ b/json/__init__.vp @@ -0,0 +1,237 @@ +import t, c +from stdint import * +import memhub +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: memhub.MemManager | 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: memhub.MemManager | 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: memhub.MemManager | 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: memhub.MemManager | 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: memhub.MemManager | 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: memhub.MemManager | 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: memhub.MemManager | 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: memhub.MemManager | 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: memhub.MemManager | 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: memhub.MemManager | 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/json/__parser.vp b/json/__parser.vp new file mode 100644 index 0000000..2c9a300 --- /dev/null +++ b/json/__parser.vp @@ -0,0 +1,291 @@ +import t, c +from stdint import * +import memhub +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: memhub.MemManager | t.CPtr + + def __init__(self, src: t.CChar | t.CPtr, pool: memhub.MemManager | 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: memhub.MemManager | 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/json/__writer.vp b/json/__writer.vp new file mode 100644 index 0000000..4b6435b --- /dev/null +++ b/json/__writer.vp @@ -0,0 +1,119 @@ +import t, c +from stdint import * +import memhub +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: memhub.MemManager | 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: memhub.MemManager | 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/linkedlist.vp b/linkedlist.vp new file mode 100644 index 0000000..770a6ee --- /dev/null +++ b/linkedlist.vp @@ -0,0 +1,479 @@ +import t, c +from stdint import * + + +# ============================================================ +# LinkedNode: Non-polymorphic base class (@t.NoVTable) +# +# Subclasses inheriting from this class gain standard linked list and tree capabilities: +# - Bidirectional sibling links (next/prev) → O(1) removal +# - Parent-child tree structure (child/last_child/parent) → O(1) child appending +# - Child counter (child_count) +# +# Fields are flattened and embedded into subclasses with no vtable overhead +# (equivalent to non-polymorphic inheritance in C++). +# OOP methods are automatically wrapped for subclasses via _generate_inherited_method_wrappers +# (self pointer cast to base type before invocation). Inherited methods can be called directly by subclasses. +# +# Usage: +# class MyNode(LinkedNode): +# value: t.CInt +# root: MyNode = MyNode() +# child: MyNode = MyNode() +# root.append(child) # OOP invocation, self = root +# child.detach() # Remove self from sibling chain +# ============================================================ +@t.NoVTable +class LinkedNode: + next: "LinkedNode" | t.CPtr # Next sibling node + prev: "LinkedNode" | t.CPtr # Previous sibling node (doubly linked list, O(1) removal) + child: "LinkedNode" | t.CPtr # First child node + last_child: "LinkedNode" | t.CPtr # Last child node (O(1) append) + parent: "LinkedNode" | t.CPtr # Parent node + child_count: t.CSizeT # Number of child nodes + + def append(self, node: "LinkedNode" | t.CPtr): + """Append node as the last child of self (O(1)). + + If node is already attached to any list, the caller shall invoke node.detach() prior to append. + """ + if self is None or node is None: return + node.parent = self + node.next = None + node.prev = self.last_child + if self.child is None: + self.child = node + else: + self.last_child.next = node + self.last_child = node + self.child_count += 1 + + def prepend(self, node: "LinkedNode" | t.CPtr): + """Insert node as the first child of self (O(1)).""" + if self is None or node is None: return + node.parent = self + node.prev = None + node.next = self.child + if self.child is not None: + self.child.prev = node + else: + self.last_child = node + self.child = node + self.child_count += 1 + + def insert_before(self, node: "LinkedNode" | t.CPtr, + new_node: "LinkedNode" | t.CPtr): + """Insert new_node before node (O(1)). node must be a direct child of self.""" + if self is None or node is None or new_node is None: return + new_node.parent = self + new_node.prev = node.prev + new_node.next = node + if node.prev is not None: + node.prev.next = new_node + else: + self.child = new_node + node.prev = new_node + self.child_count += 1 + + def insert_after(self, node: "LinkedNode" | t.CPtr, + new_node: "LinkedNode" | t.CPtr): + """Insert new_node after node (O(1)). node must be a direct child of self.""" + if self is None or node is None or new_node is None: return + new_node.parent = self + new_node.prev = node + new_node.next = node.next + if node.next is not None: + node.next.prev = new_node + else: + self.last_child = new_node + node.next = new_node + self.child_count += 1 + + def remove_child(self, node: "LinkedNode" | t.CPtr): + """Remove node from self's child linked list (O(1)). The node must be a direct child of self.""" + if self is None or node is None: + return + # Patch prev.next + if node.prev is not None: + node.prev.next = node.next + else: + self.child = node.next + # Patch next.prev + if node.next is not None: + node.next.prev = node.prev + else: + self.last_child = node.prev + # Clear sibling and parent links of node + node.next = None + node.prev = None + node.parent = None + if self.child_count > 0: + self.child_count -= 1 + + def detach(self): + """Detach self from its sibling linked list (O(1)). + + After invocation, self.next/self.prev/self.parent are cleared. The child chain remains untouched. + """ + if self is None: + return + # Patch prev.next + if self.prev is not None: + self.prev.next = self.next + elif self.parent is not None: + self.parent.child = self.next + # Patch next.prev + if self.next is not None: + self.next.prev = self.prev + elif self.parent is not None: + self.parent.last_child = self.prev + # Decrement parent child counter + if self.parent is not None: + if self.parent.child_count > 0: + self.parent.child_count -= 1 + # Clear links of self + self.next = None + self.prev = None + self.parent = None + + def unlink(self): + """Sever all links of self (siblings and parent). Child nodes are not processed recursively. + + After invocation, self becomes an isolated node, while its child chain still references original children + (the parent field of child nodes still points to self). For full isolation, the caller shall + invoke self.remove_child on each child beforehand. + """ + if self is None: + return + # First detach from sibling list + self.detach() + # Then break parent-child links + self.child = None + self.last_child = None + self.child_count = 0 + + def has_children(self) -> t.CInt: + """Return 1 if child nodes exist, otherwise return 0.""" + if self is None: + return 0 + if self.child is not None: + return 1 + return 0 + + def child_at(self, index: t.CSizeT) -> "LinkedNode" | t.CPtr: + """Return the child node at specified zero-based index (O(n)). Return None if index out of bounds.""" + if self is None: + return None + cur: "LinkedNode" | t.CPtr = self.child + i: t.CSizeT = 0 + while cur is not None: + if i == index: + return cur + i += 1 + cur = cur.next + return None + + def count_children(self) -> t.CSizeT: + """Count children by traversal (O(n)), used to validate child_count.""" + if self is None: return 0 + n: t.CSizeT = 0 + cur: "LinkedNode" | t.CPtr = self.child + while cur is not None: + n += 1 + cur = cur.next + return n + + def first_sibling(self) -> "LinkedNode" | t.CPtr: + """Return the head node of sibling linked list (traverse backward via prev pointers).""" + if self is None: return None + cur: "LinkedNode" | t.CPtr = self + while cur.prev is not None: + cur = cur.prev + return cur + + def last_sibling(self) -> "LinkedNode" | t.CPtr: + """Return the tail node of sibling linked list (traverse forward via next pointers).""" + if self is None: return None + cur: "LinkedNode" | t.CPtr = self + while cur.next is not None: + cur = cur.next + return cur + + +# ============================================================ +# SListNode: Singly linked list node (@t.NoVTable) +# +# Lightweight singly linked list with only Next pointer. No prev/parent/child. +# Suitable for queues, stacks and simple linked structures +# (such as Param/BasicBlock/Function/Line/Value in llvmlite). +# O(1) append requires caller to maintain tail pointer (append_after). +# O(n) append works with head pointer only (append). +# ============================================================ +@t.NoVTable +class SListNode: + Next: "SListNode" | t.CPtr # Next node + + def append(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: + """Append node to the end of the linked list (O(n)). Return self (head). + + If self is None, the caller shall adopt node directly as the new head. + """ + if self is None: + return node + if node is None: + return self + node.Next = None + cur: "SListNode" | t.CPtr = self + while cur.Next is not None: + cur = cur.Next + cur.Next = node + return self + + def append_after(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: + """Insert node immediately after self (O(1)). Return new tail (node). + + Caller must maintain the head pointer manually. Return node as head if self is None. + """ + if node is None: + return self + node.Next = None + if self is not None: + self.Next = node + return node + + def count(self) -> t.CSizeT: + """Calculate list length via full traversal (O(n)).""" + if self is None: + return 0 + n: t.CSizeT = 0 + cur: "SListNode" | t.CPtr = self + while cur is not None: + n += 1 + cur = cur.Next + return n + + def at(self, index: t.CSizeT) -> "SListNode" | t.CPtr: + """Return node at zero-based index (O(n)). Return None if index out of bounds.""" + if self is None: + return None + cur: "SListNode" | t.CPtr = self + i: t.CSizeT = 0 + while cur is not None: + if i == index: + return cur + i += 1 + cur = cur.Next + return None + + def remove(self, node: "SListNode" | t.CPtr) -> "SListNode" | t.CPtr: + """Remove node from list (O(n)). Return updated head. + + The Next pointer of node will be cleared. If node is the original head, return head.Next. + """ + if self is None or node is None: + return self + if self is node: + new_head: "SListNode" | t.CPtr = self.Next + self.Next = None + return new_head + cur: "SListNode" | t.CPtr = self + while cur.Next is not None: + if cur.Next is node: + cur.Next = node.Next + node.Next = None + break + cur = cur.Next + return self + + +# ============================================================ +# GSListNode[T]: Generic singly linked list node (@t.NoVTable + PEP 695 generics) +# +# Unlike SListNode (non-generic, Next: SListNode|t.CPtr), the Next field of GSListNode[T] +# is typed as T|t.CPtr. After specialization it becomes a concrete node type directly, +# eliminating downcasts. +# +# Recursive generic usage pattern (subclass inherits from self-specialized variant): +# class GNode(GSListNode[GNode]): +# value: t.CInt +# # At this point GNode.Next: GNode|t.CPtr (strongly typed, no casting required) +# +# Technical validation targets: +# 1. Recursive generics: class GNode(GSListNode[GNode]) +# 2. Combination of @t.NoVTable attribute with generics +# 3. Generic class used as field type: list: GSList[GNode] +# 4. Inheritance of generic methods (GSList[T].append available after specialization) +# ============================================================ +@t.NoVTable +class GSListNode[T]: + Next: T | t.CPtr + + +# ============================================================ +# GSList[T]: Generic singly linked list container (@t.NoVTable + PEP 695 generics) +# +# Holds Head, Tail and Count. Provides O(1) append and O(n) indexed access. +# Node type T must inherit from GSListNode[T] (to acquire the Next field). +# +# Usage: +# list: GSList[GNode] | t.CPtr = GSList[GNode]() +# list.append(node) # Method invocation, not free function +# ============================================================ +@t.NoVTable +class GSList[T]: + Head: T | t.CPtr + Tail: T | t.CPtr + Count: t.CSizeT + + def __init__(self): + self.Head = None + self.Tail = None + self.Count = 0 + + def append(self, node: T): + """Append node to the end of the list (O(1)).""" + if node is None: + return + node.Next = None + if self.Head is None: + self.Head = node + else: + self.Tail.Next = node + self.Tail = node + self.Count += 1 + + def count(self) -> t.CSizeT: + """Return node count (O(1)).""" + return self.Count + + def at(self, index: t.CSizeT) -> T | t.CPtr: + """Return node at zero-based index (O(n)). Return None if index out of bounds.""" + if self.Head is None: + return None + cur: T | t.CPtr = self.Head + i: t.CSizeT = 0 + while cur is not None: + if i == index: + return cur + i += 1 + cur = cur.Next + return None + + +# ============================================================ +# GTreeNode[T]: Generic tree node (@t.NoVTable + PEP 695 generics) +# +# Type-safe variant of LinkedNode. All pointer fields are typed T|t.CPtr. +# Capabilities provided: +# - Bidirectional sibling linked list (Next/Prev) → O(1) removal +# - Parent-child tree structure (Child/LastChild/Parent) → O(1) child appending +# - Child counter (Count) +# +# Recursive generic usage pattern (subclass inherits self-specialized variant): +# @t.CVTable +# class AST(GTreeNode[AST]): +# def kind(self) -> t.CInt: +# return 0 +# # At this point AST.Next/Prev/Child/LastChild/Parent are all AST|t.CPtr (strongly typed) +# +# Fields are flattened and embedded into subclasses with no vtable overhead +# (equivalent to non-polymorphic inheritance in C++). +# If a subclass is marked @t.CVTable, it receives its own vtable (at offset 0), +# and GTreeNode fields are laid out after the vtable. +# +# OOP methods are automatically wrapped for subclasses via _generate_inherited_method_wrappers +# (self pointer cast to base type before invocation). Inherited methods can be called directly by subclasses. +# ============================================================ +@t.NoVTable +class GTreeNode[T]: + Next: T | t.CPtr # Next sibling node + Prev: T | t.CPtr # Previous sibling node (doubly linked list, O(1) removal) + Child: T | t.CPtr # First child node + LastChild: T | t.CPtr # Last child node (O(1) append) + Parent: T | t.CPtr # Parent node + Count: t.CSizeT # Number of child nodes + + def append(self, node: T | t.CPtr): + """Append node as the last child of self (O(1)). + + If node is already attached to any list, the caller shall invoke node.detach() prior to append. + """ + if self is None or node is None: + return + node.Parent = self + node.Next = None + node.Prev = self.LastChild + if self.Child is None: + self.Child = node + else: + self.LastChild.Next = node + self.LastChild = node + self.Count += 1 + + def prepend(self, node: T | t.CPtr): + """Insert node as the first child of self (O(1)).""" + if self is None or node is None: + return + node.Parent = self + node.Prev = None + node.Next = self.Child + if self.Child is not None: + self.Child.Prev = node + else: + self.LastChild = node + self.Child = node + self.Count += 1 + + def detach(self): + """Detach self from its sibling linked list (O(1)). + + After invocation, self.Next/self.Prev/self.Parent are cleared. The child chain remains untouched. + """ + if self is None: + return + if self.Prev is not None: + self.Prev.Next = self.Next + elif self.Parent is not None: + self.Parent.Child = self.Next + if self.Next is not None: + self.Next.Prev = self.Prev + elif self.Parent is not None: + self.Parent.LastChild = self.Prev + if self.Parent is not None: + if self.Parent.Count > 0: + self.Parent.Count -= 1 + self.Next = None + self.Prev = None + self.Parent = None + + def has_children(self) -> t.CInt: + """Return 1 if child nodes exist, otherwise return 0.""" + if self is None: + return 0 + if self.Child is not None: + return 1 + return 0 + + def child_at(self, index: t.CSizeT) -> T | t.CPtr: + """Return the child node at specified zero-based index (O(n)). Return None if index out of bounds.""" + if self is None: + return None + cur: T | t.CPtr = self.Child + i: t.CSizeT = 0 + while cur is not None: + if i == index: + return cur + i += 1 + cur = cur.Next + return None + + def count_children(self) -> t.CSizeT: + """Count children by traversal (O(n)), used to validate Count field.""" + if self is None: + return 0 + n: t.CSizeT = 0 + cur: T | t.CPtr = self.Child + while cur is not None: + n += 1 + cur = cur.Next + return n diff --git a/llvmlite/README.md b/llvmlite/README.md new file mode 100644 index 0000000..9d2e534 --- /dev/null +++ b/llvmlite/README.md @@ -0,0 +1,301 @@ +# llvmlite 设计方案 + +用 TransPyC 自身实现的轻量级 LLVM IR 文本生成库,替代 Python `llvmlite` 依赖,为自举(见 `wiki/13-bootstrapping.md` 路径 B)铺路。 + +## 1. 目标与定位 + +- **输入**:类型/值/指令的语义对象 +- **输出**:合法的 LLVM IR 文本(`.ll`),可直接喂给 `llc` +- **不做什么**:不解析 IR、不做优化、不绑定 LLVM C API(纯文本生成) +- **自举约束**:本库必须能用当前 TransPyC 编译器完整编译,不得依赖任何 Python 运行时 + +## 2. 核心设计决策 + +### 2.1 类型系统用 `t.REnum`(tagged union) + +LLVM 类型变体少、无通用字段、字段都是指针/小整数、操作主要通过 `match` 分派 —— 完全契合 REnum 的 tag+union 模型。 + +### 2.2 指令 opcode 用 `t.CEnum` + +指令类别(Binary/Unary/Cast/Memory/Terminator/Compare)与具体 opcode(Add/Sub/Load/Store/Br/Ret/...)用 `t.CEnum` 组织,类型安全且零开销。 + +### 2.3 IR 文本生成用 `viperlib.snprintf` + +所有 IR 文本通过 `viperlib.snprintf(buf, size, fmt, *args)` 格式化写入缓冲区,避免手写逐字符拼接。`snprintf` 已支持宽度/精度/符号/`%s`/`%d`/`%x` 等,足够覆盖 IR 语法。 + +### 2.4 对象分配用普通类 + `mpool` + +像 `mbuddy` 一样用普通类(无 `__new__`),由调用方注入 `mpool.MPool` 做批量分配。库内部不持有全局 `mbuddy`,遵循项目约定(`_mbuddy` 指针由 `os.vp` 或调用方设置)。 + +--- + +## 3. 为什么 AST 不用 REnum,而 llvmlite 用? + +用户质疑:REnum 是 tag+union(Rust enum),配合 `match` 模式匹配,按理很适合 AST。下面解释两者的适配性差异。 + +### 3.1 REnum 的硬限制(来自 `HandlesClassDef._EmitREnumLlvm`) + +1. **无通用字段共享**:每个 variant 独立声明字段,通用字段(如 `lineno`/`child`/`next`)必须在每 variant 重复声明。 +2. **共享最大变体尺寸**:布局为 `{ i32 __tag, }`,小变体浪费内存。 +3. **payload 仅位置绑定**:`match` 通过位置绑定 payload,不能直接 `node.child` 属性访问 payload 字段。 +4. **无方法**:variant 不能挂方法。 + +### 3.2 AST 不适合 REnum 的四个原因 + +| 维度 | AST 需求 | REnum 限制 | 冲突 | +|------|----------|------------|------| +| 变体数量 | 70+ 节点类型 | 共享最大变体尺寸 | 内存膨胀(每节点都占最大变体空间) | +| 通用字段 | lineno/child/next/parent 等 ~8 个字段全节点共享 | 无通用字段共享 | 要么每 variant 重复声明(冗长),要么放弃统一访问 | +| 访问模式 | 频繁直接 `node.child`/`node.next`/`node.lineno` | payload 仅位置绑定,需 match 分派 | 遍历代码爆炸(每次访问都要 match) | +| 字段复用 | `int_val`/`str_val`/`op` 等字段按 vtype 复用语义 | 每 variant 独立 payload | 无法复用 | + +AST 采用"胖节点"设计(所有节点共用一个 `AST` struct,用 `vtype` 区分):一次 `malloc`、统一链表遍历(`child`/`next`)、字段复用。这与 REnum"每变体独立 payload"的哲学根本冲突。 + +### 3.3 llvmlite 的 LLVMType 适合 REnum 的原因 + +| 维度 | LLVMType 需求 | REnum 特性 | 契合度 | +|------|---------------|------------|--------| +| 变体数量 | ~10 个(Int/Ptr/Func/Array/Struct/Void/Float/Label/...) | 共享最大变体尺寸 | 浪费可接受(最大变体 ~24 字节) | +| 通用字段 | 无(每变体字段不同) | 无通用字段共享 | 完美匹配 | +| 访问模式 | 类型操作天然通过 match 分派("是 Int 取 bits,是 Ptr 取 pointee") | payload 位置绑定 + match | 天然契合 | +| 字段尺寸 | 都是指针(8B)或小整数(4B) | 共享最大变体 | 浪费小 | + +**结论**:REnum 是"少变体、无共性、match 分派"场景的最佳工具 —— llvmlite 类型系统正好如此,AST 正好相反。 + +--- + +## 4. 文件结构 + +``` +includes/llvmlite/ +├── __init__.vp # 公共导出 + 便捷工厂函数 +├── __types.vp # LLVMType (REnum) + 类型构造/打印 +├── __values.vp # Value/Constant/SSA 值表示 +├── __module.vp # Module 容器(函数列表 + 目标三元组 + 输出 .ll) +├── __function.vp # Function + BasicBlock + 参数管理 +├── __builder.vp # IRBuilder(指令发射 + SSA 命名 + 块跳转) +└── README.md # 本文件 +``` + +### 职责划分 + +- `__types.vp`:`LLVMType` REnum 定义 + `TypePrint(buf, ty)` 将类型序列化为 IR 文本(如 `i32`/`i32*`/`{i32, i8*}`) +- `__values.vp`:`Value` 表示一个 SSA 值(`%0`/`%result`/常量),含类型指针 + 名字 + 是否常量 +- `__module.vp`:`Module` 持有函数链表 + 目标三元组 + 数据布局,`ModulePrint` 输出完整 `.ll` +- `__function.vp`:`Function` 持有基本块链表 + 参数 + 返回类型;`BasicBlock` 持有指令文本缓冲 +- `__builder.vp`:`IRBuilder` 游标式 API,`build_add`/`build_load`/`build_br`/... 发射指令到当前块 + +--- + +## 5. 类型系统设计(REnum) + +```python +import t +from stdint import * + +class LLVMType(t.REnum): + # 变体 Int:整数类型 + IntBits: t.CInt # 位宽 1/8/16/32/64/128 + + # 变体 Ptr:指针类型 + PtrPointee: LLVMType | t.CPtr # 指向的类型(自引用用指针) + + # 变体 Func:函数类型 + FuncRet: LLVMType | t.CPtr # 返回类型 + FuncParams: LLVMType | t.CPtr # 参数类型链表头 + FuncPCount: t.CInt # 参数数量 + + # 变体 Array:数组类型 + ArrayElem: LLVMType | t.CPtr # 元素类型 + ArrayCount: t.CInt # 元素数量 + + # 变体 Struct:结构体类型 + StructHead: LLVMType | t.CPtr # 字段类型链表头 + StructCount: t.CInt # 字段数量 + + # 变体 Float:浮点类型 + FloatBits: t.CInt # 16/32/64/128 + + # 变体 Void / Label / Metadata:无 payload + # (REnum 允许空变体,仅靠 __tag 区分) +``` + +### 类型工厂(`__init__.vp` 导出) + +```python +def Int1() -> LLVMType | t.CPtr: ... # i1 +def Int8() -> LLVMType | t.CPtr: ... # i8 +def Int32() -> LLVMType | t.CPtr: ... # i32 +def Int64() -> LLVMType | t.CPtr: ... # i64 +def Ptr(pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr: ... +def Func(ret: LLVMType | t.CPtr, params: LLVMType | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr: ... +def Void() -> LLVMType | t.CPtr: ... +``` + +### 类型打印(match 分派) + +```python +def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, ty: LLVMType | t.CPtr): + match ty: + case LLVMType.Int: # 位置绑定 IntBits + viperlib.snprintf(buf, size, "i%d", ty.IntBits) + case LLVMType.Ptr: # 位置绑定 PtrPointee + TypePrint(inner, size2, ty.PtrPointee) + # 拼接 "*" + case LLVMType.Func: + # 打印 ret (params) + case LLVMType.Void: + string.strcpy(buf, "void") + ... +``` + +--- + +## 6. Value / SSA 设计 + +```python +class Value: + Ty: LLVMType | t.CPtr # 值的类型 + Name: t.CChar | t.CPtr # SSA 名("%0"/"%result")或常量文本 + IsConst: t.CInt # 1=常量字面量,0=SSA 临时值 + Next: Value | t.CPtr # 链表(函数内的值池) +``` + +`IRBuilder` 维护一个递增的 `%N` 计数器,每发射一条产生结果的指令就分配一个新名。 + +--- + +## 7. IRBuilder 设计 + +游标式 API,跟踪当前 `BasicBlock`,发射指令文本到块的缓冲区。 + +```python +class IRBuilder: + Func: Function | t.CPtr # 所属函数 + CurBlock: BasicBlock | t.CPtr # 当前插入点 + Counter: t.CInt # SSA 名计数器 + + def build_add(self, lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + # 1. 分配 SSA 名 %N + # 2. snprintf(buf, size, " %%%d = add %s %s, %s\n", N, ty, lhs, rhs) + # 3. 追加到 CurBlock 缓冲 + # 4. 返回新 Value + + def build_load(self, ty: LLVMType | t.CPtr, ptr: Value | t.CPtr) -> Value | t.CPtr: ... + def build_store(self, val: Value | t.CPtr, ptr: Value | t.CPtr): ... + def build_br(self, target: BasicBlock | t.CPtr): ... + def build_cond_br(self, cond: Value | t.CPtr, then: BasicBlock | t.CPtr, else_: BasicBlock | t.CPtr): ... + def build_ret(self, val: Value | t.CPtr): ... + def build_alloca(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr: ... + def build_gep(self, ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: ... + def build_call(self, callee: t.CChar | t.CPtr, args: Value | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr: ... +``` + +### 指令 opcode(CEnum) + +```python +class IROp(t.CEnum): + # Terminator + Ret: t.CEnum = 1 + Br: t.CEnum = 2 + CondBr: t.CEnum = 3 + Switch: t.CEnum = 4 + # Binary + Add: t.CEnum = 10 + Sub: t.CEnum = 11 + Mul: t.CEnum = 12 + SDiv: t.CEnum = 13 + # Memory + Load: t.CEnum = 20 + Store: t.CEnum = 21 + Alloca: t.CEnum = 22 + Gep: t.CEnum = 23 + # Cast + BitCast: t.CEnum = 30 + SExt: t.CEnum = 31 + Trunc: t.CEnum = 32 + # Compare + ICmp: t.CEnum = 40 + # Call + Call: t.CEnum = 50 +``` + +--- + +## 8. IR 文本生成(snprintf 用法) + +每条指令发射用 `viperlib.snprintf` 格式化到块缓冲区。示例: + +```python +import viperlib + +def _emit_add(block: BasicBlock | t.CPtr, name: t.CChar | t.CPtr, + ty_str: t.CChar | t.CPtr, lhs: t.CChar | t.CPtr, rhs: t.CChar | t.CPtr): + line: t.CChar | t.CPtr = mpool.alloc(128) # 行缓冲 + viperlib.snprintf(line, 128, " %s = add %s %s, %s\n", name, ty_str, lhs, rhs) + _block_append(block, line) +``` + +### Module 输出 + +```python +def ModulePrint(mod: Module | t.CPtr, out_path: t.CChar | t.CPtr): + # 1. 写头部:target triple / datalayout + # 2. 遍历函数,写 declare/define + # 3. 每函数:签名 + 基本块 + 指令 + # 用 snprintf 拼接,写到文件(viperio 或 w32/win32file) +``` + +--- + +## 9. 内存管理 + +- 库内所有对象从 `mpool.MPool` 分配(像 `ast` 库一样) +- `IRBuilder`/`Module`/`Function` 不持有 `mbuddy`,由调用方传入 `mpool` +- 文本缓冲区按行分配(每指令一行,128 字节起步),避免频繁 realloc + +--- + +## 10. 基础构建范围(第一阶段) + +最小可用集,能生成一个完整的小程序 IR: + +1. **类型**:`IntType`(1/8/16/32/64) + `PointerType` + `FunctionType` + `VoidType` + `StructType` +2. **值**:`Value` + 常量整数字面量 +3. **Module/Function/BasicBlock**:容器与链表 +4. **IRBuilder** 指令子集: + - `alloca` / `load` / `store` + - `add` / `sub` / `mul` / `sdiv` + - `icmp` (eq/ne/sgt/sge/slt/sle) + - `br` / `cond_br` / `ret` + - `call`(外部函数) + - `bitcast` / `sext` / `trunc` + - `getelementptr` +5. **ModulePrint**:输出完整 `.ll` 文件 + +### 后续扩展路线 + +- **第二阶段**:浮点指令、`phi` 节点、`switch`、字符串常量全局、属性(`nounwind`/`nocapture`) +- **第三阶段**:内联汇编、`atomic` 指令、`va_arg`、精确的 SSA 验证(支配边界、phi 完整性) +- **第四阶段**:对接 TransPyC 的 `LLVMCG`,替换 Python `llvmlite`,完成路径 B 自举 + +--- + +## 11. 测试计划 + +独立测试项目(`Test/LLvmLiteTest/`): + +1. **类型打印测试**:构造各 `LLVMType`,`TypePrint` 输出,对比预期字符串 +2. **小函数生成**:用 `IRBuilder` 生成 `i32 add(i32 a, i32 b) { ret i32 %r }`,`ModulePrint` 写 `.ll`,用 `llc` 编译验证语法合法 +3. **match 分派测试**:构造各变体 `LLVMType`,`match` 正确绑定 payload +4. **snprintf 格式测试**:验证 `%d`/`%s`/`%x` 在 IR 文本中的正确性 + +--- + +## 12. 与现有架构的对接点 + +- **`lib/core/Codegen/LLVMCG.py`**:当前用 Python `llvmlite` 生成 IR,自举时改用本库 +- **`includes/viperlib.vp`**:提供 `snprintf` / `sprintf` +- **`includes/mpool.vp`**:提供 `MPool` 内存池 +- **`includes/string.vp`**:提供 `strcpy`/`strlen`/`memcpy` +- **`includes/ast/`**:参考其"胖节点 + mpool + CEnum 常量"的组织方式(但类型系统用 REnum 而非胖节点) diff --git a/llvmlite/__builder.vp b/llvmlite/__builder.vp new file mode 100644 index 0000000..8c949a9 --- /dev/null +++ b/llvmlite/__builder.vp @@ -0,0 +1,1827 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +import stdio +import stdlib +from linkedlist import GSListNode, GSList +from .__types import LLVMType, TypePrint +from .__values import Value, new_value, SSAValue +from .__function import Function, BasicBlock, block_append_text, block_set_terminated, block_get_terminated, function_move_block_to_end, _ll_name_needs_quote, block_insert_text_before_terminator + +# ============================================================ +# IRBuilder: 游标式 IR 指令发射器 +# +# 跟踪当前 BasicBlock,将指令文本追加到块的指令链表。 +# 维护递增的 SSA 名计数器(%0, %1, %2, ...)。 +# +# 用法: +# builder = new_builder(pool, func) +# builder.PositionAtEnd(entry_block) +# a = builder.build_alloca(i32_ty) +# b = builder.build_alloca(i32_ty) +# builder.build_store(ConstInt(42), a) +# r = builder.build_load(i32_ty, a) +# builder.build_ret(r) +# +# 注意: 加 @t.NoVTable 以与硬编码 BUILDER_SIZE=32 保持一致 +# (方法以实例方法实现,无虚表;文件末尾的同名顶层函数为一行委托)。 +# ============================================================ +@t.NoVTable +class IRBuilder: + Pool: memhub.MemBuddy | t.CPtr # 内存池 + Func: Function | t.CPtr # 所属函数 + CurBlock: BasicBlock | t.CPtr # 当前插入点 + Counter: t.CInt # SSA 名计数器 + + # ============================================================ + # 内部辅助 + # ============================================================ + def _alloc_ssa_name(self) -> t.CChar | t.CPtr: + """分配一个 SSA 名字符串 "%N" 并递增计数器""" + pool: memhub.MemBuddy | t.CPtr = self.Pool + buf: t.CChar | t.CPtr = pool.alloc(16) + if buf is None: return None + viperlib.snprintf(buf, 16, "%%%d", self.Counter) + self.Counter += 1 + return buf + + + def _type_str(self, ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr: + """获取类型的 IR 文本(从 pool 分配 512 字节缓冲区) + + 注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节, + 必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。 + """ + pool: memhub.MemBuddy | t.CPtr = self.Pool + buf: t.CChar | t.CPtr = pool.alloc(512) + if buf is None: return None + buf[0] = '\0' + TypePrint(buf, 512, ty, pool) + return buf + + + def _emit(self, text: t.CChar | t.CPtr): + """将指令文本追加到当前块""" + if self is None or self.CurBlock is None: return + block_append_text(self.Pool, self.CurBlock, text) + + + def _mark_terminated(self): + """标记当前块已终止""" + if self is None or self.CurBlock is None: return + block_set_terminated(self.CurBlock, 1) + + + def _build_binop(self, op: t.CChar | t.CPtr, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """二元运算通用实现""" + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(lhs.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = %s %s %s, %s", name, op, ty_s, lhs.Name, rhs.Name) + self._emit(line) + return SSAValue(pool, lhs.Ty, name) + + + # ============================================================ + # 块定位 + # ============================================================ + def position_at_end(self, block: BasicBlock | t.CPtr): + """将插入点设为 block 的末尾,并把 block 移到函数块链表末尾。 + + 移动 block 是为了保证 BB 文本输出顺序与控制流(position)顺序一致, + 避免 SSA 名在文本中非单调递增导致 llc 编译失败。 + """ + if self is None: return + self.CurBlock = block + if self.Func is not None: + function_move_block_to_end(self.Func, block) + + + def builder_cur_block_is_terminated(self) -> t.CInt: + """检查当前块的 IsTerminated 标志 + + 通过 block_get_terminated 辅助函数访问,避免链式属性 + self.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque + 导致的 GEP 静默跳过问题。 + """ + if self is None or self.CurBlock is None: + return 1 + return block_get_terminated(self.CurBlock) + + + # ============================================================ + # 内存指令 + # ============================================================ + def build_alloca(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = alloca + + 返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。 + 注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退), + 因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = alloca %s", name, ty_s) + self._emit(line) + + # 结果类型是 ty* + result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty) + result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_alloca_aligned(self, ty: LLVMType | t.CPtr, + align: int) -> Value | t.CPtr: + """%N = alloca , align N + + 返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。 + align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = alloca %s, align %d", name, ty_s, align) + self._emit(line) + + # 结果类型是 ty* + result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty) + result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_alloca_at_entry(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = alloca (在函数入口块生成,确保支配性) + + 在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca + 导致的支配性违规(Instruction does not dominate all uses)。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + func: Function | t.CPtr = self.Func + if func is None or func.Blocks is None: + return self.build_alloca(ty) + entry_blk: BasicBlock | t.CPtr = func.Blocks.Head + if entry_blk is None: + return self.build_alloca(ty) + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + line_text: t.CChar | t.CPtr = pool.alloc(128) + if line_text is None: return None + viperlib.snprintf(line_text, 128, "%s = alloca %s", name, ty_s) + # 在入口块终止指令之前插入 + block_insert_text_before_terminator(pool, entry_blk, line_text) + # 结果类型是 ty* + result_ty: LLVMType | t.CPtr = LLVMType.Ptr(ty) + result_ty_ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty_ptr is not None: + string.memset(result_ty_ptr, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty_ptr, result_ty) + return SSAValue(pool, result_ty_ptr, name) + + + def build_load(self, ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr) -> Value | t.CPtr: + """%N = load , """ + if self is None or ptr is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = load %s, %s %s", name, ty_s, ptr_ty_s, ptr.Name) + self._emit(line) + return SSAValue(pool, ty, name) + + + def build_store(self, val: Value | t.CPtr, ptr: Value | t.CPtr): + """store , """ + if self is None or val is None or ptr is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + val_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return + viperlib.snprintf(line, 256, "store %s %s, %s %s", val_ty_s, val.Name, ptr_ty_s, ptr.Name) + self._emit(line) + + + # ============================================================ + # 二元运算指令 + # ============================================================ + def build_add(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = add , """ + return self._build_binop("add", lhs, rhs) + + + def build_sub(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = sub , """ + return self._build_binop("sub", lhs, rhs) + + + def build_mul(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = mul , """ + return self._build_binop("mul", lhs, rhs) + + + def build_sdiv(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = sdiv , """ + return self._build_binop("sdiv", lhs, rhs) + + + def build_udiv(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = udiv , """ + return self._build_binop("udiv", lhs, rhs) + + + def build_srem(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = srem , """ + return self._build_binop("srem", lhs, rhs) + + + def build_urem(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = urem , """ + return self._build_binop("urem", lhs, rhs) + + + def build_and(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = and , """ + return self._build_binop("and", lhs, rhs) + + + def build_or(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = or , """ + return self._build_binop("or", lhs, rhs) + + + def build_xor(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = xor , """ + return self._build_binop("xor", lhs, rhs) + + + def build_shl(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = shl , """ + return self._build_binop("shl", lhs, rhs) + + + def build_lshr(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = lshr , """ + return self._build_binop("lshr", lhs, rhs) + + + def build_ashr(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = ashr , """ + return self._build_binop("ashr", lhs, rhs) + + + # ============================================================ + # 浮点二元运算指令 + # ============================================================ + def build_fadd(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fadd , """ + return self._build_binop("fadd", lhs, rhs) + + + def build_fsub(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fsub , """ + return self._build_binop("fsub", lhs, rhs) + + + def build_fmul(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fmul , """ + return self._build_binop("fmul", lhs, rhs) + + + def build_fdiv(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fdiv , """ + return self._build_binop("fdiv", lhs, rhs) + + + def build_frem(self, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = frem , """ + return self._build_binop("frem", lhs, rhs) + + + def build_fneg(self, val: Value | t.CPtr) -> Value | t.CPtr: + """%N = fneg """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return None + viperlib.snprintf(line, 128, "%s = fneg %s %s", name, ty_s, val.Name) + self._emit(line) + return SSAValue(pool, val.Ty, name) + + + # ============================================================ + # 比较指令 + # ============================================================ + def build_icmp(self, pred: t.CInt, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = icmp , + + 返回类型为 i1 的 SSA 值 + """ + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(lhs.Ty) + pred_s: t.CChar | t.CPtr = _icmp_pred_str(pred) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = icmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name) + self._emit(line) + + # 结果类型是 i1 + i1_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if i1_ty is not None: + string.memset(i1_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(i1_ty, LLVMType.Int(1)) + return SSAValue(pool, i1_ty, name) + + + def build_fcmp(self, pred: t.CInt, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fcmp , + + 返回类型为 i1 的 SSA 值 + """ + if self is None or lhs is None or rhs is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(lhs.Ty) + pred_s: t.CChar | t.CPtr = _fcmp_pred_str(pred) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fcmp %s %s %s, %s", name, pred_s, ty_s, lhs.Name, rhs.Name) + self._emit(line) + + # 结果类型是 i1 + i1_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if i1_ty is not None: + string.memset(i1_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(i1_ty, LLVMType.Int(1)) + return SSAValue(pool, i1_ty, name) + + + # ============================================================ + # 终止指令 + # ============================================================ + def build_br(self, target: BasicBlock | t.CPtr): + """br label %""" + if self is None or target is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + line: t.CChar | t.CPtr = pool.alloc(64) + if line is None: return + viperlib.snprintf(line, 64, "br label %%%s", target.Name) + self._emit(line) + self._mark_terminated() + + + def build_cond_br(self, cond: Value | t.CPtr, + then_blk: BasicBlock | t.CPtr, else_blk: BasicBlock | t.CPtr): + """br i1 , label %, label %""" + if self is None or cond is None or then_blk is None or else_blk is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return + viperlib.snprintf(line, 128, "br i1 %s, label %%%s, label %%%s", + cond.Name, then_blk.Name, else_blk.Name) + self._emit(line) + self._mark_terminated() + + + def build_ret(self, val: Value | t.CPtr): + """ret """ + if self is None or val is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + line: t.CChar | t.CPtr = pool.alloc(128) + if line is None: return + viperlib.snprintf(line, 128, "ret %s %s", ty_s, val.Name) + self._emit(line) + self._mark_terminated() + + + def build_ret_void(self): + """ret void""" + if self is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + line: t.CChar | t.CPtr = pool.alloc(16) + if line is None: return + string.strcpy(line, "ret void") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # 调用指令 + # ============================================================ + def build_call(self, callee: t.CChar | t.CPtr, + args: Value | t.CPtr, arg_count: t.CInt, + ret_ty: LLVMType | t.CPtr, + is_variadic: t.CInt = 0) -> Value | t.CPtr: + """%N = call @() + + args 是 Value 链表头,arg_count 是参数数量。 + 若 ret_ty 是 void,不分配 SSA 名(使用 call 而非 %N = call)。 + is_variadic=1 时发射函数类型签名(如 i32 (i8*, ...) @printf)。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + + # 判断返回类型是否为 void + is_void: t.CInt = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: t.CChar | t.CPtr = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: t.CChar | t.CPtr = self._type_str(ret_ty) + + # 构建参数列表文本 + 变参函数类型签名 + args_buf: t.CChar | t.CPtr = pool.alloc(1024) + if args_buf is None: return None + args_buf[0] = '\0' + func_ty_buf: t.CChar | t.CPtr = pool.alloc(1024) + if func_ty_buf is None: return None + func_ty_buf[0] = '\0' + cur: Value | t.CPtr = args + first: t.CInt = 1 + while cur is not None: + if first == 0: + _append_cstr(args_buf, 1024, ", ") + _append_cstr(func_ty_buf, 1024, ", ") + arg_ty_s: t.CChar | t.CPtr = self._type_str(cur.Ty) + _append_cstr(args_buf, 1024, arg_ty_s) + _append_cstr(args_buf, 1024, " ") + if cur.Name is not None: + _append_cstr(args_buf, 1024, cur.Name) + _append_cstr(func_ty_buf, 1024, arg_ty_s) + cur = cur.Next + first = 0 + if is_variadic == 1: + if first == 0: + _append_cstr(func_ty_buf, 1024, ", ") + _append_cstr(func_ty_buf, 1024, "...") + + # 构造带引号的 callee 名字(SHA1 前缀名含 '.' 或以数字开头需要加引号) + callee_buf: t.CChar | t.CPtr = pool.alloc(128) + if callee_buf is None: return None + callee_buf[0] = '\0' + if _ll_name_needs_quote(callee) != 0: + _append_cstr(callee_buf, 128, "\"") + _append_cstr(callee_buf, 128, callee) + _append_cstr(callee_buf, 128, "\"") + else: + _append_cstr(callee_buf, 128, callee) + + line: t.CChar | t.CPtr = pool.alloc(2048) + if line is None: return None + if is_variadic == 1: + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s (%s) @%s(%s)", ret_ty_s, func_ty_buf, callee_buf, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s (%s) @%s(%s)", name, ret_ty_s, func_ty_buf, callee_buf, args_buf) + else: + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s @%s(%s)", ret_ty_s, callee_buf, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s @%s(%s)", name, ret_ty_s, callee_buf, args_buf) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + + # ============================================================ + # 间接调用指令: call %callee() + # + # callee_val 是函数指针 SSA 值(必须已是函数指针类型,如 i32(i8*)*) + # ============================================================ + def build_call_indirect(self, callee_val: Value | t.CPtr, + args: Value | t.CPtr, arg_count: t.CInt, + ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = call %callee() + + 间接调用:callee_val 是函数指针 SSA 值。 + """ + if self is None or callee_val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + + is_void: t.CInt = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: t.CChar | t.CPtr = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: t.CChar | t.CPtr = self._type_str(ret_ty) + + # 构建参数列表文本 + args_buf: t.CChar | t.CPtr = pool.alloc(1024) + if args_buf is None: return None + args_buf[0] = '\0' + cur: Value | t.CPtr = args + first: t.CInt = 1 + while cur is not None: + if first == 0: + _append_cstr(args_buf, 1024, ", ") + arg_ty_s: t.CChar | t.CPtr = self._type_str(cur.Ty) + _append_cstr(args_buf, 1024, arg_ty_s) + _append_cstr(args_buf, 1024, " ") + if cur.Name is not None: + _append_cstr(args_buf, 1024, cur.Name) + cur = cur.Next + first = 0 + + line: t.CChar | t.CPtr = pool.alloc(2048) + if line is None: return None + if is_void == 1: + viperlib.snprintf(line, 2048, "call %s %s(%s)", ret_ty_s, callee_val.Name, args_buf) + else: + viperlib.snprintf(line, 2048, "%s = call %s %s(%s)", name, ret_ty_s, callee_val.Name, args_buf) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + + # ============================================================ + # 类型转换指令 + # ============================================================ + def build_bitcast(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = bitcast to """ + if self is None or val is None: + return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + if val.Name is None: + return None + viperlib.snprintf(line, 256, "%s = bitcast %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + ret: Value | t.CPtr = SSAValue(pool, to_ty, name) + return ret + + + def build_sext(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = sext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = sext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_trunc(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = trunc to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = trunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_zext(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = zext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = zext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_ptrtoint(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = ptrtoint to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = ptrtoint %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_inttoptr(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = inttoptr to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = inttoptr %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + # ============================================================ + # 浮点转换指令 + # ============================================================ + def build_fpext(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fpext to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fpext %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fptrunc(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptrunc to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptrunc %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fp2si(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptosi to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptosi %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_si2fp(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = sitofp to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = sitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_fp2ui(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptoui to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = fptoui %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + def build_ui2fp(self, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = uitofp to """ + if self is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + from_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + to_ty_s: t.CChar | t.CPtr = self._type_str(to_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = uitofp %s %s to %s", name, from_ty_s, val.Name, to_ty_s) + self._emit(line) + return SSAValue(pool, to_ty, name) + + + # ============================================================ + # GEP 指令 + # ============================================================ + def build_gep(self, elem_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: + """%N = getelementptr , , """ + if self is None or ptr is None or idx is None: return None + # 防御性检查: ptr.Ty 必须是指针类型,否则 llc 报错 + # "base of getelementptr must be a pointer" + # 当 translate_value 返回非指针值(如 i32 常量 0)时, + # 直接 GEP 会导致 llc 编译失败 + if _is_ptr_type(ptr.Ty) == 0: + return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + elem_ty_s: t.CChar | t.CPtr = self._type_str(elem_ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + idx_ty_s: t.CChar | t.CPtr = self._type_str(idx.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, %s %s", + name, elem_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name) + self._emit(line) + + # GEP 结果类型是 elem_ty* + result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty is not None: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(elem_ty)) + return SSAValue(pool, result_ty, name) + + + # ============================================================ + # build_gep_array — 数组双索引 GEP: getelementptr [N x ty], [N x ty]* %ptr, i32 0, i32 %idx + # ============================================================ + def build_gep_array(self, array_ty: LLVMType | t.CPtr, + elem_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: + """%N = getelementptr [N x elem_ty], [N x elem_ty]* %ptr, i32 0, i32 %idx + + 结果类型是 elem_ty* + """ + if self is None or ptr is None or idx is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + array_ty_s: t.CChar | t.CPtr = self._type_str(array_ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + idx_ty_s: t.CChar | t.CPtr = self._type_str(idx.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = getelementptr %s, %s %s, i32 0, %s %s", + name, array_ty_s, ptr_ty_s, ptr.Name, idx_ty_s, idx.Name) + self._emit(line) + + # GEP 结果类型是 elem_ty* + result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty is not None: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(elem_ty)) + return SSAValue(pool, result_ty, name) + + + # ============================================================ + # build_gep_struct — 结构体字段 GEP: getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + # ============================================================ + def build_gep_struct(self, struct_ty: LLVMType | t.CPtr, + field_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, field_idx: t.CInt) -> Value | t.CPtr: + """%N = getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + + 结果类型是 field_ty* + """ + if self is None or ptr is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + struct_ty_s: t.CChar | t.CPtr = self._type_str(struct_ty) + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + line: t.CChar | t.CPtr = pool.alloc(2048) + if line is None: + stdio.printf("[BGS] line alloc None\n") + return None + viperlib.snprintf(line, 2048, "%s = getelementptr %s, %s %s, i32 0, i32 %d", + name, struct_ty_s, ptr_ty_s, ptr.Name, field_idx) + self._emit(line) + + # GEP 结果类型是 field_ty* + result_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if result_ty is None: + stdio.printf("[BGS] result_ty alloc None\n") + else: + string.memset(result_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(result_ty, LLVMType.Ptr(field_ty)) + rv: Value | t.CPtr = SSAValue(pool, result_ty, name) + if rv is None: + stdio.printf("[BGS] SSAValue None\n") + return rv + + + # ============================================================ + # Phi 指令 + # ============================================================ + def build_phi(self, ty: LLVMType | t.CPtr, + incoming_head: PhiIncoming | t.CPtr, count: t.CInt) -> Value | t.CPtr: + """%N = phi [val1, %blk1], [val2, %blk2], ... + + incoming_head 是 PhiIncoming 链表头,count 是入边数量。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(ty) + + # 构建入边列表文本: [val, %blk], [val, %blk], ... + # 入边可能很多(如 30+ 个 or 链的 bool.merge),需要大缓冲区 + parts: t.CChar | t.CPtr = pool.alloc(4096) + if parts is None: return None + parts[0] = '\0' + cur: PhiIncoming | t.CPtr = incoming_head + first: t.CInt = 1 + while cur is not None: + if first == 0: + _append_cstr(parts, 4096, ", ") + _append_cstr(parts, 4096, "[") + # 使用中间变量避免链式结构体成员访问被编译器丢弃 + inc_val: Value | t.CPtr = cur.Val + if inc_val is not None: + inc_val_name: t.CChar | t.CPtr = inc_val.Name + if inc_val_name is not None: + _append_cstr(parts, 4096, inc_val_name) + _append_cstr(parts, 4096, ", %") + inc_blk: BasicBlock | t.CPtr = cur.Block + if inc_blk is not None: + inc_blk_name: t.CChar | t.CPtr = inc_blk.Name + if inc_blk_name is not None: + _append_cstr(parts, 4096, inc_blk_name) + _append_cstr(parts, 4096, "]") + cur = cur.Next + first = 0 + + line: t.CChar | t.CPtr = pool.alloc(8192) + if line is None: return None + viperlib.snprintf(line, 8192, "%s = phi %s %s", name, ty_s, parts) + self._emit(line) + return SSAValue(pool, ty, name) + + + # ============================================================ + # Switch 指令 + # ============================================================ + def build_switch(self, val: Value | t.CPtr, + default_blk: BasicBlock | t.CPtr, + cases_head: SwitchCase | t.CPtr, case_count: t.CInt): + """switch , label % [, label % ...]""" + if self is None or val is None or default_blk is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + + # 构建主体: switch , label %default + line: t.CChar | t.CPtr = pool.alloc(512) + if line is None: return + viperlib.snprintf(line, 512, "switch %s %s, label %%%s", + ty_s, val.Name, default_blk.Name) + _append_cstr(line, 512, " [") + _append_cstr(line, 512, "\n") + + # 遍历 case 列表 + cur: SwitchCase | t.CPtr = cases_head + case_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + while cur is not None: + case_line: t.CChar | t.CPtr = pool.alloc(128) + if case_line is not None: + # 使用中间变量避免链式结构体成员访问被编译器丢弃 + cv: Value | t.CPtr = cur.CaseVal + cb: BasicBlock | t.CPtr = cur.Block + if cv is not None and cb is not None: + cv_name: t.CChar | t.CPtr = cv.Name + cb_name: t.CChar | t.CPtr = cb.Name + if cv_name is not None and cb_name is not None: + viperlib.snprintf(case_line, 128, " %s %s, label %%%s\n", + case_ty_s, cv_name, cb_name) + _append_cstr(line, 512, case_line) + cur = cur.Next + + _append_cstr(line, 512, "]") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # Select 指令 + # ============================================================ + def build_select(self, cond: Value | t.CPtr, + true_val: Value | t.CPtr, false_val: Value | t.CPtr) -> Value | t.CPtr: + """%N = select i1 , , """ + if self is None or cond is None or true_val is None or false_val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ty_s: t.CChar | t.CPtr = self._type_str(true_val.Ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = select i1 %s, %s %s, %s %s", + name, cond.Name, ty_s, true_val.Name, ty_s, false_val.Name) + self._emit(line) + return SSAValue(pool, true_val.Ty, name) + + + # ============================================================ + # Unreachable 指令 + # ============================================================ + def build_unreachable(self): + """unreachable""" + if self is None: return + pool: memhub.MemBuddy | t.CPtr = self.Pool + line: t.CChar | t.CPtr = pool.alloc(16) + if line is None: return + string.strcpy(line, "unreachable") + self._emit(line) + self._mark_terminated() + + + # ============================================================ + # 原子指令 (Phase 3) + # ============================================================ + def build_atomicrmw(self, op: t.CInt, + ptr: Value | t.CPtr, val: Value | t.CPtr, + order: t.CInt) -> Value | t.CPtr: + """%N = atomicrmw , """ + if self is None or ptr is None or val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + val_ty_s: t.CChar | t.CPtr = self._type_str(val.Ty) + op_s: t.CChar | t.CPtr = _atomic_op_str(op) + ord_s: t.CChar | t.CPtr = _atomic_order_str(order) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + viperlib.snprintf(line, 256, "%s = atomicrmw %s %s %s, %s %s %s", + name, op_s, ptr_ty_s, ptr.Name, val_ty_s, val.Name, ord_s) + self._emit(line) + return SSAValue(pool, val.Ty, name) + + + def build_cmpxchg(self, ptr: Value | t.CPtr, + cmp_val: Value | t.CPtr, new_val: Value | t.CPtr, + succ_order: t.CInt, fail_order: t.CInt) -> Value | t.CPtr: + """%N = cmpxchg , , + + 返回 {, i1} 类型的 SSA 值(简化为返回 i64 表示的值对) + """ + if self is None or ptr is None or cmp_val is None or new_val is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + ptr_ty_s: t.CChar | t.CPtr = self._type_str(ptr.Ty) + cmp_ty_s: t.CChar | t.CPtr = self._type_str(cmp_val.Ty) + new_ty_s: t.CChar | t.CPtr = self._type_str(new_val.Ty) + succ_s: t.CChar | t.CPtr = _atomic_order_str(succ_order) + fail_s: t.CChar | t.CPtr = _atomic_order_str(fail_order) + line: t.CChar | t.CPtr = pool.alloc(384) + if line is None: return None + viperlib.snprintf(line, 384, "%s = cmpxchg %s %s, %s %s, %s %s %s %s", + name, ptr_ty_s, ptr.Name, cmp_ty_s, cmp_val.Name, + new_ty_s, new_val.Name, succ_s, fail_s) + self._emit(line) + # 返回原始值的类型 + return SSAValue(pool, new_val.Ty, name) + + + # ============================================================ + # va_arg 指令: 从 va_list 读取下一个变长参数 + # ============================================================ + def build_va_arg(self, + va_list_ptr: Value | t.CPtr, + arg_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = va_arg , """ + if self is None or va_list_ptr is None or arg_ty is None: + return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + name: t.CChar | t.CPtr = self._alloc_ssa_name() + va_list_ty_s: t.CChar | t.CPtr = self._type_str(va_list_ptr.Ty) + arg_ty_s: t.CChar | t.CPtr = self._type_str(arg_ty) + line: t.CChar | t.CPtr = pool.alloc(256) + if line is None: return None + if va_list_ptr.Name is None: + return None + viperlib.snprintf(line, 256, "%s = va_arg %s %s, %s", + name, va_list_ty_s, va_list_ptr.Name, arg_ty_s) + self._emit(line) + return SSAValue(pool, arg_ty, name) + + + # ============================================================ + # 内联汇编 (Phase 3) + # ============================================================ + def build_inline_asm(self, ret_ty: LLVMType | t.CPtr, + asm_text: t.CChar | t.CPtr, constraints: t.CChar | t.CPtr, + has_side_effects: t.CInt) -> Value | t.CPtr: + """%N = call asm [sideeffect] "" ""() + + 简化的内联汇编调用,无参数版本。 + """ + if self is None: return None + pool: memhub.MemBuddy | t.CPtr = self.Pool + + # 判断返回类型是否为 void + is_void: t.CInt = 0 + match ret_ty: + case LLVMType.Void(): + is_void = 1 + case _: + is_void = 0 + + name: t.CChar | t.CPtr = None + if is_void == 0: + name = self._alloc_ssa_name() + + ret_ty_s: t.CChar | t.CPtr = self._type_str(ret_ty) + line: t.CChar | t.CPtr = pool.alloc(512) + if line is None: return None + + if has_side_effects != 0: + if is_void == 1: + viperlib.snprintf(line, 512, "call %s asm sideeffect \"%s\", \"%s\"()", + ret_ty_s, asm_text, constraints) + else: + viperlib.snprintf(line, 512, "%s = call %s asm sideeffect \"%s\", \"%s\"()", + name, ret_ty_s, asm_text, constraints) + else: + if is_void == 1: + viperlib.snprintf(line, 512, "call %s asm \"%s\", \"%s\"()", + ret_ty_s, asm_text, constraints) + else: + viperlib.snprintf(line, 512, "%s = call %s asm \"%s\", \"%s\"()", + name, ret_ty_s, asm_text, constraints) + self._emit(line) + + if is_void == 1: + return None + return SSAValue(pool, ret_ty, name) + + +# ============================================================ +# 工厂函数 +# ============================================================ +# IRBuilder 硬编码大小: Pool(8) + Func(8) + CurBlock(8) + Counter(4) = 32 字节 +BUILDER_SIZE: t.CDefine = 32 + +def new_builder(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr) -> IRBuilder | t.CPtr: + """创建 IRBuilder,关联到函数 func""" + ptr: IRBuilder | t.CPtr = pool.alloc(BUILDER_SIZE) + if ptr is None: return None + string.memset(ptr, 0, BUILDER_SIZE) + ptr.Pool = pool + ptr.Func = func + ptr.CurBlock = None + ptr.Counter = 0 + return ptr + + +# ============================================================ +# 块定位 +# ============================================================ +def position_at_end(builder: IRBuilder | t.CPtr, block: BasicBlock | t.CPtr): + """将插入点设为 block 的末尾,并把 block 移到函数块链表末尾。 + + 移动 block 是为了保证 BB 文本输出顺序与控制流(position)顺序一致, + 避免 SSA 名在文本中非单调递增导致 llc 编译失败。 + """ + builder.position_at_end(block) + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _alloc_ssa_name(builder: IRBuilder | t.CPtr) -> t.CChar | t.CPtr: + """分配一个 SSA 名字符串 "%N" 并递增计数器""" + return builder._alloc_ssa_name() + + +def _type_str(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr: + """获取类型的 IR 文本(从 pool 分配 512 字节缓冲区) + + 注意:复杂结构体类型(如 13 方法的虚表 {i8*,i8*,...})可能超过 64 字节, + 必须使用足够大的缓冲区,否则 '}' 会被截断导致 IR 语法错误。 + """ + return builder._type_str(ty) + + +def _emit(builder: IRBuilder | t.CPtr, text: t.CChar | t.CPtr): + """将指令文本追加到当前块""" + builder._emit(text) + + +def _mark_terminated(builder: IRBuilder | t.CPtr): + """标记当前块已终止""" + builder._mark_terminated() + + +def builder_cur_block_is_terminated(builder: IRBuilder | t.CPtr) -> t.CInt: + """检查当前块的 IsTerminated 标志 + + 通过 block_get_terminated 辅助函数访问,避免链式属性 + builder.CurBlock.IsTerminated 在跨模块场景下 BasicBlock 为 opaque + 导致的 GEP 静默跳过问题。 + """ + return builder.builder_cur_block_is_terminated() + + +# ============================================================ +# 内存指令 +# ============================================================ +def build_alloca(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = alloca + + 返回类型为 ty* 的 SSA 值(默认对齐,由后端决定)。 + 注意:TPC 并行编译时 include 模块的函数默认参数不会预注册(argN 名回退), + 因此本函数不设默认参数;需要显式对齐请用 build_alloca_aligned。 + """ + return builder.build_alloca(ty) + + +def build_alloca_aligned(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr, + align: int) -> Value | t.CPtr: + """%N = alloca , align N + + 返回类型为 ty* 的 SSA 值;显式指定对齐(如 va_list 24 字节缓冲区需 16 对齐)。 + align 不设默认值(TPC 并行编译时 include 默认参数不预注册),调用方必须显式传入。 + """ + return builder.build_alloca_aligned(ty, align) + + +def build_alloca_at_entry(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = alloca (在函数入口块生成,确保支配性) + + 在入口块的终止指令之前插入 alloca,避免在条件分支内生成 alloca + 导致的支配性违规(Instruction does not dominate all uses)。 + """ + return builder.build_alloca_at_entry(ty) + + +def build_load(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr) -> Value | t.CPtr: + """%N = load , """ + return builder.build_load(ty, ptr) + + +def build_store(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, ptr: Value | t.CPtr): + """store , """ + builder.build_store(val, ptr) + + +# ============================================================ +# 二元运算指令 +# ============================================================ +def build_add(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = add , """ + return builder.build_add(lhs, rhs) + + +def build_sub(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = sub , """ + return builder.build_sub(lhs, rhs) + + +def build_mul(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = mul , """ + return builder.build_mul(lhs, rhs) + + +def build_sdiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = sdiv , """ + return builder.build_sdiv(lhs, rhs) + + +def build_udiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = udiv , """ + return builder.build_udiv(lhs, rhs) + + +def build_srem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = srem , """ + return builder.build_srem(lhs, rhs) + + +def build_urem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = urem , """ + return builder.build_urem(lhs, rhs) + + +def build_and(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = and , """ + return builder.build_and(lhs, rhs) + + +def build_or(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = or , """ + return builder.build_or(lhs, rhs) + + +def build_xor(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = xor , """ + return builder.build_xor(lhs, rhs) + + +def build_shl(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = shl , """ + return builder.build_shl(lhs, rhs) + + +def build_lshr(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = lshr , """ + return builder.build_lshr(lhs, rhs) + + +def build_ashr(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = ashr , """ + return builder.build_ashr(lhs, rhs) + + +# ============================================================ +# 浮点二元运算指令 +# ============================================================ +def build_fadd(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fadd , """ + return builder.build_fadd(lhs, rhs) + + +def build_fsub(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fsub , """ + return builder.build_fsub(lhs, rhs) + + +def build_fmul(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fmul , """ + return builder.build_fmul(lhs, rhs) + + +def build_fdiv(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fdiv , """ + return builder.build_fdiv(lhs, rhs) + + +def build_frem(builder: IRBuilder | t.CPtr, lhs: Value | t.CPtr, + rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = frem , """ + return builder.build_frem(lhs, rhs) + + +def build_fneg(builder: IRBuilder | t.CPtr, val: Value | t.CPtr) -> Value | t.CPtr: + """%N = fneg """ + return builder.build_fneg(val) + + +def _build_binop(builder: IRBuilder | t.CPtr, op: t.CChar | t.CPtr, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """二元运算通用实现""" + return builder._build_binop(op, lhs, rhs) + + +# ============================================================ +# 比较指令 +# ============================================================ +# ICMP 谓词常量 +ICMP_EQ: t.CDefine = 0 +ICMP_NE: t.CDefine = 1 +ICMP_SGT: t.CDefine = 2 +ICMP_SGE: t.CDefine = 3 +ICMP_SLT: t.CDefine = 4 +ICMP_SLE: t.CDefine = 5 +ICMP_UGT: t.CDefine = 6 +ICMP_UGE: t.CDefine = 7 +ICMP_ULT: t.CDefine = 8 +ICMP_ULE: t.CDefine = 9 + +# FCMP 谓词常量 +FCMP_FALSE: t.CDefine = 0 +FCMP_OEQ: t.CDefine = 1 +FCMP_OGT: t.CDefine = 2 +FCMP_OGE: t.CDefine = 3 +FCMP_OLT: t.CDefine = 4 +FCMP_OLE: t.CDefine = 5 +FCMP_ONE: t.CDefine = 6 +FCMP_ORD: t.CDefine = 7 +FCMP_UNO: t.CDefine = 8 +FCMP_UEQ: t.CDefine = 9 +FCMP_UGT: t.CDefine = 10 +FCMP_UGE: t.CDefine = 11 +FCMP_ULT: t.CDefine = 12 +FCMP_ULE: t.CDefine = 13 +FCMP_UNE: t.CDefine = 14 +FCMP_TRUE: t.CDefine = 15 + + +def _icmp_pred_str(pred: t.CInt) -> t.CChar | t.CPtr: + if pred == ICMP_EQ: return "eq" + if pred == ICMP_NE: return "ne" + if pred == ICMP_SGT: return "sgt" + if pred == ICMP_SGE: return "sge" + if pred == ICMP_SLT: return "slt" + if pred == ICMP_SLE: return "sle" + if pred == ICMP_UGT: return "ugt" + if pred == ICMP_UGE: return "uge" + if pred == ICMP_ULT: return "ult" + if pred == ICMP_ULE: return "ule" + return "eq" + + +def _fcmp_pred_str(pred: t.CInt) -> t.CChar | t.CPtr: + if pred == FCMP_FALSE: return "false" + if pred == FCMP_OEQ: return "oeq" + if pred == FCMP_OGT: return "ogt" + if pred == FCMP_OGE: return "oge" + if pred == FCMP_OLT: return "olt" + if pred == FCMP_OLE: return "ole" + if pred == FCMP_ONE: return "one" + if pred == FCMP_ORD: return "ord" + if pred == FCMP_UNO: return "uno" + if pred == FCMP_UEQ: return "ueq" + if pred == FCMP_UGT: return "ugt" + if pred == FCMP_UGE: return "uge" + if pred == FCMP_ULT: return "ult" + if pred == FCMP_ULE: return "ule" + if pred == FCMP_UNE: return "une" + if pred == FCMP_TRUE: return "true" + return "oeq" + + +def build_icmp(builder: IRBuilder | t.CPtr, pred: t.CInt, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = icmp , + + 返回类型为 i1 的 SSA 值 + """ + return builder.build_icmp(pred, lhs, rhs) + + +def build_fcmp(builder: IRBuilder | t.CPtr, pred: t.CInt, + lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr: + """%N = fcmp , + + 返回类型为 i1 的 SSA 值 + """ + return builder.build_fcmp(pred, lhs, rhs) + + +# ============================================================ +# 终止指令 +# ============================================================ +def build_br(builder: IRBuilder | t.CPtr, target: BasicBlock | t.CPtr): + """br label %""" + builder.build_br(target) + + +def build_cond_br(builder: IRBuilder | t.CPtr, cond: Value | t.CPtr, + then_blk: BasicBlock | t.CPtr, else_blk: BasicBlock | t.CPtr): + """br i1 , label %, label %""" + builder.build_cond_br(cond, then_blk, else_blk) + + +def build_ret(builder: IRBuilder | t.CPtr, val: Value | t.CPtr): + """ret """ + builder.build_ret(val) + + +def build_ret_void(builder: IRBuilder | t.CPtr): + """ret void""" + builder.build_ret_void() + + +# ============================================================ +# 调用指令 +# ============================================================ +def build_call(builder: IRBuilder | t.CPtr, callee: t.CChar | t.CPtr, + args: Value | t.CPtr, arg_count: t.CInt, + ret_ty: LLVMType | t.CPtr, + is_variadic: t.CInt = 0) -> Value | t.CPtr: + """%N = call @() + + args 是 Value 链表头,arg_count 是参数数量。 + 若 ret_ty 是 void,不分配 SSA 名(使用 call 而非 %N = call)。 + is_variadic=1 时发射函数类型签名(如 i32 (i8*, ...) @printf)。 + """ + return builder.build_call(callee, args, arg_count, ret_ty, is_variadic) + + +# ============================================================ +# 间接调用指令: call %callee() +# +# callee_val 是函数指针 SSA 值(必须已是函数指针类型,如 i32(i8*)*) +# ============================================================ +def build_call_indirect(builder: IRBuilder | t.CPtr, callee_val: Value | t.CPtr, + args: Value | t.CPtr, arg_count: t.CInt, + ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = call %callee() + + 间接调用:callee_val 是函数指针 SSA 值。 + """ + return builder.build_call_indirect(callee_val, args, arg_count, ret_ty) + + +# ============================================================ +# 类型转换指令 +# ============================================================ +def build_bitcast(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = bitcast to """ + return builder.build_bitcast(val, to_ty) + + +def build_sext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = sext to """ + return builder.build_sext(val, to_ty) + + +def build_trunc(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = trunc to """ + return builder.build_trunc(val, to_ty) + + +def build_zext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = zext to """ + return builder.build_zext(val, to_ty) + + +def build_ptrtoint(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = ptrtoint to """ + return builder.build_ptrtoint(val, to_ty) + + +def build_inttoptr(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = inttoptr to """ + return builder.build_inttoptr(val, to_ty) + + +# ============================================================ +# 浮点转换指令 +# ============================================================ +def build_fpext(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fpext to """ + return builder.build_fpext(val, to_ty) + + +def build_fptrunc(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptrunc to """ + return builder.build_fptrunc(val, to_ty) + + +def build_fp2si(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptosi to """ + return builder.build_fp2si(val, to_ty) + + +def build_si2fp(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = sitofp to """ + return builder.build_si2fp(val, to_ty) + + +def build_fp2ui(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = fptoui to """ + return builder.build_fp2ui(val, to_ty) + + +def build_ui2fp(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + to_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = uitofp to """ + return builder.build_ui2fp(val, to_ty) + + +# ============================================================ +# GEP 指令 +# ============================================================ +def _is_ptr_type(ty: LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Ptr 类型(独立函数,避免嵌套 match 的编译器 BUG)""" + if ty is None: + return 0 + match ty: + case LLVMType.Ptr(pointee): + return 1 + case _: + return 0 + + +def build_gep(builder: IRBuilder | t.CPtr, elem_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: + """%N = getelementptr , , """ + return builder.build_gep(elem_ty, ptr, idx) + + +# ============================================================ +# build_gep_array — 数组双索引 GEP: getelementptr [N x ty], [N x ty]* %ptr, i32 0, i32 %idx +# ============================================================ +def build_gep_array(builder: IRBuilder | t.CPtr, array_ty: LLVMType | t.CPtr, + elem_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: + """%N = getelementptr [N x elem_ty], [N x elem_ty]* %ptr, i32 0, i32 %idx + + 结果类型是 elem_ty* + """ + return builder.build_gep_array(array_ty, elem_ty, ptr, idx) + + +# ============================================================ +# build_gep_struct — 结构体字段 GEP: getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx +# ============================================================ +def build_gep_struct(builder: IRBuilder | t.CPtr, struct_ty: LLVMType | t.CPtr, + field_ty: LLVMType | t.CPtr, + ptr: Value | t.CPtr, field_idx: t.CInt) -> Value | t.CPtr: + """%N = getelementptr struct_ty, struct_ty* %ptr, i32 0, i32 %field_idx + + 结果类型是 field_ty* + """ + return builder.build_gep_struct(struct_ty, field_ty, ptr, field_idx) + + +# ============================================================ +# PhiIncoming: phi 节点的入边 (value, block) 对 +# 继承 GSListNode[PhiIncoming] 获取强类型 Next +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class PhiIncoming(GSListNode[PhiIncoming]): + Val: Value | t.CPtr + Block: BasicBlock | t.CPtr + + +# PhiIncoming 硬编码大小: Next(8) + Val(8) + Block(8) = 24 字节 +PHIINC_SIZE: t.CDefine = 24 + +def new_phi_incoming(pool: memhub.MemBuddy | t.CPtr, + val: Value | t.CPtr, block: BasicBlock | t.CPtr) -> PhiIncoming | t.CPtr: + ptr: PhiIncoming | t.CPtr = pool.alloc(PHIINC_SIZE) + if ptr is None: return None + string.memset(ptr, 0, PHIINC_SIZE) + ptr.Val = val + ptr.Block = block + return ptr + + +# ============================================================ +# Phi 指令 +# ============================================================ +def build_phi(builder: IRBuilder | t.CPtr, ty: LLVMType | t.CPtr, + incoming_head: PhiIncoming | t.CPtr, count: t.CInt) -> Value | t.CPtr: + """%N = phi [val1, %blk1], [val2, %blk2], ... + + incoming_head 是 PhiIncoming 链表头,count 是入边数量。 + """ + return builder.build_phi(ty, incoming_head, count) + + +# ============================================================ +# SwitchCase: switch 指令的 case 分支 +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class SwitchCase(GSListNode[SwitchCase]): + CaseVal: Value | t.CPtr + Block: BasicBlock | t.CPtr + + +# SwitchCase 硬编码大小: Next(8) + CaseVal(8) + Block(8) = 24 字节 +SWCASE_SIZE: t.CDefine = 24 + +def new_switch_case(pool: memhub.MemBuddy | t.CPtr, + case_val: Value | t.CPtr, block: BasicBlock | t.CPtr) -> SwitchCase | t.CPtr: + ptr: SwitchCase | t.CPtr = pool.alloc(SWCASE_SIZE) + if ptr is None: return None + string.memset(ptr, 0, SWCASE_SIZE) + ptr.CaseVal = case_val + ptr.Block = block + return ptr + + +# ============================================================ +# Switch 指令 +# ============================================================ +def build_switch(builder: IRBuilder | t.CPtr, val: Value | t.CPtr, + default_blk: BasicBlock | t.CPtr, + cases_head: SwitchCase | t.CPtr, case_count: t.CInt): + """switch , label % [, label % ...]""" + builder.build_switch(val, default_blk, cases_head, case_count) + + +# ============================================================ +# Select 指令 +# ============================================================ +def build_select(builder: IRBuilder | t.CPtr, cond: Value | t.CPtr, + true_val: Value | t.CPtr, false_val: Value | t.CPtr) -> Value | t.CPtr: + """%N = select i1 , , """ + return builder.build_select(cond, true_val, false_val) + + +# ============================================================ +# Unreachable 指令 +# ============================================================ +def build_unreachable(builder: IRBuilder | t.CPtr): + """unreachable""" + builder.build_unreachable() + + +# ============================================================ +# 原子指令 (Phase 3) +# ============================================================ +# AtomicRMW 操作常量 +ATOMIC_XCHG: t.CDefine = 0 +ATOMIC_ADD: t.CDefine = 1 +ATOMIC_SUB: t.CDefine = 2 +ATOMIC_AND: t.CDefine = 3 +ATOMIC_NAND: t.CDefine = 4 +ATOMIC_OR: t.CDefine = 5 +ATOMIC_XOR: t.CDefine = 6 +ATOMIC_MAX: t.CDefine = 7 +ATOMIC_MIN: t.CDefine = 8 +ATOMIC_UMAX: t.CDefine = 9 +ATOMIC_UMIN: t.CDefine = 10 + +# 内存序常量 +ATOMIC_ORDER_NOTATOMIC: t.CDefine = 0 +ATOMIC_ORDER_UNORDERED: t.CDefine = 1 +ATOMIC_ORDER_MONOTONIC: t.CDefine = 2 +ATOMIC_ORDER_ACQUIRE: t.CDefine = 3 +ATOMIC_ORDER_RELEASE: t.CDefine = 4 +ATOMIC_ORDER_ACQ_REL: t.CDefine = 5 +ATOMIC_ORDER_SEQ_CST: t.CDefine = 6 + + +def _atomic_op_str(op: t.CInt) -> t.CChar | t.CPtr: + if op == ATOMIC_XCHG: return "xchg" + if op == ATOMIC_ADD: return "add" + if op == ATOMIC_SUB: return "sub" + if op == ATOMIC_AND: return "and" + if op == ATOMIC_NAND: return "nand" + if op == ATOMIC_OR: return "or" + if op == ATOMIC_XOR: return "xor" + if op == ATOMIC_MAX: return "max" + if op == ATOMIC_MIN: return "min" + if op == ATOMIC_UMAX: return "umax" + if op == ATOMIC_UMIN: return "umin" + return "xchg" + + +def _atomic_order_str(ord: t.CInt) -> t.CChar | t.CPtr: + if ord == ATOMIC_ORDER_UNORDERED: return "unordered" + if ord == ATOMIC_ORDER_MONOTONIC: return "monotonic" + if ord == ATOMIC_ORDER_ACQUIRE: return "acquire" + if ord == ATOMIC_ORDER_RELEASE: return "release" + if ord == ATOMIC_ORDER_ACQ_REL: return "acq_rel" + if ord == ATOMIC_ORDER_SEQ_CST: return "seq_cst" + return "monotonic" + + +def build_atomicrmw(builder: IRBuilder | t.CPtr, op: t.CInt, + ptr: Value | t.CPtr, val: Value | t.CPtr, + order: t.CInt) -> Value | t.CPtr: + """%N = atomicrmw , """ + return builder.build_atomicrmw(op, ptr, val, order) + + +def build_cmpxchg(builder: IRBuilder | t.CPtr, ptr: Value | t.CPtr, + cmp_val: Value | t.CPtr, new_val: Value | t.CPtr, + succ_order: t.CInt, fail_order: t.CInt) -> Value | t.CPtr: + """%N = cmpxchg , , + + 返回 {, i1} 类型的 SSA 值(简化为返回 i64 表示的值对) + """ + return builder.build_cmpxchg(ptr, cmp_val, new_val, succ_order, fail_order) + + +# ============================================================ +# va_arg 指令: 从 va_list 读取下一个变长参数 +# ============================================================ +def build_va_arg(builder: IRBuilder | t.CPtr, + va_list_ptr: Value | t.CPtr, + arg_ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """%N = va_arg , """ + return builder.build_va_arg(va_list_ptr, arg_ty) + + +# ============================================================ +# 内联汇编 (Phase 3) +# ============================================================ +def build_inline_asm(builder: IRBuilder | t.CPtr, ret_ty: LLVMType | t.CPtr, + asm_text: t.CChar | t.CPtr, constraints: t.CChar | t.CPtr, + has_side_effects: t.CInt) -> Value | t.CPtr: + """%N = call asm [sideeffect] "" ""() + + 简化的内联汇编调用,无参数版本。 + """ + return builder.build_inline_asm(ret_ty, asm_text, constraints, has_side_effects) + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' diff --git a/llvmlite/__function.vp b/llvmlite/__function.vp new file mode 100644 index 0000000..8e0577e --- /dev/null +++ b/llvmlite/__function.vp @@ -0,0 +1,811 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +import stdio +from linkedlist import GSListNode, GSList +from .__types import LLVMType, ParamNode, TypePrint + + +# ============================================================ +# Line: 指令文本行 +# +# 每条 LLVM IR 指令序列化为一行文本,通过链表组织。 +# 继承 GSListNode[Line] 获取强类型 Next: Line|CPtr +# +# 注意: 必须加 @t.NoVTable。否则 TransPyC 为子类添加 vtable 指针(T*), +# 但完全丢失父类 GSListNode[T] 的 Next 字段,导致 struct 布局错位, +# 所有字段访问读取垃圾值(见续 XV 会话根因分析)。 +# ============================================================ +@t.NoVTable +class Line(GSListNode[Line]): + Buf: t.CChar | t.CPtr # 行文本(NUL 结尾) + Len: t.CSizeT # 文本长度(不含 NUL) + + +# ============================================================ +# BasicBlock: 基本块 +# +# 持有名称 + 指令行链表 + 终止指令标志。 +# 继承 GSListNode[BasicBlock] 获取强类型 Next: BasicBlock|CPtr +# Lines 为 GSList[Line] 指针,提供 O(1) 追加。 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +@t.NoVTable +class BasicBlock(GSListNode[BasicBlock]): + Name: t.CChar | t.CPtr # 块名(如 "entry"/"if.then") + Lines: GSList[Line] | t.CPtr # 指令行链表容器(Head/Tail/Count) + IsTerminated: t.CInt # 1=已有终止指令(br/ret) + + +# ============================================================ +# Param: 函数参数 +# +# 继承 GSListNode[Param] 获取强类型 Next: Param|CPtr +# Attrs 存储参数属性文本(如 "noundef"/"nocapture"/"readonly"),None=无属性 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +@t.NoVTable +class Param(GSListNode[Param]): + Ty: LLVMType | t.CPtr # 参数类型 + Name: t.CChar | t.CPtr # 参数名(如 "%0"/"%a") + Attrs: t.CChar | t.CPtr # 参数属性文本(None=无属性) + + +# ============================================================ +# Function: 函数 +# +# 持有名称 + 返回类型 + 参数链表 + 基本块链表。 +# 继承 GSListNode[Function] 获取强类型 Next: Function|CPtr +# Params/Blocks 为 GSList 指针,提供 O(1) 追加。 +# Attrs 存储函数级属性文本(如 "nounwind"/"noinline"),None=无属性 +# +# 注意: 必须加 @t.NoVTable(理由同 Line)。 +# ============================================================ +@t.NoVTable +class Function(GSListNode[Function]): + Name: t.CChar | t.CPtr # 函数名 + RetTy: LLVMType | t.CPtr # 返回类型 + Params: GSList[Param] | t.CPtr # 参数链表容器 + Blocks: GSList[BasicBlock] | t.CPtr # 基本块链表容器 + IsDeclared: t.CInt # 1=仅声明(declare), 0=定义(define) + IsVarArg: t.CInt # 1=变参函数(...) + Attrs: t.CChar | t.CPtr # 函数属性文本(None=无属性) + + +# ============================================================ +# 工厂函数 +# ============================================================ +# Line 硬编码大小: Next(8) + Buf(8) + Len(8) = 24 字节 +LINE_SIZE: t.CDefine = 24 + +def new_line(pool: memhub.MemBuddy | t.CPtr, text: t.CChar | t.CPtr) -> Line | t.CPtr: + """创建一个指令行,复制 text 到新分配的缓冲区""" + ptr: Line | t.CPtr = pool.alloc(LINE_SIZE) + if ptr is None: return None + string.memset(ptr, 0, LINE_SIZE) + if text is not None: + slen: t.CSizeT = string.strlen(text) + buf: t.CChar | t.CPtr = pool.alloc(slen + 1) + if buf is not None: + string.strcpy(buf, text) + ptr.Buf = buf + ptr.Len = slen + return ptr + + +def _new_gslist(pool: memhub.MemBuddy | t.CPtr, list_size: t.CSizeT) -> t.CPtr: + """从 pool 分配并零初始化一个 GSList 容器(Head/Tail/Count 全零)""" + gsl: t.CPtr = pool.alloc(list_size) + if gsl is None: return None + string.memset(gsl, 0, list_size) + return gsl + + +# BasicBlock 硬编码大小: Next(8) + Name(8) + Lines(8) + IsTerminated(4) = 32 字节 +BLOCK_SIZE: t.CDefine = 32 + +def new_basic_block(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr: + """创建一个基本块""" + ptr: BasicBlock | t.CPtr = pool.alloc(BLOCK_SIZE) + if ptr is None: return None + string.memset(ptr, 0, BLOCK_SIZE) + ptr.Name = name + ptr.Lines = _new_gslist(pool, 24) # GSList: Head+Tail+Count + ptr.IsTerminated = 0 + return ptr + + +# Param 硬编码大小: Next(8) + Ty(8) + Name(8) + Attrs(8) = 32 字节 +PARAM_SIZE: t.CDefine = 32 + +def new_param(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + name: t.CChar | t.CPtr) -> Param | t.CPtr: + """创建一个函数参数""" + ptr: Param | t.CPtr = pool.alloc(PARAM_SIZE) + if ptr is None: return None + string.memset(ptr, 0, PARAM_SIZE) + ptr.Ty = ty + ptr.Name = name + ptr.Attrs = None + return ptr + + +# Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) = 56 字节 +FUNC_SIZE: t.CDefine = 56 + +def new_function(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr, + ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + """创建一个函数""" + ptr: Function | t.CPtr = pool.alloc(FUNC_SIZE) + if ptr is None: return None + string.memset(ptr, 0, FUNC_SIZE) + ptr.Name = name + ptr.RetTy = ret_ty + ptr.Params = _new_gslist(pool, 24) # GSList: Head+Tail+Count + ptr.Blocks = _new_gslist(pool, 24) + ptr.IsDeclared = 0 + ptr.Attrs = None + return ptr + + +# ============================================================ +# 链表操作(委托 GSList.append) +# ============================================================ +def function_add_param(func: Function | t.CPtr, param: Param | t.CPtr): + """将参数追加到函数参数链表""" + if func is None or param is None: return + if func.Params is None: return + func.Params.append(param) + + +def function_add_block(func: Function | t.CPtr, block: BasicBlock | t.CPtr): + """将基本块追加到函数块链表""" + if func is None or block is None: return + if func.Blocks is None: return + func.Blocks.append(block) + + +def function_move_block_to_end(func: Function | t.CPtr, block: BasicBlock | t.CPtr): + """将 block 移动到函数块链表末尾(保证 BB 文本顺序与控制流顺序一致)。 + + 用于解决 SSA 名非单调问题:BB 按创建顺序排列,但指令按控制流顺序生成, + 导致 SSA 编号在文本输出时非单调递增,llc 报错。 + 在 position_at_end 时调用此函数,使 BB 顺序与 position 顺序一致。 + + 注意:必须使用 GSList[BasicBlock] 带类型参数,否则 TransPyC 创建不完整 + struct 类型,导致 blocks.Head/Tail/Count 字段访问读取垃圾值。 + """ + if func is None or block is None: return + blocks: GSList[BasicBlock] | t.CPtr = func.Blocks + if blocks is None: return + + # 已经是 Tail,无需移动 + if blocks.Tail is block: + return + + # 从链表中移除 block + if blocks.Head is block: + # block 是 Head,直接后移 Head + blocks.Head = block.Next + else: + # 遍历找前驱 + prev: BasicBlock | t.CPtr = blocks.Head + while prev is not None and prev.Next is not block: + prev = prev.Next + if prev is None: + # block 不在链表中,直接 append + blocks.append(block) + return + prev.Next = block.Next + + # block.Next 由移除逻辑处理,重置为 None + block.Next = None + + # append 到末尾(不调用 blocks.append 以避免 Count 重复递增) + if blocks.Tail is not None: + blocks.Tail.Next = block + blocks.Tail = block + + +def block_append_line(block: BasicBlock | t.CPtr, line: Line | t.CPtr): + """将指令行追加到基本块""" + if block is None or line is None: return + if block.Lines is None: return + block.Lines.append(line) + + +def block_set_terminated(block: BasicBlock | t.CPtr, val: t.CInt): + """设置块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)""" + if block is None: return + block.IsTerminated = val + + +def block_get_terminated(block: BasicBlock | t.CPtr) -> t.CInt: + """获取块的终止标志(供跨模块调用,避免链式属性访问的 opaque 类型问题)""" + if block is None: + return 1 + return block.IsTerminated + + +def block_append_text(pool: memhub.MemBuddy | t.CPtr, block: BasicBlock | t.CPtr, + text: t.CChar | t.CPtr): + """创建指令行并追加到基本块""" + if block is None or text is None: return + line: Line | t.CPtr = new_line(pool, text) + if line is not None: + block_append_line(block, line) + + +def block_insert_text_before_terminator(pool: memhub.MemBuddy | t.CPtr, + block: BasicBlock | t.CPtr, + text: t.CChar | t.CPtr): + """创建指令行并插入到基本块终止指令之前 + + 如果块未终止,追加到末尾。 + 如果块已终止(有 br/ret),在终止指令之前插入,确保 alloca 等指令 + 不出现在终止指令之后。 + """ + if block is None or text is None: return + if block.Lines is None: return + line: Line | t.CPtr = new_line(pool, text) + if line is None: return + # 块未终止:直接追加 + if block.IsTerminated == 0: + block_append_line(block, line) + return + # 块已终止:在 Tail(终止指令)之前插入 + lines: GSList[Line] | t.CPtr = block.Lines + if lines.Head is None: + block_append_line(block, line) + return + # 只有一个节点:在 Head 之前插入 + if lines.Head is lines.Tail: + line.Next = lines.Head + lines.Head = line + lines.Count += 1 + return + # 找到 Tail 的前驱节点 + prev: Line | t.CPtr = lines.Head + while prev is not None and prev.Next is not lines.Tail: + prev = prev.Next + if prev is None: + # 找不到前驱,回退到追加 + block_append_line(block, line) + return + # 在 prev 和 Tail 之间插入 line + line.Next = lines.Tail + prev.Next = line + lines.Count += 1 + + +# ============================================================ +# 属性设置 +# ============================================================ +def function_set_attrs(func: Function | t.CPtr, attrs: t.CChar | t.CPtr): + """设置函数级属性文本(如 "nounwind"/"noinline")""" + if func is None: return + func.Attrs = attrs + + +def param_set_attrs(param: Param | t.CPtr, attrs: t.CChar | t.CPtr): + """设置参数属性文本(如 "noundef"/"nocapture"/"readonly")""" + if param is None: return + param.Attrs = attrs + + +# ============================================================ +# _ll_name_needs_quote - 检查 LLVM 标识符是否需要加引号 +# +# LLVM IR 规范:标识符合法字符集为 [-a-zA-Z$._][-a-zA-Z$._0-9]* +# 以数字开头或含非合法字符(如 '['、']'、' '、'@' 等)时必须用双引号包围。 +# '.' 是合法字符,不需要加引号(如 @.str、@llvm.memcpy 都不加引号)。 +# SHA1 命名空间的函数名(如 "4dad2ba72ed7ba09.GSListNode[Param]")含 '['、']', +# 需要加引号;但纯 hex+点 的名字(如 "abc.def")不需要。 +# ============================================================ +def _ll_name_needs_quote(name: str) -> t.CInt: + """检查 LLVM 标识符是否需要加引号(以数字开头或含非合法字符) + + LLVM IR 合法字符:a-z, A-Z, 0-9, -, $, ., _ + 首字符是数字时需要加引号(LLVM 要求局部/全局标识符首字符非数字,除非加引号)。 + 含其他字符(如 '['、']'、空格)时需要加引号。 + """ + if name is None: + return 0 + c0: t.CChar = name[0] + if c0 >= '0' and c0 <= '9': + return 1 + name_len: t.CSizeT = string.strlen(name) + i: t.CSizeT = 0 + while i < name_len: + ch: t.CChar = name[i] + # 合法字符:a-z, A-Z, 0-9, -, $, ., _ + if not ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or + (ch >= '0' and ch <= '9') or ch == '-' or ch == '$' or + ch == '.' or ch == '_'): + return 1 + i += 1 + return 0 + + +# ============================================================ +# RenumberSSA: 重编号函数内数字 SSA 名 +# +# 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致 +# SSA 名在文本输出中非单调递增的问题(llc 报错: +# "instruction expected to be numbered '%N' or greater")。 +# +# 现象: entry 块原指令 %0-%6 + br,alloca_at_entry 插入 %28/%41 到 br 之前, +# 文本输出顺序为 entry(%0..%6, %28, %41) → if.then(%7..%27), +# 导致 %28 出现在 %7 之前,llc 拒绝编译。 +# +# 算法: +# 1. 扫描所有 BB 指令行,按文本输出顺序收集数字 SSA 名 %N +# 2. 按首次出现顺序建立 old→new 映射(从 0 递增) +# 3. 替换所有指令行文本中的 %N 为新编号 +# +# 注意: +# - 仅重编号纯数字 SSA 名(%0, %1, ...) +# - 命名 SSA 名(%entry, %.tmp, %self)、块标签、全局符号 @N 不重编号 +# - 仅对 define(有函数体)调用,declare 无函数体无需处理 +# - 当前 TransPyV 参数多为命名(%self/%env/%n),非数字,无需重编号参数 +# ============================================================ + +# 判定字符是否为十进制数字 +def _is_digit_ch(ch: t.CChar) -> t.CInt: + """判断字符是否是 '0'-'9' + + ch 是值类型 (t.CChar = i8),TPC 已修复值类型 is None 处理: + 值类型 is None 恒为 false(生成 i1 0 常量),不会解引用空指针。 + """ + if ch is None: + return 0 + if ch >= '0' and ch <= '9': + return 1 + return 0 + + +# ============================================================ +# i32 数组的安全访问(显式字节偏移) +# +# TransPyC 的 ptr[i] 指针索引可能被当作字节索引(i8*)而非 i32* 索引, +# 导致内存损坏。必须显式计算字节偏移:addr = base + idx * 4,再转型为 i32*。 +# 参见 HandlesTranslator.py:358 的 t.CUInt64T(ptr) + offset * sizeof 用法。 +# ============================================================ +def _map_get_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt) -> t.CInt: + """读取 i32 数组 map_arr[idx](显式字节偏移 idx*4) + + 使用 (t.CInt | t.CPtr)(uint64) 强转将字节偏移转为 i32*,再用 c.Deref 解引用。 + TPC 已修复类型联合强转(_HandleTypeUnionCastLlvm 添加 fallback),此写法可用。 + """ + if map_arr is None: + return -1 + byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4 + elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off) + return c.Deref(elem_ptr) + + +def _map_set_i32(map_arr: t.CChar | t.CPtr, idx: t.CInt, val: t.CInt): + """写入 map_arr[idx] = val(i32 数组,显式字节偏移 idx*4) + + 使用 (t.CInt | t.CPtr)(uint64) 强转 + c.DerefAs 解引用赋值。 + TPC 已修复类型联合强转,此写法可用。 + """ + if map_arr is None: + return + byte_off: t.CUInt64T = t.CUInt64T(map_arr) + idx * 4 + elem_ptr: t.CInt | t.CPtr = (t.CInt | t.CPtr)(byte_off) + c.DerefAs(elem_ptr, val) + + +def _scan_max_ssa_in_text(text: t.CChar | t.CPtr, cur_max: t.CInt) -> t.CInt: + """扫描文本,找出 %N(N 为数字)中最大的 N,与 cur_max 比较返回更大值 + + 仅匹配 '%' 后紧跟数字的情况,跳过命名 SSA 名(%entry 等)。 + """ + result: t.CInt = cur_max + p: t.CChar | t.CPtr = text + while p is not None and p[0] != '\0': + if p[0] == '%': + nxt: t.CChar | t.CPtr = p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: t.CInt = string.atoi(nxt) + if num > result: + result = num + p = p + 1 + return result + + +def _find_max_ssa_number(func: Function | t.CPtr) -> t.CInt: + """遍历所有 BB 指令行,找出最大的 %N 数字;无数字 SSA 名返回 -1""" + max_n: t.CInt = -1 + if func is None or func.Blocks is None: + return max_n + blk: BasicBlock | t.CPtr = func.Blocks.Head + while blk is not None: + if blk.Lines is not None: + line: Line | t.CPtr = blk.Lines.Head + while line is not None: + if line.Buf is not None: + max_n = _scan_max_ssa_in_text(line.Buf, max_n) + line = line.Next + blk = blk.Next + return max_n + + +def _assign_new_numbers(text: t.CChar | t.CPtr, + map_arr: t.CChar | t.CPtr, + max_n: t.CInt, next_new: t.CInt) -> t.CInt: + """扫描文本,对每个 %N(数字),若 map_arr[N]==-1 则分配 next_new + + 返回更新后的 next_new。按文本首次出现顺序建立映射。 + """ + result: t.CInt = next_new + p: t.CChar | t.CPtr = text + while p is not None and p[0] != '\0': + if p[0] == '%': + nxt: t.CChar | t.CPtr = p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: t.CInt = string.atoi(nxt) + if num >= 0 and num <= max_n: + if _map_get_i32(map_arr, num) == -1: + _map_set_i32(map_arr, num, result) + result += 1 + p = p + 1 + return result + + +def _replace_ssa_numbers(text: t.CChar | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + map_arr: t.CChar | t.CPtr, + max_n: t.CInt) -> t.CChar | t.CPtr: + """构建新文本,将 %N 替换为映射后的新编号 + + 逐字符扫描:遇到 %N(数字)查映射表替换,其他字符原样复制。 + 返回新分配的缓冲区(调用方无需释放旧 Buf,pool 统一管理)。 + """ + src_len: t.CSizeT = string.strlen(text) + # 新缓冲区:最坏情况每个数字变长(位数增加),分配 src_len*2 + 64 + new_size: t.CSizeT = src_len * 2 + 64 + new_buf: t.CChar | t.CPtr = pool.alloc(new_size) + if new_buf is None: + return None + # 一次性分配数字缓冲区(循环中复用) + num_buf: t.CChar | t.CPtr = pool.alloc(16) + if num_buf is None: + new_buf[0] = '\0' + return new_buf + + dst_idx: t.CSizeT = 0 + src_p: t.CChar | t.CPtr = text + while src_p is not None and src_p[0] != '\0': + if dst_idx + 16 >= new_size: + # 缓冲区不足,截断 + break + if src_p[0] == '%': + nxt: t.CChar | t.CPtr = src_p + 1 + if nxt is not None and _is_digit_ch(nxt[0]) != 0: + num: t.CInt = string.atoi(nxt) + # 先做范围检查再读 map_arr:num 超 max_n 时 map_arr 只有 + # (max_n+1)*4 字节,先读后查会越界读远端内存 + if num >= 0 and num <= max_n: + new_num: t.CInt = _map_get_i32(map_arr, num) + if new_num != -1: + # 写入 '%' + new_buf[dst_idx] = '%' + dst_idx += 1 + # 写入新编号 + num_buf[0] = '\0' + viperlib.snprintf(num_buf, 16, "%d", new_num) + k: t.CSizeT = 0 + while num_buf[k] != '\0' and dst_idx + 1 < new_size: + new_buf[dst_idx] = num_buf[k] + dst_idx += 1 + k += 1 + # 跳过旧数字字符 + src_p = src_p + 1 + while src_p is not None and _is_digit_ch(src_p[0]) != 0: + src_p = src_p + 1 + continue + # 普通字符:直接复制 + new_buf[dst_idx] = src_p[0] + dst_idx += 1 + src_p = src_p + 1 + + new_buf[dst_idx] = '\0' + return new_buf + + +def RenumberSSA(func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """重编号函数内所有数字 SSA 名,确保按文本输出顺序单调递增 + + 在 FunctionPrint 序列化函数体之前调用。 + 仅对 define(IsDeclared==0)且 Blocks 非空 的函数生效。 + """ + if func is None or pool is None: + return + if func.IsDeclared == 1: + return # declare 无函数体 + if func.Blocks is None: + return + + # 1. 第一遍扫描:找出最大 SSA 编号 + max_n: t.CInt = _find_max_ssa_number(func) + if max_n < 0: + return # 无数字 SSA 名 + + # 2. 分配并初始化映射数组 map_arr[0..max_n] = -1 + # 用 i8* 存储(pool.alloc 返回 i8*),通过 _map_get_i32/_map_set_i32 访问。 + # 初始化为 -1:每个 i32 元素 4 字节,0xFFFFFFFF = -1(有符号 i32)。 + # 用 memset 一次性填充,避免循环内 ptr[i] 指针索引问题。 + map_bytes: t.CSizeT = (max_n + 1) * 4 # t.CInt = 4 字节 + map_arr: t.CChar | t.CPtr = pool.alloc(map_bytes) + if map_arr is None: + return + string.memset(map_arr, 0xFF, map_bytes) # 0xFF * 4 = 0xFFFFFFFF = -1 + + # 3. 第二遍扫描:按文本顺序分配新编号 + next_new: t.CInt = 0 + blk: BasicBlock | t.CPtr = func.Blocks.Head + while blk is not None: + if blk.Lines is not None: + line: Line | t.CPtr = blk.Lines.Head + while line is not None: + if line.Buf is not None: + next_new = _assign_new_numbers(line.Buf, map_arr, max_n, next_new) + line = line.Next + blk = blk.Next + + # 4. 检查是否有需要重编号的(old != new) + need_renumber: t.CInt = 0 + i: t.CInt = 0 + while i <= max_n: + v: t.CInt = _map_get_i32(map_arr, i) + if v != -1 and v != i: + need_renumber = 1 + break + i += 1 + if need_renumber == 0: + return # 编号已单调,无需替换 + + # 5. 第三遍扫描:替换所有指令行文本 + blk = func.Blocks.Head + while blk is not None: + if blk.Lines is not None: + line: Line | t.CPtr = blk.Lines.Head + while line is not None: + if line.Buf is not None: + new_buf: t.CChar | t.CPtr = _replace_ssa_numbers( + line.Buf, pool, map_arr, max_n) + if new_buf is not None: + line.Buf = new_buf + line.Len = string.strlen(new_buf) + line = line.Next + blk = blk.Next + + +# ============================================================ +# FunctionPrint: 将函数序列化为 IR 文本 +# +# 格式: +# define @() { +# : +# +# +# : +# +# } +# ============================================================ +def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT, + func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """将函数 func 序列化为 IR 文本写入 buf""" + if func is None or buf is None or size == 0: return + + # 在序列化前重编号数字 SSA 名,确保按文本输出顺序单调递增。 + # 解决 build_alloca_at_entry 在入口块终止指令前插入 alloca 导致 + # SSA 名非单调(llc 报错 "instruction expected to be numbered '%N' or greater")。 + # RenumberSSA 内部会跳过 declare 函数(IsDeclared==1),无需在此判断。 + RenumberSSA(func, pool) + + ty_buf: t.CChar | t.CPtr = pool.alloc(128) + if ty_buf is None: return + ty_buf[0] = '\0' + + # define @() + if func.IsDeclared == 1: + _append_cstr(buf, size, "declare ") + else: + # 泛型特化类方法(如 GSList[NameEntry].__before_init__):多个模块各自 + # 特化生成同名定义 → ld.lld duplicate symbol warning。特化方法代码由 + # 相同模板+类型参数生成,定义相同,输出 linkonce_odr 让链接器合并。 + if func.Name is not None and string.strchr(func.Name, 91) is not None: + _append_cstr(buf, size, "define linkonce_odr ") + else: + _append_cstr(buf, size, "define ") + ty_buf[0] = '\0' + TypePrint(ty_buf, 128, func.RetTy, pool) + _append_cstr(buf, size, ty_buf) + _append_cstr(buf, size, " @") + if func.Name is not None: + if _ll_name_needs_quote(func.Name) != 0: + _append_cstr(buf, size, "\"") + _append_cstr(buf, size, func.Name) + _append_cstr(buf, size, "\"") + else: + _append_cstr(buf, size, func.Name) + _append_cstr(buf, size, "(") + + # 参数列表(从 GSList[Param].Head 遍历) + cur: Param | t.CPtr = None + if func.Params is not None: + cur = func.Params.Head + first: t.CInt = 1 + while cur is not None: + if first == 0: + _append_cstr(buf, size, ", ") + # 参数属性(如 "noundef"/"nocapture")在类型之前 + if cur.Attrs is not None: + _append_cstr(buf, size, cur.Attrs) + _append_cstr(buf, size, " ") + ty_buf[0] = '\0' + TypePrint(ty_buf, 128, cur.Ty, pool) + _append_cstr(buf, size, ty_buf) + # declare 和 define 都打印参数名(如果有) + if cur.Name is not None: + _append_cstr(buf, size, " ") + # LLVM IR 要求参数名以 % 开头 + if cur.Name[0] != '%': + _append_cstr(buf, size, "%") + _append_cstr(buf, size, cur.Name) + cur = cur.Next + first = 0 + # 变参函数追加 ... + if func.IsVarArg == 1: + if func.Params is not None and func.Params.Head is not None: + _append_cstr(buf, size, ", ...") + else: + _append_cstr(buf, size, "...") + _append_cstr(buf, size, ")") + + # 函数级属性(如 "nounwind"/"noinline")在 ) 之后 + if func.Attrs is not None: + _append_cstr(buf, size, " ") + _append_cstr(buf, size, func.Attrs) + + if func.IsDeclared == 1: + _append_cstr(buf, size, "\n") + return + + # 函数体 + _append_cstr(buf, size, " {\n") + + blk: BasicBlock | t.CPtr = None + if func.Blocks is not None: + blk = func.Blocks.Head + while blk is not None: + # 块标签 + if blk.Name is not None: + _append_cstr(buf, size, blk.Name) + _append_cstr(buf, size, ":\n") + # 指令行(从 GSList[Line].Head 遍历) + line: Line | t.CPtr = None + if blk.Lines is not None: + line = blk.Lines.Head + has_lines: t.CInt = 0 + while line is not None: + if line.Buf is not None: + _append_cstr(buf, size, " ") + _append_cstr(buf, size, line.Buf) + _append_cstr(buf, size, "\n") + has_lines = 1 + line = line.Next + # 块未终止兜底:LLVM IR 要求每个基本块以终止指令(br/ret/unreachable)结尾。 + # 两种情况需要补 unreachable: + # 1. 空块(has_lines==0):标签后无任何指令 + # 2. 有指令但未终止(IsTerminated==0):如 break/continue 后的 dead.N 块 + # 被后续语句填入指令但缺少终止符,导致下一个标签处报 + # "expected instruction opcode" + if has_lines == 0 or blk.IsTerminated == 0: + _append_cstr(buf, size, " unreachable\n") + blk = blk.Next + + _append_cstr(buf, size, "}\n") + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# ============================================================ +# 字段访问器(供其他模块绕过 stub 类型限制使用) +# +# 跨模块编译时,使用方模块只有 Function/Param 的 stub 类型 +# (字段不足且字段类型可能错误),导致 TransPyC 静默跳过 +# 字段访问(不生成 GEP,不报错),字段值永远为 null。 +# +# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问 +# 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。 +# ============================================================ +def function_get_name(func: Function | t.CPtr) -> t.CChar | t.CPtr: + """获取函数名""" + if func is None: + return None + return func.Name + + +def function_get_ret_ty(func: Function | t.CPtr) -> LLVMType | t.CPtr: + """获取函数返回类型""" + if func is None: + return None + return func.RetTy + + +def function_get_params(func: Function | t.CPtr) -> GSList[Param] | t.CPtr: + """获取函数参数链表容器""" + if func is None: + return None + return func.Params + + +def function_get_param_head(func: Function | t.CPtr) -> Param | t.CPtr: + """获取函数参数链表头节点(一步到位,避免调用方访问 GSList.Head)""" + if func is None: + return None + if func.Params is None: + return None + return func.Params.Head + + +def function_get_next(func: Function | t.CPtr) -> Function | t.CPtr: + """获取链表下一个函数""" + if func is None: + return None + return func.Next + + +def function_is_declared(func: Function | t.CPtr) -> t.CInt: + """获取函数是否为声明(1=declare 仅声明, 0=define 定义)""" + if func is None: + return 0 + return func.IsDeclared + + +def param_get_name(param: Param | t.CPtr) -> t.CChar | t.CPtr: + """获取参数名""" + if param is None: + return None + return param.Name + + +def param_get_ty(param: Param | t.CPtr) -> LLVMType | t.CPtr: + """获取参数类型""" + if param is None: + return None + return param.Ty + + +def param_get_next(param: Param | t.CPtr) -> Param | t.CPtr: + """获取链表下一个参数""" + if param is None: + return None + return param.Next diff --git a/llvmlite/__init__.vp b/llvmlite/__init__.vp new file mode 100644 index 0000000..581560a --- /dev/null +++ b/llvmlite/__init__.vp @@ -0,0 +1,423 @@ +import t, c +from stdint import * +import memhub +import string +import viperlib + +# 导入子模块 +from .__types import ( + LLVMType, ParamNode, LLVMTypeCore, + Int1, Int8, Int16, Int32, Int64, Ptr, Func, Void, Array, Struct, + Half, Float, Double, FP128, Label, + new_param_node, param_list_append, + paramnode_get_ty, paramnode_get_next, paramnode_set_ty, paramnode_set_next, + TypePrint, PrintStructDefinition, get_struct_name, + get_struct_fields, get_struct_fcount, DeepCopyType, +) +from .__values import ( + Value, new_value, ConstInt, ConstNull, ConstZero, ConstFloat, SSAValue, ValuePrint, + value_get_ty, value_get_next, + value_set_ty, value_set_next, value_set_name, value_set_isconst, +) +from .__function import ( + Line, BasicBlock, Param, Function, + new_line, new_basic_block, new_param, new_function, + function_add_param, function_add_block, + block_append_line, block_append_text, + function_set_attrs, param_set_attrs, + function_get_name, function_get_ret_ty, function_get_params, + function_get_param_head, function_get_next, function_is_declared, + param_get_name, param_get_ty, param_get_next, + FunctionPrint, +) +from .__module import ( + LLVMModule, GlobalVariable, NamedTypeNode, new_module, new_global_variable, + module_add_function, module_add_global, module_add_named_type, + module_set_target, module_set_datalayout, + global_set_constant, global_set_linkage, global_set_unnamed_addr, global_set_section, + LLVMModulePrint, OUTPUT_FULL, OUTPUT_STUB, OUTPUT_TEXT, + module_ensure_opaque_for_type, +) +from .__builder import ( + IRBuilder, new_builder, position_at_end, + builder_cur_block_is_terminated, + build_alloca, build_alloca_aligned, build_alloca_at_entry, build_load, build_store, + build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem, + build_and, build_or, build_xor, build_shl, build_lshr, build_ashr, + build_fadd, build_fsub, build_fmul, build_fdiv, build_frem, build_fneg, + build_icmp, build_fcmp, + build_br, build_cond_br, build_ret, build_ret_void, + build_call, build_call_indirect, build_bitcast, build_sext, build_trunc, build_zext, + build_ptrtoint, build_inttoptr, + build_fpext, build_fptrunc, build_fp2si, build_si2fp, build_fp2ui, build_ui2fp, + build_gep, build_gep_array, build_gep_struct, + build_phi, build_switch, build_select, build_unreachable, + build_atomicrmw, build_cmpxchg, build_inline_asm, build_va_arg, + PhiIncoming, new_phi_incoming, SwitchCase, new_switch_case, + ICMP_EQ, ICMP_NE, ICMP_SGT, ICMP_SGE, ICMP_SLT, ICMP_SLE, + ICMP_UGT, ICMP_UGE, ICMP_ULT, ICMP_ULE, + FCMP_FALSE, FCMP_OEQ, FCMP_OGT, FCMP_OGE, FCMP_OLT, FCMP_OLE, + FCMP_ONE, FCMP_ORD, FCMP_UNO, FCMP_UEQ, FCMP_UGT, FCMP_UGE, + FCMP_ULT, FCMP_ULE, FCMP_UNE, FCMP_TRUE, + ATOMIC_XCHG, ATOMIC_ADD, ATOMIC_SUB, ATOMIC_AND, ATOMIC_NAND, + ATOMIC_OR, ATOMIC_XOR, ATOMIC_MAX, ATOMIC_MIN, ATOMIC_UMAX, ATOMIC_UMIN, + ATOMIC_ORDER_NOTATOMIC, ATOMIC_ORDER_UNORDERED, ATOMIC_ORDER_MONOTONIC, + ATOMIC_ORDER_ACQUIRE, ATOMIC_ORDER_RELEASE, ATOMIC_ORDER_ACQ_REL, + ATOMIC_ORDER_SEQ_CST, +) +from .__verify import ( + VerifyResult, NameEntry, + verify_function, verify_module, + VERIFY_OK, VERIFY_ERR_NO_TERMINATOR, VERIFY_ERR_DUPLICATE_DEF, + VERIFY_ERR_UNDEFINED_USE, VERIFY_ERR_PHI_NOT_FIRST, + _new_verify_result, +) + + +# ============================================================ +# 便捷工厂: 字符串复制 +# ============================================================ +def _str_dup(pool: memhub.MemBuddy | t.CPtr, src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """从 pool 分配并复制一个 C 字符串""" + if src is None: return None + slen: t.CSizeT = string.strlen(src) + buf: t.CChar | t.CPtr = pool.alloc(slen + 1) + if buf is None: return None + string.strcpy(buf, src) + return buf + + +# ============================================================ +# 便捷工厂: 创建带名称的基本块 +# ============================================================ +def create_block(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr, + name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr: + """创建基本块并添加到函数""" + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + blk: BasicBlock | t.CPtr = new_basic_block(pool, name_dup) + if blk is not None: + function_add_block(func, blk) + return blk + + +# ============================================================ +# 便捷工厂: 创建整数常量值 +# ============================================================ +def const_int(pool: memhub.MemBuddy | t.CPtr, bits: t.CInt, + val: t.CInt64T) -> Value | t.CPtr: + """创建整数常量值(自动创建类型 + 名字文本) + + 参数: + bits: 位宽 (1/8/16/32/64) + val: 整数值 + """ + # 创建类型 + ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if ty is None: return None + string.memset(ty, 0, LLVMType.__sizeof__()) + c.DerefAs(ty, LLVMType.Int(bits)) + + # 创建名字文本 + name: t.CChar | t.CPtr = pool.alloc(32) + if name is None: return None + viperlib.snprintf(name, 32, "%lld", val) + + return ConstInt(pool, ty, val, name) + + +def const_int32(pool: memhub.MemBuddy | t.CPtr, val: t.CInt64T) -> Value | t.CPtr: + """便捷: 创建 i32 整数常量""" + return const_int(pool, 32, val) + + +def const_int64(pool: memhub.MemBuddy | t.CPtr, val: t.CInt64T) -> Value | t.CPtr: + """便捷: 创建 i64 整数常量""" + return const_int(pool, 64, val) + + +# ============================================================ +# 便捷工厂: 创建函数并添加到模块 +# ============================================================ +def create_function(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, + name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + """创建函数并添加到模块""" + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + func: Function | t.CPtr = new_function(pool, name_dup, ret_ty) + if func is not None: + module_add_function(mod, func) + return func + + +def add_param(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr, + ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Param | t.CPtr: + """创建参数并添加到函数""" + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + param: Param | t.CPtr = new_param(pool, ty, name_dup) + if param is not None: + function_add_param(func, param) + return param + + +# ============================================================ +# 便捷工厂: 创建函数声明(declare) +# ============================================================ +def create_declare(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, + name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + """创建函数声明(declare,无函数体)并添加到模块 + + 与 create_function 不同,声明不生成函数体,仅生成: + declare @() + """ + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + func: Function | t.CPtr = new_function(pool, name_dup, ret_ty) + if func is not None: + func.IsDeclared = 1 + module_add_function(mod, func) + return func + + +# ============================================================ +# 便捷工厂: 创建字符串常量全局变量 +# +# 生成 LLVM IR: +# @.str = private unnamed_addr constant [N x i8] c"contents\00" +# ============================================================ +def create_global_string(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, + name: t.CChar | t.CPtr, text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr: + """创建字符串常量全局变量并添加到模块 + + 参数: + name: 全局变量名(如 ".str") + text: 字符串内容(C 字符串,不含末尾 NUL,NUL 由本函数自动添加) + + 返回: GlobalVariable 指针,其类型为 [len+1 x i8] + """ + if text is None: return None + slen: t.CSizeT = string.strlen(text) + count: t.CInt = slen + 1 # 含末尾 NUL + + # 创建 i8 类型 + i8_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if i8_ty is None: return None + string.memset(i8_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(i8_ty, LLVMType.Int(8)) + + # 创建 [count x i8] 数组类型 + arr_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if arr_ty is None: return None + string.memset(arr_ty, 0, LLVMType.__sizeof__()) + c.DerefAs(arr_ty, LLVMType.Array(i8_ty, count)) + + # 创建全局变量 + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, arr_ty) + if gv is None: return None + + # 设置属性: private + unnamed_addr + constant + global_set_linkage(gv, "private") + global_set_unnamed_addr(gv, 1) + global_set_constant(gv, 1) + + # 构造初始化值文本: c"contents\00" + # LLVM IR 字符串字面量格式: c"" 其中 " 和 \ 及非打印字符用 \xx 转义 + # 缓冲区大小: 最坏情况每个字符4字节(\xx)+ c"..." + \00 + " + init_buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8) + if init_buf is None: return None + pos: t.CSizeT = 0 + init_buf[pos] = 'c' + pos += 1 + init_buf[pos] = '"' + pos += 1 + i: t.CSizeT = 0 + while i < slen: + ch: t.CUInt8T = text[i] + if ch == 0x22 or ch == 0x5C or ch < 0x20 or ch >= 0x7F: + # 需要转义: " → \22, \ → \5c, 非打印字符 → \xx + init_buf[pos] = '\\' + pos += 1 + hi: t.CInt = (ch >> 4) & 0x0F + lo: t.CInt = ch & 0x0F + if hi < 10: + init_buf[pos] = 0x30 + hi + else: + init_buf[pos] = 0x61 + hi - 10 + pos += 1 + if lo < 10: + init_buf[pos] = 0x30 + lo + else: + init_buf[pos] = 0x61 + lo - 10 + pos += 1 + else: + init_buf[pos] = ch + pos += 1 + i += 1 + # 末尾 NUL 字节 + init_buf[pos] = '\\' + pos += 1 + init_buf[pos] = '0' + pos += 1 + init_buf[pos] = '0' + pos += 1 + init_buf[pos] = '"' + pos += 1 + init_buf[pos] = '\0' + gv.Initializer = init_buf + + module_add_global(mod, gv) + return gv + + +# ============================================================ +# 便捷工厂: 创建带初始化值的整数全局变量 +# ============================================================ +def create_global_int(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, + name: t.CChar | t.CPtr, bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr: + """创建整数全局变量并添加到模块 + + 生成 LLVM IR: + @ = global i + """ + # 创建整数类型 + ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if ty is None: return None + string.memset(ty, 0, LLVMType.__sizeof__()) + c.DerefAs(ty, LLVMType.Int(bits)) + + name_dup: t.CChar | t.CPtr = _str_dup(pool, name) + gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, ty) + if gv is None: return None + + # 构造初始化值文本: "42" (类型由 _print_global 单独打印) + init_buf: t.CChar | t.CPtr = pool.alloc(48) + if init_buf is None: return None + viperlib.snprintf(init_buf, 48, "%lld", val) + gv.Initializer = init_buf + + module_add_global(mod, gv) + return gv + + +# ============================================================ +# LLVMModuleCore: 模块/函数/值创建核心,封装 pool 避免重复传参 +# +# 用法: +# mcore: LLVMModuleCore | t.CPtr = LLVMModuleCore(pool) +# mod: LLVMModule | t.CPtr = mcore.NewModule("test") +# func: Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32) +# val: Value | t.CPtr = mcore.ConstInt32(42) +# ============================================================ +@t.NoVTable +class LLVMModuleCore: + """模块/函数/值创建核心,封装 pool 避免每次创建都传 pool""" + Pool: memhub.MemBuddy | t.CPtr + + def __init__(self, pool: memhub.MemBuddy | t.CPtr): + self.Pool = pool + + # ---- 模块操作 ---- + def NewModule(self, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr: + return new_module(self.Pool, name) + + def CreateFunction(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + return create_function(self.Pool, mod, name, ret_ty) + + def CreateDeclare(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: + """创建函数声明(declare,无函数体)""" + return create_declare(self.Pool, mod, name, ret_ty) + + def AddParam(self, func: Function | t.CPtr, ty: LLVMType | t.CPtr, + name: t.CChar | t.CPtr) -> Param | t.CPtr: + return add_param(self.Pool, func, ty, name) + + def FunctionSetAttrs(self, func: Function | t.CPtr, attrs: t.CChar | t.CPtr): + """设置函数级属性文本""" + function_set_attrs(func, attrs) + + def ParamSetAttrs(self, param: Param | t.CPtr, attrs: t.CChar | t.CPtr): + """设置参数属性文本""" + param_set_attrs(param, attrs) + + def CreateBlock(self, func: Function | t.CPtr, + name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr: + return create_block(self.Pool, func, name) + + def NewBuilder(self, func: Function | t.CPtr) -> IRBuilder | t.CPtr: + return new_builder(self.Pool, func) + + # ---- 全局变量 ---- + def NewGlobal(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr: + """创建全局变量并添加到模块""" + name_dup: t.CChar | t.CPtr = _str_dup(self.Pool, name) + gv: GlobalVariable | t.CPtr = new_global_variable(self.Pool, name_dup, ty) + if gv is not None: + module_add_global(mod, gv) + return gv + + def CreateGlobalString(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr: + """创建字符串常量全局变量""" + return create_global_string(self.Pool, mod, name, text) + + def CreateGlobalInt(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr, + bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr: + """创建带初始化值的整数全局变量""" + return create_global_int(self.Pool, mod, name, bits, val) + + def GlobalSetConstant(self, gv: GlobalVariable | t.CPtr, is_const: t.CInt): + global_set_constant(gv, is_const) + + def GlobalSetLinkage(self, gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr): + global_set_linkage(gv, linkage) + + def GlobalSetUnnamedAddr(self, gv: GlobalVariable | t.CPtr, level: t.CInt): + global_set_unnamed_addr(gv, level) + + def GlobalSetSection(self, gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr): + global_set_section(gv, section) + + # ---- 值创建 ---- + def ConstInt(self, bits: t.CInt, val: t.CInt64T) -> Value | t.CPtr: + return const_int(self.Pool, bits, val) + + def ConstInt32(self, val: t.CInt64T) -> Value | t.CPtr: + return const_int32(self.Pool, val) + + def ConstInt64(self, val: t.CInt64T) -> Value | t.CPtr: + return const_int64(self.Pool, val) + + def ConstFloat(self, ty: LLVMType | t.CPtr, val: t.CDouble) -> Value | t.CPtr: + return ConstFloat(self.Pool, ty, val) + + def SSAValue(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr: + return SSAValue(self.Pool, ty, name) + + def ConstNull(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr: + return ConstNull(self.Pool, ty, name) + + # ---- 打印 ---- + def PrintValue(self, buf: t.CChar | t.CPtr, size: t.CSizeT, val: Value | t.CPtr): + ValuePrint(buf, size, val, self.Pool) + + def PrintFunction(self, buf: t.CChar | t.CPtr, size: t.CSizeT, func: Function | t.CPtr): + FunctionPrint(buf, size, func, self.Pool) + + def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT, mod: LLVMModule | t.CPtr): + LLVMModulePrint(buf, size, mod, self.Pool, OUTPUT_FULL) + + # ---- SSA 验证 ---- + def NewVerifyResult(self, buf_size: t.CSizeT) -> VerifyResult | t.CPtr: + """创建验证结果对象(buf_size 为错误消息缓冲区大小)""" + return _new_verify_result(self.Pool, buf_size) + + def VerifyFunction(self, func: Function | t.CPtr, + result: VerifyResult | t.CPtr) -> t.CInt: + """验证单个函数的 SSA 正确性,返回错误数(0=通过)""" + return verify_function(self.Pool, func, result) + + def VerifyModule(self, mod: LLVMModule | t.CPtr, + result: VerifyResult | t.CPtr) -> t.CInt: + """验证模块中所有函数的 SSA 正确性,返回错误数(0=通过)""" + return verify_module(self.Pool, mod, result) diff --git a/llvmlite/__module.vp b/llvmlite/__module.vp new file mode 100644 index 0000000..cc96d15 --- /dev/null +++ b/llvmlite/__module.vp @@ -0,0 +1,638 @@ +import t, c +from stdint import * +import string +import stdio +import stdlib +import viperlib +import memhub +from linkedlist import GSList, GSListNode +from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct, ParamNode +from .__function import Function, FunctionPrint, _ll_name_needs_quote, Param + + +# ============================================================ +# GlobalVariable: LLVM IR 全局变量 +# +# 持有名称 + 类型 + 初始化值 + 常量标志 + 链接类型。 +# 继承 GSListNode[GlobalVariable] 获取强类型 Next。 +# ============================================================ +@t.NoVTable +class GlobalVariable(GSListNode[GlobalVariable]): + Name: t.CChar | t.CPtr # 全局变量名(如 ".str" / "my_global") + Ty: LLVMType | t.CPtr # 变量类型 + Initializer: t.CVoid | t.CPtr # 初始化值 Value*(None = 无初始化) + IsConstant: t.CInt # 1=constant, 0=variable + Linkage: t.CChar | t.CPtr # 链接类型("private"/"internal"/"external"/...) + Section: t.CChar | t.CPtr # 段名(None = 默认) + UnnamedAddr: t.CInt # 1=unnamed_addr, 2=local_unnamed_addr, 0=none + + +# ============================================================ +# NamedTypeNode: 命名结构体类型链表节点 +# +# 持有 LLVMType* 指针(必须是命名 Struct 类型)。 +# 继承 GSListNode[NamedTypeNode] 获取强类型 Next。 +# ============================================================ +@t.NoVTable +class NamedTypeNode(GSListNode[NamedTypeNode]): + Ty: LLVMType | t.CPtr # 命名结构体类型指针 + + +# ============================================================ +# LLVMModule: LLVM IR 模块容器 +# +# 使用嵌入式 Head/Tail/Count 字段代替 GSList 指针, +# 避免泛型 GSList 的 __sizeof__ 返回 0 和 vtable 偏移不一致问题。 +# LLVMModulePrint 输出完整 .ll 文件内容。 +# 注意: 类名必须为 LLVMModule 而非 Module,避免与 ast.Module 命名冲突 +# ============================================================ +@t.NoVTable +class LLVMModule: + Name: t.CChar | t.CPtr # 模块名 + FuncHead: Function | t.CPtr # 函数链表头 + FuncTail: Function | t.CPtr # 函数链表尾 + FuncCount: t.CSizeT # 函数计数 + GlobalHead: GlobalVariable | t.CPtr # 全局变量链表头 + GlobalTail: GlobalVariable | t.CPtr # 全局变量链表尾 + GlobalCount: t.CSizeT # 全局变量计数 + TargetTriple: t.CChar | t.CPtr # 目标三元组(如 "x86_64-pc-linux-gnu") + DataLayout: t.CChar | t.CPtr # 数据布局(如 "e-m:e-p270:32:32-...") + NamedTypeHead: NamedTypeNode | t.CPtr # 命名结构体类型链表头 + NamedTypeTail: NamedTypeNode | t.CPtr # 命名结构体类型链表尾 + NamedTypeCount: t.CSizeT # 命名结构体类型计数 + # 总计: 12 字段 * 8 = 96 字节(无 vtable) + + # ============================================================ + # 实例方法(对象化重构:原 module_* 顶层函数改写为方法, + # 原顶层函数保留为一行委托) + # ============================================================ + + # ---- 链表操作 ---- + def add_function(self, func: Function | t.CPtr): + """将函数追加到模块函数链表(O(1))""" + if self is None or func is None: return + func.Next = None + if self.FuncHead is None: + self.FuncHead = func + else: + self.FuncTail.Next = func + self.FuncTail = func + self.FuncCount += 1 + + def add_global(self, gv: GlobalVariable | t.CPtr): + """将全局变量追加到模块全局变量链表(O(1))""" + if self is None or gv is None: return + gv.Next = None + if self.GlobalHead is None: + self.GlobalHead = gv + else: + self.GlobalTail.Next = gv + self.GlobalTail = gv + self.GlobalCount += 1 + + # ---- 目标属性 ---- + def set_target(self, triple: t.CChar | t.CPtr): + """设置目标三元组""" + if self is None: return + self.TargetTriple = triple + + def set_datalayout(self, layout: t.CChar | t.CPtr): + """设置数据布局""" + if self is None: return + self.DataLayout = layout + + # ---- 命名结构体类型管理 ---- + def add_named_type(self, pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr): + """将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行) + + 非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。 + 按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。 + """ + if self is None or pool is None or ty is None: + return + name: t.CChar | t.CPtr = get_struct_name(ty) + if name is None: + return + # 去重检查(opaque 声明可被完整定义替换) + cur: NamedTypeNode | t.CPtr = self.NamedTypeHead + cnt_dedup: t.CInt = 0 + while cur is not None: + # 步数守卫:NamedTypeHead 链表成环(内存损坏/插入 bug)会导致 + # 无限遍历挂起(G3 编译 LinkedNode.prepend 挂起根因)。 + # 正常链表节点数远小于此上限,超限即链表损坏 → 立即报错终止。 + cnt_dedup += 1 + if cnt_dedup > 100000: + stdio.printf("[ANT-LOOP] NamedTypeHead 链表疑似成环, name=%s, 遍历节点=%d, 强制终止\n", + name if name is not None else "(null)", cnt_dedup) + stdlib.exit(1) + if cur.Ty is not None: + existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty) + if existing_name is not None: + if string.strcmp(existing_name, name) == 0: + # 已有完整定义则无需替换 + if _is_opaque_struct(cur.Ty) == 0: + return + # 已有 opaque,新类型也是 opaque 则不重复 + if _is_opaque_struct(ty) != 0: + return + # 用完整定义替换 opaque 声明(原地替换 Ty 指针) + cur.Ty = ty + return + cur = cur.Next + # 创建新节点 + node: NamedTypeNode | t.CPtr = pool.alloc(NAMED_TYPE_NODE_SIZE) + if node is None: + return + string.memset(node, 0, NAMED_TYPE_NODE_SIZE) + node.Ty = ty + # opaque 类型插入链表头部,确保在引用它的完整定义之前声明。 + # 例如 TypeRegistry{HashTable*, ...} 中,HashTable 的 opaque 声明 + # 必须在 TypeRegistry 定义之前,否则 llc 报 "use of undefined type"。 + # 完整定义追加到链表尾部,保持原有顺序。 + if _is_opaque_struct(ty) != 0: + node.Next = self.NamedTypeHead + if self.NamedTypeHead is None: + self.NamedTypeTail = node + self.NamedTypeHead = node + else: + node.Next = None + if self.NamedTypeHead is None: + self.NamedTypeHead = node + else: + self.NamedTypeTail.Next = node + self.NamedTypeTail = node + self.NamedTypeCount += 1 + + def _is_type_defined_in_module(self, name: t.CChar | t.CPtr) -> int: + """检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义""" + if self is None or name is None: + return 0 + cur: NamedTypeNode | t.CPtr = self.NamedTypeHead + cnt_tdm: t.CInt = 0 + while cur is not None: + # 步数守卫:同上,防 NamedTypeHead 链表成环无限遍历 + cnt_tdm += 1 + if cnt_tdm > 100000: + stdio.printf("[TDM-LOOP] NamedTypeHead 链表疑似成环, name=%s, 强制终止\n", + name if name is not None else "(null)") + stdlib.exit(1) + if cur.Ty is not None: + existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty) + if existing_name is not None: + if string.strcmp(existing_name, name) == 0: + return 1 + cur = cur.Next + return 0 + + def ensure_opaque_for_type(self, pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr): + """为类型中的跨模块结构体引用添加 opaque 声明 + + 当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时, + 如果该名称未在模块中定义,则添加 opaque 声明。 + """ + _scan_type_for_cross_module_refs(pool, self, ty) + + # ---- 打印 ---- + def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT, + pool: memhub.MemBuddy | t.CPtr, mode: t.CInt): + """将模块序列化为 .ll 文本写入 buf""" + if self is None or buf is None or size == 0: return + + # 头部注释(stub 和 full 模式输出,text 模式不输出) + if mode == OUTPUT_FULL or mode == OUTPUT_STUB: + _append_cstr(buf, size, "; ModuleID = '") + if self.Name is not None: + _append_cstr(buf, size, self.Name) + _append_cstr(buf, size, "'\n") + + # 目标三元组 + if self.TargetTriple is not None: + _append_cstr(buf, size, "target triple = \"") + _append_cstr(buf, size, self.TargetTriple) + _append_cstr(buf, size, "\"\n") + + # 数据布局 + if self.DataLayout is not None: + _append_cstr(buf, size, "target datalayout = \"") + _append_cstr(buf, size, self.DataLayout) + _append_cstr(buf, size, "\"\n") + + # 空行 + _append_cstr(buf, size, "\n") + + # 命名结构体类型定义(stub 和 full 模式输出,text 模式不输出) + if mode == OUTPUT_FULL or mode == OUTPUT_STUB: + # 扫描所有函数签名,为跨模块结构体引用添加 opaque 定义 + # 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义 + # 修复:alloc_buf 返回 viperio.Buf,但 Buf 类型未在 NamedTypeHead 中注册 + func_scan: Function | t.CPtr = self.FuncHead + while func_scan is not None: + if func_scan.RetTy is not None: + self.ensure_opaque_for_type(pool, func_scan.RetTy) + if func_scan.Params is not None: + param_scan: Param | t.CPtr = func_scan.Params.Head + while param_scan is not None: + if param_scan.Ty is not None: + self.ensure_opaque_for_type(pool, param_scan.Ty) + param_scan = param_scan.Next + func_scan = func_scan.Next + nt: NamedTypeNode | t.CPtr = self.NamedTypeHead + # 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够 + # 在循环外分配一次并复用,减少 pool 碎片 + ty_buf: t.CChar | t.CPtr = pool.alloc(4096) + while nt is not None: + if nt.Ty is not None: + if ty_buf is not None: + ty_buf[0] = '\0' + PrintStructDefinition(ty_buf, 4096, nt.Ty, pool) + _append_cstr(buf, size, ty_buf) + _append_cstr(buf, size, "\n") + nt = nt.Next + + if self.NamedTypeHead is not None: + _append_cstr(buf, size, "\n") + + # 全局变量 + gv: GlobalVariable | t.CPtr = self.GlobalHead + if mode == OUTPUT_STUB: + # stub 模式:输出 external global(无初值) + while gv is not None: + _print_global_stub(buf, size, gv, pool) + _append_cstr(buf, size, "\n") + gv = gv.Next + else: + # full 和 text 模式:输出完整全局变量 + # text 模式跳过无初值的全局变量(纯声明) + gv_idx: t.CInt = 0 + while gv is not None: + if mode == OUTPUT_TEXT and gv.Initializer is None: + gv = gv.Next + gv_idx += 1 + continue + _print_global(buf, size, gv, pool) + _append_cstr(buf, size, "\n") + gv = gv.Next + gv_idx += 1 + + if self.GlobalHead is not None and (mode == OUTPUT_FULL or mode == OUTPUT_STUB): + _append_cstr(buf, size, "\n") + elif self.GlobalHead is not None and mode == OUTPUT_TEXT: + # text 模式下如果输出了全局变量,也加空行 + had_global: t.CInt = 0 + gv2: GlobalVariable | t.CPtr = self.GlobalHead + while gv2 is not None: + if gv2.Initializer is not None: + had_global = 1 + break + gv2 = gv2.Next + if had_global != 0: + _append_cstr(buf, size, "\n") + + # 遍历函数 + func: Function | t.CPtr = self.FuncHead + func_idx: t.CInt = 0 + while func is not None: + if mode == OUTPUT_STUB: + # stub 模式:仅输出 declare(IsDeclared==1) + if func.IsDeclared == 1: + FunctionPrint(buf, size, func, pool) + _append_cstr(buf, size, "\n") + elif mode == OUTPUT_TEXT: + # text 模式:仅输出 define(IsDeclared==0) + if func.IsDeclared == 0: + FunctionPrint(buf, size, func, pool) + _append_cstr(buf, size, "\n") + else: + # full 模式:输出所有函数 + FunctionPrint(buf, size, func, pool) + _append_cstr(buf, size, "\n") + func = func.Next + func_idx += 1 + + +# ============================================================ +# 工厂函数 +# ============================================================ +def new_module(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr: + """创建一个模块""" + # 硬编码 96 字节:12 字段 * 8 字节(无 vtable,@t.NoVTable) + ptr: LLVMModule | t.CPtr = pool.alloc(96) + if ptr is None: return None + string.memset(ptr, 0, 96) + ptr.Name = name + ptr.FuncHead = None + ptr.FuncTail = None + ptr.FuncCount = 0 + ptr.GlobalHead = None + ptr.GlobalTail = None + ptr.GlobalCount = 0 + ptr.TargetTriple = None + ptr.DataLayout = None + ptr.NamedTypeHead = None + ptr.NamedTypeTail = None + ptr.NamedTypeCount = 0 + return ptr + + +# GlobalVariable 硬编码大小: Next(8) + Name(8) + Ty(8) + Initializer(8) + IsConstant(4) + Linkage(8) + Section(8) + UnnamedAddr(4) = 64 字节 +GV_SIZE: t.CDefine = 64 + +# NamedTypeNode 硬编码大小: Next(8) + Ty(8) = 16 字节 +NAMED_TYPE_NODE_SIZE: t.CDefine = 16 + +def new_global_variable(pool: memhub.MemBuddy | t.CPtr, + name: t.CChar | t.CPtr, ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr: + """创建一个全局变量""" + ptr: GlobalVariable | t.CPtr = pool.alloc(GV_SIZE) + if ptr is None: return None + string.memset(ptr, 0, GV_SIZE) + ptr.Name = name + ptr.Ty = ty + ptr.Initializer = None + ptr.IsConstant = 0 + ptr.Linkage = "external" + ptr.Section = None + ptr.UnnamedAddr = 0 + return ptr + + +# ============================================================ +# 链表操作(嵌入式 Head/Tail/Count,O(1) 追加) +# ============================================================ +def module_add_function(mod: LLVMModule | t.CPtr, func: Function | t.CPtr): + return mod.add_function(func) + + +def module_add_global(mod: LLVMModule | t.CPtr, gv: GlobalVariable | t.CPtr): + return mod.add_global(gv) + + +def module_set_target(mod: LLVMModule | t.CPtr, triple: t.CChar | t.CPtr): + return mod.set_target(triple) + + +def module_set_datalayout(mod: LLVMModule | t.CPtr, layout: t.CChar | t.CPtr): + return mod.set_datalayout(layout) + + +# ============================================================ +# 命名结构体类型管理 +# ============================================================ + +# ============================================================ +# _is_opaque_struct - 检查类型是否是 opaque 结构体 +# +# opaque 结构体特征: Struct 类型,fcount == -1(哨兵标记,跨模块前向 +# 声明,仅名称无字段定义)。通过 Struct(pool, None, -1, name) 创建, +# IR 输出为 %"name" = type opaque。注意区分空结构体(fcount==0, +# fields==None,无字段类)——它是合法完整定义(= type {},可 alloca)。 +# 用于在 module_add_named_type 中区分 opaque 声明和完整定义, +# 确保 opaque 声明插入链表头部(在使用之前声明)。 +# +# Returns: 1=是 opaque / 0=否 +# ============================================================ +def _is_opaque_struct(ty: LLVMType | t.CPtr) -> int: + """检查类型是否是 opaque 结构体 + + opaque 是跨模块前向声明(仅名称无字段定义),由 + _scan_type_for_cross_module_refs 创建,fcount=-1 哨兵标记。 + 空结构体(fcount==0, fields==None,无字段类)是合法完整定义 + (LLVM {} 类型,可 alloca),必须与 opaque 区分——此前混淆导致 + 空类结构体被输出为 "= type opaque",alloca 报 Cannot allocate + unsized type。 + """ + if ty is None: + return 0 + match ty: + case LLVMType.Struct(fields, fcount, name): + # opaque: fcount == -1(哨兵) + if fcount < 0: + return 1 + return 0 + case _: + return 0 + + +def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr): + return mod.add_named_type(pool, ty) + + +# ============================================================ +# module_ensure_opaque_for_type - 为类型中的跨模块结构体引用添加 opaque 声明 +# +# 递归扫描 LLVMType 树,当遇到 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时, +# 如果该名称未在模块中定义,则添加 opaque 声明(%"name" = type opaque)。 +# 这解决了跨模块结构体引用导致的 llc "use of undefined type" 错误。 +# ============================================================ +def _is_type_defined_in_module(mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr) -> int: + return mod._is_type_defined_in_module(name) + + +def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr, + mod: LLVMModule | t.CPtr, + ty: LLVMType | t.CPtr, + depth: t.CInt = 0): + """递归扫描类型树,为跨模块结构体引用添加 opaque 声明""" + if ty is None or mod is None or pool is None: + return + # 深度守卫:自引用结构体(链表/树节点,如 Node{...; Ptr(Node) next}) + # 会无限递归栈溢出,与其他递归(TypePrint/DeepCopyType)一致设上限 + if depth >= 100: + return + match ty: + case LLVMType.Ptr(pointee): + if pointee is not None: + match pointee: + case LLVMType.Struct(sfields, sfcount, sname): + if sname is not None: + # 检查是否为跨模块引用(名称包含 '.') + if string.strchr(sname, 46) is not None: + # 检查是否已在模块中定义 + if _is_type_defined_in_module(mod, sname) == 0: + # 创建 opaque 类型并添加到模块 + # fcount=-1 哨兵标记 opaque(区别于空结构体 {}, + # 后者 fcount==0 是合法完整定义,可 alloca) + opaque_ty: LLVMType | t.CPtr = Struct(pool, None, -1, sname) + if opaque_ty is not None: + module_add_named_type(mod, pool, opaque_ty) + # 递归扫描结构体字段中的跨模块引用 + # 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用 + if sfields is not None: + fld: ParamNode | t.CPtr = sfields + while fld is not None: + if fld.Ty is not None: + _scan_type_for_cross_module_refs(pool, mod, fld.Ty, depth + 1) + fld = fld.Next + case _: + _scan_type_for_cross_module_refs(pool, mod, pointee, depth + 1) + case LLVMType.Struct(sfields2, sfcount2, sname2): + # 顶层结构体(非指针):递归扫描字段 + if sfields2 is not None: + fld2: ParamNode | t.CPtr = sfields2 + while fld2 is not None: + if fld2.Ty is not None: + _scan_type_for_cross_module_refs(pool, mod, fld2.Ty, depth + 1) + fld2 = fld2.Next + case LLVMType.Array(elem_ty, acount): + if elem_ty is not None: + _scan_type_for_cross_module_refs(pool, mod, elem_ty, depth + 1) + case _: + pass + + +def module_ensure_opaque_for_type(mod: LLVMModule | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr): + return mod.ensure_opaque_for_type(pool, ty) + + +# ============================================================ +# 全局变量属性设置 +# ============================================================ +def global_set_constant(gv: GlobalVariable | t.CPtr, is_const: t.CInt): + """设置全局变量是否为常量""" + if gv is None: return + gv.IsConstant = is_const + + +def global_set_linkage(gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr): + """设置链接类型 (private/internal/external/... )""" + if gv is None: return + gv.Linkage = linkage + + +def global_set_unnamed_addr(gv: GlobalVariable | t.CPtr, level: t.CInt): + """设置 unnamed_addr 属性 (0=none, 1=unnamed_addr, 2=local_unnamed_addr)""" + if gv is None: return + gv.UnnamedAddr = level + + +def global_set_section(gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr): + """设置段名""" + if gv is None: return + gv.Section = section + + +# ============================================================ +# 输出模式常量 +# ============================================================ +OUTPUT_FULL: t.CDefine = 0 # 完整 IR(stub + text) +OUTPUT_STUB: t.CDefine = 1 # 仅声明(header + 类型定义 + declare + external global) +OUTPUT_TEXT: t.CDefine = 2 # 仅代码(define + global 带初值) + + +# ============================================================ +# LLVMModulePrint: 将模块序列化为 .ll 文本 +# +# mode: OUTPUT_FULL=完整, OUTPUT_STUB=仅声明, OUTPUT_TEXT=仅代码 +# ============================================================ +def LLVMModulePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, + mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr, + mode: t.CInt): + return mod.PrintModule(buf, size, pool, mode) + + +# ============================================================ +# 全局变量打印 +# ============================================================ +def _print_global(buf: t.CChar | t.CPtr, size: t.CSizeT, + gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """打印单个全局变量: @ = [linkage] [unnamed_addr] [constant] """ + if gv is None: return + + _append_cstr(buf, size, "@") + if gv.Name is not None: + if _ll_name_needs_quote(gv.Name) != 0: + _append_cstr(buf, size, "\"") + _append_cstr(buf, size, gv.Name) + _append_cstr(buf, size, "\"") + else: + _append_cstr(buf, size, gv.Name) + _append_cstr(buf, size, " = ") + + # 链接类型(有初始值时不输出 external,因为 external + 初始值是非法 IR) + if gv.Linkage is not None: + if gv.Initializer is not None and string.strcmp(gv.Linkage, "external") == 0: + pass + else: + _append_cstr(buf, size, gv.Linkage) + _append_cstr(buf, size, " ") + + # unnamed_addr + if gv.UnnamedAddr == 1: + _append_cstr(buf, size, "unnamed_addr ") + elif gv.UnnamedAddr == 2: + _append_cstr(buf, size, "local_unnamed_addr ") + + # constant / global + if gv.IsConstant == 1: + _append_cstr(buf, size, "constant ") + else: + _append_cstr(buf, size, "global ") + + # 类型 + ty_buf: t.CChar | t.CPtr = pool.alloc(512) + if ty_buf is not None: + ty_buf[0] = '\0' + TypePrint(ty_buf, 512, gv.Ty, pool) + _append_cstr(buf, size, ty_buf) + + # 初始化值 + if gv.Initializer is not None: + _append_cstr(buf, size, " ") + _append_cstr(buf, size, gv.Initializer) + + # 段名 + if gv.Section is not None: + _append_cstr(buf, size, ", section \"") + _append_cstr(buf, size, gv.Section) + _append_cstr(buf, size, "\"") + + +# ============================================================ +# _print_global_stub - 打印全局变量的声明形式(external global,无初值) +# ============================================================ +def _print_global_stub(buf: t.CChar | t.CPtr, size: t.CSizeT, + gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """打印全局变量声明: @ = external global """ + if gv is None: return + + _append_cstr(buf, size, "@") + if gv.Name is not None: + if _ll_name_needs_quote(gv.Name) != 0: + _append_cstr(buf, size, "\"") + _append_cstr(buf, size, gv.Name) + _append_cstr(buf, size, "\"") + else: + _append_cstr(buf, size, gv.Name) + _append_cstr(buf, size, " = external global ") + + # 类型 + ty_buf: t.CChar | t.CPtr = pool.alloc(512) + if ty_buf is not None: + ty_buf[0] = '\0' + TypePrint(ty_buf, 512, gv.Ty, pool) + _append_cstr(buf, size, ty_buf) + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 C 字符串 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' \ No newline at end of file diff --git a/llvmlite/__types.vp b/llvmlite/__types.vp new file mode 100644 index 0000000..d3afb58 --- /dev/null +++ b/llvmlite/__types.vp @@ -0,0 +1,765 @@ +import t, c +from stdint import * +import viperlib +import string +import memhub +import stdio +import stdlib +from linkedlist import GSListNode + + +# ============================================================ +# ParamNode: 函数参数类型链表节点 +# 继承 GSListNode[ParamNode] 获取强类型 Next: ParamNode|CPtr +# Ty 用 t.CVoid | t.CPtr 前向引用,使用时转型为 (LLVMType | t.CPtr) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class ParamNode(GSListNode[ParamNode]): + Ty: t.CVoid | t.CPtr # LLVMType*(前向引用,使用时转型) + + +# ============================================================ +# LLVMType: LLVM IR 类型系统(t.REnum tagged union) +# +# 变体少、无通用字段、操作通过 match 分派 —— 契合 REnum 模型。 +# 布局: { i32 __tag, } +# ============================================================ +class LLVMType(t.REnum): + # 整数类型: i1/i8/i16/i32/i64 + class Int: + Bits: t.CInt + + # 指针类型: pointee* + class Ptr: + Pointee: LLVMType | t.CPtr + + # 函数类型: ret (params) + class Func: + Ret: LLVMType | t.CPtr + Params: ParamNode | t.CPtr + PCount: t.CInt + + # 数组类型: [N x elem_ty] + class Array: + ElemTy: LLVMType | t.CPtr + Count: t.CInt + + # 结构体类型: {ty1, ty2, ...} 或 %"name" = type {ty1, ty2, ...} + # Fields 复用 ParamNode 链表(ParamNode.Ty 即字段类型) + # Name 非 None 时为命名结构体,TypePrint 输出 %"name" 而非 {...} + class Struct: + Fields: ParamNode | t.CPtr + FCount: t.CInt + Name: t.CChar | t.CPtr + + # 浮点类型: half/float/double/fp128 + class Float: + Bits: t.CInt # 16=half, 32=float, 64=double, 128=fp128 + + # 无值类型 + class Void: + pass + + # 标签类型 + class Label: + pass + + # 元数据类型 + class Metadata: + pass + + +# ============================================================ +# 内部分配辅助 +# ============================================================ +def _new_type(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """从 mpool 分配一个零初始化的 LLVMType""" + ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__()) + if ptr: + string.memset(ptr, 0, LLVMType.__sizeof__()) + return ptr + + +# ============================================================ +# 类型工厂函数 +# ============================================================ +def Int1(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(1)) + return ptr + + +def Int8(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(8)) + return ptr + + +def Int16(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(16)) + return ptr + + +def Int32(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(32)) + return ptr + + +def Int64(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Int(64)) + return ptr + + +def Ptr(pool: memhub.MemBuddy | t.CPtr, pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr: + """创建指针类型 Ptr(pointee) + + LLVM IR 中 **不允许 void* 指针**("pointers to void are invalid"), + 因此: + - 若 pointee == None → 回退 Ptr(Int8) + - 若 pointee 是 LLVMType.Void → 回退 Ptr(Int8)(对应 C 的 void* 语法在 TPV 中写 Ptr(t.CVoid)) + 其他类型正常构造 Ptr(pointee)。 + """ + # ============== 前置校验: 拦截 Void / None pointee(void* 非法)============== + safe_pointee: LLVMType | t.CPtr = pointee + if safe_pointee is None: + safe_pointee = Int8(pool) + else: + match safe_pointee: + case LLVMType.Void(): + safe_pointee = Int8(pool) + case _: + pass + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Ptr(safe_pointee)) + return ptr + + +def Func(pool: memhub.MemBuddy | t.CPtr, ret: LLVMType | t.CPtr, + params: ParamNode | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Func(ret, params, count)) + return ptr + + +def Void(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Void()) + return ptr + + +def Array(pool: memhub.MemBuddy | t.CPtr, elem_ty: LLVMType | t.CPtr, + count: t.CInt) -> LLVMType | t.CPtr: + """创建数组类型 [count x elem_ty]""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Array(elem_ty, count)) + return ptr + + +def Struct(pool: memhub.MemBuddy | t.CPtr, fields: ParamNode | t.CPtr, + fcount: t.CInt, name: t.CChar | t.CPtr) -> LLVMType | t.CPtr: + """创建结构体类型 {ty1, ty2, ...} + + fields 为 ParamNode 链表头,fcount 为字段数量。 + name 非 None 时为命名结构体(如 "sha1.ClassName"),TypePrint 输出 %"name"。 + name 为 None 时为匿名结构体,TypePrint 输出 {ty1, ty2, ...}。 + """ + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Struct(fields, fcount, name)) + return ptr + + +def Half(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建半精度浮点类型 half (16-bit)""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(16)) + return ptr + + +def Float(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建单精度浮点类型 float (32-bit)""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(32)) + return ptr + + +def Double(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建双精度浮点类型 double (64-bit)""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(64)) + return ptr + + +def FP128(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建四精度浮点类型 fp128 (128-bit)""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Float(128)) + return ptr + + +def Label(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr: + """创建标签类型 label""" + ptr: LLVMType | t.CPtr = _new_type(pool) + if ptr is None: return None + c.DerefAs(ptr, LLVMType.Label()) + return ptr + + +# ============================================================ +# ParamNode 辅助 +# ============================================================ +# ParamNode 硬编码大小: Next(8) + Ty(8) = 16 字节 +PNODE_SIZE: t.CDefine = 16 + +def new_param_node(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr: + """创建一个参数节点,Ty 设为给定类型指针""" + ptr: ParamNode | t.CPtr = pool.alloc(PNODE_SIZE) + if ptr is None: return None + string.memset(ptr, 0, PNODE_SIZE) + ptr.Ty = ty + ptr.Next = None + return ptr + + +def param_list_append(head: ParamNode | t.CPtr, tail: ParamNode | t.CPtr, + node: ParamNode | t.CPtr) -> ParamNode | t.CPtr: + """将 node 追加到参数链表尾部,返回 head 和更新后的 tail""" + if node is None: return head + node.Next = None + if head is None: + return node + if tail is not None: + tail.Next = node + return node + + +# ============================================================ +# ParamNode 字段访问器(供其他模块绕过 stub 类型限制使用) +# +# 跨模块编译时,使用方模块只有 ParamNode 的 stub 类型, +# 导致 TransPyC 静默跳过字段访问。这些访问器在拥有完整类型定义的 +# 本模块内执行,能正确访问所有字段。 +# ============================================================ +def paramnode_get_ty(node: ParamNode | t.CPtr) -> LLVMType | t.CPtr: + """获取参数节点的类型""" + if node is None: + return None + return (LLVMType | t.CPtr)(node.Ty) + + +def paramnode_get_next(node: ParamNode | t.CPtr) -> ParamNode | t.CPtr: + """获取链表下一个参数节点""" + if node is None: + return None + return node.Next + + +def paramnode_set_ty(node: ParamNode | t.CPtr, ty: LLVMType | t.CPtr): + """设置参数节点的类型""" + if node is None: + return + node.Ty = ty + + +def paramnode_set_next(node: ParamNode | t.CPtr, nxt: ParamNode | t.CPtr): + """设置链表下一个参数节点""" + if node is None: + return + node.Next = nxt + + +# ============================================================ +# LLVMTypeCore: 类型创建核心,封装 pool 避免重复传参 +# +# 用法: +# core: LLVMTypeCore | t.CPtr = LLVMTypeCore(pool) +# ty_i32: LLVMType | t.CPtr = core.Int32() +# ty_ptr: LLVMType | t.CPtr = core.Ptr(ty_i32) +# ty_void: LLVMType | t.CPtr = core.Void() +# ============================================================ +@t.NoVTable +class LLVMTypeCore: + """类型创建核心,封装 pool 避免每次创建类型都传 pool""" + Pool: memhub.MemBuddy | t.CPtr + + def __init__(self, pool: memhub.MemBuddy | t.CPtr): + self.Pool = pool + + def Int1(self) -> LLVMType | t.CPtr: + return Int1(self.Pool) + + def Int8(self) -> LLVMType | t.CPtr: + return Int8(self.Pool) + + def Int16(self) -> LLVMType | t.CPtr: + return Int16(self.Pool) + + def Int32(self) -> LLVMType | t.CPtr: + return Int32(self.Pool) + + def Int64(self) -> LLVMType | t.CPtr: + return Int64(self.Pool) + + def Ptr(self, pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr: + return Ptr(self.Pool, pointee) + + def Func(self, ret: LLVMType | t.CPtr, params: ParamNode | t.CPtr, + count: t.CInt) -> LLVMType | t.CPtr: + return Func(self.Pool, ret, params, count) + + def Array(self, elem_ty: LLVMType | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr: + return Array(self.Pool, elem_ty, count) + + def Struct(self, fields: ParamNode | t.CPtr, fcount: t.CInt, + name: t.CChar | t.CPtr = None) -> LLVMType | t.CPtr: + return Struct(self.Pool, fields, fcount, name) + + def Void(self) -> LLVMType | t.CPtr: + return Void(self.Pool) + + def Half(self) -> LLVMType | t.CPtr: + return Half(self.Pool) + + def Float(self) -> LLVMType | t.CPtr: + return Float(self.Pool) + + def Double(self) -> LLVMType | t.CPtr: + return Double(self.Pool) + + def FP128(self) -> LLVMType | t.CPtr: + return FP128(self.Pool) + + def Label(self) -> LLVMType | t.CPtr: + return Label(self.Pool) + + def NewParamNode(self, ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr: + return new_param_node(self.Pool, ty) + + # ---- 链表辅助 ---- + def ParamListAppend(self, head: ParamNode | t.CPtr, tail: ParamNode | t.CPtr, + node: ParamNode | t.CPtr) -> ParamNode | t.CPtr: + """将 node 追加到参数/字段链表,返回新的 tail""" + return param_list_append(head, tail, node) + + # ---- 打印 ---- + def PrintType(self, buf: t.CChar | t.CPtr, size: t.CSizeT, ty: LLVMType | t.CPtr): + TypePrint(buf, size, ty, self.Pool) + + +# ============================================================ +# TypePrint: 将 LLVMType 序列化为 IR 文本 +# +# 示例: +# Int(32) -> "i32" +# Int(8) -> "i8" +# Ptr(Int(32)) -> "i32*" +# Void -> "void" +# Array(Int(32),4) -> "[4 x i32]" +# Struct(...) -> "{i32, i8*}" +# Func(...) -> "i32 (i32, i8*)" +# +# pool 用于复杂类型(Array/Struct/Func)递归打印子类型时分配临时缓冲区。 +# ============================================================ +def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, + ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """将类型 ty 序列化为 IR 文本写入 buf(容量 size) + + pool 用于递归打印子类型时分配临时缓冲区。 + """ + _TypePrintDepth(buf, size, ty, pool, 0) + + +# 递归深度上限:悬空/自引用的 LLVMType 树(1b reset 后内存被复用)会导致 +# Ptr(pointee)/Struct(fields)/Func(params) 无限递归,每次递归分配临时缓冲 +# 造成 OOM(单文件暴涨 900MB 根因)。超过 100 层即停止打印。 +TYPEPRINT_MAX_DEPTH: t.CDefine = 100 + +def _TypePrintDepth(buf: t.CChar | t.CPtr, size: t.CSizeT, + ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr, + depth: t.CInt): + """带递归深度上限的 TypePrint 内部实现""" + if ty is None or buf is None or size == 0: + return + if depth >= TYPEPRINT_MAX_DEPTH: + viperlib.snprintf(buf, size, "...") + return + buf[0] = '\0' + match ty: + case LLVMType.Int(bits): + viperlib.snprintf(buf, size, "i%d", bits) + case LLVMType.Ptr(pointee): + # ================================================================ + # LLVM IR 不允许 "void*",必须是 "i8*"。 + # 兜底处理: + # pointee == None / Void() / Label() / Metadata() → 统一打印 i8* + # ================================================================ + # 先判断是否 Struct(name) 的快速路径(需先判断 pointee 非None) + if pointee is not None: + match pointee: + case LLVMType.Struct(sfields, sfcount, sname): + if sname is not None: + # 悬空防护:sname 可能指向被 reset 回收/部分复用的 pool 内存。 + # viperlib 的 %s 未实现 precision(%.40s 会全量读 sname), + # 手动 strncpy 限长拷贝后再打印,读侧限制在缓冲内。 + # 类型名含 sha1 前缀可超 40 字符(如 + # "bbdf3bbd4c3bc28c.CONSOLE_SCREEN_BUFFER_INFO"=42), + # 原 40 字节截断会产生未定义类型引用(llc: undefined type)。 + sn_cp: t.CChar | t.CPtr = pool.alloc(256) + if sn_cp is not None: + string.strncpy(sn_cp, sname, 255) + sn_cp[255] = '\0' + viperlib.snprintf(buf, size, "%%\"%s\"*", sn_cp) + return + case LLVMType.Void(): + # Ptr(Void) → i8*(LLVM IR void* 非法) + viperlib.snprintf(buf, size, "%s", "i8*") + return + case LLVMType.Label(): + viperlib.snprintf(buf, size, "%s", "i8*") + return + case LLVMType.Metadata(): + viperlib.snprintf(buf, size, "%s", "i8*") + return + case _: + pass + # pointee == None 时也兜底 Ptr(Int8) 打印 i8* + if pointee is None: + viperlib.snprintf(buf, size, "%s", "i8*") + return + # 通用路径: 递归打印 pointee 后追加 '*' + _TypePrintDepth(buf, size, pointee, pool, depth + 1) + pos: t.CSizeT = string.strlen(buf) + if pos + 1 < size: + buf[pos] = '*' + buf[pos + 1] = '\0' + case LLVMType.Array(elem_ty, count): + # [N x elem_ty] + viperlib.snprintf(buf, size, "[%d x ", count) + # SHA1 限定类型名(如 %"21a7fcfc665f75ef.NamedTypeNode")可达 ~50 字节, + # 嵌套指针/数组更易超过 128,使用 512 字节避免截断 + tmp: t.CChar | t.CPtr = pool.alloc(512) + if tmp is not None: + _TypePrintDepth(tmp, 512, elem_ty, pool, depth + 1) + _strappend(buf, size, tmp) + _strappend(buf, size, "]") + case LLVMType.Struct(fields, fcount, name): + if name is not None: + # 命名结构体: %"name" + viperlib.snprintf(buf, size, "%%\"%s\"", name) + else: + # 匿名结构体: {ty1, ty2, ...} + _print_struct_body(buf, size, fields, pool, depth) + case LLVMType.Func(ret, params, count): + # ret (ty1, ty2, ...) + _TypePrintDepth(buf, size, ret, pool, depth + 1) + _strappend(buf, size, " (") + cur2: ParamNode | t.CPtr = params + first2: t.CInt = 1 + _pc2: t.CInt = 0 + # 函数参数类型可能为 SHA1 限定命名结构体指针,512 字节避免截断 + tmp3: t.CChar | t.CPtr = pool.alloc(512) + while cur2 is not None: + # 悬空保护:参数链若被 reset 回收后内容复用,可能成环无限循环 + _pc2 += 1 + if _pc2 > 200: + _strappend(buf, size, "...)") + break + if first2 == 0: + _strappend(buf, size, ", ") + if tmp3 is not None: + _TypePrintDepth(tmp3, 512, cur2.Ty, pool, depth + 1) + _strappend(buf, size, tmp3) + cur2 = cur2.Next + first2 = 0 + _strappend(buf, size, ")") + case LLVMType.Void(): + viperlib.snprintf(buf, size, "%s", "void") + case LLVMType.Label(): + viperlib.snprintf(buf, size, "%s", "label") + case LLVMType.Metadata(): + viperlib.snprintf(buf, size, "%s", "metadata") + case LLVMType.Float(bits): + if bits == 16: + viperlib.snprintf(buf, size, "%s", "half") + elif bits == 32: + viperlib.snprintf(buf, size, "%s", "float") + elif bits == 64: + viperlib.snprintf(buf, size, "%s", "double") + elif bits == 128: + viperlib.snprintf(buf, size, "%s", "fp128") + else: + viperlib.snprintf(buf, size, "float%x", bits) + case _: + viperlib.snprintf(buf, size, "%s", "void") + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 src 追加到 dst 末尾(不超过 dst_size)""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到 GB 外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# ============================================================ +# _print_struct_body - 打印结构体字段部分 {ty1, ty2, ...} +# +# 供 TypePrint(匿名结构体)和 PrintStructDefinition(命名结构体定义行)复用 +# ============================================================ +def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT, + fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr, + depth: t.CInt = 0): + """打印 {ty1, ty2, ...} 到 buf(追加模式,不覆盖已有内容) + + 直接在 buf 当前末尾写入字段类型,避免 pool.alloc 返回与 buf 重叠的内存 + 导致 TypePrint 写入 tmp 时覆盖 buf 已有内容。 + """ + if buf is None or size == 0: + return + _strappend(buf, size, "{") + cur: ParamNode | t.CPtr = fields + first: t.CInt = 1 + fidx: t.CInt = 0 + while cur is not None: + # 悬空保护:ParamNode 链若被 reset 回收后内容复用,Next 指针可能成环或 + # 指向垃圾,无限循环。最多打印 200 个字段即停止,防止 OOM。 + if fidx >= 200: + _strappend(buf, size, "...}") + return + if first == 0: + _strappend(buf, size, ", ") + # 直接在 buf 当前末尾位置写入字段类型 + # TypePrint 首字节置 '\0' 是无害的(pos 处本来就是 '\0') + pos: t.CSizeT = string.strlen(buf) + if pos + 2 < size: + _TypePrintDepth(buf + pos, size - pos, cur.Ty, pool, depth + 1) + cur = cur.Next + first = 0 + fidx += 1 + _strappend(buf, size, "}") + + +# ============================================================ +# PrintStructDefinition - 打印命名结构体类型定义行 +# +# 输出格式: %"name" = type { ty1, ty2, ... } +# 供 LLVMModulePrint 在全局变量/函数之前输出类型定义 +# ============================================================ +def PrintStructDefinition(buf: t.CChar | t.CPtr, size: t.CSizeT, + ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """打印命名结构体类型定义行 %"name" = type { ty1, ty2, ... } + + 当 fcount == -1(哨兵)时输出 opaque 声明: %"name" = type opaque。 + 空结构体(fcount==0, fields==None,无字段类)是完整定义,输出 "= type {}"。 + """ + if ty is None or buf is None or size == 0: + return + match ty: + case LLVMType.Struct(fields, fcount, name): + if name is None: + return + # 使用 snprintf 构建 "%%"name" = type" 前缀,避免 _strappend 截断 + # opaque 类型: fcount == -1(哨兵,跨模块前向声明) + if fcount < 0: + viperlib.snprintf(buf, size, "%%\"%s\" = type opaque", name) + else: + viperlib.snprintf(buf, size, "%%\"%s\" = type ", name) + _print_struct_body(buf, size, fields, pool) + case _: + return + + +# ============================================================ +# get_struct_name - 获取命名结构体的名称 +# +# 返回 Name 字段(如 "sha1.ClassName"),非 Struct 类型或匿名 Struct 返回 None +# 供 module_add_named_type 检查是否为命名结构体及去重 +# ============================================================ +def get_struct_name(ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr: + """获取命名结构体的名称,非命名结构体返回 None""" + if ty is None: + return None + match ty: + case LLVMType.Struct(fields, fcount, name): + return name + case _: + return None + + +def get_struct_fields(ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr: + """获取结构体的字段链表(供跨模块重建 Struct 类型用)""" + if ty is None: + return None + match ty: + case LLVMType.Struct(fields, fcount, name): + return fields + case _: + return None + + +def get_struct_fcount(ty: LLVMType | t.CPtr) -> t.CInt: + """获取结构体的字段数量(供跨模块重建 Struct 类型用)""" + if ty is None: + return 0 + match ty: + case LLVMType.Struct(fields, fcount, name): + return fcount + case _: + return 0 + + +# ============================================================ +# DeepCopyType - 深拷贝 LLVMType 到 stdlib 区(跨文件 reset 存活) +# +# 背景: 1b 阶段(mark1 之后)新注册的结构体(泛型特化类等),其 +# struct_ty 是 pool 分配的 LLVMType,所在文件翻译完 reset_to(mark1) +# 后指针悬空。_struct_table 中的 entry.Ty 指向它,后续文件遍历 +# _struct_table(find_struct_by_type/lookup_field 等)时解引用悬空 +# 指针导致崩溃(0xC0000005)。 +# +# 本函数递归拷贝整棵 LLVMType 树到 stdlib(含 ParamNode 字段链和 +# 字符串名),保证 entry.Ty 跨文件永久存活。 +# +# 注意: 自引用类型(如 Value 含 Ptr(Value) 字段)会导致无限递归, +# 用深度上限防护(超过即返回浅拷贝副本,后续不再递归)。 +# ============================================================ +DEEPCOPY_MAX_DEPTH: t.CDefine = 64 + +def DeepCopyType(pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr) -> LLVMType | t.CPtr: + """深拷贝 LLVMType 到 stdlib 区(深度限制防自引用递归),失败返回 None""" + return _DeepCopyDepth(pool, ty, 0) + + +def _DeepCopyDepth(pool: memhub.MemBuddy | t.CPtr, + ty: LLVMType | t.CPtr, depth: t.CInt) -> LLVMType | t.CPtr: + """带深度上限的深拷贝实现 + + 分配源用传入的 pool 参数(调用方决定):传主 pool 为瞬时拷贝 + (随 mark/reset 回收),传永久 pool(CompilerFactory.get_perm_pool()) + 为跨 mark 持久拷贝(代替 stdlib.malloc,buddy 分配更快)。 + """ + if ty is None: + return None + new_ty: LLVMType | t.CPtr = (LLVMType | t.CPtr)(pool.alloc(LLVMType.__sizeof__())) + if new_ty is None: + return None + string.memset(new_ty, 0, LLVMType.__sizeof__()) + if depth >= DEEPCOPY_MAX_DEPTH: + # 深度超限:浅拷贝 tag 后停止递归(复制当前变体但不深拷子类型) + match ty: + case LLVMType.Int(bits): + c.DerefAs(new_ty, LLVMType.Int(bits)) + case LLVMType.Float(bits): + c.DerefAs(new_ty, LLVMType.Float(bits)) + case LLVMType.Void(): + c.DerefAs(new_ty, LLVMType.Void()) + case LLVMType.Label(): + c.DerefAs(new_ty, LLVMType.Label()) + case LLVMType.Metadata(): + c.DerefAs(new_ty, LLVMType.Metadata()) + case _: + c.DerefAs(new_ty, LLVMType.Void()) + return new_ty + match ty: + case LLVMType.Int(bits): + c.DerefAs(new_ty, LLVMType.Int(bits)) + case LLVMType.Float(bits): + c.DerefAs(new_ty, LLVMType.Float(bits)) + case LLVMType.Void(): + c.DerefAs(new_ty, LLVMType.Void()) + case LLVMType.Label(): + c.DerefAs(new_ty, LLVMType.Label()) + case LLVMType.Metadata(): + c.DerefAs(new_ty, LLVMType.Metadata()) + case LLVMType.Ptr(pointee): + c.DerefAs(new_ty, LLVMType.Ptr(_DeepCopyDepth(pool, pointee, depth + 1))) + case LLVMType.Array(elem_ty, count): + c.DerefAs(new_ty, LLVMType.Array(_DeepCopyDepth(pool, elem_ty, depth + 1), count)) + case LLVMType.Func(ret, params, pcount): + c.DerefAs(new_ty, LLVMType.Func( + _DeepCopyDepth(pool, ret, depth + 1), + _DeepCopyParamChain(pool, params, depth + 1), pcount)) + case LLVMType.Struct(fields, fcount, name): + c.DerefAs(new_ty, LLVMType.Struct( + _DeepCopyParamChain(pool, fields, depth + 1), + fcount, _DeepCopyStr(pool, name))) + case _: + stdlib.free(new_ty) + return None + return new_ty + + +def _DeepCopyParamChain(pool: memhub.MemBuddy | t.CPtr, + head: ParamNode | t.CPtr, depth: t.CInt) -> ParamNode | t.CPtr: + """深拷贝 ParamNode 链表到 stdlib""" + if head is None: + return None + first: ParamNode | t.CPtr = None + prev: ParamNode | t.CPtr = None + cur: ParamNode | t.CPtr = head + guard: t.CInt = 0 + while cur is not None: + guard += 1 + if guard > 512: + break + node: ParamNode | t.CPtr = (ParamNode | t.CPtr)(pool.alloc(PNODE_SIZE)) + if node is None: + break + string.memset(node, 0, PNODE_SIZE) + node.Ty = _DeepCopyDepth(pool, paramnode_get_ty(cur), depth + 1) + node.Next = None + if first is None: + first = node + if prev is not None: + prev.Next = node + prev = node + cur = paramnode_get_next(cur) + return first + + +def _DeepCopyStr(pool: memhub.MemBuddy | t.CPtr, s: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """深拷贝字符串到 stdlib""" + if s is None: + return None + slen: t.CSizeT = string.strlen(s) + copy: t.CChar | t.CPtr = pool.alloc(slen + 1) + if copy is None: + return None + string.strcpy(copy, s) + return copy + + + + diff --git a/llvmlite/__values.vp b/llvmlite/__values.vp new file mode 100644 index 0000000..af44781 --- /dev/null +++ b/llvmlite/__values.vp @@ -0,0 +1,234 @@ +import t, c +from stdint import * +import string +import viperlib +import stdio +import memhub +from linkedlist import GSListNode +from .__types import LLVMType, TypePrint + + +# ============================================================ +# Value: SSA 值表示 +# +# 表示一个 LLVM IR 值:SSA 临时值(%0/%result)或常量字面量(42/0)。 +# 每个值有类型指针、名字、是否常量标志。 +# 继承 GSListNode[Value] 获取强类型 Next: Value|CPtr(值池链表) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class Value(GSListNode[Value]): + Ty: LLVMType | t.CPtr # 值的类型 + Name: t.CChar | t.CPtr # SSA 名("%0"/"%result")或常量文本("42"/"1.5e+00") + IsConst: t.CInt # 1=常量字面量, 0=SSA 临时值 + IntVal: t.CInt64T # 整数常量值(当 IsConst=1 时使用) + FloatVal: t.CDouble # 浮点常量值(当 IsConst=1 且 Ty 为 Float 时使用) + + +# ============================================================ +# 工厂函数 +# ============================================================ +# Value 硬编码大小: Next(8) + Ty(8) + Name(8) + IsConst(4) + IntVal(8) + FloatVal(8) = 48 字节 +VALUE_SIZE: t.CDefine = 48 + +def new_value(pool: memhub.MemBuddy | t.CPtr) -> Value | t.CPtr: + """从 mpool 分配一个零初始化的 Value""" + ptr: Value | t.CPtr = pool.alloc(VALUE_SIZE) + if ptr: + string.memset(ptr, 0, VALUE_SIZE) + return ptr + + +def ConstInt(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + val: t.CInt64T, name: t.CChar | t.CPtr) -> Value | t.CPtr: + """创建整数常量值 + + 参数: + ty: 整数类型(Int1/Int8/Int32/Int64) + val: 整数值 + name: 常量文本(如 "42"),由调用方提供 + """ + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = name + v.IsConst = 1 + v.IntVal = val + return v + + +def ConstNull(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + name: t.CChar | t.CPtr) -> Value | t.CPtr: + """创建 null 指针常量""" + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = name + v.IsConst = 1 + v.IntVal = 0 + return v + + +def ConstZero(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr: + """创建 zeroinitializer 常量(零初始化聚合类型:结构体/数组)""" + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = "zeroinitializer" + v.IsConst = 1 + v.IntVal = 0 + return v + + +def ConstFloat(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + val: t.CDouble) -> Value | t.CPtr: + """创建浮点常量值 + + 参数: + ty: 浮点类型(Half/Float/Double/FP128) + val: 浮点数值 + 名字自动格式化为 LLVM IR 科学计数法文本(如 "1.500000e+00")。 + """ + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.IsConst = 1 + v.FloatVal = val + v.IntVal = 0 + # 格式化名字: LLVM IR 浮点常量文本用十六进制位模式(0x%016llx / 0x%08x) + # 原因: %.17e 科学计数法文本经 llc 解析对部分值产生 ±1 ulp 误差 + # (如 "1.10000000000000000e+01" 解析为 11.000000000000002 而非 11.0, + # 导致 add_scalar[0]==11 等浮点常量比较失败)。位模式无精度损失。 + # 原 %e 默认 6 位小数还会截断精度(3.1415926535897931 -> 3.141593e+00)。 + # 用 CRT stdio.snprintf: viperlib 自实现 %g 有小数位反转 bug。 + f_bits: t.CInt = 64 + match ty: + case llvmlite.LLVMType.Float(ftb): + f_bits = ftb + fv_bits: t.CUInt64T = 0 + c.Load(c.Addr(fv_bits), c.Addr(val)) + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is not None: + if f_bits == 32: + stdio.snprintf(name_buf, 32, "0x%08x", t.CUInt32T(fv_bits)) + else: + stdio.snprintf(name_buf, 32, "0x%016llx", fv_bits) + v.Name = name_buf + return v + + +def SSAValue(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, + name: t.CChar | t.CPtr) -> Value | t.CPtr: + """创建 SSA 临时值 + + 参数: + ty: 值类型 + name: SSA 名(如 "%0"/"%result"),由调用方提供 + """ + v: Value | t.CPtr = new_value(pool) + if v is None: return None + v.Ty = ty + v.Name = name + v.IsConst = 0 + v.IntVal = 0 + return v + + +# ============================================================ +# ValuePrint: 将值序列化为 IR 文本 +# +# 示例: +# ConstInt(i32, 42, "42") -> "i32 42" +# SSAValue(i32, "%0") -> "i32 %0" +# ============================================================ +def ValuePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, + val: Value | t.CPtr, pool: memhub.MemBuddy | t.CPtr): + """将值 val 序列化为 IR 文本写入 buf + + 格式: + pool 用于复杂类型(Array/Struct/Func)递归打印时分配临时缓冲区。 + """ + if val is None or buf is None or size == 0: + return + # 先写类型 + TypePrint(buf, size, val.Ty, pool) + # 追加空格 + pos: t.CSizeT = string.strlen(buf) + if pos + 1 < size: + buf[pos] = ' ' + buf[pos + 1] = '\0' + # 追加名字 + if val.Name is not None: + pos = string.strlen(buf) + _append_str(buf, size, val.Name) + + +# ============================================================ +# Value 字段访问器(供其他模块绕过 stub 类型限制使用) +# +# 跨模块编译时,使用方模块只有 Value 的 stub 类型(字段不足或偏移错误), +# 导致 TransPyC 静默跳过字段访问(不生成 GEP,不报错)。 +# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问所有字段。 +# ============================================================ +def value_get_ty(val: Value | t.CPtr) -> LLVMType | t.CPtr: + """获取值的类型""" + if val is None: + return None + return val.Ty + + +def value_get_next(val: Value | t.CPtr) -> Value | t.CPtr: + """获取链表下一个值""" + if val is None: + return None + return val.Next + + +def value_set_ty(val: Value | t.CPtr, ty: LLVMType | t.CPtr): + """设置值的类型""" + if val is None: + return + val.Ty = ty + + +def value_set_next(val: Value | t.CPtr, nxt: Value | t.CPtr): + """设置链表下一个值""" + if val is None: + return + val.Next = nxt + + +def value_set_name(val: Value | t.CPtr, name: t.CChar | t.CPtr): + """设置值的名字""" + if val is None: + return + val.Name = name + + +def value_set_isconst(val: Value | t.CPtr, is_const: t.CInt): + """设置是否为常量""" + if val is None: + return + val.IsConst = is_const + + +# ============================================================ +# 内部辅助 +# ============================================================ +def _append_str(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' diff --git a/llvmlite/__verify.vp b/llvmlite/__verify.vp new file mode 100644 index 0000000..1c21e86 --- /dev/null +++ b/llvmlite/__verify.vp @@ -0,0 +1,403 @@ +import t, c +from stdint import * +import string +import viperlib +import memhub +from linkedlist import GSListNode, GSList +from .__function import Function, BasicBlock, Line, Param +from .__module import LLVMModule + + +# ============================================================ +# SSA 验证器 +# +# 检查项: +# 1. 块终止: 每个基本块必须以终止指令结尾 (ret/br/switch/unreachable) +# 2. SSA 唯一性: 每个 %name 只能被定义一次 +# 3. 未定义引用: 所有 %name 使用必须有对应定义 +# 4. Phi 位置: phi 指令只能出现在块首(非 phi 指令之前) +# ============================================================ + +# 错误码 +VERIFY_OK: t.CDefine = 0 +VERIFY_ERR_NO_TERMINATOR: t.CDefine = 1 +VERIFY_ERR_DUPLICATE_DEF: t.CDefine = 2 +VERIFY_ERR_UNDEFINED_USE: t.CDefine = 3 +VERIFY_ERR_PHI_NOT_FIRST: t.CDefine = 4 + + +# ============================================================ +# NameEntry: 已定义 SSA 名条目(链表节点) +# +# 注意: 必须加 @t.NoVTable(理由见 __function.py 的 Line 注释)。 +# ============================================================ +@t.NoVTable +class NameEntry(GSListNode[NameEntry]): + Name: t.CChar | t.CPtr # SSA 名(如 "%0"/"%result") + + +# ============================================================ +# VerifyResult: 验证结果 +# ============================================================ +class VerifyResult: + ErrorCount: t.CInt # 错误总数 + WarningCount: t.CInt # 警告总数 + ErrorCode: t.CInt # 第一个错误码 + ErrorBuf: t.CChar | t.CPtr # 错误消息缓冲区 + ErrorBufSize: t.CSizeT # 缓冲区大小 + + +# ============================================================ +# 辅助函数 +# ============================================================ +def _new_verify_result(pool: memhub.MemBuddy | t.CPtr, + buf_size: t.CSizeT) -> VerifyResult | t.CPtr: + """创建验证结果对象""" + ptr: VerifyResult | t.CPtr = pool.alloc(VerifyResult.__sizeof__()) + if ptr is None: return None + string.memset(ptr, 0, VerifyResult.__sizeof__()) + ptr.ErrorCount = 0 + ptr.WarningCount = 0 + ptr.ErrorCode = VERIFY_OK + buf: t.CChar | t.CPtr = pool.alloc(buf_size) + if buf is not None: + buf[0] = '\0' + ptr.ErrorBuf = buf + ptr.ErrorBufSize = buf_size + return ptr + + +def _report_error(result: VerifyResult | t.CPtr, code: t.CInt, msg: t.CChar | t.CPtr): + """记录一个错误""" + if result is None: return + result.ErrorCount += 1 + if result.ErrorCode == VERIFY_OK: + result.ErrorCode = code + if result.ErrorBuf is not None and msg is not None: + _append_cstr(result.ErrorBuf, result.ErrorBufSize, msg) + _append_cstr(result.ErrorBuf, result.ErrorBufSize, "\n") + + +def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): + """将 src 追加到 dst 末尾""" + if dst is None or src is None: return + dlen: t.CSizeT = string.strlen(dst) + # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, + # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 + if dlen >= dst_size: + return + slen: t.CSizeT = string.strlen(src) + remain: t.CSizeT = dst_size - dlen + if remain <= 0: return + i: t.CSizeT = 0 + while i < slen and i + 1 < remain: + dst[dlen + i] = src[i] + i += 1 + dst[dlen + i] = '\0' + + +# ============================================================ +# SSA 名表操作 +# ============================================================ +def _new_name_table(pool: memhub.MemBuddy | t.CPtr) -> GSList[NameEntry] | t.CPtr: + """创建空名表""" + gsl: GSList[NameEntry] | t.CPtr = pool.alloc(24) # GSList: Head+Tail+Count + if gsl is None: return None + string.memset(gsl, 0, 24) + return gsl + + +# NameEntry 硬编码大小: Next(8) + Name(8) = 16 字节 +NENTRY_SIZE: t.CDefine = 16 + +def _name_table_add(table: GSList[NameEntry] | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + name: t.CChar | t.CPtr) -> t.CInt: + """添加名到表。返回 1=重复, 0=成功添加""" + if table is None or name is None: return 0 + # 检查重复 + cur: NameEntry | t.CPtr = table.Head + while cur is not None: + if string.strcmp(cur.Name, name) == 0: + return 1 + cur = cur.Next + # 添加新条目 + entry: NameEntry | t.CPtr = pool.alloc(NENTRY_SIZE) + if entry is None: return 0 + string.memset(entry, 0, NENTRY_SIZE) + entry.Name = name + table.append(entry) + return 0 + + +def _name_table_contains(table: GSList[NameEntry] | t.CPtr, + name: t.CChar | t.CPtr) -> t.CInt: + """检查名是否在表中。返回 1=存在, 0=不存在""" + if table is None or name is None: return 0 + cur: NameEntry | t.CPtr = table.Head + while cur is not None: + if string.strcmp(cur.Name, name) == 0: + return 1 + cur = cur.Next + return 0 + + +# ============================================================ +# 文本分析辅助 +# ============================================================ +def _is_char_name(ch: t.CChar) -> t.CInt: + """判断字符是否为 SSA 名字符 [a-zA-Z0-9._]""" + if ch >= 'a' and ch <= 'z': return 1 + if ch >= 'A' and ch <= 'Z': return 1 + if ch >= '0' and ch <= '9': return 1 + if ch == '.' or ch == '_': return 1 + return 0 + + +def _extract_def_name(pool: memhub.MemBuddy | t.CPtr, + text: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """从定义行提取被定义的 SSA 名。 + + 定义行格式: "% = " + 返回分配的 NUL 结尾名串(如 "%0"),或 None 若非定义行。 + """ + if text is None: return None + if text[0] != '%': return None + # 扫描 " = " 模式 + i: t.CInt = 1 + while text[i] != '\0': + if text[i] == ' ' and text[i + 1] == '=' and text[i + 2] == ' ': + # 找到 " = " 在位置 i + name_len: t.CInt = i + name: t.CChar | t.CPtr = pool.alloc(name_len + 1) + if name is None: return None + j: t.CInt = 0 + while j < name_len: + name[j] = text[j] + j += 1 + name[name_len] = '\0' + return name + i += 1 + return None + + +def _is_terminator(text: t.CChar | t.CPtr) -> t.CInt: + """判断文本是否为终止指令""" + if text is None: return 0 + if string.strncmp(text, "ret", 3) == 0: return 1 + if string.strncmp(text, "br ", 3) == 0: return 1 + if string.strncmp(text, "switch ", 7) == 0: return 1 + if string.strncmp(text, "unreachable", 11) == 0: return 1 + if string.strncmp(text, "indirectbr ", 11) == 0: return 1 + if string.strncmp(text, "resume ", 7) == 0: return 1 + return 0 + + +def _is_phi(text: t.CChar | t.CPtr) -> t.CInt: + """判断文本是否为 phi 指令""" + if text is None: return 0 + if string.strstr(text, " = phi ") is not None: return 1 + return 0 + + +def _check_uses_in_line(table: GSList[NameEntry] | t.CPtr, + text: t.CChar | t.CPtr, + def_name: t.CChar | t.CPtr) -> t.CInt: + """检查行中所有 SSA 名使用是否已定义。 + + 跳过 def_name(定义位置的名字)。 + 返回未定义使用数量。 + """ + if text is None: return 0 + i: t.CInt = 0 + undef_count: t.CInt = 0 + while text[i] != '\0': + if text[i] == '%': + # 提取名 + name_start: t.CInt = i + i += 1 + while text[i] != '\0' and _is_char_name(text[i]) == 1: + i += 1 + name_len: t.CInt = i - name_start + if name_len > 1: + # 构建临时名串进行比较 + # 由于无法在栈上分配,用 strstr 进行简化检查 + # 这里采用逐字符比较方式 + if _name_matches_at(text, name_start, name_len, table) == 0: + # 检查是否是 def_name(定义本身的位置) + if def_name is not None: + if _str_matches_at(text, name_start, name_len, def_name) == 0: + undef_count += 1 + else: + undef_count += 1 + else: + i += 1 + return undef_count + + +def _name_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt, + table: GSList[NameEntry] | t.CPtr) -> t.CInt: + """检查 text[start:start+length] 是否匹配名表中的某个条目。 + 返回 1=匹配, 0=不匹配 + """ + if table is None: return 0 + cur: NameEntry | t.CPtr = table.Head + while cur is not None: + if cur.Name is not None: + if _str_matches_at(text, start, length, cur.Name) == 1: + return 1 + cur = cur.Next + return 0 + + +def _str_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt, + target: t.CChar | t.CPtr) -> t.CInt: + """检查 text[start:start+length] 是否等于 target 字符串。 + 返回 1=匹配, 0=不匹配 + """ + if text is None or target is None: return 0 + # 检查 target 长度 + target_len: t.CInt = string.strlen(target) + if target_len != length: return 0 + i: t.CInt = 0 + while i < length: + if text[start + i] != target[i]: return 0 + i += 1 + return 1 + + +# ============================================================ +# 主验证函数 +# ============================================================ +def verify_function(pool: memhub.MemBuddy | t.CPtr, + func: Function | t.CPtr, + result: VerifyResult | t.CPtr) -> t.CInt: + """验证函数的 SSA 正确性。 + + 参数: + pool: 内存池 + func: 要验证的函数 + result: 验证结果(调用前需用 _new_verify_result 创建) + + 返回: 错误数量(0 = 验证通过) + """ + if func is None or result is None: return 1 + + # 创建名表 + name_table: GSList[NameEntry] | t.CPtr = _new_name_table(pool) + if name_table is None: return 1 + + # 1. 将函数参数加入名表(参数是已定义的) + param: Param | t.CPtr = None + if func.Params is not None: + param = func.Params.Head + while param is not None: + if param.Name is not None: + _name_table_add(name_table, pool, param.Name) + param = param.Next + + # 1b. 将基本块名加入名表(块标签如 %then 是 br/phi 的合法引用目标) + blk_iter: BasicBlock | t.CPtr = None + if func.Blocks is not None: + blk_iter = func.Blocks.Head + while blk_iter is not None: + if blk_iter.Name is not None: + blk_name_len: t.CSizeT = string.strlen(blk_iter.Name) + blk_ref: t.CChar | t.CPtr = pool.alloc(blk_name_len + 2) + if blk_ref is not None: + # 构造 "%" 字符串 + blk_ref[0] = '%' + k: t.CSizeT = 0 + while k < blk_name_len: + blk_ref[k + 1] = blk_iter.Name[k] + k += 1 + blk_ref[blk_name_len + 1] = '\0' + _name_table_add(name_table, pool, blk_ref) + blk_iter = blk_iter.Next + + # 2. 遍历所有块 + blk: BasicBlock | t.CPtr = None + if func.Blocks is not None: + blk = func.Blocks.Head + while blk is not None: + # 检查终止指令 + if blk.IsTerminated == 0: + # 进一步检查最后一行是否为终止指令 + has_term: t.CInt = 0 + line_check: Line | t.CPtr = None + if blk.Lines is not None: + line_check = blk.Lines.Head + while line_check is not None: + if line_check.Buf is not None: + if _is_terminator(line_check.Buf) == 1: + has_term = 1 + line_check = line_check.Next + if has_term == 0: + blk_name: t.CChar | t.CPtr = "" + if blk.Name is not None: + blk_name = blk.Name + err_buf: t.CChar | t.CPtr = pool.alloc(128) + if err_buf is not None: + viperlib.snprintf(err_buf, 128, "ERROR: block '%s' missing terminator", blk_name) + _report_error(result, VERIFY_ERR_NO_TERMINATOR, err_buf) + + # 遍历块内指令行 + seen_non_phi: t.CInt = 0 + line: Line | t.CPtr = None + if blk.Lines is not None: + line = blk.Lines.Head + while line is not None: + if line.Buf is not None: + text: t.CChar | t.CPtr = line.Buf + + # 检查 phi 位置 + if _is_phi(text) == 1: + if seen_non_phi == 1: + phi_err: t.CChar | t.CPtr = pool.alloc(128) + if phi_err is not None: + viperlib.snprintf(phi_err, 128, "ERROR: phi not at block start") + _report_error(result, VERIFY_ERR_PHI_NOT_FIRST, phi_err) + else: + # 非空行且非 phi 标记为已见非 phi + if string.strlen(text) > 0: + seen_non_phi = 1 + + # 提取定义名 + def_name: t.CChar | t.CPtr = _extract_def_name(pool, text) + if def_name is not None: + # 检查重复定义 + dup: t.CInt = _name_table_add(name_table, pool, def_name) + if dup == 1: + dup_err: t.CChar | t.CPtr = pool.alloc(128) + if dup_err is not None: + viperlib.snprintf(dup_err, 128, "ERROR: duplicate definition '%s'", def_name) + _report_error(result, VERIFY_ERR_DUPLICATE_DEF, dup_err) + + # 检查未定义使用 + undef: t.CInt = _check_uses_in_line(name_table, text, def_name) + if undef > 0: + use_err: t.CChar | t.CPtr = pool.alloc(128) + if use_err is not None: + viperlib.snprintf(use_err, 128, "ERROR: %d undefined use(s) in: %s", undef, text) + _report_error(result, VERIFY_ERR_UNDEFINED_USE, use_err) + + line = line.Next + + blk = blk.Next + + return result.ErrorCount + + +def verify_module(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, result: VerifyResult | t.CPtr) -> t.CInt: + """验证模块中所有函数的 SSA 正确性。 + + 返回: 错误总数 + """ + if mod is None or result is None: return 1 + func: Function | t.CPtr = mod.FuncHead + while func is not None: + if func.IsDeclared == 0: + # 只验证有函数体的定义,跳过声明 + verify_function(pool, func, result) + func = func.Next + return result.ErrorCount diff --git a/lock.vp b/lock.vp new file mode 100644 index 0000000..5d0c114 --- /dev/null +++ b/lock.vp @@ -0,0 +1,38 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32sync import CRITICAL_SECTION, InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection, DeleteCriticalSection, TryEnterCriticalSection + + +class Lock: + """Mutex built on CRITICAL_SECTION, supports recursive locking. + + Usage: + lock: Lock = Lock() + with lock: + # Critical section + pass + """ + cs: CRITICAL_SECTION + + def __init__(self): + InitializeCriticalSection(c.Addr(self.cs)) + + def acquire(self): + EnterCriticalSection(c.Addr(self.cs)) + + def release(self): + LeaveCriticalSection(c.Addr(self.cs)) + + def try_acquire(self) -> BOOL: + return TryEnterCriticalSection(c.Addr(self.cs)) + + def __enter__(self) -> 'Lock' | t.CPtr: + self.acquire() + return self + + def __exit__(self): + self.release() + + def delete(self): + DeleteCriticalSection(c.Addr(self.cs)) diff --git a/memhub.vp b/memhub.vp new file mode 100644 index 0000000..ff540d4 --- /dev/null +++ b/memhub.vp @@ -0,0 +1,823 @@ +import t, c +from stdint import * +import string +import atom +import viperio +import stdio +import stdlib + +# ============================================================ +# memhub - Unified memory management library +# MemManager (polymorphic base class, vtable) +# ├─ MemPool (arena bump allocator, no support for individual free) +# ├─ MemSlab (fixed-size block pool, alloc/free tracked via bitmap) +# └─ MemBuddy (buddy system, supports alloc/free/realloc with coalescing) +# All subclasses override alloc/free/reset via vtable, invokable polymorphically through MemManager pointer +# ============================================================ + +MEMHUB_ALIGN: t.CDefine = 8 + +# MemSlab bitmap constants +MEMSLAB_MIN_BLOCK: t.CDefine = 16 +MEMSLAB_BITMAP_BYTES: t.CDefine = 256 + +# MemBuddy buddy constants +MEMBUDDY_MIN_BLOCK: t.CDefine = 32 +MEMBUDDY_MAX_ORDERS: t.CDefine = 32 +MEMBUDDY_HEADER_SIZE: t.CDefine = 8 +# 块尾 canary:alloc 时在块尾(用户数据区之外)写 8 字节哨兵, +# check_alive_blocks 校验——越界写穿数据区会破坏 canary,把 +# "崩溃点漂移/事发地遥远"变成"确定性定位到越界写发生的文件" +MEMBUDDY_CANARY: t.CDefine = 8 + + +def _canary_pattern() -> t.CUInt64T: + """块尾 canary 值(0xA5A5A5A5A5A5A5A5,64 位)""" + lo: t.CUInt64T = t.CUInt64T(0xA5A5A5A5) + return (lo << 32) | lo + +def _align_up(val: t.CSizeT, align: t.CSizeT) -> t.CSizeT: + if align == 0: return val + return (val + align - 1) & ~(align - 1) + + +def _largest_pow2_le(val: t.CSizeT) -> t.CSizeT: + if val == 0: return 0 + p: t.CSizeT = 1 + while p * 2 <= val: + p = p * 2 + return p + + +def _block_size_at_order(order: t.CInt) -> t.CSizeT: + bs: t.CSizeT = MEMBUDDY_MIN_BLOCK + i: t.CInt + for i in range(order): + bs = bs << 1 + return bs + + +# ============================================================ +# MemManager - Polymorphic base class +# @t.CVTable explicit annotation to ensure recognition as vtable class during cross-module imports +# (HandlesImports only detects IsCVTable via decorator; automatic inference is unavailable across modules) +# ============================================================ +@t.CVTable +class MemManager: + __provides__: list[str] = ['__memmgr__'] + base: t.CVoid | t.CPtr # Starting address of memory region + size: t.CSizeT # Total size of memory region + + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT): + self.base = base + self.size = size + + # === Virtual functions (overridden by subclasses) === + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + # Default: allocation not supported + return None + + def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + # Default: no operation + return 0 + + def reset(self) -> t.CInt: + # Default: no operation + return 0 + + # === Concrete methods (invoke virtual functions for automatic polymorphic dispatch) === + + def calloc(self, count: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr: + total: t.CSizeT = count * size + ptr: t.CVoid | t.CPtr = self.alloc(total) + if ptr is not None: + string.memset(ptr, 0, total) + return ptr + + def realloc(self, ptr: t.CVoid | t.CPtr, new_size: t.CSizeT) -> t.CVoid | t.CPtr: + if ptr is None: + return self.alloc(new_size) + if new_size == 0: + self.free(ptr) + return None + new_ptr: t.CVoid | t.CPtr = self.alloc(new_size) + if new_ptr is None: + return ptr + # Base class cannot track original allocation size; data will not be copied. Subclasses may override to preserve data + self.free(ptr) + return new_ptr + + def __enter__(self) -> 'MemManager' | t.CPtr: + return self + + def __exit__(self): + self.reset() + + def alloc_buf(self, capacity: t.CSizeT) -> viperio.Buf | t.CPtr: + buf: viperio.Buf | t.CPtr = self.alloc(viperio.Buf.__sizeof__()) + if buf is None: + return None + data_ptr: t.CVoid | t.CPtr = self.alloc(capacity) + if data_ptr is None: + return None + buf.__before_init__() + buf.__init__(t.CChar(t.CUInt64T(data_ptr), t.CPtr), capacity) + return buf + + +# ============================================================ +# MemPool - Arena bump allocator +# Individual free operations are unsupported; reset reclaims all memory at once +# ============================================================ +class MemPool(MemManager): + offset: t.CSizeT # Bump pointer offset + high_water: t.CSizeT # High-water mark + + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT): + self.base = base + self.size = size + self.offset = 0 + self.high_water = 0 + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + if size == 0: return None + aligned: t.CSizeT = _align_up(size, MEMHUB_ALIGN) + if self.offset + aligned > self.size: + stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n") + stdio.printf("[OOM] 尝试分配: %zu 字节,失败\n", size) + stdio.printf("[OOM] MemPool: total=%zu used=%zu (bump allocator, 无释放)\n", + self.size, self.offset) + stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n") + stdlib.exit(1) + ptr: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.base) + self.offset, t.CPtr) + self.offset += aligned + if self.offset > self.high_water: + self.high_water = self.offset + return ptr + + def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + # Bump allocator does not support individual free operations + return 1 + + def reset(self) -> t.CInt: + self.offset = 0 + self.high_water = 0 + return 1 + + +# ============================================================ +# MemSlab - Fixed-size block pool +# Bitmap stored at the start of arena; subsequent area split into block_size units managed by free list +# ============================================================ +class MemSlab(MemManager): + block_size: t.CSizeT # Block size (aligned) + block_count: t.CSizeT # Total block count + used_count: t.CSizeT # Used block count + free_list: t.CVoid | t.CPtr # Free list head + alloc_map: t.CUInt8T | t.CPtr # Allocation bitmap (at start of arena) + alloc_map_size: t.CSizeT # Bitmap byte count + usable: t.CVoid | t.CPtr # Usable block area start (after bitmap) + usable_size: t.CSizeT # Usable block area size + + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT, block_size: t.CSizeT): + self.base = base + self.size = size + 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 + self.usable = None + self.usable_size = 0 + + if base is None: return + + bs: t.CSizeT = _align_up(block_size, MEMHUB_ALIGN) + if bs < MEMSLAB_MIN_BLOCK: bs = MEMSLAB_MIN_BLOCK + + map_bytes: t.CSizeT = _align_up(MEMSLAB_BITMAP_BYTES, MEMHUB_ALIGN) + if size < map_bytes + bs: return + + self.alloc_map = base + self.alloc_map_size = map_bytes + self.usable = t.CVoid(t.CUInt64T(base) + map_bytes, t.CPtr) + self.usable_size = size - map_bytes + self.block_size = bs + + # Clear bitmap + idx: t.CSizeT = 0 + while idx < map_bytes: + self.alloc_map[idx] = 0 + idx += 1 + + self.block_count = self.usable_size / bs + if self.block_count == 0: return + + # Construct free list: the first 8 bytes of each block store pointer to next block + self.free_list = None + i: t.CSizeT = 0 + while i < self.block_count: + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(self.usable) + i * bs, t.CPtr) + c.DerefAs(block, self.free_list) + self.free_list = block + i += 1 + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + # Slab mode: allocate one block only if requested size <= block_size + if self.free_list is None: + stdio.printf("\n[OOM] 内存不足 (Out of Memory)\n") + stdio.printf("[OOM] 尝试分配: %zu 字节,失败(free_list 已空)\n", size) + stdio.printf("[OOM] MemSlab: block_size=%zu block_count=%zu used=%zu\n", + self.block_size, self.block_count, self.used_count) + stdio.printf("[OOM] 说明: 内存池已耗尽。可能原因: (1) 池大小不足,需增大 POOL_SIZE; (2) 存在内存泄漏。\n") + stdlib.exit(1) + if size > self.block_size: + # 超块大小请求 = 调用方错误:优雅失败返回 NULL(类 malloc 语义,调用方自行判断)。 + # 与 free_list 耗尽(真正的 OOM,打印后 exit(1))区分开。 + stdio.printf("[WARN] MemSlab: 请求 %zu 字节超过 block_size=%zu,分配失败返回 NULL;应改用 MemBuddy/MemPool。\n", + size, self.block_size) + 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.usable)) / self.block_size + self.alloc_map[idx / 8] = self.alloc_map[idx / 8] | t.CUInt8T(1 << (idx % 8)) + return block + + def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + if ptr is None: return 0 + p: t.CUInt64T = t.CUInt64T(ptr) + if p < t.CUInt64T(self.usable): return 0 + if p >= t.CUInt64T(self.usable) + self.block_count * self.block_size: return 0 + if (p - t.CUInt64T(self.usable)) % self.block_size != 0: return 0 + idx: t.CSizeT = (p - t.CUInt64T(self.usable)) / 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 0 + 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 + return 1 + + def reset(self) -> t.CInt: + 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.usable) + 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 + return 1 + + +# ============================================================ +# MemBuddy - Buddy system allocator +# Free list head array stored at arena start; subsequent memory managed in power-of-two sized blocks +# Thread-safe (spinlock enabled), supports block coalescing +# +# Checkpoint 支持(供编译器等长任务回收阶段性分配): +# mark() → 返回当前分配水位(不分配内存) +# reset_to(m) → 释放水位 m 之后分配的所有块(回收到 free list) +# 记录栈从 usable 顶部预留 _CHK_RESERVE 字节,不参与 buddy 分配。 +# ============================================================ +class MemBuddy(MemManager): + # Override parent __provides__: MemBuddy provides both __mbuddy__ and __memmgr__. + # Within `with MemBuddy(...)` context, classes (e.g. _str) with __requires__=['__mbuddy__'] + # can be automatically injected via _find_provider + __provides__: list[str] = ['__mbuddy__', '__memmgr__'] + max_order: t.CInt # Maximum order + free_lists: t.CUInt64T | t.CPtr # Free list head array (located at arena start) + lock_val: t.CVolatile | t.CInt # Spinlock + usable: t.CVoid | t.CPtr # Start of usable memory region (skips free_lists) + usable_size: t.CSizeT # Size of usable memory (power of two) + chk_stack: t.CUInt64T | t.CPtr # Checkpoint 分配记录栈(存 block 地址) + chk_cap: t.CSizeT # 记录栈容量(条目数) + chk_depth: t.CSizeT # 当前记录深度 + chk_base: t.CVoid | t.CPtr # 记录栈起始地址(由 stdlib.malloc 分配,独立于 buddy 区) + big_alloc_count: t.CSizeT # ≥8KB 大分配计数(OOM 诊断:定位大缓冲反复分配) + + def __init__(self, base: t.CVoid | t.CPtr, size: t.CSizeT): + self.base = base + self.size = size + self.max_order = 0 + self.free_lists = None + self.lock_val = 0 + self.usable = None + self.usable_size = 0 + self.chk_stack = None + self.chk_cap = 0 + self.chk_depth = 0 + self.chk_base = None + self.big_alloc_count = 0 + + self.lock_val = 0 + fl_bytes: t.CSizeT = (MEMBUDDY_MAX_ORDERS + 1) * 8 + self.free_lists = base + + # Initialize all free list heads to be 0 + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + self.free_lists[i] = 0 + + if size <= fl_bytes: + self.usable = None + self.usable_size = 0 + self.max_order = 0 + return + + remaining: t.CSizeT = size - fl_bytes + + # 注意:不能在 __init__ 里预留 checkpoint 记录栈! + # 记录栈改为 mark() 时从 buddy 池懒分配(见 mark())。 + # + # 非 2 的幂 arena 支持:主池 1.2GB(非 2 幂)不再被 + # _largest_pow2_le 砍成 1GB 浪费 0.2GB。整个区域按二进制 + # 分解拆成若干个 2 的幂空闲块压入对应 free list;buddy 合并 + # 按 offset^bs 匹配,跨分解边界的块因 order 不匹配自然停止 + # 合并,不会破坏 buddy 一致性。remaining 恰为 2 的幂时分解 + # 结果与原实现(单个 max_order 块)完全等价。 + max_blk: t.CSizeT = _largest_pow2_le(remaining) + if max_blk < MEMBUDDY_MIN_BLOCK: + self.usable = None + self.usable_size = 0 + self.max_order = 0 + return + + self.usable = t.CVoid(t.CUInt64T(base) + fl_bytes, t.CPtr) + + # 计算 max_order: log2(max_blk / MIN_BLOCK) + self.max_order = 0 + bs: t.CSizeT = MEMBUDDY_MIN_BLOCK + while bs < max_blk: + bs = bs << 1 + self.max_order += 1 + + # 二进制分解:把 [usable, usable+remaining) 拆成 2 的幂空闲块。 + # 尾部碎片(< MIN_BLOCK)不入 free list;usable_size 记实际 + # 可分配字节(used/free 统计不含碎片)。 + pos: t.CSizeT = 0 + rem: t.CSizeT = remaining + used_area: t.CSizeT = 0 + while rem >= MEMBUDDY_MIN_BLOCK: + blk: t.CSizeT = _largest_pow2_le(rem) + o: t.CInt = 0 + ob: t.CSizeT = MEMBUDDY_MIN_BLOCK + while ob < blk: + ob = ob << 1 + o += 1 + self._fl_push(o, t.CVoid(t.CUInt64T(self.usable) + pos, t.CPtr)) + pos += blk + used_area += blk + rem -= blk + self.usable_size = used_area + + # === Checkpoint support === + + def mark(self) -> t.CSizeT: + """返回当前分配水位(checkpoint) + + 记录栈用 stdlib.malloc 分配(独立于 buddy 区,避免占用 buddy 池、 + 避免 reset_to 误释放栈自身,也避免栈内存与 buddy 块重叠)。 + 初始容量 2M 条目(16MB):单文件翻译(parse AST + 生成 IR)可产生 + 几十万次 alloc,64K 初始容量会在首个大文件就触发 realloc 扩容, + 扩容失败时块不再记录 → reset_to 永久 no-op → 所有分配泄漏 → + 1GB 主池 OOM(NewAstTest Phase2 根因)。 + """ + if self.chk_stack is None: + cap: t.CSizeT = 2 * 1024 * 1024 + base: t.CVoid | t.CPtr = t.CVoid(stdlib.malloc(cap * 8), t.CPtr) + if base is None: + return 0 + self.chk_base = base + self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(base, t.CPtr)) + self.chk_cap = cap + self.chk_depth = 0 + return self.chk_depth + + def reset_to(self, mark: t.CSizeT): + """释放水位 mark 之后分配的所有块,回收到 free list + + 栈中每个 block:若 header 仍标记为已分配(奇数),_coalesce 归还; + 若已被单独 free(header==0),跳过避免重复归还。 + """ + if self.chk_stack is None: + return + if mark > self.chk_depth: + # mark 大于当前深度:调用方 mark 值异常(可能读错字段/跨实例), + # reset 将 no-op → 之后分配全泄漏 → 1GB 主池 OOM。fail-fast 暴露。 + stdio.printf( + "[MEM] reset_to mark=%zu > chk_depth=%zu(mark 异常,reset 失效,终止)\n", + mark, self.chk_depth) + return + if mark >= self.chk_depth: + return + self._lock() + while self.chk_depth > mark: + self.chk_depth -= 1 + block: t.CVoid | t.CPtr = t.CVoid(self.chk_stack[self.chk_depth], t.CPtr) + if block is None: + continue + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + if (stored_val & 1) == 0: + continue # 已被单独 free,跳过 + order: t.CInt = t.CInt(stored_val >> 1) + if order < 0 or order > self.max_order: + continue + self._coalesce(block, order) + self._unlock() + + def reset_all(self): + """回收全部已分配块(等价 reset_to(0))""" + if self.chk_stack is None: + return + self.reset_to(0) + + # === Free list operations === + + def _fl_push(self, order: t.CInt, block: t.CVoid | t.CPtr): + old_head: t.CUInt64T = self.free_lists[order] + c.DerefAs(block, t.CVoid(old_head, t.CPtr)) + self.free_lists[order] = t.CUInt64T(block) + + def _fl_pop(self, order: t.CInt) -> t.CVoid | t.CPtr: + head_val: t.CUInt64T = self.free_lists[order] + if head_val == 0: + return None + block: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + self.free_lists[order] = t.CUInt64T(next_ptr) + return block + + def _fl_find_and_remove(self, order: t.CInt, target: t.CVoid | t.CPtr) -> t.CInt: + head_val: t.CUInt64T = self.free_lists[order] + if head_val == 0: + return 0 + head: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + if t.CUInt64T(head) == t.CUInt64T(target): + next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(head, t.CPtr)), t.CPtr) + self.free_lists[order] = t.CUInt64T(next_ptr) + return 1 + prev: t.CVoid | t.CPtr = head + cur: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(head, t.CPtr)), t.CPtr) + while t.CUInt64T(cur) != 0: + if t.CUInt64T(cur) == t.CUInt64T(target): + next_ptr: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + c.DerefAs(prev, next_ptr) + return 1 + prev = cur + cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + return 0 + + # === Buddy system core === + + def _buddy_of(self, block: t.CVoid | t.CPtr, order: t.CInt) -> t.CVoid | t.CPtr: + offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable) + bs: t.CSizeT = _block_size_at_order(order) + buddy_offset: t.CSizeT = offset ^ bs + return t.CVoid(t.CUInt64T(self.usable) + buddy_offset, t.CPtr) + + def _order_for_size(self, size: t.CSizeT) -> t.CInt: + order: t.CInt = 0 + bs: t.CSizeT = MEMBUDDY_MIN_BLOCK + while bs < size: + bs = bs << 1 + order += 1 + return order + + def _split_to_order(self, to_order: t.CInt) -> t.CVoid | t.CPtr: + found_order: t.CInt = to_order + while found_order <= self.max_order: + if self.free_lists[found_order] != 0: + break + found_order += 1 + if found_order > self.max_order: + return None + block: t.CVoid | t.CPtr = self._fl_pop(found_order) + while found_order > to_order: + found_order -= 1 + bs: t.CSizeT = _block_size_at_order(found_order) + buddy: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(block) + bs, t.CPtr) + self._fl_push(found_order, buddy) + return block + + def _coalesce(self, block: t.CVoid | t.CPtr, order: t.CInt): + while order < self.max_order: + buddy: t.CVoid | t.CPtr = self._buddy_of(block, order) + found: t.CInt = self._fl_find_and_remove(order, buddy) + if found == 0: + break + if t.CUInt64T(buddy) < t.CUInt64T(block): + block = buddy + order += 1 + self._fl_push(order, block) + + def _is_valid_ptr(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + if ptr is None: return 0 + if self.usable is None: return 0 + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr) + if t.CUInt64T(block) < t.CUInt64T(self.usable): return 0 + if t.CUInt64T(block) >= t.CUInt64T(self.usable) + self.usable_size: return 0 + offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable) + if offset % MEMBUDDY_MIN_BLOCK != 0: return 0 + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + if (stored_val & 1) == 0: return 0 + order: t.CInt = t.CInt(stored_val >> 1) + if order < 0: return 0 + if order > self.max_order: return 0 + # 记录栈一致性校验:分配时(alloc)每个 block 地址都会压入 chk_stack。 + # reset_to(mark) 会把 [mark, chk_depth) 的块弹栈并归还 free list, + # 之后这些地址会被重新分配。若一个 header 恰好是合法奇数(假阳性), + # 但地址不在当前 chk_stack[0..chk_depth) 存活区间内,说明已被回收, + # 不能当作有效指针(否则 _format_func_type_str/TypePrint 会沿垃圾链 + # 无限分配导致 OOM)。 + # 注意:chk_stack 容量满(64K)后 alloc 不再记录新块(chk_depth==chk_cap), + # 此时无法区分,跳过校验(退化到仅 header 校验,避免误判正常 free)。 + if self.chk_stack is not None and self.chk_depth < self.chk_cap: + alive: t.CInt = 0 + ci: t.CSizeT = 0 + while ci < self.chk_depth: + if self.chk_stack[ci] == t.CUInt64T(block): + alive = 1 + break + ci += 1 + if alive == 0: + return 0 + return 1 + + # === Spinlock === + + def _lock(self): # can use the spinlock library for decoupling + while atom.__atomic_test_and_set(c.Addr(self.lock_val), atom.ATOMIC_ACQUIRE): + pass + + def _unlock(self): + atom.__atomic_clear(c.Addr(self.lock_val), atom.ATOMIC_RELEASE) + + # === Virtual function overrides === + + def alloc(self, size: t.CSizeT) -> t.CVoid | t.CPtr: + self._lock() + result: t.CVoid | t.CPtr = None + if size != 0 and self.usable is not None: + # +MEMBUDDY_CANARY:预留块尾 8 字节哨兵(用户数据区之外),越界写定位用 + needed: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY + order: t.CInt = self._order_for_size(needed) + if order <= self.max_order: + block: t.CVoid | t.CPtr = self._split_to_order(order) + if block is not None: + c.DerefAs(block, t.CVoid(t.CUInt64T((order << 1) | 1), t.CPtr)) + result = t.CVoid(t.CUInt64T(block) + MEMBUDDY_HEADER_SIZE, t.CPtr) + # 写块尾 canary(block + block_size - CANARY) + bs: t.CSizeT = _block_size_at_order(order) + c.DerefAs(t.CVoid(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr), + t.CVoid(_canary_pattern(), t.CPtr)) + # 记录到 checkpoint 栈(供 reset_to 回收) + # 栈满时 stdlib.realloc 翻倍扩容(防爆满后记录缺失 + # → reset 不回收 + _is_valid_ptr 栈校验退化的连锁问题) + if self.chk_stack is not None: + if self.chk_depth >= self.chk_cap: + new_cap: t.CSizeT = self.chk_cap * 2 + new_stack: t.CVoid | t.CPtr = t.CVoid( + stdlib.realloc(self.chk_base, new_cap * 8), t.CPtr) + if new_stack is not None: + self.chk_base = new_stack + self.chk_stack = (t.CUInt64T | t.CPtr)(t.CVoid(new_stack, t.CPtr)) + self.chk_cap = new_cap + else: + # realloc 失败:块不再记录 → reset_to 无法回收该块 → + # 渐进泄漏最终 1GB 主池 OOM。fail-fast 暴露而非静默。 + stdio.printf( + "[MEM] 记录栈 realloc 失败 cap=%zu depth=%zu(reset 将失效,终止)\n", + self.chk_cap, self.chk_depth) + if self.chk_depth < self.chk_cap: + self.chk_stack[self.chk_depth] = t.CUInt64T(block) + self.chk_depth += 1 + if result is None: + # 分配失败诊断(定位"异常 size/池耗尽导致 None → 调用方解引用段错误") + if size != 0 and self.usable is not None: + needed2: t.CSizeT = size + MEMBUDDY_HEADER_SIZE + MEMBUDDY_CANARY + order2: t.CInt = self._order_for_size(needed2) + stdio.printf("[MEM] alloc 失败 size=%zu needed=%zu order=%d max_order=%d used=%zu\n", + size, needed2, order2, self.max_order, self.used_bytes()) + # 越界写诊断:free list 结构损坏(self_check!=0)说明有越界写穿 + # 破坏块头/free list next 指针 → alloc 找不到块(used 虚高非真实耗尽) + sc: t.CInt = self.self_check() + stdio.printf("[MEM] alloc 失败 self_check=%d free_bytes=%zu free_count=%zu chk_depth=%zu big=%zu\n", + sc, self.free_bytes(), self.free_count(), self.chk_depth, self.big_alloc_count) + # chk_depth 巨大(数百万)→ 分配次数爆炸(每语句/每调用反复分配); + # chk_depth 不大但 used 巨大 → 单次大分配(缓冲/表扩容)反复发生 + if order2 > self.max_order: + stdio.printf("[MEM] 原因:请求 size 超 pool 最大块(order %d > max %d)\n", + order2, self.max_order) + else: + stdio.printf("[MEM] 原因:pool 耗尽(空闲 %zu 字节不足)\n", self.free_bytes()) + # 分配失败(alloc(0) 或池耗尽):解锁并返回 None,由调用者决定后续处理。 + # 不能 exit——测试依赖 alloc 失败返回 None 后继续 free+重试 + # (如 OOM section: 耗尽后 free 一块再 alloc 应成功)。 + self._unlock() + return None + self._unlock() + return result + + def free(self, ptr: t.CVoid | t.CPtr) -> t.CInt: + self._lock() + if ptr is not None: + if self._is_valid_ptr(ptr) != 0: + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr) + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + order: t.CInt = t.CInt(stored_val >> 1) + c.DerefAs(block, t.CVoid(0, t.CPtr)) + self._coalesce(block, order) + self._unlock() + return 1 + + def _rebuild_free_lists(self): + """按二进制分解重建空闲链表(reset 恢复初始分配格局) + + 与 __init__ 的初始化分解一致:非 2 的幂 arena 会拆成多个 + 2 的幂空闲块(buddy 合并跨分解边界时因 order 不匹配自然 + 停止,安全);2 的幂 arena 等价于单个 max_order 块。 + """ + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + self.free_lists[i] = 0 + pos: t.CSizeT = 0 + rem: t.CSizeT = self.usable_size + while rem >= MEMBUDDY_MIN_BLOCK: + blk: t.CSizeT = _largest_pow2_le(rem) + o: t.CInt = 0 + ob: t.CSizeT = MEMBUDDY_MIN_BLOCK + while ob < blk: + ob = ob << 1 + o += 1 + self._fl_push(o, t.CVoid(t.CUInt64T(self.usable) + pos, t.CPtr)) + pos += blk + rem -= blk + + def reset(self) -> t.CInt: + if self.usable is None: + return 0 + self._rebuild_free_lists() + return 1 + + # realloc override: buddy system reads original order from block header; old_size is not required + def realloc(self, ptr: t.CVoid | t.CPtr, new_size: t.CSizeT) -> t.CVoid | t.CPtr: + if ptr is None: + return self.alloc(new_size) + if new_size == 0: + self.free(ptr) + return None + if self._is_valid_ptr(ptr) == 0: + return None + block: t.CVoid | t.CPtr = t.CVoid(t.CUInt64T(ptr) - MEMBUDDY_HEADER_SIZE, t.CPtr) + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + old_order: t.CInt = t.CInt(stored_val >> 1) + needed: t.CSizeT = new_size + MEMBUDDY_HEADER_SIZE + new_order: t.CInt = self._order_for_size(needed) + if new_order <= old_order: + return ptr + new_ptr: t.CVoid | t.CPtr = self.alloc(new_size) + if new_ptr is None: + return ptr + old_block_size: t.CSizeT = _block_size_at_order(old_order) + old_data_size: t.CSizeT = old_block_size - MEMBUDDY_HEADER_SIZE + string.memcpy(new_ptr, ptr, old_data_size) + self.free(ptr) + return new_ptr + + # === Status Queries === + + @property + def mem_size(self) -> t.CSizeT: + # Total usable region size (power of two). Maximum allocatable size = mem_size - MEMBUDDY_HEADER_SIZE + return self.usable_size + + def stats(self) -> t.CSizeT: + # Return total usable region size, for status statistics + return self.usable_size + + def free_count(self) -> t.CSizeT: + # Count total blocks in all order lists for status statistics + count: t.CSizeT = 0 + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + head_val: t.CUInt64T = self.free_lists[i] + cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + while t.CUInt64T(cur) != 0: + count += 1 + cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + return count + + def free_bytes(self) -> t.CSizeT: + # Count total bytes in all free blocks for status statistics + total: t.CSizeT = 0 + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + head_val: t.CUInt64T = self.free_lists[i] + cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + while t.CUInt64T(cur) != 0: + total += _block_size_at_order(i) + cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + return total + + def used_bytes(self) -> t.CSizeT: + # Used bytes = total usable region size - free bytes in all free blocks + return self.usable_size - self.free_bytes() + + def dump_stats(self, label: t.CChar | t.CPtr): + # Print memory usage statistics + fb: t.CSizeT = self.free_bytes() + ub: t.CSizeT = self.usable_size - fb + stdio.printf("[MEM] %s: total=%zu used=%zu (%zu%%) free=%zu free_blocks=%zu\n", + label, self.usable_size, ub, + (ub * 100) / self.usable_size if self.usable_size > 0 else 0, + fb, self.free_count()) + + def self_check(self) -> t.CInt: + # Validate buddy allocator internal consistency, return 0=OK, non-0=damage + if self.usable is None: + return 0 + # 环检测:free list 被越界写破坏 next 指针后可能成环, + # 无步数上限会导致无限循环(崩溃点漂移排查哨兵必须能终止)。 + max_steps: t.CSizeT = self.usable_size / MEMBUDDY_MIN_BLOCK + 2 + i: t.CInt + for i in range(MEMBUDDY_MAX_ORDERS + 1): + head_val: t.CUInt64T = self.free_lists[i] + cur: t.CVoid | t.CPtr = t.CVoid(head_val, t.CPtr) + steps: t.CSizeT = 0 + while t.CUInt64T(cur) != 0: + steps += 1 + if steps > max_steps: + return 4 # free list 成环或节点数超上限(next 指针被破坏) + # Check pointer is in usable region range + if t.CUInt64T(cur) < t.CUInt64T(self.usable): + return 1 + if t.CUInt64T(cur) >= t.CUInt64T(self.usable) + self.usable_size: + return 2 + # Check alignment: order i blocks must be aligned to size _block_size_at_order(i) + offset: t.CSizeT = t.CUInt64T(cur) - t.CUInt64T(self.usable) + bs: t.CSizeT = _block_size_at_order(i) + if offset % bs != 0: + return 3 + cur = t.CVoid(c.Deref(t.CUInt64T(cur, t.CPtr)), t.CPtr) + return 0 + + def check_alive_blocks(self, from_mark: t.CSizeT) -> t.CInt: + # 检查 [from_mark, chk_depth) 记录的所有已分配块 header 完整性。 + # 越界写(参数错位/下标 GEP 越界)会破坏相邻块 header(奇偶位/order 错乱), + # 返回 0=OK,非 0=损坏(rc 语义见调用方注释)。 + # 用于 reset_to 前哨兵:把"崩溃点漂移"变成"确定性定位到损坏发生的文件"。 + if self.chk_stack is None: + return + if from_mark > self.chk_depth: + # from_mark 大于当前深度:调用方 mark 值异常(可能读错字段/跨实例), + # 校验将 no-op → 越界写漏检。fail-fast 暴露。 + stdio.printf( + "[MEM] check_alive_blocks from_mark=%zu > chk_depth=%zu(mark 异常)\n", + from_mark, self.chk_depth) + return + if from_mark >= self.chk_depth: + return 0 + if self.usable is None: + return 0 + ci: t.CSizeT = from_mark + while ci < self.chk_depth: + block: t.CVoid | t.CPtr = t.CVoid(self.chk_stack[ci], t.CPtr) + if block is not None: + if t.CUInt64T(block) < t.CUInt64T(self.usable): + return 1 + if t.CUInt64T(block) >= t.CUInt64T(self.usable) + self.usable_size: + return 2 + stored: t.CVoid | t.CPtr = t.CVoid(c.Deref(t.CUInt64T(block, t.CPtr)), t.CPtr) + stored_val: t.CUInt64T = t.CUInt64T(stored) + if (stored_val & 1) != 0: + # 活块:header 必须是 (order<<1)|1,order 合法且块对齐到该 order 大小 + order: t.CInt = t.CInt(stored_val >> 1) + if order < 0: + return 3 + if order > self.max_order: + return 4 + offset: t.CSizeT = t.CUInt64T(block) - t.CUInt64T(self.usable) + bs: t.CSizeT = _block_size_at_order(order) + if offset % bs != 0: + return 5 + # 块尾 canary 校验:越界写穿数据区会破坏块尾哨兵, + # 立即定位到越界写发生的文件(崩溃点漂移的关键哨兵) + can_stored: t.CVoid | t.CPtr = t.CVoid( + c.Deref(t.CUInt64T(t.CUInt64T(block) + bs - MEMBUDDY_CANARY, t.CPtr), t.CPtr), + t.CPtr) + if t.CUInt64T(can_stored) != _canary_pattern(): + return 6 + ci += 1 + return 0 + diff --git a/numpy/__init__.vp b/numpy/__init__.vp new file mode 100644 index 0000000..f8e5456 --- /dev/null +++ b/numpy/__init__.vp @@ -0,0 +1,1163 @@ +from stdint import * +import stdlib +import string +import vipermath +import stdio +import t, c +import memhub + + +# ============================================================ +# 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 - generic n-dimensional array (PEP 695) +# +# Element type T is a numeric type (t.CDouble / t.CFloat / t.CInt / ...). +# T is erased to i8* at the IR level but each ndarray[T] instantiation +# generates specialized code (data access uses T's load/store width). +# +# Default usage: ndarray[t.CDouble] for floating point. +# ============================================================ +@t.Object +class ndarray[T]: + data: T | t.CPtr + shape: t.CArray[t.CSizeT, MAX_NDIM] + strides: t.CArray[t.CSizeT, MAX_NDIM] + ndim: t.CInt + size: t.CSizeT + owns_data: t.CInt + pool: memhub.MemManager | t.CPtr + + def __new__(self, pool: memhub.MemManager | t.CPtr, n: t.CSizeT): + self.pool = pool + self.data = pool.alloc(n * T.__sizeof__()) + if self.data: + string.memset(self.data, 0, n * T.__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] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | 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] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | 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] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | 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] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != T(0): + result.data[i] = self.data[i] / other.data[i] + else: + result.data[i] = T(0) + i += 1 + return result + + def __floordiv__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != T(0): + result.data[i] = vipermath.floor(self.data[i] / other.data[i]) + else: + result.data[i] = T(0) + i += 1 + return result + + def __mod__(self, other: ndarray[T] | t.CPtr) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + i: t.CSizeT = 0 + while i < self.size: + if other.data[i] != T(0): + result.data[i] = vipermath.fmod(self.data[i], other.data[i]) + else: + result.data[i] = T(0) + i += 1 + return result + + def __neg__(self) -> ndarray[T] | t.CPtr: + result: ndarray[T] | 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: + return self.data[row * self.shape[1] + col] + + def set2d(self, row: t.CSizeT, col: t.CSizeT, val: T): + 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): + i: t.CSizeT = 0 + while i < self.size: + self.data[i] = val + i += 1 + + def copy(self) -> ndarray[T] | t.CPtr: + result: ndarray[T] | t.CPtr = _empty_like(self) + if not result: return None + string.memcpy(result.data, self.data, self.size * T.__sizeof__()) + return result + + def reshape(self, new_shape: INTPTR, new_ndim: t.CInt) -> ndarray[T] | 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] | 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: + s: T = T(0) + i: t.CSizeT = 0 + while i < self.size: + s += self.data[i] + i += 1 + return s + + def mean(self) -> T: + if self.size == 0: return T(0) + return self.sum() / T(self.size) + + def min(self) -> T: + if self.size == 0: return T(0) + m: T = 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: + if self.size == 0: return T(0) + m: T = 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 = 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 = 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] | t.CPtr) -> T: + s: T = T(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] | t.CPtr: + if self.ndim != 2: return None + rows: t.CSizeT = self.shape[0] + cols: t.CSizeT = self.shape[1] + result: ndarray[T] | 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: + stdio.printf("[") + i: t.CSizeT = 0 + while i < self.size: + if i > 0: stdio.printf(", ") + stdio.printf("%.4f", self.data[i]) + i += 1 + stdio.printf("]\n") + elif self.ndim == 2: + rows: t.CSizeT = self.shape[0] + cols: t.CSizeT = self.shape[1] + stdio.printf("[") + i: t.CSizeT = 0 + while i < rows: + if i > 0: stdio.printf(" ") + stdio.printf("[") + j: t.CSizeT = 0 + while j < cols: + if j > 0: stdio.printf(", ") + stdio.printf("%.4f", self.data[i * cols + j]) + j += 1 + if i < rows - 1: + stdio.printf("]\n") + else: + stdio.printf("]]\n") + i += 1 + + +# ============================================================ +# Convenience aliases: typed ndarray instantiations +# (must be after class ndarray[T] definition to avoid forward reference) +# ============================================================ +Float64Array: t.CTypedef = ndarray[t.CDouble] +Float32Array: t.CTypedef = ndarray[t.CFloat] +Int64Array: t.CTypedef = ndarray[t.CLong] +Int32Array: t.CTypedef = ndarray[t.CInt] +Uint8Array: t.CTypedef = ndarray[t.CUnsignedChar] + + +# ============================================================ +# Internal helpers (specialized for float64 by default) +# Use _alloc_ndarray_t[T] / _empty_like_t[T] for other types +# ============================================================ +def _alloc_ndarray(pool: memhub.MemManager | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = pool.alloc(ndarray[t.CDouble].__sizeof__()) + if a: + string.memset(a, 0, ndarray[t.CDouble].__sizeof__()) + return a + +def _compute_strides(a: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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 (float64 default) +# ============================================================ +def array(pool: memhub.MemManager | t.CPtr, data: t.CDouble | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | 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 + string.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: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | 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 + string.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: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = zeros(pool, n) + if not a: return None + a.fill(t.CDouble(1.0)) + return a + +def full(pool: memhub.MemManager | t.CPtr, n: t.CSizeT, val: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = zeros(pool, n) + if not a: return None + a.fill(val) + return a + +def arange(pool: memhub.MemManager | t.CPtr, start: t.CDouble, stop: t.CDouble, step: t.CDouble) -> ndarray[t.CDouble] | 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.CDouble] | 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: memhub.MemManager | t.CPtr, start: t.CDouble, stop: t.CDouble, num: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + if num == 0: return None + a: ndarray[t.CDouble] | 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: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | 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 + string.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: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + return empty2d(pool, rows, cols) + +def ones2d(pool: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, rows, cols) + if not a: return None + a.fill(t.CDouble(1.0)) + return a + +def eye(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | 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: memhub.MemManager | t.CPtr, vals: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + n: t.CSizeT = vals.size + a: ndarray[t.CDouble] | 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, float64 default) +# ============================================================ +def np_abs(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, p: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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 (float64 default) +# ============================================================ +def add_scalar(a: ndarray[t.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, s: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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 (float64 default) +# ============================================================ +def matmul(a: ndarray[t.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | 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.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.dot(b) + + +# ============================================================ +# Reduction operations (float64 default) +# ============================================================ +def np_sum(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.sum() + +def np_mean(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.mean() + +def np_min(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.min() + +def np_max(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return a.max() + +def np_argmax(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: + return a.argmax() + +def np_argmin(a: ndarray[t.CDouble] | t.CPtr) -> t.CInt: + return a.argmin() + + +# ============================================================ +# Utility (float64 default) +# ============================================================ +def var(a: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> t.CDouble: + return vipermath.sqrt(var(a)) + +def norm(a: ndarray[t.CDouble] | t.CPtr) -> t.CDouble: + return vipermath.sqrt(a.dot(a)) + +def clip(a: ndarray[t.CDouble] | t.CPtr, lo: t.CDouble, hi: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + if a.ndim != 1 or b.ndim != 1: return None + total: t.CSizeT = a.size + b.size + result: ndarray[t.CDouble] | t.CPtr = zeros(a.pool, total) + if not result: return None + string.memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) + string.memcpy(result.data + a.size, b.data, b.size * t.CDouble.__sizeof__()) + return result + +def sort_arr(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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, float64 default) +# ============================================================ +def np_log10(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, x: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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 (float64 default) +# ============================================================ +def cumsum(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + if a.size < 2: return None + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + result.ndim = 1 + result.shape[0] = a.size + result.strides[0] = 1 + string.memcpy(result.data, a.data, a.size * t.CDouble.__sizeof__()) + return result + +def trace(a: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, x: ndarray[t.CDouble] | t.CPtr, y: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | 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.CDouble] | 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.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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 (float64 default) +# ============================================================ +def empty(pool: memhub.MemManager | t.CPtr, n: t.CSizeT) -> ndarray[t.CDouble] | t.CPtr: + return zeros(pool, n) + +def full2d(pool: memhub.MemManager | t.CPtr, rows: t.CSizeT, cols: t.CSizeT, val: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + a: ndarray[t.CDouble] | t.CPtr = empty2d(pool, rows, cols) + if not a: return None + a.fill(val) + return a + +def zeros_like(a: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | 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 + string.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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + result: ndarray[t.CDouble] | t.CPtr = _empty_like(a) + if not result: return None + result.fill(t.CDouble(1.0)) + return result + +def arange1(pool: memhub.MemManager | t.CPtr, stop: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + return arange(pool, t.CDouble(0.0), stop, t.CDouble(1.0)) + +def linspace2(pool: memhub.MemManager | t.CPtr, start: t.CDouble, stop: t.CDouble) -> ndarray[t.CDouble] | t.CPtr: + return linspace(pool, start, stop, 50) + +def meshgrid(x: ndarray[t.CDouble] | t.CPtr, y: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + # Returns flattened grid pairs - simplified version + # Returns X grid as 2D array (each row is x) + result: ndarray[t.CDouble] | 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 (float64 default) +# ============================================================ +def det2x2(a: ndarray[t.CDouble] | 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.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + # Inverse of 2x2 matrix + d: t.CDouble = det2x2(a) + if d == t.CDouble(0.0): return None + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, b: ndarray[t.CDouble] | t.CPtr) -> ndarray[t.CDouble] | t.CPtr: + # Cross product of 3D vectors + result: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, fp: ndarray[t.CDouble] | 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.CDouble] | 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.CDouble] | t.CPtr) -> t.CDouble: + if a.size == 0: return t.CDouble(0.0) + s: ndarray[t.CDouble] | 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.CDouble] | t.CPtr, q: t.CDouble) -> t.CDouble: + if a.size == 0: return t.CDouble(0.0) + s: ndarray[t.CDouble] | 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/os/__init__.vp b/os/__init__.vp new file mode 100644 index 0000000..daf8635 --- /dev/null +++ b/os/__init__.vp @@ -0,0 +1,134 @@ +import t, c +from stdint import * +import platmacro +import memhub +import os.path +import os._win32 +import os._posix + + +# os package entry point +# Dispatches to _win32 or _posix backend based on platmacro.IS_WINDOWS +# os.path is for cross-platform pure string operations, can be used directly + +# Module-level global MBuddy pointer (initialized by the user in main) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# File/Directory Attribute Query +# ============================================================================= + +def exists(path: str) -> bool: + """Check if the file/directory exists""" + if platmacro.IS_WINDOWS: + return os._win32.exists(path) + return os._posix.exists(path) + + +def isdir(path: str) -> bool: + """Check if the path is a directory""" + if platmacro.IS_WINDOWS: + return os._win32.isdir(path) + return os._posix.isdir(path) + + +def isfile(path: str) -> bool: + """Check if the path is a regular file""" + if platmacro.IS_WINDOWS: + return os._win32.isfile(path) + return os._posix.isfile(path) + + +def getsize(path: str) -> t.CInt64T: + """Returns the file size (in bytes). Returns -1 on failure.""" + if platmacro.IS_WINDOWS: + return os._win32.getsize(path) + return os._posix.getsize(path) + + +# ============================================================================= +# Working Directory +# ============================================================================= + +def getcwd() -> str: + """Return the current working directory (memory allocated via _mbuddy)""" + if platmacro.IS_WINDOWS: + return os._win32.getcwd() + return os._posix.getcwd_impl() + + +def chdir(path: str) -> int: + """Switch the current working directory. Returns 0 if successful, -1 if it fails.""" + if platmacro.IS_WINDOWS: + return os._win32.chdir(path) + return os._posix.chdir_impl(path) + + +# ============================================================================= +# File/Directory Operations +# ============================================================================= + +def mkdir(path: str) -> int: + """Create a directory. Returns 0 on success, -1 on failure.""" + if platmacro.IS_WINDOWS: + return os._win32.mkdir(path) + return os._posix.mkdir_impl(path) + + +def remove(path: str) -> int: + """Delete the file. Returns 0 if successful, -1 if it fails.""" + if platmacro.IS_WINDOWS: + return os._win32.remove(path) + return os._posix.remove(path) + + +def rmdir(path: str) -> int: + """Delete empty directories. Returns 0 if successful, -1 if it fails.""" + if platmacro.IS_WINDOWS: + return os._win32.rmdir(path) + return os._posix.rmdir_impl(path) + + +def rename(old_path: str, new_path: str) -> int: + """Rename/move a file or directory. Returns 0 on success, -1 on failure.""" + if platmacro.IS_WINDOWS: + return os._win32.rename(old_path, new_path) + return os._posix.rename_impl(old_path, new_path) + + +def chmod(path: str, mode: int) -> int: + """Modify file permissions. Returns 0 on success, -1 on failure. + On Windows, only the read-only bit (S_IWUSR) is handled; + On POSIX, full permission bits are used.""" + if platmacro.IS_WINDOWS: + return os._win32.chmod(path, mode) + return os._posix.chmod_impl(path, mode) + + +# ============================================================================= +# Table of Contents Listing +# ============================================================================= + +def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: + """列举目录下的文件/子目录名。 + out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。 + 文件名通过 _mbuddy 分配内存。 + max_count 为 out_names 数组最大容量。 + 返回实际列举的条目数。失败返回 0。""" + if platmacro.IS_WINDOWS: + return os._win32.listdir(path, out_names, max_count) + return os._posix.listdir(path, out_names, max_count) + + +# ============================================================================= +# 命令执行 +# ============================================================================= + +def system(cmd: str) -> int: + """执行命令行命令(通过 C 运行时 system())。 + 命令输出直接到终端(继承父进程 stdout/stderr)。 + 返回命令的退出码(0 表示成功)。""" + if platmacro.IS_WINDOWS: + return os._win32.system(cmd) + return os._posix.system_impl(cmd) diff --git a/os/_posix.vp b/os/_posix.vp new file mode 100644 index 0000000..f5d9114 --- /dev/null +++ b/os/_posix.vp @@ -0,0 +1,190 @@ +import t, c +from stdint import * +import posix +import memhub +import stdlib + + +# POSIX 路径最大长度 +MAX_PATH_LEN: t.CDefine = 4096 + +# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# 文件/目录属性查询 +# ============================================================================= + +def _stat(path: str) -> posix.Stat | t.CPtr: + """调用 stat 并返回 Stat 结构体指针。失败返回 None。 + 注意:Stat 结构体通过 _mbuddy 分配,调用者负责释放。""" + st: posix.Stat = posix.Stat() + result: INT = posix.stat(path, t.CPtr(c.Addr(st))) + if result != 0: + return None + return t.CPtr(c.Addr(st)) + + +def exists(path: str) -> bool: + """检查文件/目录是否存在""" + result: INT = posix.access(path, posix.F_OK) + if result == 0: + return True + return False + + +def isdir(path: str) -> bool: + """检查路径是否为目录""" + st: posix.Stat = posix.Stat() + result: INT = posix.stat(path, t.CPtr(c.Addr(st))) + if result != 0: + return False + if posix.S_ISDIR(st.st_mode): + return True + return False + + +def isfile(path: str) -> bool: + """检查路径是否为普通文件""" + st: posix.Stat = posix.Stat() + result: INT = posix.stat(path, t.CPtr(c.Addr(st))) + if result != 0: + return False + if posix.S_ISREG(st.st_mode): + return True + return False + + +def getsize(path: str) -> t.CInt64T: + """返回文件大小(字节)。失败返回 -1。""" + st: posix.Stat = posix.Stat() + result: INT = posix.stat(path, t.CPtr(c.Addr(st))) + if result != 0: + return -1 + return st.st_size + + +# ============================================================================= +# 工作目录 +# ============================================================================= + +def getcwd_impl() -> str: + """返回当前工作目录(通过 _mbuddy 分配内存)""" + buf: bytes = _mbuddy.alloc(MAX_PATH_LEN) + if buf == None: return None + result: CHARPTR = posix.getcwd(buf, MAX_PATH_LEN) + if result == None: + return None + return str(buf) + + +def chdir_impl(path: str) -> int: + """切换当前工作目录。成功返回 0,失败返回 -1。""" + result: INT = posix.chdir(path) + if result != 0: + return -1 + return 0 + + +# ============================================================================= +# 文件/目录操作 +# ============================================================================= + +def mkdir_impl(path: str) -> int: + """创建目录。成功返回 0,失败返回 -1。 + 默认权限 0o755(rwxr-xr-x)。""" + result: INT = posix.mkdir(path, 0o755) + if result != 0: + return -1 + return 0 + + +def remove(path: str) -> int: + """删除文件。成功返回 0,失败返回 -1。""" + result: INT = posix.unlink(path) + if result != 0: + return -1 + return 0 + + +def rmdir_impl(path: str) -> int: + """删除空目录。成功返回 0,失败返回 -1。""" + result: INT = posix.rmdir(path) + if result != 0: + return -1 + return 0 + + +def rename_impl(old_path: str, new_path: str) -> int: + """重命名/移动文件或目录。成功返回 0,失败返回 -1。""" + result: INT = posix.rename(old_path, new_path) + if result != 0: + return -1 + return 0 + + +def chmod_impl(path: str, mode: int) -> int: + """修改文件权限。成功返回 0,失败返回 -1。 + mode 为 POSIX 权限位(如 0o755)。""" + result: INT = posix.chmod(path, posix.mode_t(mode)) + if result != 0: + return -1 + return 0 + + +# ============================================================================= +# 目录列举(opendir / readdir / closedir) +# ============================================================================= + +def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: + """列举目录下的文件/子目录名。 + out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。 + 文件名通过 _mbuddy 分配内存。 + max_count 为 out_names 数组最大容量。 + 返回实际列举的条目数。失败返回 0。""" + dirp: posix.DIR | t.CPtr = posix.opendir(path) + if dirp == None: + return 0 + + count: ULONG = 0 + while count < max_count: + entry: posix.Dirent | t.CPtr = posix.readdir(dirp) + if entry == None: + break + + # 读取 d_name 字段 + name: str = entry.d_name + if name[0] == '.': + if name[1] == 0: + # "." + continue + if name[1] == '.' and name[2] == 0: + # ".." + continue + + # 复制文件名到新分配的内存 + name_len: t.CSizeT = len(name) + name_buf: bytes = _mbuddy.alloc(name_len + 1) + if name_buf == None: break + i: t.CSizeT = 0 + for ch in name: + name_buf[i] = ch + i += 1 + name_buf[name_len] = 0 + out_names[count] = str(name_buf) + count += 1 + + posix.closedir(dirp) + return count + + +# ============================================================================= +# 命令执行 +# ============================================================================= + +def system_impl(cmd: str) -> int: + """执行命令行命令(通过 C 运行时 system())。 + 命令输出直接到子进程的终端(继承父进程 stdout/stderr)。 + 返回命令的退出码(0 表示成功)。""" + return stdlib.system(cmd) diff --git a/os/_win32.vp b/os/_win32.vp new file mode 100644 index 0000000..6292e53 --- /dev/null +++ b/os/_win32.vp @@ -0,0 +1,234 @@ +import t, c +from stdint import * +import w32.win32base +import w32.win32file +import memhub +import stdlib + + +# Windows 路径最大长度 +MAX_PATH_LEN: t.CDefine = 260 + +# INVALID_FILE_ATTRIBUTES +INVALID_FILE_ATTRIBUTES: t.CDefine = 0xFFFFFFFF + +# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# 文件/目录属性查询 +# ============================================================================= + +def _get_attrs(path: str) -> ULONG: + """获取文件属性。失败返回 INVALID_FILE_ATTRIBUTES。""" + return w32.win32file.GetFileAttributesA(path) + + +def exists(path: str) -> bool: + """检查文件/目录是否存在""" + attrs: ULONG = _get_attrs(path) + if attrs == INVALID_FILE_ATTRIBUTES: + return False + return True + + +def isdir(path: str) -> bool: + """检查路径是否为目录""" + attrs: ULONG = _get_attrs(path) + if attrs == INVALID_FILE_ATTRIBUTES: + return False + if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + return True + return False + + +def isfile(path: str) -> bool: + """检查路径是否为普通文件""" + attrs: ULONG = _get_attrs(path) + if attrs == INVALID_FILE_ATTRIBUTES: + return False + if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + return False + return True + + +def getsize(path: str) -> t.CInt64T: + """返回文件大小(字节)。失败返回 -1。""" + handle: w32.win32base.HANDLE = w32.win32file.CreateFileA( + path, w32.win32file.GENERIC_READ, w32.win32file.FILE_SHARE_READ, + t.CPtr(0), w32.win32file.OPEN_EXISTING, w32.win32file.FILE_ATTRIBUTE_NORMAL, t.CPtr(0) + ) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + return -1 + li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER() + result: BOOL = w32.win32file.GetFileSizeEx(handle, t.CPtr(c.Addr(li))) + w32.win32base.CloseHandle(handle) + if result == 0: + return -1 + return li.QuadPart + + +# ============================================================================= +# 工作目录 +# ============================================================================= + +def getcwd() -> str: + """返回当前工作目录(通过 _mbuddy 分配内存)""" + buf: bytes = _mbuddy.alloc(MAX_PATH_LEN + 1) + if buf == None: return None + length: ULONG = w32.win32file.GetCurrentDirectoryA(MAX_PATH_LEN + 1, buf) + if length == 0: + return None + if length > MAX_PATH_LEN: + # 缓冲区不够,重新分配 + buf2: bytes = _mbuddy.alloc(length + 1) + if buf2 == None: return None + w32.win32file.GetCurrentDirectoryA(length + 1, buf2) + buf2[length] = 0 + return str(buf2) + buf[length] = 0 + return str(buf) + + +def chdir(path: str) -> int: + """切换当前工作目录。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.SetCurrentDirectoryA(path) + if result == 0: + return -1 + return 0 + + +# ============================================================================= +# 文件/目录操作 +# ============================================================================= + +def mkdir(path: str) -> int: + """创建目录。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.CreateDirectoryA(path, t.CPtr(0)) + if result == 0: + return -1 + return 0 + + +def remove(path: str) -> int: + """删除文件。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.DeleteFileA(path) + if result == 0: + return -1 + return 0 + + +def rmdir(path: str) -> int: + """删除空目录。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.RemoveDirectoryA(path) + if result == 0: + return -1 + return 0 + + +def rename(old_path: str, new_path: str) -> int: + """重命名/移动文件或目录。成功返回 0,失败返回 -1。""" + result: BOOL = w32.win32file.MoveFileExA( + old_path, new_path, + w32.win32file.MOVEFILE_REPLACE_EXISTING | w32.win32file.MOVEFILE_COPY_ALLOWED + ) + if result == 0: + return -1 + return 0 + + +def chmod(path: str, mode: int) -> int: + """修改文件属性(Windows 简化版:只处理只读位)。 + mode 的 S_IWUSR 位(0o200)为 0 时设为只读,为 1 时设为可写。 + 成功返回 0,失败返回 -1。""" + if (mode & 0o200) != 0: + # 可写:清除只读属性 + result: BOOL = w32.win32file.SetFileAttributesA( + path, w32.win32file.FILE_ATTRIBUTE_NORMAL + ) + else: + # 只读:设置只读属性 + result: BOOL = w32.win32file.SetFileAttributesA( + path, w32.win32file.FILE_ATTRIBUTE_READONLY + ) + if result == 0: + return -1 + return 0 + + +# ============================================================================= +# 目录列举(FindFirstFile / FindNextFile) +# ============================================================================= + +def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG: + """列举目录下的文件/子目录名。 + out_names 为调用者提供的字符串指针数组(char**),每个元素指向一个文件名。 + 文件名通过 _mbuddy 分配内存。 + max_count 为 out_names 数组最大容量。 + 返回实际列举的条目数。失败返回 0。""" + # 构造搜索模式:path\* + path_len: t.CSizeT = len(path) + pattern: bytes = _mbuddy.alloc(path_len + 3) + if pattern == None: return 0 + i: t.CSizeT = 0 + for ch in path: + pattern[i] = ch + i += 1 + # 添加 \* 后缀 + if path[path_len - 1] != '\\' and path[path_len - 1] != '/': + pattern[i] = '\\' + i += 1 + pattern[i] = '*' + i += 1 + pattern[i] = 0 + + find_data: w32.win32file.WIN32_FIND_DATAA = w32.win32file.WIN32_FIND_DATAA() + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, t.CPtr(c.Addr(find_data))) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + return 0 + + count: ULONG = 0 + while count < max_count: + # 跳过 . 和 .. + name: str = find_data.cFileName + if name[0] == '.': + if name[1] == 0: + # "." + if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0: + break + continue + if name[1] == '.' and name[2] == 0: + # ".." + if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0: + break + continue + + # 复制文件名到新分配的内存 + name_len: t.CSizeT = len(name) + name_buf: bytes = _mbuddy.alloc(name_len + 1) + if name_buf == None: break + j: t.CSizeT = 0 + for ch in name: + name_buf[j] = ch + j += 1 + name_buf[name_len] = 0 + out_names[count] = str(name_buf) + count += 1 + + if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0: + break + + w32.win32file.FindClose(handle) + return count + + +# ============================================================================= +# 命令执行 +# ============================================================================= + +def system(cmd: str) -> int: + """执行命令行命令(通过 C 运行时 system())。 + 命令输出直接到子进程的终端(继承父进程 stdout/stderr)。 + 返回命令的退出码(0 表示成功)。""" + return stdlib.system(cmd) diff --git a/os/path.vp b/os/path.vp new file mode 100644 index 0000000..af38b91 --- /dev/null +++ b/os/path.vp @@ -0,0 +1,316 @@ +import t, c +from stdint import * +import string +import memhub +import platmacro + + +# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# 路径分隔符 +# ============================================================================= + +def sep() -> t.CChar: + """返回当前平台的路径分隔符(Windows: \\,POSIX: /)""" + if platmacro.IS_WINDOWS: + return '\\' + return '/' + + +def _is_sep(ch: t.CChar) -> bool: + """判断字符是否为路径分隔符(/ 或 \\,跨平台识别)""" + return ch == '/' or ch == '\\' + + +# ============================================================================= +# 内部辅助函数 +# ============================================================================= + +def _dup_str(s: str) -> str: + """复制字符串(通过全局 MBuddy 分配内存)""" + if s == None: return None + length: t.CSizeT = len(s) + buf: bytes = _mbuddy.alloc(length + 1) + if buf == None: return None + i: t.CSizeT = 0 + for ch in s: + buf[i] = ch + i += 1 + buf[length] = 0 + return str(buf) + + +def _substr(s: str, start: t.CSizeT, end: t.CSizeT) -> str: + """提取子串 s[start:end](通过全局 MBuddy 分配内存)""" + if s == None: return None + if start >= end: return _dup_str("") + result_len: t.CSizeT = end - start + buf: bytes = _mbuddy.alloc(result_len + 1) + if buf == None: return None + i: t.CSizeT = 0 + k: t.CSizeT = start + while k < end: + buf[i] = s[k] + i += 1 + k += 1 + buf[i] = 0 + return str(buf) + + +# ============================================================================= +# 路径判断 +# ============================================================================= + +def isabs(path: str) -> bool: + """判断路径是否为绝对路径。 + POSIX: 以 / 开头。 + Windows: 以 \\ 开头(UNC)或 X:\\ / X:/ 开头(盘符)。""" + if path == None: return False + if path[0] == 0: return False + if path[0] == '/' or path[0] == '\\': return True + if platmacro.IS_WINDOWS: + # 检查 X:\ 或 X:/ 模式 + c0: t.CChar = path[0] + if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'): + if path[1] == ':': + if path[2] == '\\' or path[2] == '/': + return True + return False + + +# ============================================================================= +# 路径拼接与分割 +# ============================================================================= + +def join(path1: str, path2: str) -> str: + """拼接两个路径。如果 path2 是绝对路径,返回 path2 的副本。""" + if path1 == None or path1[0] == 0: + return _dup_str(path2) + if path2 == None or path2[0] == 0: + return _dup_str(path1) + if isabs(path2): + return _dup_str(path2) + + len1: t.CSizeT = len(path1) + len2: t.CSizeT = len(path2) + + # 检查 path1 是否以分隔符结尾 + need_sep: bool = True + if _is_sep(path1[len1 - 1]): + need_sep = False + + total: t.CSizeT = len1 + len2 + 1 + if need_sep: + total += 1 + + buf: bytes = _mbuddy.alloc(total) + if buf == None: return None + + # 复制 path1 + i: t.CSizeT = 0 + for ch in path1: + buf[i] = ch + i += 1 + + # 添加分隔符 + if need_sep: + buf[i] = sep() + i += 1 + + # 复制 path2 + for ch in path2: + buf[i] = ch + i += 1 + + buf[i] = 0 + return str(buf) + + +def basename(path: str) -> str: + """返回路径的文件名部分(最后一个分隔符之后的内容)""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str("") + + # 从后向前找分隔符 + i: t.CSizeT = length + while i > 0: + i -= 1 + if _is_sep(path[i]): + return _substr(path, i + 1, length) + + # 没有分隔符,返回整个路径的副本 + return _dup_str(path) + + +def dirname(path: str) -> str: + """返回路径的目录部分(最后一个分隔符之前的内容)""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str("") + + # 从后向前找分隔符 + i: t.CSizeT = length + while i > 0: + i -= 1 + if _is_sep(path[i]): + if i == 0: + # 路径以分隔符开头,返回根目录 + return _dup_str("/") + return _substr(path, 0, i) + + # 没有分隔符,返回空字符串 + return _dup_str("") + + +# ============================================================================= +# 扩展名处理 +# ============================================================================= + +def splitext_name(path: str) -> str: + """返回路径去除扩展名后的主名部分。 + 扩展名从最后一个 '.' 开始(该 '.' 不能是路径最后一个组件的第一个字符)。""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str("") + + # 从后向前找 '.',遇到分隔符停止 + i: t.CSizeT = length + while i > 0: + i -= 1 + if path[i] == '.': + return _substr(path, 0, i) + if _is_sep(path[i]): + break + + # 没有扩展名,返回整个路径的副本 + return _dup_str(path) + + +def splitext_ext(path: str) -> str: + """返回路径的扩展名部分(包含 '.')。无扩展名时返回空字符串。""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str("") + + # 从后向前找 '.',遇到分隔符停止 + i: t.CSizeT = length + while i > 0: + i -= 1 + if path[i] == '.': + return _substr(path, i, length) + if _is_sep(path[i]): + break + + # 没有扩展名,返回空字符串 + return _dup_str("") + + +# ============================================================================= +# 路径规范化 +# ============================================================================= + +def normpath(path: str) -> str: + """规范化路径:统一分隔符、消除多余的 . 和 .. 组件、合并连续分隔符。 + 注意:不解析符号链接,不调用系统 API。""" + if path == None: return None + length: t.CSizeT = len(path) + if length == 0: return _dup_str(".") + + # 分配输出缓冲区(最坏情况:长度不变 + 前缀 /) + buf: bytes = _mbuddy.alloc(length + 2) + if buf == None: return None + + out_pos: t.CSizeT = 0 + i: t.CSizeT = 0 + s: str = sep() + + # 处理绝对路径前缀 + is_absolute: bool = False + if _is_sep(path[0]): + is_absolute = True + buf[out_pos] = s + out_pos += 1 + i = 1 + + # Windows 盘符前缀(X:\ 或 X:/) + drive_prefix_len: t.CSizeT = 0 + if platmacro.IS_WINDOWS: + if length >= 3: + c0: t.CChar = path[0] + if (c0 >= 'A' and c0 <= 'Z') or (c0 >= 'a' and c0 <= 'z'): + if path[1] == ':': + if _is_sep(path[2]): + buf[out_pos] = path[0] + out_pos += 1 + buf[out_pos] = ':' + out_pos += 1 + buf[out_pos] = s + out_pos += 1 + drive_prefix_len = 3 + i = 3 + is_absolute = True + + # 逐组件处理 + while i < length: + # 跳过连续分隔符 + while i < length and _is_sep(path[i]): + i += 1 + if i >= length: + break + + # 提取组件 + comp_start: t.CSizeT = i + while i < length and not _is_sep(path[i]): + i += 1 + comp_len: t.CSizeT = i - comp_start + + # 处理 "." 组件:跳过 + if comp_len == 1 and path[comp_start] == '.': + continue + + # 处理 ".." 组件:回退一级 + if comp_len == 2 and path[comp_start] == '.' and path[comp_start + 1] == '.': + if out_pos > drive_prefix_len: + # 回退到上一个分隔符前 + out_pos -= 1 + while out_pos > drive_prefix_len and not _is_sep(buf[out_pos - 1]): + out_pos -= 1 + # 如果回退到了根目录前缀,不删除前缀 + if out_pos == drive_prefix_len and is_absolute: + out_pos = drive_prefix_len + if drive_prefix_len == 0: + # POSIX 根:保留 / + buf[out_pos] = s + out_pos += 1 + continue + + # 普通组件:复制到输出 + if out_pos > drive_prefix_len and not (drive_prefix_len == 0 and out_pos == 1 and is_absolute): + buf[out_pos] = s + out_pos += 1 + elif out_pos == 0 and not is_absolute: + pass # 第一个组件,不需要前导分隔符 + elif is_absolute and out_pos == drive_prefix_len: + # 已经有前导分隔符,不重复添加 + pass + else: + buf[out_pos] = s + out_pos += 1 + + j: t.CSizeT = comp_start + while j < comp_start + comp_len: + buf[out_pos] = path[j] + out_pos += 1 + j += 1 + + # 处理空结果 + if out_pos == 0: + buf[out_pos] = '.' + out_pos += 1 + + buf[out_pos] = 0 + return str(buf) diff --git a/platmacro.vp b/platmacro.vp new file mode 100644 index 0000000..695f918 --- /dev/null +++ b/platmacro.vp @@ -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 = 8 +INT_SIZE: t.CDefine = 4 +LONG_SIZE: t.CDefine = 4 +WORD_SIZE: t.CDefine = 8 + +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 = 4 +ALIGNOF_PTR: t.CDefine = 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 = 4 +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 = 8 +SIZEOF_SIZE_T: t.CDefine = 8 +SIZEOF_PTRDIFF_T: t.CDefine = 8 + +BYTE_ORDER_LE: t.CDefine = 1 +BYTE_ORDER_BE: t.CDefine = 0 diff --git a/posix.vp b/posix.vp new file mode 100644 index 0000000..d98e7ac --- /dev/null +++ b/posix.vp @@ -0,0 +1,265 @@ +import t, c +from stdint import * + + +# ============================================================================= +# POSIX Type Alias +# Note: ssize_t has already been defined as t.CPtrDiffT in stdint.py, so we won’t repeat it here. +# ============================================================================= +DIR: t.CTypedef = t.CVoid | t.CPtr # Opaque directory stream handle +mode_t: t.CTypedef = t.CUInt32T # File mode/permission bits +pid_t: t.CTypedef = t.CInt32T # Process ID +off_t: t.CTypedef = t.CInt64T # File offset (Linux x86_64) +dev_t: t.CTypedef = t.CUInt64T # Device number +ino_t: t.CTypedef = t.CUInt64T # inode number +nlink_t: t.CTypedef = t.CUInt64T # Hard link count +uid_t: t.CTypedef = t.CUInt32T # User ID +gid_t: t.CTypedef = t.CUInt32T # Group ID +blksize_t: t.CTypedef = t.CInt64T # File I/O block size +blkcnt_t: t.CTypedef = t.CInt64T # Allocated block count +time_t: t.CTypedef = t.CInt64T # Calendar time seconds + + +# ============================================================================= +# open() Flags +# ============================================================================= +O_RDONLY: t.CDefine = 0 +O_WRONLY: t.CDefine = 1 +O_RDWR: t.CDefine = 2 +O_CREAT: t.CDefine = 0o100 +O_EXCL: t.CDefine = 0o200 +O_TRUNC: t.CDefine = 0o1000 +O_APPEND: t.CDefine = 0o2000 +O_NONBLOCK: t.CDefine = 0o4000 +O_CLOEXEC: t.CDefine = 0o2000000 + + +# ============================================================================= +# access() Test Flags +# ============================================================================= +F_OK: t.CDefine = 0 # File exists +R_OK: t.CDefine = 4 # Read permission +W_OK: t.CDefine = 2 # Write permission +X_OK: t.CDefine = 1 # Execute permission + + +# ============================================================================= +# stat struct st_mode Mask and Type Bits +# ============================================================================= +S_IFMT: t.CDefine = 0o170000 # Type mask bits +S_IFSOCK: t.CDefine = 0o140000 # Socket +S_IFLNK: t.CDefine = 0o120000 # Symbolic link +S_IFREG: t.CDefine = 0o100000 # Regular file +S_IFBLK: t.CDefine = 0o060000 # Block device +S_IFDIR: t.CDefine = 0o040000 # Directory +S_IFCHR: t.CDefine = 0o020000 # Character device +S_IFIFO: t.CDefine = 0o010000 # FIFO/pipe + +# Permission Bits +S_ISUID: t.CDefine = 0o4000 # Set-user-ID +S_ISGID: t.CDefine = 0o2000 # Set-group-ID +S_ISVTX: t.CDefine = 0o1000 # Sticky bit +S_IRWXU: t.CDefine = 0o700 # Read/write/execute permission +S_IRUSR: t.CDefine = 0o400 # User read permission +S_IWUSR: t.CDefine = 0o200 # User write permission +S_IXUSR: t.CDefine = 0o100 # User execute permission +S_IRWXG: t.CDefine = 0o070 # Read/write/execute permission +S_IRGRP: t.CDefine = 0o040 # Read permission +S_IWGRP: t.CDefine = 0o020 # Write +S_IXGRP: t.CDefine = 0o010 # Execute +S_IRWXO: t.CDefine = 0o007 # Read/write/execute permission +S_IROTH: t.CDefine = 0o004 # Other read permission +S_IWOTH: t.CDefine = 0o002 # Other write permission +S_IXOTH: t.CDefine = 0o001 # Other execute permission + + +# ============================================================================= +# lseek() whence values +# ============================================================================= +SEEK_SET: t.CDefine = 0 +SEEK_CUR: t.CDefine = 1 +SEEK_END: t.CDefine = 2 + + +# ============================================================================= +# Path/name length limits +# ============================================================================= +PATH_MAX: t.CDefine = 4096 +NAME_MAX: t.CDefine = 255 + + +# ============================================================================= +# sysconf() parameters +# ============================================================================= +_SC_NPROCESSORS_ONLN: t.CDefine = 84 +_SC_PAGESIZE: t.CDefine = 30 +_SC_CLK_TCK: t.CDefine = 2 + + +# ============================================================================= +# dirent struct d_type values +# ============================================================================= +DT_UNKNOWN: t.CDefine = 0 +DT_FIFO: t.CDefine = 1 +DT_CHR: t.CDefine = 2 +DT_DIR: t.CDefine = 4 +DT_BLK: t.CDefine = 6 +DT_REG: t.CDefine = 8 +DT_LNK: t.CDefine = 10 +DT_SOCK: t.CDefine = 12 +DT_WHT: t.CDefine = 14 + + +# ============================================================================= +# waitpid() options +# ============================================================================= +WNOHANG: t.CDefine = 1 +WUNTRACED: t.CDefine = 2 +WCONTINUED: t.CDefine = 8 + + +# ============================================================================= +# Struct: Linux x86_64 Layout +# ============================================================================= + +# struct stat (144 bytes, Linux x86_64 glibc layout) +# Note: st_atim/st_mtim/st_ctim in C are struct timespec { tv_sec; tv_nsec; } +# Here split into _sec/_nsec two LONGLONG fields to maintain binary compatibility +class Stat(): + st_dev: dev_t # @ 0 + st_ino: ino_t # @ 8 + st_nlink: nlink_t # @ 16 + st_mode: mode_t # @ 24 + st_uid: uid_t # @ 28 + st_gid: gid_t # @ 32 + __pad0: INT # @ 36 + st_rdev: dev_t # @ 40 + st_size: off_t # @ 48 + st_blksize: blksize_t # @ 56 + st_blocks: blkcnt_t # @ 64 + st_atim_sec: time_t # @ 72 + st_atim_nsec: LONGLONG # @ 80 + st_mtim_sec: time_t # @ 88 + st_mtim_nsec: LONGLONG # @ 96 + st_ctim_sec: time_t # @ 104 + st_ctim_nsec: LONGLONG # @ 112 + __unused0: LONGLONG # @ 120 + __unused1: LONGLONG # @ 128 + __unused2: LONGLONG # @ 136 + + +# struct dirent (Linux x86_64, d_name is char[256]) +# Note: d_name is actually a fixed-length char[256], TransPyC uses CHARPTR as a placeholder (8 bytes). +# Users usually access it via the read-only pointer returned by readdir, not by directly allocating a Dirent structure. +class Dirent(): + d_ino: ino_t # @ 0 + d_off: off_t # @ 8 + d_reclen: USHORT # @ 16 + d_type: BYTE # @ 18 + d_name: CHARPTR # @ 19 (actually char[256], this is a placeholder) + + +# ============================================================================= +# File operations (10) +# ============================================================================= +def open(path: t.CConst | str, oflag: INT, *args) -> INT | t.State: pass +def close(fd: INT) -> INT | t.State: pass +def read(fd: INT, buf: bytes, count: t.CSizeT) -> ssize_t | t.State: pass +def write(fd: INT, buf: t.CConst | bytes, count: t.CSizeT) -> ssize_t | t.State: pass +def lseek(fd: INT, offset: off_t, whence: INT) -> off_t | t.State: pass +def unlink(path: t.CConst | str) -> INT | t.State: pass +def access(path: t.CConst | str, amode: INT) -> INT | t.State: pass +def realpath(path: t.CConst | str, resolved: CHARPTR) -> CHARPTR | t.State: pass +def rename(oldpath: t.CConst | str, newpath: t.CConst | str) -> INT | t.State: pass +def chmod(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass + + +# ============================================================================= +# stat series (2) +# ============================================================================= +def stat(path: t.CConst | str, buf: Stat | t.CPtr) -> INT | t.State: pass +def fstat(fd: INT, buf: Stat | t.CPtr) -> INT | t.State: pass + + +# ============================================================================= +# Directory operations (6) +# ============================================================================= +def opendir(name: t.CConst | str) -> DIR | t.CPtr | t.State: pass +def readdir(dirp: DIR | t.CPtr) -> Dirent | t.CPtr | t.State: pass +def closedir(dirp: DIR | t.CPtr) -> INT | t.State: pass +def mkdir(path: t.CConst | str, mode: mode_t) -> INT | t.State: pass +def rmdir(path: t.CConst | str) -> INT | t.State: pass +def getcwd(buf: CHARPTR, size: t.CSizeT) -> CHARPTR | t.State: pass +def chdir(path: t.CConst | str) -> INT | t.State: pass + + +# ============================================================================= +# Process operations (8) +# ============================================================================= +def fork() -> pid_t | t.State: pass +def execvp(file: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass +def execv(path: t.CConst | str, argv: CHARPTR | t.CPtr) -> INT | t.State: pass +def waitpid(pid: pid_t, status: INT | t.CPtr, options: INT) -> pid_t | t.State: pass +def pipe(fds: INT | t.CPtr) -> INT | t.State: pass +def dup2(oldfd: INT, newfd: INT) -> INT | t.State: pass +def _exit(status: INT) -> t.CVoid | t.State: pass +def getpid() -> pid_t | t.State: pass + + +# ============================================================================= +# Environment operations (4) +# ============================================================================= +def getenv(name: t.CConst | str) -> CHARPTR | t.State: pass +def setenv(name: t.CConst | str, value: t.CConst | str, overwrite: INT) -> INT | t.State: pass +def sysconf(name: INT) -> LONG | t.State: pass +def isatty(fd: INT) -> INT | t.State: pass + + +# ============================================================================= +# Inline macros (C macros, implemented as normal functions, not marked as t.CExtern) +# ============================================================================= + +# st_mode type determination +def S_ISREG(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFREG + + +def S_ISDIR(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFDIR + + +def S_ISLNK(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFLNK + + +def S_ISCHR(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFCHR + + +def S_ISBLK(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFBLK + + +def S_ISFIFO(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFIFO + + +def S_ISSOCK(mode: mode_t) -> bool: + return (mode & S_IFMT) == S_IFSOCK + + +# waitpid status parsing +def WIFEXITED(status: INT) -> bool: + return (status & 0x7F) == 0 + + +def WEXITSTATUS(status: INT) -> INT: + return (status >> 8) & 0xFF + + +def WIFSIGNALED(status: INT) -> bool: + return ((status & 0x7F) != 0) and ((status & 0x7F) != 0x7F) + + +def WTERMSIG(status: INT) -> INT: + return status & 0x7F diff --git a/requests.vp b/requests.vp new file mode 100644 index 0000000..ba9f72e --- /dev/null +++ b/requests.vp @@ -0,0 +1,360 @@ +import t, c +from stdint import * +import string +import socket +import memhub +import stdio + + +# ============================================================ +# requests.py — HTTP client library (Python original style) +# +# Usage: +# requests._mbuddy = my_mbuddy +# resp = requests.get("http://example.com/path") +# if resp is not None: +# print(resp.status_code) +# print(resp.text) +# requests.release(resp) +# ============================================================ + +# Module-level global MBuddy pointer (assigned by the user in main) +_mbuddy: memhub.MemBuddy | t.CPtr + +# Socket initialization flag +_socket_ready: bool = False + +HTTP_PORT: t.CDefine = 80 +HTTP_BUFSIZ: t.CDefine = 4096 + + +# ============================================================ +# Response — HTTP response object +# ============================================================ + +class Response: + """HTTP response object, similar to how Python's requests.Response works. + + Allocated from _mbuddy, call release(resp) to free it after use. + """ + status_code: INT # HTTP status code (e.g., 200, 404) + text: str # Response body text (points into _raw_buf) + body_len: INT # Response body length + _raw_buf: str # Raw buffer pointer + + +# ============================================================ +# Internal auxiliary functions +# ============================================================ + +def _EnsureSocketInit() -> INT: + """Ensure Socket library is initialized (idempotent).""" + global _socket_ready + if _socket_ready: return 0 + result: INT = socket.SocketInit() + if result == 0: + _socket_ready = True + return result + + +def _AllocResponse() -> Response | t.CPtr: + """Allocate Response struct from _mbuddy and initialize it in-place.""" + if _mbuddy is None: return None + resp: Response | t.CPtr = _mbuddy.alloc(Response.__sizeof__()) + if resp is None: return None + resp.status_code = 0 + resp.text = None + resp.body_len = 0 + resp._raw_buf = None + return resp + + +def _ParseUrl(url: str, host_buf: str, host_size: INT, path_buf: str, path_size: INT, port: INT | t.CPtr) -> INT: + """Parse URL and extract host, port, and path.""" + if url is None: return -1 + if host_buf is None or path_buf is None or port is None: return -1 + + p: str = url + + # Skip "http://" + if string.strncmp(p, "http://", 7) == 0: + p += 7 + + # Parse host + host_start: str = p + host_len: INT = 0 + while p[0] != '\0' and p[0] != ':' and p[0] != '/': + host_len += 1 + p += 1 + + if host_len == 0 or host_len >= host_size: return -1 + string.strncpy(host_buf, host_start, host_len) + host_buf[host_len] = 0 + + # Parse port + if p[0] == ':': + p += 1 + port_val: INT = 0 + while p[0] >= '0' and p[0] <= '9': + port_val = port_val * 10 + INT(p[0] - '0') + p += 1 + c.DerefAs(port, port_val) + else: + c.DerefAs(port, HTTP_PORT) + + # Parse path + if p[0] == '/': + path_start: str = p + path_len: INT = 0 + while p[0] != '\0': + path_len += 1 + p += 1 + if path_len >= path_size: return -1 + string.strncpy(path_buf, path_start, path_len) + path_buf[path_len] = 0 + else: + if path_size < 2: return -1 + path_buf[0] = '/' + path_buf[1] = 0 + + return 0 + + +def _ParseStatusLine(resp_text: str, out_code: INT | t.CPtr) -> INT: + """Parse HTTP status line and extract status code.""" + if resp_text is None or out_code is None: return -1 + + p: str = resp_text + + # Skip "HTTP/x.x " + while p[0] != '\0' and p[0] != ' ': + p += 1 + if p[0] == ' ': p += 1 + + # Parse status code + code: INT = 0 + while p[0] >= '0' and p[0] <= '9': + code = code * 10 + INT(p[0] - '0') + p += 1 + + c.DerefAs(out_code, code) + + # Find \n + while p[0] != '\0' and p[0] != '\n': + p += 1 + if p[0] == '\n': p += 1 + + return INT(t.CUInt64T(p) - t.CUInt64T(resp_text)) + + +def _FindBodyStart(resp_text: str, resp_len: INT) -> INT: + """Find the start of the HTTP response body (after rnrn).""" + if resp_text is None: return -1 + + end_of_headers: str = string.strstr(resp_text, "\r\n\r\n") + if end_of_headers is None: + end_of_headers = string.strstr(resp_text, "\n\n") + if end_of_headers is None: + return -1 + return INT(t.CUInt64T(end_of_headers) - t.CUInt64T(resp_text)) + 2 + + return INT(t.CUInt64T(end_of_headers) - t.CUInt64T(resp_text)) + 4 + + +# ============================================================ +# 公共 API +# ============================================================ + +def get(url: str) -> Response | t.CPtr: + """HTTP GET request. + + Args: + url: Full URL (e.g., "http://example.com/path") + Returns: + Pointer to a Response object (allocated from _mbuddy), returns None on failure. + """ + if _mbuddy is None: return None + + resp: Response | t.CPtr = _AllocResponse() + if resp is None: return None + + if _EnsureSocketInit() != 0: + release(resp) + return None + + # Parse URL + host_buf: t.CArray[t.CChar, 256] + path_buf: t.CArray[t.CChar, 1024] + port: INT = 0 + + if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: + release(resp) + return None + + # Create Socket + sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) + if sock.fd == socket.INVALID_SOCKET: + release(resp) + return None + + if sock.connect(host_buf, port) != 0: + sock.close() + release(resp) + return None + + # Build HTTP request + req_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) + if req_buf is None: + sock.close() + release(resp) + return None + + stdio.snprintf(req_buf, HTTP_BUFSIZ, + "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", + path_buf, host_buf) + + req_len: INT = INT(string.strlen(req_buf)) + sent: INT = sock.send(req_buf, req_len) + _mbuddy.free(req_buf) + + if sent <= 0: + sock.close() + release(resp) + return None + + # Receive response body + resp_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) + if resp_buf is None: + sock.close() + release(resp) + return None + + total: INT = 0 + while total < HTTP_BUFSIZ - 1: + n: INT = sock.recv(resp_buf + total, HTTP_BUFSIZ - 1 - total) + if n <= 0: break + total += n + + resp_buf[total] = 0 + sock.close() + + resp._raw_buf = resp_buf + + # Parse status line + _ParseStatusLine(resp_buf, c.Addr(resp.status_code)) + + # Find body start + body_offset: INT = _FindBodyStart(resp_buf, total) + if body_offset < 0 or body_offset >= total: + resp.text = None + resp.body_len = 0 + else: + resp.text = resp_buf + body_offset + resp.body_len = total - body_offset + + return resp + + +def post(url: str, data: str = None, content_type: str = "application/x-www-form-urlencoded") -> Response | t.CPtr: + """HTTP POST request. + + Args: + url: Full URL + data: Request body data + content_type: Content-Type header (default is "application/x-www-form-urlencoded") + Returns: + Pointer to Response object (allocated from _mbuddy), returns None on failure. + """ + if _mbuddy is None: return None + + resp: Response | t.CPtr = _AllocResponse() + if resp is None: return None + + if _EnsureSocketInit() != 0: + release(resp) + return None + + # Parse URL + host_buf: t.CArray[t.CChar, 256] + path_buf: t.CArray[t.CChar, 1024] + port: INT = 0 + + if _ParseUrl(url, host_buf, 256, path_buf, 1024, c.Addr(port)) != 0: + release(resp) + return None + + body_len: INT = INT(string.strlen(data)) if data is not None else 0 + ct: str = content_type if content_type is not None else "application/x-www-form-urlencoded" + + # Create Socket + sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) + if sock.fd == socket.INVALID_SOCKET: + release(resp) + return None + + if sock.connect(host_buf, port) != 0: + sock.close() + release(resp) + return None + + # Build HTTP request + req_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) + if req_buf is None: + sock.close() + release(resp) + return None + + stdio.snprintf(req_buf, HTTP_BUFSIZ, + "POST %s HTTP/1.1\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\nConnection: close\r\n\r\n", + path_buf, host_buf, ct, body_len) + + hdr_len: INT = INT(string.strlen(req_buf)) + + # Send headers + body + sent: INT = sock.send(req_buf, hdr_len) + if sent > 0 and body_len > 0 and data is not None: + sock.send(data, body_len) + + _mbuddy.free(req_buf) + + # Receive response body + resp_buf: str = _mbuddy.alloc(HTTP_BUFSIZ) + if resp_buf is None: + sock.close() + release(resp) + return None + + total: INT = 0 + while total < HTTP_BUFSIZ - 1: + n: INT = sock.recv(resp_buf + total, HTTP_BUFSIZ - 1 - total) + if n <= 0: break + total += n + + resp_buf[total] = 0 + sock.close() + + resp._raw_buf = resp_buf + + _ParseStatusLine(resp_buf, c.Addr(resp.status_code)) + body_offset: INT = _FindBodyStart(resp_buf, total) + if body_offset < 0 or body_offset >= total: + resp.text = None + resp.body_len = 0 + else: + resp.text = resp_buf + body_offset + resp.body_len = total - body_offset + + return resp + + +def release(resp: Response | t.CPtr): + """Release Response object and its internal buffers. + + Args: + resp: The Response object to release + """ + if resp is None: return + if _mbuddy is None: return + if resp._raw_buf is not None: + _mbuddy.free(resp._raw_buf) + _mbuddy.free(t.CVoid(t.CUInt64T(resp), t.CPtr)) diff --git a/rwlock.vp b/rwlock.vp new file mode 100644 index 0000000..3d0ae58 --- /dev/null +++ b/rwlock.vp @@ -0,0 +1,46 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32sync import ( + InitializeSRWLock, + AcquireSRWLockExclusive, ReleaseSRWLockExclusive, + AcquireSRWLockShared, ReleaseSRWLockShared +) + + +@t.Object +class RWLock: + """SRWLock-based read-write lock that supports multiple readers and single writer, but does not support recursion. + + Usage: + rwlock: RWLock = RWLock() + rwlock.acquire_read() + # ... read shared data + rwlock.release_read() + rwlock.acquire_write() + # ... modify shared data + rwlock.release_write() + """ + lock: VOIDPTR + + def __init__(self): + InitializeSRWLock(c.Addr(self.lock)) + + def acquire_read(self): + AcquireSRWLockShared(c.Addr(self.lock)) + + def release_read(self): + ReleaseSRWLockShared(c.Addr(self.lock)) + + def acquire_write(self): + AcquireSRWLockExclusive(c.Addr(self.lock)) + + def release_write(self): + ReleaseSRWLockExclusive(c.Addr(self.lock)) + + def __enter__(self) -> 'RWLock' | t.CPtr: + self.acquire_write() + return self + + def __exit__(self): + self.release_write() diff --git a/shutil.vp b/shutil.vp new file mode 100644 index 0000000..ed7e578 --- /dev/null +++ b/shutil.vp @@ -0,0 +1,283 @@ +import t, c +from stdint import * +import platmacro +import memhub +import string + +# Windows backend dependencies +import w32.win32base +import w32.win32file + +# POSIX backend dependencies +import posix + + +# File copy buffer size +COPY_BUF_SIZE: t.CDefine = 65536 # 2^16 + +# Module-level global MBuddy pointer (initialized by the user in main) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# copyfile: Copy file content (without preserving permissions/metadata) +# ============================================================================= + +def copyfile(src: str, dst: str) -> int: + """Copy file content. Returns 0, otherwise -1.""" + if platmacro.IS_WINDOWS: + return _copyfile_win32(src, dst) + return _copyfile_posix(src, dst) + + +def _copyfile_win32(src: str, dst: str) -> int: + """Windows: Use CopyFileA kernel implementation (efficient).""" + result: BOOL = w32.win32file.CopyFileA(src, dst, 0) + if result == 0: + return -1 + return 0 + + +def _copyfile_posix(src: str, dst: str) -> int: + """POSIX: Manual file read/write loop copy""" + fd_in: INT = posix.open(src, posix.O_RDONLY, 0) + if fd_in < 0: + return -1 + fd_out: INT = posix.open(dst, posix.O_WRONLY | posix.O_CREAT | posix.O_TRUNC, 0o644) + if fd_out < 0: + posix.close(fd_in) + return -1 + buf: bytes = _mbuddy.alloc(COPY_BUF_SIZE) + if buf == None: + posix.close(fd_in) + posix.close(fd_out) + return -1 + n: ssize_t = 0 + result: int = 0 + n = posix.read(fd_in, buf, COPY_BUF_SIZE) + while n > 0: + written: ssize_t = posix.write(fd_out, buf, t.CSizeT(n)) + if written < 0: + result = -1 + break + n = posix.read(fd_in, buf, COPY_BUF_SIZE) + if n < 0: + result = -1 + _mbuddy.free(buf) + posix.close(fd_in) + posix.close(fd_out) + return result + + +# ============================================================================= +# copy: Copy file and preserve permissions/metadata (POSIX only) +# ============================================================================= + +def copy(src: str, dst: str) -> int: + """Copy file and preserve permissions/metadata (POSIX only). Returns 0, otherwise -1.""" + if platmacro.IS_WINDOWS: + return _copy_win32(src, dst) + return _copy_posix(src, dst) + + +def _copy_win32(src: str, dst: str) -> int: + """Windows: Copy file (using CopyFileA kernel implementation (simple, delegate to copyfile).""" + return _copyfile_win32(src, dst) + + +def _copy_posix(src: str, dst: str) -> int: + """POSIX: Copy file and preserve permissions (stat+chmod). Returns 0, otherwise -1.""" + result: int = _copyfile_posix(src, dst) + if result != 0: + return -1 + st: posix.Stat = posix.Stat() + if posix.stat(src, t.CPtr(c.Addr(st))) == 0: + posix.chmod(dst, st.st_mode) + return 0 + + +# ============================================================================= +# rmtree: Recursively remove directory tree (POSIX only) +# ============================================================================= + +def rmtree(path: str) -> int: + """Recursively delete a directory tree. Returns 0 on success and -1 on failure.""" + if platmacro.IS_WINDOWS: + return _rmtree_win32(path) + return _rmtree_posix(path) + + +def _rmtree_win32(path: str) -> int: + """Windows: Recursively delete a directory tree using FindFirstFileA/FindNextFileA.""" + path_len: t.CSizeT = len(path) + # Construct search pattern path\* + pattern: bytes = _mbuddy.alloc(path_len + 3) + if pattern == None: + return -1 + i: t.CSizeT = 0 + for ch in path: + pattern[i] = ch + i += 1 + if path_len > 0: + if path[path_len - 1] != '\\' and path[path_len - 1] != '/': + pattern[i] = '\\' + i += 1 + pattern[i] = '*' + i += 1 + pattern[i] = 0 + + find_data: w32.win32file.WIN32_FIND_DATAA = w32.win32file.WIN32_FIND_DATAA() + handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, t.CPtr(c.Addr(find_data))) + _mbuddy.free(pattern) + if handle == w32.win32base.INVALID_HANDLE_VALUE: + return -1 + + result: int = 0 + has_more: int = 1 + while has_more == 1: + name: str = find_data.cFileName + # Skip . and .. + skip: bool = False + if name[0] == '.': + if name[1] == 0: + skip = True + elif name[1] == '.' and name[2] == 0: + skip = True + if not skip: + # Construct full path path\name + name_len: t.CSizeT = len(name) + full_path: bytes = _mbuddy.alloc(path_len + name_len + 2) + if full_path == None: + result = -1 + else: + j: t.CSizeT = 0 + for ch in path: + full_path[j] = ch + j += 1 + if path_len > 0: + if path[path_len - 1] != '\\' and path[path_len - 1] != '/': + full_path[j] = '\\' + j += 1 + for ch in name: + full_path[j] = ch + j += 1 + full_path[j] = 0 + # Check if it's a directory or a file + if (find_data.dwFileAttributes & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0: + # Recursively delete subdirectory + sub_result: int = _rmtree_win32(str(full_path)) + if sub_result != 0: + result = -1 + else: + # Delete file + if w32.win32file.DeleteFileA(str(full_path)) == 0: + result = -1 + _mbuddy.free(full_path) + # Continue searching next entry + if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0: + has_more = 0 + + w32.win32file.FindClose(handle) + # Delete empty directory itself + if result == 0: + if w32.win32file.RemoveDirectoryA(path) == 0: + result = -1 + return result + + +def _rmtree_posix(path: str) -> int: + """POSIX: Recursively delete a directory tree using opendir/readdir.""" + dirp: posix.DIR = posix.opendir(path) + if dirp == None: + return -1 + + path_len: t.CSizeT = len(path) + result: int = 0 + entry: posix.Dirent | t.CPtr = posix.readdir(dirp) + while entry != None: + name: str = entry.d_name + # Skip . and .. + skip: bool = False + if name[0] == '.': + if name[1] == 0: + skip = True + elif name[1] == '.' and name[2] == 0: + skip = True + if not skip: + # Construct full path path/name + name_len: t.CSizeT = len(name) + full_path: bytes = _mbuddy.alloc(path_len + name_len + 2) + if full_path == None: + result = -1 + else: + j: t.CSizeT = 0 + for ch in path: + full_path[j] = ch + j += 1 + if path_len > 0: + if path[path_len - 1] != '/': + full_path[j] = '/' + j += 1 + for ch in name: + full_path[j] = ch + j += 1 + full_path[j] = 0 + # Check entry type + if entry.d_type == posix.DT_DIR: + # Recursively delete subdirectory + sub_result: int = _rmtree_posix(str(full_path)) + if sub_result != 0: + result = -1 + else: + # Delete file or symbolic link etc. + if posix.unlink(str(full_path)) != 0: + result = -1 + _mbuddy.free(full_path) + entry = posix.readdir(dirp) + + posix.closedir(dirp) + # Delete empty directory itself + if result == 0: + if posix.rmdir(path) != 0: + result = -1 + return result + + +# ============================================================================= +# move:Move file/directory +# ============================================================================= + +def move(src: str, dst: str) -> int: + """Move/rename files or directories. If it's the same partition, just rename; + if it's across partitions, copy then delete. Returns 0 on success, -1 on failure.""" + if platmacro.IS_WINDOWS: + return _move_win32(src, dst) + return _move_posix(src, dst) + + +def _move_win32(src: str, dst: str) -> int: + """Windows: MoveFileExA (rename within the same partition, copy and delete across partitions)""" + rename_result: BOOL = w32.win32file.MoveFileExA( + src, dst, + w32.win32file.MOVEFILE_REPLACE_EXISTING | w32.win32file.MOVEFILE_COPY_ALLOWED + ) + if rename_result != 0: + return 0 + # rename failed, try copy or remove + if copyfile(src, dst) != 0: + return -1 + if w32.win32file.DeleteFileA(src) == 0: + return -1 + return 0 + + +def _move_posix(src: str, dst: str) -> int: + """POSIX: rename (within the same partition), copy and unlink across partitions""" + if posix.rename(src, dst) == 0: + return 0 + # rename failed (possibly across partitions), try copy or remove + if copyfile(src, dst) != 0: + return -1 + if posix.unlink(src) != 0: + return -1 + return 0 diff --git a/socket.vp b/socket.vp new file mode 100644 index 0000000..163873e --- /dev/null +++ b/socket.vp @@ -0,0 +1,454 @@ +import t, c +from stdint import * +import string +import platmacro +import stdio +import w32.winsock2 + + +# ============================================================ +# socket.py — Cross-platform wrapper for Socket +# Python-style OOP API + Compatibility with legacy procedural functions +# +# Example: +# sock = socket.Socket(socket.AF_INET, socket.SOCK_STREAM) +# sock.connect("example.com", 80) +# sock.send(data, length) +# n = sock.recv(buf, bufsize) +# sock.close() +# +# Only 3 platform differences (via platmacro.IS_WINDOWS branch): +# 1. WSAStartup() / WSACleanup() +# 2. closesocket() vs close() +# 3. WSAGetLastError() vs errno +# ============================================================ + + +# ============================================================ +# Constants +# ============================================================ +AF_INET: t.CDefine = 2 +AF_INET6: t.CDefine = 10 + +SOCK_STREAM: t.CDefine = 1 +SOCK_DGRAM: t.CDefine = 2 +SOCK_RAW: t.CDefine = 3 + +IPPROTO_TCP: t.CDefine = 6 +IPPROTO_UDP: t.CDefine = 17 + +SOL_SOCKET: t.CDefine = 1 +SO_RCVTIMEO: t.CDefine = 20 +SO_SNDTIMEO: t.CDefine = 21 +SO_REUSEADDR: t.CDefine = 2 + +INADDR_ANY: t.CDefine = 0 + +SOCKET_ERROR: t.CDefine = -1 +INVALID_SOCKET: t.CDefine = -1 + +SOCKET_DEFAULT_TIMEOUT: t.CDefine = 0 + + +# ============================================================ +# Structures +# ============================================================ + +class SocketAddr: + """sockaddr_in — IPv4 address (16 bytes layout)""" + family: u16 + port: u16 + addr: u32 + zero: u64 + + +class HostEnt: + """struct hostent — DNS resolution result""" + h_name: CHARPTR + h_aliases: CHARPTR + h_addrtype: INT + h_length: INT + h_addr_list: CHARPTR + + +class timeval: + """struct timeval — Timeout setting""" + tv_sec: INT + tv_usec: INT + + +# ============================================================ +# External C Functions — Using u64 Handle, Cross-platform Compatibility +# (Windows SOCKET=u64, POSIX fd=int → u64 Zero-Extension Compatible) +# ============================================================ + +def socket(family: INT, type: INT, protocol: INT) -> u64 | t.CExtern | t.CExport: pass +def connect(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT) -> INT | t.CExtern | t.CExport: pass +def send(fd: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT | t.CExtern | t.CExport: pass +def recv(fd: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT | t.CExtern | t.CExport: pass +def bind(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT) -> INT | t.CExtern | t.CExport: pass +def listen(fd: u64, backlog: INT) -> INT | t.CExtern | t.CExport: pass +def accept(fd: u64, addr: SocketAddr | t.CPtr, addrlen: INT | t.CPtr) -> u64 | t.CExtern | t.CExport: pass +def setsockopt(fd: u64, level: INT, optname: INT, optval: t.CVoid | t.CPtr, optlen: INT) -> INT | t.CExtern | t.CExport: pass +def gethostbyname(name: t.CChar | t.CConst | t.CPtr) -> HostEnt | t.CPtr | t.CExtern | t.CExport: pass +def ntohs(netshort: u16) -> u16 | t.CExtern | t.CExport: pass +def htons(hostshort: u16) -> u16 | t.CExtern | t.CExport: pass +def close(fd: u64) -> INT | t.CExtern | t.CExport: pass + + +# ============================================================ +# Internal Auxiliary Functions +# ============================================================ + +def _CloseFd(fd: INT) -> INT: + """Platform differences: Windows uses closesocket, POSIX uses close。""" + if platmacro.IS_WINDOWS: + return w32.winsock2.closesocket(u64(fd)) + return close(fd) + + +def _MakeAddr(host: str, port: INT) -> SocketAddr: + """Build SocketAddr. First try decimal IP, then DNS resolution. + If decimal IP fails, try DNS resolution. + If DNS resolution fails, return INADDR_ANY.""" + addr: SocketAddr + string.memset(c.Addr(addr), 0, 16) + addr.family = u16(AF_INET) + addr.port = htons(u16(port)) + + ip: u32 = 0 + if _ParseIPv4(host, c.Addr(ip)): + addr.addr = ip + return addr + + # DNS resolution — gethostbyname returns struct hostent* + # h_addr_list is char** → h_addr_list[0] is char* → *(uint32_t*)h_addr_list[0] is IP + if platmacro.IS_WINDOWS: + he_raw: w32.winsock2.WSAHostEnt | t.CPtr = w32.winsock2.gethostbyname(host) + if he_raw is not None: + # he_raw.h_addr_list → he_raw->h_addr_list (char**) + # c.Deref(t.CUInt64T(he_raw.h_addr_list, t.CPtr)) → *(uint64_t*)(he_raw->h_addr_list) → h_addr_list[0] + ip_ptr: u64 = u64(c.Deref(t.CUInt64T(he_raw.h_addr_list, t.CPtr))) + if ip_ptr != 0: + addr.addr = u32(c.Deref(t.CUInt32T(ip_ptr, t.CPtr))) + else: + he: HostEnt | t.CPtr = gethostbyname(host) + if he is not None: + ip_ptr: u64 = u64(c.Deref(t.CUInt64T(he.h_addr_list, t.CPtr))) + if ip_ptr != 0: + addr.addr = u32(c.Deref(t.CUInt32T(ip_ptr, t.CPtr))) + + return addr + + +def _ParseIPv4(ip_str: str, out_addr: u32 | t.CPtr) -> bool: + """Parse IPv4 address.""" + if ip_str is None or out_addr is None: return False + + parts: t.CArray[INT, 4] + part_count: INT = 0 + current: INT = 0 + started: bool = False + + for ch in ip_str: + if ch >= '0' and ch <= '9': + if not started: started = True + current = current * 10 + INT(ch - '0') + if current > 255: return False + elif ch == '.': + if not started: return False + if part_count >= 4: return False + parts[part_count] = current + part_count += 1 + current = 0 + started = False + else: + break + + if started and part_count < 4: + parts[part_count] = current + part_count += 1 + + if part_count != 4: return False + + result: u32 = 0 + result = result | (u32(parts[0]) << 24) + result = result | (u32(parts[1]) << 16) + result = result | (u32(parts[2]) << 8) + result = result | u32(parts[3]) + c.DerefAs(out_addr, result) + return True + + +# ============================================================ +# Socket class — Python OOP API +# ============================================================ + +class Socket: + """Cross-platform Socket class, similar to Python socket.socket. + + Usage: + sock = Socket(AF_INET, SOCK_STREAM) + sock.connect("example.com", 80) + sock.send(data, length) + n = sock.recv(buf, bufsize) + sock.close() + """ + fd: INT + family: INT + type: INT + protocol: INT + + def __init__(self, family: INT, type: INT, protocol: INT = 0): + """Create Socket. + + Args: + family: Address family (AF_INET) + type: Socket type (SOCK_STREAM) + protocol: Protocol (default 0, auto-match) + """ + self.family = family + self.type = type + self.protocol = protocol + + if platmacro.IS_WINDOWS: + self.fd = INT(w32.winsock2.socket(family, type, protocol)) + else: + self.fd = socket(family, type, protocol) + + def connect(self, host: str, port: INT) -> INT: + """Connect to remote host. + + Args: + host: Hostname or IP + port: Port number + Returns: + 0 success, non 0 otherwise + """ + if self.fd == INVALID_SOCKET: return -1 + addr: SocketAddr = _MakeAddr(host, port) + + result: INT = 0 + if platmacro.IS_WINDOWS: + result = w32.winsock2.connect(u64(self.fd), c.Addr(addr), 16) + if result != 0: + err: INT = w32.winsock2.WSAGetLastError() + else: + result = connect(self.fd, c.Addr(addr), 16) + return result + + def send(self, data: t.CVoid | t.CPtr, length: INT) -> INT: + """Send data. + + Returns: + Sent bytes, SOCKET_ERROR on error + """ + if self.fd == INVALID_SOCKET: return SOCKET_ERROR + if data is None or length <= 0: return 0 + + if platmacro.IS_WINDOWS: + return w32.winsock2.send(u64(self.fd), data, length, 0) + return send(self.fd, data, length, 0) + + def recv(self, buf: t.CVoid | t.CPtr, bufsize: INT) -> INT: + """Receive data. + + Returns: + Received bytes, SOCKET_ERROR on error, 0 on connection close + """ + if self.fd == INVALID_SOCKET: return SOCKET_ERROR + if buf is None or bufsize <= 0: return 0 + + if platmacro.IS_WINDOWS: + return w32.winsock2.recv(u64(self.fd), buf, bufsize, 0) + return recv(self.fd, buf, bufsize, 0) + + def sendall(self, data: t.CVoid | t.CPtr, length: INT) -> INT: + """Send all data. + + Returns: + 0 success, SOCKET_ERROR on error + """ + if self.fd == INVALID_SOCKET: return SOCKET_ERROR + if data is None or length <= 0: return 0 + + total: INT = 0 + while total < length: + n: INT = self.send(t.CVoid(t.CUInt64T(data) + total, t.CPtr), length - total) + if n <= 0: return SOCKET_ERROR + total += n + return 0 + + def close(self) -> INT: + """Close Socket.""" + if self.fd == INVALID_SOCKET: return 0 + result: INT = _CloseFd(self.fd) + self.fd = INVALID_SOCKET + return result + + def bind(self, host: str, port: INT) -> INT: + """Bind address and port (server-side). + + Returns: + 0 success, non 0 otherwise + """ + if self.fd == INVALID_SOCKET: return -1 + addr: SocketAddr = _MakeAddr(host, port) + + if platmacro.IS_WINDOWS: + return w32.winsock2.bind(u64(self.fd), c.Addr(addr), 16) + return bind(self.fd, c.Addr(addr), 16) + + def listen(self, backlog: INT) -> INT: + """Start for incoming connections (server-side). + + Returns: + 0 success, non 0 otherwise + """ + if self.fd == INVALID_SOCKET: return -1 + + if platmacro.IS_WINDOWS: + return w32.winsock2.listen(u64(self.fd), backlog) + return listen(self.fd, backlog) + + def accept(self, out_client: 'Socket' | t.CPtr) -> INT: + """Accept a client connection. + + Args: + out_client: Output parameter, receives client Socket + Returns: + Client fd (>= 0 on success), SOCKET_ERROR on error + """ + if self.fd == INVALID_SOCKET: return SOCKET_ERROR + if out_client is None: return SOCKET_ERROR + + addr: SocketAddr + string.memset(c.Addr(addr), 0, 16) + addrlen: INT = 16 + + if platmacro.IS_WINDOWS: + client_fd: u64 = w32.winsock2.accept(u64(self.fd), c.Addr(addr), c.Addr(addrlen)) + if client_fd == w32.winsock2.INVALID_SOCKET: + return SOCKET_ERROR + out_client.fd = INT(client_fd) + out_client.family = self.family + out_client.type = self.type + out_client.protocol = self.protocol + return INT(client_fd) + + client_fd: INT = accept(self.fd, c.Addr(addr), c.Addr(addrlen)) + if client_fd == SOCKET_ERROR: + return SOCKET_ERROR + out_client.fd = client_fd + out_client.family = self.family + out_client.type = self.type + out_client.protocol = self.protocol + return client_fd + + def settimeout(self, timeout_ms: INT) -> INT: + """Set timeout for receive and send operations (milliseconds). + + Returns: + 0 success, non 0 otherwise + """ + if self.fd == INVALID_SOCKET: return -1 + + tv: timeval + tv.tv_sec = timeout_ms / 1000 + tv.tv_usec = (timeout_ms % 1000) * 1000 + optlen: INT = 8 + + if platmacro.IS_WINDOWS: + r1: INT = w32.winsock2.setsockopt(u64(self.fd), SOL_SOCKET, SO_RCVTIMEO, c.Addr(tv), optlen) + r2: INT = w32.winsock2.setsockopt(u64(self.fd), SOL_SOCKET, SO_SNDTIMEO, c.Addr(tv), optlen) + else: + r1 = setsockopt(self.fd, SOL_SOCKET, SO_RCVTIMEO, c.Addr(tv), optlen) + r2 = setsockopt(self.fd, SOL_SOCKET, SO_SNDTIMEO, c.Addr(tv), optlen) + + if r1 != 0: return r1 + return r2 + + def fileno(self) -> INT: + """Return underlying file descriptor / SOCKET handle.""" + return self.fd + + +# ============================================================ +# Platform initialization +# ============================================================ + +def SocketInit() -> INT: + """Initialize the Socket library. On Windows, call WSAStartup; on POSIX, do nothing.""" + if platmacro.IS_WINDOWS: + wsa_data: t.CArray[BYTE, 400] + string.memset(c.Addr(wsa_data), 0, 400) + return w32.winsock2.WSAStartup(w32.winsock2.WINSOCK_VERSION, c.Addr(wsa_data)) + return 0 + + +def SocketCleanup() -> INT: + """Cleanup the Socket library.""" + if platmacro.IS_WINDOWS: + return w32.winsock2.WSACleanup() + return 0 + + +# ============================================================ +# Compatibility with old procedural API (delegates to Socket methods) +# ============================================================ + +def SocketCreate(family: INT, type: INT, protocol: INT, out_sock: Socket | t.CPtr) -> INT: + """Create a Socket handle (compatible with old API). It is recommended to use Socket(...) constructor.""" + if out_sock is None: return -1 + out_sock.family = family + out_sock.type = type + out_sock.protocol = protocol + + if platmacro.IS_WINDOWS: + fd: u64 = w32.winsock2.socket(family, type, protocol) + out_sock.fd = INT(fd) + if fd == w32.winsock2.INVALID_SOCKET: return -1 + else: + fd: INT = socket(family, type, protocol) + out_sock.fd = fd + if fd == INVALID_SOCKET: return -1 + return 0 + +# But maybe using OOP would be better, though that can be wrapped up later. + +def SocketConnect(sock: Socket | t.CPtr, host: str, port: INT) -> INT: + return sock.connect(host, port) + + +def SocketSend(sock: Socket | t.CPtr, data: t.CVoid | t.CPtr, length: INT) -> INT: + return sock.send(data, length) + + +def SocketRecv(sock: Socket | t.CPtr, buf: t.CVoid | t.CPtr, bufsize: INT) -> INT: + return sock.recv(buf, bufsize) + + +def SocketClose(sock: Socket | t.CPtr) -> INT: + return sock.close() + + +def SocketBind(sock: Socket | t.CPtr, host: str, port: INT) -> INT: + return sock.bind(host, port) + + +def SocketListen(sock: Socket | t.CPtr, backlog: INT) -> INT: + return sock.listen(backlog) + + +def SocketAccept(sock: Socket | t.CPtr, out_client: Socket | t.CPtr) -> INT: + return sock.accept(out_client) + + +def SocketSetTimeout(sock: Socket | t.CPtr, timeout_ms: INT) -> INT: + return sock.settimeout(timeout_ms) + + +def SocketIsValid(sock: Socket | t.CPtr) -> bool: + """Check if a Socket is valid.""" + if sock is None: return False + return sock.fd != INVALID_SOCKET \ No newline at end of file diff --git a/spinlock.vp b/spinlock.vp new file mode 100644 index 0000000..b16ecb3 --- /dev/null +++ b/spinlock.vp @@ -0,0 +1,16 @@ +import t, c +import atom + + +class _spinlock: + locked: t.CVolatile | t.CInt + name: t.CArray[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/stdarg.vp b/stdarg.vp new file mode 100644 index 0000000..1d0192f --- /dev/null +++ b/stdarg.vp @@ -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/stdint.vp b/stdint.vp new file mode 100644 index 0000000..727b759 --- /dev/null +++ b/stdint.vp @@ -0,0 +1,133 @@ +import t + + +# ============================================================================= +# 大写别名(Win32/TransPyC 风格) +# 注意:INTPTR/UINTPTR 在此模块中是 int*/unsigned int* 指针类型(历史命名)。 +# 它们与 C 标准的 intptr_t/uintptr_t 整数类型不同,后者见下方小写 _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.CLongLong +ULONGLONG: t.CTypedef = t.CUnsignedLongLong +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 + +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 + +i8: t.CTypedef = t.CInt8T +i16: t.CTypedef = t.CInt16T +i32: t.CTypedef = t.CInt32T +i64: t.CTypedef = t.CInt64T + +u8: t.CTypedef = t.CUInt8T +u16: t.CTypedef = t.CUInt16T +u32: t.CTypedef = t.CUInt32T +u64: t.CTypedef = t.CUInt64T + +SIZE_T: t.CTypedef = t.CSizeT +SSIZE_T: t.CTypedef = t.CPtrDiffT +PTRDIFF_T: t.CTypedef = t.CPtrDiffT + + +# ============================================================================= +# C 标准库 类型名(小写 _t 后缀) +# 这些是 C 语言标准类型名,从 _CNAME_ALIAS 挪到此处作为 typedef 提供。 +# 用户 `from stdint import *` 后即可直接使用 int8_t / size_t 等。 +# ============================================================================= +int8_t: t.CTypedef = t.CInt8T +int16_t: t.CTypedef = t.CInt16T +int32_t: t.CTypedef = t.CInt32T +int64_t: t.CTypedef = t.CInt64T + +uint8_t: t.CTypedef = t.CUInt8T +uint16_t: t.CTypedef = t.CUInt16T +uint32_t: t.CTypedef = t.CUInt32T +uint64_t: t.CTypedef = t.CUInt64T + +size_t: t.CTypedef = t.CSizeT +ssize_t: t.CTypedef = t.CPtrDiffT +ptrdiff_t: t.CTypedef = t.CPtrDiffT + +# intptr_t/uintptr_t 是足以容纳指针的整数类型(不是指针!) +# 与上方的 INTPTR/UINTPTR(int 指针)语义不同。 +intptr_t: t.CTypedef = t.CIntPtrT +uintptr_t: t.CTypedef = t.CUIntPtrT + +# 宽字符 / 字符类型 +wchar_t: t.CTypedef = t.CWCharT +char8_t: t.CTypedef = t.CChar8T +char16_t: t.CTypedef = t.CChar16T +char32_t: t.CTypedef = t.CChar32T + +# 浮点特化类型 +float8_t: t.CTypedef = t.CFloat8T +float16_t: t.CTypedef = t.CFloat16T +float32_t: t.CTypedef = t.CFloat32T +float64_t: t.CTypedef = t.CFloat64T +float128_t: t.CTypedef = t.CFloat128T + +_Bool: t.CTypedef = t.CBool diff --git a/stdio.vp b/stdio.vp new file mode 100644 index 0000000..5dd3213 --- /dev/null +++ b/stdio.vp @@ -0,0 +1,11 @@ +import t, c + + +def printf(fmt: t.CConst | str, *args) -> int | t.State: pass +def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> int | t.State: pass +def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> int | t.State: pass +def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> int | t.State: pass +def puts(s: t.CConst | str) -> int | t.State: pass +def fputs(s: t.CConst | str, stream: bytes) -> int | t.State: pass +def fgets(buf: bytes, size: int, stream: bytes) -> bytes | t.State: pass +def fflush(stream: bytes) -> int | t.State: pass diff --git a/stdlib.vp b/stdlib.vp new file mode 100644 index 0000000..a580043 --- /dev/null +++ b/stdlib.vp @@ -0,0 +1,10 @@ +from stdint import * +import t + + +def malloc(size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass +def calloc(nmemb: t.CSizeT, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass +def realloc(p: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CVoid | t.CPtr | t.State: pass +def free(p: t.CVoid | t.CPtr) -> t.State: pass +def system(cmd: t.CConst | t.CChar | t.CPtr) -> INT | t.State: pass +def exit(status: int) -> t.State: pass \ No newline at end of file diff --git a/string.vp b/string.vp new file mode 100644 index 0000000..89981f1 --- /dev/null +++ b/string.vp @@ -0,0 +1,417 @@ +from stdint import * +import t, c +import stdio + + +# String copy function +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 + + +# String concatenate function +def strcat(dest: str, src: str) -> str: + if dest == None or src == None: return dest + original_dest: str = dest + # Find end of dest + while dest[0] != '\0': + dest += 1 + # Copy src + for s in src: + dest[0] = s + dest += 1 + dest[0] = 0 + return original_dest + + +# String copy function with limited length +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 + # Fill remaining space with '\0' + while i < n: + dest[0] = 0 + dest += 1 + i += 1 + return original_dest + + +# String concatenate function with limited length +def strncat(dest: str, src: str, n: t.CSizeT) -> str: + if dest == None or src == None or n == 0: return dest + original_dest: str = dest + # Find end of dest + while dest[0] != '\0': + dest += 1 + # Copy up to n chars from src + i: t.CSizeT = 0 + for s in src: + if i >= n: break + dest[0] = s + dest += 1 + i += 1 + dest[0] = 0 + return original_dest + + +# String length function +def strlen(src: str) -> t.CSizeT | t.CExport: + length: t.CSizeT = 0 + for _ in src: + length += 1 + return length + +# String comparison function +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 + + +# String compare function with limited length +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 + + +# Memory compare function +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 + + +# String find function +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 + +# String reverse find function (find last occurrence of character) +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 + + +# Substring search function (find first occurrence of needle in s, return pointer to that position, or None if not found) +def strstr(s: str, needle: str) -> str: + if needle[0] == 0: + return s + needle_len: t.CSizeT = strlen(needle) + if needle_len == 0: + return s + i: t.CSizeT = 0 + s_len: t.CSizeT = strlen(s) + while i + needle_len <= s_len: + if strncmp(s + i, needle, needle_len) == 0: + return s + i + i += 1 + return None + +# String skip function +def strspn(s: str, skip: str = " ") -> int: + si: int = 0 + while s[si] != 0: + found: int = 0 + sj: int = 0 + while skip[sj] != 0: + if s[si] == skip[sj]: + found = 1 + break + sj += 1 + if found == 0: + break + si += 1 + return si + +# Memory set function +def memset(ptr: t.CVoid | t.CPtr, value: t.CInt, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: + # Original implementation: + # 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: + # Original implementation: + # 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 + + +# Memory copy function +def memcpy(dest: t.CVoid | t.CPtr, src: t.CVoid | t.CPtr, num: t.CSizeT) -> t.CVoid | t.CPtr | t.CExport: + # Original implementation: + # 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 + # 十六进制前缀 0x / 0X + is_hex: t.CInt = 0 + if s[0] == '0' and (s[1] == 'x' or s[1] == 'X'): + is_hex = 1 + s += 2 + if is_hex: + for ch in s: + d: t.CInt = 0 + if ch >= '0' and ch <= '9': + d = ch - '0' + elif ch >= 'a' and ch <= 'f': + d = ch - 'a' + 10 + elif ch >= 'A' and ch <= 'F': + d = ch - 'A' + 10 + else: + break + digit: t.CInt64T = t.CInt64T(d) + num = num * 16 + digit + else: + 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 atof_out(src: str, out: t.CDouble | t.CPtr) -> t.CInt: + """atof 结果写入 out[0](输出参数方式,避免跨模块 double 返回值传递 bug) + + 返回值仅表示成功与否(1=成功,0=失败),结果值通过 out 指针传递, + 不依赖 double 返回值的跨模块传递。 + """ + if out is None: + return 0 + v: t.CDouble = atof(src) + out[0] = v + return 1 + +def split(s: str, delim: str, result: t.CArray[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 + + +ascii_lowercase: str = "abcdefghijklmnopqrstuvwxyz" +ascii_uppercase: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +ascii_letters: str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +digits: str = "0123456789" +hexdigits: str = "0123456789abcdefABCDEF" +octdigits: str = "01234567" +punctuation: str = "!\"#$%&'()*+,-./:;<=>?@[]^_`{|}~" +whitespace: str = " \t\n\r\f\v" +printable: str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\f\v" diff --git a/subprocess.vp b/subprocess.vp new file mode 100644 index 0000000..3496993 --- /dev/null +++ b/subprocess.vp @@ -0,0 +1,196 @@ +import t, c +from stdint import * +import platmacro +import memhub +import string + +# Windows backend dependencies +import w32.win32base +import w32.win32file +import w32.win32process +import w32.win32sync + +# POSIX backend dependencies +import posix + + +# Subprocess output buffer size +OUTPUT_BUF_SIZE: t.CDefine = 65536 + +# Module global MBuddy pointer (initialized in main) +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# CompletedProcess result class +# ============================================================================= + +class CompletedProcess: + """Result class for subprocess.run.""" + args: str # Original command line + returncode: int # Process exit code (0 means success) + stdout: str # Standard output (when capture_output=True) + stderr: str # Standard error (when capture_output=True) + + def __new__(self, args: str, returncode: int, stdout: str, stderr: str) -> t.CPtr: + # Heap allocation (avoiding use-after-return) + return t.CPtr(_mbuddy.alloc(CompletedProcess.__sizeof__())) + + def __init__(self, args: str, returncode: int, stdout: str, stderr: str): + self.args = args + self.returncode = returncode + self.stdout = stdout + self.stderr = stderr + + +# ============================================================================= +# Entry function +# ============================================================================= + +def run(args: str, capture_output: bool = True, text: bool = True) -> CompletedProcess | t.CPtr: + """Run a subprocess synchronously and wait for it to finish. + The args are the full command line string. + If capture_output=True, stdout/stderr will be captured. If text=True, the output will be a string (currently it always returns a string). + Returns a CompletedProcess object.""" + if platmacro.IS_WINDOWS: + return _run_win32(args, capture_output, text) + return _run_posix(args, capture_output, text) + + +# ============================================================================= +# Windows backend implementation +# ============================================================================= + +def _run_win32(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr: + """Windows platform subprocess execution (CreateProcessA pipe)""" + # Copy command line (CreateProcessA requires a modifiable lpCommandLine) + args_len: t.CSizeT = len(args) + cmd_line: bytes = _mbuddy.alloc(args_len + 1) + if cmd_line == None: + return CompletedProcess(args, -1, None, None) + i: t.CSizeT = 0 + for ch in args: + cmd_line[i] = ch + i += 1 + cmd_line[args_len] = 0 + + # Security attributes (allow handle inheritance) + sa: w32.win32base.SECURITY_ATTRIBUTES = w32.win32base.SECURITY_ATTRIBUTES() + sa.nLength = w32.win32base.SECURITY_ATTRIBUTES.__sizeof__() + sa.lpSecurityDescriptor = t.CPtr(0) + sa.bInheritHandle = 1 # TRUE + + # Create stdout pipe + stdout_read: w32.win32base.HANDLE = t.CPtr(0) + stdout_write: w32.win32base.HANDLE = t.CPtr(0) + if capture_output: + pipe_result: BOOL = w32.win32file.CreatePipe( + t.CPtr(c.Addr(stdout_read)), + t.CPtr(c.Addr(stdout_write)), + t.CPtr(c.Addr(sa)), + 0 + ) + if pipe_result == 0: + return CompletedProcess(args, -1, None, None) + # Prevent read end from being inherited by child process + w32.win32file.SetHandleInformation(stdout_read, w32.win32file.HANDLE_FLAG_INHERIT, 0) + + # Set startup information + si: w32.win32process.STARTUPINFOA = w32.win32process.STARTUPINFOA() + si.cb = w32.win32process.STARTUPINFOA.__sizeof__() + if capture_output: + si.dwFlags = w32.win32process.STARTF_USESTDHANDLES + si.hStdOutput = stdout_write + si.hStdError = stdout_write # stderr merged to stdout + + pi: w32.win32process.PROCESS_INFORMATION = w32.win32process.PROCESS_INFORMATION() + + # Create process + # use CREATE_NO_WINDOW when capture_output=True (output to pipe, no console) + # use 0 when capture_output=False (inherit parent process console, let stdout directly display) + create_flags: ULONG = w32.win32process.CREATE_NO_WINDOW if capture_output else 0 + create_result: BOOL = w32.win32process.CreateProcessA( + t.CPtr(0), # lpApplicationName (NULL, parse from command line) + cmd_line, # lpCommandLine (modifiable) + t.CPtr(0), # lpProcessAttributes + t.CPtr(0), # lpThreadAttributes + 1, # bInheritHandles = TRUE + create_flags, # dwCreationFlags + t.CPtr(0), # lpEnvironment (inherit from parent process) + t.CPtr(0), # lpCurrentDirectory (inherit from parent process) + t.CPtr(c.Addr(si)), + t.CPtr(c.Addr(pi)) + ) + + if create_result == 0: + # Create process failed + if capture_output: + w32.win32base.CloseHandle(stdout_read) + w32.win32base.CloseHandle(stdout_write) + return CompletedProcess(args, -1, None, None) + + # Close parent process's write end (child process already has a copy of it) + if capture_output: + w32.win32base.CloseHandle(stdout_write) + + # Read stdout + wait for process to exit + # Note: must read and wait at the same time, or else deadlock will occur when child process outputs more than pipe buffer size + # (child process blocks on writing stdout, parent process blocks on WaitForSingleObject) + stdout_str: str = None + if capture_output: + buf_size: ULONG = OUTPUT_BUF_SIZE + buf: bytes = _mbuddy.alloc(buf_size) + if buf != None: + total: ULONG = 0 + while 1: + bytes_read: ULONG = 0 + read_result: BOOL = w32.win32file.ReadFile( + stdout_read, + buf + total, + buf_size - 1 - total, + t.CPtr(c.Addr(bytes_read)), + t.CPtr(0) + ) + if read_result == 0 or bytes_read == 0: + break + total += bytes_read + # Buffer will be full, double it + if total >= buf_size - 1 - 4096: + new_size: ULONG = buf_size * 2 + new_buf: bytes = _mbuddy.alloc(new_size) + if new_buf != None: + string.memcpy(new_buf, buf, total) + buf = new_buf + buf_size = new_size + else: + # Expand failed, stop reading + break + buf[total] = 0 + stdout_str = str(buf) + + # Wait for process to exit + w32.win32sync.WaitForSingleObject(pi.hProcess, w32.win32base.INFINITE) + + # Get exit code + exit_code: ULONG = 0 + w32.win32process.GetExitCodeProcess(pi.hProcess, t.CPtr(c.Addr(exit_code))) + + # Close handles + w32.win32base.CloseHandle(pi.hProcess) + w32.win32base.CloseHandle(pi.hThread) + if capture_output: + w32.win32base.CloseHandle(stdout_read) + + return CompletedProcess(args, exit_code, stdout_str, None) + + +# ============================================================================= +# POSIX backend implementation +# ============================================================================= + +def _run_posix(args: str, capture_output: bool, text: bool) -> CompletedProcess | t.CPtr: + """POSIX platform subprocess execution (fork, execvp, pipe, waitpid) + Note: Currently this is a stub function. + POSIX implementation requires pipe/fork/waitpid, which are not available on Windows MinGW. + It will be completed when testing on a POSIX platform.""" + return CompletedProcess(args, -1, None, None) diff --git a/sys.vp b/sys.vp new file mode 100644 index 0000000..251a776 --- /dev/null +++ b/sys.vp @@ -0,0 +1,200 @@ +import t, c +from stdint import * +import platmacro +import memhub +import string +import stdio + +# Windows backend dependencies +import w32.win32base +import w32.win32process + +# POSIX backend dependencies +import posix + +# Module global MBuddy pointer (initialized in user main), Plans to ban +_mbuddy: memhub.MemBuddy | t.CPtr + + +# ============================================================================= +# C Standard Library IO Declarations +# ============================================================================= + +def fgets(buf: bytes, size: int, stream: t.CVoid | t.CPtr) -> str | t.State: pass + +def fflush(stream: t.CVoid | t.CPtr) -> int | t.State: pass + +# C standard library exit (terminates the process after flushing the buffer, cross-platform) +def exit(status: int) -> t.State: pass + + +# ============================================================================= +# Platform Information +# ============================================================================= + +# Maximum integer value (64-bit platform ssize_t upper limit) +maxsize: t.CDefine = 9223372036854775807 # 2^63 - 1 + + +def platform() -> str: + """Returns the platform identifier string ('win32' or 'linux').""" + if platmacro.IS_WINDOWS: + return "win32" + return "linux" + + +# ============================================================================= +# Process Information +# ============================================================================= + +def get_pid() -> int: + """返回当前进程 ID""" + if platmacro.IS_WINDOWS: + return w32.win32process.GetCurrentProcessId() + return posix.getpid() + + +# ============================================================================= +# Command Line Arguments (argv) +# ============================================================================= + +# global argv status (initialized on first access) +_argc: int = 0 +# _argv is a pointer array (char**), must use str | t.CPtr to index with sizeof(char*) +# str | t.CPtr is a pointer to char** +# bytes | t.CPtr is a pointer to char** +_argv: str | t.CPtr + + +def _init_argv(): + """Initialize global argv once on first access""" + global _argc, _argv + if _argc != 0: + return + if platmacro.IS_WINDOWS: + _init_argv_win32() + else: + _init_argv_posix() + + +def _init_argv_win32(): + """Windows: GetCommandLineA + manual parsing (handle spaces/double quotes/backslashes)""" + global _argc, _argv + cmdline: CHARPTR = w32.win32base.GetCommandLineA() + if cmdline == None: + return + cmdlen: t.CSizeT = string.strlen(cmdline) + if cmdlen == 0: + return + + # Allocate buffer for parameter strings (worst case: entire command line + argc \0s) + buf: bytes = _mbuddy.alloc(cmdlen + 1) + if buf == None: + return + + # Allocate pointer array for argv (worst case: each character is a parameter) + max_args: t.CSizeT = cmdlen + 1 + argv_arr: str | t.CPtr = (str | t.CPtr)(_mbuddy.alloc(max_args * platmacro.SIZEOF_POINTER)) + if argv_arr == None: + return + + argc: INT = 0 + i: t.CSizeT = 0 + j: t.CSizeT = 0 + in_quote: bool = False + in_arg: bool = False + + while i < cmdlen: + ch: t.CInt = cmdline[i] + if ch == 34: # Double quote + in_quote = not in_quote + if not in_arg: + argv_arr[argc] = str(buf + j) + argc += 1 + in_arg = True + elif (ch == 32 or ch == 9) and not in_quote: + # Space or Tab (outside quotes): parameter delimiter + if in_arg: + buf[j] = 0 + j += 1 + in_arg = False + else: + if not in_arg: + argv_arr[argc] = str(buf + j) + argc += 1 + in_arg = True + buf[j] = ch + j += 1 + i += 1 + + if in_arg: + buf[j] = 0 + + _argc = argc + _argv = argv_arr + + +def _init_argv_posix(): + """POSIX: Read cmdline from /proc/self/cmdline (\0) separated parameters""" + global _argc, _argv + fd: INT = posix.open("/proc/self/cmdline", posix.O_RDONLY, 0) + if fd < 0: + return + + # Read cmdline (4KB) + buf: bytes = _mbuddy.alloc(4096) # Need to verify size of buffer + if buf == None: + posix.close(fd) + return + + total: ssize_t = posix.read(fd, buf, 4096) + posix.close(fd) + if total <= 0: + return + + # Calculate argument count (\0 delimited) + argc: INT = 0 + i: t.CSizeT = 0 + total_size: t.CSizeT = t.CSizeT(total) + while i < total_size: + if buf[i] == 0: + argc += 1 + i += 1 + + if argc == 0: + return + + # Allocate pointer array for argv (argc pointers) + argv_arr: str | t.CPtr = (str | t.CPtr)(_mbuddy.alloc(argc * platmacro.SIZEOF_POINTER)) + if argv_arr == None: + return + + # Populate pointer array (start address of each parameter) + argv_arr[0] = str(buf) + idx: INT = 1 + i = 0 + while i < total_size and idx < argc: + if buf[i] == 0: + argv_arr[idx] = str(buf + i + 1) + idx += 1 + i += 1 + + _argc = argc + _argv = argv_arr + + +def argc() -> int: + """Returns the number of command line arguments. Automatically initializes on the first call.""" + if _argc == 0: + _init_argv() + return _argc + + +def argv(index: int) -> str: + """Returns the command line argument at index `index` (starting from 0). + Automatically initializes on first call. Returns None if the index is out of range.""" + if _argc == 0: + _init_argv() + if index < 0 or index >= _argc: + return None + return _argv[index] diff --git a/testcheck.vp b/testcheck.vp new file mode 100644 index 0000000..29e1989 --- /dev/null +++ b/testcheck.vp @@ -0,0 +1,71 @@ +# testcheck - Regression test formatted output library +# Provide PASS/FAIL counts, section headers, summary reports +import t, c +import stdio +from w32.win32console import SetConsoleOutputCP, SetConsoleCP + +CP_UTF8: t.CDefine = 65001 + +_pass_count: t.CInt = 0 +_fail_count: t.CInt = 0 +_total_pass: t.CInt = 0 +_total_fail: t.CInt = 0 + + +def begin(name: str): + """Start the test suite, print the header, and reset the current suite counter (total count remains the same)""" + global _pass_count, _fail_count + _pass_count = 0 + _fail_count = 0 + SetConsoleOutputCP(CP_UTF8) + SetConsoleCP(CP_UTF8) + stdio.printf("=== %s ===\n\n", name) + + +def section(name: str): + """Print the section header""" + stdio.printf("--- %s ---\n", name) + + +def ok(msg: str): + """Print PASS and count""" + global _pass_count + _pass_count += 1 + stdio.printf("PASS: %s\n", msg) + + +def fail(msg: str): + """Print FAIL and count""" + global _fail_count + _fail_count += 1 + stdio.printf("FAIL: %s\n", msg) + + +def check(cond: t.CInt, ok_msg: str, fail_msg: str): + """Conditional check, automatically select PASS/FAIL""" + if cond: + ok(ok_msg) + else: + fail(fail_msg) + + +def info(msg: str): + """Print information message (not counted in the PASS/FAIL messages)""" + stdio.printf("%s\n", msg) + + +def end() -> t.CInt: + """Print the current suite summary, accumulate to total, return the current suite fail count""" + global _total_pass, _total_fail + _total_pass += _pass_count + _total_fail += _fail_count + stdio.printf("\n--- Summary ---\n") + stdio.printf("PASS: %d, FAIL: %d\n", _pass_count, _fail_count) + return _fail_count + + +def summary() -> t.CInt: + """Print the total summary of all suites, return the total fail count""" + stdio.printf("\n=== Total Summary ===\n") + stdio.printf("Total PASS: %d, Total FAIL: %d\n", _total_pass, _total_fail) + return _total_fail diff --git a/this.vp b/this.vp new file mode 100644 index 0000000..8c93b93 --- /dev/null +++ b/this.vp @@ -0,0 +1,39 @@ +import stdio, t, c + + +def this(): + s: str = """Ivcre Cevapvcyrf, ol GrezvArkhf + +Ornhgl orngf htyvarff. +Rkcyvpvg orngf vzcyvpvg. +Fvzcyr orngf pbzcyrk. +Pbapvfr orngf ireobfr. +Syng orngf qrrc arfgvat. +Fcnpvbhf orngf pyhggrerq. +Ernqnovyvgl vf pehpvny. +Fcrpvny pnfrf qba’g whfgvsl oernxvat gur ehyrf. +Ohg cenpgvpnyvgl orngf cher vqrnyf. +Reebef fubhyq arire or fvyragyl vtaberq. +Hayrff rkcyvpvgyl fgngrq gb or vtaberq. +Jura snprq jvgu nzovthbhf frznagvpf, erfvfg znxvat nffhzcgvbaf. +Hayrff pyrneyl nyybjrq. +Gurer fubhyq or bar — cersrenoyl bayl bar — boivbhf jnl gb qb vg. +Rira vs vg’f uneq gb tenfc ng svefg, hayrff lbh qrrcyl haqrefgnaq gur haqreylvat flfgrz. +Fgnegvat vzzrqvngryl orngf vaqrsvavgr qrynl. +Ohg unfgl npgvba vf bsgra jbefr guna pnershy jnvgvat. +Vs na vzcyrzragngvba vf bofpher naq uneq gb qrfpevor, vg’f n onq fbyhgvba. +Vs na vzcyrzragngvba vf pyrne naq rnfl gb haqrefgnaq, punaprf ner vg’f n tbbq fbyhgvba. +Anzrfcnprf ner vaperqvoyl inyhnoyr — hfr gurz trarebhfyl!""" + + # ASCII + m: t.CArray[t.CChar, 256] = [0] + l: t.CArray[int, 2] = [65, 97] + + for k in [65, 97]: + for i in range(26): + m[k + i] = (k + ((i + 13) % 26)) # Implicit type conversion + + for ch in s: + _: t.CUInt8T = ch + stdio.printf("%c", m[_] if m[_] else ch) + stdio.printf("\n") diff --git a/vector.vp b/vector.vp new file mode 100644 index 0000000..e32a74b --- /dev/null +++ b/vector.vp @@ -0,0 +1,65 @@ +import t, c +from stdint import * +import memhub + + +class Vector[T](): + data: t.CVoid | t.CPtr + length: t.CSizeT + capacity: t.CSizeT + elem_size: t.CSizeT + pool: memhub.MemManager | t.CPtr + + def __init__(self, pool: memhub.MemManager | 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 + new_size: t.CSizeT = new_capacity * self.elem_size + new_data: t.CVoid | t.CPtr = self.pool.realloc(self.data, 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/viperio.vp b/viperio.vp new file mode 100644 index 0000000..48157bc --- /dev/null +++ b/viperio.vp @@ -0,0 +1,59 @@ +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 + # 恰好写满(n==avail)时 data[capacity] 越界 1 字节,加保护 + if self.length < self.capacity: + 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/viperlib.vp b/viperlib.vp new file mode 100644 index 0000000..f0cecb6 --- /dev/null +++ b/viperlib.vp @@ -0,0 +1,1375 @@ +import t, c +import viperio +from stdarg import arg, va_arg + +TEMP_BUF_SIZE: t.CDefine = 68 + +def get_digit_count(num: t.CUnsignedInt, base: t.CInt) -> t.CStatic | t.CInt: + 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.CExport: + if buf is None or rule is None: return + vsnprintf(buf, 0x7FFFFFFF, rule, args) + +def vsprintf(buf: t.CChar | t.CPtr, rule: str, *args) -> t.CInt: + if buf is None or rule is None: return 0 + return vsnprintf(buf, 0x7FFFFFFF, rule, args) + +def snprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, *args) -> t.CInt | t.CExport: + if fmt is None: return 0 + if buf is None or size == 0: + return vsnprintf(None, 0, fmt, args) + ret: t.CInt = vsnprintf(buf, size, fmt, args) + return ret + +# Check floating-point special values (IEEE 754) +# Return: 0=normal, 1=+inf, 2=-inf, 3=nan +def _check_special_float(fv: t.CDouble) -> t.CInt: + fbits: t.CUInt64T = 0 + c.Load(c.Addr(fbits), c.Addr(fv)) + if ((fbits >> 52) & 0x7FF) != 0x7FF: + return 0 + is_neg: t.CInt = 1 if (fbits >> 63) != 0 else 0 + if (fbits & 0x000FFFFFFFFFFFFF) == 0: + if is_neg: + return 2 + return 1 + return 3 + +def vsnprintf(buf: t.CChar | t.CPtr, size: t.CSizeT, fmt: str, ap: t.CChar | t.CPtr) -> t.CInt | t.CExport: + if fmt is None: return 0 + # 长度探测模式:buf is None 时只计算格式化后长度,不实际写入 + # _step=0 使 ptr 不前进,反复写入同一个 dummy 字节(无害),write_count 正确累加 + count_mode: t.CInt = 0 + _step: t.CInt = 1 + _dummy: t.CChar = '\0' + if buf is None or size == 0: + count_mode = 1 + _step = 0 + buf = c.Addr(_dummy) + size = 0x7FFFFFFF + ptr: t.CChar | t.CPtr = buf + write_count: t.CInt = 0 + temp: t.CArray[t.CChar, 68] + 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 += _step + 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 + space_sign: t.CInt = 0 + alt_form: t.CInt = 0 + precision: t.CInt = -1 + is_long: t.CInt = 0 + is_long_long: t.CInt = 0 + is_size: t.CInt = 0 + is_short: t.CInt = 0 + is_char: 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 + elif c.Deref(fmt) == 32: + space_sign = 1 + fmt += 1 + elif c.Deref(fmt) == 35: + alt_form = 1 + fmt += 1 + else: break + if show_sign: space_sign = 0 + 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) == 104: + is_short = 1 + fmt += 1 + if c.Deref(fmt) == 104: + is_char = 1 + is_short = 0 + fmt += 1 + elif c.Deref(fmt) == 122: + is_size = 1 + fmt += 1 + elif c.Deref(fmt) == 106: + is_long_long = 1 + fmt += 1 + elif c.Deref(fmt) == 116: + is_long = 1 + fmt += 1 + if c.Deref(fmt) == 99: + if write_count < size - 1: + ptr_i: t.CInt = va_arg(ap) + ptr[0] = t.CChar(ptr_i) + write_count += 1 + ptr += _step + else: + ptr_i: t.CInt = va_arg(ap) + elif c.Deref(fmt) == 115: + s: str = va_arg(ap, t.CPtr) + if s is 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 += _step + pad_count -= 1 + while c.Deref(s) != 0 and write_count < size - 1: + ptr[0] = c.Deref(s) + write_count += 1 + ptr += _step + 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 += _step + pad_count -= 1 + elif c.Deref(fmt) == 100 or c.Deref(fmt) == 105: + if is_long_long or is_size or is_long: + num_l: t.CInt64T = va_arg(ap, t.CInt64T) + else: + num_l: t.CInt64T = t.CInt64T(va_arg(ap, t.CInt)) + if is_char: + num_l = t.CInt64T(t.CChar(num_l)) + elif is_short: + num_l = t.CInt64T(t.CShort(num_l)) + sign: t.CInt = 0 + if num_l < 0: + sign = 1 + if num_l == (-9223372036854775807 - 1): + u_num: t.CUInt64T = t.CUInt64T(0x8000000000000000) + else: + u_num: t.CUInt64T = t.CUInt64T(-num_l) + else: + u_num: t.CUInt64T = t.CUInt64T(num_l) + if show_sign: sign = 2 + elif space_sign: sign = 3 + 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 + elif sign == 3 and i < TEMP_BUF_SIZE - 1: + temp[i] = 32 + 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 += _step + 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 += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + 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 += _step + pad_count -= 1 + elif c.Deref(fmt) == 117: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + 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 += _step + 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 += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + 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 += _step + pad_count -= 1 + elif c.Deref(fmt) == 120: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + is_nonzero: t.CInt = 0 + if u_num_l != 0: + is_nonzero = 1 + 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 + digit_count: t.CInt = i + prefix_len: t.CInt = 0 + if alt_form and is_nonzero: + prefix_len = 2 + effective_len: t.CInt = digit_count + prefix_len + if not left_align and not pad_zero and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if prefix_len > 0: + if write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 120 + write_count += 1 + ptr += _step + if pad_zero and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 88: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + is_nonzero = 0 + if u_num_l != 0: + is_nonzero = 1 + 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 + digit_count = i + prefix_len = 0 + if alt_form and is_nonzero: + prefix_len = 2 + effective_len = digit_count + prefix_len + if not left_align and not pad_zero and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if prefix_len > 0: + if write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 88 + write_count += 1 + ptr += _step + if pad_zero and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + if left_align and width > effective_len: + pad_count = width - effective_len + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 111: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + if is_char: + u_num_l = t.CUInt64T(t.CChar(u_num_l)) + elif is_short: + u_num_l = t.CUInt64T(t.CShort(u_num_l)) + i = 0 + if u_num_l == 0 and not alt_form: + temp[0] = 48 + i = 1 + else: + while True: + if i >= TEMP_BUF_SIZE - 1: break + temp[i] = t.CChar(u_num_l % 8 + 48) + i += 1 + u_num_l //= 8 + if u_num_l <= 0: break + if alt_form and i < TEMP_BUF_SIZE - 1: + temp[i] = 48 + 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 += _step + 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 += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + 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 += _step + pad_count -= 1 + elif c.Deref(fmt) == 98: + if is_long or is_long_long or is_size: + u_num_l: t.CUInt64T = va_arg(ap, t.CUInt64T) + else: + u_num_l: t.CUInt64T = t.CUInt64T(t.CUnsignedInt(va_arg(ap))) + if is_char: + u_num_l = t.CUInt64T(t.CChar(u_num_l)) + elif is_short: + u_num_l = t.CUInt64T(t.CShort(u_num_l)) + i = 0 + if u_num_l == 0: + temp[0] = 48 + i = 1 + else: + while True: + if i >= TEMP_BUF_SIZE - 1: break + temp[i] = t.CChar(u_num_l % 2 + 48) + i += 1 + u_num_l //= 2 + if u_num_l <= 0: break + if alt_form and i < TEMP_BUF_SIZE - 1: + temp[i] = 98 + 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 += _step + 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 += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + 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 += _step + pad_count -= 1 + elif c.Deref(fmt) == 112: + ptr_val: t.CUInt64T = t.CUInt64T(va_arg(ap, t.CPtr)) + if ptr_val == 0: + temp[0] = 40 + temp[1] = 110 + temp[2] = 105 + temp[3] = 108 + temp[4] = 41 + i = 5 + else: + u_num_l = ptr_val + 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 + 97) + u_num_l //= 16 + i += 1 + if u_num_l <= 0: break + if i < TEMP_BUF_SIZE - 1: + temp[i] = 120 + i += 1 + if i < TEMP_BUF_SIZE - 1: + temp[i] = 48 + 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 += _step + 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 += _step + pad_count -= 1 + while i > 0 and write_count < size - 1: + i -= 1 + ptr[0] = temp[i] + write_count += 1 + ptr += _step + 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 += _step + pad_count -= 1 + elif c.Deref(fmt) == 102 or c.Deref(fmt) == 70: + f_upper: t.CInt = 1 if c.Deref(fmt) == 70 else 0 + if precision < 0: precision = 6 + fv: t.CDouble = va_arg(ap, t.CDouble) + f_sp: t.CInt = _check_special_float(fv) + if f_sp != 0: + f_sgn_len: t.CInt = 0 + if f_sp == 2: + f_sgn_len = 1 + elif f_sp == 1 and show_sign: + f_sgn_len = 1 + elif f_sp == 1 and space_sign: + f_sgn_len = 1 + f_total_len: t.CInt = f_sgn_len + 3 + if not left_align and width > f_total_len: + f_pad: t.CInt = width - f_total_len + while f_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + f_pad -= 1 + if f_sp == 2: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif f_sp == 1 and show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif f_sp == 1 and space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + fi_c: t.CInt = 0 + while fi_c < 3 and write_count < size - 1: + fc: t.CInt = 0 + if f_sp == 3: + # nan + if fi_c == 0: + fc = 110 + elif fi_c == 1: + fc = 97 + else: + fc = 110 + else: + # inf (f_sp==1 +inf 或 f_sp==2 -inf) + if fi_c == 0: + fc = 105 + elif fi_c == 1: + fc = 110 + else: + fc = 102 + if f_upper and fc >= 97 and fc <= 122: + fc -= 32 + ptr[0] = t.CChar(fc) + write_count += 1 + ptr += _step + fi_c += 1 + if left_align and width > f_total_len: + f_pad = width - f_total_len + while f_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + f_pad -= 1 + fmt += 1 + continue + if fv < 0.0: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + fv = 0.0 - fv + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + di: t.CInt = 0 + work: t.CDouble = fv + if work < 1.0: + temp[0] = 48 + di = 1 + else: + scale: t.CDouble = 1.0 + while work >= scale * 10.0: + scale *= 10.0 + while scale >= 1.0 and di < TEMP_BUF_SIZE - 1: + d: t.CInt = t.CInt(work / scale) + if d > 9: d = 9 + temp[di] = t.CChar(d + 48) + di += 1 + work = work - t.CDouble(d) * scale + scale /= 10.0 + frac_val: t.CDouble = work + p: t.CInt = 0 + while p < precision: + frac_val *= 10.0 + p += 1 + frac_part: t.CUInt64T = t.CUInt64T(frac_val + 0.5) + 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 += _step + 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 += _step + pad_count -= 1 + while di > 0 and write_count < size - 1: + di -= 1 + ptr[0] = temp[di] + write_count += 1 + ptr += _step + if precision > 0: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + 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 < precision and fi < TEMP_BUF_SIZE - 1: + temp[fi] = 48 + fi += 1 + while fi > 0 and write_count < size - 1: + fi -= 1 + ptr[0] = temp[fi] + write_count += 1 + ptr += _step + elif alt_form: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + 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 += _step + pad_count -= 1 + elif c.Deref(fmt) == 101 or c.Deref(fmt) == 69: + if precision < 0: precision = 6 + fv: t.CDouble = va_arg(ap, t.CDouble) + e_upper: t.CInt = 1 if c.Deref(fmt) == 69 else 0 + e_sp: t.CInt = _check_special_float(fv) + if e_sp != 0: + e_sgn_len: t.CInt = 0 + if e_sp == 2: + e_sgn_len = 1 + elif e_sp == 1 and show_sign: + e_sgn_len = 1 + elif e_sp == 1 and space_sign: + e_sgn_len = 1 + e_total_len: t.CInt = e_sgn_len + 3 + if not left_align and width > e_total_len: + e_pad: t.CInt = width - e_total_len + while e_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + e_pad -= 1 + if e_sp == 2: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif e_sp == 1 and show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif e_sp == 1 and space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + ei_c: t.CInt = 0 + while ei_c < 3 and write_count < size - 1: + ec: t.CInt = 0 + if e_sp == 3: + # nan + if ei_c == 0: + ec = 110 + elif ei_c == 1: + ec = 97 + else: + ec = 110 + else: + # inf (e_sp==1 +inf 或 e_sp==2 -inf) + if ei_c == 0: + ec = 105 + elif ei_c == 1: + ec = 110 + else: + ec = 102 + if e_upper and ec >= 97 and ec <= 122: + ec -= 32 + ptr[0] = t.CChar(ec) + write_count += 1 + ptr += _step + ei_c += 1 + if left_align and width > e_total_len: + e_pad = width - e_total_len + while e_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + e_pad -= 1 + fmt += 1 + continue + if fv < 0.0: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + fv = 0.0 - fv + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + exp10: t.CInt = 0 + if fv != 0.0: + while fv >= 10.0: + fv /= 10.0 + exp10 += 1 + while fv < 1.0: + fv *= 10.0 + exp10 -= 1 + int_digit: t.CInt = t.CInt(fv) + if int_digit > 9: int_digit = 9 + if int_digit < 0: int_digit = 0 + frac_v: t.CDouble = fv - t.CDouble(int_digit) + p: t.CInt = 0 + while p < precision: + frac_v *= 10.0 + p += 1 + frac_p: t.CUInt64T = t.CUInt64T(frac_v + 0.5) + carry: t.CUInt64T = 1 + p = 0 + while p < precision: + carry *= 10 + p += 1 + if frac_p >= carry and carry > 0: + frac_p = 0 + int_digit += 1 + if int_digit > 9: + int_digit = 1 + exp10 += 1 + e_total: t.CInt = 1 + (precision + 1 if precision > 0 else 0) + 4 + if not left_align and not pad_zero and width > e_total: + pad_count = width - e_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > e_total: + pad_count = width - e_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + if write_count < size - 1: + ptr[0] = t.CChar(int_digit + 48) + write_count += 1 + ptr += _step + if precision > 0: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + fi: t.CInt = 0 + while fi < precision and fi < TEMP_BUF_SIZE - 1: + temp[fi] = t.CChar(frac_p % 10 + 48) + fi += 1 + frac_p //= 10 + while fi < precision and fi < TEMP_BUF_SIZE - 1: + temp[fi] = 48 + fi += 1 + while fi > 0 and write_count < size - 1: + fi -= 1 + ptr[0] = temp[fi] + write_count += 1 + ptr += _step + elif alt_form: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 101 if e_upper == 0 else 69 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 45 if exp10 < 0 else 43 + write_count += 1 + ptr += _step + exp_abs: t.CUInt64T = t.CUInt64T(exp10) if exp10 >= 0 else t.CUInt64T(0 - exp10) + ei: t.CInt = 0 + if exp_abs == 0: + temp[0] = 48 + temp[1] = 48 + ei = 2 + else: + while exp_abs > 0 and ei < TEMP_BUF_SIZE - 1: + temp[ei] = t.CChar(exp_abs % 10 + 48) + ei += 1 + exp_abs //= 10 + while ei < 2: + temp[ei] = 48 + ei += 1 + while ei > 0 and write_count < size - 1: + ei -= 1 + ptr[0] = temp[ei] + write_count += 1 + ptr += _step + if left_align and width > e_total: + pad_count = width - e_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 103 or c.Deref(fmt) == 71: + if precision < 0: precision = 6 + if precision == 0: precision = 1 + fv: t.CDouble = va_arg(ap, t.CDouble) + g_upper: t.CInt = 1 if c.Deref(fmt) == 71 else 0 + g_sp: t.CInt = _check_special_float(fv) + if g_sp != 0: + g_sgn_len: t.CInt = 0 + if g_sp == 2: + g_sgn_len = 1 + elif g_sp == 1 and show_sign: + g_sgn_len = 1 + elif g_sp == 1 and space_sign: + g_sgn_len = 1 + g_total_len: t.CInt = g_sgn_len + 3 + if not left_align and width > g_total_len: + g_pad: t.CInt = width - g_total_len + while g_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + g_pad -= 1 + if g_sp == 2: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif g_sp == 1 and show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif g_sp == 1 and space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + gi_c: t.CInt = 0 + while gi_c < 3 and write_count < size - 1: + gc: t.CInt = 0 + if g_sp == 3: + # nan + if gi_c == 0: + gc = 110 + elif gi_c == 1: + gc = 97 + else: + gc = 110 + else: + # inf (g_sp==1 +inf 或 g_sp==2 -inf) + if gi_c == 0: + gc = 105 + elif gi_c == 1: + gc = 110 + else: + gc = 102 + if g_upper and gc >= 97 and gc <= 122: + gc -= 32 + ptr[0] = t.CChar(gc) + write_count += 1 + ptr += _step + gi_c += 1 + if left_align and width > g_total_len: + g_pad = width - g_total_len + while g_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + g_pad -= 1 + fmt += 1 + continue + if fv < 0.0: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + fv = 0.0 - fv + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + fv_orig: t.CDouble = fv + exp10: t.CInt = 0 + if fv != 0.0: + while fv >= 10.0: + fv /= 10.0 + exp10 += 1 + while fv < 1.0: + fv *= 10.0 + exp10 -= 1 + g_use_e: t.CInt = 0 + if exp10 < -4 or exp10 >= precision: + g_use_e = 1 + g_len: t.CInt = 0 + if g_use_e: + int_digit: t.CInt = t.CInt(fv) + if int_digit > 9: int_digit = 9 + if int_digit < 0: int_digit = 0 + frac_v: t.CDouble = fv - t.CDouble(int_digit) + prec_e: t.CInt = precision - 1 + p: t.CInt = 0 + while p < prec_e: + frac_v *= 10.0 + p += 1 + frac_p: t.CUInt64T = t.CUInt64T(frac_v + 0.5) + carry: t.CUInt64T = 1 + p = 0 + while p < prec_e: + carry *= 10 + p += 1 + if frac_p >= carry and carry > 0: + frac_p = 0 + int_digit += 1 + if int_digit > 9: + int_digit = 1 + exp10 += 1 + temp[0] = t.CChar(int_digit + 48) + g_len = 1 + if prec_e > 0: + temp[1] = 46 + g_len = 2 + # 小数位逆序存入(个位放 g_len+prec_e-1),temp 直接为正序。 + # 原交换反转循环在 TPV 编译产物中失效(小数位未反转,如 456->654), + # 改逆序存储,与 %f 的倒序输出一致,绕开三变量交换。 + fi: t.CInt = 0 + fp_inv: t.CUInt64T = frac_p + fp_idx: t.CInt = g_len + prec_e - 1 + while fi < prec_e and fp_idx < TEMP_BUF_SIZE - 1: + temp[fp_idx] = t.CChar(fp_inv % 10 + 48) + fp_idx -= 1 + fp_inv //= 10 + fi += 1 + g_len += prec_e + else: + prec_f: t.CInt = precision - 1 - exp10 + if prec_f < 0: prec_f = 0 + work: t.CDouble = fv_orig + if work < 1.0: + temp[0] = 48 + g_len = 1 + else: + scale: t.CDouble = 1.0 + while work >= scale * 10.0: + scale *= 10.0 + while scale >= 1.0 and g_len < TEMP_BUF_SIZE - 1: + d: t.CInt = t.CInt(work / scale) + if d > 9: d = 9 + temp[g_len] = t.CChar(d + 48) + g_len += 1 + work = work - t.CDouble(d) * scale + scale /= 10.0 + if prec_f > 0 and g_len < TEMP_BUF_SIZE - 1: + temp[g_len] = 46 + g_len += 1 + frac_val: t.CDouble = work + p = 0 + while p < prec_f: + frac_val *= 10.0 + p += 1 + frac_part: t.CUInt64T = t.CUInt64T(frac_val + 0.5) + # 小数位逆序存入(个位放 g_len+prec_f-1),temp 直接为正序。 + # 原交换反转循环在 TPV 编译产物中失效(小数位未反转,如 456->654), + # 改逆序存储,与 %f 的倒序输出一致,绕开三变量交换。 + fi = 0 + fp_inv: t.CUInt64T = frac_part + fp_idx: t.CInt = g_len + prec_f - 1 + while fi < prec_f and fp_idx < TEMP_BUF_SIZE - 1: + temp[fp_idx] = t.CChar(fp_inv % 10 + 48) + fp_idx -= 1 + fp_inv //= 10 + fi += 1 + g_len += prec_f + if not alt_form and g_len > 0: + while g_len > 0: + if temp[g_len - 1] == 48: + g_len -= 1 + else: + break + if g_len > 0 and temp[g_len - 1] == 46: + g_len -= 1 + g_total: t.CInt = g_len + if g_use_e: g_total = g_len + 4 + if not left_align and not pad_zero and width > g_total: + pad_count = width - g_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + if pad_zero and width > g_total: + pad_count = width - g_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + pad_count -= 1 + gi: t.CInt = 0 + while gi < g_len and write_count < size - 1: + ptr[0] = temp[gi] + write_count += 1 + ptr += _step + gi += 1 + if g_use_e: + if write_count < size - 1: + ptr[0] = 101 if g_upper == 0 else 69 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = 45 if exp10 < 0 else 43 + write_count += 1 + ptr += _step + exp_abs: t.CUInt64T = t.CUInt64T(exp10) if exp10 >= 0 else t.CUInt64T(0 - exp10) + ei: t.CInt = 0 + if exp_abs == 0: + temp[0] = 48 + temp[1] = 48 + ei = 2 + else: + while exp_abs > 0 and ei < TEMP_BUF_SIZE - 1: + temp[ei] = t.CChar(exp_abs % 10 + 48) + ei += 1 + exp_abs //= 10 + while ei < 2: + temp[ei] = 48 + ei += 1 + while ei > 0 and write_count < size - 1: + ei -= 1 + ptr[0] = temp[ei] + write_count += 1 + ptr += _step + if left_align and width > g_total: + pad_count = width - g_total + while pad_count > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + pad_count -= 1 + elif c.Deref(fmt) == 97 or c.Deref(fmt) == 65: + a_upper: t.CInt = 1 if c.Deref(fmt) == 65 else 0 + fv: t.CDouble = va_arg(ap, t.CDouble) + a_sp: t.CInt = _check_special_float(fv) + if a_sp != 0: + a_sgn_len: t.CInt = 0 + if a_sp == 2: + a_sgn_len = 1 + elif a_sp == 1 and show_sign: + a_sgn_len = 1 + elif a_sp == 1 and space_sign: + a_sgn_len = 1 + a_total_len: t.CInt = a_sgn_len + 3 + if not left_align and width > a_total_len: + a_pad: t.CInt = width - a_total_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + a_pad -= 1 + if a_sp == 2: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif a_sp == 1 and show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif a_sp == 1 and space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + ai_c: t.CInt = 0 + while ai_c < 3 and write_count < size - 1: + ac: t.CInt = 0 + if a_sp == 3: + # nan + if ai_c == 0: + ac = 110 + elif ai_c == 1: + ac = 97 + else: + ac = 110 + else: + # inf (a_sp==1 +inf 或 a_sp==2 -inf) + if ai_c == 0: + ac = 105 + elif ai_c == 1: + ac = 110 + else: + ac = 102 + if a_upper and ac >= 97 and ac <= 122: + ac -= 32 + ptr[0] = t.CChar(ac) + write_count += 1 + ptr += _step + ai_c += 1 + if left_align and width > a_total_len: + a_pad = width - a_total_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + a_pad -= 1 + fmt += 1 + continue + fbits: t.CUInt64T = 0 + c.Load(c.Addr(fbits), c.Addr(fv)) + a_neg: t.CInt = 1 if (fbits >> 63) != 0 else 0 + a_exp: t.CInt = t.CInt((fbits >> 52) & 0x7FF) + a_frac: t.CUInt64T = fbits & 0x000FFFFFFFFFFFFF + a_leading: t.CInt = 0 + a_binexp: t.CInt = 0 + if a_exp == 0: + a_leading = 0 + if a_frac == 0: + a_binexp = 0 + else: + a_binexp = -1022 + else: + a_leading = 1 + a_binexp = a_exp - 1023 + a_prec: t.CInt = precision + if a_prec < 0: + a_prec = 13 + if a_prec > 50: + a_prec = 50 + a_hi: t.CInt = 0 + while a_hi < 13 and a_hi < a_prec: + a_digit: t.CInt = t.CInt((a_frac >> (48 - 4 * a_hi)) & 0xF) + if a_digit < 10: + temp[a_hi] = t.CChar(a_digit + 48) + else: + if a_upper: + temp[a_hi] = t.CChar(a_digit - 10 + 65) + else: + temp[a_hi] = t.CChar(a_digit - 10 + 97) + a_hi += 1 + while a_hi < a_prec: + temp[a_hi] = 48 + a_hi += 1 + a_hd_count: t.CInt = a_prec + if precision < 0: + while a_hd_count > 0 and temp[a_hd_count - 1] == 48: + a_hd_count -= 1 + a_has_dot: t.CInt = 0 + if a_hd_count > 0: + a_has_dot = 1 + elif alt_form: + a_has_dot = 1 + a_eb: t.CInt = a_binexp + a_esign: t.CInt = 0 + if a_binexp < 0: + a_esign = 1 + a_eb = -a_binexp + a_ei: t.CInt = 0 + if a_eb == 0: + temp[60] = 48 + a_ei = 1 + else: + while a_eb > 0 and a_ei < 7: + temp[60 + a_ei] = t.CChar(a_eb % 10 + 48) + a_ei += 1 + a_eb //= 10 + a_ecount: t.CInt = a_ei + a_sign_len: t.CInt = 0 + if a_neg: + a_sign_len = 1 + elif show_sign: + a_sign_len = 1 + elif space_sign: + a_sign_len = 1 + a_content_len: t.CInt = a_sign_len + 2 + 1 + a_has_dot + a_hd_count + 1 + 1 + a_ecount + if not left_align and not pad_zero and width > a_content_len: + a_pad = width - a_content_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + a_pad -= 1 + if a_neg: + if write_count < size - 1: + ptr[0] = 45 + write_count += 1 + ptr += _step + elif show_sign: + if write_count < size - 1: + ptr[0] = 43 + write_count += 1 + ptr += _step + elif space_sign: + if write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + if pad_zero and width > a_content_len: + a_pad = width - a_content_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + a_pad -= 1 + if write_count < size - 1: + ptr[0] = 48 + write_count += 1 + ptr += _step + if write_count < size - 1: + if a_upper: + ptr[0] = 88 + else: + ptr[0] = 120 + write_count += 1 + ptr += _step + if write_count < size - 1: + ptr[0] = t.CChar(a_leading + 48) + write_count += 1 + ptr += _step + if a_has_dot: + if write_count < size - 1: + ptr[0] = 46 + write_count += 1 + ptr += _step + a_hj: t.CInt = 0 + while a_hj < a_hd_count and write_count < size - 1: + ptr[0] = temp[a_hj] + write_count += 1 + ptr += _step + a_hj += 1 + if write_count < size - 1: + if a_upper: + ptr[0] = 80 + else: + ptr[0] = 112 + write_count += 1 + ptr += _step + if write_count < size - 1: + if a_esign: + ptr[0] = 45 + else: + ptr[0] = 43 + write_count += 1 + ptr += _step + a_ek: t.CInt = a_ecount + while a_ek > 0 and write_count < size - 1: + a_ek -= 1 + ptr[0] = temp[60 + a_ek] + write_count += 1 + ptr += _step + if left_align and width > a_content_len: + a_pad = width - a_content_len + while a_pad > 0 and write_count < size - 1: + ptr[0] = 32 + write_count += 1 + ptr += _step + a_pad -= 1 + elif c.Deref(fmt) == 110: + if is_long_long or is_long: + np: t.CInt64T | t.CPtr = va_arg(ap, t.CInt64T | t.CPtr) + if np != None: + np[0] = t.CInt64T(write_count) + elif is_short: + sp: t.CShort | t.CPtr = va_arg(ap, t.CShort | t.CPtr) + if sp != None: + sp[0] = t.CShort(write_count) + elif is_char: + cp: t.CChar | t.CPtr = va_arg(ap, t.CChar | t.CPtr) + if cp != None: + cp[0] = t.CChar(write_count) + else: + ip: t.CInt | t.CPtr = va_arg(ap, t.CInt | t.CPtr) + if ip != None: + ip[0] = write_count + elif c.Deref(fmt) == 37: + if write_count < size - 1: + ptr[0] = 37 + write_count += 1 + ptr += _step + else: + if write_count < size - 1: + ptr[0] = c.Deref(fmt) + write_count += 1 + ptr += _step + fmt += 1 + ptr[0] = 0 + return write_count diff --git a/vipermath.vp b/vipermath.vp new file mode 100644 index 0000000..b121af1 --- /dev/null +++ b/vipermath.vp @@ -0,0 +1,544 @@ +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(a, b) = a = b:a 为 c.Deref(iptr) 左值表达式 → *iptr = int_part + # TPV 的 c.Deref 立即 load 返回右值,故 c.Set 需识别 Deref 左值形态(translate_c_set 形态 1) + 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/vipersimd.vp b/vipersimd.vp new file mode 100644 index 0000000..e567495 --- /dev/null +++ b/vipersimd.vp @@ -0,0 +1,492 @@ +import t, c + + +# ============================================================ +# AVX2 double precision vector operations (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 single precision vector operations (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']) + + +# ============================================================ +# Batch array operations (AVX2 loop, process N double values) +# ============================================================ + +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_neg_array(a: t.CPtr, out: t.CPtr, n: t.CSizeT) -> t.CVoid: + """AVX2 batch: out[i:i+4] = -a[i:i+4] (flip sign bit via XOR)""" + 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 .Lneg_end +.Lneg_loop: +vmovupd ymm0, [r8] +vxorpd ymm0, ymm0, ymm2 +vmovupd [r10], ymm0 +add r8, 32 +add r10, 32 +dec rcx +jnz .Lneg_loop +.Lneg_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 precise scalar operations (LLVM intrinsic functions) +# ============================================================ + +def simd_sqrt(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: sqrt(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.sqrt.f64(double {c.LInp(x)})") + return out + + +def simd_fabs(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: |x|""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.fabs.f64(double {c.LInp(x)})") + return out + + +def simd_floor(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: floor(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.floor.f64(double {c.LInp(x)})") + return out + + +def simd_ceil(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: ceil(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.ceil.f64(double {c.LInp(x)})") + return out + + +def simd_round(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: round(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.round.f64(double {c.LInp(x)})") + return out + + +def simd_trunc(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: trunc(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.trunc.f64(double {c.LInp(x)})") + return out + + +def simd_fma(a: t.CDouble, b: t.CDouble, c_val: t.CDouble) -> t.CDouble: + """LLVM intrinsic: a*b + c (single rounding)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.fma.f64(double {c.LInp(a)}, double {c.LInp(b)}, double {c.LInp(c_val)})") + return out + + +def simd_copysign(mag: t.CDouble, sign: t.CDouble) -> t.CDouble: + """LLVM intrinsic: copysign(mag, sign)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.copysign.f64(double {c.LInp(mag)}, double {c.LInp(sign)})") + return out + + +def simd_neg(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: -x (via copysign, correct for negative/-0.0/NaN inputs) + + copysign(x, -1.0) is wrong for x < 0 (returns -|x| instead of +|x|). + copysign(x, -x) = |x| * sign(-x) = -x is correct for all IEEE 754 values. + """ + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.copysign.f64(double {c.LInp(x)}, double {c.LInp(t.CDouble(0.0) - x)})") + return out + + +def simd_minnum(a: t.CDouble, b: t.CDouble) -> t.CDouble: + """LLVM intrinsic: min(a, b) (NaN-aware)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.minnum.f64(double {c.LInp(a)}, double {c.LInp(b)})") + return out + + +def simd_maxnum(a: t.CDouble, b: t.CDouble) -> t.CDouble: + """LLVM intrinsic: max(a, b) (NaN-aware)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.maxnum.f64(double {c.LInp(a)}, double {c.LInp(b)})") + return out + + +def simd_exp(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: e^x""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.exp.f64(double {c.LInp(x)})") + return out + + +def simd_log(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: ln(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.log.f64(double {c.LInp(x)})") + return out + + +def simd_sin(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: sin(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.sin.f64(double {c.LInp(x)})") + return out + + +def simd_cos(x: t.CDouble) -> t.CDouble: + """LLVM intrinsic: cos(x)""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.cos.f64(double {c.LInp(x)})") + return out + + +def simd_pow(x: t.CDouble, y: t.CDouble) -> t.CDouble: + """LLVM intrinsic: x^y""" + out: t.CDouble + c.LLVMIR(f"{c.LOut(out)} = call double @llvm.pow.f64(double {c.LInp(x)}, double {c.LInp(y)})") + return out diff --git a/viperstring.vp b/viperstring.vp new file mode 100644 index 0000000..212d749 --- /dev/null +++ b/viperstring.vp @@ -0,0 +1 @@ +from .string import * diff --git a/vqt6 copy/CMakeLists.txt b/vqt6 copy/CMakeLists.txt new file mode 100644 index 0000000..d08d121 --- /dev/null +++ b/vqt6 copy/CMakeLists.txt @@ -0,0 +1,110 @@ +# ============================================================ +# vqt6 CMakeLists.txt — 构建 vqt6 C 桥接层 +# +# 默认产物: libvqt6_bridge.a (静态库) +# 可选产物: vqt6_bridge.dll (动态库) +# +# 使用: +# cmake -B build -S . +# cmake --build build --config Release +# ============================================================ + +cmake_minimum_required(VERSION 3.16) +project(vqt6_bridge CXX C) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_AUTOMOC ON) + +# 构建选项 +option(VQT6_BUILD_SHARED "Build vqt6 as shared library (DLL)" OFF) +option(VQT6_BUILD_STATIC "Build vqt6 as static library" ON) +option(VQT6_BUILD_EXAMPLES "Build example programs" OFF) + +# Qt6 依赖 +find_package(Qt6 6.5 REQUIRED COMPONENTS + Core + Gui + Widgets + Network +) + +# Win32 GUI 应用不需要控制台 +if(WIN32) + set(CMAKE_WIN32_EXECUTABLE OFF) +endif() + +# 公共源文件 +set(VQT6_SOURCES + _bridge_core.cpp + _bridge_widgets.cpp + _bridge_gui.cpp + _bridge_network.cpp +) + +set(VQT6_HEADERS + _bridge.h + _bridge_widgets.h + _bridge_gui.h + _bridge_network.h +) + +# Qt 模块 +set(VQT6_QT_MODULES + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::Network +) + +# ============================================================ +# 静态库 +# ============================================================ +if(VQT6_BUILD_STATIC) + add_library(vqt6_bridge_static STATIC ${VQT6_SOURCES} ${VQT6_HEADERS}) + target_link_libraries(vqt6_bridge_static PUBLIC ${VQT6_QT_MODULES}) + target_compile_definitions(vqt6_bridge_static PUBLIC VQT6_BRIDGE_STATIC) + target_include_directories(vqt6_bridge_static PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + set_target_properties(vqt6_bridge_static PROPERTIES + OUTPUT_NAME vqt6_bridge + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + ) +endif() + +# ============================================================ +# 动态库 +# ============================================================ +if(VQT6_BUILD_SHARED) + add_library(vqt6_bridge SHARED ${VQT6_SOURCES} ${VQT6_HEADERS}) + target_link_libraries(vqt6_bridge PUBLIC ${VQT6_QT_MODULES}) + target_compile_definitions(vqt6_bridge PRIVATE VQT6_BRIDGE_BUILD) + target_include_directories(vqt6_bridge PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + set_target_properties(vqt6_bridge PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + ) +endif() + +# ============================================================ +# 安装 +# ============================================================ +install(TARGETS vqt6_bridge_static vqt6_bridge + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +install(FILES ${VQT6_HEADERS} + DESTINATION include/vqt6 +) + +# ============================================================ +# 示例 +# ============================================================ +if(VQT6_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/vqt6 copy/README.md b/vqt6 copy/README.md new file mode 100644 index 0000000..eba4e88 --- /dev/null +++ b/vqt6 copy/README.md @@ -0,0 +1,90 @@ +# vqt6 — Viper 的 Qt6 绑定包 + +`vqt6` 是 [Viper](https://git.gvsds.com/GVSDS/TransPyC) 语言的 **Qt6 GUI 框架绑定**,是 Viper 包管理器分发的"包"(类似于 Python 的 PyQt6、Node.js 的 node-gtk)。 + +> 注意:`vqt6` **不是** 包管理器,而是一个**被包管理器管理的包**(库)。 +> 包管理器负责下载、预编译、安装;`vqt6` 只负责把 Qt6 C++ API 暴露给 Viper 代码。 + +## 架构 + +``` ++--------------------+ +-----------------------+ +------------+ +| Viper 用户代码 | FFI | vqt6 桥接层 (libvqt6) | C++ | Qt6 C++ | +| (app.vp) | <----> | - t.State 声明 | <-----> | QtCore | +| | | - C 桥接函数 | | QtGui | +| vqt6.QApplication | | (extern "C") | | QtWidgets | +| vqt6.QLabel | | - 静态库 / 动态库 | | QtNetwork | ++--------------------+ +-----------------------+ +------------+ +``` + +**FFI 路径**: +1. Viper 编译器把 `t.State` 声明的 `def xxx() -> t.State: pass` 解析为外部函数符号 +2. 链接时通过 `libvqt6_bridge.a`(静态)或 `vqt6_bridge.dll`(动态)解析符号 +3. 运行时 C 桥接层调用 Qt6 C++ API 完成实际工作 + +## 链接模式 + +| 模式 | 产物 | 优点 | 缺点 | +|------|------|------|------| +| **静态**(默认) | `libvqt6_bridge.a` | 部署简单(一个 exe),无需分发 dll | exe 体积较大 | +| **动态** | `vqt6_bridge.dll` | 共享内存,多个程序共用 | 需随 exe 分发 dll | + +vqt6 同一套 C 桥接源代码,可同时编译为两种产物。Viper 项目通过 `project.vpj` 切换。 + +## 目录结构 + +``` +includes/vqt6/ +├── README.md # 本文件 +├── __init__.vp # 公共 Pythonic API(用户使用) +├── _types.vp # 公共类型(不透明指针 typedef) +├── _qtcore.vp # QtCore 的 t.State FFI 声明 +├── _qtwidgets.vp # QtWidgets 的 t.State FFI 声明 +├── _qtgui.vp # QtGui 的 t.State FFI 声明 +├── _qtnetwork.vp # QtNetwork 的 t.State FFI 声明 +├── _bridge.h # C 桥接层头文件 +├── _bridge.cpp # C 桥接层实现(extern "C" 包装 Qt6 C++ API) +└── CMakeLists.txt # 构建脚本(生成 libvqt6_bridge.a) +``` + +## 使用示例 + +```python +# App/main.vp +import t +import c +import vqt6 + +# 1. 创建 QApplication +app: vqt6.QApplication | t.CPtr = vqt6.QApplication([]) + +# 2. 创建窗口 +window: vqt6.QWidget | t.CPtr = vqt6.QWidget() +window.setWindowTitle("vqt6 Hello") +window.resize(400, 300) + +# 3. 创建标签 +label: vqt6.QLabel | t.CPtr = vqt6.QLabel("你好,Viper!", window) +label.move(50, 50) + +# 4. 显示并进入事件循环 +window.show() +app.exec() +``` + +## 设计原则 + +1. **不透明指针**:Viper 端不直接操作 Qt6 C++ 类(`QWidget*`、`QString*` 等),所有操作通过 C 桥接函数 `vqt6_xxx()` 转发。 +2. **t.State 声明**:所有 FFI 函数返回 `t.State`,C 桥接层函数实现负责实际操作。 +3. **句柄化对象模型**:Viper 端的对象是 `t.CPtr`(不透明指针),C 端管理生命周期(构造函数/析构函数)。 +4. **跨平台**:同一套 C 桥接代码可在 Windows / Linux / macOS 编译(差异在 Qt6 安装路径)。 + +## 当前状态 + +- [x] 架构设计 +- [x] FFI 覆盖:QtCore / QtWidgets / QtGui / QtNetwork +- [x] FFI 粒度:仅暴露 C 桥接函数 +- [ ] FFI 声明文件编写中 +- [ ] C 桥接层实现 +- [ ] CMakeLists.txt 构建脚本 +- [ ] Hello World 示例验证 diff --git a/vqt6 copy/__init__.vp b/vqt6 copy/__init__.vp new file mode 100644 index 0000000..16446c3 --- /dev/null +++ b/vqt6 copy/__init__.vp @@ -0,0 +1,208 @@ +# ============================================================ +# vqt6 — Viper 的 Qt6 绑定包 +# +# 公共 Pythonic API(基于 C 桥接层) +# 用户用法: +# import vqt6 +# app = vqt6.QApplication([]) +# win = vqt6.QWidget() +# win.setWindowTitle("Hello") +# win.show() +# app.exec() +# ============================================================ + +import t +from stdint import * +from vqt6._types import * +from vqt6._qtcore import * +from vqt6._qtwidgets import * +from vqt6._qtgui import * +from vqt6._qtnetwork import * + + +# ============================================================ +# 高级 API 类(Pythonic 包装,不透明指针) +# ============================================================ +@t.NoVTable +class QApplication: + """QApplication 包装(不透明指针)""" + _ptr: QtAppPtr + + def __init__(self, argv: list[str] | t.CPtr): + # 把 argv 转换为 argc/argv 数组 + argc: t.CInt = 1 + # Viper 端 argv 是 c_char_p 指针数组 + # 这里仅传空 argv,避免 C ABI 复杂性 + argv_ptr: t.CPtr = t.CPtr(0) + self._ptr = vqt6_qapplication_create(argc, argv_ptr) + if self._ptr is None: + raise RuntimeError("Failed to create QApplication") + + def exec(self) -> int: + return vqt6_qapplication_exec(self._ptr) + + def quit(self): + vqt6_qapplication_quit(self._ptr) + + def exit(self, code: int): + vqt6_qapplication_exit(self._ptr, code) + + def process_events(self): + vqt6_qapplication_process_events(self._ptr) + + def desktop_width(self) -> int: + return vqt6_qapplication_desktop_width(self._ptr) + + def desktop_height(self) -> int: + return vqt6_qapplication_desktop_height(self._ptr) + + +@t.NoVTable +class QWidget: + """QWidget 包装""" + _ptr: QtWidgetPtr + + def __init__(self, parent: "QWidget | None" = None): + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qwidget_create_with_parent(parent._ptr) + else: + self._ptr = vqt6_qwidget_create() + if self._ptr is None: + raise RuntimeError("Failed to create QWidget") + + def show(self): + vqt6_qwidget_show(self._ptr) + + def hide(self): + vqt6_qwidget_hide(self._ptr) + + def close(self) -> int: + return vqt6_qwidget_close(self._ptr) + + def setWindowTitle(self, title: str): + title_qs: QtStringPtr = vqt6_qstring_create(title) + vqt6_qwidget_set_window_title(self._ptr, title_qs) + vqt6_qstring_free(title_qs) + + def windowTitle(self) -> str: + result: QtStringPtr = vqt6_qwidget_window_title(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def resize(self, w: int, h: int): + vqt6_qwidget_resize(self._ptr, w, h) + + def move(self, x: int, y: int): + vqt6_qwidget_move(self._ptr, x, y) + + def setGeometry(self, x: int, y: int, w: int, h: int): + vqt6_qwidget_set_geometry(self._ptr, x, y, w, h) + + def setEnabled(self, enabled: int): + vqt6_qwidget_set_enabled(self._ptr, enabled) + + def setVisible(self, visible: int): + vqt6_qwidget_set_visible(self._ptr, visible) + + def isVisible(self) -> int: + return vqt6_qwidget_is_visible(self._ptr) + + def setToolTip(self, tip: str): + tip_qs: QtStringPtr = vqt6_qstring_create(tip) + vqt6_qwidget_set_tool_tip(self._ptr, tip_qs) + vqt6_qstring_free(tip_qs) + + +@t.NoVTable +class QLabel: + """QLabel 包装""" + _ptr: QtLabelPtr + + def __init__(self, text: str = "", parent: "QWidget | None" = None): + text_qs: QtStringPtr = vqt6_qstring_create(text) + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qlabel_create_with_text_parent(text_qs, parent._ptr) + elif text_qs is not None: + self._ptr = vqt6_qlabel_create_with_text(text_qs) + else: + self._ptr = vqt6_qlabel_create() + vqt6_qstring_free(text_qs) + if self._ptr is None: + raise RuntimeError("Failed to create QLabel") + + def setText(self, text: str): + text_qs: QtStringPtr = vqt6_qstring_create(text) + vqt6_qlabel_set_text(self._ptr, text_qs) + vqt6_qstring_free(text_qs) + + def text(self) -> str: + result: QtStringPtr = vqt6_qlabel_text(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def setAlignment(self, alignment: int): + vqt6_qlabel_set_alignment(self._ptr, alignment) + + +@t.NoVTable +class QPushButton: + """QPushButton 包装""" + _ptr: QtPushButtonPtr + + def __init__(self, text: str = "", parent: "QWidget | None" = None): + text_qs: QtStringPtr = vqt6_qstring_create(text) + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qpushbutton_create_with_text_parent(text_qs, parent._ptr) + elif text_qs is not None: + self._ptr = vqt6_qpushbutton_create_with_text(text_qs) + else: + self._ptr = vqt6_qpushbutton_create() + vqt6_qstring_free(text_qs) + if self._ptr is None: + raise RuntimeError("Failed to create QPushButton") + + def setText(self, text: str): + text_qs: QtStringPtr = vqt6_qstring_create(text) + vqt6_qpushbutton_set_text(self._ptr, text_qs) + vqt6_qstring_free(text_qs) + + def text(self) -> str: + result: QtStringPtr = vqt6_qpushbutton_text(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def click(self): + vqt6_qpushbutton_click(self._ptr) + + def setEnabled(self, enabled: int): + vqt6_qwidget_set_enabled(self._ptr, enabled) + + +# ============================================================ +# 模块导出 +# ============================================================ +__all__ = [ + # 高层类 + "QApplication", "QWidget", "QLabel", "QPushButton", + # 类型 + "QtObjectPtr", "QtStringPtr", "QtByteArrayPtr", "QtWidgetPtr", "QtAppPtr", + "QtLabelPtr", "QtPushButtonPtr", + "QtColorPtr", "QtFontPtr", "QtPixmapPtr", "QtImagePtr", "QtPainterPtr", + "QtTcpSocketPtr", "QtHostAddressPtr", "QtNetworkRequestPtr", "QtNetworkReplyPtr", + # 常量 + "QT_KEY_ESCAPE", "QT_KEY_RETURN", "QT_KEY_A", "QT_KEY_Z", + "QT_LEFT_BUTTON", "QT_RIGHT_BUTTON", "QT_MID_BUTTON", + "QT_HORIZONTAL", "QT_VERTICAL", + "QT_ALIGN_LEFT", "QT_ALIGN_CENTER", "QT_ALIGN_RIGHT", + "QT_PORT_HTTP", "QT_PORT_HTTPS", "QT_PORT_FTP", + "QT_OK", "QT_CANCEL", "QT_YES", "QT_NO", "QT_CLOSE", +] diff --git a/vqt6 copy/_bridge.h b/vqt6 copy/_bridge.h new file mode 100644 index 0000000..e573ea8 --- /dev/null +++ b/vqt6 copy/_bridge.h @@ -0,0 +1,151 @@ +// ============================================================ +// vqt6/_bridge.h — C 桥接层头文件 +// +// 作用: 把 Qt6 C++ API 包装成 extern "C" 函数,供 Viper FFI 调用 +// 编译: 作为静态库 libvqt6_bridge.a 或动态库 vqt6_bridge.dll +// ============================================================ + +#ifndef VQT6_BRIDGE_H +#define VQT6_BRIDGE_H + +#include +#include + +#if defined(_WIN32) +# if defined(VQT6_BRIDGE_STATIC) +# define VQT6_API +# elif defined(VQT6_BRIDGE_BUILD) +# define VQT6_API __declspec(dllexport) +# else +# define VQT6_API __declspec(dllimport) +# endif +#else +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define VQT6_API __attribute__((visibility("default"))) +# else +# define VQT6_API +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QString +// ============================================================ +VQT6_API void* vqt6_qstring_create(const char* utf8); +VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size); +VQT6_API void vqt6_qstring_free(void* qstr); +VQT6_API int vqt6_qstring_length(void* qstr); +VQT6_API int vqt6_qstring_is_empty(void* qstr); +VQT6_API int vqt6_qstring_equals(void* qstr, void* other); +VQT6_API void* vqt6_qstring_append(void* qstr, void* other); + +// ============================================================ +// QByteArray +// ============================================================ +VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size); +VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size); +VQT6_API size_t vqt6_qbytearray_size(void* qba); +VQT6_API void vqt6_qbytearray_free(void* qba); + +// ============================================================ +// QObject +// ============================================================ +VQT6_API void vqt6_qobject_delete(void* obj); +VQT6_API void vqt6_qobject_delete_later(void* obj); +VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name); +VQT6_API void* vqt6_qobject_object_name(void* obj); +VQT6_API void vqt6_qobject_set_parent(void* child, void* parent); +VQT6_API void* vqt6_qobject_parent(void* obj); +VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name, + void* receiver, const char* slot_name); +VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name, + void* receiver, const char* slot_name); +VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter); +VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter); + +// ============================================================ +// QCoreApplication +// ============================================================ +VQT6_API void* vqt6_qcoreapp_create(const char* app_name); +VQT6_API void* vqt6_qcoreapp_instance(void); +VQT6_API int vqt6_qcoreapp_exec(void* app); +VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code); +VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code); +VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags); +VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event); +VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event); +VQT6_API void* vqt6_qcoreapp_organization_name(void* app); +VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name); +VQT6_API void* vqt6_qcoreapp_application_name(void* app); +VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name); + +// ============================================================ +// QTimer +// ============================================================ +VQT6_API void* vqt6_qtimer_create(void); +VQT6_API void* vqt6_qtimer_create_with_parent(void* parent); +VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms); +VQT6_API void vqt6_qtimer_stop(void* timer); +VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms); +VQT6_API int vqt6_qtimer_interval(void* timer); +VQT6_API int vqt6_qtimer_is_active(void* timer); +VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot); +VQT6_API int vqt6_qtimer_is_single_shot(void* timer); + +// ============================================================ +// QVariant +// ============================================================ +VQT6_API void* vqt6_qvariant_create_int(int value); +VQT6_API void* vqt6_qvariant_create_double(double value); +VQT6_API void* vqt6_qvariant_create_bool(int value); +VQT6_API void* vqt6_qvariant_create_string(void* s); +VQT6_API int vqt6_qvariant_to_int(void* v, int* ok); +VQT6_API double vqt6_qvariant_to_double(void* v, int* ok); +VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok); +VQT6_API void* vqt6_qvariant_to_string(void* v); +VQT6_API int vqt6_qvariant_type_id(void* v); +VQT6_API int vqt6_qvariant_is_valid(void* v); +VQT6_API void vqt6_qvariant_free(void* v); + +// ============================================================ +// QEvent +// ============================================================ +VQT6_API int vqt6_qevent_type(void* event); +VQT6_API void vqt6_qevent_accept(void* event); +VQT6_API void vqt6_qevent_ignore(void* event); +VQT6_API int vqt6_qevent_is_accepted(void* event); + +// ============================================================ +// QStringList +// ============================================================ +VQT6_API void* vqt6_qstringlist_create(void); +VQT6_API void vqt6_qstringlist_append(void* list, void* str); +VQT6_API int vqt6_qstringlist_size(void* list); +VQT6_API void* vqt6_qstringlist_at(void* list, int index); +VQT6_API void vqt6_qstringlist_free(void* list); + +// ============================================================ +// QByteArrayList +// ============================================================ +VQT6_API void* vqt6_qbytearraylist_create(void); +VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba); +VQT6_API int vqt6_qbytearraylist_size(void* list); +VQT6_API void* vqt6_qbytearraylist_at(void* list, int index); +VQT6_API void vqt6_qbytearraylist_free(void* list); + +// ============================================================ +// 全局回调注册表 +// ============================================================ +typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data); +VQT6_API void vqt6_register_slot(int slot_id, void* user_data); +VQT6_API void vqt6_unregister_slot(int slot_id); +VQT6_API void vqt6_trigger_slot(int slot_id); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_H diff --git a/vqt6 copy/_bridge_core.cpp b/vqt6 copy/_bridge_core.cpp new file mode 100644 index 0000000..3f420d8 --- /dev/null +++ b/vqt6 copy/_bridge_core.cpp @@ -0,0 +1,433 @@ +// ============================================================ +// vqt6/_bridge_core.cpp — QtCore C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 全局回调表(线程安全) +namespace { + QMutex g_slot_mutex; + QHash> g_slots; +} + +// ============================================================ +// QString +// ============================================================ +extern "C" VQT6_API void* vqt6_qstring_create(const char* utf8) { + if (utf8 == nullptr) return nullptr; + return new QString(QString::fromUtf8(utf8)); +} + +extern "C" VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size) { + if (qstr == nullptr || buf == nullptr || buf_size == 0) return 0; + QString* s = static_cast(qstr); + QByteArray ba = s->toUtf8(); + size_t len = static_cast(ba.size()); + if (len >= buf_size) len = buf_size - 1; + std::memcpy(buf, ba.constData(), len); + buf[len] = '\0'; + return len; +} + +extern "C" VQT6_API void vqt6_qstring_free(void* qstr) { + delete static_cast(qstr); +} + +extern "C" VQT6_API int vqt6_qstring_length(void* qstr) { + if (qstr == nullptr) return 0; + return static_cast(qstr)->length(); +} + +extern "C" VQT6_API int vqt6_qstring_is_empty(void* qstr) { + if (qstr == nullptr) return 1; + return static_cast(qstr)->isEmpty() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qstring_equals(void* qstr, void* other) { + if (qstr == nullptr || other == nullptr) return 0; + return *static_cast(qstr) == *static_cast(other) ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qstring_append(void* qstr, void* other) { + if (qstr == nullptr || other == nullptr) return nullptr; + return new QString(*static_cast(qstr) + *static_cast(other)); +} + +// ============================================================ +// QByteArray +// ============================================================ +extern "C" VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size) { + if (data == nullptr) return new QByteArray(); + return new QByteArray(static_cast(data), static_cast(size)); +} + +extern "C" VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size) { + if (qba == nullptr) return nullptr; + QByteArray* ba = static_cast(qba); + if (out_size != nullptr) *out_size = static_cast(ba->size()); + return ba->data(); +} + +extern "C" VQT6_API size_t vqt6_qbytearray_size(void* qba) { + if (qba == nullptr) return 0; + return static_cast(static_cast(qba)->size()); +} + +extern "C" VQT6_API void vqt6_qbytearray_free(void* qba) { + delete static_cast(qba); +} + +// ============================================================ +// QObject +// ============================================================ +extern "C" VQT6_API void vqt6_qobject_delete(void* obj) { + if (obj == nullptr) return; + delete static_cast(obj); +} + +extern "C" VQT6_API void vqt6_qobject_delete_later(void* obj) { + if (obj == nullptr) return; + static_cast(obj)->deleteLater(); +} + +extern "C" VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name) { + if (obj == nullptr || name == nullptr) return; + static_cast(obj)->setObjectName(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qobject_object_name(void* obj) { + if (obj == nullptr) return nullptr; + return new QString(static_cast(obj)->objectName()); +} + +extern "C" VQT6_API void vqt6_qobject_set_parent(void* child, void* parent) { + if (child == nullptr) return; + static_cast(child)->setParent(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qobject_parent(void* obj) { + if (obj == nullptr) return nullptr; + return static_cast(obj)->parent(); +} + +extern "C" VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name, + void* receiver, const char* slot_name) { + if (sender == nullptr || receiver == nullptr || signal_name == nullptr || slot_name == nullptr) + return 0; + return QObject::connect( + static_cast(sender), signal_name, + static_cast(receiver), slot_name + ) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name, + void* receiver, const char* slot_name) { + if (sender == nullptr || receiver == nullptr) return 0; + return QObject::disconnect( + static_cast(sender), signal_name, + static_cast(receiver), slot_name + ) ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter) { + if (watched == nullptr || filter == nullptr) return; + static_cast(watched)->installEventFilter(static_cast(filter)); +} + +extern "C" VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter) { + if (watched == nullptr || filter == nullptr) return; + static_cast(watched)->removeEventFilter(static_cast(filter)); +} + +// ============================================================ +// QCoreApplication +// ============================================================ +extern "C" VQT6_API void* vqt6_qcoreapp_create(const char* app_name) { + if (app_name == nullptr) return nullptr; + int argc = 1; + static char app_name_copy[1024]; + std::strncpy(app_name_copy, app_name, sizeof(app_name_copy) - 1); + app_name_copy[sizeof(app_name_copy) - 1] = '\0'; + char* argv[] = { app_name_copy, nullptr }; + return new QCoreApplication(argc, argv); +} + +extern "C" VQT6_API void* vqt6_qcoreapp_instance(void) { + return QCoreApplication::instance(); +} + +extern "C" VQT6_API int vqt6_qcoreapp_exec(void* app) { + if (app == nullptr) return -1; + return static_cast(app)->exec(); +} + +extern "C" VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code) { + if (app == nullptr) return; + // 优先使用 exit_code 重载 + QCoreApplication* a = static_cast(app); + if (a == QCoreApplication::instance()) { + a->exit(exit_code); + } +} + +extern "C" VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code) { + if (app == nullptr) return; + static_cast(app)->exit(exit_code); +} + +extern "C" VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags) { + if (app == nullptr) return; + static_cast(app)->processEvents(static_cast(flags)); +} + +extern "C" VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event) { + if (receiver == nullptr || event == nullptr) return; + QCoreApplication::postEvent(static_cast(receiver), static_cast(event)); +} + +extern "C" VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event) { + if (receiver == nullptr || event == nullptr) return 0; + return QCoreApplication::sendEvent(static_cast(receiver), static_cast(event)) ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qcoreapp_organization_name(void* app) { + if (app == nullptr) return nullptr; + return new QString(QCoreApplication::organizationName()); +} + +extern "C" VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name) { + if (app == nullptr || name == nullptr) return; + QCoreApplication::setOrganizationName(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qcoreapp_application_name(void* app) { + if (app == nullptr) return nullptr; + return new QString(QCoreApplication::applicationName()); +} + +extern "C" VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name) { + if (app == nullptr || name == nullptr) return; + QCoreApplication::setApplicationName(*static_cast(name)); +} + +// ============================================================ +// QTimer +// ============================================================ +extern "C" VQT6_API void* vqt6_qtimer_create(void) { + return new QTimer(); +} + +extern "C" VQT6_API void* vqt6_qtimer_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTimer(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms) { + if (timer == nullptr) return; + static_cast(timer)->start(interval_ms); +} + +extern "C" VQT6_API void vqt6_qtimer_stop(void* timer) { + if (timer == nullptr) return; + static_cast(timer)->stop(); +} + +extern "C" VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms) { + if (timer == nullptr) return; + static_cast(timer)->setInterval(interval_ms); +} + +extern "C" VQT6_API int vqt6_qtimer_interval(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->interval(); +} + +extern "C" VQT6_API int vqt6_qtimer_is_active(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->isActive() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot) { + if (timer == nullptr) return; + static_cast(timer)->setSingleShot(single_shot != 0); +} + +extern "C" VQT6_API int vqt6_qtimer_is_single_shot(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->isSingleShot() ? 1 : 0; +} + +// ============================================================ +// QVariant +// ============================================================ +extern "C" VQT6_API void* vqt6_qvariant_create_int(int value) { + return new QVariant(value); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_double(double value) { + return new QVariant(value); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_bool(int value) { + return new QVariant(value != 0); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_string(void* s) { + if (s == nullptr) return new QVariant(); + return new QVariant(*static_cast(s)); +} + +extern "C" VQT6_API int vqt6_qvariant_to_int(void* v, int* ok) { + if (v == nullptr) return 0; + bool bok = false; + int val = static_cast(v)->toInt(&bok); + if (ok != nullptr) *ok = bok ? 1 : 0; + return val; +} + +extern "C" VQT6_API double vqt6_qvariant_to_double(void* v, int* ok) { + if (v == nullptr) return 0.0; + bool bok = false; + double val = static_cast(v)->toDouble(&bok); + if (ok != nullptr) *ok = bok ? 1 : 0; + return val; +} + +extern "C" VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok) { + if (v == nullptr) return 0; + bool bok = false; + bool val = static_cast(v)->toBool(); + if (ok != nullptr) *ok = 1; + return val ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qvariant_to_string(void* v) { + if (v == nullptr) return nullptr; + return new QString(static_cast(v)->toString()); +} + +extern "C" VQT6_API int vqt6_qvariant_type_id(void* v) { + if (v == nullptr) return 0; + return static_cast(static_cast(v)->typeId()); +} + +extern "C" VQT6_API int vqt6_qvariant_is_valid(void* v) { + if (v == nullptr) return 0; + return static_cast(v)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qvariant_free(void* v) { + delete static_cast(v); +} + +// ============================================================ +// QEvent +// ============================================================ +extern "C" VQT6_API int vqt6_qevent_type(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->type()); +} + +extern "C" VQT6_API void vqt6_qevent_accept(void* event) { + if (event == nullptr) return; + static_cast(event)->accept(); +} + +extern "C" VQT6_API void vqt6_qevent_ignore(void* event) { + if (event == nullptr) return; + static_cast(event)->ignore(); +} + +extern "C" VQT6_API int vqt6_qevent_is_accepted(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAccepted() ? 1 : 0; +} + +// ============================================================ +// QStringList +// ============================================================ +extern "C" VQT6_API void* vqt6_qstringlist_create(void) { + return new QStringList(); +} + +extern "C" VQT6_API void vqt6_qstringlist_append(void* list, void* str) { + if (list == nullptr || str == nullptr) return; + static_cast(list)->append(*static_cast(str)); +} + +extern "C" VQT6_API int vqt6_qstringlist_size(void* list) { + if (list == nullptr) return 0; + return static_cast(list)->size(); +} + +extern "C" VQT6_API void* vqt6_qstringlist_at(void* list, int index) { + if (list == nullptr) return nullptr; + QStringList* sl = static_cast(list); + if (index < 0 || index >= sl->size()) return nullptr; + return new QString(sl->at(index)); +} + +extern "C" VQT6_API void vqt6_qstringlist_free(void* list) { + delete static_cast(list); +} + +// ============================================================ +// QByteArrayList +// ============================================================ +extern "C" VQT6_API void* vqt6_qbytearraylist_create(void) { + return new QList(); +} + +extern "C" VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba) { + if (list == nullptr || qba == nullptr) return; + static_cast*>(list)->append(*static_cast(qba)); +} + +extern "C" VQT6_API int vqt6_qbytearraylist_size(void* list) { + if (list == nullptr) return 0; + return static_cast*>(list)->size(); +} + +extern "C" VQT6_API void* vqt6_qbytearraylist_at(void* list, int index) { + if (list == nullptr) return nullptr; + QList* qbl = static_cast*>(list); + if (index < 0 || index >= qbl->size()) return nullptr; + return new QByteArray(qbl->at(index)); +} + +extern "C" VQT6_API void vqt6_qbytearraylist_free(void* list) { + delete static_cast*>(list); +} + +// ============================================================ +// 全局回调注册表 +// ============================================================ +extern "C" VQT6_API void vqt6_register_slot(int slot_id, void* user_data) { + QMutexLocker locker(&g_slot_mutex); + g_slots.insert(slot_id, QPair(nullptr, user_data)); +} + +extern "C" VQT6_API void vqt6_unregister_slot(int slot_id) { + QMutexLocker locker(&g_slot_mutex); + g_slots.remove(slot_id); +} + +extern "C" VQT6_API void vqt6_trigger_slot(int slot_id) { + QMutexLocker locker(&g_slot_mutex); + auto it = g_slots.find(slot_id); + if (it != g_slots.end() && it.value().first != nullptr) { + it.value().first(slot_id, it.value().second); + } +} diff --git a/vqt6 copy/_bridge_gui.cpp b/vqt6 copy/_bridge_gui.cpp new file mode 100644 index 0000000..089f0d7 --- /dev/null +++ b/vqt6 copy/_bridge_gui.cpp @@ -0,0 +1,868 @@ +// ============================================================ +// vqt6/_bridge_gui.cpp — QtGui C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_gui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QColor +// ============================================================ +extern "C" VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b) { + return new QColor(r, g, b); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a) { + return new QColor(r, g, b, a); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_name(void* name) { + if (name == nullptr) return new QColor(); + return new QColor(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_hex(void* hex_str) { + if (hex_str == nullptr) return new QColor(); + return new QColor(*static_cast(hex_str)); +} + +extern "C" VQT6_API int vqt6_qcolor_red(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->red(); +} + +extern "C" VQT6_API int vqt6_qcolor_green(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->green(); +} + +extern "C" VQT6_API int vqt6_qcolor_blue(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->blue(); +} + +extern "C" VQT6_API int vqt6_qcolor_alpha(void* c) { + if (c == nullptr) return 255; + return static_cast(c)->alpha(); +} + +extern "C" VQT6_API void vqt6_qcolor_set_red(void* c, int r) { + if (c == nullptr) return; + static_cast(c)->setRed(r); +} + +extern "C" VQT6_API void vqt6_qcolor_set_green(void* c, int g) { + if (c == nullptr) return; + static_cast(c)->setGreen(g); +} + +extern "C" VQT6_API void vqt6_qcolor_set_blue(void* c, int b) { + if (c == nullptr) return; + static_cast(c)->setBlue(b); +} + +extern "C" VQT6_API void vqt6_qcolor_set_alpha(void* c, int a) { + if (c == nullptr) return; + static_cast(c)->setAlpha(a); +} + +extern "C" VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b) { + if (c == nullptr) return; + static_cast(c)->setRgb(r, g, b); +} + +extern "C" VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a) { + if (c == nullptr) return; + static_cast(c)->setRgba(r, g, b, a); +} + +extern "C" VQT6_API void* vqt6_qcolor_name(void* c) { + if (c == nullptr) return nullptr; + return new QString(static_cast(c)->name()); +} + +extern "C" VQT6_API int vqt6_qcolor_is_valid(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcolor_free(void* c) { + delete static_cast(c); +} + +// ============================================================ +// QFont +// ============================================================ +extern "C" VQT6_API void* vqt6_qfont_create(void) { + return new QFont(); +} + +extern "C" VQT6_API void* vqt6_qfont_create_with_family(void* family) { + if (family == nullptr) return new QFont(); + return new QFont(*static_cast(family)); +} + +extern "C" VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size) { + if (family == nullptr) return new QFont(); + return new QFont(*static_cast(family), point_size); +} + +extern "C" VQT6_API void vqt6_qfont_set_family(void* font, void* family) { + if (font == nullptr || family == nullptr) return; + static_cast(font)->setFamily(*static_cast(family)); +} + +extern "C" VQT6_API void* vqt6_qfont_family(void* font) { + if (font == nullptr) return nullptr; + return new QString(static_cast(font)->family()); +} + +extern "C" VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size) { + if (font == nullptr) return; + static_cast(font)->setPointSize(point_size); +} + +extern "C" VQT6_API int vqt6_qfont_point_size(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->pointSize(); +} + +extern "C" VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size) { + if (font == nullptr) return; + static_cast(font)->setPixelSize(pixel_size); +} + +extern "C" VQT6_API int vqt6_qfont_pixel_size(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->pixelSize(); +} + +extern "C" VQT6_API void vqt6_qfont_set_bold(void* font, int bold) { + if (font == nullptr) return; + static_cast(font)->setBold(bold != 0); +} + +extern "C" VQT6_API int vqt6_qfont_bold(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->bold() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_italic(void* font, int italic) { + if (font == nullptr) return; + static_cast(font)->setItalic(italic != 0); +} + +extern "C" VQT6_API int vqt6_qfont_italic(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->italic() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_underline(void* font, int underline) { + if (font == nullptr) return; + static_cast(font)->setUnderline(underline != 0); +} + +extern "C" VQT6_API int vqt6_qfont_underline(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->underline() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out) { + if (font == nullptr) return; + static_cast(font)->setStrikeOut(strike_out != 0); +} + +extern "C" VQT6_API int vqt6_qfont_strike_out(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->strikeOut() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_weight(void* font, int weight) { + if (font == nullptr) return; + static_cast(font)->setWeight(static_cast(weight)); +} + +extern "C" VQT6_API int vqt6_qfont_weight(void* font) { + if (font == nullptr) return 0; + return static_cast(static_cast(font)->weight()); +} + +extern "C" VQT6_API void vqt6_qfont_free(void* font) { + delete static_cast(font); +} + +// ============================================================ +// QFontMetrics +// ============================================================ +extern "C" VQT6_API void* vqt6_qfontmetrics_create(void* font) { + if (font == nullptr) return nullptr; + return new QFontMetrics(*static_cast(font)); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text) { + if (fm == nullptr || text == nullptr) return 0; + return static_cast(fm)->horizontalAdvance(*static_cast(text)); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_height(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->height(); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_ascent(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->ascent(); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_descent(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->descent(); +} + +extern "C" VQT6_API void vqt6_qfontmetrics_free(void* fm) { + delete static_cast(fm); +} + +// ============================================================ +// QPixmap +// ============================================================ +extern "C" VQT6_API void* vqt6_qpixmap_create(void) { + return new QPixmap(); +} + +extern "C" VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h) { + return new QPixmap(w, h); +} + +extern "C" VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name) { + if (pm == nullptr || file_name == nullptr) return 0; + return static_cast(pm)->load(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size) { + if (pm == nullptr || data == nullptr) return 0; + return static_cast(pm)->loadFromData(static_cast(data), static_cast(size)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name) { + if (pm == nullptr || file_name == nullptr) return 0; + return static_cast(pm)->save(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_width(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->width(); +} + +extern "C" VQT6_API int vqt6_qpixmap_height(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->height(); +} + +extern "C" VQT6_API int vqt6_qpixmap_is_null(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h) { + if (pm == nullptr) return nullptr; + return new QPixmap(static_cast(pm)->scaled(w, h)); +} + +extern "C" VQT6_API void vqt6_qpixmap_fill(void* pm, void* color) { + if (pm == nullptr) return; + if (color != nullptr) { + static_cast(pm)->fill(*static_cast(color)); + } else { + static_cast(pm)->fill(); + } +} + +extern "C" VQT6_API void vqt6_qpixmap_free(void* pm) { + delete static_cast(pm); +} + +// ============================================================ +// QImage +// ============================================================ +extern "C" VQT6_API void* vqt6_qimage_create(void) { + return new QImage(); +} + +extern "C" VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format) { + return new QImage(w, h, static_cast(format)); +} + +extern "C" VQT6_API int vqt6_qimage_load(void* img, void* file_name) { + if (img == nullptr || file_name == nullptr) return 0; + return static_cast(img)->load(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qimage_save(void* img, void* file_name) { + if (img == nullptr || file_name == nullptr) return 0; + return static_cast(img)->save(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qimage_width(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->width(); +} + +extern "C" VQT6_API int vqt6_qimage_height(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->height(); +} + +extern "C" VQT6_API int vqt6_qimage_format(void* img) { + if (img == nullptr) return 0; + return static_cast(static_cast(img)->format()); +} + +extern "C" VQT6_API int vqt6_qimage_is_null(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qimage_fill(void* img, void* color) { + if (img == nullptr) return; + if (color != nullptr) { + static_cast(img)->fill(*static_cast(color)); + } +} + +extern "C" VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h) { + if (img == nullptr) return nullptr; + return new QImage(static_cast(img)->scaled(w, h)); +} + +extern "C" VQT6_API void vqt6_qimage_free(void* img) { + delete static_cast(img); +} + +// ============================================================ +// QPainter +// ============================================================ +extern "C" VQT6_API void* vqt6_qpainter_create(void) { + return new QPainter(); +} + +extern "C" VQT6_API int vqt6_qpainter_begin(void* p, void* device) { + if (p == nullptr || device == nullptr) return 0; + return static_cast(p)->begin(static_cast(device)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpainter_end(void* p) { + if (p == nullptr) return 0; + return static_cast(p)->end() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpainter_is_active(void* p) { + if (p == nullptr) return 0; + return static_cast(p)->isActive() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen) { + if (p == nullptr || pen == nullptr) return; + static_cast(p)->setPen(*static_cast(pen)); +} + +extern "C" VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush) { + if (p == nullptr || brush == nullptr) return; + static_cast(p)->setBrush(*static_cast(brush)); +} + +extern "C" VQT6_API void vqt6_qpainter_set_font(void* p, void* font) { + if (p == nullptr || font == nullptr) return; + static_cast(p)->setFont(*static_cast(font)); +} + +extern "C" VQT6_API void* vqt6_qpainter_pen(void* p) { + if (p == nullptr) return nullptr; + return new QPen(static_cast(p)->pen()); +} + +extern "C" VQT6_API void* vqt6_qpainter_brush(void* p) { + if (p == nullptr) return nullptr; + return new QBrush(static_cast(p)->brush()); +} + +extern "C" VQT6_API void* vqt6_qpainter_font(void* p) { + if (p == nullptr) return nullptr; + return new QFont(static_cast(p)->font()); +} + +extern "C" VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity) { + if (p == nullptr) return; + static_cast(p)->setOpacity(opacity); +} + +extern "C" VQT6_API double vqt6_qpainter_opacity(void* p) { + if (p == nullptr) return 1.0; + return static_cast(p)->opacity(); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2) { + if (p == nullptr) return; + static_cast(p)->drawLine(x1, y1, x2, y2); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h) { + if (p == nullptr) return; + static_cast(p)->drawRect(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color) { + if (p == nullptr || color == nullptr) return; + static_cast(p)->fillRect(x, y, w, h, *static_cast(color)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h) { + if (p == nullptr) return; + static_cast(p)->drawEllipse(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawArc(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawChord(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawPie(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon polygon; + for (int i = 0; i < point_count; ++i) { + polygon << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPolygon(polygon); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon polyline; + for (int i = 0; i < point_count; ++i) { + polyline << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPolyline(polyline); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y) { + if (p == nullptr) return; + static_cast(p)->drawPoint(x, y); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon pts; + for (int i = 0; i < point_count; ++i) { + pts << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPoints(pts); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text) { + if (p == nullptr || text == nullptr) return; + static_cast(p)->drawText(x, y, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text) { + if (p == nullptr || text == nullptr) return; + static_cast(p)->drawText(x, y, w, h, flags, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap) { + if (p == nullptr || pixmap == nullptr) return; + static_cast(p)->drawPixmap(x, y, *static_cast(pixmap)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image) { + if (p == nullptr || image == nullptr) return; + static_cast(p)->drawImage(x, y, *static_cast(image)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap) { + if (p == nullptr || pixmap == nullptr) return; + static_cast(p)->drawTiledPixmap(x, y, w, h, *static_cast(pixmap)); +} + +extern "C" VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy) { + if (p == nullptr) return; + static_cast(p)->translate(dx, dy); +} + +extern "C" VQT6_API void vqt6_qpainter_rotate(void* p, double angle) { + if (p == nullptr) return; + static_cast(p)->rotate(angle); +} + +extern "C" VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy) { + if (p == nullptr) return; + static_cast(p)->scale(sx, sy); +} + +extern "C" VQT6_API void vqt6_qpainter_reset_transform(void* p) { + if (p == nullptr) return; + static_cast(p)->resetTransform(); +} + +extern "C" VQT6_API void vqt6_qpainter_save(void* p) { + if (p == nullptr) return; + static_cast(p)->save(); +} + +extern "C" VQT6_API void vqt6_qpainter_restore(void* p) { + if (p == nullptr) return; + static_cast(p)->restore(); +} + +extern "C" VQT6_API void vqt6_qpainter_free(void* p) { + delete static_cast(p); +} + +// ============================================================ +// QPen +// ============================================================ +extern "C" VQT6_API void* vqt6_qpen_create(void) { + return new QPen(); +} + +extern "C" VQT6_API void* vqt6_qpen_create_with_color(void* color) { + if (color == nullptr) return new QPen(); + return new QPen(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width) { + if (color == nullptr) return new QPen(); + return new QPen(*static_cast(color), width); +} + +extern "C" VQT6_API void vqt6_qpen_set_color(void* pen, void* color) { + if (pen == nullptr || color == nullptr) return; + static_cast(pen)->setColor(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qpen_color(void* pen) { + if (pen == nullptr) return nullptr; + return new QColor(static_cast(pen)->color()); +} + +extern "C" VQT6_API void vqt6_qpen_set_width(void* pen, int width) { + if (pen == nullptr) return; + static_cast(pen)->setWidth(width); +} + +extern "C" VQT6_API int vqt6_qpen_width(void* pen) { + if (pen == nullptr) return 0; + return static_cast(pen)->width(); +} + +extern "C" VQT6_API void vqt6_qpen_set_style(void* pen, int style) { + if (pen == nullptr) return; + static_cast(pen)->setStyle(static_cast(style)); +} + +extern "C" VQT6_API int vqt6_qpen_style(void* pen) { + if (pen == nullptr) return 0; + return static_cast(static_cast(pen)->style()); +} + +extern "C" VQT6_API void vqt6_qpen_free(void* pen) { + delete static_cast(pen); +} + +// ============================================================ +// QBrush +// ============================================================ +extern "C" VQT6_API void* vqt6_qbrush_create(void) { + return new QBrush(); +} + +extern "C" VQT6_API void* vqt6_qbrush_create_with_color(void* color) { + if (color == nullptr) return new QBrush(); + return new QBrush(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qbrush_create_with_style(int style) { + return new QBrush(static_cast(style)); +} + +extern "C" VQT6_API void vqt6_qbrush_set_color(void* brush, void* color) { + if (brush == nullptr || color == nullptr) return; + static_cast(brush)->setColor(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qbrush_color(void* brush) { + if (brush == nullptr) return nullptr; + return new QColor(static_cast(brush)->color()); +} + +extern "C" VQT6_API void vqt6_qbrush_set_style(void* brush, int style) { + if (brush == nullptr) return; + static_cast(brush)->setStyle(static_cast(style)); +} + +extern "C" VQT6_API int vqt6_qbrush_style(void* brush) { + if (brush == nullptr) return 0; + return static_cast(static_cast(brush)->style()); +} + +extern "C" VQT6_API void vqt6_qbrush_free(void* brush) { + delete static_cast(brush); +} + +// ============================================================ +// QIcon +// ============================================================ +extern "C" VQT6_API void* vqt6_qicon_create(void) { + return new QIcon(); +} + +extern "C" VQT6_API void* vqt6_qicon_create_with_file(void* file_name) { + if (file_name == nullptr) return new QIcon(); + return new QIcon(*static_cast(file_name)); +} + +extern "C" VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name) { + if (icon == nullptr || file_name == nullptr) return; + static_cast(icon)->addFile(*static_cast(file_name)); +} + +extern "C" VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap) { + if (icon == nullptr || pixmap == nullptr) return; + static_cast(icon)->addPixmap(*static_cast(pixmap)); +} + +extern "C" VQT6_API int vqt6_qicon_is_null(void* icon) { + if (icon == nullptr) return 0; + return static_cast(icon)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h) { + if (icon == nullptr) return nullptr; + return new QPixmap(static_cast(icon)->pixmap(w, h)); +} + +extern "C" VQT6_API void vqt6_qicon_free(void* icon) { + delete static_cast(icon); +} + +// ============================================================ +// QCursor +// ============================================================ +extern "C" VQT6_API void* vqt6_qcursor_create(void) { + return new QCursor(); +} + +extern "C" VQT6_API void* vqt6_qcursor_create_with_shape(int shape) { + return new QCursor(static_cast(shape)); +} + +extern "C" VQT6_API void vqt6_qcursor_pos(int* x, int* y) { + QPoint p = QCursor::pos(); + if (x != nullptr) *x = p.x(); + if (y != nullptr) *y = p.y(); +} + +extern "C" VQT6_API void vqt6_qcursor_set_pos(int x, int y) { + QCursor::setPos(x, y); +} + +extern "C" VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape) { + if (cursor == nullptr) return; + static_cast(cursor)->setShape(static_cast(shape)); +} + +extern "C" VQT6_API int vqt6_qcursor_shape(void* cursor) { + if (cursor == nullptr) return 0; + return static_cast(static_cast(cursor)->shape()); +} + +extern "C" VQT6_API void vqt6_qcursor_free(void* cursor) { + delete static_cast(cursor); +} + +// ============================================================ +// QKeyEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text) { + QString* t = static_cast(text); + return new QKeyEvent(static_cast(type), key, static_cast(modifiers), + t != nullptr ? *t : QString()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_key(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->key(); +} + +extern "C" VQT6_API void* vqt6_qkeyevent_text(void* event) { + if (event == nullptr) return nullptr; + return new QString(static_cast(event)->text()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_modifiers(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->modifiers()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAutoRepeat() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qkeyevent_free(void* event) { + delete static_cast(event); +} + +// ============================================================ +// QMouseEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers) { + QPointF* lp = static_cast(local_pos); + return new QMouseEvent( + static_cast(type), + lp != nullptr ? *lp : QPointF(0, 0), + Qt::NoButton, + static_cast(button), + static_cast(modifiers) + ); +} + +extern "C" VQT6_API int vqt6_qmouseevent_button(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->button()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_buttons(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->buttons()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_x(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->position().x()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_y(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->position().y()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_global_x(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->globalPosition().x()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_global_y(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->globalPosition().y()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_modifiers(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->modifiers()); +} + +extern "C" VQT6_API void vqt6_qmouseevent_free(void* event) { + delete static_cast(event); +} + +// ============================================================ +// QResizeEvent / QPaintEvent / QCloseEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height) { + return new QResizeEvent(QSize(width, height), QSize(old_width, old_height)); +} + +extern "C" VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h) { + if (event == nullptr) return; + QSize s = static_cast(event)->size(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h) { + if (event == nullptr) return; + QSize s = static_cast(event)->oldSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qresizeevent_free(void* event) { + delete static_cast(event); +} + +extern "C" VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h) { + return new QPaintEvent(QRect(rect_x, rect_y, rect_w, rect_h)); +} + +extern "C" VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h) { + if (event == nullptr) return; + QRect r = static_cast(event)->rect(); + if (x != nullptr) *x = r.x(); + if (y != nullptr) *y = r.y(); + if (w != nullptr) *w = r.width(); + if (h != nullptr) *h = r.height(); +} + +extern "C" VQT6_API void vqt6_qpaintevent_free(void* event) { + delete static_cast(event); +} + +extern "C" VQT6_API void* vqt6_qcloseevent_create(void) { + return new QCloseEvent(); +} + +extern "C" VQT6_API int vqt6_qcloseevent_is_accepted(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAccepted() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcloseevent_accept(void* event) { + if (event == nullptr) return; + static_cast(event)->accept(); +} + +extern "C" VQT6_API void vqt6_qcloseevent_ignore(void* event) { + if (event == nullptr) return; + static_cast(event)->ignore(); +} + +extern "C" VQT6_API void vqt6_qcloseevent_free(void* event) { + delete static_cast(event); +} diff --git a/vqt6 copy/_bridge_gui.h b/vqt6 copy/_bridge_gui.h new file mode 100644 index 0000000..d2bb224 --- /dev/null +++ b/vqt6 copy/_bridge_gui.h @@ -0,0 +1,231 @@ +// ============================================================ +// vqt6/_bridge_gui.h — QtGui C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_GUI_H +#define VQT6_BRIDGE_GUI_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QColor +// ============================================================ +VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b); +VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a); +VQT6_API void* vqt6_qcolor_create_name(void* name); +VQT6_API void* vqt6_qcolor_create_hex(void* hex_str); +VQT6_API int vqt6_qcolor_red(void* c); +VQT6_API int vqt6_qcolor_green(void* c); +VQT6_API int vqt6_qcolor_blue(void* c); +VQT6_API int vqt6_qcolor_alpha(void* c); +VQT6_API void vqt6_qcolor_set_red(void* c, int r); +VQT6_API void vqt6_qcolor_set_green(void* c, int g); +VQT6_API void vqt6_qcolor_set_blue(void* c, int b); +VQT6_API void vqt6_qcolor_set_alpha(void* c, int a); +VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b); +VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a); +VQT6_API void* vqt6_qcolor_name(void* c); +VQT6_API int vqt6_qcolor_is_valid(void* c); +VQT6_API void vqt6_qcolor_free(void* c); + +// ============================================================ +// QFont +// ============================================================ +VQT6_API void* vqt6_qfont_create(void); +VQT6_API void* vqt6_qfont_create_with_family(void* family); +VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size); +VQT6_API void vqt6_qfont_set_family(void* font, void* family); +VQT6_API void* vqt6_qfont_family(void* font); +VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size); +VQT6_API int vqt6_qfont_point_size(void* font); +VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size); +VQT6_API int vqt6_qfont_pixel_size(void* font); +VQT6_API void vqt6_qfont_set_bold(void* font, int bold); +VQT6_API int vqt6_qfont_bold(void* font); +VQT6_API void vqt6_qfont_set_italic(void* font, int italic); +VQT6_API int vqt6_qfont_italic(void* font); +VQT6_API void vqt6_qfont_set_underline(void* font, int underline); +VQT6_API int vqt6_qfont_underline(void* font); +VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out); +VQT6_API int vqt6_qfont_strike_out(void* font); +VQT6_API void vqt6_qfont_set_weight(void* font, int weight); +VQT6_API int vqt6_qfont_weight(void* font); +VQT6_API void vqt6_qfont_free(void* font); + +// ============================================================ +// QFontMetrics +// ============================================================ +VQT6_API void* vqt6_qfontmetrics_create(void* font); +VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text); +VQT6_API int vqt6_qfontmetrics_height(void* fm); +VQT6_API int vqt6_qfontmetrics_ascent(void* fm); +VQT6_API int vqt6_qfontmetrics_descent(void* fm); +VQT6_API void vqt6_qfontmetrics_free(void* fm); + +// ============================================================ +// QPixmap +// ============================================================ +VQT6_API void* vqt6_qpixmap_create(void); +VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h); +VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name); +VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size); +VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name); +VQT6_API int vqt6_qpixmap_width(void* pm); +VQT6_API int vqt6_qpixmap_height(void* pm); +VQT6_API int vqt6_qpixmap_is_null(void* pm); +VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h); +VQT6_API void vqt6_qpixmap_fill(void* pm, void* color); +VQT6_API void vqt6_qpixmap_free(void* pm); + +// ============================================================ +// QImage +// ============================================================ +VQT6_API void* vqt6_qimage_create(void); +VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format); +VQT6_API int vqt6_qimage_load(void* img, void* file_name); +VQT6_API int vqt6_qimage_save(void* img, void* file_name); +VQT6_API int vqt6_qimage_width(void* img); +VQT6_API int vqt6_qimage_height(void* img); +VQT6_API int vqt6_qimage_format(void* img); +VQT6_API int vqt6_qimage_is_null(void* img); +VQT6_API void vqt6_qimage_fill(void* img, void* color); +VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h); +VQT6_API void vqt6_qimage_free(void* img); + +// ============================================================ +// QPainter +// ============================================================ +VQT6_API void* vqt6_qpainter_create(void); +VQT6_API int vqt6_qpainter_begin(void* p, void* device); +VQT6_API int vqt6_qpainter_end(void* p); +VQT6_API int vqt6_qpainter_is_active(void* p); +VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen); +VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush); +VQT6_API void vqt6_qpainter_set_font(void* p, void* font); +VQT6_API void* vqt6_qpainter_pen(void* p); +VQT6_API void* vqt6_qpainter_brush(void* p); +VQT6_API void* vqt6_qpainter_font(void* p); +VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity); +VQT6_API double vqt6_qpainter_opacity(void* p); +VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2); +VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h); +VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color); +VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h); +VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y); +VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text); +VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text); +VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap); +VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image); +VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap); +VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy); +VQT6_API void vqt6_qpainter_rotate(void* p, double angle); +VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy); +VQT6_API void vqt6_qpainter_reset_transform(void* p); +VQT6_API void vqt6_qpainter_save(void* p); +VQT6_API void vqt6_qpainter_restore(void* p); +VQT6_API void vqt6_qpainter_free(void* p); + +// ============================================================ +// QPen +// ============================================================ +VQT6_API void* vqt6_qpen_create(void); +VQT6_API void* vqt6_qpen_create_with_color(void* color); +VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width); +VQT6_API void vqt6_qpen_set_color(void* pen, void* color); +VQT6_API void* vqt6_qpen_color(void* pen); +VQT6_API void vqt6_qpen_set_width(void* pen, int width); +VQT6_API int vqt6_qpen_width(void* pen); +VQT6_API void vqt6_qpen_set_style(void* pen, int style); +VQT6_API int vqt6_qpen_style(void* pen); +VQT6_API void vqt6_qpen_free(void* pen); + +// ============================================================ +// QBrush +// ============================================================ +VQT6_API void* vqt6_qbrush_create(void); +VQT6_API void* vqt6_qbrush_create_with_color(void* color); +VQT6_API void* vqt6_qbrush_create_with_style(int style); +VQT6_API void vqt6_qbrush_set_color(void* brush, void* color); +VQT6_API void* vqt6_qbrush_color(void* brush); +VQT6_API void vqt6_qbrush_set_style(void* brush, int style); +VQT6_API int vqt6_qbrush_style(void* brush); +VQT6_API void vqt6_qbrush_free(void* brush); + +// ============================================================ +// QIcon +// ============================================================ +VQT6_API void* vqt6_qicon_create(void); +VQT6_API void* vqt6_qicon_create_with_file(void* file_name); +VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name); +VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap); +VQT6_API int vqt6_qicon_is_null(void* icon); +VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h); +VQT6_API void vqt6_qicon_free(void* icon); + +// ============================================================ +// QCursor +// ============================================================ +VQT6_API void* vqt6_qcursor_create(void); +VQT6_API void* vqt6_qcursor_create_with_shape(int shape); +VQT6_API void vqt6_qcursor_pos(int* x, int* y); +VQT6_API void vqt6_qcursor_set_pos(int x, int y); +VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape); +VQT6_API int vqt6_qcursor_shape(void* cursor); +VQT6_API void vqt6_qcursor_free(void* cursor); + +// ============================================================ +// QKeyEvent +// ============================================================ +VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text); +VQT6_API int vqt6_qkeyevent_key(void* event); +VQT6_API void* vqt6_qkeyevent_text(void* event); +VQT6_API int vqt6_qkeyevent_modifiers(void* event); +VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event); +VQT6_API void vqt6_qkeyevent_free(void* event); + +// ============================================================ +// QMouseEvent +// ============================================================ +VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers); +VQT6_API int vqt6_qmouseevent_button(void* event); +VQT6_API int vqt6_qmouseevent_buttons(void* event); +VQT6_API int vqt6_qmouseevent_x(void* event); +VQT6_API int vqt6_qmouseevent_y(void* event); +VQT6_API int vqt6_qmouseevent_global_x(void* event); +VQT6_API int vqt6_qmouseevent_global_y(void* event); +VQT6_API int vqt6_qmouseevent_modifiers(void* event); +VQT6_API void vqt6_qmouseevent_free(void* event); + +// ============================================================ +// QResizeEvent / QPaintEvent / QCloseEvent +// ============================================================ +VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height); +VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h); +VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h); +VQT6_API void vqt6_qresizeevent_free(void* event); + +VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h); +VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h); +VQT6_API void vqt6_qpaintevent_free(void* event); + +VQT6_API void* vqt6_qcloseevent_create(void); +VQT6_API int vqt6_qcloseevent_is_accepted(void* event); +VQT6_API void vqt6_qcloseevent_accept(void* event); +VQT6_API void vqt6_qcloseevent_ignore(void* event); +VQT6_API void vqt6_qcloseevent_free(void* event); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_GUI_H diff --git a/vqt6 copy/_bridge_network.cpp b/vqt6 copy/_bridge_network.cpp new file mode 100644 index 0000000..00cab5e --- /dev/null +++ b/vqt6 copy/_bridge_network.cpp @@ -0,0 +1,519 @@ +// ============================================================ +// vqt6/_bridge_network.cpp — QtNetwork C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_network.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QHostAddress +// ============================================================ +extern "C" VQT6_API void* vqt6_qhostaddress_create(void) { + return new QHostAddress(); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4) { + return new QHostAddress(static_cast(ipv4)); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_string(void* address) { + if (address == nullptr) return new QHostAddress(); + return new QHostAddress(*static_cast(address)); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_host(void) { + return new QHostAddress(QHostAddress::LocalHost); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void) { + return new QHostAddress(QHostAddress::LocalHostIPv4); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void) { + return new QHostAddress(QHostAddress::Broadcast); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void) { + return new QHostAddress(QHostAddress::AnyIPv4); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_to_string(void* addr) { + if (addr == nullptr) return nullptr; + return new QString(static_cast(addr)->toString()); +} + +extern "C" VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr) { + if (addr == nullptr) return 0; + return static_cast(static_cast(addr)->toIPv4Address()); +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_null(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_loopback(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isLoopback() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isBroadcast() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_protocol(void* addr) { + if (addr == nullptr) return 0; + return static_cast(static_cast(addr)->protocol()); +} + +extern "C" VQT6_API void vqt6_qhostaddress_free(void* addr) { + delete static_cast(addr); +} + +// ============================================================ +// QAbstractSocket +// ============================================================ +extern "C" VQT6_API int vqt6_qabstractsocket_state(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->state()); +} + +extern "C" VQT6_API int vqt6_qabstractsocket_error(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->error()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_error_string(void* socket) { + if (socket == nullptr) return nullptr; + return new QString(static_cast(socket)->errorString()); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port) { + if (socket == nullptr || host_name == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(host_name), port); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port) { + if (socket == nullptr || address == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(address), port); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->disconnectFromHost(); +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForConnected(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForReadyRead(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForBytesWritten(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForDisconnected(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_is_valid(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_is_open(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->isOpen() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_flush(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->flush() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qabstractsocket_close(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->close(); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_abort(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->abort(); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size) { + if (socket == nullptr || buf == nullptr) return 0; + return static_cast(static_cast(socket)->read(static_cast(buf), static_cast(max_size))); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size) { + if (socket == nullptr) return nullptr; + QByteArray ba = static_cast(socket)->readAll(); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size) { + if (socket == nullptr || data == nullptr) return 0; + return static_cast(static_cast(socket)->write(static_cast(data), static_cast(size))); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->bytesAvailable()); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->bytesToWrite()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket) { + if (socket == nullptr) return nullptr; + return new QHostAddress(static_cast(socket)->peerAddress()); +} + +extern "C" VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->peerPort()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_local_address(void* socket) { + if (socket == nullptr) return nullptr; + return new QHostAddress(static_cast(socket)->localAddress()); +} + +extern "C" VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->localPort()); +} + +// ============================================================ +// QTcpSocket +// ============================================================ +extern "C" VQT6_API void* vqt6_qtcpsocket_create(void) { + return new QTcpSocket(); +} + +extern "C" VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTcpSocket(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode) { + if (socket == nullptr || host_name == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(host_name), port, + static_cast(mode)); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode) { + if (socket == nullptr || address == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(address), port, + static_cast(mode)); +} + +extern "C" VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor) { + if (socket == nullptr) return 0; + return static_cast(socket)->setSocketDescriptor(static_cast(socket_descriptor)) ? 1 : 0; +} + +extern "C" VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket) { + if (socket == nullptr) return -1; + return static_cast(static_cast(socket)->socketDescriptor()); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type) { + Q_UNUSED(socket); + Q_UNUSED(proxy_type); + // QNetworkProxy 配置在更高层 +} + +extern "C" VQT6_API void vqt6_qtcpsocket_abort(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->abort(); +} + +// ============================================================ +// QUdpSocket +// ============================================================ +extern "C" VQT6_API void* vqt6_qudpsocket_create(void) { + return new QUdpSocket(); +} + +extern "C" VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QUdpSocket(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port) { + if (socket == nullptr) return 0; + return static_cast(socket)->bind(port) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port) { + if (socket == nullptr || address == nullptr) return 0; + return static_cast(socket)->bind(*static_cast(address), port) ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qudpsocket_close(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->close(); +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port) { + if (socket == nullptr || data == nullptr || host == nullptr) return 0; + return static_cast(static_cast(socket)->writeDatagram( + static_cast(data), static_cast(size), + *static_cast(host), port)); +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port) { + if (socket == nullptr || data == nullptr) return 0; + QHostAddress sender; + quint16 sender_port = 0; + qint64 n = static_cast(socket)->readDatagram( + static_cast(data), static_cast(max_size), &sender, &sender_port); + if (host != nullptr) { + QHostAddress* dst = static_cast(host); + *dst = sender; + } + if (port != nullptr) { + *port = sender_port; + } + return static_cast(n); +} + +extern "C" VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->hasPendingDatagrams() ? 1 : 0; +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->pendingDatagramSize()); +} + +extern "C" VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address) { + if (socket == nullptr || group_address == nullptr) return 0; + return static_cast(socket)->joinMulticastGroup(*static_cast(group_address)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address) { + if (socket == nullptr || group_address == nullptr) return 0; + return static_cast(socket)->leaveMulticastGroup(*static_cast(group_address)) ? 1 : 0; +} + +// ============================================================ +// QNetworkRequest +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkrequest_create(void) { + return new QNetworkRequest(); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url) { + if (url == nullptr) return new QNetworkRequest(); + return new QNetworkRequest(QUrl(*static_cast(url))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url) { + if (req == nullptr || url == nullptr) return; + static_cast(req)->setUrl(QUrl(*static_cast(url))); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_url(void* req) { + if (req == nullptr) return nullptr; + return new QString(static_cast(req)->url().toString()); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value) { + if (req == nullptr || value == nullptr) return; + static_cast(req)->setHeader(static_cast(header_type), + *static_cast(value)); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type) { + if (req == nullptr) return nullptr; + return new QVariant(static_cast(req)->header(static_cast(header_type))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size) { + if (req == nullptr || header_name == nullptr) return; + static_cast(req)->setRawHeader(QByteArray(header_name), + QByteArray(static_cast(value), static_cast(value_size))); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size) { + if (req == nullptr || header_name == nullptr) return nullptr; + QByteArray ba = static_cast(req)->rawHeader(QByteArray(header_name)); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value) { + if (req == nullptr || value == nullptr) return; + static_cast(req)->setAttribute(static_cast(attr_type), + *static_cast(value)); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type) { + if (req == nullptr) return nullptr; + return new QVariant(static_cast(req)->attribute(static_cast(attr_type))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_free(void* req) { + delete static_cast(req); +} + +// ============================================================ +// QNetworkAccessManager +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create(void) { + return new QNetworkAccessManager(); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QNetworkAccessManager(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->get(*static_cast(req)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size) { + if (nam == nullptr || req == nullptr) return nullptr; + QByteArray payload; + if (data != nullptr && size > 0) { + payload = QByteArray(static_cast(data), static_cast(size)); + } + return static_cast(nam)->post(*static_cast(req), payload); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size) { + if (nam == nullptr || req == nullptr) return nullptr; + QByteArray payload; + if (data != nullptr && size > 0) { + payload = QByteArray(static_cast(data), static_cast(size)); + } + return static_cast(nam)->put(*static_cast(req), payload); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->deleteResource(*static_cast(req)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->head(*static_cast(req)); +} + +extern "C" VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store) { + if (nam == nullptr || store == nullptr) return; + QNetworkCookieJar* jar = qobject_cast(static_cast(store)); + if (jar != nullptr) { + static_cast(nam)->setCookieJar(jar); + } +} + +// ============================================================ +// QNetworkReply +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkreply_url(void* reply) { + if (reply == nullptr) return nullptr; + return new QString(static_cast(reply)->url().toString()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_request(void* reply) { + if (reply == nullptr) return nullptr; + return new QNetworkRequest(static_cast(reply)->request()); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_error(void* reply) { + if (reply == nullptr) return 0; + return static_cast(static_cast(reply)->error()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_error_string(void* reply) { + if (reply == nullptr) return nullptr; + return new QString(static_cast(reply)->errorString()); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_is_finished(void* reply) { + if (reply == nullptr) return 0; + return static_cast(reply)->isFinished() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qnetworkreply_is_running(void* reply) { + if (reply == nullptr) return 0; + return static_cast(reply)->isRunning() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qnetworkreply_abort(void* reply) { + if (reply == nullptr) return; + static_cast(reply)->abort(); +} + +extern "C" VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size) { + if (reply == nullptr || buf == nullptr) return 0; + return static_cast(static_cast(reply)->read(static_cast(buf), static_cast(max_size))); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size) { + if (reply == nullptr) return nullptr; + QByteArray ba = static_cast(reply)->readAll(); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply) { + if (reply == nullptr) return 0; + return static_cast(static_cast(reply)->bytesAvailable()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type) { + if (reply == nullptr) return nullptr; + return new QVariant(static_cast(reply)->header(static_cast(header_type))); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size) { + if (reply == nullptr || header_name == nullptr) return nullptr; + QByteArray ba = static_cast(reply)->rawHeader(QByteArray(header_name)); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code) { + if (reply == nullptr) return nullptr; + return new QVariant(static_cast(reply)->attribute(static_cast(attribute_code))); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value) { + if (reply == nullptr) return default_value; + return static_cast(reply)->attribute(static_cast(attribute_code)).toInt(default_value); +} + +extern "C" VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size) { + if (reply == nullptr || header_name == nullptr) return; + static_cast(reply)->setRawHeader(QByteArray(header_name), + QByteArray(static_cast(value), static_cast(value_size))); +} diff --git a/vqt6 copy/_bridge_network.h b/vqt6 copy/_bridge_network.h new file mode 100644 index 0000000..2f99580 --- /dev/null +++ b/vqt6 copy/_bridge_network.h @@ -0,0 +1,137 @@ +// ============================================================ +// vqt6/_bridge_network.h — QtNetwork C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_NETWORK_H +#define VQT6_BRIDGE_NETWORK_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QHostAddress +// ============================================================ +VQT6_API void* vqt6_qhostaddress_create(void); +VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4); +VQT6_API void* vqt6_qhostaddress_create_with_string(void* address); +VQT6_API void* vqt6_qhostaddress_create_with_local_host(void); +VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void); +VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void); +VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void); +VQT6_API void* vqt6_qhostaddress_to_string(void* addr); +VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr); +VQT6_API int vqt6_qhostaddress_is_null(void* addr); +VQT6_API int vqt6_qhostaddress_is_loopback(void* addr); +VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr); +VQT6_API int vqt6_qhostaddress_protocol(void* addr); +VQT6_API void vqt6_qhostaddress_free(void* addr); + +// ============================================================ +// QAbstractSocket +// ============================================================ +VQT6_API int vqt6_qabstractsocket_state(void* socket); +VQT6_API int vqt6_qabstractsocket_error(void* socket); +VQT6_API void* vqt6_qabstractsocket_error_string(void* socket); +VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port); +VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port); +VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket); +VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_is_valid(void* socket); +VQT6_API int vqt6_qabstractsocket_is_open(void* socket); +VQT6_API int vqt6_qabstractsocket_flush(void* socket); +VQT6_API void vqt6_qabstractsocket_close(void* socket); +VQT6_API void vqt6_qabstractsocket_abort(void* socket); +VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size); +VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size); +VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size); +VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket); +VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket); +VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket); +VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket); +VQT6_API void* vqt6_qabstractsocket_local_address(void* socket); +VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket); + +// ============================================================ +// QTcpSocket +// ============================================================ +VQT6_API void* vqt6_qtcpsocket_create(void); +VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent); +VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode); +VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode); +VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor); +VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket); +VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type); +VQT6_API void vqt6_qtcpsocket_abort(void* socket); + +// ============================================================ +// QUdpSocket +// ============================================================ +VQT6_API void* vqt6_qudpsocket_create(void); +VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent); +VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port); +VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port); +VQT6_API void vqt6_qudpsocket_close(void* socket); +VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port); +VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port); +VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket); +VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket); +VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address); +VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address); + +// ============================================================ +// QNetworkRequest +// ============================================================ +VQT6_API void* vqt6_qnetworkrequest_create(void); +VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url); +VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url); +VQT6_API void* vqt6_qnetworkrequest_url(void* req); +VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value); +VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type); +VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size); +VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size); +VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value); +VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type); +VQT6_API void vqt6_qnetworkrequest_free(void* req); + +// ============================================================ +// QNetworkAccessManager +// ============================================================ +VQT6_API void* vqt6_qnetworkaccessmanager_create(void); +VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent); +VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req); +VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size); +VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size); +VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req); +VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req); +VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store); + +// ============================================================ +// QNetworkReply +// ============================================================ +VQT6_API void* vqt6_qnetworkreply_url(void* reply); +VQT6_API void* vqt6_qnetworkreply_request(void* reply); +VQT6_API int vqt6_qnetworkreply_error(void* reply); +VQT6_API void* vqt6_qnetworkreply_error_string(void* reply); +VQT6_API int vqt6_qnetworkreply_is_finished(void* reply); +VQT6_API int vqt6_qnetworkreply_is_running(void* reply); +VQT6_API void vqt6_qnetworkreply_abort(void* reply); +VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size); +VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size); +VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply); +VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type); +VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size); +VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code); +VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value); +VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_NETWORK_H diff --git a/vqt6 copy/_bridge_widgets.cpp b/vqt6 copy/_bridge_widgets.cpp new file mode 100644 index 0000000..2b963a5 --- /dev/null +++ b/vqt6 copy/_bridge_widgets.cpp @@ -0,0 +1,1745 @@ +// ============================================================ +// vqt6/_bridge_widgets.cpp — QtWidgets C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_widgets.h" +#include "_bridge_gui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QApplication +// ============================================================ +extern "C" VQT6_API void* vqt6_qapplication_create(int argc, char** argv) { + return new QApplication(argc, argv); +} + +extern "C" VQT6_API void* vqt6_qapplication_instance(void) { + return QApplication::instance(); +} + +extern "C" VQT6_API int vqt6_qapplication_exec(void* app) { + if (app == nullptr) return -1; + return static_cast(app)->exec(); +} + +extern "C" VQT6_API void vqt6_qapplication_quit(void* app) { + if (app == nullptr) return; + static_cast(app)->quit(); +} + +extern "C" VQT6_API void vqt6_qapplication_exit(void* app, int exit_code) { + if (app == nullptr) return; + static_cast(app)->exit(exit_code); +} + +extern "C" VQT6_API void vqt6_qapplication_process_events(void* app) { + if (app == nullptr) return; + static_cast(app)->processEvents(); +} + +extern "C" VQT6_API int vqt6_qapplication_desktop_width(void* app) { + if (app == nullptr) return 0; + QScreen* screen = static_cast(app)->primaryScreen(); + return screen != nullptr ? screen->size().width() : 0; +} + +extern "C" VQT6_API int vqt6_qapplication_desktop_height(void* app) { + if (app == nullptr) return 0; + QScreen* screen = static_cast(app)->primaryScreen(); + return screen != nullptr ? screen->size().height() : 0; +} + +extern "C" VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit) { + if (app == nullptr) return; + static_cast(app)->setQuitOnLastWindowClosed(quit != 0); +} + +extern "C" VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app) { + if (app == nullptr) return 0; + return QApplication::quitOnLastWindowClosed() ? 1 : 0; +} + +// ============================================================ +// QWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qwidget_create(void) { + return new QWidget(); +} + +extern "C" VQT6_API void* vqt6_qwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QWidget(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qwidget_show(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->show(); +} + +extern "C" VQT6_API void vqt6_qwidget_hide(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->hide(); +} + +extern "C" VQT6_API int vqt6_qwidget_close(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->close() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qwidget_is_visible(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->isVisible() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible) { + if (widget == nullptr) return; + static_cast(widget)->setVisible(visible != 0); +} + +extern "C" VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setGeometry(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h) { + if (widget == nullptr) return; + QRect r = static_cast(widget)->geometry(); + if (x != nullptr) *x = r.x(); + if (y != nullptr) *y = r.y(); + if (w != nullptr) *w = r.width(); + if (h != nullptr) *h = r.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->resize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->size(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_move(void* widget, int x, int y) { + if (widget == nullptr) return; + static_cast(widget)->move(x, y); +} + +extern "C" VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y) { + if (widget == nullptr) return; + QPoint p = static_cast(widget)->pos(); + if (x != nullptr) *x = p.x(); + if (y != nullptr) *y = p.y(); +} + +extern "C" VQT6_API int vqt6_qwidget_width(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->width(); +} + +extern "C" VQT6_API int vqt6_qwidget_height(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->height(); +} + +extern "C" VQT6_API int vqt6_qwidget_x(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->x(); +} + +extern "C" VQT6_API int vqt6_qwidget_y(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->y(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title) { + if (widget == nullptr || title == nullptr) return; + static_cast(widget)->setWindowTitle(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qwidget_window_title(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->windowTitle()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_text(void* widget, void* text) { + if (widget == nullptr || text == nullptr) return; + static_cast(widget)->setWindowTitle(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qwidget_text(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->windowTitle()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled) { + if (widget == nullptr) return; + static_cast(widget)->setEnabled(enabled != 0); +} + +extern "C" VQT6_API int vqt6_qwidget_is_enabled(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->isEnabled() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent) { + if (widget == nullptr) return; + static_cast(widget)->setParent(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qwidget_parent_widget(void* widget) { + if (widget == nullptr) return nullptr; + return static_cast(widget)->parentWidget(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_focus(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->setFocus(); +} + +extern "C" VQT6_API void vqt6_qwidget_clear_focus(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->clearFocus(); +} + +extern "C" VQT6_API int vqt6_qwidget_has_focus(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->hasFocus() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy) { + if (widget == nullptr) return; + static_cast(widget)->setFocusPolicy(static_cast(policy)); +} + +extern "C" VQT6_API void vqt6_qwidget_update(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->update(); +} + +extern "C" VQT6_API void vqt6_qwidget_repaint(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->repaint(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled) { + if (widget == nullptr) return; + static_cast(widget)->setUpdatesEnabled(enabled != 0); +} + +extern "C" VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags) { + if (widget == nullptr) return; + static_cast(widget)->setWindowFlags(static_cast(flags)); +} + +extern "C" VQT6_API int vqt6_qwidget_window_flags(void* widget) { + if (widget == nullptr) return 0; + return static_cast(static_cast(widget)->windowFlags()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor) { + if (widget == nullptr || cursor == nullptr) return; + static_cast(widget)->setCursor(*static_cast(cursor)); +} + +extern "C" VQT6_API void* vqt6_qwidget_cursor(void* widget) { + if (widget == nullptr) return nullptr; + return new QCursor(static_cast(widget)->cursor()); +} + +extern "C" VQT6_API void vqt6_qwidget_unset_cursor(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->unsetCursor(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip) { + if (widget == nullptr || tip == nullptr) return; + static_cast(widget)->setToolTip(*static_cast(tip)); +} + +extern "C" VQT6_API void* vqt6_qwidget_tool_tip(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->toolTip()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip) { + if (widget == nullptr || tip == nullptr) return; + static_cast(widget)->setStatusTip(*static_cast(tip)); +} + +extern "C" VQT6_API void* vqt6_qwidget_status_tip(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->statusTip()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setMinimumSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setMaximumSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setFixedSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->minimumSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->maximumSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +// ============================================================ +// QDialog +// ============================================================ +extern "C" VQT6_API void* vqt6_qdialog_create(void) { + return new QDialog(); +} + +extern "C" VQT6_API void* vqt6_qdialog_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QDialog(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qdialog_exec(void* dialog) { + if (dialog == nullptr) return -1; + return static_cast(dialog)->exec(); +} + +extern "C" VQT6_API void vqt6_qdialog_done(void* dialog, int result) { + if (dialog == nullptr) return; + static_cast(dialog)->done(result); +} + +extern "C" VQT6_API void vqt6_qdialog_accept(void* dialog) { + if (dialog == nullptr) return; + static_cast(dialog)->accept(); +} + +extern "C" VQT6_API void vqt6_qdialog_reject(void* dialog) { + if (dialog == nullptr) return; + static_cast(dialog)->reject(); +} + +extern "C" VQT6_API void vqt6_qdialog_set_result(void* dialog, int result) { + if (dialog == nullptr) return; + static_cast(dialog)->setResult(result); +} + +extern "C" VQT6_API int vqt6_qdialog_result(void* dialog) { + if (dialog == nullptr) return 0; + return static_cast(dialog)->result(); +} + +extern "C" VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal) { + if (dialog == nullptr) return; + static_cast(dialog)->setModal(modal != 0); +} + +extern "C" VQT6_API int vqt6_qdialog_is_modal(void* dialog) { + if (dialog == nullptr) return 0; + return static_cast(dialog)->isModal() ? 1 : 0; +} + +// ============================================================ +// QMainWindow +// ============================================================ +extern "C" VQT6_API void* vqt6_qmainwindow_create(void) { + return new QMainWindow(); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QMainWindow(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget) { + if (mw == nullptr) return; + static_cast(mw)->setCentralWidget(static_cast(widget)); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_central_widget(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->centralWidget(); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->menuBar(); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar) { + if (mw == nullptr) return; + static_cast(mw)->setMenuBar(static_cast(menubar)); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_status_bar(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->statusBar(); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar) { + if (mw == nullptr) return; + static_cast(mw)->setStatusBar(static_cast(statusbar)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar) { + if (mw == nullptr) return; + static_cast(mw)->addToolBar(static_cast(toolbar)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw) { + if (mw == nullptr) return; + static_cast(mw)->addToolBarBreak(); +} + +// ============================================================ +// QLabel +// ============================================================ +extern "C" VQT6_API void* vqt6_qlabel_create(void) { + return new QLabel(); +} + +extern "C" VQT6_API void* vqt6_qlabel_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QLabel(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QLabel(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qlabel_set_text(void* label, void* text) { + if (label == nullptr || text == nullptr) return; + static_cast(label)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlabel_text(void* label) { + if (label == nullptr) return nullptr; + return new QString(static_cast(label)->text()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment) { + if (label == nullptr) return; + static_cast(label)->setAlignment(static_cast(alignment)); +} + +extern "C" VQT6_API int vqt6_qlabel_alignment(void* label) { + if (label == nullptr) return 0; + return static_cast(static_cast(label)->alignment()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap) { + if (label == nullptr || pixmap == nullptr) return; + static_cast(label)->setPixmap(*static_cast(pixmap)); +} + +extern "C" VQT6_API void* vqt6_qlabel_pixmap(void* label) { + if (label == nullptr) return nullptr; + return new QPixmap(static_cast(label)->pixmap()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_indent(void* label, int indent) { + if (label == nullptr) return; + static_cast(label)->setIndent(indent); +} + +extern "C" VQT6_API void vqt6_qlabel_set_margin(void* label, int margin) { + if (label == nullptr) return; + static_cast(label)->setMargin(margin); +} + +extern "C" VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap) { + if (label == nullptr) return; + static_cast(label)->setWordWrap(wrap != 0); +} + +extern "C" VQT6_API int vqt6_qlabel_word_wrap(void* label) { + if (label == nullptr) return 0; + return static_cast(label)->wordWrap() ? 1 : 0; +} + +// ============================================================ +// QPushButton +// ============================================================ +extern "C" VQT6_API void* vqt6_qpushbutton_create(void) { + return new QPushButton(); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QPushButton(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QPushButton(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text) { + if (btn == nullptr || text == nullptr) return; + static_cast(btn)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_text(void* btn) { + if (btn == nullptr) return nullptr; + return new QString(static_cast(btn)->text()); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon) { + if (btn == nullptr || icon == nullptr) return; + static_cast(btn)->setIcon(*static_cast(icon)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_icon(void* btn) { + if (btn == nullptr) return nullptr; + return new QIcon(static_cast(btn)->icon()); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default) { + if (btn == nullptr) return; + static_cast(btn)->setDefault(is_default != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_default(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isDefault() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat) { + if (btn == nullptr) return; + static_cast(btn)->setFlat(flat != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_flat(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isFlat() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable) { + if (btn == nullptr) return; + static_cast(btn)->setCheckable(checkable != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_checkable(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isCheckable() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked) { + if (btn == nullptr) return; + static_cast(btn)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_checked(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_click(void* btn) { + if (btn == nullptr) return; + static_cast(btn)->click(); +} + +// ============================================================ +// QLineEdit +// ============================================================ +extern "C" VQT6_API void* vqt6_qlineedit_create(void) { + return new QLineEdit(); +} + +extern "C" VQT6_API void* vqt6_qlineedit_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QLineEdit(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QLineEdit(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_text(void* le) { + if (le == nullptr) return nullptr; + return new QString(static_cast(le)->text()); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_text(void* le, void* text) { + if (le == nullptr || text == nullptr) return; + static_cast(le)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_placeholder_text(void* le) { + if (le == nullptr) return nullptr; + return new QString(static_cast(le)->placeholderText()); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text) { + if (le == nullptr || text == nullptr) return; + static_cast(le)->setPlaceholderText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max) { + if (le == nullptr) return; + static_cast(le)->setMaxLength(max); +} + +extern "C" VQT6_API int vqt6_qlineedit_max_length(void* le) { + if (le == nullptr) return 0; + return static_cast(le)->maxLength(); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro) { + if (le == nullptr) return; + static_cast(le)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qlineedit_is_read_only(void* le) { + if (le == nullptr) return 0; + return static_cast(le)->isReadOnly() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode) { + if (le == nullptr) return; + static_cast(le)->setEchoMode(static_cast(mode)); +} + +extern "C" VQT6_API int vqt6_qlineedit_echo_mode(void* le) { + if (le == nullptr) return 0; + return static_cast(static_cast(le)->echoMode()); +} + +extern "C" VQT6_API void vqt6_qlineedit_select_all(void* le) { + if (le == nullptr) return; + static_cast(le)->selectAll(); +} + +extern "C" VQT6_API void vqt6_qlineedit_clear(void* le) { + if (le == nullptr) return; + static_cast(le)->clear(); +} + +// ============================================================ +// QTextEdit / QPlainTextEdit +// ============================================================ +extern "C" VQT6_API void* vqt6_qtextedit_create(void) { + return new QTextEdit(); +} + +extern "C" VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTextEdit(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qtextedit_to_plain_text(void* te) { + if (te == nullptr) return nullptr; + return new QString(static_cast(te)->toPlainText()); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text) { + if (te == nullptr || text == nullptr) return; + static_cast(te)->setPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_html(void* te, void* html) { + if (te == nullptr || html == nullptr) return; + static_cast(te)->setHtml(*static_cast(html)); +} + +extern "C" VQT6_API void* vqt6_qtextedit_to_html(void* te) { + if (te == nullptr) return nullptr; + return new QString(static_cast(te)->toHtml()); +} + +extern "C" VQT6_API void vqt6_qtextedit_append(void* te, void* text) { + if (te == nullptr || text == nullptr) return; + static_cast(te)->append(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtextedit_clear(void* te) { + if (te == nullptr) return; + static_cast(te)->clear(); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro) { + if (te == nullptr) return; + static_cast(te)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qtextedit_is_read_only(void* te) { + if (te == nullptr) return 0; + return static_cast(te)->isReadOnly() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_create(void) { + return new QPlainTextEdit(); +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QPlainTextEdit(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte) { + if (pte == nullptr) return nullptr; + return new QString(static_cast(pte)->toPlainText()); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text) { + if (pte == nullptr || text == nullptr) return; + static_cast(pte)->setPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text) { + if (pte == nullptr || text == nullptr) return; + static_cast(pte)->appendPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_clear(void* pte) { + if (pte == nullptr) return; + static_cast(pte)->clear(); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro) { + if (pte == nullptr) return; + static_cast(pte)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qplaintextedit_line_count(void* pte) { + if (pte == nullptr) return 0; + return static_cast(pte)->blockCount(); +} + +// ============================================================ +// QCheckBox / QRadioButton +// ============================================================ +extern "C" VQT6_API void* vqt6_qcheckbox_create(void) { + return new QCheckBox(); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QCheckBox(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QCheckBox(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked) { + if (cb == nullptr) return; + static_cast(cb)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qcheckbox_is_checked(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_text(void* cb) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->text()); +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate) { + if (cb == nullptr) return; + static_cast(cb)->setTristate(tristate != 0); +} + +extern "C" VQT6_API int vqt6_qcheckbox_is_tristate(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isTristate() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create(void) { + return new QRadioButton(); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QRadioButton(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QRadioButton(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked) { + if (rb == nullptr) return; + static_cast(rb)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qradiobutton_is_checked(void* rb) { + if (rb == nullptr) return 0; + return static_cast(rb)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text) { + if (rb == nullptr || text == nullptr) return; + static_cast(rb)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_text(void* rb) { + if (rb == nullptr) return nullptr; + return new QString(static_cast(rb)->text()); +} + +// ============================================================ +// QComboBox +// ============================================================ +extern "C" VQT6_API void* vqt6_qcombobox_create(void) { + return new QComboBox(); +} + +extern "C" VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QComboBox(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->addItem(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items) { + if (cb == nullptr || items == nullptr) return; + static_cast(cb)->addItems(*static_cast(items)); +} + +extern "C" VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->insertItem(index, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index) { + if (cb == nullptr) return; + static_cast(cb)->removeItem(index); +} + +extern "C" VQT6_API void vqt6_qcombobox_clear(void* cb) { + if (cb == nullptr) return; + static_cast(cb)->clear(); +} + +extern "C" VQT6_API int vqt6_qcombobox_count(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->count(); +} + +extern "C" VQT6_API int vqt6_qcombobox_current_index(void* cb) { + if (cb == nullptr) return -1; + return static_cast(cb)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index) { + if (cb == nullptr) return; + static_cast(cb)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qcombobox_current_text(void* cb) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->currentText()); +} + +extern "C" VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->itemText(index)); +} + +extern "C" VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable) { + if (cb == nullptr) return; + static_cast(cb)->setEditable(editable != 0); +} + +extern "C" VQT6_API int vqt6_qcombobox_is_editable(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isEditable() ? 1 : 0; +} + +// ============================================================ +// QListWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qlistwidget_create(void) { + return new QListWidget(); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QListWidget(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text) { + if (lw == nullptr || text == nullptr) return; + static_cast(lw)->addItem(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items) { + if (lw == nullptr || items == nullptr) return; + static_cast(lw)->addItems(*static_cast(items)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text) { + if (lw == nullptr || text == nullptr) return; + static_cast(lw)->insertItem(row, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row) { + if (lw == nullptr) return; + static_cast(lw)->takeItem(row); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row) { + if (lw == nullptr) return nullptr; + return static_cast(lw)->takeItem(row); +} + +extern "C" VQT6_API void vqt6_qlistwidget_clear(void* lw) { + if (lw == nullptr) return; + static_cast(lw)->clear(); +} + +extern "C" VQT6_API int vqt6_qlistwidget_count(void* lw) { + if (lw == nullptr) return 0; + return static_cast(lw)->count(); +} + +extern "C" VQT6_API int vqt6_qlistwidget_current_row(void* lw) { + if (lw == nullptr) return -1; + return static_cast(lw)->currentRow(); +} + +extern "C" VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row) { + if (lw == nullptr) return; + static_cast(lw)->setCurrentRow(row); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw) { + if (lw == nullptr) return nullptr; + QListWidgetItem* it = static_cast(lw)->currentItem(); + if (it == nullptr) return nullptr; + return new QString(it->text()); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row) { + if (lw == nullptr) return nullptr; + QListWidgetItem* it = static_cast(lw)->item(row); + if (it == nullptr) return nullptr; + return new QString(it->text()); +} + +extern "C" VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text) { + if (lw == nullptr || text == nullptr) return; + QListWidgetItem* it = static_cast(lw)->item(row); + if (it != nullptr) it->setText(*static_cast(text)); +} + +// ============================================================ +// QProgressBar +// ============================================================ +extern "C" VQT6_API void* vqt6_qprogressbar_create(void) { + return new QProgressBar(); +} + +extern "C" VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QProgressBar(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value) { + if (pb == nullptr) return; + static_cast(pb)->setValue(value); +} + +extern "C" VQT6_API int vqt6_qprogressbar_value(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->value(); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min) { + if (pb == nullptr) return; + static_cast(pb)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max) { + if (pb == nullptr) return; + static_cast(pb)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max) { + if (pb == nullptr) return; + static_cast(pb)->setRange(min, max); +} + +extern "C" VQT6_API int vqt6_qprogressbar_minimum(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->minimum(); +} + +extern "C" VQT6_API int vqt6_qprogressbar_maximum(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->maximum(); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible) { + if (pb == nullptr) return; + static_cast(pb)->setTextVisible(visible != 0); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format) { + if (pb == nullptr || format == nullptr) return; + static_cast(pb)->setFormat(*static_cast(format)); +} + +extern "C" VQT6_API void vqt6_qprogressbar_reset(void* pb) { + if (pb == nullptr) return; + static_cast(pb)->reset(); +} + +// ============================================================ +// QSlider +// ============================================================ +extern "C" VQT6_API void* vqt6_qslider_create(void) { + return new QSlider(); +} + +extern "C" VQT6_API void* vqt6_qslider_create_with_orientation(int orientation) { + return new QSlider(static_cast(orientation)); +} + +extern "C" VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent) { + if (parent == nullptr) return nullptr; + return new QSlider(static_cast(orientation), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qslider_set_value(void* s, int value) { + if (s == nullptr) return; + static_cast(s)->setValue(value); +} + +extern "C" VQT6_API int vqt6_qslider_value(void* s) { + if (s == nullptr) return 0; + return static_cast(s)->value(); +} + +extern "C" VQT6_API void vqt6_qslider_set_minimum(void* s, int min) { + if (s == nullptr) return; + static_cast(s)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qslider_set_maximum(void* s, int max) { + if (s == nullptr) return; + static_cast(s)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qslider_set_range(void* s, int min, int max) { + if (s == nullptr) return; + static_cast(s)->setRange(min, max); +} + +extern "C" VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation) { + if (s == nullptr) return; + static_cast(s)->setOrientation(static_cast(orientation)); +} + +extern "C" VQT6_API int vqt6_qslider_orientation(void* s) { + if (s == nullptr) return 0; + return static_cast(static_cast(s)->orientation()); +} + +extern "C" VQT6_API void vqt6_qslider_set_single_step(void* s, int step) { + if (s == nullptr) return; + static_cast(s)->setSingleStep(step); +} + +extern "C" VQT6_API void vqt6_qslider_set_page_step(void* s, int step) { + if (s == nullptr) return; + static_cast(s)->setPageStep(step); +} + +// ============================================================ +// QSpinBox +// ============================================================ +extern "C" VQT6_API void* vqt6_qspinbox_create(void) { + return new QSpinBox(); +} + +extern "C" VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QSpinBox(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qspinbox_value(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->value(); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_value(void* sb, int value) { + if (sb == nullptr) return; + static_cast(sb)->setValue(value); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min) { + if (sb == nullptr) return; + static_cast(sb)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max) { + if (sb == nullptr) return; + static_cast(sb)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max) { + if (sb == nullptr) return; + static_cast(sb)->setRange(min, max); +} + +extern "C" VQT6_API int vqt6_qspinbox_minimum(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->minimum(); +} + +extern "C" VQT6_API int vqt6_qspinbox_maximum(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->maximum(); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step) { + if (sb == nullptr) return; + static_cast(sb)->setSingleStep(step); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix) { + if (sb == nullptr || prefix == nullptr) return; + static_cast(sb)->setPrefix(*static_cast(prefix)); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix) { + if (sb == nullptr || suffix == nullptr) return; + static_cast(sb)->setSuffix(*static_cast(suffix)); +} + +extern "C" VQT6_API void* vqt6_qspinbox_prefix(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->prefix()); +} + +extern "C" VQT6_API void* vqt6_qspinbox_suffix(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->suffix()); +} + +// ============================================================ +// Layouts +// ============================================================ +extern "C" VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget) { + if (layout == nullptr || widget == nullptr) return; + static_cast(layout)->addWidget(static_cast(widget)); +} + +extern "C" VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget) { + if (layout == nullptr || widget == nullptr) return; + static_cast(layout)->removeWidget(static_cast(widget)); +} + +extern "C" VQT6_API int vqt6_qlayout_count(void* layout) { + if (layout == nullptr) return 0; + return static_cast(layout)->count(); +} + +extern "C" VQT6_API void* vqt6_qlayout_item_at(void* layout, int index) { + if (layout == nullptr) return nullptr; + QLayoutItem* item = static_cast(layout)->itemAt(index); + return item != nullptr ? item->widget() : nullptr; +} + +extern "C" VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom) { + if (layout == nullptr) return; + static_cast(layout)->setContentsMargins(left, top, right, bottom); +} + +extern "C" VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing) { + if (layout == nullptr) return; + static_cast(layout)->setSpacing(spacing); +} + +extern "C" VQT6_API int vqt6_qlayout_spacing(void* layout) { + if (layout == nullptr) return 0; + return static_cast(layout)->spacing(); +} + +extern "C" VQT6_API void vqt6_qlayout_invalidate(void* layout) { + if (layout == nullptr) return; + static_cast(layout)->invalidate(); +} + +extern "C" VQT6_API void* vqt6_qhboxlayout_create(void) { + return new QHBoxLayout(); +} + +extern "C" VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QHBoxLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child) { + if (layout == nullptr || child == nullptr) return; + static_cast(layout)->addLayout(static_cast(child)); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch) { + if (layout == nullptr) return; + static_cast(layout)->addStretch(stretch); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size) { + if (layout == nullptr) return; + static_cast(layout)->addSpacing(size); +} + +extern "C" VQT6_API void* vqt6_qvboxlayout_create(void) { + return new QVBoxLayout(); +} + +extern "C" VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QVBoxLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child) { + if (layout == nullptr || child == nullptr) return; + static_cast(layout)->addLayout(static_cast(child)); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch) { + if (layout == nullptr) return; + static_cast(layout)->addStretch(stretch); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size) { + if (layout == nullptr) return; + static_cast(layout)->addSpacing(size); +} + +extern "C" VQT6_API void* vqt6_qgridlayout_create(void) { + return new QGridLayout(); +} + +extern "C" VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QGridLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col) { + if (gl == nullptr || w == nullptr) return; + static_cast(gl)->addWidget(static_cast(w), row, col); +} + +extern "C" VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span) { + if (gl == nullptr || w == nullptr) return; + static_cast(gl)->addWidget(static_cast(w), row, col, row_span, col_span); +} + +extern "C" VQT6_API void* vqt6_qformlayout_create(void) { + return new QFormLayout(); +} + +extern "C" VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QFormLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field) { + if (fl == nullptr || label == nullptr || field == nullptr) return; + static_cast(fl)->addRow(*static_cast(label), static_cast(field)); +} + +extern "C" VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field) { + if (fl == nullptr || label == nullptr || field == nullptr) return; + static_cast(fl)->addRow(static_cast(label), static_cast(field)); +} + +// ============================================================ +// QStackedWidget / QTabWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qstackedwidget_create(void) { + return new QStackedWidget(); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QStackedWidget(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w) { + if (sw == nullptr || w == nullptr) return -1; + return static_cast(sw)->addWidget(static_cast(w)); +} + +extern "C" VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w) { + if (sw == nullptr || w == nullptr) return; + static_cast(sw)->removeWidget(static_cast(w)); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_count(void* sw) { + if (sw == nullptr) return 0; + return static_cast(sw)->count(); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_current_index(void* sw) { + if (sw == nullptr) return -1; + return static_cast(sw)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index) { + if (sw == nullptr) return; + static_cast(sw)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw) { + if (sw == nullptr) return nullptr; + return static_cast(sw)->currentWidget(); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index) { + if (sw == nullptr) return nullptr; + return static_cast(sw)->widget(index); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_create(void) { + return new QTabWidget(); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTabWidget(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label) { + if (tw == nullptr || w == nullptr || label == nullptr) return -1; + return static_cast(tw)->addTab(static_cast(w), *static_cast(label)); +} + +extern "C" VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label) { + if (tw == nullptr || w == nullptr || label == nullptr) return -1; + return static_cast(tw)->insertTab(index, static_cast(w), *static_cast(label)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index) { + if (tw == nullptr) return; + static_cast(tw)->removeTab(index); +} + +extern "C" VQT6_API int vqt6_qtabwidget_count(void* tw) { + if (tw == nullptr) return 0; + return static_cast(tw)->count(); +} + +extern "C" VQT6_API int vqt6_qtabwidget_current_index(void* tw) { + if (tw == nullptr) return -1; + return static_cast(tw)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index) { + if (tw == nullptr) return; + static_cast(tw)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index) { + if (tw == nullptr) return nullptr; + return new QString(static_cast(tw)->tabText(index)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text) { + if (tw == nullptr || text == nullptr) return; + static_cast(tw)->setTabText(index, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable) { + if (tw == nullptr) return; + static_cast(tw)->setTabsClosable(closable != 0); +} + +extern "C" VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw) { + if (tw == nullptr) return 0; + return static_cast(tw)->tabsClosable() ? 1 : 0; +} + +// ============================================================ +// QMenuBar / QMenu / QAction +// ============================================================ +extern "C" VQT6_API void* vqt6_qmenubar_create(void) { + return new QMenuBar(); +} + +extern "C" VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QMenuBar(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title) { + if (mb == nullptr || title == nullptr) return nullptr; + return static_cast(mb)->addMenu(*static_cast(title)); +} + +extern "C" VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu) { + if (mb == nullptr || menu == nullptr) return; + static_cast(mb)->addMenu(static_cast(menu)); +} + +extern "C" VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action) { + if (mb == nullptr || action == nullptr) return; + static_cast(mb)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qmenubar_clear(void* mb) { + if (mb == nullptr) return; + static_cast(mb)->clear(); +} + +extern "C" VQT6_API void* vqt6_qmenu_create(void) { + return new QMenu(); +} + +extern "C" VQT6_API void* vqt6_qmenu_create_with_title(void* title) { + if (title == nullptr) return nullptr; + return new QMenu(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent) { + if (title == nullptr || parent == nullptr) return nullptr; + return new QMenu(*static_cast(title), static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title) { + if (menu == nullptr || title == nullptr) return nullptr; + return static_cast(menu)->addMenu(*static_cast(title)); +} + +extern "C" VQT6_API void vqt6_qmenu_add_action(void* menu, void* action) { + if (menu == nullptr || action == nullptr) return; + static_cast(menu)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qmenu_add_separator(void* menu) { + if (menu == nullptr) return; + static_cast(menu)->addSeparator(); +} + +extern "C" VQT6_API void vqt6_qmenu_clear(void* menu) { + if (menu == nullptr) return; + static_cast(menu)->clear(); +} + +extern "C" VQT6_API void vqt6_qmenu_set_title(void* menu, void* title) { + if (menu == nullptr || title == nullptr) return; + static_cast(menu)->setTitle(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qmenu_title(void* menu) { + if (menu == nullptr) return nullptr; + return new QString(static_cast(menu)->title()); +} + +extern "C" VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text) { + if (menu == nullptr || text == nullptr) return nullptr; + return static_cast(menu)->addAction(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_create(void) { + return new QAction(); +} + +extern "C" VQT6_API void* vqt6_qaction_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QAction(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QAction(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qaction_set_text(void* action, void* text) { + if (action == nullptr || text == nullptr) return; + static_cast(action)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_text(void* action) { + if (action == nullptr) return nullptr; + return new QString(static_cast(action)->text()); +} + +extern "C" VQT6_API void vqt6_qaction_set_icon(void* action, void* icon) { + if (action == nullptr || icon == nullptr) return; + static_cast(action)->setIcon(*static_cast(icon)); +} + +extern "C" VQT6_API void* vqt6_qaction_icon(void* action) { + if (action == nullptr) return nullptr; + return new QIcon(static_cast(action)->icon()); +} + +extern "C" VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence) { + if (action == nullptr || key_sequence == nullptr) return; + static_cast(action)->setShortcut(QKeySequence(*static_cast(key_sequence))); +} + +extern "C" VQT6_API void* vqt6_qaction_shortcut(void* action) { + if (action == nullptr) return nullptr; + return new QString(static_cast(action)->shortcut().toString()); +} + +extern "C" VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable) { + if (action == nullptr) return; + static_cast(action)->setCheckable(checkable != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_checkable(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isCheckable() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_set_checked(void* action, int checked) { + if (action == nullptr) return; + static_cast(action)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_checked(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled) { + if (action == nullptr) return; + static_cast(action)->setEnabled(enabled != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_enabled(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isEnabled() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_trigger(void* action) { + if (action == nullptr) return; + static_cast(action)->trigger(); +} + +// ============================================================ +// QStatusBar / QToolBar +// ============================================================ +extern "C" VQT6_API void* vqt6_qstatusbar_create(void) { + return new QStatusBar(); +} + +extern "C" VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QStatusBar(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms) { + if (sb == nullptr || message == nullptr) return; + static_cast(sb)->showMessage(*static_cast(message), timeout_ms); +} + +extern "C" VQT6_API void vqt6_qstatusbar_clear_message(void* sb) { + if (sb == nullptr) return; + static_cast(sb)->clearMessage(); +} + +extern "C" VQT6_API void* vqt6_qstatusbar_current_message(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->currentMessage()); +} + +extern "C" VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch) { + if (sb == nullptr || w == nullptr) return; + static_cast(sb)->addWidget(static_cast(w), stretch); +} + +extern "C" VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch) { + if (sb == nullptr || w == nullptr) return; + static_cast(sb)->addPermanentWidget(static_cast(w), stretch); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_create(void) { + return new QToolBar(); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QToolBar(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w) { + if (tb == nullptr || w == nullptr) return nullptr; + return static_cast(tb)->addWidget(static_cast(w)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action) { + if (tb == nullptr || action == nullptr) return; + static_cast(tb)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_add_separator(void* tb) { + if (tb == nullptr) return; + static_cast(tb)->addSeparator(); +} + +extern "C" VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h) { + if (tb == nullptr) return; + static_cast(tb)->setIconSize(QSize(w, h)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation) { + if (tb == nullptr) return; + static_cast(tb)->setOrientation(static_cast(orientation)); +} + +extern "C" VQT6_API int vqt6_qtoolbar_orientation(void* tb) { + if (tb == nullptr) return 0; + return static_cast(static_cast(tb)->orientation()); +} + +// ============================================================ +// QMessageBox +// ============================================================ +extern "C" VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0400), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0200), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0100), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0200), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text) { + if (title == nullptr || text == nullptr) return; + QMessageBox::about(static_cast(parent), *static_cast(title), *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qmessagebox_about_qt(void* parent) { + QMessageBox::aboutQt(static_cast(parent)); +} + +// ============================================================ +// QFileDialog +// ============================================================ +extern "C" VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter) { + QString* result = new QString(QFileDialog::getOpenFileName( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter) { + QString* result = new QString(QFileDialog::getSaveFileName( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir) { + QString* result = new QString(QFileDialog::getExistingDirectory( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter) { + return new QStringList(QFileDialog::getOpenFileNames( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); +} diff --git a/vqt6 copy/_bridge_widgets.h b/vqt6 copy/_bridge_widgets.h new file mode 100644 index 0000000..0197377 --- /dev/null +++ b/vqt6 copy/_bridge_widgets.h @@ -0,0 +1,432 @@ +// ============================================================ +// vqt6/_bridge_widgets.h — QtWidgets C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_WIDGETS_H +#define VQT6_BRIDGE_WIDGETS_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QApplication +// ============================================================ +VQT6_API void* vqt6_qapplication_create(int argc, char** argv); +VQT6_API void* vqt6_qapplication_instance(void); +VQT6_API int vqt6_qapplication_exec(void* app); +VQT6_API void vqt6_qapplication_quit(void* app); +VQT6_API void vqt6_qapplication_exit(void* app, int exit_code); +VQT6_API void vqt6_qapplication_process_events(void* app); +VQT6_API int vqt6_qapplication_desktop_width(void* app); +VQT6_API int vqt6_qapplication_desktop_height(void* app); +VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit); +VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app); + +// ============================================================ +// QWidget +// ============================================================ +VQT6_API void* vqt6_qwidget_create(void); +VQT6_API void* vqt6_qwidget_create_with_parent(void* parent); +VQT6_API void vqt6_qwidget_show(void* widget); +VQT6_API void vqt6_qwidget_hide(void* widget); +VQT6_API int vqt6_qwidget_close(void* widget); +VQT6_API int vqt6_qwidget_is_visible(void* widget); +VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible); +VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h); +VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h); +VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h); +VQT6_API void vqt6_qwidget_move(void* widget, int x, int y); +VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y); +VQT6_API int vqt6_qwidget_width(void* widget); +VQT6_API int vqt6_qwidget_height(void* widget); +VQT6_API int vqt6_qwidget_x(void* widget); +VQT6_API int vqt6_qwidget_y(void* widget); +VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title); +VQT6_API void* vqt6_qwidget_window_title(void* widget); +VQT6_API void vqt6_qwidget_set_text(void* widget, void* text); +VQT6_API void* vqt6_qwidget_text(void* widget); +VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled); +VQT6_API int vqt6_qwidget_is_enabled(void* widget); +VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent); +VQT6_API void* vqt6_qwidget_parent_widget(void* widget); +VQT6_API void vqt6_qwidget_set_focus(void* widget); +VQT6_API void vqt6_qwidget_clear_focus(void* widget); +VQT6_API int vqt6_qwidget_has_focus(void* widget); +VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy); +VQT6_API void vqt6_qwidget_update(void* widget); +VQT6_API void vqt6_qwidget_repaint(void* widget); +VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled); +VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags); +VQT6_API int vqt6_qwidget_window_flags(void* widget); +VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor); +VQT6_API void* vqt6_qwidget_cursor(void* widget); +VQT6_API void vqt6_qwidget_unset_cursor(void* widget); +VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip); +VQT6_API void* vqt6_qwidget_tool_tip(void* widget); +VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip); +VQT6_API void* vqt6_qwidget_status_tip(void* widget); +VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h); +VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h); + +// ============================================================ +// QDialog +// ============================================================ +VQT6_API void* vqt6_qdialog_create(void); +VQT6_API void* vqt6_qdialog_create_with_parent(void* parent); +VQT6_API int vqt6_qdialog_exec(void* dialog); +VQT6_API void vqt6_qdialog_done(void* dialog, int result); +VQT6_API void vqt6_qdialog_accept(void* dialog); +VQT6_API void vqt6_qdialog_reject(void* dialog); +VQT6_API void vqt6_qdialog_set_result(void* dialog, int result); +VQT6_API int vqt6_qdialog_result(void* dialog); +VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal); +VQT6_API int vqt6_qdialog_is_modal(void* dialog); + +// ============================================================ +// QMainWindow +// ============================================================ +VQT6_API void* vqt6_qmainwindow_create(void); +VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent); +VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget); +VQT6_API void* vqt6_qmainwindow_central_widget(void* mw); +VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw); +VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar); +VQT6_API void* vqt6_qmainwindow_status_bar(void* mw); +VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar); +VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar); +VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw); + +// ============================================================ +// QLabel +// ============================================================ +VQT6_API void* vqt6_qlabel_create(void); +VQT6_API void* vqt6_qlabel_create_with_text(void* text); +VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qlabel_set_text(void* label, void* text); +VQT6_API void* vqt6_qlabel_text(void* label); +VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment); +VQT6_API int vqt6_qlabel_alignment(void* label); +VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap); +VQT6_API void* vqt6_qlabel_pixmap(void* label); +VQT6_API void vqt6_qlabel_set_indent(void* label, int indent); +VQT6_API void vqt6_qlabel_set_margin(void* label, int margin); +VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap); +VQT6_API int vqt6_qlabel_word_wrap(void* label); + +// ============================================================ +// QPushButton +// ============================================================ +VQT6_API void* vqt6_qpushbutton_create(void); +VQT6_API void* vqt6_qpushbutton_create_with_text(void* text); +VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text); +VQT6_API void* vqt6_qpushbutton_text(void* btn); +VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon); +VQT6_API void* vqt6_qpushbutton_icon(void* btn); +VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default); +VQT6_API int vqt6_qpushbutton_is_default(void* btn); +VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat); +VQT6_API int vqt6_qpushbutton_is_flat(void* btn); +VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable); +VQT6_API int vqt6_qpushbutton_is_checkable(void* btn); +VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked); +VQT6_API int vqt6_qpushbutton_is_checked(void* btn); +VQT6_API void vqt6_qpushbutton_click(void* btn); + +// ============================================================ +// QLineEdit +// ============================================================ +VQT6_API void* vqt6_qlineedit_create(void); +VQT6_API void* vqt6_qlineedit_create_with_text(void* text); +VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent); +VQT6_API void* vqt6_qlineedit_text(void* le); +VQT6_API void vqt6_qlineedit_set_text(void* le, void* text); +VQT6_API void* vqt6_qlineedit_placeholder_text(void* le); +VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text); +VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max); +VQT6_API int vqt6_qlineedit_max_length(void* le); +VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro); +VQT6_API int vqt6_qlineedit_is_read_only(void* le); +VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode); +VQT6_API int vqt6_qlineedit_echo_mode(void* le); +VQT6_API void vqt6_qlineedit_select_all(void* le); +VQT6_API void vqt6_qlineedit_clear(void* le); + +// ============================================================ +// QTextEdit / QPlainTextEdit +// ============================================================ +VQT6_API void* vqt6_qtextedit_create(void); +VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent); +VQT6_API void* vqt6_qtextedit_to_plain_text(void* te); +VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text); +VQT6_API void vqt6_qtextedit_set_html(void* te, void* html); +VQT6_API void* vqt6_qtextedit_to_html(void* te); +VQT6_API void vqt6_qtextedit_append(void* te, void* text); +VQT6_API void vqt6_qtextedit_clear(void* te); +VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro); +VQT6_API int vqt6_qtextedit_is_read_only(void* te); + +VQT6_API void* vqt6_qplaintextedit_create(void); +VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent); +VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte); +VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text); +VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text); +VQT6_API void vqt6_qplaintextedit_clear(void* pte); +VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro); +VQT6_API int vqt6_qplaintextedit_line_count(void* pte); + +// ============================================================ +// QCheckBox / QRadioButton +// ============================================================ +VQT6_API void* vqt6_qcheckbox_create(void); +VQT6_API void* vqt6_qcheckbox_create_with_text(void* text); +VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked); +VQT6_API int vqt6_qcheckbox_is_checked(void* cb); +VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text); +VQT6_API void* vqt6_qcheckbox_text(void* cb); +VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate); +VQT6_API int vqt6_qcheckbox_is_tristate(void* cb); + +VQT6_API void* vqt6_qradiobutton_create(void); +VQT6_API void* vqt6_qradiobutton_create_with_text(void* text); +VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked); +VQT6_API int vqt6_qradiobutton_is_checked(void* rb); +VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text); +VQT6_API void* vqt6_qradiobutton_text(void* rb); + +// ============================================================ +// QComboBox +// ============================================================ +VQT6_API void* vqt6_qcombobox_create(void); +VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent); +VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text); +VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items); +VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text); +VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index); +VQT6_API void vqt6_qcombobox_clear(void* cb); +VQT6_API int vqt6_qcombobox_count(void* cb); +VQT6_API int vqt6_qcombobox_current_index(void* cb); +VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index); +VQT6_API void* vqt6_qcombobox_current_text(void* cb); +VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index); +VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable); +VQT6_API int vqt6_qcombobox_is_editable(void* cb); + +// ============================================================ +// QListWidget +// ============================================================ +VQT6_API void* vqt6_qlistwidget_create(void); +VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent); +VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text); +VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items); +VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text); +VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row); +VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row); +VQT6_API void vqt6_qlistwidget_clear(void* lw); +VQT6_API int vqt6_qlistwidget_count(void* lw); +VQT6_API int vqt6_qlistwidget_current_row(void* lw); +VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row); +VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw); +VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row); +VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text); + +// ============================================================ +// QProgressBar +// ============================================================ +VQT6_API void* vqt6_qprogressbar_create(void); +VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent); +VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value); +VQT6_API int vqt6_qprogressbar_value(void* pb); +VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min); +VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max); +VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max); +VQT6_API int vqt6_qprogressbar_minimum(void* pb); +VQT6_API int vqt6_qprogressbar_maximum(void* pb); +VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible); +VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format); +VQT6_API void vqt6_qprogressbar_reset(void* pb); + +// ============================================================ +// QSlider +// ============================================================ +VQT6_API void* vqt6_qslider_create(void); +VQT6_API void* vqt6_qslider_create_with_orientation(int orientation); +VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent); +VQT6_API void vqt6_qslider_set_value(void* s, int value); +VQT6_API int vqt6_qslider_value(void* s); +VQT6_API void vqt6_qslider_set_minimum(void* s, int min); +VQT6_API void vqt6_qslider_set_maximum(void* s, int max); +VQT6_API void vqt6_qslider_set_range(void* s, int min, int max); +VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation); +VQT6_API int vqt6_qslider_orientation(void* s); +VQT6_API void vqt6_qslider_set_single_step(void* s, int step); +VQT6_API void vqt6_qslider_set_page_step(void* s, int step); + +// ============================================================ +// QSpinBox +// ============================================================ +VQT6_API void* vqt6_qspinbox_create(void); +VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent); +VQT6_API int vqt6_qspinbox_value(void* sb); +VQT6_API void vqt6_qspinbox_set_value(void* sb, int value); +VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min); +VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max); +VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max); +VQT6_API int vqt6_qspinbox_minimum(void* sb); +VQT6_API int vqt6_qspinbox_maximum(void* sb); +VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step); +VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix); +VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix); +VQT6_API void* vqt6_qspinbox_prefix(void* sb); +VQT6_API void* vqt6_qspinbox_suffix(void* sb); + +// ============================================================ +// Layouts +// ============================================================ +VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget); +VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget); +VQT6_API int vqt6_qlayout_count(void* layout); +VQT6_API void* vqt6_qlayout_item_at(void* layout, int index); +VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom); +VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing); +VQT6_API int vqt6_qlayout_spacing(void* layout); +VQT6_API void vqt6_qlayout_invalidate(void* layout); + +VQT6_API void* vqt6_qhboxlayout_create(void); +VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child); +VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch); +VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size); + +VQT6_API void* vqt6_qvboxlayout_create(void); +VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child); +VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch); +VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size); + +VQT6_API void* vqt6_qgridlayout_create(void); +VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col); +VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span); + +VQT6_API void* vqt6_qformlayout_create(void); +VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field); +VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field); + +// ============================================================ +// QStackedWidget / QTabWidget +// ============================================================ +VQT6_API void* vqt6_qstackedwidget_create(void); +VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent); +VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w); +VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w); +VQT6_API int vqt6_qstackedwidget_count(void* sw); +VQT6_API int vqt6_qstackedwidget_current_index(void* sw); +VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index); +VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw); +VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index); + +VQT6_API void* vqt6_qtabwidget_create(void); +VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent); +VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label); +VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label); +VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index); +VQT6_API int vqt6_qtabwidget_count(void* tw); +VQT6_API int vqt6_qtabwidget_current_index(void* tw); +VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index); +VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index); +VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text); +VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable); +VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw); + +// ============================================================ +// QMenuBar / QMenu / QAction +// ============================================================ +VQT6_API void* vqt6_qmenubar_create(void); +VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent); +VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title); +VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu); +VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action); +VQT6_API void vqt6_qmenubar_clear(void* mb); + +VQT6_API void* vqt6_qmenu_create(void); +VQT6_API void* vqt6_qmenu_create_with_title(void* title); +VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent); +VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title); +VQT6_API void vqt6_qmenu_add_action(void* menu, void* action); +VQT6_API void vqt6_qmenu_add_separator(void* menu); +VQT6_API void vqt6_qmenu_clear(void* menu); +VQT6_API void vqt6_qmenu_set_title(void* menu, void* title); +VQT6_API void* vqt6_qmenu_title(void* menu); +VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text); + +VQT6_API void* vqt6_qaction_create(void); +VQT6_API void* vqt6_qaction_create_with_text(void* text); +VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qaction_set_text(void* action, void* text); +VQT6_API void* vqt6_qaction_text(void* action); +VQT6_API void vqt6_qaction_set_icon(void* action, void* icon); +VQT6_API void* vqt6_qaction_icon(void* action); +VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence); +VQT6_API void* vqt6_qaction_shortcut(void* action); +VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable); +VQT6_API int vqt6_qaction_is_checkable(void* action); +VQT6_API void vqt6_qaction_set_checked(void* action, int checked); +VQT6_API int vqt6_qaction_is_checked(void* action); +VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled); +VQT6_API int vqt6_qaction_is_enabled(void* action); +VQT6_API void vqt6_qaction_trigger(void* action); + +// ============================================================ +// QStatusBar / QToolBar +// ============================================================ +VQT6_API void* vqt6_qstatusbar_create(void); +VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent); +VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms); +VQT6_API void vqt6_qstatusbar_clear_message(void* sb); +VQT6_API void* vqt6_qstatusbar_current_message(void* sb); +VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch); +VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch); + +VQT6_API void* vqt6_qtoolbar_create(void); +VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent); +VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w); +VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action); +VQT6_API void vqt6_qtoolbar_add_separator(void* tb); +VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h); +VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation); +VQT6_API int vqt6_qtoolbar_orientation(void* tb); + +// ============================================================ +// QMessageBox +// ============================================================ +VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons); +VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text); +VQT6_API void vqt6_qmessagebox_about_qt(void* parent); + +// ============================================================ +// QFileDialog +// ============================================================ +VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter); +VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter); +VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir); +VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_WIDGETS_H diff --git a/vqt6 copy/_qtcore.vp b/vqt6 copy/_qtcore.vp new file mode 100644 index 0000000..ddb7035 --- /dev/null +++ b/vqt6 copy/_qtcore.vp @@ -0,0 +1,157 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtcore.py — QtCore 的 t.State FFI 声明 +# +# 所有函数都是 C 桥接层 (libvqt6_bridge.a) 的 extern "C" 函数 +# 命名规范: vqt6__ +# ============================================================ + +# ============================================================ +# QString — UTF-16 字符串 +# ============================================================ +# 创建 QString(从 UTF-8 C 字符串) +def vqt6_qstring_create(utf8: t.CChar | t.CPtr) -> QtStringPtr | t.State: pass + +# 获取 QString 的 UTF-8 表示(写入 buf,返回实际长度,不含 \0) +# buf 需足够大(建议 4 * qstring.length() + 1) +def vqt6_qstring_to_utf8(qstr: QtStringPtr, buf: t.CChar | t.CPtr, buf_size: t.CSizeT) -> t.CSizeT | t.State: pass + +# 释放 QString +def vqt6_qstring_free(qstr: QtStringPtr) -> t.State: pass + +# 获取 QString 字符数 +def vqt6_qstring_length(qstr: QtStringPtr) -> t.CInt | t.State: pass + +# QString 是否为空 +def vqt6_qstring_is_empty(qstr: QtStringPtr) -> t.CInt | t.State: pass + +# QString 比较 +def vqt6_qstring_equals(qstr: QtStringPtr, other: QtStringPtr) -> t.CInt | t.State: pass + +# QString 拼接(返回新 QString) +def vqt6_qstring_append(qstr: QtStringPtr, other: QtStringPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# QByteArray — 字节数组 +# ============================================================ +def vqt6_qbytearray_create(data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearray_data(qba: QtByteArrayPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qbytearray_size(qba: QtByteArrayPtr) -> t.CSizeT | t.State: pass +def vqt6_qbytearray_free(qba: QtByteArrayPtr) -> t.State: pass + + +# ============================================================ +# QObject — 所有 Qt 对象的基类 +# ============================================================ +# 注意: Qt 对象的内存由 C++ 管理,Viper 端不应直接 free +def vqt6_qobject_delete(obj: QtObjectPtr) -> t.State: pass +def vqt6_qobject_delete_later(obj: QtObjectPtr) -> t.State: pass +def vqt6_qobject_set_object_name(obj: QtObjectPtr, name: QtStringPtr) -> t.State: pass +def vqt6_qobject_object_name(obj: QtObjectPtr) -> QtStringPtr | t.State: pass +def vqt6_qobject_set_parent(child: QtObjectPtr, parent: QtObjectPtr) -> t.State: pass +def vqt6_qobject_parent(obj: QtObjectPtr) -> QtObjectPtr | t.State: pass + +# 信号/槽连接 (简化版: 函数指针形式) +# typedef void (*vqt6_callback_t)(void* user_data); +# vqt6_qobject_connect_typed(sender, signal_id, receiver, slot_id, type) 由 C++ 桥接层处理 +# 由于函数指针在 C ABI 中复杂,我们采用字符串 signal/slot 名 + 全局回调注册表 +def vqt6_qobject_connect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, + receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass + +def vqt6_qobject_disconnect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, + receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass + +# 事件过滤器 +def vqt6_qobject_install_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass +def vqt6_qobject_remove_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass + + +# ============================================================ +# QCoreApplication — 事件循环基类 +# ============================================================ +def vqt6_qcoreapp_create(app_name: t.CChar | t.CPtr) -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_instance() -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_exec(app: QtCoreAppPtr) -> t.CInt | t.State: pass +def vqt6_qcoreapp_quit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qcoreapp_exit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qcoreapp_process_events(app: QtCoreAppPtr, flags: t.CInt) -> t.State: pass +def vqt6_qcoreapp_post_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.State: pass +def vqt6_qcoreapp_send_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.CInt | t.State: pass +def vqt6_qcoreapp_organization_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass +def vqt6_qcoreapp_set_organization_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass +def vqt6_qcoreapp_application_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass +def vqt6_qcoreapp_set_application_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass + + +# ============================================================ +# QTimer — 定时器 +# ============================================================ +def vqt6_qtimer_create() -> QtTimerPtr | t.State: pass +def vqt6_qtimer_create_with_parent(parent: QtObjectPtr) -> QtTimerPtr | t.State: pass +def vqt6_qtimer_start(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass +def vqt6_qtimer_stop(timer: QtTimerPtr) -> t.State: pass +def vqt6_qtimer_set_interval(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass +def vqt6_qtimer_interval(timer: QtTimerPtr) -> t.CInt | t.State: pass +def vqt6_qtimer_is_active(timer: QtTimerPtr) -> t.CInt | t.State: pass +def vqt6_qtimer_set_single_shot(timer: QtTimerPtr, single_shot: t.CInt) -> t.State: pass +def vqt6_qtimer_is_single_shot(timer: QtTimerPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QVariant — 通用数据容器 +# ============================================================ +def vqt6_qvariant_create_int(value: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_double(value: t.CDouble) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_bool(value: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_string(s: QtStringPtr) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_to_int(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_to_double(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CDouble | t.State: pass +def vqt6_qvariant_to_bool(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_to_string(v: QtVariantPtr) -> QtStringPtr | t.State: pass +def vqt6_qvariant_type_id(v: QtVariantPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_is_valid(v: QtVariantPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_free(v: QtVariantPtr) -> t.State: pass + + +# ============================================================ +# QEvent — 事件基类 +# ============================================================ +def vqt6_qevent_type(event: QtEventPtr) -> t.CInt | t.State: pass +def vqt6_qevent_accept(event: QtEventPtr) -> t.State: pass +def vqt6_qevent_ignore(event: QtEventPtr) -> t.State: pass +def vqt6_qevent_is_accepted(event: QtEventPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 字符串列表 (QStringList / QList) +# ============================================================ +def vqt6_qstringlist_create() -> QtStringListPtr | t.State: pass +def vqt6_qstringlist_append(list: QtStringListPtr, str: QtStringPtr) -> t.State: pass +def vqt6_qstringlist_size(list: QtStringListPtr) -> t.CInt | t.State: pass +def vqt6_qstringlist_at(list: QtStringListPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qstringlist_free(list: QtStringListPtr) -> t.State: pass + + +# ============================================================ +# 字节数组列表 (QList) +# ============================================================ +def vqt6_qbytearraylist_create() -> QtByteArrayListPtr | t.State: pass +def vqt6_qbytearraylist_append(list: QtByteArrayListPtr, qba: QtByteArrayPtr) -> t.State: pass +def vqt6_qbytearraylist_size(list: QtByteArrayListPtr) -> t.CInt | t.State: pass +def vqt6_qbytearraylist_at(list: QtByteArrayListPtr, index: t.CInt) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearraylist_free(list: QtByteArrayListPtr) -> t.State: pass + + +# ============================================================ +# 全局回调注册表 +# ============================================================ +# 用于从 C++ 端回调 Viper 代码 +# Viper 注册一个 slot 函数(用整数 ID 标识),C++ 在触发信号时通过 ID 查找 +# typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data); +def vqt6_register_slot(slot_id: t.CInt, user_data: t.CVoid | t.CPtr) -> t.State: pass +def vqt6_unregister_slot(slot_id: t.CInt) -> t.State: pass +def vqt6_trigger_slot(slot_id: t.CInt) -> t.State: pass # 测试用 diff --git a/vqt6 copy/_qtgui.vp b/vqt6 copy/_qtgui.vp new file mode 100644 index 0000000..80f0094 --- /dev/null +++ b/vqt6 copy/_qtgui.vp @@ -0,0 +1,237 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtgui.py — QtGui 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QColor — 颜色 +# ============================================================ +def vqt6_qcolor_create_rgb(r: t.CInt, g: t.CInt, b: t.CInt) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_rgba(r: t.CInt, g: t.CInt, b: t.CInt, a: t.CInt) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_name(name: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_hex(hex_str: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qcolor_red(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_green(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_blue(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_alpha(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_set_red(c: QtColorPtr, r: t.CInt) -> t.State: pass +def vqt6_qcolor_set_green(c: QtColorPtr, g: t.CInt) -> t.State: pass +def vqt6_qcolor_set_blue(c: QtColorPtr, b: t.CInt) -> t.State: pass +def vqt6_qcolor_set_alpha(c: QtColorPtr, a: t.CInt) -> t.State: pass +def vqt6_qcolor_set_rgb(c: QtColorPtr, r: t.CInt, g: t.CInt, b: t.CInt) -> t.State: pass +def vqt6_qcolor_set_rgba(c: QtColorPtr, r: t.CInt, g: t.CInt, b: t.CInt, a: t.CInt) -> t.State: pass +def vqt6_qcolor_name(c: QtColorPtr) -> QtStringPtr | t.State: pass +def vqt6_qcolor_is_valid(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_free(c: QtColorPtr) -> t.State: pass + + +# ============================================================ +# QFont — 字体 +# ============================================================ +def vqt6_qfont_create() -> QtFontPtr | t.State: pass +def vqt6_qfont_create_with_family(family: QtStringPtr) -> QtFontPtr | t.State: pass +def vqt6_qfont_create_with_family_size(family: QtStringPtr, point_size: t.CInt) -> QtFontPtr | t.State: pass +def vqt6_qfont_set_family(font: QtFontPtr, family: QtStringPtr) -> t.State: pass +def vqt6_qfont_family(font: QtFontPtr) -> QtStringPtr | t.State: pass +def vqt6_qfont_set_point_size(font: QtFontPtr, point_size: t.CInt) -> t.State: pass +def vqt6_qfont_point_size(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_pixel_size(font: QtFontPtr, pixel_size: t.CInt) -> t.State: pass +def vqt6_qfont_pixel_size(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_bold(font: QtFontPtr, bold: t.CInt) -> t.State: pass +def vqt6_qfont_bold(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_italic(font: QtFontPtr, italic: t.CInt) -> t.State: pass +def vqt6_qfont_italic(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_underline(font: QtFontPtr, underline: t.CInt) -> t.State: pass +def vqt6_qfont_underline(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_strike_out(font: QtFontPtr, strike_out: t.CInt) -> t.State: pass +def vqt6_qfont_strike_out(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_weight(font: QtFontPtr, weight: t.CInt) -> t.State: pass +def vqt6_qfont_weight(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_free(font: QtFontPtr) -> t.State: pass + + +# ============================================================ +# QFontMetrics — 字体度量 +# ============================================================ +def vqt6_qfontmetrics_create(font: QtFontPtr) -> QtFontMetricsPtr | t.State: pass +def vqt6_qfontmetrics_width(fm: QtFontMetricsPtr, text: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_height(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_ascent(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_descent(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_free(fm: QtFontMetricsPtr) -> t.State: pass + + +# ============================================================ +# QPixmap — 像素图 +# ============================================================ +def vqt6_qpixmap_create() -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_create_with_size(w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_load(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_load_from_data(pm: QtPixmapPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CInt | t.State: pass +def vqt6_qpixmap_save(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_width(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_height(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_is_null(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_scaled(pm: QtPixmapPtr, w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_fill(pm: QtPixmapPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qpixmap_free(pm: QtPixmapPtr) -> t.State: pass + + +# ============================================================ +# QImage — 图像 +# ============================================================ +def vqt6_qimage_create() -> QtImagePtr | t.State: pass +def vqt6_qimage_create_with_size(w: t.CInt, h: t.CInt, format: t.CInt) -> QtImagePtr | t.State: pass +def vqt6_qimage_load(img: QtImagePtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qimage_save(img: QtImagePtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qimage_width(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_height(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_format(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_is_null(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_fill(img: QtImagePtr, color: QtColorPtr) -> t.State: pass +def vqt6_qimage_scaled(img: QtImagePtr, w: t.CInt, h: t.CInt) -> QtImagePtr | t.State: pass +def vqt6_qimage_free(img: QtImagePtr) -> t.State: pass + + +# ============================================================ +# QPainter — 绘画器 +# ============================================================ +def vqt6_qpainter_create() -> QtPainterPtr | t.State: pass +def vqt6_qpainter_begin(p: QtPainterPtr, device: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_end(p: QtPainterPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_is_active(p: QtPainterPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_set_pen(p: QtPainterPtr, pen: QtPenPtr) -> t.State: pass +def vqt6_qpainter_set_brush(p: QtPainterPtr, brush: QtBrushPtr) -> t.State: pass +def vqt6_qpainter_set_font(p: QtPainterPtr, font: QtFontPtr) -> t.State: pass +def vqt6_qpainter_pen(p: QtPainterPtr) -> QtPenPtr | t.State: pass +def vqt6_qpainter_brush(p: QtPainterPtr) -> QtBrushPtr | t.State: pass +def vqt6_qpainter_font(p: QtPainterPtr) -> QtFontPtr | t.State: pass +def vqt6_qpainter_set_opacity(p: QtPainterPtr, opacity: t.CDouble) -> t.State: pass +def vqt6_qpainter_opacity(p: QtPainterPtr) -> t.CDouble | t.State: pass + +# 绘图原语 +def vqt6_qpainter_draw_line(p: QtPainterPtr, x1: t.CInt, y1: t.CInt, x2: t.CInt, y2: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qpainter_fill_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, color: QtColorPtr) -> t.State: pass +def vqt6_qpainter_draw_ellipse(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_arc(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_chord(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_pie(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_polygon(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_polyline(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_point(p: QtPainterPtr, x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_points(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_text(p: QtPainterPtr, x: t.CInt, y: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qpainter_draw_text_in_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, flags: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qpainter_draw_pixmap(p: QtPainterPtr, x: t.CInt, y: t.CInt, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qpainter_draw_image(p: QtPainterPtr, x: t.CInt, y: t.CInt, image: QtImagePtr) -> t.State: pass +def vqt6_qpainter_draw_tiled_pixmap(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, pixmap: QtPixmapPtr) -> t.State: pass + +# 变换 +def vqt6_qpainter_translate(p: QtPainterPtr, dx: t.CInt, dy: t.CInt) -> t.State: pass +def vqt6_qpainter_rotate(p: QtPainterPtr, angle: t.CDouble) -> t.State: pass +def vqt6_qpainter_scale(p: QtPainterPtr, sx: t.CDouble, sy: t.CDouble) -> t.State: pass +def vqt6_qpainter_reset_transform(p: QtPainterPtr) -> t.State: pass +def vqt6_qpainter_save(p: QtPainterPtr) -> t.State: pass +def vqt6_qpainter_restore(p: QtPainterPtr) -> t.State: pass + +def vqt6_qpainter_free(p: QtPainterPtr) -> t.State: pass + + +# ============================================================ +# QPen — 画笔 +# ============================================================ +def vqt6_qpen_create() -> QtPenPtr | t.State: pass +def vqt6_qpen_create_with_color(color: QtColorPtr) -> QtPenPtr | t.State: pass +def vqt6_qpen_create_with_color_width(color: QtColorPtr, width: t.CInt) -> QtPenPtr | t.State: pass +def vqt6_qpen_set_color(pen: QtPenPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qpen_color(pen: QtPenPtr) -> QtColorPtr | t.State: pass +def vqt6_qpen_set_width(pen: QtPenPtr, width: t.CInt) -> t.State: pass +def vqt6_qpen_width(pen: QtPenPtr) -> t.CInt | t.State: pass +def vqt6_qpen_set_style(pen: QtPenPtr, style: t.CInt) -> t.State: pass +def vqt6_qpen_style(pen: QtPenPtr) -> t.CInt | t.State: pass +def vqt6_qpen_free(pen: QtPenPtr) -> t.State: pass + + +# ============================================================ +# QBrush — 画刷 +# ============================================================ +def vqt6_qbrush_create() -> QtBrushPtr | t.State: pass +def vqt6_qbrush_create_with_color(color: QtColorPtr) -> QtBrushPtr | t.State: pass +def vqt6_qbrush_create_with_style(style: t.CInt) -> QtBrushPtr | t.State: pass +def vqt6_qbrush_set_color(brush: QtBrushPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qbrush_color(brush: QtBrushPtr) -> QtColorPtr | t.State: pass +def vqt6_qbrush_set_style(brush: QtBrushPtr, style: t.CInt) -> t.State: pass +def vqt6_qbrush_style(brush: QtBrushPtr) -> t.CInt | t.State: pass +def vqt6_qbrush_free(brush: QtBrushPtr) -> t.State: pass + + +# ============================================================ +# QIcon — 图标 +# ============================================================ +def vqt6_qicon_create() -> QtIconPtr | t.State: pass +def vqt6_qicon_create_with_file(file_name: QtStringPtr) -> QtIconPtr | t.State: pass +def vqt6_qicon_add_file(icon: QtIconPtr, file_name: QtStringPtr) -> t.State: pass +def vqt6_qicon_add_pixmap(icon: QtIconPtr, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qicon_is_null(icon: QtIconPtr) -> t.CInt | t.State: pass +def vqt6_qicon_pixmap(icon: QtIconPtr, w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qicon_free(icon: QtIconPtr) -> t.State: pass + + +# ============================================================ +# QCursor — 鼠标光标 +# ============================================================ +def vqt6_qcursor_create() -> QtCursorPtr | t.State: pass +def vqt6_qcursor_create_with_shape(shape: t.CInt) -> QtCursorPtr | t.State: pass +def vqt6_qcursor_pos(x: t.CInt | t.CPtr, y: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qcursor_set_pos(x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qcursor_set_shape(cursor: QtCursorPtr, shape: t.CInt) -> t.State: pass +def vqt6_qcursor_shape(cursor: QtCursorPtr) -> t.CInt | t.State: pass +def vqt6_qcursor_free(cursor: QtCursorPtr) -> t.State: pass + + +# ============================================================ +# QKeyEvent — 键盘事件 +# ============================================================ +def vqt6_qkeyevent_create(type: t.CInt, key: t.CInt, modifiers: t.CInt, text: QtStringPtr) -> QtKeyEventPtr | t.State: pass +def vqt6_qkeyevent_key(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_text(event: QtKeyEventPtr) -> QtStringPtr | t.State: pass +def vqt6_qkeyevent_modifiers(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_is_auto_repeat(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_free(event: QtKeyEventPtr) -> t.State: pass + + +# ============================================================ +# QMouseEvent — 鼠标事件 +# ============================================================ +def vqt6_qmouseevent_create(type: t.CInt, local_pos: QtObjectPtr, button: t.CInt, buttons: t.CInt, modifiers: t.CInt) -> QtMouseEventPtr | t.State: pass +def vqt6_qmouseevent_button(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_buttons(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_x(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_y(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_global_x(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_global_y(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_modifiers(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_free(event: QtMouseEventPtr) -> t.State: pass + + +# ============================================================ +# QResizeEvent / QPaintEvent / QCloseEvent +# ============================================================ +def vqt6_qresizeevent_create(width: t.CInt, height: t.CInt, old_width: t.CInt, old_height: t.CInt) -> QtResizeEventPtr | t.State: pass +def vqt6_qresizeevent_size(event: QtResizeEventPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qresizeevent_old_size(event: QtResizeEventPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qresizeevent_free(event: QtResizeEventPtr) -> t.State: pass + +def vqt6_qpaintevent_create(rect_x: t.CInt, rect_y: t.CInt, rect_w: t.CInt, rect_h: t.CInt) -> QtPaintEventPtr | t.State: pass +def vqt6_qpaintevent_rect(event: QtPaintEventPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qpaintevent_free(event: QtPaintEventPtr) -> t.State: pass + +def vqt6_qcloseevent_create() -> QtCloseEventPtr | t.State: pass +def vqt6_qcloseevent_is_accepted(event: QtCloseEventPtr) -> t.CInt | t.State: pass +def vqt6_qcloseevent_accept(event: QtCloseEventPtr) -> t.State: pass +def vqt6_qcloseevent_ignore(event: QtCloseEventPtr) -> t.State: pass +def vqt6_qcloseevent_free(event: QtCloseEventPtr) -> t.State: pass diff --git a/vqt6 copy/_qtnetwork.vp b/vqt6 copy/_qtnetwork.vp new file mode 100644 index 0000000..6859d8b --- /dev/null +++ b/vqt6 copy/_qtnetwork.vp @@ -0,0 +1,184 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtnetwork.py — QtNetwork 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QHostAddress — IP 地址 +# ============================================================ +def vqt6_qhostaddress_create() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_ipv4(ipv4: t.CUInt32T) -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_string(address: QtStringPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_local_host() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_local_ipv4() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_broadcast() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_any_ipv4() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_to_string(addr: QtHostAddressPtr) -> QtStringPtr | t.State: pass +def vqt6_qhostaddress_to_ipv4(addr: QtHostAddressPtr) -> t.CUInt32T | t.State: pass +def vqt6_qhostaddress_is_null(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_is_loopback(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_is_broadcast(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_protocol(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_free(addr: QtHostAddressPtr) -> t.State: pass + + +# ============================================================ +# QAbstractSocket — TCP/UDP 套接字基类 +# ============================================================ +# 套接字状态 +QT_SOCKET_UNCONNECTED_STATE: t.CDefine = 0 +QT_SOCKET_HOST_LOOKUP_STATE: t.CDefine = 1 +QT_SOCKET_CONNECTING_STATE: t.CDefine = 2 +QT_SOCKET_CONNECTED_STATE: t.CDefine = 3 +QT_SOCKET_BOUND_STATE: t.CDefine = 4 +QT_SOCKET_LISTENING_STATE: t.CDefine = 5 +QT_SOCKET_CLOSING_STATE: t.CDefine = 6 + +# 套接字类型 +QT_SOCKET_TCP: t.CDefine = 0 +QT_SOCKET_UDP: t.CDefine = 1 + +# 套接字错误 +QT_SOCKET_NO_ERROR: t.CDefine = 0 + +# 通用方法 +def vqt6_qabstractsocket_state(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_error(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_error_string(socket: QtAbstractSocketPtr) -> QtStringPtr | t.State: pass +def vqt6_qabstractsocket_connect_to_host(socket: QtAbstractSocketPtr, host_name: QtStringPtr, port: t.CUInt16T) -> t.State: pass +def vqt6_qabstractsocket_connect_to_host_with_addr(socket: QtAbstractSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.State: pass +def vqt6_qabstractsocket_disconnect_from_host(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_wait_for_connected(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_ready_read(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_bytes_written(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_disconnected(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_is_valid(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_is_open(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_flush(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_close(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_abort(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_read(socket: QtAbstractSocketPtr, buf: t.CVoid | t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_read_all(socket: QtAbstractSocketPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qabstractsocket_write(socket: QtAbstractSocketPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_bytes_available(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_bytes_to_write(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_peer_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qabstractsocket_peer_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass +def vqt6_qabstractsocket_local_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qabstractsocket_local_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass + + +# ============================================================ +# QTcpSocket — TCP 套接字 +# ============================================================ +def vqt6_qtcpsocket_create() -> QtTcpSocketPtr | t.State: pass +def vqt6_qtcpsocket_create_with_parent(parent: QtObjectPtr) -> QtTcpSocketPtr | t.State: pass +def vqt6_qtcpsocket_connect_to_host(socket: QtTcpSocketPtr, host_name: QtStringPtr, port: t.CUInt16T, mode: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_connect_to_host_with_addr(socket: QtTcpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T, mode: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_set_socket_descriptor(socket: QtTcpSocketPtr, socket_descriptor: t.CInt) -> t.CInt | t.State: pass +def vqt6_qtcpsocket_socket_descriptor(socket: QtTcpSocketPtr) -> t.CInt | t.State: pass +def vqt6_qtcpsocket_set_proxy(socket: QtTcpSocketPtr, proxy_type: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_abort(socket: QtTcpSocketPtr) -> t.State: pass + + +# ============================================================ +# QUdpSocket — UDP 套接字 +# ============================================================ +def vqt6_qudpsocket_create() -> QtUdpSocketPtr | t.State: pass +def vqt6_qudpsocket_create_with_parent(parent: QtObjectPtr) -> QtUdpSocketPtr | t.State: pass +def vqt6_qudpsocket_bind(socket: QtUdpSocketPtr, port: t.CUInt16T) -> t.CInt | t.State: pass +def vqt6_qudpsocket_bind_with_addr(socket: QtUdpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.CInt | t.State: pass +def vqt6_qudpsocket_close(socket: QtUdpSocketPtr) -> t.State: pass +def vqt6_qudpsocket_write_datagram(socket: QtUdpSocketPtr, data: t.CVoid | t.CPtr, size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_read_datagram(socket: QtUdpSocketPtr, data: t.CVoid | t.CPtr, max_size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T | t.CPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_has_pending_datagrams(socket: QtUdpSocketPtr) -> t.CInt | t.State: pass +def vqt6_qudpsocket_pending_datagram_size(socket: QtUdpSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_join_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qudpsocket_leave_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QNetworkRequest — 网络请求 +# ============================================================ +def vqt6_qnetworkrequest_create() -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkrequest_create_with_url(url: QtStringPtr) -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkrequest_set_url(req: QtNetworkRequestPtr, url: QtStringPtr) -> t.State: pass +def vqt6_qnetworkrequest_url(req: QtNetworkRequestPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkrequest_set_header(req: QtNetworkRequestPtr, header_type: t.CInt, value: QtVariantPtr) -> t.State: pass +def vqt6_qnetworkrequest_header(req: QtNetworkRequestPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkrequest_set_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, value: t.CVoid | t.CPtr, value_size: t.CSizeT) -> t.State: pass +def vqt6_qnetworkrequest_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkrequest_set_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt, value: QtVariantPtr) -> t.State: pass +def vqt6_qnetworkrequest_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkrequest_free(req: QtNetworkRequestPtr) -> t.State: pass + + +# ============================================================ +# QNetworkAccessManager — HTTP 客户端管理器 +# ============================================================ +def vqt6_qnetworkaccessmanager_create() -> QtNetworkAccessManagerPtr | t.State: pass +def vqt6_qnetworkaccessmanager_create_with_parent(parent: QtObjectPtr) -> QtNetworkAccessManagerPtr | t.State: pass +def vqt6_qnetworkaccessmanager_get(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_post(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_put(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_delete_resource(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_head(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_set_cookie_store(nam: QtNetworkAccessManagerPtr, store: QtObjectPtr) -> t.State: pass + + +# ============================================================ +# QNetworkReply — 网络响应 +# ============================================================ +def vqt6_qnetworkreply_url(reply: QtNetworkReplyPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkreply_request(reply: QtNetworkReplyPtr) -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkreply_error(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_error_string(reply: QtNetworkReplyPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkreply_is_finished(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_is_running(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_abort(reply: QtNetworkReplyPtr) -> t.State: pass +def vqt6_qnetworkreply_read(reply: QtNetworkReplyPtr, buf: t.CVoid | t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_read_all(reply: QtNetworkReplyPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkreply_bytes_available(reply: QtNetworkReplyPtr) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_header(reply: QtNetworkReplyPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkreply_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkreply_attribute(reply: QtNetworkReplyPtr, attribute_code: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkreply_attribute_int(reply: QtNetworkReplyPtr, attribute_code: t.CInt, default_value: t.CInt) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_set_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, value: t.CVoid | t.CPtr, value_size: t.CSizeT) -> t.State: pass + + +# ============================================================ +# 套接字类型枚举 +# ============================================================ +# 套接字类型 +QT_ABSTRACT_SOCKET_TCP: t.CDefine = 0 +QT_ABSTRACT_SOCKET_UDP: t.CDefine = 1 + +# 网络层协议 +QT_NETWORK_IPV4_PROTOCOL: t.CDefine = 0 +QT_NETWORK_IPV6_PROTOCOL: t.CDefine = 1 +QT_NETWORK_ANY_IP_PROTOCOL: t.CDefine = 2 + +# 主机地址特殊情况 +QT_HOST_ADDRESS_LOCAL_HOST: t.CDefine = 0x00000000 +QT_HOST_ADDRESS_LOCAL_HOST_IPV6: t.CDefine = 0x00000001 +QT_HOST_ADDRESS_BROADCAST: t.CDefine = 0x00000002 +QT_HOST_ADDRESS_ANY_IPV4: t.CDefine = 0x00000004 +QT_HOST_ADDRESS_ANY_IPV6: t.CDefine = 0x00000005 + + +# ============================================================ +# 已知端口常量 +# ============================================================ +QT_PORT_FTP: t.CDefine = 21 +QT_PORT_SSH: t.CDefine = 22 +QT_PORT_TELNET: t.CDefine = 23 +QT_PORT_SMTP: t.CDefine = 25 +QT_PORT_DNS: t.CDefine = 53 +QT_PORT_HTTP: t.CDefine = 80 +QT_PORT_POP3: t.CDefine = 110 +QT_PORT_IMAP: t.CDefine = 143 +QT_PORT_HTTPS: t.CDefine = 443 +QT_PORT_SMB: t.CDefine = 445 diff --git a/vqt6 copy/_qtwidgets.vp b/vqt6 copy/_qtwidgets.vp new file mode 100644 index 0000000..025d026 --- /dev/null +++ b/vqt6 copy/_qtwidgets.vp @@ -0,0 +1,478 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtwidgets.py — QtWidgets 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QApplication — GUI 应用入口 +# ============================================================ +# argc/argv 通过单独的 buffer 数组传入(Viper 中 C 数组使用指针+长度) +def vqt6_qapplication_create(argc: t.CInt, argv: t.CPtr | t.CPtr) -> QtAppPtr | t.State: pass +def vqt6_qapplication_instance() -> QtAppPtr | t.State: pass +def vqt6_qapplication_exec(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_quit(app: QtAppPtr) -> t.State: pass +def vqt6_qapplication_exit(app: QtAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qapplication_process_events(app: QtAppPtr) -> t.State: pass +def vqt6_qapplication_desktop_width(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_desktop_height(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_set_quit_on_last_window_closed(app: QtAppPtr, quit: t.CInt) -> t.State: pass +def vqt6_qapplication_quit_on_last_window_closed(app: QtAppPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QWidget — 所有窗口的基类 +# ============================================================ +def vqt6_qwidget_create() -> QtWidgetPtr | t.State: pass +def vqt6_qwidget_create_with_parent(parent: QtWidgetPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qwidget_show(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_hide(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_close(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_is_visible(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_set_visible(widget: QtWidgetPtr, visible: t.CInt) -> t.State: pass + +# 几何 +def vqt6_qwidget_set_geometry(widget: QtWidgetPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_geometry(widget: QtWidgetPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_resize(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_move(widget: QtWidgetPtr, x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qwidget_pos(widget: QtWidgetPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_width(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_height(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_x(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_y(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 文本与标题 +def vqt6_qwidget_set_window_title(widget: QtWidgetPtr, title: QtStringPtr) -> t.State: pass +def vqt6_qwidget_window_title(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass +def vqt6_qwidget_set_text(widget: QtWidgetPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qwidget_text(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 启用 +def vqt6_qwidget_set_enabled(widget: QtWidgetPtr, enabled: t.CInt) -> t.State: pass +def vqt6_qwidget_is_enabled(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 父对象 +def vqt6_qwidget_set_parent(widget: QtWidgetPtr, parent: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_parent_widget(widget: QtWidgetPtr) -> QtWidgetPtr | t.State: pass + +# 焦点 +def vqt6_qwidget_set_focus(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_clear_focus(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_has_focus(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_set_focus_policy(widget: QtWidgetPtr, policy: t.CInt) -> t.State: pass + +# 更新 +def vqt6_qwidget_update(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_repaint(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_set_update_enabled(widget: QtWidgetPtr, enabled: t.CInt) -> t.State: pass + +# 窗口标志 +def vqt6_qwidget_set_window_flags(widget: QtWidgetPtr, flags: t.CInt) -> t.State: pass +def vqt6_qwidget_window_flags(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 鼠标光标 +def vqt6_qwidget_set_cursor(widget: QtWidgetPtr, cursor: QtCursorPtr) -> t.State: pass +def vqt6_qwidget_cursor(widget: QtWidgetPtr) -> QtCursorPtr | t.State: pass +def vqt6_qwidget_unset_cursor(widget: QtWidgetPtr) -> t.State: pass + +# 工具提示 +def vqt6_qwidget_set_tool_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass +def vqt6_qwidget_tool_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 状态栏提示 +def vqt6_qwidget_set_status_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass +def vqt6_qwidget_status_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 最小/最大尺寸 +def vqt6_qwidget_set_minimum_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_set_maximum_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_set_fixed_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_minimum_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_maximum_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass + + +# ============================================================ +# QDialog — 对话框 +# ============================================================ +def vqt6_qdialog_create() -> QtDialogPtr | t.State: pass +def vqt6_qdialog_create_with_parent(parent: QtWidgetPtr) -> QtDialogPtr | t.State: pass +def vqt6_qdialog_exec(dialog: QtDialogPtr) -> t.CInt | t.State: pass +def vqt6_qdialog_done(dialog: QtDialogPtr, result: t.CInt) -> t.State: pass +def vqt6_qdialog_accept(dialog: QtDialogPtr) -> t.State: pass +def vqt6_qdialog_reject(dialog: QtDialogPtr) -> t.State: pass +def vqt6_qdialog_set_result(dialog: QtDialogPtr, result: t.CInt) -> t.State: pass +def vqt6_qdialog_result(dialog: QtDialogPtr) -> t.CInt | t.State: pass +def vqt6_qdialog_set_modal(dialog: QtDialogPtr, modal: t.CInt) -> t.State: pass +def vqt6_qdialog_is_modal(dialog: QtDialogPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMainWindow — 主窗口 +# ============================================================ +def vqt6_qmainwindow_create() -> QtMainWindowPtr | t.State: pass +def vqt6_qmainwindow_create_with_parent(parent: QtWidgetPtr) -> QtMainWindowPtr | t.State: pass +def vqt6_qmainwindow_set_central_widget(mw: QtMainWindowPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qmainwindow_central_widget(mw: QtMainWindowPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qmainwindow_menu_bar(mw: QtMainWindowPtr) -> QtMenuBarPtr | t.State: pass +def vqt6_qmainwindow_set_menu_bar(mw: QtMainWindowPtr, menubar: QtMenuBarPtr) -> t.State: pass +def vqt6_qmainwindow_status_bar(mw: QtMainWindowPtr) -> QtStatusBarPtr | t.State: pass +def vqt6_qmainwindow_set_status_bar(mw: QtMainWindowPtr, statusbar: QtStatusBarPtr) -> t.State: pass +def vqt6_qmainwindow_add_tool_bar(mw: QtMainWindowPtr, toolbar: QtToolBarPtr) -> t.State: pass +def vqt6_qmainwindow_add_tool_bar_break(mw: QtMainWindowPtr) -> t.State: pass + + +# ============================================================ +# QLabel — 标签 +# ============================================================ +def vqt6_qlabel_create() -> QtLabelPtr | t.State: pass +def vqt6_qlabel_create_with_text(text: QtStringPtr) -> QtLabelPtr | t.State: pass +def vqt6_qlabel_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLabelPtr | t.State: pass +def vqt6_qlabel_set_text(label: QtLabelPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlabel_text(label: QtLabelPtr) -> QtStringPtr | t.State: pass +def vqt6_qlabel_set_alignment(label: QtLabelPtr, alignment: t.CInt) -> t.State: pass +def vqt6_qlabel_alignment(label: QtLabelPtr) -> t.CInt | t.State: pass +def vqt6_qlabel_set_pixmap(label: QtLabelPtr, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qlabel_pixmap(label: QtLabelPtr) -> QtPixmapPtr | t.State: pass +def vqt6_qlabel_set_indent(label: QtLabelPtr, indent: t.CInt) -> t.State: pass +def vqt6_qlabel_set_margin(label: QtLabelPtr, margin: t.CInt) -> t.State: pass +def vqt6_qlabel_set_word_wrap(label: QtLabelPtr, wrap: t.CInt) -> t.State: pass +def vqt6_qlabel_word_wrap(label: QtLabelPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QPushButton — 按钮 +# ============================================================ +def vqt6_qpushbutton_create() -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_create_with_text(text: QtStringPtr) -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_set_text(btn: QtPushButtonPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qpushbutton_text(btn: QtPushButtonPtr) -> QtStringPtr | t.State: pass +def vqt6_qpushbutton_set_icon(btn: QtPushButtonPtr, icon: QtIconPtr) -> t.State: pass +def vqt6_qpushbutton_icon(btn: QtPushButtonPtr) -> QtIconPtr | t.State: pass +def vqt6_qpushbutton_set_default(btn: QtPushButtonPtr, is_default: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_default(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_flat(btn: QtPushButtonPtr, flat: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_flat(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_checkable(btn: QtPushButtonPtr, checkable: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_checkable(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_checked(btn: QtPushButtonPtr, checked: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_checked(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_click(btn: QtPushButtonPtr) -> t.State: pass + + +# ============================================================ +# QLineEdit — 单行输入框 +# ============================================================ +def vqt6_qlineedit_create() -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_create_with_text(text: QtStringPtr) -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_text(le: QtLineEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qlineedit_set_text(le: QtLineEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlineedit_placeholder_text(le: QtLineEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qlineedit_set_placeholder_text(le: QtLineEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlineedit_set_max_length(le: QtLineEditPtr, max: t.CInt) -> t.State: pass +def vqt6_qlineedit_max_length(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_set_read_only(le: QtLineEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qlineedit_is_read_only(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_set_echo_mode(le: QtLineEditPtr, mode: t.CInt) -> t.State: pass +def vqt6_qlineedit_echo_mode(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_select_all(le: QtLineEditPtr) -> t.State: pass +def vqt6_qlineedit_clear(le: QtLineEditPtr) -> t.State: pass + + +# ============================================================ +# QTextEdit / QPlainTextEdit — 多行文本编辑器 +# ============================================================ +def vqt6_qtextedit_create() -> QtTextEditPtr | t.State: pass +def vqt6_qtextedit_create_with_parent(parent: QtWidgetPtr) -> QtTextEditPtr | t.State: pass +def vqt6_qtextedit_to_plain_text(te: QtTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qtextedit_set_plain_text(te: QtTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_set_html(te: QtTextEditPtr, html: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_to_html(te: QtTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qtextedit_append(te: QtTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_clear(te: QtTextEditPtr) -> t.State: pass +def vqt6_qtextedit_set_read_only(te: QtTextEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qtextedit_is_read_only(te: QtTextEditPtr) -> t.CInt | t.State: pass + +def vqt6_qplaintextedit_create() -> QtPlainTextEditPtr | t.State: pass +def vqt6_qplaintextedit_create_with_parent(parent: QtWidgetPtr) -> QtPlainTextEditPtr | t.State: pass +def vqt6_qplaintextedit_to_plain_text(pte: QtPlainTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qplaintextedit_set_plain_text(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qplaintextedit_append(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qplaintextedit_clear(pte: QtPlainTextEditPtr) -> t.State: pass +def vqt6_qplaintextedit_set_read_only(pte: QtPlainTextEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qplaintextedit_line_count(pte: QtPlainTextEditPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QCheckBox / QRadioButton — 复选/单选 +# ============================================================ +def vqt6_qcheckbox_create() -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_create_with_text(text: QtStringPtr) -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_set_checked(cb: QtCheckBoxPtr, checked: t.CInt) -> t.State: pass +def vqt6_qcheckbox_is_checked(cb: QtCheckBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcheckbox_set_text(cb: QtCheckBoxPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qcheckbox_text(cb: QtCheckBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qcheckbox_set_tristate(cb: QtCheckBoxPtr, tristate: t.CInt) -> t.State: pass +def vqt6_qcheckbox_is_tristate(cb: QtCheckBoxPtr) -> t.CInt | t.State: pass + +def vqt6_qradiobutton_create() -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_create_with_text(text: QtStringPtr) -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_set_checked(rb: QtRadioButtonPtr, checked: t.CInt) -> t.State: pass +def vqt6_qradiobutton_is_checked(rb: QtRadioButtonPtr) -> t.CInt | t.State: pass +def vqt6_qradiobutton_set_text(rb: QtRadioButtonPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qradiobutton_text(rb: QtRadioButtonPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# QComboBox — 下拉框 +# ============================================================ +def vqt6_qcombobox_create() -> QtComboBoxPtr | t.State: pass +def vqt6_qcombobox_create_with_parent(parent: QtWidgetPtr) -> QtComboBoxPtr | t.State: pass +def vqt6_qcombobox_add_item(cb: QtComboBoxPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qcombobox_add_items(cb: QtComboBoxPtr, items: QtStringListPtr) -> t.State: pass +def vqt6_qcombobox_insert_item(cb: QtComboBoxPtr, index: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qcombobox_remove_item(cb: QtComboBoxPtr, index: t.CInt) -> t.State: pass +def vqt6_qcombobox_clear(cb: QtComboBoxPtr) -> t.State: pass +def vqt6_qcombobox_count(cb: QtComboBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcombobox_current_index(cb: QtComboBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcombobox_set_current_index(cb: QtComboBoxPtr, index: t.CInt) -> t.State: pass +def vqt6_qcombobox_current_text(cb: QtComboBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qcombobox_item_text(cb: QtComboBoxPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qcombobox_set_editable(cb: QtComboBoxPtr, editable: t.CInt) -> t.State: pass +def vqt6_qcombobox_is_editable(cb: QtComboBoxPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QListWidget — 列表控件 +# ============================================================ +def vqt6_qlistwidget_create() -> QtListWidgetPtr | t.State: pass +def vqt6_qlistwidget_create_with_parent(parent: QtWidgetPtr) -> QtListWidgetPtr | t.State: pass +def vqt6_qlistwidget_add_item(lw: QtListWidgetPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlistwidget_add_items(lw: QtListWidgetPtr, items: QtStringListPtr) -> t.State: pass +def vqt6_qlistwidget_insert_item(lw: QtListWidgetPtr, row: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qlistwidget_remove_item_widget(lw: QtListWidgetPtr, row: t.CInt) -> t.State: pass +def vqt6_qlistwidget_take_item(lw: QtListWidgetPtr, row: t.CInt) -> QtListWidgetItemPtr | t.State: pass +def vqt6_qlistwidget_clear(lw: QtListWidgetPtr) -> t.State: pass +def vqt6_qlistwidget_count(lw: QtListWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qlistwidget_current_row(lw: QtListWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qlistwidget_set_current_row(lw: QtListWidgetPtr, row: t.CInt) -> t.State: pass +def vqt6_qlistwidget_current_item_text(lw: QtListWidgetPtr) -> QtStringPtr | t.State: pass +def vqt6_qlistwidget_item_text(lw: QtListWidgetPtr, row: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qlistwidget_set_item_text(lw: QtListWidgetPtr, row: t.CInt, text: QtStringPtr) -> t.State: pass + + +# ============================================================ +# QProgressBar — 进度条 +# ============================================================ +def vqt6_qprogressbar_create() -> QtProgressBarPtr | t.State: pass +def vqt6_qprogressbar_create_with_parent(parent: QtWidgetPtr) -> QtProgressBarPtr | t.State: pass +def vqt6_qprogressbar_set_value(pb: QtProgressBarPtr, value: t.CInt) -> t.State: pass +def vqt6_qprogressbar_value(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_set_minimum(pb: QtProgressBarPtr, min: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_maximum(pb: QtProgressBarPtr, max: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_range(pb: QtProgressBarPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qprogressbar_minimum(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_maximum(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_set_text_visible(pb: QtProgressBarPtr, visible: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_format(pb: QtProgressBarPtr, format: QtStringPtr) -> t.State: pass +def vqt6_qprogressbar_reset(pb: QtProgressBarPtr) -> t.State: pass + + +# ============================================================ +# QSlider — 滑块 +# ============================================================ +def vqt6_qslider_create() -> QtSliderPtr | t.State: pass +def vqt6_qslider_create_with_orientation(orientation: t.CInt) -> QtSliderPtr | t.State: pass +def vqt6_qslider_create_with_orientation_parent(orientation: t.CInt, parent: QtWidgetPtr) -> QtSliderPtr | t.State: pass +def vqt6_qslider_set_value(s: QtSliderPtr, value: t.CInt) -> t.State: pass +def vqt6_qslider_value(s: QtSliderPtr) -> t.CInt | t.State: pass +def vqt6_qslider_set_minimum(s: QtSliderPtr, min: t.CInt) -> t.State: pass +def vqt6_qslider_set_maximum(s: QtSliderPtr, max: t.CInt) -> t.State: pass +def vqt6_qslider_set_range(s: QtSliderPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qslider_set_orientation(s: QtSliderPtr, orientation: t.CInt) -> t.State: pass +def vqt6_qslider_orientation(s: QtSliderPtr) -> t.CInt | t.State: pass +def vqt6_qslider_set_single_step(s: QtSliderPtr, step: t.CInt) -> t.State: pass +def vqt6_qslider_set_page_step(s: QtSliderPtr, step: t.CInt) -> t.State: pass + + +# ============================================================ +# QSpinBox — 数字输入框 +# ============================================================ +def vqt6_qspinbox_create() -> QtSpinBoxPtr | t.State: pass +def vqt6_qspinbox_create_with_parent(parent: QtWidgetPtr) -> QtSpinBoxPtr | t.State: pass +def vqt6_qspinbox_value(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_set_value(sb: QtSpinBoxPtr, value: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_minimum(sb: QtSpinBoxPtr, min: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_maximum(sb: QtSpinBoxPtr, max: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_range(sb: QtSpinBoxPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qspinbox_minimum(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_maximum(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_set_single_step(sb: QtSpinBoxPtr, step: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_prefix(sb: QtSpinBoxPtr, prefix: QtStringPtr) -> t.State: pass +def vqt6_qspinbox_set_suffix(sb: QtSpinBoxPtr, suffix: QtStringPtr) -> t.State: pass +def vqt6_qspinbox_prefix(sb: QtSpinBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qspinbox_suffix(sb: QtSpinBoxPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# 布局 - QLayout / QBoxLayout / QGridLayout / QFormLayout +# ============================================================ +def vqt6_qlayout_add_widget(layout: QtLayoutPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qlayout_remove_widget(layout: QtLayoutPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qlayout_count(layout: QtLayoutPtr) -> t.CInt | t.State: pass +def vqt6_qlayout_item_at(layout: QtLayoutPtr, index: t.CInt) -> QtWidgetPtr | t.State: pass +def vqt6_qlayout_set_contents_margins(layout: QtLayoutPtr, left: t.CInt, top: t.CInt, right: t.CInt, bottom: t.CInt) -> t.State: pass +def vqt6_qlayout_set_spacing(layout: QtLayoutPtr, spacing: t.CInt) -> t.State: pass +def vqt6_qlayout_spacing(layout: QtLayoutPtr) -> t.CInt | t.State: pass +def vqt6_qlayout_invalidate(layout: QtLayoutPtr) -> t.State: pass + +# QHBoxLayout +def vqt6_qhboxlayout_create() -> QtBoxLayoutPtr | t.State: pass +def vqt6_qhboxlayout_create_with_parent(parent: QtWidgetPtr) -> QtBoxLayoutPtr | t.State: pass +def vqt6_qhboxlayout_add_layout(layout: QtBoxLayoutPtr, child: QtLayoutPtr) -> t.State: pass +def vqt6_qhboxlayout_add_stretch(layout: QtBoxLayoutPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qhboxlayout_add_spacing(layout: QtBoxLayoutPtr, size: t.CInt) -> t.State: pass + +# QVBoxLayout +def vqt6_qvboxlayout_create() -> QtBoxLayoutPtr | t.State: pass +def vqt6_qvboxlayout_create_with_parent(parent: QtWidgetPtr) -> QtBoxLayoutPtr | t.State: pass +def vqt6_qvboxlayout_add_layout(layout: QtBoxLayoutPtr, child: QtLayoutPtr) -> t.State: pass +def vqt6_qvboxlayout_add_stretch(layout: QtBoxLayoutPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qvboxlayout_add_spacing(layout: QtBoxLayoutPtr, size: t.CInt) -> t.State: pass + +# QGridLayout +def vqt6_qgridlayout_create() -> QtGridLayoutPtr | t.State: pass +def vqt6_qgridlayout_create_with_parent(parent: QtWidgetPtr) -> QtGridLayoutPtr | t.State: pass +def vqt6_qgridlayout_add_widget(gl: QtGridLayoutPtr, w: QtWidgetPtr, row: t.CInt, col: t.CInt) -> t.State: pass +def vqt6_qgridlayout_add_widget_with_span(gl: QtGridLayoutPtr, w: QtWidgetPtr, row: t.CInt, col: t.CInt, row_span: t.CInt, col_span: t.CInt) -> t.State: pass + +# QFormLayout +def vqt6_qformlayout_create() -> QtFormLayoutPtr | t.State: pass +def vqt6_qformlayout_create_with_parent(parent: QtWidgetPtr) -> QtFormLayoutPtr | t.State: pass +def vqt6_qformlayout_add_row(fl: QtFormLayoutPtr, label: QtStringPtr, field: QtWidgetPtr) -> t.State: pass +def vqt6_qformlayout_add_row_widget_pair(fl: QtFormLayoutPtr, label: QtWidgetPtr, field: QtWidgetPtr) -> t.State: pass + + +# ============================================================ +# QStackedWidget / QTabWidget +# ============================================================ +def vqt6_qstackedwidget_create() -> QtStackedWidgetPtr | t.State: pass +def vqt6_qstackedwidget_create_with_parent(parent: QtWidgetPtr) -> QtStackedWidgetPtr | t.State: pass +def vqt6_qstackedwidget_add_widget(sw: QtStackedWidgetPtr, w: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_remove_widget(sw: QtStackedWidgetPtr, w: QtWidgetPtr) -> t.State: pass +def vqt6_qstackedwidget_count(sw: QtStackedWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_current_index(sw: QtStackedWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_set_current_index(sw: QtStackedWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qstackedwidget_current_widget(sw: QtStackedWidgetPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qstackedwidget_widget(sw: QtStackedWidgetPtr, index: t.CInt) -> QtWidgetPtr | t.State: pass + +def vqt6_qtabwidget_create() -> QtTabWidgetPtr | t.State: pass +def vqt6_qtabwidget_create_with_parent(parent: QtWidgetPtr) -> QtTabWidgetPtr | t.State: pass +def vqt6_qtabwidget_add_tab(tw: QtTabWidgetPtr, w: QtWidgetPtr, label: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_insert_tab(tw: QtTabWidgetPtr, index: t.CInt, w: QtWidgetPtr, label: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_remove_tab(tw: QtTabWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qtabwidget_count(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_current_index(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_set_current_index(tw: QtTabWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qtabwidget_tab_text(tw: QtTabWidgetPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qtabwidget_set_tab_text(tw: QtTabWidgetPtr, index: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qtabwidget_set_tabs_closable(tw: QtTabWidgetPtr, closable: t.CInt) -> t.State: pass +def vqt6_qtabwidget_tabs_closable(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMenuBar / QMenu / QAction +# ============================================================ +def vqt6_qmenubar_create() -> QtMenuBarPtr | t.State: pass +def vqt6_qmenubar_create_with_parent(parent: QtWidgetPtr) -> QtMenuBarPtr | t.State: pass +def vqt6_qmenubar_add_menu(mb: QtMenuBarPtr, title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenubar_add_menu_with_menu(mb: QtMenuBarPtr, menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenubar_add_action(mb: QtMenuBarPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qmenubar_clear(mb: QtMenuBarPtr) -> t.State: pass + +def vqt6_qmenu_create() -> QtMenuPtr | t.State: pass +def vqt6_qmenu_create_with_title(title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_create_with_title_parent(title: QtStringPtr, parent: QtWidgetPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_add_menu(menu: QtMenuPtr, title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_add_action(menu: QtMenuPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qmenu_add_separator(menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenu_clear(menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenu_set_title(menu: QtMenuPtr, title: QtStringPtr) -> t.State: pass +def vqt6_qmenu_title(menu: QtMenuPtr) -> QtStringPtr | t.State: pass +def vqt6_qmenu_add_action_with_text(menu: QtMenuPtr, text: QtStringPtr) -> QtActionPtr | t.State: pass + +def vqt6_qaction_create() -> QtActionPtr | t.State: pass +def vqt6_qaction_create_with_text(text: QtStringPtr) -> QtActionPtr | t.State: pass +def vqt6_qaction_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtActionPtr | t.State: pass +def vqt6_qaction_set_text(action: QtActionPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qaction_text(action: QtActionPtr) -> QtStringPtr | t.State: pass +def vqt6_qaction_set_icon(action: QtActionPtr, icon: QtIconPtr) -> t.State: pass +def vqt6_qaction_icon(action: QtActionPtr) -> QtIconPtr | t.State: pass +def vqt6_qaction_set_shortcut(action: QtActionPtr, key_sequence: QtStringPtr) -> t.State: pass +def vqt6_qaction_shortcut(action: QtActionPtr) -> QtStringPtr | t.State: pass +def vqt6_qaction_set_checkable(action: QtActionPtr, checkable: t.CInt) -> t.State: pass +def vqt6_qaction_is_checkable(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_set_checked(action: QtActionPtr, checked: t.CInt) -> t.State: pass +def vqt6_qaction_is_checked(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_set_enabled(action: QtActionPtr, enabled: t.CInt) -> t.State: pass +def vqt6_qaction_is_enabled(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_trigger(action: QtActionPtr) -> t.State: pass + + +# ============================================================ +# QStatusBar / QToolBar +# ============================================================ +def vqt6_qstatusbar_create() -> QtStatusBarPtr | t.State: pass +def vqt6_qstatusbar_create_with_parent(parent: QtWidgetPtr) -> QtStatusBarPtr | t.State: pass +def vqt6_qstatusbar_show_message(sb: QtStatusBarPtr, message: QtStringPtr, timeout_ms: t.CInt) -> t.State: pass +def vqt6_qstatusbar_clear_message(sb: QtStatusBarPtr) -> t.State: pass +def vqt6_qstatusbar_current_message(sb: QtStatusBarPtr) -> QtStringPtr | t.State: pass +def vqt6_qstatusbar_add_widget(sb: QtStatusBarPtr, w: QtWidgetPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qstatusbar_add_permanent_widget(sb: QtStatusBarPtr, w: QtWidgetPtr, stretch: t.CInt) -> t.State: pass + +def vqt6_qtoolbar_create() -> QtToolBarPtr | t.State: pass +def vqt6_qtoolbar_create_with_parent(parent: QtWidgetPtr) -> QtToolBarPtr | t.State: pass +def vqt6_qtoolbar_add_widget(tb: QtToolBarPtr, w: QtWidgetPtr) -> QtActionPtr | t.State: pass +def vqt6_qtoolbar_add_action(tb: QtToolBarPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qtoolbar_add_separator(tb: QtToolBarPtr) -> t.State: pass +def vqt6_qtoolbar_set_icon_size(tb: QtToolBarPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qtoolbar_set_orientation(tb: QtToolBarPtr, orientation: t.CInt) -> t.State: pass +def vqt6_qtoolbar_orientation(tb: QtToolBarPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMessageBox — 消息对话框(静态方法) +# ============================================================ +def vqt6_qmessagebox_information(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_warning(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_critical(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_question(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_about(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qmessagebox_about_qt(parent: QtWidgetPtr) -> t.State: pass + + +# ============================================================ +# QFileDialog — 文件选择对话框(静态方法) +# ============================================================ +def vqt6_qfiledialog_get_open_file_name(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_save_file_name(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_existing_directory(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_open_file_names(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringListPtr | t.State: pass + + +# ============================================================ +# QColorDialog / QFontDialog / QInputDialog — 各种对话框 +# ============================================================ +def vqt6_qcolordialog_get_color(initial: QtColorPtr, parent: QtWidgetPtr, title: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qfontdialog_get_font(initial: QtFontPtr, parent: QtWidgetPtr, title: QtStringPtr) -> QtFontPtr | t.State: pass +def vqt6_qinputdialog_get_text(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, echo_mode: t.CInt, text: QtStringPtr, ok_pressed: t.CInt | t.CPtr) -> QtStringPtr | t.State: pass +def vqt6_qinputdialog_get_int(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, value: t.CInt, min_val: t.CInt, max_val: t.CInt, step: t.CInt, ok_pressed: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qinputdialog_get_double(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, value: t.CDouble, min_val: t.CDouble, max_val: t.CDouble, decimals: t.CInt, ok_pressed: t.CInt | t.CPtr) -> t.CDouble | t.State: pass +def vqt6_qinputdialog_get_item(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, items: QtStringListPtr, current: t.CInt, editable: t.CInt, ok_pressed: t.CInt | t.CPtr) -> QtStringPtr | t.State: pass diff --git a/vqt6 copy/_types.vp b/vqt6 copy/_types.vp new file mode 100644 index 0000000..86d1fe5 --- /dev/null +++ b/vqt6 copy/_types.vp @@ -0,0 +1,186 @@ +import t +from stdint import * + +# ============================================================ +# vqt6/_types.py — 公共类型定义 +# +# Qt6 C++ 类在 Viper 端都是不透明指针 (void*) +# 不暴露 C++ 类的内部布局,只暴露指针 +# ============================================================ + +# 不透明指针 typedef(Qt6 C++ 类的 Viper 端表示) +QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # void* 通用不透明指针 +QtStringPtr: t.CTypedef = t.CVoid | t.CPtr # QString* +QtByteArrayPtr: t.CTypedef = t.CVoid | t.CPtr # QByteArray* +QtVariantPtr: t.CTypedef = t.CVoid | t.CPtr # QVariant* +QtObjectListPtr: t.CTypedef = t.CVoid | t.CPtr # QList* +QtStringListPtr: t.CTypedef = t.CVoid | t.CPtr # QStringList* +QtByteArrayListPtr: t.CTypedef = t.CVoid | t.CPtr # QList* +QtEventPtr: t.CTypedef = t.CVoid | t.CPtr # QEvent* + +# QtCore +QtCoreAppPtr: t.CTypedef = t.CVoid | t.CPtr # QCoreApplication* +QtTimerPtr: t.CTypedef = t.CVoid | t.CPtr # QTimer* +QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # QObject* +QtThreadPtr: t.CTypedef = t.CVoid | t.CPtr # QThread* +QtMutexPtr: t.CTypedef = t.CVoid | t.CPtr # QMutex* +QtWaitConditionPtr: t.CTypedef = t.CVoid | t.CPtr # QWaitCondition* + +# QtGui +QtColorPtr: t.CTypedef = t.CVoid | t.CPtr # QColor* +QtFontPtr: t.CTypedef = t.CVoid | t.CPtr # QFont* +QtFontMetricsPtr: t.CTypedef = t.CVoid | t.CPtr # QFontMetrics* +QtPixmapPtr: t.CTypedef = t.CVoid | t.CPtr # QPixmap* +QtImagePtr: t.CTypedef = t.CVoid | t.CPtr # QImage* +QtPainterPtr: t.CTypedef = t.CVoid | t.CPtr # QPainter* +QtPenPtr: t.CTypedef = t.CVoid | t.CPtr # QPen* +QtBrushPtr: t.CTypedef = t.CVoid | t.CPtr # QBrush* +QtIconPtr: t.CTypedef = t.CVoid | t.CPtr # QIcon* +QtKeyEventPtr: t.CTypedef = t.CVoid | t.CPtr # QKeyEvent* +QtMouseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QMouseEvent* +QtResizeEventPtr: t.CTypedef = t.CVoid | t.CPtr # QResizeEvent* +QtPaintEventPtr: t.CTypedef = t.CVoid | t.CPtr # QPaintEvent* +QtCloseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QCloseEvent* +QtCursorPtr: t.CTypedef = t.CVoid | t.CPtr # QCursor* + +# QtWidgets +QtAppPtr: t.CTypedef = t.CVoid | t.CPtr # QApplication* +QtWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QWidget* +QtDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QDialog* +QtMainWindowPtr: t.CTypedef = t.CVoid | t.CPtr # QMainWindow* +QtLabelPtr: t.CTypedef = t.CVoid | t.CPtr # QLabel* +QtPushButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QPushButton* +QtLineEditPtr: t.CTypedef = t.CVoid | t.CPtr # QLineEdit* +QtTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QTextEdit* +QtPlainTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QPlainTextEdit* +QtCheckBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QCheckBox* +QtRadioButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QRadioButton* +QtComboBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QComboBox* +QtListWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidget* +QtListWidgetItemPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidgetItem* +QtProgressBarPtr: t.CTypedef = t.CVoid | t.CPtr # QProgressBar* +QtSliderPtr: t.CTypedef = t.CVoid | t.CPtr # QSlider* +QtSpinBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QSpinBox* +QtLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QLayout* +QtBoxLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QHBoxLayout / QVBoxLayout* +QtGridLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QGridLayout* +QtFormLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QFormLayout* +QtStackedWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QStackedWidget* +QtTabWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QTabWidget* +QtMenuBarPtr: t.CTypedef = t.CVoid | t.CPtr # QMenuBar* +QtMenuPtr: t.CTypedef = t.CVoid | t.CPtr # QMenu* +QtActionPtr: t.CTypedef = t.CVoid | t.CPtr # QAction* +QtStatusBarPtr: t.CTypedef = t.CVoid | t.CPtr # QStatusBar* +QtToolBarPtr: t.CTypedef = t.CVoid | t.CPtr # QToolBar* +QtMessageBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QMessageBox* +QtFileDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFileDialog* +QtColorDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QColorDialog* +QtFontDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFontDialog* +QtInputDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QInputDialog* + +# QtNetwork +QtTcpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QTcpSocket* +QtUdpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QUdpSocket* +QtHostAddressPtr: t.CTypedef = t.CVoid | t.CPtr # QHostAddress* +QtAbstractSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QAbstractSocket* +QtNetworkAccessManagerPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkAccessManager* +QtNetworkReplyPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkReply* +QtNetworkRequestPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkRequest* + +# ============================================================ +# Qt 通用常量(C++ 枚举值的 C 兼容定义) +# ============================================================ + +# Qt 键盘按键 (Qt::Key) +QT_KEY_ESCAPE: t.CDefine = 0x01000000 +QT_KEY_TAB: t.CDefine = 0x01000001 +QT_KEY_BACKTAB: t.CDefine = 0x01000002 +QT_KEY_BACKSPACE: t.CDefine = 0x01000003 +QT_KEY_RETURN: t.CDefine = 0x01000004 +QT_KEY_ENTER: t.CDefine = 0x01000005 +QT_KEY_INSERT: t.CDefine = 0x01000006 +QT_KEY_DELETE: t.CDefine = 0x01000007 +QT_KEY_PAUSE: t.CDefine = 0x01000008 +QT_KEY_PRINT: t.CDefine = 0x01000009 +QT_KEY_HOME: t.CDefine = 0x01000010 +QT_KEY_END: t.CDefine = 0x01000011 +QT_KEY_LEFT: t.CDefine = 0x01000012 +QT_KEY_UP: t.CDefine = 0x01000013 +QT_KEY_RIGHT: t.CDefine = 0x01000014 +QT_KEY_DOWN: t.CDefine = 0x01000015 +QT_KEY_PAGEUP: t.CDefine = 0x01000016 +QT_KEY_PAGEDOWN: t.CDefine = 0x01000017 +QT_KEY_SHIFT: t.CDefine = 0x01000020 +QT_KEY_CONTROL: t.CDefine = 0x01000021 +QT_KEY_META: t.CDefine = 0x01000022 +QT_KEY_ALT: t.CDefine = 0x01000023 +QT_KEY_F1: t.CDefine = 0x01000030 +QT_KEY_F2: t.CDefine = 0x01000031 +QT_KEY_F12: t.CDefine = 0x0100003b +QT_KEY_SPACE: t.CDefine = 0x20 +QT_KEY_A: t.CDefine = 0x41 +QT_KEY_Z: t.CDefine = 0x5a +QT_KEY_0: t.CDefine = 0x30 +QT_KEY_9: t.CDefine = 0x39 + +# Qt 鼠标按键 (Qt::MouseButton) +QT_NO_BUTTON: t.CDefine = 0x00000000 +QT_LEFT_BUTTON: t.CDefine = 0x00000001 +QT_RIGHT_BUTTON: t.CDefine = 0x00000002 +QT_MID_BUTTON: t.CDefine = 0x00000004 + +# Qt::AlignmentFlag +QT_ALIGN_LEFT: t.CDefine = 0x0001 +QT_ALIGN_RIGHT: t.CDefine = 0x0002 +QT_ALIGN_HCENTER: t.CDefine = 0x0004 +QT_ALIGN_TOP: t.CDefine = 0x0020 +QT_ALIGN_BOTTOM: t.CDefine = 0x0040 +QT_ALIGN_VCENTER: t.CDefine = 0x0080 +QT_ALIGN_CENTER: t.CDefine = QT_ALIGN_HCENTER | QT_ALIGN_VCENTER + +# Qt::Orientation +QT_HORIZONTAL: t.CDefine = 0x1 +QT_VERTICAL: t.CDefine = 0x2 + +# Qt 焦点 +QT_NO_FOCUS: t.CDefine = 0x00 +QT_TAB_FOCUS: t.CDefine = 0x01 +QT_CLICK_FOCUS: t.CDefine = 0x02 +QT_STRONG_FOCUS: t.CDefine = QT_TAB_FOCUS | QT_CLICK_FOCUS +QT_WHEEL_FOCUS: t.CDefine = 0x04 +QT_ALL_FOCUS: t.CDefine = QT_STRONG_FOCUS | QT_WHEEL_FOCUS + +# Qt::WindowFlag +QT_WINDOW: t.CDefine = 0x00000001 +QT_DIALOG: t.CDefine = 0x00000002 | QT_WINDOW +QT_SHEET: t.CDefine = 0x00000004 | QT_WINDOW +QT_DRAWER: t.CDefine = QT_SHEET | 0x00000008 +QT_POPUP: t.CDefine = 0x00000008 | QT_WINDOW +QT_TOOL: t.CDefine = 0x0000000a | QT_WINDOW +QT_TOOLTIP: t.CDefine = 0x0000000c | QT_WINDOW +QT_SPLASH_SCREEN: t.CDefine = 0x0000000e | QT_WINDOW + +QT_WINDOW_TITLE: t.CDefine = 0x00000001 +QT_WINDOW_SYSTEM_MENU: t.CDefine = 0x00000002 +QT_WINDOW_MIN_MAX_BUTTONS: t.CDefine = 0x00000004 +QT_WINDOW_CLOSE_BUTTON: t.CDefine = 0x08000000 +QT_WINDOW_CONTEXT_HELP_BUTTON: t.CDefine = 0x00000008 + +# QMessageBox 标准按钮 +QT_OK: t.CDefine = 0x00000400 +QT_CANCEL: t.CDefine = 0x00400000 +QT_YES: t.CDefine = 0x00004000 +QT_NO: t.CDefine = 0x00010000 +QT_CLOSE: t.CDefine = 0x00200000 + +# 事件类型 +QT_EVENT_NONE: t.CDefine = 0 +QT_EVENT_KEY: t.CDefine = 6 +QT_EVENT_MOUSE_BUTTON_PRESS: t.CDefine = 2 +QT_EVENT_MOUSE_BUTTON_RELEASE: t.CDefine = 3 +QT_EVENT_MOUSE_MOVE: t.CDefine = 5 +QT_EVENT_PAINT: t.CDefine = 12 +QT_EVENT_RESIZE: t.CDefine = 14 +QT_EVENT_CLOSE: t.CDefine = 19 +QT_EVENT_SHOW: t.CDefine = 17 +QT_EVENT_HIDE: t.CDefine = 18 diff --git a/vqt6/CMakeLists.txt b/vqt6/CMakeLists.txt new file mode 100644 index 0000000..d08d121 --- /dev/null +++ b/vqt6/CMakeLists.txt @@ -0,0 +1,110 @@ +# ============================================================ +# vqt6 CMakeLists.txt — 构建 vqt6 C 桥接层 +# +# 默认产物: libvqt6_bridge.a (静态库) +# 可选产物: vqt6_bridge.dll (动态库) +# +# 使用: +# cmake -B build -S . +# cmake --build build --config Release +# ============================================================ + +cmake_minimum_required(VERSION 3.16) +project(vqt6_bridge CXX C) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_AUTOMOC ON) + +# 构建选项 +option(VQT6_BUILD_SHARED "Build vqt6 as shared library (DLL)" OFF) +option(VQT6_BUILD_STATIC "Build vqt6 as static library" ON) +option(VQT6_BUILD_EXAMPLES "Build example programs" OFF) + +# Qt6 依赖 +find_package(Qt6 6.5 REQUIRED COMPONENTS + Core + Gui + Widgets + Network +) + +# Win32 GUI 应用不需要控制台 +if(WIN32) + set(CMAKE_WIN32_EXECUTABLE OFF) +endif() + +# 公共源文件 +set(VQT6_SOURCES + _bridge_core.cpp + _bridge_widgets.cpp + _bridge_gui.cpp + _bridge_network.cpp +) + +set(VQT6_HEADERS + _bridge.h + _bridge_widgets.h + _bridge_gui.h + _bridge_network.h +) + +# Qt 模块 +set(VQT6_QT_MODULES + Qt6::Core + Qt6::Gui + Qt6::Widgets + Qt6::Network +) + +# ============================================================ +# 静态库 +# ============================================================ +if(VQT6_BUILD_STATIC) + add_library(vqt6_bridge_static STATIC ${VQT6_SOURCES} ${VQT6_HEADERS}) + target_link_libraries(vqt6_bridge_static PUBLIC ${VQT6_QT_MODULES}) + target_compile_definitions(vqt6_bridge_static PUBLIC VQT6_BRIDGE_STATIC) + target_include_directories(vqt6_bridge_static PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + set_target_properties(vqt6_bridge_static PROPERTIES + OUTPUT_NAME vqt6_bridge + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + ) +endif() + +# ============================================================ +# 动态库 +# ============================================================ +if(VQT6_BUILD_SHARED) + add_library(vqt6_bridge SHARED ${VQT6_SOURCES} ${VQT6_HEADERS}) + target_link_libraries(vqt6_bridge PUBLIC ${VQT6_QT_MODULES}) + target_compile_definitions(vqt6_bridge PRIVATE VQT6_BRIDGE_BUILD) + target_include_directories(vqt6_bridge PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ) + set_target_properties(vqt6_bridge PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + ) +endif() + +# ============================================================ +# 安装 +# ============================================================ +install(TARGETS vqt6_bridge_static vqt6_bridge + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +install(FILES ${VQT6_HEADERS} + DESTINATION include/vqt6 +) + +# ============================================================ +# 示例 +# ============================================================ +if(VQT6_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/vqt6/README.md b/vqt6/README.md new file mode 100644 index 0000000..eba4e88 --- /dev/null +++ b/vqt6/README.md @@ -0,0 +1,90 @@ +# vqt6 — Viper 的 Qt6 绑定包 + +`vqt6` 是 [Viper](https://git.gvsds.com/GVSDS/TransPyC) 语言的 **Qt6 GUI 框架绑定**,是 Viper 包管理器分发的"包"(类似于 Python 的 PyQt6、Node.js 的 node-gtk)。 + +> 注意:`vqt6` **不是** 包管理器,而是一个**被包管理器管理的包**(库)。 +> 包管理器负责下载、预编译、安装;`vqt6` 只负责把 Qt6 C++ API 暴露给 Viper 代码。 + +## 架构 + +``` ++--------------------+ +-----------------------+ +------------+ +| Viper 用户代码 | FFI | vqt6 桥接层 (libvqt6) | C++ | Qt6 C++ | +| (app.vp) | <----> | - t.State 声明 | <-----> | QtCore | +| | | - C 桥接函数 | | QtGui | +| vqt6.QApplication | | (extern "C") | | QtWidgets | +| vqt6.QLabel | | - 静态库 / 动态库 | | QtNetwork | ++--------------------+ +-----------------------+ +------------+ +``` + +**FFI 路径**: +1. Viper 编译器把 `t.State` 声明的 `def xxx() -> t.State: pass` 解析为外部函数符号 +2. 链接时通过 `libvqt6_bridge.a`(静态)或 `vqt6_bridge.dll`(动态)解析符号 +3. 运行时 C 桥接层调用 Qt6 C++ API 完成实际工作 + +## 链接模式 + +| 模式 | 产物 | 优点 | 缺点 | +|------|------|------|------| +| **静态**(默认) | `libvqt6_bridge.a` | 部署简单(一个 exe),无需分发 dll | exe 体积较大 | +| **动态** | `vqt6_bridge.dll` | 共享内存,多个程序共用 | 需随 exe 分发 dll | + +vqt6 同一套 C 桥接源代码,可同时编译为两种产物。Viper 项目通过 `project.vpj` 切换。 + +## 目录结构 + +``` +includes/vqt6/ +├── README.md # 本文件 +├── __init__.vp # 公共 Pythonic API(用户使用) +├── _types.vp # 公共类型(不透明指针 typedef) +├── _qtcore.vp # QtCore 的 t.State FFI 声明 +├── _qtwidgets.vp # QtWidgets 的 t.State FFI 声明 +├── _qtgui.vp # QtGui 的 t.State FFI 声明 +├── _qtnetwork.vp # QtNetwork 的 t.State FFI 声明 +├── _bridge.h # C 桥接层头文件 +├── _bridge.cpp # C 桥接层实现(extern "C" 包装 Qt6 C++ API) +└── CMakeLists.txt # 构建脚本(生成 libvqt6_bridge.a) +``` + +## 使用示例 + +```python +# App/main.vp +import t +import c +import vqt6 + +# 1. 创建 QApplication +app: vqt6.QApplication | t.CPtr = vqt6.QApplication([]) + +# 2. 创建窗口 +window: vqt6.QWidget | t.CPtr = vqt6.QWidget() +window.setWindowTitle("vqt6 Hello") +window.resize(400, 300) + +# 3. 创建标签 +label: vqt6.QLabel | t.CPtr = vqt6.QLabel("你好,Viper!", window) +label.move(50, 50) + +# 4. 显示并进入事件循环 +window.show() +app.exec() +``` + +## 设计原则 + +1. **不透明指针**:Viper 端不直接操作 Qt6 C++ 类(`QWidget*`、`QString*` 等),所有操作通过 C 桥接函数 `vqt6_xxx()` 转发。 +2. **t.State 声明**:所有 FFI 函数返回 `t.State`,C 桥接层函数实现负责实际操作。 +3. **句柄化对象模型**:Viper 端的对象是 `t.CPtr`(不透明指针),C 端管理生命周期(构造函数/析构函数)。 +4. **跨平台**:同一套 C 桥接代码可在 Windows / Linux / macOS 编译(差异在 Qt6 安装路径)。 + +## 当前状态 + +- [x] 架构设计 +- [x] FFI 覆盖:QtCore / QtWidgets / QtGui / QtNetwork +- [x] FFI 粒度:仅暴露 C 桥接函数 +- [ ] FFI 声明文件编写中 +- [ ] C 桥接层实现 +- [ ] CMakeLists.txt 构建脚本 +- [ ] Hello World 示例验证 diff --git a/vqt6/__init__.vp b/vqt6/__init__.vp new file mode 100644 index 0000000..16446c3 --- /dev/null +++ b/vqt6/__init__.vp @@ -0,0 +1,208 @@ +# ============================================================ +# vqt6 — Viper 的 Qt6 绑定包 +# +# 公共 Pythonic API(基于 C 桥接层) +# 用户用法: +# import vqt6 +# app = vqt6.QApplication([]) +# win = vqt6.QWidget() +# win.setWindowTitle("Hello") +# win.show() +# app.exec() +# ============================================================ + +import t +from stdint import * +from vqt6._types import * +from vqt6._qtcore import * +from vqt6._qtwidgets import * +from vqt6._qtgui import * +from vqt6._qtnetwork import * + + +# ============================================================ +# 高级 API 类(Pythonic 包装,不透明指针) +# ============================================================ +@t.NoVTable +class QApplication: + """QApplication 包装(不透明指针)""" + _ptr: QtAppPtr + + def __init__(self, argv: list[str] | t.CPtr): + # 把 argv 转换为 argc/argv 数组 + argc: t.CInt = 1 + # Viper 端 argv 是 c_char_p 指针数组 + # 这里仅传空 argv,避免 C ABI 复杂性 + argv_ptr: t.CPtr = t.CPtr(0) + self._ptr = vqt6_qapplication_create(argc, argv_ptr) + if self._ptr is None: + raise RuntimeError("Failed to create QApplication") + + def exec(self) -> int: + return vqt6_qapplication_exec(self._ptr) + + def quit(self): + vqt6_qapplication_quit(self._ptr) + + def exit(self, code: int): + vqt6_qapplication_exit(self._ptr, code) + + def process_events(self): + vqt6_qapplication_process_events(self._ptr) + + def desktop_width(self) -> int: + return vqt6_qapplication_desktop_width(self._ptr) + + def desktop_height(self) -> int: + return vqt6_qapplication_desktop_height(self._ptr) + + +@t.NoVTable +class QWidget: + """QWidget 包装""" + _ptr: QtWidgetPtr + + def __init__(self, parent: "QWidget | None" = None): + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qwidget_create_with_parent(parent._ptr) + else: + self._ptr = vqt6_qwidget_create() + if self._ptr is None: + raise RuntimeError("Failed to create QWidget") + + def show(self): + vqt6_qwidget_show(self._ptr) + + def hide(self): + vqt6_qwidget_hide(self._ptr) + + def close(self) -> int: + return vqt6_qwidget_close(self._ptr) + + def setWindowTitle(self, title: str): + title_qs: QtStringPtr = vqt6_qstring_create(title) + vqt6_qwidget_set_window_title(self._ptr, title_qs) + vqt6_qstring_free(title_qs) + + def windowTitle(self) -> str: + result: QtStringPtr = vqt6_qwidget_window_title(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def resize(self, w: int, h: int): + vqt6_qwidget_resize(self._ptr, w, h) + + def move(self, x: int, y: int): + vqt6_qwidget_move(self._ptr, x, y) + + def setGeometry(self, x: int, y: int, w: int, h: int): + vqt6_qwidget_set_geometry(self._ptr, x, y, w, h) + + def setEnabled(self, enabled: int): + vqt6_qwidget_set_enabled(self._ptr, enabled) + + def setVisible(self, visible: int): + vqt6_qwidget_set_visible(self._ptr, visible) + + def isVisible(self) -> int: + return vqt6_qwidget_is_visible(self._ptr) + + def setToolTip(self, tip: str): + tip_qs: QtStringPtr = vqt6_qstring_create(tip) + vqt6_qwidget_set_tool_tip(self._ptr, tip_qs) + vqt6_qstring_free(tip_qs) + + +@t.NoVTable +class QLabel: + """QLabel 包装""" + _ptr: QtLabelPtr + + def __init__(self, text: str = "", parent: "QWidget | None" = None): + text_qs: QtStringPtr = vqt6_qstring_create(text) + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qlabel_create_with_text_parent(text_qs, parent._ptr) + elif text_qs is not None: + self._ptr = vqt6_qlabel_create_with_text(text_qs) + else: + self._ptr = vqt6_qlabel_create() + vqt6_qstring_free(text_qs) + if self._ptr is None: + raise RuntimeError("Failed to create QLabel") + + def setText(self, text: str): + text_qs: QtStringPtr = vqt6_qstring_create(text) + vqt6_qlabel_set_text(self._ptr, text_qs) + vqt6_qstring_free(text_qs) + + def text(self) -> str: + result: QtStringPtr = vqt6_qlabel_text(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def setAlignment(self, alignment: int): + vqt6_qlabel_set_alignment(self._ptr, alignment) + + +@t.NoVTable +class QPushButton: + """QPushButton 包装""" + _ptr: QtPushButtonPtr + + def __init__(self, text: str = "", parent: "QWidget | None" = None): + text_qs: QtStringPtr = vqt6_qstring_create(text) + if parent is not None and parent._ptr is not None: + self._ptr = vqt6_qpushbutton_create_with_text_parent(text_qs, parent._ptr) + elif text_qs is not None: + self._ptr = vqt6_qpushbutton_create_with_text(text_qs) + else: + self._ptr = vqt6_qpushbutton_create() + vqt6_qstring_free(text_qs) + if self._ptr is None: + raise RuntimeError("Failed to create QPushButton") + + def setText(self, text: str): + text_qs: QtStringPtr = vqt6_qstring_create(text) + vqt6_qpushbutton_set_text(self._ptr, text_qs) + vqt6_qstring_free(text_qs) + + def text(self) -> str: + result: QtStringPtr = vqt6_qpushbutton_text(self._ptr) + buf: bytes = stdlib.malloc(1024) + vqt6_qstring_to_utf8(result, buf, 1024) + s: str = string.strndup(buf, 1024) + vqt6_qstring_free(result) + return s + + def click(self): + vqt6_qpushbutton_click(self._ptr) + + def setEnabled(self, enabled: int): + vqt6_qwidget_set_enabled(self._ptr, enabled) + + +# ============================================================ +# 模块导出 +# ============================================================ +__all__ = [ + # 高层类 + "QApplication", "QWidget", "QLabel", "QPushButton", + # 类型 + "QtObjectPtr", "QtStringPtr", "QtByteArrayPtr", "QtWidgetPtr", "QtAppPtr", + "QtLabelPtr", "QtPushButtonPtr", + "QtColorPtr", "QtFontPtr", "QtPixmapPtr", "QtImagePtr", "QtPainterPtr", + "QtTcpSocketPtr", "QtHostAddressPtr", "QtNetworkRequestPtr", "QtNetworkReplyPtr", + # 常量 + "QT_KEY_ESCAPE", "QT_KEY_RETURN", "QT_KEY_A", "QT_KEY_Z", + "QT_LEFT_BUTTON", "QT_RIGHT_BUTTON", "QT_MID_BUTTON", + "QT_HORIZONTAL", "QT_VERTICAL", + "QT_ALIGN_LEFT", "QT_ALIGN_CENTER", "QT_ALIGN_RIGHT", + "QT_PORT_HTTP", "QT_PORT_HTTPS", "QT_PORT_FTP", + "QT_OK", "QT_CANCEL", "QT_YES", "QT_NO", "QT_CLOSE", +] diff --git a/vqt6/_bridge.h b/vqt6/_bridge.h new file mode 100644 index 0000000..e573ea8 --- /dev/null +++ b/vqt6/_bridge.h @@ -0,0 +1,151 @@ +// ============================================================ +// vqt6/_bridge.h — C 桥接层头文件 +// +// 作用: 把 Qt6 C++ API 包装成 extern "C" 函数,供 Viper FFI 调用 +// 编译: 作为静态库 libvqt6_bridge.a 或动态库 vqt6_bridge.dll +// ============================================================ + +#ifndef VQT6_BRIDGE_H +#define VQT6_BRIDGE_H + +#include +#include + +#if defined(_WIN32) +# if defined(VQT6_BRIDGE_STATIC) +# define VQT6_API +# elif defined(VQT6_BRIDGE_BUILD) +# define VQT6_API __declspec(dllexport) +# else +# define VQT6_API __declspec(dllimport) +# endif +#else +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define VQT6_API __attribute__((visibility("default"))) +# else +# define VQT6_API +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QString +// ============================================================ +VQT6_API void* vqt6_qstring_create(const char* utf8); +VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size); +VQT6_API void vqt6_qstring_free(void* qstr); +VQT6_API int vqt6_qstring_length(void* qstr); +VQT6_API int vqt6_qstring_is_empty(void* qstr); +VQT6_API int vqt6_qstring_equals(void* qstr, void* other); +VQT6_API void* vqt6_qstring_append(void* qstr, void* other); + +// ============================================================ +// QByteArray +// ============================================================ +VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size); +VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size); +VQT6_API size_t vqt6_qbytearray_size(void* qba); +VQT6_API void vqt6_qbytearray_free(void* qba); + +// ============================================================ +// QObject +// ============================================================ +VQT6_API void vqt6_qobject_delete(void* obj); +VQT6_API void vqt6_qobject_delete_later(void* obj); +VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name); +VQT6_API void* vqt6_qobject_object_name(void* obj); +VQT6_API void vqt6_qobject_set_parent(void* child, void* parent); +VQT6_API void* vqt6_qobject_parent(void* obj); +VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name, + void* receiver, const char* slot_name); +VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name, + void* receiver, const char* slot_name); +VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter); +VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter); + +// ============================================================ +// QCoreApplication +// ============================================================ +VQT6_API void* vqt6_qcoreapp_create(const char* app_name); +VQT6_API void* vqt6_qcoreapp_instance(void); +VQT6_API int vqt6_qcoreapp_exec(void* app); +VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code); +VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code); +VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags); +VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event); +VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event); +VQT6_API void* vqt6_qcoreapp_organization_name(void* app); +VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name); +VQT6_API void* vqt6_qcoreapp_application_name(void* app); +VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name); + +// ============================================================ +// QTimer +// ============================================================ +VQT6_API void* vqt6_qtimer_create(void); +VQT6_API void* vqt6_qtimer_create_with_parent(void* parent); +VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms); +VQT6_API void vqt6_qtimer_stop(void* timer); +VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms); +VQT6_API int vqt6_qtimer_interval(void* timer); +VQT6_API int vqt6_qtimer_is_active(void* timer); +VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot); +VQT6_API int vqt6_qtimer_is_single_shot(void* timer); + +// ============================================================ +// QVariant +// ============================================================ +VQT6_API void* vqt6_qvariant_create_int(int value); +VQT6_API void* vqt6_qvariant_create_double(double value); +VQT6_API void* vqt6_qvariant_create_bool(int value); +VQT6_API void* vqt6_qvariant_create_string(void* s); +VQT6_API int vqt6_qvariant_to_int(void* v, int* ok); +VQT6_API double vqt6_qvariant_to_double(void* v, int* ok); +VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok); +VQT6_API void* vqt6_qvariant_to_string(void* v); +VQT6_API int vqt6_qvariant_type_id(void* v); +VQT6_API int vqt6_qvariant_is_valid(void* v); +VQT6_API void vqt6_qvariant_free(void* v); + +// ============================================================ +// QEvent +// ============================================================ +VQT6_API int vqt6_qevent_type(void* event); +VQT6_API void vqt6_qevent_accept(void* event); +VQT6_API void vqt6_qevent_ignore(void* event); +VQT6_API int vqt6_qevent_is_accepted(void* event); + +// ============================================================ +// QStringList +// ============================================================ +VQT6_API void* vqt6_qstringlist_create(void); +VQT6_API void vqt6_qstringlist_append(void* list, void* str); +VQT6_API int vqt6_qstringlist_size(void* list); +VQT6_API void* vqt6_qstringlist_at(void* list, int index); +VQT6_API void vqt6_qstringlist_free(void* list); + +// ============================================================ +// QByteArrayList +// ============================================================ +VQT6_API void* vqt6_qbytearraylist_create(void); +VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba); +VQT6_API int vqt6_qbytearraylist_size(void* list); +VQT6_API void* vqt6_qbytearraylist_at(void* list, int index); +VQT6_API void vqt6_qbytearraylist_free(void* list); + +// ============================================================ +// 全局回调注册表 +// ============================================================ +typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data); +VQT6_API void vqt6_register_slot(int slot_id, void* user_data); +VQT6_API void vqt6_unregister_slot(int slot_id); +VQT6_API void vqt6_trigger_slot(int slot_id); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_H diff --git a/vqt6/_bridge_core.cpp b/vqt6/_bridge_core.cpp new file mode 100644 index 0000000..3f420d8 --- /dev/null +++ b/vqt6/_bridge_core.cpp @@ -0,0 +1,433 @@ +// ============================================================ +// vqt6/_bridge_core.cpp — QtCore C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 全局回调表(线程安全) +namespace { + QMutex g_slot_mutex; + QHash> g_slots; +} + +// ============================================================ +// QString +// ============================================================ +extern "C" VQT6_API void* vqt6_qstring_create(const char* utf8) { + if (utf8 == nullptr) return nullptr; + return new QString(QString::fromUtf8(utf8)); +} + +extern "C" VQT6_API size_t vqt6_qstring_to_utf8(void* qstr, char* buf, size_t buf_size) { + if (qstr == nullptr || buf == nullptr || buf_size == 0) return 0; + QString* s = static_cast(qstr); + QByteArray ba = s->toUtf8(); + size_t len = static_cast(ba.size()); + if (len >= buf_size) len = buf_size - 1; + std::memcpy(buf, ba.constData(), len); + buf[len] = '\0'; + return len; +} + +extern "C" VQT6_API void vqt6_qstring_free(void* qstr) { + delete static_cast(qstr); +} + +extern "C" VQT6_API int vqt6_qstring_length(void* qstr) { + if (qstr == nullptr) return 0; + return static_cast(qstr)->length(); +} + +extern "C" VQT6_API int vqt6_qstring_is_empty(void* qstr) { + if (qstr == nullptr) return 1; + return static_cast(qstr)->isEmpty() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qstring_equals(void* qstr, void* other) { + if (qstr == nullptr || other == nullptr) return 0; + return *static_cast(qstr) == *static_cast(other) ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qstring_append(void* qstr, void* other) { + if (qstr == nullptr || other == nullptr) return nullptr; + return new QString(*static_cast(qstr) + *static_cast(other)); +} + +// ============================================================ +// QByteArray +// ============================================================ +extern "C" VQT6_API void* vqt6_qbytearray_create(const void* data, size_t size) { + if (data == nullptr) return new QByteArray(); + return new QByteArray(static_cast(data), static_cast(size)); +} + +extern "C" VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size) { + if (qba == nullptr) return nullptr; + QByteArray* ba = static_cast(qba); + if (out_size != nullptr) *out_size = static_cast(ba->size()); + return ba->data(); +} + +extern "C" VQT6_API size_t vqt6_qbytearray_size(void* qba) { + if (qba == nullptr) return 0; + return static_cast(static_cast(qba)->size()); +} + +extern "C" VQT6_API void vqt6_qbytearray_free(void* qba) { + delete static_cast(qba); +} + +// ============================================================ +// QObject +// ============================================================ +extern "C" VQT6_API void vqt6_qobject_delete(void* obj) { + if (obj == nullptr) return; + delete static_cast(obj); +} + +extern "C" VQT6_API void vqt6_qobject_delete_later(void* obj) { + if (obj == nullptr) return; + static_cast(obj)->deleteLater(); +} + +extern "C" VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name) { + if (obj == nullptr || name == nullptr) return; + static_cast(obj)->setObjectName(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qobject_object_name(void* obj) { + if (obj == nullptr) return nullptr; + return new QString(static_cast(obj)->objectName()); +} + +extern "C" VQT6_API void vqt6_qobject_set_parent(void* child, void* parent) { + if (child == nullptr) return; + static_cast(child)->setParent(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qobject_parent(void* obj) { + if (obj == nullptr) return nullptr; + return static_cast(obj)->parent(); +} + +extern "C" VQT6_API int vqt6_qobject_connect(void* sender, const char* signal_name, + void* receiver, const char* slot_name) { + if (sender == nullptr || receiver == nullptr || signal_name == nullptr || slot_name == nullptr) + return 0; + return QObject::connect( + static_cast(sender), signal_name, + static_cast(receiver), slot_name + ) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qobject_disconnect(void* sender, const char* signal_name, + void* receiver, const char* slot_name) { + if (sender == nullptr || receiver == nullptr) return 0; + return QObject::disconnect( + static_cast(sender), signal_name, + static_cast(receiver), slot_name + ) ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qobject_install_event_filter(void* watched, void* filter) { + if (watched == nullptr || filter == nullptr) return; + static_cast(watched)->installEventFilter(static_cast(filter)); +} + +extern "C" VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter) { + if (watched == nullptr || filter == nullptr) return; + static_cast(watched)->removeEventFilter(static_cast(filter)); +} + +// ============================================================ +// QCoreApplication +// ============================================================ +extern "C" VQT6_API void* vqt6_qcoreapp_create(const char* app_name) { + if (app_name == nullptr) return nullptr; + int argc = 1; + static char app_name_copy[1024]; + std::strncpy(app_name_copy, app_name, sizeof(app_name_copy) - 1); + app_name_copy[sizeof(app_name_copy) - 1] = '\0'; + char* argv[] = { app_name_copy, nullptr }; + return new QCoreApplication(argc, argv); +} + +extern "C" VQT6_API void* vqt6_qcoreapp_instance(void) { + return QCoreApplication::instance(); +} + +extern "C" VQT6_API int vqt6_qcoreapp_exec(void* app) { + if (app == nullptr) return -1; + return static_cast(app)->exec(); +} + +extern "C" VQT6_API void vqt6_qcoreapp_quit(void* app, int exit_code) { + if (app == nullptr) return; + // 优先使用 exit_code 重载 + QCoreApplication* a = static_cast(app); + if (a == QCoreApplication::instance()) { + a->exit(exit_code); + } +} + +extern "C" VQT6_API void vqt6_qcoreapp_exit(void* app, int exit_code) { + if (app == nullptr) return; + static_cast(app)->exit(exit_code); +} + +extern "C" VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags) { + if (app == nullptr) return; + static_cast(app)->processEvents(static_cast(flags)); +} + +extern "C" VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event) { + if (receiver == nullptr || event == nullptr) return; + QCoreApplication::postEvent(static_cast(receiver), static_cast(event)); +} + +extern "C" VQT6_API int vqt6_qcoreapp_send_event(void* receiver, void* event) { + if (receiver == nullptr || event == nullptr) return 0; + return QCoreApplication::sendEvent(static_cast(receiver), static_cast(event)) ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qcoreapp_organization_name(void* app) { + if (app == nullptr) return nullptr; + return new QString(QCoreApplication::organizationName()); +} + +extern "C" VQT6_API void vqt6_qcoreapp_set_organization_name(void* app, void* name) { + if (app == nullptr || name == nullptr) return; + QCoreApplication::setOrganizationName(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qcoreapp_application_name(void* app) { + if (app == nullptr) return nullptr; + return new QString(QCoreApplication::applicationName()); +} + +extern "C" VQT6_API void vqt6_qcoreapp_set_application_name(void* app, void* name) { + if (app == nullptr || name == nullptr) return; + QCoreApplication::setApplicationName(*static_cast(name)); +} + +// ============================================================ +// QTimer +// ============================================================ +extern "C" VQT6_API void* vqt6_qtimer_create(void) { + return new QTimer(); +} + +extern "C" VQT6_API void* vqt6_qtimer_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTimer(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms) { + if (timer == nullptr) return; + static_cast(timer)->start(interval_ms); +} + +extern "C" VQT6_API void vqt6_qtimer_stop(void* timer) { + if (timer == nullptr) return; + static_cast(timer)->stop(); +} + +extern "C" VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms) { + if (timer == nullptr) return; + static_cast(timer)->setInterval(interval_ms); +} + +extern "C" VQT6_API int vqt6_qtimer_interval(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->interval(); +} + +extern "C" VQT6_API int vqt6_qtimer_is_active(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->isActive() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qtimer_set_single_shot(void* timer, int single_shot) { + if (timer == nullptr) return; + static_cast(timer)->setSingleShot(single_shot != 0); +} + +extern "C" VQT6_API int vqt6_qtimer_is_single_shot(void* timer) { + if (timer == nullptr) return 0; + return static_cast(timer)->isSingleShot() ? 1 : 0; +} + +// ============================================================ +// QVariant +// ============================================================ +extern "C" VQT6_API void* vqt6_qvariant_create_int(int value) { + return new QVariant(value); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_double(double value) { + return new QVariant(value); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_bool(int value) { + return new QVariant(value != 0); +} + +extern "C" VQT6_API void* vqt6_qvariant_create_string(void* s) { + if (s == nullptr) return new QVariant(); + return new QVariant(*static_cast(s)); +} + +extern "C" VQT6_API int vqt6_qvariant_to_int(void* v, int* ok) { + if (v == nullptr) return 0; + bool bok = false; + int val = static_cast(v)->toInt(&bok); + if (ok != nullptr) *ok = bok ? 1 : 0; + return val; +} + +extern "C" VQT6_API double vqt6_qvariant_to_double(void* v, int* ok) { + if (v == nullptr) return 0.0; + bool bok = false; + double val = static_cast(v)->toDouble(&bok); + if (ok != nullptr) *ok = bok ? 1 : 0; + return val; +} + +extern "C" VQT6_API int vqt6_qvariant_to_bool(void* v, int* ok) { + if (v == nullptr) return 0; + bool bok = false; + bool val = static_cast(v)->toBool(); + if (ok != nullptr) *ok = 1; + return val ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qvariant_to_string(void* v) { + if (v == nullptr) return nullptr; + return new QString(static_cast(v)->toString()); +} + +extern "C" VQT6_API int vqt6_qvariant_type_id(void* v) { + if (v == nullptr) return 0; + return static_cast(static_cast(v)->typeId()); +} + +extern "C" VQT6_API int vqt6_qvariant_is_valid(void* v) { + if (v == nullptr) return 0; + return static_cast(v)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qvariant_free(void* v) { + delete static_cast(v); +} + +// ============================================================ +// QEvent +// ============================================================ +extern "C" VQT6_API int vqt6_qevent_type(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->type()); +} + +extern "C" VQT6_API void vqt6_qevent_accept(void* event) { + if (event == nullptr) return; + static_cast(event)->accept(); +} + +extern "C" VQT6_API void vqt6_qevent_ignore(void* event) { + if (event == nullptr) return; + static_cast(event)->ignore(); +} + +extern "C" VQT6_API int vqt6_qevent_is_accepted(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAccepted() ? 1 : 0; +} + +// ============================================================ +// QStringList +// ============================================================ +extern "C" VQT6_API void* vqt6_qstringlist_create(void) { + return new QStringList(); +} + +extern "C" VQT6_API void vqt6_qstringlist_append(void* list, void* str) { + if (list == nullptr || str == nullptr) return; + static_cast(list)->append(*static_cast(str)); +} + +extern "C" VQT6_API int vqt6_qstringlist_size(void* list) { + if (list == nullptr) return 0; + return static_cast(list)->size(); +} + +extern "C" VQT6_API void* vqt6_qstringlist_at(void* list, int index) { + if (list == nullptr) return nullptr; + QStringList* sl = static_cast(list); + if (index < 0 || index >= sl->size()) return nullptr; + return new QString(sl->at(index)); +} + +extern "C" VQT6_API void vqt6_qstringlist_free(void* list) { + delete static_cast(list); +} + +// ============================================================ +// QByteArrayList +// ============================================================ +extern "C" VQT6_API void* vqt6_qbytearraylist_create(void) { + return new QList(); +} + +extern "C" VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba) { + if (list == nullptr || qba == nullptr) return; + static_cast*>(list)->append(*static_cast(qba)); +} + +extern "C" VQT6_API int vqt6_qbytearraylist_size(void* list) { + if (list == nullptr) return 0; + return static_cast*>(list)->size(); +} + +extern "C" VQT6_API void* vqt6_qbytearraylist_at(void* list, int index) { + if (list == nullptr) return nullptr; + QList* qbl = static_cast*>(list); + if (index < 0 || index >= qbl->size()) return nullptr; + return new QByteArray(qbl->at(index)); +} + +extern "C" VQT6_API void vqt6_qbytearraylist_free(void* list) { + delete static_cast*>(list); +} + +// ============================================================ +// 全局回调注册表 +// ============================================================ +extern "C" VQT6_API void vqt6_register_slot(int slot_id, void* user_data) { + QMutexLocker locker(&g_slot_mutex); + g_slots.insert(slot_id, QPair(nullptr, user_data)); +} + +extern "C" VQT6_API void vqt6_unregister_slot(int slot_id) { + QMutexLocker locker(&g_slot_mutex); + g_slots.remove(slot_id); +} + +extern "C" VQT6_API void vqt6_trigger_slot(int slot_id) { + QMutexLocker locker(&g_slot_mutex); + auto it = g_slots.find(slot_id); + if (it != g_slots.end() && it.value().first != nullptr) { + it.value().first(slot_id, it.value().second); + } +} diff --git a/vqt6/_bridge_gui.cpp b/vqt6/_bridge_gui.cpp new file mode 100644 index 0000000..089f0d7 --- /dev/null +++ b/vqt6/_bridge_gui.cpp @@ -0,0 +1,868 @@ +// ============================================================ +// vqt6/_bridge_gui.cpp — QtGui C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_gui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QColor +// ============================================================ +extern "C" VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b) { + return new QColor(r, g, b); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a) { + return new QColor(r, g, b, a); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_name(void* name) { + if (name == nullptr) return new QColor(); + return new QColor(*static_cast(name)); +} + +extern "C" VQT6_API void* vqt6_qcolor_create_hex(void* hex_str) { + if (hex_str == nullptr) return new QColor(); + return new QColor(*static_cast(hex_str)); +} + +extern "C" VQT6_API int vqt6_qcolor_red(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->red(); +} + +extern "C" VQT6_API int vqt6_qcolor_green(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->green(); +} + +extern "C" VQT6_API int vqt6_qcolor_blue(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->blue(); +} + +extern "C" VQT6_API int vqt6_qcolor_alpha(void* c) { + if (c == nullptr) return 255; + return static_cast(c)->alpha(); +} + +extern "C" VQT6_API void vqt6_qcolor_set_red(void* c, int r) { + if (c == nullptr) return; + static_cast(c)->setRed(r); +} + +extern "C" VQT6_API void vqt6_qcolor_set_green(void* c, int g) { + if (c == nullptr) return; + static_cast(c)->setGreen(g); +} + +extern "C" VQT6_API void vqt6_qcolor_set_blue(void* c, int b) { + if (c == nullptr) return; + static_cast(c)->setBlue(b); +} + +extern "C" VQT6_API void vqt6_qcolor_set_alpha(void* c, int a) { + if (c == nullptr) return; + static_cast(c)->setAlpha(a); +} + +extern "C" VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b) { + if (c == nullptr) return; + static_cast(c)->setRgb(r, g, b); +} + +extern "C" VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a) { + if (c == nullptr) return; + static_cast(c)->setRgba(r, g, b, a); +} + +extern "C" VQT6_API void* vqt6_qcolor_name(void* c) { + if (c == nullptr) return nullptr; + return new QString(static_cast(c)->name()); +} + +extern "C" VQT6_API int vqt6_qcolor_is_valid(void* c) { + if (c == nullptr) return 0; + return static_cast(c)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcolor_free(void* c) { + delete static_cast(c); +} + +// ============================================================ +// QFont +// ============================================================ +extern "C" VQT6_API void* vqt6_qfont_create(void) { + return new QFont(); +} + +extern "C" VQT6_API void* vqt6_qfont_create_with_family(void* family) { + if (family == nullptr) return new QFont(); + return new QFont(*static_cast(family)); +} + +extern "C" VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size) { + if (family == nullptr) return new QFont(); + return new QFont(*static_cast(family), point_size); +} + +extern "C" VQT6_API void vqt6_qfont_set_family(void* font, void* family) { + if (font == nullptr || family == nullptr) return; + static_cast(font)->setFamily(*static_cast(family)); +} + +extern "C" VQT6_API void* vqt6_qfont_family(void* font) { + if (font == nullptr) return nullptr; + return new QString(static_cast(font)->family()); +} + +extern "C" VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size) { + if (font == nullptr) return; + static_cast(font)->setPointSize(point_size); +} + +extern "C" VQT6_API int vqt6_qfont_point_size(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->pointSize(); +} + +extern "C" VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size) { + if (font == nullptr) return; + static_cast(font)->setPixelSize(pixel_size); +} + +extern "C" VQT6_API int vqt6_qfont_pixel_size(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->pixelSize(); +} + +extern "C" VQT6_API void vqt6_qfont_set_bold(void* font, int bold) { + if (font == nullptr) return; + static_cast(font)->setBold(bold != 0); +} + +extern "C" VQT6_API int vqt6_qfont_bold(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->bold() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_italic(void* font, int italic) { + if (font == nullptr) return; + static_cast(font)->setItalic(italic != 0); +} + +extern "C" VQT6_API int vqt6_qfont_italic(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->italic() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_underline(void* font, int underline) { + if (font == nullptr) return; + static_cast(font)->setUnderline(underline != 0); +} + +extern "C" VQT6_API int vqt6_qfont_underline(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->underline() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out) { + if (font == nullptr) return; + static_cast(font)->setStrikeOut(strike_out != 0); +} + +extern "C" VQT6_API int vqt6_qfont_strike_out(void* font) { + if (font == nullptr) return 0; + return static_cast(font)->strikeOut() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qfont_set_weight(void* font, int weight) { + if (font == nullptr) return; + static_cast(font)->setWeight(static_cast(weight)); +} + +extern "C" VQT6_API int vqt6_qfont_weight(void* font) { + if (font == nullptr) return 0; + return static_cast(static_cast(font)->weight()); +} + +extern "C" VQT6_API void vqt6_qfont_free(void* font) { + delete static_cast(font); +} + +// ============================================================ +// QFontMetrics +// ============================================================ +extern "C" VQT6_API void* vqt6_qfontmetrics_create(void* font) { + if (font == nullptr) return nullptr; + return new QFontMetrics(*static_cast(font)); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text) { + if (fm == nullptr || text == nullptr) return 0; + return static_cast(fm)->horizontalAdvance(*static_cast(text)); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_height(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->height(); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_ascent(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->ascent(); +} + +extern "C" VQT6_API int vqt6_qfontmetrics_descent(void* fm) { + if (fm == nullptr) return 0; + return static_cast(fm)->descent(); +} + +extern "C" VQT6_API void vqt6_qfontmetrics_free(void* fm) { + delete static_cast(fm); +} + +// ============================================================ +// QPixmap +// ============================================================ +extern "C" VQT6_API void* vqt6_qpixmap_create(void) { + return new QPixmap(); +} + +extern "C" VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h) { + return new QPixmap(w, h); +} + +extern "C" VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name) { + if (pm == nullptr || file_name == nullptr) return 0; + return static_cast(pm)->load(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size) { + if (pm == nullptr || data == nullptr) return 0; + return static_cast(pm)->loadFromData(static_cast(data), static_cast(size)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name) { + if (pm == nullptr || file_name == nullptr) return 0; + return static_cast(pm)->save(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpixmap_width(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->width(); +} + +extern "C" VQT6_API int vqt6_qpixmap_height(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->height(); +} + +extern "C" VQT6_API int vqt6_qpixmap_is_null(void* pm) { + if (pm == nullptr) return 0; + return static_cast(pm)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h) { + if (pm == nullptr) return nullptr; + return new QPixmap(static_cast(pm)->scaled(w, h)); +} + +extern "C" VQT6_API void vqt6_qpixmap_fill(void* pm, void* color) { + if (pm == nullptr) return; + if (color != nullptr) { + static_cast(pm)->fill(*static_cast(color)); + } else { + static_cast(pm)->fill(); + } +} + +extern "C" VQT6_API void vqt6_qpixmap_free(void* pm) { + delete static_cast(pm); +} + +// ============================================================ +// QImage +// ============================================================ +extern "C" VQT6_API void* vqt6_qimage_create(void) { + return new QImage(); +} + +extern "C" VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format) { + return new QImage(w, h, static_cast(format)); +} + +extern "C" VQT6_API int vqt6_qimage_load(void* img, void* file_name) { + if (img == nullptr || file_name == nullptr) return 0; + return static_cast(img)->load(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qimage_save(void* img, void* file_name) { + if (img == nullptr || file_name == nullptr) return 0; + return static_cast(img)->save(*static_cast(file_name)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qimage_width(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->width(); +} + +extern "C" VQT6_API int vqt6_qimage_height(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->height(); +} + +extern "C" VQT6_API int vqt6_qimage_format(void* img) { + if (img == nullptr) return 0; + return static_cast(static_cast(img)->format()); +} + +extern "C" VQT6_API int vqt6_qimage_is_null(void* img) { + if (img == nullptr) return 0; + return static_cast(img)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qimage_fill(void* img, void* color) { + if (img == nullptr) return; + if (color != nullptr) { + static_cast(img)->fill(*static_cast(color)); + } +} + +extern "C" VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h) { + if (img == nullptr) return nullptr; + return new QImage(static_cast(img)->scaled(w, h)); +} + +extern "C" VQT6_API void vqt6_qimage_free(void* img) { + delete static_cast(img); +} + +// ============================================================ +// QPainter +// ============================================================ +extern "C" VQT6_API void* vqt6_qpainter_create(void) { + return new QPainter(); +} + +extern "C" VQT6_API int vqt6_qpainter_begin(void* p, void* device) { + if (p == nullptr || device == nullptr) return 0; + return static_cast(p)->begin(static_cast(device)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpainter_end(void* p) { + if (p == nullptr) return 0; + return static_cast(p)->end() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qpainter_is_active(void* p) { + if (p == nullptr) return 0; + return static_cast(p)->isActive() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen) { + if (p == nullptr || pen == nullptr) return; + static_cast(p)->setPen(*static_cast(pen)); +} + +extern "C" VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush) { + if (p == nullptr || brush == nullptr) return; + static_cast(p)->setBrush(*static_cast(brush)); +} + +extern "C" VQT6_API void vqt6_qpainter_set_font(void* p, void* font) { + if (p == nullptr || font == nullptr) return; + static_cast(p)->setFont(*static_cast(font)); +} + +extern "C" VQT6_API void* vqt6_qpainter_pen(void* p) { + if (p == nullptr) return nullptr; + return new QPen(static_cast(p)->pen()); +} + +extern "C" VQT6_API void* vqt6_qpainter_brush(void* p) { + if (p == nullptr) return nullptr; + return new QBrush(static_cast(p)->brush()); +} + +extern "C" VQT6_API void* vqt6_qpainter_font(void* p) { + if (p == nullptr) return nullptr; + return new QFont(static_cast(p)->font()); +} + +extern "C" VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity) { + if (p == nullptr) return; + static_cast(p)->setOpacity(opacity); +} + +extern "C" VQT6_API double vqt6_qpainter_opacity(void* p) { + if (p == nullptr) return 1.0; + return static_cast(p)->opacity(); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2) { + if (p == nullptr) return; + static_cast(p)->drawLine(x1, y1, x2, y2); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h) { + if (p == nullptr) return; + static_cast(p)->drawRect(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color) { + if (p == nullptr || color == nullptr) return; + static_cast(p)->fillRect(x, y, w, h, *static_cast(color)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h) { + if (p == nullptr) return; + static_cast(p)->drawEllipse(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawArc(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawChord(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle) { + if (p == nullptr) return; + static_cast(p)->drawPie(x, y, w, h, start_angle, span_angle); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon polygon; + for (int i = 0; i < point_count; ++i) { + polygon << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPolygon(polygon); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon polyline; + for (int i = 0; i < point_count; ++i) { + polyline << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPolyline(polyline); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y) { + if (p == nullptr) return; + static_cast(p)->drawPoint(x, y); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count) { + if (p == nullptr || points == nullptr || point_count < 1) return; + QPolygon pts; + for (int i = 0; i < point_count; ++i) { + pts << QPoint(points[i*2], points[i*2+1]); + } + static_cast(p)->drawPoints(pts); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text) { + if (p == nullptr || text == nullptr) return; + static_cast(p)->drawText(x, y, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text) { + if (p == nullptr || text == nullptr) return; + static_cast(p)->drawText(x, y, w, h, flags, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap) { + if (p == nullptr || pixmap == nullptr) return; + static_cast(p)->drawPixmap(x, y, *static_cast(pixmap)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image) { + if (p == nullptr || image == nullptr) return; + static_cast(p)->drawImage(x, y, *static_cast(image)); +} + +extern "C" VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap) { + if (p == nullptr || pixmap == nullptr) return; + static_cast(p)->drawTiledPixmap(x, y, w, h, *static_cast(pixmap)); +} + +extern "C" VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy) { + if (p == nullptr) return; + static_cast(p)->translate(dx, dy); +} + +extern "C" VQT6_API void vqt6_qpainter_rotate(void* p, double angle) { + if (p == nullptr) return; + static_cast(p)->rotate(angle); +} + +extern "C" VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy) { + if (p == nullptr) return; + static_cast(p)->scale(sx, sy); +} + +extern "C" VQT6_API void vqt6_qpainter_reset_transform(void* p) { + if (p == nullptr) return; + static_cast(p)->resetTransform(); +} + +extern "C" VQT6_API void vqt6_qpainter_save(void* p) { + if (p == nullptr) return; + static_cast(p)->save(); +} + +extern "C" VQT6_API void vqt6_qpainter_restore(void* p) { + if (p == nullptr) return; + static_cast(p)->restore(); +} + +extern "C" VQT6_API void vqt6_qpainter_free(void* p) { + delete static_cast(p); +} + +// ============================================================ +// QPen +// ============================================================ +extern "C" VQT6_API void* vqt6_qpen_create(void) { + return new QPen(); +} + +extern "C" VQT6_API void* vqt6_qpen_create_with_color(void* color) { + if (color == nullptr) return new QPen(); + return new QPen(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width) { + if (color == nullptr) return new QPen(); + return new QPen(*static_cast(color), width); +} + +extern "C" VQT6_API void vqt6_qpen_set_color(void* pen, void* color) { + if (pen == nullptr || color == nullptr) return; + static_cast(pen)->setColor(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qpen_color(void* pen) { + if (pen == nullptr) return nullptr; + return new QColor(static_cast(pen)->color()); +} + +extern "C" VQT6_API void vqt6_qpen_set_width(void* pen, int width) { + if (pen == nullptr) return; + static_cast(pen)->setWidth(width); +} + +extern "C" VQT6_API int vqt6_qpen_width(void* pen) { + if (pen == nullptr) return 0; + return static_cast(pen)->width(); +} + +extern "C" VQT6_API void vqt6_qpen_set_style(void* pen, int style) { + if (pen == nullptr) return; + static_cast(pen)->setStyle(static_cast(style)); +} + +extern "C" VQT6_API int vqt6_qpen_style(void* pen) { + if (pen == nullptr) return 0; + return static_cast(static_cast(pen)->style()); +} + +extern "C" VQT6_API void vqt6_qpen_free(void* pen) { + delete static_cast(pen); +} + +// ============================================================ +// QBrush +// ============================================================ +extern "C" VQT6_API void* vqt6_qbrush_create(void) { + return new QBrush(); +} + +extern "C" VQT6_API void* vqt6_qbrush_create_with_color(void* color) { + if (color == nullptr) return new QBrush(); + return new QBrush(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qbrush_create_with_style(int style) { + return new QBrush(static_cast(style)); +} + +extern "C" VQT6_API void vqt6_qbrush_set_color(void* brush, void* color) { + if (brush == nullptr || color == nullptr) return; + static_cast(brush)->setColor(*static_cast(color)); +} + +extern "C" VQT6_API void* vqt6_qbrush_color(void* brush) { + if (brush == nullptr) return nullptr; + return new QColor(static_cast(brush)->color()); +} + +extern "C" VQT6_API void vqt6_qbrush_set_style(void* brush, int style) { + if (brush == nullptr) return; + static_cast(brush)->setStyle(static_cast(style)); +} + +extern "C" VQT6_API int vqt6_qbrush_style(void* brush) { + if (brush == nullptr) return 0; + return static_cast(static_cast(brush)->style()); +} + +extern "C" VQT6_API void vqt6_qbrush_free(void* brush) { + delete static_cast(brush); +} + +// ============================================================ +// QIcon +// ============================================================ +extern "C" VQT6_API void* vqt6_qicon_create(void) { + return new QIcon(); +} + +extern "C" VQT6_API void* vqt6_qicon_create_with_file(void* file_name) { + if (file_name == nullptr) return new QIcon(); + return new QIcon(*static_cast(file_name)); +} + +extern "C" VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name) { + if (icon == nullptr || file_name == nullptr) return; + static_cast(icon)->addFile(*static_cast(file_name)); +} + +extern "C" VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap) { + if (icon == nullptr || pixmap == nullptr) return; + static_cast(icon)->addPixmap(*static_cast(pixmap)); +} + +extern "C" VQT6_API int vqt6_qicon_is_null(void* icon) { + if (icon == nullptr) return 0; + return static_cast(icon)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h) { + if (icon == nullptr) return nullptr; + return new QPixmap(static_cast(icon)->pixmap(w, h)); +} + +extern "C" VQT6_API void vqt6_qicon_free(void* icon) { + delete static_cast(icon); +} + +// ============================================================ +// QCursor +// ============================================================ +extern "C" VQT6_API void* vqt6_qcursor_create(void) { + return new QCursor(); +} + +extern "C" VQT6_API void* vqt6_qcursor_create_with_shape(int shape) { + return new QCursor(static_cast(shape)); +} + +extern "C" VQT6_API void vqt6_qcursor_pos(int* x, int* y) { + QPoint p = QCursor::pos(); + if (x != nullptr) *x = p.x(); + if (y != nullptr) *y = p.y(); +} + +extern "C" VQT6_API void vqt6_qcursor_set_pos(int x, int y) { + QCursor::setPos(x, y); +} + +extern "C" VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape) { + if (cursor == nullptr) return; + static_cast(cursor)->setShape(static_cast(shape)); +} + +extern "C" VQT6_API int vqt6_qcursor_shape(void* cursor) { + if (cursor == nullptr) return 0; + return static_cast(static_cast(cursor)->shape()); +} + +extern "C" VQT6_API void vqt6_qcursor_free(void* cursor) { + delete static_cast(cursor); +} + +// ============================================================ +// QKeyEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text) { + QString* t = static_cast(text); + return new QKeyEvent(static_cast(type), key, static_cast(modifiers), + t != nullptr ? *t : QString()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_key(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->key(); +} + +extern "C" VQT6_API void* vqt6_qkeyevent_text(void* event) { + if (event == nullptr) return nullptr; + return new QString(static_cast(event)->text()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_modifiers(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->modifiers()); +} + +extern "C" VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAutoRepeat() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qkeyevent_free(void* event) { + delete static_cast(event); +} + +// ============================================================ +// QMouseEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers) { + QPointF* lp = static_cast(local_pos); + return new QMouseEvent( + static_cast(type), + lp != nullptr ? *lp : QPointF(0, 0), + Qt::NoButton, + static_cast(button), + static_cast(modifiers) + ); +} + +extern "C" VQT6_API int vqt6_qmouseevent_button(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->button()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_buttons(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->buttons()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_x(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->position().x()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_y(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->position().y()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_global_x(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->globalPosition().x()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_global_y(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->globalPosition().y()); +} + +extern "C" VQT6_API int vqt6_qmouseevent_modifiers(void* event) { + if (event == nullptr) return 0; + return static_cast(static_cast(event)->modifiers()); +} + +extern "C" VQT6_API void vqt6_qmouseevent_free(void* event) { + delete static_cast(event); +} + +// ============================================================ +// QResizeEvent / QPaintEvent / QCloseEvent +// ============================================================ +extern "C" VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height) { + return new QResizeEvent(QSize(width, height), QSize(old_width, old_height)); +} + +extern "C" VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h) { + if (event == nullptr) return; + QSize s = static_cast(event)->size(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h) { + if (event == nullptr) return; + QSize s = static_cast(event)->oldSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qresizeevent_free(void* event) { + delete static_cast(event); +} + +extern "C" VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h) { + return new QPaintEvent(QRect(rect_x, rect_y, rect_w, rect_h)); +} + +extern "C" VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h) { + if (event == nullptr) return; + QRect r = static_cast(event)->rect(); + if (x != nullptr) *x = r.x(); + if (y != nullptr) *y = r.y(); + if (w != nullptr) *w = r.width(); + if (h != nullptr) *h = r.height(); +} + +extern "C" VQT6_API void vqt6_qpaintevent_free(void* event) { + delete static_cast(event); +} + +extern "C" VQT6_API void* vqt6_qcloseevent_create(void) { + return new QCloseEvent(); +} + +extern "C" VQT6_API int vqt6_qcloseevent_is_accepted(void* event) { + if (event == nullptr) return 0; + return static_cast(event)->isAccepted() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcloseevent_accept(void* event) { + if (event == nullptr) return; + static_cast(event)->accept(); +} + +extern "C" VQT6_API void vqt6_qcloseevent_ignore(void* event) { + if (event == nullptr) return; + static_cast(event)->ignore(); +} + +extern "C" VQT6_API void vqt6_qcloseevent_free(void* event) { + delete static_cast(event); +} diff --git a/vqt6/_bridge_gui.h b/vqt6/_bridge_gui.h new file mode 100644 index 0000000..d2bb224 --- /dev/null +++ b/vqt6/_bridge_gui.h @@ -0,0 +1,231 @@ +// ============================================================ +// vqt6/_bridge_gui.h — QtGui C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_GUI_H +#define VQT6_BRIDGE_GUI_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QColor +// ============================================================ +VQT6_API void* vqt6_qcolor_create_rgb(int r, int g, int b); +VQT6_API void* vqt6_qcolor_create_rgba(int r, int g, int b, int a); +VQT6_API void* vqt6_qcolor_create_name(void* name); +VQT6_API void* vqt6_qcolor_create_hex(void* hex_str); +VQT6_API int vqt6_qcolor_red(void* c); +VQT6_API int vqt6_qcolor_green(void* c); +VQT6_API int vqt6_qcolor_blue(void* c); +VQT6_API int vqt6_qcolor_alpha(void* c); +VQT6_API void vqt6_qcolor_set_red(void* c, int r); +VQT6_API void vqt6_qcolor_set_green(void* c, int g); +VQT6_API void vqt6_qcolor_set_blue(void* c, int b); +VQT6_API void vqt6_qcolor_set_alpha(void* c, int a); +VQT6_API void vqt6_qcolor_set_rgb(void* c, int r, int g, int b); +VQT6_API void vqt6_qcolor_set_rgba(void* c, int r, int g, int b, int a); +VQT6_API void* vqt6_qcolor_name(void* c); +VQT6_API int vqt6_qcolor_is_valid(void* c); +VQT6_API void vqt6_qcolor_free(void* c); + +// ============================================================ +// QFont +// ============================================================ +VQT6_API void* vqt6_qfont_create(void); +VQT6_API void* vqt6_qfont_create_with_family(void* family); +VQT6_API void* vqt6_qfont_create_with_family_size(void* family, int point_size); +VQT6_API void vqt6_qfont_set_family(void* font, void* family); +VQT6_API void* vqt6_qfont_family(void* font); +VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size); +VQT6_API int vqt6_qfont_point_size(void* font); +VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size); +VQT6_API int vqt6_qfont_pixel_size(void* font); +VQT6_API void vqt6_qfont_set_bold(void* font, int bold); +VQT6_API int vqt6_qfont_bold(void* font); +VQT6_API void vqt6_qfont_set_italic(void* font, int italic); +VQT6_API int vqt6_qfont_italic(void* font); +VQT6_API void vqt6_qfont_set_underline(void* font, int underline); +VQT6_API int vqt6_qfont_underline(void* font); +VQT6_API void vqt6_qfont_set_strike_out(void* font, int strike_out); +VQT6_API int vqt6_qfont_strike_out(void* font); +VQT6_API void vqt6_qfont_set_weight(void* font, int weight); +VQT6_API int vqt6_qfont_weight(void* font); +VQT6_API void vqt6_qfont_free(void* font); + +// ============================================================ +// QFontMetrics +// ============================================================ +VQT6_API void* vqt6_qfontmetrics_create(void* font); +VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text); +VQT6_API int vqt6_qfontmetrics_height(void* fm); +VQT6_API int vqt6_qfontmetrics_ascent(void* fm); +VQT6_API int vqt6_qfontmetrics_descent(void* fm); +VQT6_API void vqt6_qfontmetrics_free(void* fm); + +// ============================================================ +// QPixmap +// ============================================================ +VQT6_API void* vqt6_qpixmap_create(void); +VQT6_API void* vqt6_qpixmap_create_with_size(int w, int h); +VQT6_API int vqt6_qpixmap_load(void* pm, void* file_name); +VQT6_API int vqt6_qpixmap_load_from_data(void* pm, const void* data, size_t size); +VQT6_API int vqt6_qpixmap_save(void* pm, void* file_name); +VQT6_API int vqt6_qpixmap_width(void* pm); +VQT6_API int vqt6_qpixmap_height(void* pm); +VQT6_API int vqt6_qpixmap_is_null(void* pm); +VQT6_API void* vqt6_qpixmap_scaled(void* pm, int w, int h); +VQT6_API void vqt6_qpixmap_fill(void* pm, void* color); +VQT6_API void vqt6_qpixmap_free(void* pm); + +// ============================================================ +// QImage +// ============================================================ +VQT6_API void* vqt6_qimage_create(void); +VQT6_API void* vqt6_qimage_create_with_size(int w, int h, int format); +VQT6_API int vqt6_qimage_load(void* img, void* file_name); +VQT6_API int vqt6_qimage_save(void* img, void* file_name); +VQT6_API int vqt6_qimage_width(void* img); +VQT6_API int vqt6_qimage_height(void* img); +VQT6_API int vqt6_qimage_format(void* img); +VQT6_API int vqt6_qimage_is_null(void* img); +VQT6_API void vqt6_qimage_fill(void* img, void* color); +VQT6_API void* vqt6_qimage_scaled(void* img, int w, int h); +VQT6_API void vqt6_qimage_free(void* img); + +// ============================================================ +// QPainter +// ============================================================ +VQT6_API void* vqt6_qpainter_create(void); +VQT6_API int vqt6_qpainter_begin(void* p, void* device); +VQT6_API int vqt6_qpainter_end(void* p); +VQT6_API int vqt6_qpainter_is_active(void* p); +VQT6_API void vqt6_qpainter_set_pen(void* p, void* pen); +VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush); +VQT6_API void vqt6_qpainter_set_font(void* p, void* font); +VQT6_API void* vqt6_qpainter_pen(void* p); +VQT6_API void* vqt6_qpainter_brush(void* p); +VQT6_API void* vqt6_qpainter_font(void* p); +VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity); +VQT6_API double vqt6_qpainter_opacity(void* p); +VQT6_API void vqt6_qpainter_draw_line(void* p, int x1, int y1, int x2, int y2); +VQT6_API void vqt6_qpainter_draw_rect(void* p, int x, int y, int w, int h); +VQT6_API void vqt6_qpainter_fill_rect(void* p, int x, int y, int w, int h, void* color); +VQT6_API void vqt6_qpainter_draw_ellipse(void* p, int x, int y, int w, int h); +VQT6_API void vqt6_qpainter_draw_arc(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_chord(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_pie(void* p, int x, int y, int w, int h, int start_angle, int span_angle); +VQT6_API void vqt6_qpainter_draw_polygon(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_polyline(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y); +VQT6_API void vqt6_qpainter_draw_points(void* p, int* points, int point_count); +VQT6_API void vqt6_qpainter_draw_text(void* p, int x, int y, void* text); +VQT6_API void vqt6_qpainter_draw_text_in_rect(void* p, int x, int y, int w, int h, int flags, void* text); +VQT6_API void vqt6_qpainter_draw_pixmap(void* p, int x, int y, void* pixmap); +VQT6_API void vqt6_qpainter_draw_image(void* p, int x, int y, void* image); +VQT6_API void vqt6_qpainter_draw_tiled_pixmap(void* p, int x, int y, int w, int h, void* pixmap); +VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy); +VQT6_API void vqt6_qpainter_rotate(void* p, double angle); +VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy); +VQT6_API void vqt6_qpainter_reset_transform(void* p); +VQT6_API void vqt6_qpainter_save(void* p); +VQT6_API void vqt6_qpainter_restore(void* p); +VQT6_API void vqt6_qpainter_free(void* p); + +// ============================================================ +// QPen +// ============================================================ +VQT6_API void* vqt6_qpen_create(void); +VQT6_API void* vqt6_qpen_create_with_color(void* color); +VQT6_API void* vqt6_qpen_create_with_color_width(void* color, int width); +VQT6_API void vqt6_qpen_set_color(void* pen, void* color); +VQT6_API void* vqt6_qpen_color(void* pen); +VQT6_API void vqt6_qpen_set_width(void* pen, int width); +VQT6_API int vqt6_qpen_width(void* pen); +VQT6_API void vqt6_qpen_set_style(void* pen, int style); +VQT6_API int vqt6_qpen_style(void* pen); +VQT6_API void vqt6_qpen_free(void* pen); + +// ============================================================ +// QBrush +// ============================================================ +VQT6_API void* vqt6_qbrush_create(void); +VQT6_API void* vqt6_qbrush_create_with_color(void* color); +VQT6_API void* vqt6_qbrush_create_with_style(int style); +VQT6_API void vqt6_qbrush_set_color(void* brush, void* color); +VQT6_API void* vqt6_qbrush_color(void* brush); +VQT6_API void vqt6_qbrush_set_style(void* brush, int style); +VQT6_API int vqt6_qbrush_style(void* brush); +VQT6_API void vqt6_qbrush_free(void* brush); + +// ============================================================ +// QIcon +// ============================================================ +VQT6_API void* vqt6_qicon_create(void); +VQT6_API void* vqt6_qicon_create_with_file(void* file_name); +VQT6_API void vqt6_qicon_add_file(void* icon, void* file_name); +VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap); +VQT6_API int vqt6_qicon_is_null(void* icon); +VQT6_API void* vqt6_qicon_pixmap(void* icon, int w, int h); +VQT6_API void vqt6_qicon_free(void* icon); + +// ============================================================ +// QCursor +// ============================================================ +VQT6_API void* vqt6_qcursor_create(void); +VQT6_API void* vqt6_qcursor_create_with_shape(int shape); +VQT6_API void vqt6_qcursor_pos(int* x, int* y); +VQT6_API void vqt6_qcursor_set_pos(int x, int y); +VQT6_API void vqt6_qcursor_set_shape(void* cursor, int shape); +VQT6_API int vqt6_qcursor_shape(void* cursor); +VQT6_API void vqt6_qcursor_free(void* cursor); + +// ============================================================ +// QKeyEvent +// ============================================================ +VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text); +VQT6_API int vqt6_qkeyevent_key(void* event); +VQT6_API void* vqt6_qkeyevent_text(void* event); +VQT6_API int vqt6_qkeyevent_modifiers(void* event); +VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event); +VQT6_API void vqt6_qkeyevent_free(void* event); + +// ============================================================ +// QMouseEvent +// ============================================================ +VQT6_API void* vqt6_qmouseevent_create(int type, void* local_pos, int button, int buttons, int modifiers); +VQT6_API int vqt6_qmouseevent_button(void* event); +VQT6_API int vqt6_qmouseevent_buttons(void* event); +VQT6_API int vqt6_qmouseevent_x(void* event); +VQT6_API int vqt6_qmouseevent_y(void* event); +VQT6_API int vqt6_qmouseevent_global_x(void* event); +VQT6_API int vqt6_qmouseevent_global_y(void* event); +VQT6_API int vqt6_qmouseevent_modifiers(void* event); +VQT6_API void vqt6_qmouseevent_free(void* event); + +// ============================================================ +// QResizeEvent / QPaintEvent / QCloseEvent +// ============================================================ +VQT6_API void* vqt6_qresizeevent_create(int width, int height, int old_width, int old_height); +VQT6_API void vqt6_qresizeevent_size(void* event, int* w, int* h); +VQT6_API void vqt6_qresizeevent_old_size(void* event, int* w, int* h); +VQT6_API void vqt6_qresizeevent_free(void* event); + +VQT6_API void* vqt6_qpaintevent_create(int rect_x, int rect_y, int rect_w, int rect_h); +VQT6_API void vqt6_qpaintevent_rect(void* event, int* x, int* y, int* w, int* h); +VQT6_API void vqt6_qpaintevent_free(void* event); + +VQT6_API void* vqt6_qcloseevent_create(void); +VQT6_API int vqt6_qcloseevent_is_accepted(void* event); +VQT6_API void vqt6_qcloseevent_accept(void* event); +VQT6_API void vqt6_qcloseevent_ignore(void* event); +VQT6_API void vqt6_qcloseevent_free(void* event); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_GUI_H diff --git a/vqt6/_bridge_network.cpp b/vqt6/_bridge_network.cpp new file mode 100644 index 0000000..00cab5e --- /dev/null +++ b/vqt6/_bridge_network.cpp @@ -0,0 +1,519 @@ +// ============================================================ +// vqt6/_bridge_network.cpp — QtNetwork C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_network.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QHostAddress +// ============================================================ +extern "C" VQT6_API void* vqt6_qhostaddress_create(void) { + return new QHostAddress(); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4) { + return new QHostAddress(static_cast(ipv4)); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_string(void* address) { + if (address == nullptr) return new QHostAddress(); + return new QHostAddress(*static_cast(address)); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_host(void) { + return new QHostAddress(QHostAddress::LocalHost); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void) { + return new QHostAddress(QHostAddress::LocalHostIPv4); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void) { + return new QHostAddress(QHostAddress::Broadcast); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void) { + return new QHostAddress(QHostAddress::AnyIPv4); +} + +extern "C" VQT6_API void* vqt6_qhostaddress_to_string(void* addr) { + if (addr == nullptr) return nullptr; + return new QString(static_cast(addr)->toString()); +} + +extern "C" VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr) { + if (addr == nullptr) return 0; + return static_cast(static_cast(addr)->toIPv4Address()); +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_null(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isNull() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_loopback(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isLoopback() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr) { + if (addr == nullptr) return 0; + return static_cast(addr)->isBroadcast() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qhostaddress_protocol(void* addr) { + if (addr == nullptr) return 0; + return static_cast(static_cast(addr)->protocol()); +} + +extern "C" VQT6_API void vqt6_qhostaddress_free(void* addr) { + delete static_cast(addr); +} + +// ============================================================ +// QAbstractSocket +// ============================================================ +extern "C" VQT6_API int vqt6_qabstractsocket_state(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->state()); +} + +extern "C" VQT6_API int vqt6_qabstractsocket_error(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->error()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_error_string(void* socket) { + if (socket == nullptr) return nullptr; + return new QString(static_cast(socket)->errorString()); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port) { + if (socket == nullptr || host_name == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(host_name), port); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port) { + if (socket == nullptr || address == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(address), port); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->disconnectFromHost(); +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForConnected(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForReadyRead(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForBytesWritten(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms) { + if (socket == nullptr) return 0; + return static_cast(socket)->waitForDisconnected(timeout_ms) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_is_valid(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->isValid() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_is_open(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->isOpen() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qabstractsocket_flush(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->flush() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qabstractsocket_close(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->close(); +} + +extern "C" VQT6_API void vqt6_qabstractsocket_abort(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->abort(); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size) { + if (socket == nullptr || buf == nullptr) return 0; + return static_cast(static_cast(socket)->read(static_cast(buf), static_cast(max_size))); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size) { + if (socket == nullptr) return nullptr; + QByteArray ba = static_cast(socket)->readAll(); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size) { + if (socket == nullptr || data == nullptr) return 0; + return static_cast(static_cast(socket)->write(static_cast(data), static_cast(size))); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->bytesAvailable()); +} + +extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->bytesToWrite()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket) { + if (socket == nullptr) return nullptr; + return new QHostAddress(static_cast(socket)->peerAddress()); +} + +extern "C" VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->peerPort()); +} + +extern "C" VQT6_API void* vqt6_qabstractsocket_local_address(void* socket) { + if (socket == nullptr) return nullptr; + return new QHostAddress(static_cast(socket)->localAddress()); +} + +extern "C" VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->localPort()); +} + +// ============================================================ +// QTcpSocket +// ============================================================ +extern "C" VQT6_API void* vqt6_qtcpsocket_create(void) { + return new QTcpSocket(); +} + +extern "C" VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTcpSocket(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode) { + if (socket == nullptr || host_name == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(host_name), port, + static_cast(mode)); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode) { + if (socket == nullptr || address == nullptr) return; + static_cast(socket)->connectToHost(*static_cast(address), port, + static_cast(mode)); +} + +extern "C" VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor) { + if (socket == nullptr) return 0; + return static_cast(socket)->setSocketDescriptor(static_cast(socket_descriptor)) ? 1 : 0; +} + +extern "C" VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket) { + if (socket == nullptr) return -1; + return static_cast(static_cast(socket)->socketDescriptor()); +} + +extern "C" VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type) { + Q_UNUSED(socket); + Q_UNUSED(proxy_type); + // QNetworkProxy 配置在更高层 +} + +extern "C" VQT6_API void vqt6_qtcpsocket_abort(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->abort(); +} + +// ============================================================ +// QUdpSocket +// ============================================================ +extern "C" VQT6_API void* vqt6_qudpsocket_create(void) { + return new QUdpSocket(); +} + +extern "C" VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QUdpSocket(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port) { + if (socket == nullptr) return 0; + return static_cast(socket)->bind(port) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port) { + if (socket == nullptr || address == nullptr) return 0; + return static_cast(socket)->bind(*static_cast(address), port) ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qudpsocket_close(void* socket) { + if (socket == nullptr) return; + static_cast(socket)->close(); +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port) { + if (socket == nullptr || data == nullptr || host == nullptr) return 0; + return static_cast(static_cast(socket)->writeDatagram( + static_cast(data), static_cast(size), + *static_cast(host), port)); +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port) { + if (socket == nullptr || data == nullptr) return 0; + QHostAddress sender; + quint16 sender_port = 0; + qint64 n = static_cast(socket)->readDatagram( + static_cast(data), static_cast(max_size), &sender, &sender_port); + if (host != nullptr) { + QHostAddress* dst = static_cast(host); + *dst = sender; + } + if (port != nullptr) { + *port = sender_port; + } + return static_cast(n); +} + +extern "C" VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket) { + if (socket == nullptr) return 0; + return static_cast(socket)->hasPendingDatagrams() ? 1 : 0; +} + +extern "C" VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket) { + if (socket == nullptr) return 0; + return static_cast(static_cast(socket)->pendingDatagramSize()); +} + +extern "C" VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address) { + if (socket == nullptr || group_address == nullptr) return 0; + return static_cast(socket)->joinMulticastGroup(*static_cast(group_address)) ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address) { + if (socket == nullptr || group_address == nullptr) return 0; + return static_cast(socket)->leaveMulticastGroup(*static_cast(group_address)) ? 1 : 0; +} + +// ============================================================ +// QNetworkRequest +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkrequest_create(void) { + return new QNetworkRequest(); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url) { + if (url == nullptr) return new QNetworkRequest(); + return new QNetworkRequest(QUrl(*static_cast(url))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url) { + if (req == nullptr || url == nullptr) return; + static_cast(req)->setUrl(QUrl(*static_cast(url))); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_url(void* req) { + if (req == nullptr) return nullptr; + return new QString(static_cast(req)->url().toString()); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value) { + if (req == nullptr || value == nullptr) return; + static_cast(req)->setHeader(static_cast(header_type), + *static_cast(value)); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type) { + if (req == nullptr) return nullptr; + return new QVariant(static_cast(req)->header(static_cast(header_type))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size) { + if (req == nullptr || header_name == nullptr) return; + static_cast(req)->setRawHeader(QByteArray(header_name), + QByteArray(static_cast(value), static_cast(value_size))); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size) { + if (req == nullptr || header_name == nullptr) return nullptr; + QByteArray ba = static_cast(req)->rawHeader(QByteArray(header_name)); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value) { + if (req == nullptr || value == nullptr) return; + static_cast(req)->setAttribute(static_cast(attr_type), + *static_cast(value)); +} + +extern "C" VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type) { + if (req == nullptr) return nullptr; + return new QVariant(static_cast(req)->attribute(static_cast(attr_type))); +} + +extern "C" VQT6_API void vqt6_qnetworkrequest_free(void* req) { + delete static_cast(req); +} + +// ============================================================ +// QNetworkAccessManager +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create(void) { + return new QNetworkAccessManager(); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QNetworkAccessManager(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->get(*static_cast(req)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size) { + if (nam == nullptr || req == nullptr) return nullptr; + QByteArray payload; + if (data != nullptr && size > 0) { + payload = QByteArray(static_cast(data), static_cast(size)); + } + return static_cast(nam)->post(*static_cast(req), payload); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size) { + if (nam == nullptr || req == nullptr) return nullptr; + QByteArray payload; + if (data != nullptr && size > 0) { + payload = QByteArray(static_cast(data), static_cast(size)); + } + return static_cast(nam)->put(*static_cast(req), payload); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->deleteResource(*static_cast(req)); +} + +extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req) { + if (nam == nullptr || req == nullptr) return nullptr; + return static_cast(nam)->head(*static_cast(req)); +} + +extern "C" VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store) { + if (nam == nullptr || store == nullptr) return; + QNetworkCookieJar* jar = qobject_cast(static_cast(store)); + if (jar != nullptr) { + static_cast(nam)->setCookieJar(jar); + } +} + +// ============================================================ +// QNetworkReply +// ============================================================ +extern "C" VQT6_API void* vqt6_qnetworkreply_url(void* reply) { + if (reply == nullptr) return nullptr; + return new QString(static_cast(reply)->url().toString()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_request(void* reply) { + if (reply == nullptr) return nullptr; + return new QNetworkRequest(static_cast(reply)->request()); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_error(void* reply) { + if (reply == nullptr) return 0; + return static_cast(static_cast(reply)->error()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_error_string(void* reply) { + if (reply == nullptr) return nullptr; + return new QString(static_cast(reply)->errorString()); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_is_finished(void* reply) { + if (reply == nullptr) return 0; + return static_cast(reply)->isFinished() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qnetworkreply_is_running(void* reply) { + if (reply == nullptr) return 0; + return static_cast(reply)->isRunning() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qnetworkreply_abort(void* reply) { + if (reply == nullptr) return; + static_cast(reply)->abort(); +} + +extern "C" VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size) { + if (reply == nullptr || buf == nullptr) return 0; + return static_cast(static_cast(reply)->read(static_cast(buf), static_cast(max_size))); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size) { + if (reply == nullptr) return nullptr; + QByteArray ba = static_cast(reply)->readAll(); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply) { + if (reply == nullptr) return 0; + return static_cast(static_cast(reply)->bytesAvailable()); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type) { + if (reply == nullptr) return nullptr; + return new QVariant(static_cast(reply)->header(static_cast(header_type))); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size) { + if (reply == nullptr || header_name == nullptr) return nullptr; + QByteArray ba = static_cast(reply)->rawHeader(QByteArray(header_name)); + if (out_size != nullptr) *out_size = static_cast(ba.size()); + return ba.data(); +} + +extern "C" VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code) { + if (reply == nullptr) return nullptr; + return new QVariant(static_cast(reply)->attribute(static_cast(attribute_code))); +} + +extern "C" VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value) { + if (reply == nullptr) return default_value; + return static_cast(reply)->attribute(static_cast(attribute_code)).toInt(default_value); +} + +extern "C" VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size) { + if (reply == nullptr || header_name == nullptr) return; + static_cast(reply)->setRawHeader(QByteArray(header_name), + QByteArray(static_cast(value), static_cast(value_size))); +} diff --git a/vqt6/_bridge_network.h b/vqt6/_bridge_network.h new file mode 100644 index 0000000..2f99580 --- /dev/null +++ b/vqt6/_bridge_network.h @@ -0,0 +1,137 @@ +// ============================================================ +// vqt6/_bridge_network.h — QtNetwork C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_NETWORK_H +#define VQT6_BRIDGE_NETWORK_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QHostAddress +// ============================================================ +VQT6_API void* vqt6_qhostaddress_create(void); +VQT6_API void* vqt6_qhostaddress_create_with_ipv4(uint32_t ipv4); +VQT6_API void* vqt6_qhostaddress_create_with_string(void* address); +VQT6_API void* vqt6_qhostaddress_create_with_local_host(void); +VQT6_API void* vqt6_qhostaddress_create_with_local_ipv4(void); +VQT6_API void* vqt6_qhostaddress_create_with_broadcast(void); +VQT6_API void* vqt6_qhostaddress_create_with_any_ipv4(void); +VQT6_API void* vqt6_qhostaddress_to_string(void* addr); +VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr); +VQT6_API int vqt6_qhostaddress_is_null(void* addr); +VQT6_API int vqt6_qhostaddress_is_loopback(void* addr); +VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr); +VQT6_API int vqt6_qhostaddress_protocol(void* addr); +VQT6_API void vqt6_qhostaddress_free(void* addr); + +// ============================================================ +// QAbstractSocket +// ============================================================ +VQT6_API int vqt6_qabstractsocket_state(void* socket); +VQT6_API int vqt6_qabstractsocket_error(void* socket); +VQT6_API void* vqt6_qabstractsocket_error_string(void* socket); +VQT6_API void vqt6_qabstractsocket_connect_to_host(void* socket, void* host_name, uint16_t port); +VQT6_API void vqt6_qabstractsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port); +VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket); +VQT6_API int vqt6_qabstractsocket_wait_for_connected(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_ready_read(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_bytes_written(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_wait_for_disconnected(void* socket, int timeout_ms); +VQT6_API int vqt6_qabstractsocket_is_valid(void* socket); +VQT6_API int vqt6_qabstractsocket_is_open(void* socket); +VQT6_API int vqt6_qabstractsocket_flush(void* socket); +VQT6_API void vqt6_qabstractsocket_close(void* socket); +VQT6_API void vqt6_qabstractsocket_abort(void* socket); +VQT6_API size_t vqt6_qabstractsocket_read(void* socket, void* buf, size_t max_size); +VQT6_API void* vqt6_qabstractsocket_read_all(void* socket, size_t* out_size); +VQT6_API size_t vqt6_qabstractsocket_write(void* socket, const void* data, size_t size); +VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket); +VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket); +VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket); +VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket); +VQT6_API void* vqt6_qabstractsocket_local_address(void* socket); +VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket); + +// ============================================================ +// QTcpSocket +// ============================================================ +VQT6_API void* vqt6_qtcpsocket_create(void); +VQT6_API void* vqt6_qtcpsocket_create_with_parent(void* parent); +VQT6_API void vqt6_qtcpsocket_connect_to_host(void* socket, void* host_name, uint16_t port, int mode); +VQT6_API void vqt6_qtcpsocket_connect_to_host_with_addr(void* socket, void* address, uint16_t port, int mode); +VQT6_API int vqt6_qtcpsocket_set_socket_descriptor(void* socket, intptr_t socket_descriptor); +VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket); +VQT6_API void vqt6_qtcpsocket_set_proxy(void* socket, int proxy_type); +VQT6_API void vqt6_qtcpsocket_abort(void* socket); + +// ============================================================ +// QUdpSocket +// ============================================================ +VQT6_API void* vqt6_qudpsocket_create(void); +VQT6_API void* vqt6_qudpsocket_create_with_parent(void* parent); +VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port); +VQT6_API int vqt6_qudpsocket_bind_with_addr(void* socket, void* address, uint16_t port); +VQT6_API void vqt6_qudpsocket_close(void* socket); +VQT6_API size_t vqt6_qudpsocket_write_datagram(void* socket, const void* data, size_t size, void* host, uint16_t port); +VQT6_API size_t vqt6_qudpsocket_read_datagram(void* socket, void* data, size_t max_size, void* host, uint16_t* port); +VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket); +VQT6_API size_t vqt6_qudpsocket_pending_datagram_size(void* socket); +VQT6_API int vqt6_qudpsocket_join_multicast_group(void* socket, void* group_address); +VQT6_API int vqt6_qudpsocket_leave_multicast_group(void* socket, void* group_address); + +// ============================================================ +// QNetworkRequest +// ============================================================ +VQT6_API void* vqt6_qnetworkrequest_create(void); +VQT6_API void* vqt6_qnetworkrequest_create_with_url(void* url); +VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url); +VQT6_API void* vqt6_qnetworkrequest_url(void* req); +VQT6_API void vqt6_qnetworkrequest_set_header(void* req, int header_type, void* value); +VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type); +VQT6_API void vqt6_qnetworkrequest_set_raw_header(void* req, const char* header_name, const void* value, size_t value_size); +VQT6_API void* vqt6_qnetworkrequest_raw_header(void* req, const char* header_name, size_t* out_size); +VQT6_API void vqt6_qnetworkrequest_set_attribute(void* req, int attr_type, void* value); +VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type); +VQT6_API void vqt6_qnetworkrequest_free(void* req); + +// ============================================================ +// QNetworkAccessManager +// ============================================================ +VQT6_API void* vqt6_qnetworkaccessmanager_create(void); +VQT6_API void* vqt6_qnetworkaccessmanager_create_with_parent(void* parent); +VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req); +VQT6_API void* vqt6_qnetworkaccessmanager_post(void* nam, void* req, const void* data, size_t size); +VQT6_API void* vqt6_qnetworkaccessmanager_put(void* nam, void* req, const void* data, size_t size); +VQT6_API void* vqt6_qnetworkaccessmanager_delete_resource(void* nam, void* req); +VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req); +VQT6_API void vqt6_qnetworkaccessmanager_set_cookie_store(void* nam, void* store); + +// ============================================================ +// QNetworkReply +// ============================================================ +VQT6_API void* vqt6_qnetworkreply_url(void* reply); +VQT6_API void* vqt6_qnetworkreply_request(void* reply); +VQT6_API int vqt6_qnetworkreply_error(void* reply); +VQT6_API void* vqt6_qnetworkreply_error_string(void* reply); +VQT6_API int vqt6_qnetworkreply_is_finished(void* reply); +VQT6_API int vqt6_qnetworkreply_is_running(void* reply); +VQT6_API void vqt6_qnetworkreply_abort(void* reply); +VQT6_API size_t vqt6_qnetworkreply_read(void* reply, void* buf, size_t max_size); +VQT6_API void* vqt6_qnetworkreply_read_all(void* reply, size_t* out_size); +VQT6_API size_t vqt6_qnetworkreply_bytes_available(void* reply); +VQT6_API void* vqt6_qnetworkreply_header(void* reply, int header_type); +VQT6_API void* vqt6_qnetworkreply_raw_header(void* reply, const char* header_name, size_t* out_size); +VQT6_API void* vqt6_qnetworkreply_attribute(void* reply, int attribute_code); +VQT6_API int vqt6_qnetworkreply_attribute_int(void* reply, int attribute_code, int default_value); +VQT6_API void vqt6_qnetworkreply_set_raw_header(void* reply, const char* header_name, const void* value, size_t value_size); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_NETWORK_H diff --git a/vqt6/_bridge_widgets.cpp b/vqt6/_bridge_widgets.cpp new file mode 100644 index 0000000..2b963a5 --- /dev/null +++ b/vqt6/_bridge_widgets.cpp @@ -0,0 +1,1745 @@ +// ============================================================ +// vqt6/_bridge_widgets.cpp — QtWidgets C 桥接层实现 +// ============================================================ + +#include "_bridge.h" +#include "_bridge_widgets.h" +#include "_bridge_gui.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================ +// QApplication +// ============================================================ +extern "C" VQT6_API void* vqt6_qapplication_create(int argc, char** argv) { + return new QApplication(argc, argv); +} + +extern "C" VQT6_API void* vqt6_qapplication_instance(void) { + return QApplication::instance(); +} + +extern "C" VQT6_API int vqt6_qapplication_exec(void* app) { + if (app == nullptr) return -1; + return static_cast(app)->exec(); +} + +extern "C" VQT6_API void vqt6_qapplication_quit(void* app) { + if (app == nullptr) return; + static_cast(app)->quit(); +} + +extern "C" VQT6_API void vqt6_qapplication_exit(void* app, int exit_code) { + if (app == nullptr) return; + static_cast(app)->exit(exit_code); +} + +extern "C" VQT6_API void vqt6_qapplication_process_events(void* app) { + if (app == nullptr) return; + static_cast(app)->processEvents(); +} + +extern "C" VQT6_API int vqt6_qapplication_desktop_width(void* app) { + if (app == nullptr) return 0; + QScreen* screen = static_cast(app)->primaryScreen(); + return screen != nullptr ? screen->size().width() : 0; +} + +extern "C" VQT6_API int vqt6_qapplication_desktop_height(void* app) { + if (app == nullptr) return 0; + QScreen* screen = static_cast(app)->primaryScreen(); + return screen != nullptr ? screen->size().height() : 0; +} + +extern "C" VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit) { + if (app == nullptr) return; + static_cast(app)->setQuitOnLastWindowClosed(quit != 0); +} + +extern "C" VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app) { + if (app == nullptr) return 0; + return QApplication::quitOnLastWindowClosed() ? 1 : 0; +} + +// ============================================================ +// QWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qwidget_create(void) { + return new QWidget(); +} + +extern "C" VQT6_API void* vqt6_qwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QWidget(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qwidget_show(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->show(); +} + +extern "C" VQT6_API void vqt6_qwidget_hide(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->hide(); +} + +extern "C" VQT6_API int vqt6_qwidget_close(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->close() ? 1 : 0; +} + +extern "C" VQT6_API int vqt6_qwidget_is_visible(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->isVisible() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible) { + if (widget == nullptr) return; + static_cast(widget)->setVisible(visible != 0); +} + +extern "C" VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setGeometry(x, y, w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h) { + if (widget == nullptr) return; + QRect r = static_cast(widget)->geometry(); + if (x != nullptr) *x = r.x(); + if (y != nullptr) *y = r.y(); + if (w != nullptr) *w = r.width(); + if (h != nullptr) *h = r.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->resize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->size(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_move(void* widget, int x, int y) { + if (widget == nullptr) return; + static_cast(widget)->move(x, y); +} + +extern "C" VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y) { + if (widget == nullptr) return; + QPoint p = static_cast(widget)->pos(); + if (x != nullptr) *x = p.x(); + if (y != nullptr) *y = p.y(); +} + +extern "C" VQT6_API int vqt6_qwidget_width(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->width(); +} + +extern "C" VQT6_API int vqt6_qwidget_height(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->height(); +} + +extern "C" VQT6_API int vqt6_qwidget_x(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->x(); +} + +extern "C" VQT6_API int vqt6_qwidget_y(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->y(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title) { + if (widget == nullptr || title == nullptr) return; + static_cast(widget)->setWindowTitle(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qwidget_window_title(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->windowTitle()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_text(void* widget, void* text) { + if (widget == nullptr || text == nullptr) return; + static_cast(widget)->setWindowTitle(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qwidget_text(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->windowTitle()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled) { + if (widget == nullptr) return; + static_cast(widget)->setEnabled(enabled != 0); +} + +extern "C" VQT6_API int vqt6_qwidget_is_enabled(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->isEnabled() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent) { + if (widget == nullptr) return; + static_cast(widget)->setParent(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qwidget_parent_widget(void* widget) { + if (widget == nullptr) return nullptr; + return static_cast(widget)->parentWidget(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_focus(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->setFocus(); +} + +extern "C" VQT6_API void vqt6_qwidget_clear_focus(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->clearFocus(); +} + +extern "C" VQT6_API int vqt6_qwidget_has_focus(void* widget) { + if (widget == nullptr) return 0; + return static_cast(widget)->hasFocus() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy) { + if (widget == nullptr) return; + static_cast(widget)->setFocusPolicy(static_cast(policy)); +} + +extern "C" VQT6_API void vqt6_qwidget_update(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->update(); +} + +extern "C" VQT6_API void vqt6_qwidget_repaint(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->repaint(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled) { + if (widget == nullptr) return; + static_cast(widget)->setUpdatesEnabled(enabled != 0); +} + +extern "C" VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags) { + if (widget == nullptr) return; + static_cast(widget)->setWindowFlags(static_cast(flags)); +} + +extern "C" VQT6_API int vqt6_qwidget_window_flags(void* widget) { + if (widget == nullptr) return 0; + return static_cast(static_cast(widget)->windowFlags()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor) { + if (widget == nullptr || cursor == nullptr) return; + static_cast(widget)->setCursor(*static_cast(cursor)); +} + +extern "C" VQT6_API void* vqt6_qwidget_cursor(void* widget) { + if (widget == nullptr) return nullptr; + return new QCursor(static_cast(widget)->cursor()); +} + +extern "C" VQT6_API void vqt6_qwidget_unset_cursor(void* widget) { + if (widget == nullptr) return; + static_cast(widget)->unsetCursor(); +} + +extern "C" VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip) { + if (widget == nullptr || tip == nullptr) return; + static_cast(widget)->setToolTip(*static_cast(tip)); +} + +extern "C" VQT6_API void* vqt6_qwidget_tool_tip(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->toolTip()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip) { + if (widget == nullptr || tip == nullptr) return; + static_cast(widget)->setStatusTip(*static_cast(tip)); +} + +extern "C" VQT6_API void* vqt6_qwidget_status_tip(void* widget) { + if (widget == nullptr) return nullptr; + return new QString(static_cast(widget)->statusTip()); +} + +extern "C" VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setMinimumSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setMaximumSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h) { + if (widget == nullptr) return; + static_cast(widget)->setFixedSize(w, h); +} + +extern "C" VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->minimumSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +extern "C" VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h) { + if (widget == nullptr) return; + QSize s = static_cast(widget)->maximumSize(); + if (w != nullptr) *w = s.width(); + if (h != nullptr) *h = s.height(); +} + +// ============================================================ +// QDialog +// ============================================================ +extern "C" VQT6_API void* vqt6_qdialog_create(void) { + return new QDialog(); +} + +extern "C" VQT6_API void* vqt6_qdialog_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QDialog(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qdialog_exec(void* dialog) { + if (dialog == nullptr) return -1; + return static_cast(dialog)->exec(); +} + +extern "C" VQT6_API void vqt6_qdialog_done(void* dialog, int result) { + if (dialog == nullptr) return; + static_cast(dialog)->done(result); +} + +extern "C" VQT6_API void vqt6_qdialog_accept(void* dialog) { + if (dialog == nullptr) return; + static_cast(dialog)->accept(); +} + +extern "C" VQT6_API void vqt6_qdialog_reject(void* dialog) { + if (dialog == nullptr) return; + static_cast(dialog)->reject(); +} + +extern "C" VQT6_API void vqt6_qdialog_set_result(void* dialog, int result) { + if (dialog == nullptr) return; + static_cast(dialog)->setResult(result); +} + +extern "C" VQT6_API int vqt6_qdialog_result(void* dialog) { + if (dialog == nullptr) return 0; + return static_cast(dialog)->result(); +} + +extern "C" VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal) { + if (dialog == nullptr) return; + static_cast(dialog)->setModal(modal != 0); +} + +extern "C" VQT6_API int vqt6_qdialog_is_modal(void* dialog) { + if (dialog == nullptr) return 0; + return static_cast(dialog)->isModal() ? 1 : 0; +} + +// ============================================================ +// QMainWindow +// ============================================================ +extern "C" VQT6_API void* vqt6_qmainwindow_create(void) { + return new QMainWindow(); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QMainWindow(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget) { + if (mw == nullptr) return; + static_cast(mw)->setCentralWidget(static_cast(widget)); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_central_widget(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->centralWidget(); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->menuBar(); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar) { + if (mw == nullptr) return; + static_cast(mw)->setMenuBar(static_cast(menubar)); +} + +extern "C" VQT6_API void* vqt6_qmainwindow_status_bar(void* mw) { + if (mw == nullptr) return nullptr; + return static_cast(mw)->statusBar(); +} + +extern "C" VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar) { + if (mw == nullptr) return; + static_cast(mw)->setStatusBar(static_cast(statusbar)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar) { + if (mw == nullptr) return; + static_cast(mw)->addToolBar(static_cast(toolbar)); +} + +extern "C" VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw) { + if (mw == nullptr) return; + static_cast(mw)->addToolBarBreak(); +} + +// ============================================================ +// QLabel +// ============================================================ +extern "C" VQT6_API void* vqt6_qlabel_create(void) { + return new QLabel(); +} + +extern "C" VQT6_API void* vqt6_qlabel_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QLabel(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QLabel(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qlabel_set_text(void* label, void* text) { + if (label == nullptr || text == nullptr) return; + static_cast(label)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlabel_text(void* label) { + if (label == nullptr) return nullptr; + return new QString(static_cast(label)->text()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment) { + if (label == nullptr) return; + static_cast(label)->setAlignment(static_cast(alignment)); +} + +extern "C" VQT6_API int vqt6_qlabel_alignment(void* label) { + if (label == nullptr) return 0; + return static_cast(static_cast(label)->alignment()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap) { + if (label == nullptr || pixmap == nullptr) return; + static_cast(label)->setPixmap(*static_cast(pixmap)); +} + +extern "C" VQT6_API void* vqt6_qlabel_pixmap(void* label) { + if (label == nullptr) return nullptr; + return new QPixmap(static_cast(label)->pixmap()); +} + +extern "C" VQT6_API void vqt6_qlabel_set_indent(void* label, int indent) { + if (label == nullptr) return; + static_cast(label)->setIndent(indent); +} + +extern "C" VQT6_API void vqt6_qlabel_set_margin(void* label, int margin) { + if (label == nullptr) return; + static_cast(label)->setMargin(margin); +} + +extern "C" VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap) { + if (label == nullptr) return; + static_cast(label)->setWordWrap(wrap != 0); +} + +extern "C" VQT6_API int vqt6_qlabel_word_wrap(void* label) { + if (label == nullptr) return 0; + return static_cast(label)->wordWrap() ? 1 : 0; +} + +// ============================================================ +// QPushButton +// ============================================================ +extern "C" VQT6_API void* vqt6_qpushbutton_create(void) { + return new QPushButton(); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QPushButton(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QPushButton(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text) { + if (btn == nullptr || text == nullptr) return; + static_cast(btn)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_text(void* btn) { + if (btn == nullptr) return nullptr; + return new QString(static_cast(btn)->text()); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon) { + if (btn == nullptr || icon == nullptr) return; + static_cast(btn)->setIcon(*static_cast(icon)); +} + +extern "C" VQT6_API void* vqt6_qpushbutton_icon(void* btn) { + if (btn == nullptr) return nullptr; + return new QIcon(static_cast(btn)->icon()); +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default) { + if (btn == nullptr) return; + static_cast(btn)->setDefault(is_default != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_default(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isDefault() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat) { + if (btn == nullptr) return; + static_cast(btn)->setFlat(flat != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_flat(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isFlat() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable) { + if (btn == nullptr) return; + static_cast(btn)->setCheckable(checkable != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_checkable(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isCheckable() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked) { + if (btn == nullptr) return; + static_cast(btn)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qpushbutton_is_checked(void* btn) { + if (btn == nullptr) return 0; + return static_cast(btn)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qpushbutton_click(void* btn) { + if (btn == nullptr) return; + static_cast(btn)->click(); +} + +// ============================================================ +// QLineEdit +// ============================================================ +extern "C" VQT6_API void* vqt6_qlineedit_create(void) { + return new QLineEdit(); +} + +extern "C" VQT6_API void* vqt6_qlineedit_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QLineEdit(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QLineEdit(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_text(void* le) { + if (le == nullptr) return nullptr; + return new QString(static_cast(le)->text()); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_text(void* le, void* text) { + if (le == nullptr || text == nullptr) return; + static_cast(le)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qlineedit_placeholder_text(void* le) { + if (le == nullptr) return nullptr; + return new QString(static_cast(le)->placeholderText()); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text) { + if (le == nullptr || text == nullptr) return; + static_cast(le)->setPlaceholderText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max) { + if (le == nullptr) return; + static_cast(le)->setMaxLength(max); +} + +extern "C" VQT6_API int vqt6_qlineedit_max_length(void* le) { + if (le == nullptr) return 0; + return static_cast(le)->maxLength(); +} + +extern "C" VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro) { + if (le == nullptr) return; + static_cast(le)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qlineedit_is_read_only(void* le) { + if (le == nullptr) return 0; + return static_cast(le)->isReadOnly() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode) { + if (le == nullptr) return; + static_cast(le)->setEchoMode(static_cast(mode)); +} + +extern "C" VQT6_API int vqt6_qlineedit_echo_mode(void* le) { + if (le == nullptr) return 0; + return static_cast(static_cast(le)->echoMode()); +} + +extern "C" VQT6_API void vqt6_qlineedit_select_all(void* le) { + if (le == nullptr) return; + static_cast(le)->selectAll(); +} + +extern "C" VQT6_API void vqt6_qlineedit_clear(void* le) { + if (le == nullptr) return; + static_cast(le)->clear(); +} + +// ============================================================ +// QTextEdit / QPlainTextEdit +// ============================================================ +extern "C" VQT6_API void* vqt6_qtextedit_create(void) { + return new QTextEdit(); +} + +extern "C" VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTextEdit(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qtextedit_to_plain_text(void* te) { + if (te == nullptr) return nullptr; + return new QString(static_cast(te)->toPlainText()); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text) { + if (te == nullptr || text == nullptr) return; + static_cast(te)->setPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_html(void* te, void* html) { + if (te == nullptr || html == nullptr) return; + static_cast(te)->setHtml(*static_cast(html)); +} + +extern "C" VQT6_API void* vqt6_qtextedit_to_html(void* te) { + if (te == nullptr) return nullptr; + return new QString(static_cast(te)->toHtml()); +} + +extern "C" VQT6_API void vqt6_qtextedit_append(void* te, void* text) { + if (te == nullptr || text == nullptr) return; + static_cast(te)->append(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtextedit_clear(void* te) { + if (te == nullptr) return; + static_cast(te)->clear(); +} + +extern "C" VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro) { + if (te == nullptr) return; + static_cast(te)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qtextedit_is_read_only(void* te) { + if (te == nullptr) return 0; + return static_cast(te)->isReadOnly() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_create(void) { + return new QPlainTextEdit(); +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QPlainTextEdit(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte) { + if (pte == nullptr) return nullptr; + return new QString(static_cast(pte)->toPlainText()); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text) { + if (pte == nullptr || text == nullptr) return; + static_cast(pte)->setPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text) { + if (pte == nullptr || text == nullptr) return; + static_cast(pte)->appendPlainText(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_clear(void* pte) { + if (pte == nullptr) return; + static_cast(pte)->clear(); +} + +extern "C" VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro) { + if (pte == nullptr) return; + static_cast(pte)->setReadOnly(ro != 0); +} + +extern "C" VQT6_API int vqt6_qplaintextedit_line_count(void* pte) { + if (pte == nullptr) return 0; + return static_cast(pte)->blockCount(); +} + +// ============================================================ +// QCheckBox / QRadioButton +// ============================================================ +extern "C" VQT6_API void* vqt6_qcheckbox_create(void) { + return new QCheckBox(); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QCheckBox(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QCheckBox(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked) { + if (cb == nullptr) return; + static_cast(cb)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qcheckbox_is_checked(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qcheckbox_text(void* cb) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->text()); +} + +extern "C" VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate) { + if (cb == nullptr) return; + static_cast(cb)->setTristate(tristate != 0); +} + +extern "C" VQT6_API int vqt6_qcheckbox_is_tristate(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isTristate() ? 1 : 0; +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create(void) { + return new QRadioButton(); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QRadioButton(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QRadioButton(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked) { + if (rb == nullptr) return; + static_cast(rb)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qradiobutton_is_checked(void* rb) { + if (rb == nullptr) return 0; + return static_cast(rb)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text) { + if (rb == nullptr || text == nullptr) return; + static_cast(rb)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qradiobutton_text(void* rb) { + if (rb == nullptr) return nullptr; + return new QString(static_cast(rb)->text()); +} + +// ============================================================ +// QComboBox +// ============================================================ +extern "C" VQT6_API void* vqt6_qcombobox_create(void) { + return new QComboBox(); +} + +extern "C" VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QComboBox(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->addItem(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items) { + if (cb == nullptr || items == nullptr) return; + static_cast(cb)->addItems(*static_cast(items)); +} + +extern "C" VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text) { + if (cb == nullptr || text == nullptr) return; + static_cast(cb)->insertItem(index, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index) { + if (cb == nullptr) return; + static_cast(cb)->removeItem(index); +} + +extern "C" VQT6_API void vqt6_qcombobox_clear(void* cb) { + if (cb == nullptr) return; + static_cast(cb)->clear(); +} + +extern "C" VQT6_API int vqt6_qcombobox_count(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->count(); +} + +extern "C" VQT6_API int vqt6_qcombobox_current_index(void* cb) { + if (cb == nullptr) return -1; + return static_cast(cb)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index) { + if (cb == nullptr) return; + static_cast(cb)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qcombobox_current_text(void* cb) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->currentText()); +} + +extern "C" VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index) { + if (cb == nullptr) return nullptr; + return new QString(static_cast(cb)->itemText(index)); +} + +extern "C" VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable) { + if (cb == nullptr) return; + static_cast(cb)->setEditable(editable != 0); +} + +extern "C" VQT6_API int vqt6_qcombobox_is_editable(void* cb) { + if (cb == nullptr) return 0; + return static_cast(cb)->isEditable() ? 1 : 0; +} + +// ============================================================ +// QListWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qlistwidget_create(void) { + return new QListWidget(); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QListWidget(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text) { + if (lw == nullptr || text == nullptr) return; + static_cast(lw)->addItem(*static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items) { + if (lw == nullptr || items == nullptr) return; + static_cast(lw)->addItems(*static_cast(items)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text) { + if (lw == nullptr || text == nullptr) return; + static_cast(lw)->insertItem(row, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row) { + if (lw == nullptr) return; + static_cast(lw)->takeItem(row); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row) { + if (lw == nullptr) return nullptr; + return static_cast(lw)->takeItem(row); +} + +extern "C" VQT6_API void vqt6_qlistwidget_clear(void* lw) { + if (lw == nullptr) return; + static_cast(lw)->clear(); +} + +extern "C" VQT6_API int vqt6_qlistwidget_count(void* lw) { + if (lw == nullptr) return 0; + return static_cast(lw)->count(); +} + +extern "C" VQT6_API int vqt6_qlistwidget_current_row(void* lw) { + if (lw == nullptr) return -1; + return static_cast(lw)->currentRow(); +} + +extern "C" VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row) { + if (lw == nullptr) return; + static_cast(lw)->setCurrentRow(row); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw) { + if (lw == nullptr) return nullptr; + QListWidgetItem* it = static_cast(lw)->currentItem(); + if (it == nullptr) return nullptr; + return new QString(it->text()); +} + +extern "C" VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row) { + if (lw == nullptr) return nullptr; + QListWidgetItem* it = static_cast(lw)->item(row); + if (it == nullptr) return nullptr; + return new QString(it->text()); +} + +extern "C" VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text) { + if (lw == nullptr || text == nullptr) return; + QListWidgetItem* it = static_cast(lw)->item(row); + if (it != nullptr) it->setText(*static_cast(text)); +} + +// ============================================================ +// QProgressBar +// ============================================================ +extern "C" VQT6_API void* vqt6_qprogressbar_create(void) { + return new QProgressBar(); +} + +extern "C" VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QProgressBar(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value) { + if (pb == nullptr) return; + static_cast(pb)->setValue(value); +} + +extern "C" VQT6_API int vqt6_qprogressbar_value(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->value(); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min) { + if (pb == nullptr) return; + static_cast(pb)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max) { + if (pb == nullptr) return; + static_cast(pb)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max) { + if (pb == nullptr) return; + static_cast(pb)->setRange(min, max); +} + +extern "C" VQT6_API int vqt6_qprogressbar_minimum(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->minimum(); +} + +extern "C" VQT6_API int vqt6_qprogressbar_maximum(void* pb) { + if (pb == nullptr) return 0; + return static_cast(pb)->maximum(); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible) { + if (pb == nullptr) return; + static_cast(pb)->setTextVisible(visible != 0); +} + +extern "C" VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format) { + if (pb == nullptr || format == nullptr) return; + static_cast(pb)->setFormat(*static_cast(format)); +} + +extern "C" VQT6_API void vqt6_qprogressbar_reset(void* pb) { + if (pb == nullptr) return; + static_cast(pb)->reset(); +} + +// ============================================================ +// QSlider +// ============================================================ +extern "C" VQT6_API void* vqt6_qslider_create(void) { + return new QSlider(); +} + +extern "C" VQT6_API void* vqt6_qslider_create_with_orientation(int orientation) { + return new QSlider(static_cast(orientation)); +} + +extern "C" VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent) { + if (parent == nullptr) return nullptr; + return new QSlider(static_cast(orientation), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qslider_set_value(void* s, int value) { + if (s == nullptr) return; + static_cast(s)->setValue(value); +} + +extern "C" VQT6_API int vqt6_qslider_value(void* s) { + if (s == nullptr) return 0; + return static_cast(s)->value(); +} + +extern "C" VQT6_API void vqt6_qslider_set_minimum(void* s, int min) { + if (s == nullptr) return; + static_cast(s)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qslider_set_maximum(void* s, int max) { + if (s == nullptr) return; + static_cast(s)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qslider_set_range(void* s, int min, int max) { + if (s == nullptr) return; + static_cast(s)->setRange(min, max); +} + +extern "C" VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation) { + if (s == nullptr) return; + static_cast(s)->setOrientation(static_cast(orientation)); +} + +extern "C" VQT6_API int vqt6_qslider_orientation(void* s) { + if (s == nullptr) return 0; + return static_cast(static_cast(s)->orientation()); +} + +extern "C" VQT6_API void vqt6_qslider_set_single_step(void* s, int step) { + if (s == nullptr) return; + static_cast(s)->setSingleStep(step); +} + +extern "C" VQT6_API void vqt6_qslider_set_page_step(void* s, int step) { + if (s == nullptr) return; + static_cast(s)->setPageStep(step); +} + +// ============================================================ +// QSpinBox +// ============================================================ +extern "C" VQT6_API void* vqt6_qspinbox_create(void) { + return new QSpinBox(); +} + +extern "C" VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QSpinBox(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qspinbox_value(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->value(); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_value(void* sb, int value) { + if (sb == nullptr) return; + static_cast(sb)->setValue(value); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min) { + if (sb == nullptr) return; + static_cast(sb)->setMinimum(min); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max) { + if (sb == nullptr) return; + static_cast(sb)->setMaximum(max); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max) { + if (sb == nullptr) return; + static_cast(sb)->setRange(min, max); +} + +extern "C" VQT6_API int vqt6_qspinbox_minimum(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->minimum(); +} + +extern "C" VQT6_API int vqt6_qspinbox_maximum(void* sb) { + if (sb == nullptr) return 0; + return static_cast(sb)->maximum(); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step) { + if (sb == nullptr) return; + static_cast(sb)->setSingleStep(step); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix) { + if (sb == nullptr || prefix == nullptr) return; + static_cast(sb)->setPrefix(*static_cast(prefix)); +} + +extern "C" VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix) { + if (sb == nullptr || suffix == nullptr) return; + static_cast(sb)->setSuffix(*static_cast(suffix)); +} + +extern "C" VQT6_API void* vqt6_qspinbox_prefix(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->prefix()); +} + +extern "C" VQT6_API void* vqt6_qspinbox_suffix(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->suffix()); +} + +// ============================================================ +// Layouts +// ============================================================ +extern "C" VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget) { + if (layout == nullptr || widget == nullptr) return; + static_cast(layout)->addWidget(static_cast(widget)); +} + +extern "C" VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget) { + if (layout == nullptr || widget == nullptr) return; + static_cast(layout)->removeWidget(static_cast(widget)); +} + +extern "C" VQT6_API int vqt6_qlayout_count(void* layout) { + if (layout == nullptr) return 0; + return static_cast(layout)->count(); +} + +extern "C" VQT6_API void* vqt6_qlayout_item_at(void* layout, int index) { + if (layout == nullptr) return nullptr; + QLayoutItem* item = static_cast(layout)->itemAt(index); + return item != nullptr ? item->widget() : nullptr; +} + +extern "C" VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom) { + if (layout == nullptr) return; + static_cast(layout)->setContentsMargins(left, top, right, bottom); +} + +extern "C" VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing) { + if (layout == nullptr) return; + static_cast(layout)->setSpacing(spacing); +} + +extern "C" VQT6_API int vqt6_qlayout_spacing(void* layout) { + if (layout == nullptr) return 0; + return static_cast(layout)->spacing(); +} + +extern "C" VQT6_API void vqt6_qlayout_invalidate(void* layout) { + if (layout == nullptr) return; + static_cast(layout)->invalidate(); +} + +extern "C" VQT6_API void* vqt6_qhboxlayout_create(void) { + return new QHBoxLayout(); +} + +extern "C" VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QHBoxLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child) { + if (layout == nullptr || child == nullptr) return; + static_cast(layout)->addLayout(static_cast(child)); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch) { + if (layout == nullptr) return; + static_cast(layout)->addStretch(stretch); +} + +extern "C" VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size) { + if (layout == nullptr) return; + static_cast(layout)->addSpacing(size); +} + +extern "C" VQT6_API void* vqt6_qvboxlayout_create(void) { + return new QVBoxLayout(); +} + +extern "C" VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QVBoxLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child) { + if (layout == nullptr || child == nullptr) return; + static_cast(layout)->addLayout(static_cast(child)); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch) { + if (layout == nullptr) return; + static_cast(layout)->addStretch(stretch); +} + +extern "C" VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size) { + if (layout == nullptr) return; + static_cast(layout)->addSpacing(size); +} + +extern "C" VQT6_API void* vqt6_qgridlayout_create(void) { + return new QGridLayout(); +} + +extern "C" VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QGridLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col) { + if (gl == nullptr || w == nullptr) return; + static_cast(gl)->addWidget(static_cast(w), row, col); +} + +extern "C" VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span) { + if (gl == nullptr || w == nullptr) return; + static_cast(gl)->addWidget(static_cast(w), row, col, row_span, col_span); +} + +extern "C" VQT6_API void* vqt6_qformlayout_create(void) { + return new QFormLayout(); +} + +extern "C" VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QFormLayout(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field) { + if (fl == nullptr || label == nullptr || field == nullptr) return; + static_cast(fl)->addRow(*static_cast(label), static_cast(field)); +} + +extern "C" VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field) { + if (fl == nullptr || label == nullptr || field == nullptr) return; + static_cast(fl)->addRow(static_cast(label), static_cast(field)); +} + +// ============================================================ +// QStackedWidget / QTabWidget +// ============================================================ +extern "C" VQT6_API void* vqt6_qstackedwidget_create(void) { + return new QStackedWidget(); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QStackedWidget(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w) { + if (sw == nullptr || w == nullptr) return -1; + return static_cast(sw)->addWidget(static_cast(w)); +} + +extern "C" VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w) { + if (sw == nullptr || w == nullptr) return; + static_cast(sw)->removeWidget(static_cast(w)); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_count(void* sw) { + if (sw == nullptr) return 0; + return static_cast(sw)->count(); +} + +extern "C" VQT6_API int vqt6_qstackedwidget_current_index(void* sw) { + if (sw == nullptr) return -1; + return static_cast(sw)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index) { + if (sw == nullptr) return; + static_cast(sw)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw) { + if (sw == nullptr) return nullptr; + return static_cast(sw)->currentWidget(); +} + +extern "C" VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index) { + if (sw == nullptr) return nullptr; + return static_cast(sw)->widget(index); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_create(void) { + return new QTabWidget(); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QTabWidget(static_cast(parent)); +} + +extern "C" VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label) { + if (tw == nullptr || w == nullptr || label == nullptr) return -1; + return static_cast(tw)->addTab(static_cast(w), *static_cast(label)); +} + +extern "C" VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label) { + if (tw == nullptr || w == nullptr || label == nullptr) return -1; + return static_cast(tw)->insertTab(index, static_cast(w), *static_cast(label)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index) { + if (tw == nullptr) return; + static_cast(tw)->removeTab(index); +} + +extern "C" VQT6_API int vqt6_qtabwidget_count(void* tw) { + if (tw == nullptr) return 0; + return static_cast(tw)->count(); +} + +extern "C" VQT6_API int vqt6_qtabwidget_current_index(void* tw) { + if (tw == nullptr) return -1; + return static_cast(tw)->currentIndex(); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index) { + if (tw == nullptr) return; + static_cast(tw)->setCurrentIndex(index); +} + +extern "C" VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index) { + if (tw == nullptr) return nullptr; + return new QString(static_cast(tw)->tabText(index)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text) { + if (tw == nullptr || text == nullptr) return; + static_cast(tw)->setTabText(index, *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable) { + if (tw == nullptr) return; + static_cast(tw)->setTabsClosable(closable != 0); +} + +extern "C" VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw) { + if (tw == nullptr) return 0; + return static_cast(tw)->tabsClosable() ? 1 : 0; +} + +// ============================================================ +// QMenuBar / QMenu / QAction +// ============================================================ +extern "C" VQT6_API void* vqt6_qmenubar_create(void) { + return new QMenuBar(); +} + +extern "C" VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QMenuBar(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title) { + if (mb == nullptr || title == nullptr) return nullptr; + return static_cast(mb)->addMenu(*static_cast(title)); +} + +extern "C" VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu) { + if (mb == nullptr || menu == nullptr) return; + static_cast(mb)->addMenu(static_cast(menu)); +} + +extern "C" VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action) { + if (mb == nullptr || action == nullptr) return; + static_cast(mb)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qmenubar_clear(void* mb) { + if (mb == nullptr) return; + static_cast(mb)->clear(); +} + +extern "C" VQT6_API void* vqt6_qmenu_create(void) { + return new QMenu(); +} + +extern "C" VQT6_API void* vqt6_qmenu_create_with_title(void* title) { + if (title == nullptr) return nullptr; + return new QMenu(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent) { + if (title == nullptr || parent == nullptr) return nullptr; + return new QMenu(*static_cast(title), static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title) { + if (menu == nullptr || title == nullptr) return nullptr; + return static_cast(menu)->addMenu(*static_cast(title)); +} + +extern "C" VQT6_API void vqt6_qmenu_add_action(void* menu, void* action) { + if (menu == nullptr || action == nullptr) return; + static_cast(menu)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qmenu_add_separator(void* menu) { + if (menu == nullptr) return; + static_cast(menu)->addSeparator(); +} + +extern "C" VQT6_API void vqt6_qmenu_clear(void* menu) { + if (menu == nullptr) return; + static_cast(menu)->clear(); +} + +extern "C" VQT6_API void vqt6_qmenu_set_title(void* menu, void* title) { + if (menu == nullptr || title == nullptr) return; + static_cast(menu)->setTitle(*static_cast(title)); +} + +extern "C" VQT6_API void* vqt6_qmenu_title(void* menu) { + if (menu == nullptr) return nullptr; + return new QString(static_cast(menu)->title()); +} + +extern "C" VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text) { + if (menu == nullptr || text == nullptr) return nullptr; + return static_cast(menu)->addAction(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_create(void) { + return new QAction(); +} + +extern "C" VQT6_API void* vqt6_qaction_create_with_text(void* text) { + if (text == nullptr) return nullptr; + return new QAction(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent) { + if (text == nullptr || parent == nullptr) return nullptr; + return new QAction(*static_cast(text), static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qaction_set_text(void* action, void* text) { + if (action == nullptr || text == nullptr) return; + static_cast(action)->setText(*static_cast(text)); +} + +extern "C" VQT6_API void* vqt6_qaction_text(void* action) { + if (action == nullptr) return nullptr; + return new QString(static_cast(action)->text()); +} + +extern "C" VQT6_API void vqt6_qaction_set_icon(void* action, void* icon) { + if (action == nullptr || icon == nullptr) return; + static_cast(action)->setIcon(*static_cast(icon)); +} + +extern "C" VQT6_API void* vqt6_qaction_icon(void* action) { + if (action == nullptr) return nullptr; + return new QIcon(static_cast(action)->icon()); +} + +extern "C" VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence) { + if (action == nullptr || key_sequence == nullptr) return; + static_cast(action)->setShortcut(QKeySequence(*static_cast(key_sequence))); +} + +extern "C" VQT6_API void* vqt6_qaction_shortcut(void* action) { + if (action == nullptr) return nullptr; + return new QString(static_cast(action)->shortcut().toString()); +} + +extern "C" VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable) { + if (action == nullptr) return; + static_cast(action)->setCheckable(checkable != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_checkable(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isCheckable() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_set_checked(void* action, int checked) { + if (action == nullptr) return; + static_cast(action)->setChecked(checked != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_checked(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isChecked() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled) { + if (action == nullptr) return; + static_cast(action)->setEnabled(enabled != 0); +} + +extern "C" VQT6_API int vqt6_qaction_is_enabled(void* action) { + if (action == nullptr) return 0; + return static_cast(action)->isEnabled() ? 1 : 0; +} + +extern "C" VQT6_API void vqt6_qaction_trigger(void* action) { + if (action == nullptr) return; + static_cast(action)->trigger(); +} + +// ============================================================ +// QStatusBar / QToolBar +// ============================================================ +extern "C" VQT6_API void* vqt6_qstatusbar_create(void) { + return new QStatusBar(); +} + +extern "C" VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QStatusBar(static_cast(parent)); +} + +extern "C" VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms) { + if (sb == nullptr || message == nullptr) return; + static_cast(sb)->showMessage(*static_cast(message), timeout_ms); +} + +extern "C" VQT6_API void vqt6_qstatusbar_clear_message(void* sb) { + if (sb == nullptr) return; + static_cast(sb)->clearMessage(); +} + +extern "C" VQT6_API void* vqt6_qstatusbar_current_message(void* sb) { + if (sb == nullptr) return nullptr; + return new QString(static_cast(sb)->currentMessage()); +} + +extern "C" VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch) { + if (sb == nullptr || w == nullptr) return; + static_cast(sb)->addWidget(static_cast(w), stretch); +} + +extern "C" VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch) { + if (sb == nullptr || w == nullptr) return; + static_cast(sb)->addPermanentWidget(static_cast(w), stretch); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_create(void) { + return new QToolBar(); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent) { + if (parent == nullptr) return nullptr; + return new QToolBar(static_cast(parent)); +} + +extern "C" VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w) { + if (tb == nullptr || w == nullptr) return nullptr; + return static_cast(tb)->addWidget(static_cast(w)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action) { + if (tb == nullptr || action == nullptr) return; + static_cast(tb)->addAction(static_cast(action)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_add_separator(void* tb) { + if (tb == nullptr) return; + static_cast(tb)->addSeparator(); +} + +extern "C" VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h) { + if (tb == nullptr) return; + static_cast(tb)->setIconSize(QSize(w, h)); +} + +extern "C" VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation) { + if (tb == nullptr) return; + static_cast(tb)->setOrientation(static_cast(orientation)); +} + +extern "C" VQT6_API int vqt6_qtoolbar_orientation(void* tb) { + if (tb == nullptr) return 0; + return static_cast(static_cast(tb)->orientation()); +} + +// ============================================================ +// QMessageBox +// ============================================================ +extern "C" VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0400), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0200), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0100), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons) { + if (title == nullptr || text == nullptr) return 0; + QMessageBox mb(static_cast(0x0200), *static_cast(title), *static_cast(text), + static_cast(buttons), static_cast(parent)); + return mb.exec(); +} + +extern "C" VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text) { + if (title == nullptr || text == nullptr) return; + QMessageBox::about(static_cast(parent), *static_cast(title), *static_cast(text)); +} + +extern "C" VQT6_API void vqt6_qmessagebox_about_qt(void* parent) { + QMessageBox::aboutQt(static_cast(parent)); +} + +// ============================================================ +// QFileDialog +// ============================================================ +extern "C" VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter) { + QString* result = new QString(QFileDialog::getOpenFileName( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter) { + QString* result = new QString(QFileDialog::getSaveFileName( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir) { + QString* result = new QString(QFileDialog::getExistingDirectory( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString() + )); + return result; +} + +extern "C" VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter) { + return new QStringList(QFileDialog::getOpenFileNames( + static_cast(parent), + caption != nullptr ? *static_cast(caption) : QString(), + dir != nullptr ? *static_cast(dir) : QString(), + filter != nullptr ? *static_cast(filter) : QString() + )); +} diff --git a/vqt6/_bridge_widgets.h b/vqt6/_bridge_widgets.h new file mode 100644 index 0000000..0197377 --- /dev/null +++ b/vqt6/_bridge_widgets.h @@ -0,0 +1,432 @@ +// ============================================================ +// vqt6/_bridge_widgets.h — QtWidgets C 桥接函数声明 +// ============================================================ + +#ifndef VQT6_BRIDGE_WIDGETS_H +#define VQT6_BRIDGE_WIDGETS_H + +#include "_bridge.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ============================================================ +// QApplication +// ============================================================ +VQT6_API void* vqt6_qapplication_create(int argc, char** argv); +VQT6_API void* vqt6_qapplication_instance(void); +VQT6_API int vqt6_qapplication_exec(void* app); +VQT6_API void vqt6_qapplication_quit(void* app); +VQT6_API void vqt6_qapplication_exit(void* app, int exit_code); +VQT6_API void vqt6_qapplication_process_events(void* app); +VQT6_API int vqt6_qapplication_desktop_width(void* app); +VQT6_API int vqt6_qapplication_desktop_height(void* app); +VQT6_API void vqt6_qapplication_set_quit_on_last_window_closed(void* app, int quit); +VQT6_API int vqt6_qapplication_quit_on_last_window_closed(void* app); + +// ============================================================ +// QWidget +// ============================================================ +VQT6_API void* vqt6_qwidget_create(void); +VQT6_API void* vqt6_qwidget_create_with_parent(void* parent); +VQT6_API void vqt6_qwidget_show(void* widget); +VQT6_API void vqt6_qwidget_hide(void* widget); +VQT6_API int vqt6_qwidget_close(void* widget); +VQT6_API int vqt6_qwidget_is_visible(void* widget); +VQT6_API void vqt6_qwidget_set_visible(void* widget, int visible); +VQT6_API void vqt6_qwidget_set_geometry(void* widget, int x, int y, int w, int h); +VQT6_API void vqt6_qwidget_geometry(void* widget, int* x, int* y, int* w, int* h); +VQT6_API void vqt6_qwidget_resize(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_size(void* widget, int* w, int* h); +VQT6_API void vqt6_qwidget_move(void* widget, int x, int y); +VQT6_API void vqt6_qwidget_pos(void* widget, int* x, int* y); +VQT6_API int vqt6_qwidget_width(void* widget); +VQT6_API int vqt6_qwidget_height(void* widget); +VQT6_API int vqt6_qwidget_x(void* widget); +VQT6_API int vqt6_qwidget_y(void* widget); +VQT6_API void vqt6_qwidget_set_window_title(void* widget, void* title); +VQT6_API void* vqt6_qwidget_window_title(void* widget); +VQT6_API void vqt6_qwidget_set_text(void* widget, void* text); +VQT6_API void* vqt6_qwidget_text(void* widget); +VQT6_API void vqt6_qwidget_set_enabled(void* widget, int enabled); +VQT6_API int vqt6_qwidget_is_enabled(void* widget); +VQT6_API void vqt6_qwidget_set_parent(void* widget, void* parent); +VQT6_API void* vqt6_qwidget_parent_widget(void* widget); +VQT6_API void vqt6_qwidget_set_focus(void* widget); +VQT6_API void vqt6_qwidget_clear_focus(void* widget); +VQT6_API int vqt6_qwidget_has_focus(void* widget); +VQT6_API void vqt6_qwidget_set_focus_policy(void* widget, int policy); +VQT6_API void vqt6_qwidget_update(void* widget); +VQT6_API void vqt6_qwidget_repaint(void* widget); +VQT6_API void vqt6_qwidget_set_update_enabled(void* widget, int enabled); +VQT6_API void vqt6_qwidget_set_window_flags(void* widget, int flags); +VQT6_API int vqt6_qwidget_window_flags(void* widget); +VQT6_API void vqt6_qwidget_set_cursor(void* widget, void* cursor); +VQT6_API void* vqt6_qwidget_cursor(void* widget); +VQT6_API void vqt6_qwidget_unset_cursor(void* widget); +VQT6_API void vqt6_qwidget_set_tool_tip(void* widget, void* tip); +VQT6_API void* vqt6_qwidget_tool_tip(void* widget); +VQT6_API void vqt6_qwidget_set_status_tip(void* widget, void* tip); +VQT6_API void* vqt6_qwidget_status_tip(void* widget); +VQT6_API void vqt6_qwidget_set_minimum_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_set_maximum_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_set_fixed_size(void* widget, int w, int h); +VQT6_API void vqt6_qwidget_minimum_size(void* widget, int* w, int* h); +VQT6_API void vqt6_qwidget_maximum_size(void* widget, int* w, int* h); + +// ============================================================ +// QDialog +// ============================================================ +VQT6_API void* vqt6_qdialog_create(void); +VQT6_API void* vqt6_qdialog_create_with_parent(void* parent); +VQT6_API int vqt6_qdialog_exec(void* dialog); +VQT6_API void vqt6_qdialog_done(void* dialog, int result); +VQT6_API void vqt6_qdialog_accept(void* dialog); +VQT6_API void vqt6_qdialog_reject(void* dialog); +VQT6_API void vqt6_qdialog_set_result(void* dialog, int result); +VQT6_API int vqt6_qdialog_result(void* dialog); +VQT6_API void vqt6_qdialog_set_modal(void* dialog, int modal); +VQT6_API int vqt6_qdialog_is_modal(void* dialog); + +// ============================================================ +// QMainWindow +// ============================================================ +VQT6_API void* vqt6_qmainwindow_create(void); +VQT6_API void* vqt6_qmainwindow_create_with_parent(void* parent); +VQT6_API void vqt6_qmainwindow_set_central_widget(void* mw, void* widget); +VQT6_API void* vqt6_qmainwindow_central_widget(void* mw); +VQT6_API void* vqt6_qmainwindow_menu_bar(void* mw); +VQT6_API void vqt6_qmainwindow_set_menu_bar(void* mw, void* menubar); +VQT6_API void* vqt6_qmainwindow_status_bar(void* mw); +VQT6_API void vqt6_qmainwindow_set_status_bar(void* mw, void* statusbar); +VQT6_API void vqt6_qmainwindow_add_tool_bar(void* mw, void* toolbar); +VQT6_API void vqt6_qmainwindow_add_tool_bar_break(void* mw); + +// ============================================================ +// QLabel +// ============================================================ +VQT6_API void* vqt6_qlabel_create(void); +VQT6_API void* vqt6_qlabel_create_with_text(void* text); +VQT6_API void* vqt6_qlabel_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qlabel_set_text(void* label, void* text); +VQT6_API void* vqt6_qlabel_text(void* label); +VQT6_API void vqt6_qlabel_set_alignment(void* label, int alignment); +VQT6_API int vqt6_qlabel_alignment(void* label); +VQT6_API void vqt6_qlabel_set_pixmap(void* label, void* pixmap); +VQT6_API void* vqt6_qlabel_pixmap(void* label); +VQT6_API void vqt6_qlabel_set_indent(void* label, int indent); +VQT6_API void vqt6_qlabel_set_margin(void* label, int margin); +VQT6_API void vqt6_qlabel_set_word_wrap(void* label, int wrap); +VQT6_API int vqt6_qlabel_word_wrap(void* label); + +// ============================================================ +// QPushButton +// ============================================================ +VQT6_API void* vqt6_qpushbutton_create(void); +VQT6_API void* vqt6_qpushbutton_create_with_text(void* text); +VQT6_API void* vqt6_qpushbutton_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qpushbutton_set_text(void* btn, void* text); +VQT6_API void* vqt6_qpushbutton_text(void* btn); +VQT6_API void vqt6_qpushbutton_set_icon(void* btn, void* icon); +VQT6_API void* vqt6_qpushbutton_icon(void* btn); +VQT6_API void vqt6_qpushbutton_set_default(void* btn, int is_default); +VQT6_API int vqt6_qpushbutton_is_default(void* btn); +VQT6_API void vqt6_qpushbutton_set_flat(void* btn, int flat); +VQT6_API int vqt6_qpushbutton_is_flat(void* btn); +VQT6_API void vqt6_qpushbutton_set_checkable(void* btn, int checkable); +VQT6_API int vqt6_qpushbutton_is_checkable(void* btn); +VQT6_API void vqt6_qpushbutton_set_checked(void* btn, int checked); +VQT6_API int vqt6_qpushbutton_is_checked(void* btn); +VQT6_API void vqt6_qpushbutton_click(void* btn); + +// ============================================================ +// QLineEdit +// ============================================================ +VQT6_API void* vqt6_qlineedit_create(void); +VQT6_API void* vqt6_qlineedit_create_with_text(void* text); +VQT6_API void* vqt6_qlineedit_create_with_text_parent(void* text, void* parent); +VQT6_API void* vqt6_qlineedit_text(void* le); +VQT6_API void vqt6_qlineedit_set_text(void* le, void* text); +VQT6_API void* vqt6_qlineedit_placeholder_text(void* le); +VQT6_API void vqt6_qlineedit_set_placeholder_text(void* le, void* text); +VQT6_API void vqt6_qlineedit_set_max_length(void* le, int max); +VQT6_API int vqt6_qlineedit_max_length(void* le); +VQT6_API void vqt6_qlineedit_set_read_only(void* le, int ro); +VQT6_API int vqt6_qlineedit_is_read_only(void* le); +VQT6_API void vqt6_qlineedit_set_echo_mode(void* le, int mode); +VQT6_API int vqt6_qlineedit_echo_mode(void* le); +VQT6_API void vqt6_qlineedit_select_all(void* le); +VQT6_API void vqt6_qlineedit_clear(void* le); + +// ============================================================ +// QTextEdit / QPlainTextEdit +// ============================================================ +VQT6_API void* vqt6_qtextedit_create(void); +VQT6_API void* vqt6_qtextedit_create_with_parent(void* parent); +VQT6_API void* vqt6_qtextedit_to_plain_text(void* te); +VQT6_API void vqt6_qtextedit_set_plain_text(void* te, void* text); +VQT6_API void vqt6_qtextedit_set_html(void* te, void* html); +VQT6_API void* vqt6_qtextedit_to_html(void* te); +VQT6_API void vqt6_qtextedit_append(void* te, void* text); +VQT6_API void vqt6_qtextedit_clear(void* te); +VQT6_API void vqt6_qtextedit_set_read_only(void* te, int ro); +VQT6_API int vqt6_qtextedit_is_read_only(void* te); + +VQT6_API void* vqt6_qplaintextedit_create(void); +VQT6_API void* vqt6_qplaintextedit_create_with_parent(void* parent); +VQT6_API void* vqt6_qplaintextedit_to_plain_text(void* pte); +VQT6_API void vqt6_qplaintextedit_set_plain_text(void* pte, void* text); +VQT6_API void vqt6_qplaintextedit_append(void* pte, void* text); +VQT6_API void vqt6_qplaintextedit_clear(void* pte); +VQT6_API void vqt6_qplaintextedit_set_read_only(void* pte, int ro); +VQT6_API int vqt6_qplaintextedit_line_count(void* pte); + +// ============================================================ +// QCheckBox / QRadioButton +// ============================================================ +VQT6_API void* vqt6_qcheckbox_create(void); +VQT6_API void* vqt6_qcheckbox_create_with_text(void* text); +VQT6_API void* vqt6_qcheckbox_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qcheckbox_set_checked(void* cb, int checked); +VQT6_API int vqt6_qcheckbox_is_checked(void* cb); +VQT6_API void vqt6_qcheckbox_set_text(void* cb, void* text); +VQT6_API void* vqt6_qcheckbox_text(void* cb); +VQT6_API void vqt6_qcheckbox_set_tristate(void* cb, int tristate); +VQT6_API int vqt6_qcheckbox_is_tristate(void* cb); + +VQT6_API void* vqt6_qradiobutton_create(void); +VQT6_API void* vqt6_qradiobutton_create_with_text(void* text); +VQT6_API void* vqt6_qradiobutton_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qradiobutton_set_checked(void* rb, int checked); +VQT6_API int vqt6_qradiobutton_is_checked(void* rb); +VQT6_API void vqt6_qradiobutton_set_text(void* rb, void* text); +VQT6_API void* vqt6_qradiobutton_text(void* rb); + +// ============================================================ +// QComboBox +// ============================================================ +VQT6_API void* vqt6_qcombobox_create(void); +VQT6_API void* vqt6_qcombobox_create_with_parent(void* parent); +VQT6_API void vqt6_qcombobox_add_item(void* cb, void* text); +VQT6_API void vqt6_qcombobox_add_items(void* cb, void* items); +VQT6_API void vqt6_qcombobox_insert_item(void* cb, int index, void* text); +VQT6_API void vqt6_qcombobox_remove_item(void* cb, int index); +VQT6_API void vqt6_qcombobox_clear(void* cb); +VQT6_API int vqt6_qcombobox_count(void* cb); +VQT6_API int vqt6_qcombobox_current_index(void* cb); +VQT6_API void vqt6_qcombobox_set_current_index(void* cb, int index); +VQT6_API void* vqt6_qcombobox_current_text(void* cb); +VQT6_API void* vqt6_qcombobox_item_text(void* cb, int index); +VQT6_API void vqt6_qcombobox_set_editable(void* cb, int editable); +VQT6_API int vqt6_qcombobox_is_editable(void* cb); + +// ============================================================ +// QListWidget +// ============================================================ +VQT6_API void* vqt6_qlistwidget_create(void); +VQT6_API void* vqt6_qlistwidget_create_with_parent(void* parent); +VQT6_API void vqt6_qlistwidget_add_item(void* lw, void* text); +VQT6_API void vqt6_qlistwidget_add_items(void* lw, void* items); +VQT6_API void vqt6_qlistwidget_insert_item(void* lw, int row, void* text); +VQT6_API void vqt6_qlistwidget_remove_item_widget(void* lw, int row); +VQT6_API void* vqt6_qlistwidget_take_item(void* lw, int row); +VQT6_API void vqt6_qlistwidget_clear(void* lw); +VQT6_API int vqt6_qlistwidget_count(void* lw); +VQT6_API int vqt6_qlistwidget_current_row(void* lw); +VQT6_API void vqt6_qlistwidget_set_current_row(void* lw, int row); +VQT6_API void* vqt6_qlistwidget_current_item_text(void* lw); +VQT6_API void* vqt6_qlistwidget_item_text(void* lw, int row); +VQT6_API void vqt6_qlistwidget_set_item_text(void* lw, int row, void* text); + +// ============================================================ +// QProgressBar +// ============================================================ +VQT6_API void* vqt6_qprogressbar_create(void); +VQT6_API void* vqt6_qprogressbar_create_with_parent(void* parent); +VQT6_API void vqt6_qprogressbar_set_value(void* pb, int value); +VQT6_API int vqt6_qprogressbar_value(void* pb); +VQT6_API void vqt6_qprogressbar_set_minimum(void* pb, int min); +VQT6_API void vqt6_qprogressbar_set_maximum(void* pb, int max); +VQT6_API void vqt6_qprogressbar_set_range(void* pb, int min, int max); +VQT6_API int vqt6_qprogressbar_minimum(void* pb); +VQT6_API int vqt6_qprogressbar_maximum(void* pb); +VQT6_API void vqt6_qprogressbar_set_text_visible(void* pb, int visible); +VQT6_API void vqt6_qprogressbar_set_format(void* pb, void* format); +VQT6_API void vqt6_qprogressbar_reset(void* pb); + +// ============================================================ +// QSlider +// ============================================================ +VQT6_API void* vqt6_qslider_create(void); +VQT6_API void* vqt6_qslider_create_with_orientation(int orientation); +VQT6_API void* vqt6_qslider_create_with_orientation_parent(int orientation, void* parent); +VQT6_API void vqt6_qslider_set_value(void* s, int value); +VQT6_API int vqt6_qslider_value(void* s); +VQT6_API void vqt6_qslider_set_minimum(void* s, int min); +VQT6_API void vqt6_qslider_set_maximum(void* s, int max); +VQT6_API void vqt6_qslider_set_range(void* s, int min, int max); +VQT6_API void vqt6_qslider_set_orientation(void* s, int orientation); +VQT6_API int vqt6_qslider_orientation(void* s); +VQT6_API void vqt6_qslider_set_single_step(void* s, int step); +VQT6_API void vqt6_qslider_set_page_step(void* s, int step); + +// ============================================================ +// QSpinBox +// ============================================================ +VQT6_API void* vqt6_qspinbox_create(void); +VQT6_API void* vqt6_qspinbox_create_with_parent(void* parent); +VQT6_API int vqt6_qspinbox_value(void* sb); +VQT6_API void vqt6_qspinbox_set_value(void* sb, int value); +VQT6_API void vqt6_qspinbox_set_minimum(void* sb, int min); +VQT6_API void vqt6_qspinbox_set_maximum(void* sb, int max); +VQT6_API void vqt6_qspinbox_set_range(void* sb, int min, int max); +VQT6_API int vqt6_qspinbox_minimum(void* sb); +VQT6_API int vqt6_qspinbox_maximum(void* sb); +VQT6_API void vqt6_qspinbox_set_single_step(void* sb, int step); +VQT6_API void vqt6_qspinbox_set_prefix(void* sb, void* prefix); +VQT6_API void vqt6_qspinbox_set_suffix(void* sb, void* suffix); +VQT6_API void* vqt6_qspinbox_prefix(void* sb); +VQT6_API void* vqt6_qspinbox_suffix(void* sb); + +// ============================================================ +// Layouts +// ============================================================ +VQT6_API void vqt6_qlayout_add_widget(void* layout, void* widget); +VQT6_API void vqt6_qlayout_remove_widget(void* layout, void* widget); +VQT6_API int vqt6_qlayout_count(void* layout); +VQT6_API void* vqt6_qlayout_item_at(void* layout, int index); +VQT6_API void vqt6_qlayout_set_contents_margins(void* layout, int left, int top, int right, int bottom); +VQT6_API void vqt6_qlayout_set_spacing(void* layout, int spacing); +VQT6_API int vqt6_qlayout_spacing(void* layout); +VQT6_API void vqt6_qlayout_invalidate(void* layout); + +VQT6_API void* vqt6_qhboxlayout_create(void); +VQT6_API void* vqt6_qhboxlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qhboxlayout_add_layout(void* layout, void* child); +VQT6_API void vqt6_qhboxlayout_add_stretch(void* layout, int stretch); +VQT6_API void vqt6_qhboxlayout_add_spacing(void* layout, int size); + +VQT6_API void* vqt6_qvboxlayout_create(void); +VQT6_API void* vqt6_qvboxlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qvboxlayout_add_layout(void* layout, void* child); +VQT6_API void vqt6_qvboxlayout_add_stretch(void* layout, int stretch); +VQT6_API void vqt6_qvboxlayout_add_spacing(void* layout, int size); + +VQT6_API void* vqt6_qgridlayout_create(void); +VQT6_API void* vqt6_qgridlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qgridlayout_add_widget(void* gl, void* w, int row, int col); +VQT6_API void vqt6_qgridlayout_add_widget_with_span(void* gl, void* w, int row, int col, int row_span, int col_span); + +VQT6_API void* vqt6_qformlayout_create(void); +VQT6_API void* vqt6_qformlayout_create_with_parent(void* parent); +VQT6_API void vqt6_qformlayout_add_row(void* fl, void* label, void* field); +VQT6_API void vqt6_qformlayout_add_row_widget_pair(void* fl, void* label, void* field); + +// ============================================================ +// QStackedWidget / QTabWidget +// ============================================================ +VQT6_API void* vqt6_qstackedwidget_create(void); +VQT6_API void* vqt6_qstackedwidget_create_with_parent(void* parent); +VQT6_API int vqt6_qstackedwidget_add_widget(void* sw, void* w); +VQT6_API void vqt6_qstackedwidget_remove_widget(void* sw, void* w); +VQT6_API int vqt6_qstackedwidget_count(void* sw); +VQT6_API int vqt6_qstackedwidget_current_index(void* sw); +VQT6_API void vqt6_qstackedwidget_set_current_index(void* sw, int index); +VQT6_API void* vqt6_qstackedwidget_current_widget(void* sw); +VQT6_API void* vqt6_qstackedwidget_widget(void* sw, int index); + +VQT6_API void* vqt6_qtabwidget_create(void); +VQT6_API void* vqt6_qtabwidget_create_with_parent(void* parent); +VQT6_API int vqt6_qtabwidget_add_tab(void* tw, void* w, void* label); +VQT6_API int vqt6_qtabwidget_insert_tab(void* tw, int index, void* w, void* label); +VQT6_API void vqt6_qtabwidget_remove_tab(void* tw, int index); +VQT6_API int vqt6_qtabwidget_count(void* tw); +VQT6_API int vqt6_qtabwidget_current_index(void* tw); +VQT6_API void vqt6_qtabwidget_set_current_index(void* tw, int index); +VQT6_API void* vqt6_qtabwidget_tab_text(void* tw, int index); +VQT6_API void vqt6_qtabwidget_set_tab_text(void* tw, int index, void* text); +VQT6_API void vqt6_qtabwidget_set_tabs_closable(void* tw, int closable); +VQT6_API int vqt6_qtabwidget_tabs_closable(void* tw); + +// ============================================================ +// QMenuBar / QMenu / QAction +// ============================================================ +VQT6_API void* vqt6_qmenubar_create(void); +VQT6_API void* vqt6_qmenubar_create_with_parent(void* parent); +VQT6_API void* vqt6_qmenubar_add_menu(void* mb, void* title); +VQT6_API void vqt6_qmenubar_add_menu_with_menu(void* mb, void* menu); +VQT6_API void vqt6_qmenubar_add_action(void* mb, void* action); +VQT6_API void vqt6_qmenubar_clear(void* mb); + +VQT6_API void* vqt6_qmenu_create(void); +VQT6_API void* vqt6_qmenu_create_with_title(void* title); +VQT6_API void* vqt6_qmenu_create_with_title_parent(void* title, void* parent); +VQT6_API void* vqt6_qmenu_add_menu(void* menu, void* title); +VQT6_API void vqt6_qmenu_add_action(void* menu, void* action); +VQT6_API void vqt6_qmenu_add_separator(void* menu); +VQT6_API void vqt6_qmenu_clear(void* menu); +VQT6_API void vqt6_qmenu_set_title(void* menu, void* title); +VQT6_API void* vqt6_qmenu_title(void* menu); +VQT6_API void* vqt6_qmenu_add_action_with_text(void* menu, void* text); + +VQT6_API void* vqt6_qaction_create(void); +VQT6_API void* vqt6_qaction_create_with_text(void* text); +VQT6_API void* vqt6_qaction_create_with_text_parent(void* text, void* parent); +VQT6_API void vqt6_qaction_set_text(void* action, void* text); +VQT6_API void* vqt6_qaction_text(void* action); +VQT6_API void vqt6_qaction_set_icon(void* action, void* icon); +VQT6_API void* vqt6_qaction_icon(void* action); +VQT6_API void vqt6_qaction_set_shortcut(void* action, void* key_sequence); +VQT6_API void* vqt6_qaction_shortcut(void* action); +VQT6_API void vqt6_qaction_set_checkable(void* action, int checkable); +VQT6_API int vqt6_qaction_is_checkable(void* action); +VQT6_API void vqt6_qaction_set_checked(void* action, int checked); +VQT6_API int vqt6_qaction_is_checked(void* action); +VQT6_API void vqt6_qaction_set_enabled(void* action, int enabled); +VQT6_API int vqt6_qaction_is_enabled(void* action); +VQT6_API void vqt6_qaction_trigger(void* action); + +// ============================================================ +// QStatusBar / QToolBar +// ============================================================ +VQT6_API void* vqt6_qstatusbar_create(void); +VQT6_API void* vqt6_qstatusbar_create_with_parent(void* parent); +VQT6_API void vqt6_qstatusbar_show_message(void* sb, void* message, int timeout_ms); +VQT6_API void vqt6_qstatusbar_clear_message(void* sb); +VQT6_API void* vqt6_qstatusbar_current_message(void* sb); +VQT6_API void vqt6_qstatusbar_add_widget(void* sb, void* w, int stretch); +VQT6_API void vqt6_qstatusbar_add_permanent_widget(void* sb, void* w, int stretch); + +VQT6_API void* vqt6_qtoolbar_create(void); +VQT6_API void* vqt6_qtoolbar_create_with_parent(void* parent); +VQT6_API void* vqt6_qtoolbar_add_widget(void* tb, void* w); +VQT6_API void vqt6_qtoolbar_add_action(void* tb, void* action); +VQT6_API void vqt6_qtoolbar_add_separator(void* tb); +VQT6_API void vqt6_qtoolbar_set_icon_size(void* tb, int w, int h); +VQT6_API void vqt6_qtoolbar_set_orientation(void* tb, int orientation); +VQT6_API int vqt6_qtoolbar_orientation(void* tb); + +// ============================================================ +// QMessageBox +// ============================================================ +VQT6_API int vqt6_qmessagebox_information(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_warning(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_critical(void* parent, void* title, void* text, int buttons); +VQT6_API int vqt6_qmessagebox_question(void* parent, void* title, void* text, int buttons); +VQT6_API void vqt6_qmessagebox_about(void* parent, void* title, void* text); +VQT6_API void vqt6_qmessagebox_about_qt(void* parent); + +// ============================================================ +// QFileDialog +// ============================================================ +VQT6_API void* vqt6_qfiledialog_get_open_file_name(void* parent, void* caption, void* dir, void* filter); +VQT6_API void* vqt6_qfiledialog_get_save_file_name(void* parent, void* caption, void* dir, void* filter); +VQT6_API void* vqt6_qfiledialog_get_existing_directory(void* parent, void* caption, void* dir); +VQT6_API void* vqt6_qfiledialog_get_open_file_names(void* parent, void* caption, void* dir, void* filter); + +#ifdef __cplusplus +} +#endif + +#endif // VQT6_BRIDGE_WIDGETS_H diff --git a/vqt6/_qtcore.vp b/vqt6/_qtcore.vp new file mode 100644 index 0000000..ddb7035 --- /dev/null +++ b/vqt6/_qtcore.vp @@ -0,0 +1,157 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtcore.py — QtCore 的 t.State FFI 声明 +# +# 所有函数都是 C 桥接层 (libvqt6_bridge.a) 的 extern "C" 函数 +# 命名规范: vqt6__ +# ============================================================ + +# ============================================================ +# QString — UTF-16 字符串 +# ============================================================ +# 创建 QString(从 UTF-8 C 字符串) +def vqt6_qstring_create(utf8: t.CChar | t.CPtr) -> QtStringPtr | t.State: pass + +# 获取 QString 的 UTF-8 表示(写入 buf,返回实际长度,不含 \0) +# buf 需足够大(建议 4 * qstring.length() + 1) +def vqt6_qstring_to_utf8(qstr: QtStringPtr, buf: t.CChar | t.CPtr, buf_size: t.CSizeT) -> t.CSizeT | t.State: pass + +# 释放 QString +def vqt6_qstring_free(qstr: QtStringPtr) -> t.State: pass + +# 获取 QString 字符数 +def vqt6_qstring_length(qstr: QtStringPtr) -> t.CInt | t.State: pass + +# QString 是否为空 +def vqt6_qstring_is_empty(qstr: QtStringPtr) -> t.CInt | t.State: pass + +# QString 比较 +def vqt6_qstring_equals(qstr: QtStringPtr, other: QtStringPtr) -> t.CInt | t.State: pass + +# QString 拼接(返回新 QString) +def vqt6_qstring_append(qstr: QtStringPtr, other: QtStringPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# QByteArray — 字节数组 +# ============================================================ +def vqt6_qbytearray_create(data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearray_data(qba: QtByteArrayPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qbytearray_size(qba: QtByteArrayPtr) -> t.CSizeT | t.State: pass +def vqt6_qbytearray_free(qba: QtByteArrayPtr) -> t.State: pass + + +# ============================================================ +# QObject — 所有 Qt 对象的基类 +# ============================================================ +# 注意: Qt 对象的内存由 C++ 管理,Viper 端不应直接 free +def vqt6_qobject_delete(obj: QtObjectPtr) -> t.State: pass +def vqt6_qobject_delete_later(obj: QtObjectPtr) -> t.State: pass +def vqt6_qobject_set_object_name(obj: QtObjectPtr, name: QtStringPtr) -> t.State: pass +def vqt6_qobject_object_name(obj: QtObjectPtr) -> QtStringPtr | t.State: pass +def vqt6_qobject_set_parent(child: QtObjectPtr, parent: QtObjectPtr) -> t.State: pass +def vqt6_qobject_parent(obj: QtObjectPtr) -> QtObjectPtr | t.State: pass + +# 信号/槽连接 (简化版: 函数指针形式) +# typedef void (*vqt6_callback_t)(void* user_data); +# vqt6_qobject_connect_typed(sender, signal_id, receiver, slot_id, type) 由 C++ 桥接层处理 +# 由于函数指针在 C ABI 中复杂,我们采用字符串 signal/slot 名 + 全局回调注册表 +def vqt6_qobject_connect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, + receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass + +def vqt6_qobject_disconnect(sender: QtObjectPtr, signal_name: t.CChar | t.CPtr, + receiver: QtObjectPtr, slot_name: t.CChar | t.CPtr) -> t.CInt | t.State: pass + +# 事件过滤器 +def vqt6_qobject_install_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass +def vqt6_qobject_remove_event_filter(watched: QtObjectPtr, filter: QtObjectPtr) -> t.State: pass + + +# ============================================================ +# QCoreApplication — 事件循环基类 +# ============================================================ +def vqt6_qcoreapp_create(app_name: t.CChar | t.CPtr) -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_instance() -> QtCoreAppPtr | t.State: pass +def vqt6_qcoreapp_exec(app: QtCoreAppPtr) -> t.CInt | t.State: pass +def vqt6_qcoreapp_quit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qcoreapp_exit(app: QtCoreAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qcoreapp_process_events(app: QtCoreAppPtr, flags: t.CInt) -> t.State: pass +def vqt6_qcoreapp_post_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.State: pass +def vqt6_qcoreapp_send_event(receiver: QtObjectPtr, event: QtEventPtr) -> t.CInt | t.State: pass +def vqt6_qcoreapp_organization_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass +def vqt6_qcoreapp_set_organization_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass +def vqt6_qcoreapp_application_name(app: QtCoreAppPtr) -> QtStringPtr | t.State: pass +def vqt6_qcoreapp_set_application_name(app: QtCoreAppPtr, name: QtStringPtr) -> t.State: pass + + +# ============================================================ +# QTimer — 定时器 +# ============================================================ +def vqt6_qtimer_create() -> QtTimerPtr | t.State: pass +def vqt6_qtimer_create_with_parent(parent: QtObjectPtr) -> QtTimerPtr | t.State: pass +def vqt6_qtimer_start(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass +def vqt6_qtimer_stop(timer: QtTimerPtr) -> t.State: pass +def vqt6_qtimer_set_interval(timer: QtTimerPtr, interval_ms: t.CInt) -> t.State: pass +def vqt6_qtimer_interval(timer: QtTimerPtr) -> t.CInt | t.State: pass +def vqt6_qtimer_is_active(timer: QtTimerPtr) -> t.CInt | t.State: pass +def vqt6_qtimer_set_single_shot(timer: QtTimerPtr, single_shot: t.CInt) -> t.State: pass +def vqt6_qtimer_is_single_shot(timer: QtTimerPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QVariant — 通用数据容器 +# ============================================================ +def vqt6_qvariant_create_int(value: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_double(value: t.CDouble) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_bool(value: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_create_string(s: QtStringPtr) -> QtVariantPtr | t.State: pass +def vqt6_qvariant_to_int(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_to_double(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CDouble | t.State: pass +def vqt6_qvariant_to_bool(v: QtVariantPtr, ok: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_to_string(v: QtVariantPtr) -> QtStringPtr | t.State: pass +def vqt6_qvariant_type_id(v: QtVariantPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_is_valid(v: QtVariantPtr) -> t.CInt | t.State: pass +def vqt6_qvariant_free(v: QtVariantPtr) -> t.State: pass + + +# ============================================================ +# QEvent — 事件基类 +# ============================================================ +def vqt6_qevent_type(event: QtEventPtr) -> t.CInt | t.State: pass +def vqt6_qevent_accept(event: QtEventPtr) -> t.State: pass +def vqt6_qevent_ignore(event: QtEventPtr) -> t.State: pass +def vqt6_qevent_is_accepted(event: QtEventPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# 字符串列表 (QStringList / QList) +# ============================================================ +def vqt6_qstringlist_create() -> QtStringListPtr | t.State: pass +def vqt6_qstringlist_append(list: QtStringListPtr, str: QtStringPtr) -> t.State: pass +def vqt6_qstringlist_size(list: QtStringListPtr) -> t.CInt | t.State: pass +def vqt6_qstringlist_at(list: QtStringListPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qstringlist_free(list: QtStringListPtr) -> t.State: pass + + +# ============================================================ +# 字节数组列表 (QList) +# ============================================================ +def vqt6_qbytearraylist_create() -> QtByteArrayListPtr | t.State: pass +def vqt6_qbytearraylist_append(list: QtByteArrayListPtr, qba: QtByteArrayPtr) -> t.State: pass +def vqt6_qbytearraylist_size(list: QtByteArrayListPtr) -> t.CInt | t.State: pass +def vqt6_qbytearraylist_at(list: QtByteArrayListPtr, index: t.CInt) -> QtByteArrayPtr | t.State: pass +def vqt6_qbytearraylist_free(list: QtByteArrayListPtr) -> t.State: pass + + +# ============================================================ +# 全局回调注册表 +# ============================================================ +# 用于从 C++ 端回调 Viper 代码 +# Viper 注册一个 slot 函数(用整数 ID 标识),C++ 在触发信号时通过 ID 查找 +# typedef void (*vqt6_slot_callback_t)(int slot_id, void* user_data); +def vqt6_register_slot(slot_id: t.CInt, user_data: t.CVoid | t.CPtr) -> t.State: pass +def vqt6_unregister_slot(slot_id: t.CInt) -> t.State: pass +def vqt6_trigger_slot(slot_id: t.CInt) -> t.State: pass # 测试用 diff --git a/vqt6/_qtgui.vp b/vqt6/_qtgui.vp new file mode 100644 index 0000000..80f0094 --- /dev/null +++ b/vqt6/_qtgui.vp @@ -0,0 +1,237 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtgui.py — QtGui 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QColor — 颜色 +# ============================================================ +def vqt6_qcolor_create_rgb(r: t.CInt, g: t.CInt, b: t.CInt) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_rgba(r: t.CInt, g: t.CInt, b: t.CInt, a: t.CInt) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_name(name: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qcolor_create_hex(hex_str: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qcolor_red(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_green(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_blue(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_alpha(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_set_red(c: QtColorPtr, r: t.CInt) -> t.State: pass +def vqt6_qcolor_set_green(c: QtColorPtr, g: t.CInt) -> t.State: pass +def vqt6_qcolor_set_blue(c: QtColorPtr, b: t.CInt) -> t.State: pass +def vqt6_qcolor_set_alpha(c: QtColorPtr, a: t.CInt) -> t.State: pass +def vqt6_qcolor_set_rgb(c: QtColorPtr, r: t.CInt, g: t.CInt, b: t.CInt) -> t.State: pass +def vqt6_qcolor_set_rgba(c: QtColorPtr, r: t.CInt, g: t.CInt, b: t.CInt, a: t.CInt) -> t.State: pass +def vqt6_qcolor_name(c: QtColorPtr) -> QtStringPtr | t.State: pass +def vqt6_qcolor_is_valid(c: QtColorPtr) -> t.CInt | t.State: pass +def vqt6_qcolor_free(c: QtColorPtr) -> t.State: pass + + +# ============================================================ +# QFont — 字体 +# ============================================================ +def vqt6_qfont_create() -> QtFontPtr | t.State: pass +def vqt6_qfont_create_with_family(family: QtStringPtr) -> QtFontPtr | t.State: pass +def vqt6_qfont_create_with_family_size(family: QtStringPtr, point_size: t.CInt) -> QtFontPtr | t.State: pass +def vqt6_qfont_set_family(font: QtFontPtr, family: QtStringPtr) -> t.State: pass +def vqt6_qfont_family(font: QtFontPtr) -> QtStringPtr | t.State: pass +def vqt6_qfont_set_point_size(font: QtFontPtr, point_size: t.CInt) -> t.State: pass +def vqt6_qfont_point_size(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_pixel_size(font: QtFontPtr, pixel_size: t.CInt) -> t.State: pass +def vqt6_qfont_pixel_size(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_bold(font: QtFontPtr, bold: t.CInt) -> t.State: pass +def vqt6_qfont_bold(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_italic(font: QtFontPtr, italic: t.CInt) -> t.State: pass +def vqt6_qfont_italic(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_underline(font: QtFontPtr, underline: t.CInt) -> t.State: pass +def vqt6_qfont_underline(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_strike_out(font: QtFontPtr, strike_out: t.CInt) -> t.State: pass +def vqt6_qfont_strike_out(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_set_weight(font: QtFontPtr, weight: t.CInt) -> t.State: pass +def vqt6_qfont_weight(font: QtFontPtr) -> t.CInt | t.State: pass +def vqt6_qfont_free(font: QtFontPtr) -> t.State: pass + + +# ============================================================ +# QFontMetrics — 字体度量 +# ============================================================ +def vqt6_qfontmetrics_create(font: QtFontPtr) -> QtFontMetricsPtr | t.State: pass +def vqt6_qfontmetrics_width(fm: QtFontMetricsPtr, text: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_height(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_ascent(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_descent(fm: QtFontMetricsPtr) -> t.CInt | t.State: pass +def vqt6_qfontmetrics_free(fm: QtFontMetricsPtr) -> t.State: pass + + +# ============================================================ +# QPixmap — 像素图 +# ============================================================ +def vqt6_qpixmap_create() -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_create_with_size(w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_load(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_load_from_data(pm: QtPixmapPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CInt | t.State: pass +def vqt6_qpixmap_save(pm: QtPixmapPtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_width(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_height(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_is_null(pm: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpixmap_scaled(pm: QtPixmapPtr, w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qpixmap_fill(pm: QtPixmapPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qpixmap_free(pm: QtPixmapPtr) -> t.State: pass + + +# ============================================================ +# QImage — 图像 +# ============================================================ +def vqt6_qimage_create() -> QtImagePtr | t.State: pass +def vqt6_qimage_create_with_size(w: t.CInt, h: t.CInt, format: t.CInt) -> QtImagePtr | t.State: pass +def vqt6_qimage_load(img: QtImagePtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qimage_save(img: QtImagePtr, file_name: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qimage_width(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_height(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_format(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_is_null(img: QtImagePtr) -> t.CInt | t.State: pass +def vqt6_qimage_fill(img: QtImagePtr, color: QtColorPtr) -> t.State: pass +def vqt6_qimage_scaled(img: QtImagePtr, w: t.CInt, h: t.CInt) -> QtImagePtr | t.State: pass +def vqt6_qimage_free(img: QtImagePtr) -> t.State: pass + + +# ============================================================ +# QPainter — 绘画器 +# ============================================================ +def vqt6_qpainter_create() -> QtPainterPtr | t.State: pass +def vqt6_qpainter_begin(p: QtPainterPtr, device: QtPixmapPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_end(p: QtPainterPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_is_active(p: QtPainterPtr) -> t.CInt | t.State: pass +def vqt6_qpainter_set_pen(p: QtPainterPtr, pen: QtPenPtr) -> t.State: pass +def vqt6_qpainter_set_brush(p: QtPainterPtr, brush: QtBrushPtr) -> t.State: pass +def vqt6_qpainter_set_font(p: QtPainterPtr, font: QtFontPtr) -> t.State: pass +def vqt6_qpainter_pen(p: QtPainterPtr) -> QtPenPtr | t.State: pass +def vqt6_qpainter_brush(p: QtPainterPtr) -> QtBrushPtr | t.State: pass +def vqt6_qpainter_font(p: QtPainterPtr) -> QtFontPtr | t.State: pass +def vqt6_qpainter_set_opacity(p: QtPainterPtr, opacity: t.CDouble) -> t.State: pass +def vqt6_qpainter_opacity(p: QtPainterPtr) -> t.CDouble | t.State: pass + +# 绘图原语 +def vqt6_qpainter_draw_line(p: QtPainterPtr, x1: t.CInt, y1: t.CInt, x2: t.CInt, y2: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qpainter_fill_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, color: QtColorPtr) -> t.State: pass +def vqt6_qpainter_draw_ellipse(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_arc(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_chord(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_pie(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, start_angle: t.CInt, span_angle: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_polygon(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_polyline(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_point(p: QtPainterPtr, x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_points(p: QtPainterPtr, points: t.CInt | t.CPtr, point_count: t.CInt) -> t.State: pass +def vqt6_qpainter_draw_text(p: QtPainterPtr, x: t.CInt, y: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qpainter_draw_text_in_rect(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, flags: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qpainter_draw_pixmap(p: QtPainterPtr, x: t.CInt, y: t.CInt, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qpainter_draw_image(p: QtPainterPtr, x: t.CInt, y: t.CInt, image: QtImagePtr) -> t.State: pass +def vqt6_qpainter_draw_tiled_pixmap(p: QtPainterPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt, pixmap: QtPixmapPtr) -> t.State: pass + +# 变换 +def vqt6_qpainter_translate(p: QtPainterPtr, dx: t.CInt, dy: t.CInt) -> t.State: pass +def vqt6_qpainter_rotate(p: QtPainterPtr, angle: t.CDouble) -> t.State: pass +def vqt6_qpainter_scale(p: QtPainterPtr, sx: t.CDouble, sy: t.CDouble) -> t.State: pass +def vqt6_qpainter_reset_transform(p: QtPainterPtr) -> t.State: pass +def vqt6_qpainter_save(p: QtPainterPtr) -> t.State: pass +def vqt6_qpainter_restore(p: QtPainterPtr) -> t.State: pass + +def vqt6_qpainter_free(p: QtPainterPtr) -> t.State: pass + + +# ============================================================ +# QPen — 画笔 +# ============================================================ +def vqt6_qpen_create() -> QtPenPtr | t.State: pass +def vqt6_qpen_create_with_color(color: QtColorPtr) -> QtPenPtr | t.State: pass +def vqt6_qpen_create_with_color_width(color: QtColorPtr, width: t.CInt) -> QtPenPtr | t.State: pass +def vqt6_qpen_set_color(pen: QtPenPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qpen_color(pen: QtPenPtr) -> QtColorPtr | t.State: pass +def vqt6_qpen_set_width(pen: QtPenPtr, width: t.CInt) -> t.State: pass +def vqt6_qpen_width(pen: QtPenPtr) -> t.CInt | t.State: pass +def vqt6_qpen_set_style(pen: QtPenPtr, style: t.CInt) -> t.State: pass +def vqt6_qpen_style(pen: QtPenPtr) -> t.CInt | t.State: pass +def vqt6_qpen_free(pen: QtPenPtr) -> t.State: pass + + +# ============================================================ +# QBrush — 画刷 +# ============================================================ +def vqt6_qbrush_create() -> QtBrushPtr | t.State: pass +def vqt6_qbrush_create_with_color(color: QtColorPtr) -> QtBrushPtr | t.State: pass +def vqt6_qbrush_create_with_style(style: t.CInt) -> QtBrushPtr | t.State: pass +def vqt6_qbrush_set_color(brush: QtBrushPtr, color: QtColorPtr) -> t.State: pass +def vqt6_qbrush_color(brush: QtBrushPtr) -> QtColorPtr | t.State: pass +def vqt6_qbrush_set_style(brush: QtBrushPtr, style: t.CInt) -> t.State: pass +def vqt6_qbrush_style(brush: QtBrushPtr) -> t.CInt | t.State: pass +def vqt6_qbrush_free(brush: QtBrushPtr) -> t.State: pass + + +# ============================================================ +# QIcon — 图标 +# ============================================================ +def vqt6_qicon_create() -> QtIconPtr | t.State: pass +def vqt6_qicon_create_with_file(file_name: QtStringPtr) -> QtIconPtr | t.State: pass +def vqt6_qicon_add_file(icon: QtIconPtr, file_name: QtStringPtr) -> t.State: pass +def vqt6_qicon_add_pixmap(icon: QtIconPtr, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qicon_is_null(icon: QtIconPtr) -> t.CInt | t.State: pass +def vqt6_qicon_pixmap(icon: QtIconPtr, w: t.CInt, h: t.CInt) -> QtPixmapPtr | t.State: pass +def vqt6_qicon_free(icon: QtIconPtr) -> t.State: pass + + +# ============================================================ +# QCursor — 鼠标光标 +# ============================================================ +def vqt6_qcursor_create() -> QtCursorPtr | t.State: pass +def vqt6_qcursor_create_with_shape(shape: t.CInt) -> QtCursorPtr | t.State: pass +def vqt6_qcursor_pos(x: t.CInt | t.CPtr, y: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qcursor_set_pos(x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qcursor_set_shape(cursor: QtCursorPtr, shape: t.CInt) -> t.State: pass +def vqt6_qcursor_shape(cursor: QtCursorPtr) -> t.CInt | t.State: pass +def vqt6_qcursor_free(cursor: QtCursorPtr) -> t.State: pass + + +# ============================================================ +# QKeyEvent — 键盘事件 +# ============================================================ +def vqt6_qkeyevent_create(type: t.CInt, key: t.CInt, modifiers: t.CInt, text: QtStringPtr) -> QtKeyEventPtr | t.State: pass +def vqt6_qkeyevent_key(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_text(event: QtKeyEventPtr) -> QtStringPtr | t.State: pass +def vqt6_qkeyevent_modifiers(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_is_auto_repeat(event: QtKeyEventPtr) -> t.CInt | t.State: pass +def vqt6_qkeyevent_free(event: QtKeyEventPtr) -> t.State: pass + + +# ============================================================ +# QMouseEvent — 鼠标事件 +# ============================================================ +def vqt6_qmouseevent_create(type: t.CInt, local_pos: QtObjectPtr, button: t.CInt, buttons: t.CInt, modifiers: t.CInt) -> QtMouseEventPtr | t.State: pass +def vqt6_qmouseevent_button(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_buttons(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_x(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_y(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_global_x(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_global_y(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_modifiers(event: QtMouseEventPtr) -> t.CInt | t.State: pass +def vqt6_qmouseevent_free(event: QtMouseEventPtr) -> t.State: pass + + +# ============================================================ +# QResizeEvent / QPaintEvent / QCloseEvent +# ============================================================ +def vqt6_qresizeevent_create(width: t.CInt, height: t.CInt, old_width: t.CInt, old_height: t.CInt) -> QtResizeEventPtr | t.State: pass +def vqt6_qresizeevent_size(event: QtResizeEventPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qresizeevent_old_size(event: QtResizeEventPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qresizeevent_free(event: QtResizeEventPtr) -> t.State: pass + +def vqt6_qpaintevent_create(rect_x: t.CInt, rect_y: t.CInt, rect_w: t.CInt, rect_h: t.CInt) -> QtPaintEventPtr | t.State: pass +def vqt6_qpaintevent_rect(event: QtPaintEventPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qpaintevent_free(event: QtPaintEventPtr) -> t.State: pass + +def vqt6_qcloseevent_create() -> QtCloseEventPtr | t.State: pass +def vqt6_qcloseevent_is_accepted(event: QtCloseEventPtr) -> t.CInt | t.State: pass +def vqt6_qcloseevent_accept(event: QtCloseEventPtr) -> t.State: pass +def vqt6_qcloseevent_ignore(event: QtCloseEventPtr) -> t.State: pass +def vqt6_qcloseevent_free(event: QtCloseEventPtr) -> t.State: pass diff --git a/vqt6/_qtnetwork.vp b/vqt6/_qtnetwork.vp new file mode 100644 index 0000000..6859d8b --- /dev/null +++ b/vqt6/_qtnetwork.vp @@ -0,0 +1,184 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtnetwork.py — QtNetwork 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QHostAddress — IP 地址 +# ============================================================ +def vqt6_qhostaddress_create() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_ipv4(ipv4: t.CUInt32T) -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_string(address: QtStringPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_local_host() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_local_ipv4() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_broadcast() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_create_with_any_ipv4() -> QtHostAddressPtr | t.State: pass +def vqt6_qhostaddress_to_string(addr: QtHostAddressPtr) -> QtStringPtr | t.State: pass +def vqt6_qhostaddress_to_ipv4(addr: QtHostAddressPtr) -> t.CUInt32T | t.State: pass +def vqt6_qhostaddress_is_null(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_is_loopback(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_is_broadcast(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_protocol(addr: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qhostaddress_free(addr: QtHostAddressPtr) -> t.State: pass + + +# ============================================================ +# QAbstractSocket — TCP/UDP 套接字基类 +# ============================================================ +# 套接字状态 +QT_SOCKET_UNCONNECTED_STATE: t.CDefine = 0 +QT_SOCKET_HOST_LOOKUP_STATE: t.CDefine = 1 +QT_SOCKET_CONNECTING_STATE: t.CDefine = 2 +QT_SOCKET_CONNECTED_STATE: t.CDefine = 3 +QT_SOCKET_BOUND_STATE: t.CDefine = 4 +QT_SOCKET_LISTENING_STATE: t.CDefine = 5 +QT_SOCKET_CLOSING_STATE: t.CDefine = 6 + +# 套接字类型 +QT_SOCKET_TCP: t.CDefine = 0 +QT_SOCKET_UDP: t.CDefine = 1 + +# 套接字错误 +QT_SOCKET_NO_ERROR: t.CDefine = 0 + +# 通用方法 +def vqt6_qabstractsocket_state(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_error(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_error_string(socket: QtAbstractSocketPtr) -> QtStringPtr | t.State: pass +def vqt6_qabstractsocket_connect_to_host(socket: QtAbstractSocketPtr, host_name: QtStringPtr, port: t.CUInt16T) -> t.State: pass +def vqt6_qabstractsocket_connect_to_host_with_addr(socket: QtAbstractSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.State: pass +def vqt6_qabstractsocket_disconnect_from_host(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_wait_for_connected(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_ready_read(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_bytes_written(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_wait_for_disconnected(socket: QtAbstractSocketPtr, timeout_ms: t.CInt) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_is_valid(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_is_open(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_flush(socket: QtAbstractSocketPtr) -> t.CInt | t.State: pass +def vqt6_qabstractsocket_close(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_abort(socket: QtAbstractSocketPtr) -> t.State: pass +def vqt6_qabstractsocket_read(socket: QtAbstractSocketPtr, buf: t.CVoid | t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_read_all(socket: QtAbstractSocketPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qabstractsocket_write(socket: QtAbstractSocketPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_bytes_available(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_bytes_to_write(socket: QtAbstractSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qabstractsocket_peer_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qabstractsocket_peer_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass +def vqt6_qabstractsocket_local_address(socket: QtAbstractSocketPtr) -> QtHostAddressPtr | t.State: pass +def vqt6_qabstractsocket_local_port(socket: QtAbstractSocketPtr) -> t.CUInt16T | t.State: pass + + +# ============================================================ +# QTcpSocket — TCP 套接字 +# ============================================================ +def vqt6_qtcpsocket_create() -> QtTcpSocketPtr | t.State: pass +def vqt6_qtcpsocket_create_with_parent(parent: QtObjectPtr) -> QtTcpSocketPtr | t.State: pass +def vqt6_qtcpsocket_connect_to_host(socket: QtTcpSocketPtr, host_name: QtStringPtr, port: t.CUInt16T, mode: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_connect_to_host_with_addr(socket: QtTcpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T, mode: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_set_socket_descriptor(socket: QtTcpSocketPtr, socket_descriptor: t.CInt) -> t.CInt | t.State: pass +def vqt6_qtcpsocket_socket_descriptor(socket: QtTcpSocketPtr) -> t.CInt | t.State: pass +def vqt6_qtcpsocket_set_proxy(socket: QtTcpSocketPtr, proxy_type: t.CInt) -> t.State: pass +def vqt6_qtcpsocket_abort(socket: QtTcpSocketPtr) -> t.State: pass + + +# ============================================================ +# QUdpSocket — UDP 套接字 +# ============================================================ +def vqt6_qudpsocket_create() -> QtUdpSocketPtr | t.State: pass +def vqt6_qudpsocket_create_with_parent(parent: QtObjectPtr) -> QtUdpSocketPtr | t.State: pass +def vqt6_qudpsocket_bind(socket: QtUdpSocketPtr, port: t.CUInt16T) -> t.CInt | t.State: pass +def vqt6_qudpsocket_bind_with_addr(socket: QtUdpSocketPtr, address: QtHostAddressPtr, port: t.CUInt16T) -> t.CInt | t.State: pass +def vqt6_qudpsocket_close(socket: QtUdpSocketPtr) -> t.State: pass +def vqt6_qudpsocket_write_datagram(socket: QtUdpSocketPtr, data: t.CVoid | t.CPtr, size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_read_datagram(socket: QtUdpSocketPtr, data: t.CVoid | t.CPtr, max_size: t.CSizeT, host: QtHostAddressPtr, port: t.CUInt16T | t.CPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_has_pending_datagrams(socket: QtUdpSocketPtr) -> t.CInt | t.State: pass +def vqt6_qudpsocket_pending_datagram_size(socket: QtUdpSocketPtr) -> t.CSizeT | t.State: pass +def vqt6_qudpsocket_join_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass +def vqt6_qudpsocket_leave_multicast_group(socket: QtUdpSocketPtr, group_address: QtHostAddressPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QNetworkRequest — 网络请求 +# ============================================================ +def vqt6_qnetworkrequest_create() -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkrequest_create_with_url(url: QtStringPtr) -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkrequest_set_url(req: QtNetworkRequestPtr, url: QtStringPtr) -> t.State: pass +def vqt6_qnetworkrequest_url(req: QtNetworkRequestPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkrequest_set_header(req: QtNetworkRequestPtr, header_type: t.CInt, value: QtVariantPtr) -> t.State: pass +def vqt6_qnetworkrequest_header(req: QtNetworkRequestPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkrequest_set_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, value: t.CVoid | t.CPtr, value_size: t.CSizeT) -> t.State: pass +def vqt6_qnetworkrequest_raw_header(req: QtNetworkRequestPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkrequest_set_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt, value: QtVariantPtr) -> t.State: pass +def vqt6_qnetworkrequest_attribute(req: QtNetworkRequestPtr, attr_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkrequest_free(req: QtNetworkRequestPtr) -> t.State: pass + + +# ============================================================ +# QNetworkAccessManager — HTTP 客户端管理器 +# ============================================================ +def vqt6_qnetworkaccessmanager_create() -> QtNetworkAccessManagerPtr | t.State: pass +def vqt6_qnetworkaccessmanager_create_with_parent(parent: QtObjectPtr) -> QtNetworkAccessManagerPtr | t.State: pass +def vqt6_qnetworkaccessmanager_get(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_post(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_put(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr, data: t.CVoid | t.CPtr, size: t.CSizeT) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_delete_resource(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_head(nam: QtNetworkAccessManagerPtr, req: QtNetworkRequestPtr) -> QtNetworkReplyPtr | t.State: pass +def vqt6_qnetworkaccessmanager_set_cookie_store(nam: QtNetworkAccessManagerPtr, store: QtObjectPtr) -> t.State: pass + + +# ============================================================ +# QNetworkReply — 网络响应 +# ============================================================ +def vqt6_qnetworkreply_url(reply: QtNetworkReplyPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkreply_request(reply: QtNetworkReplyPtr) -> QtNetworkRequestPtr | t.State: pass +def vqt6_qnetworkreply_error(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_error_string(reply: QtNetworkReplyPtr) -> QtStringPtr | t.State: pass +def vqt6_qnetworkreply_is_finished(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_is_running(reply: QtNetworkReplyPtr) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_abort(reply: QtNetworkReplyPtr) -> t.State: pass +def vqt6_qnetworkreply_read(reply: QtNetworkReplyPtr, buf: t.CVoid | t.CPtr, max_size: t.CSizeT) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_read_all(reply: QtNetworkReplyPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkreply_bytes_available(reply: QtNetworkReplyPtr) -> t.CSizeT | t.State: pass +def vqt6_qnetworkreply_header(reply: QtNetworkReplyPtr, header_type: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkreply_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, out_size: t.CSizeT | t.CPtr) -> t.CVoid | t.CPtr | t.State: pass +def vqt6_qnetworkreply_attribute(reply: QtNetworkReplyPtr, attribute_code: t.CInt) -> QtVariantPtr | t.State: pass +def vqt6_qnetworkreply_attribute_int(reply: QtNetworkReplyPtr, attribute_code: t.CInt, default_value: t.CInt) -> t.CInt | t.State: pass +def vqt6_qnetworkreply_set_raw_header(reply: QtNetworkReplyPtr, header_name: t.CChar | t.CPtr, value: t.CVoid | t.CPtr, value_size: t.CSizeT) -> t.State: pass + + +# ============================================================ +# 套接字类型枚举 +# ============================================================ +# 套接字类型 +QT_ABSTRACT_SOCKET_TCP: t.CDefine = 0 +QT_ABSTRACT_SOCKET_UDP: t.CDefine = 1 + +# 网络层协议 +QT_NETWORK_IPV4_PROTOCOL: t.CDefine = 0 +QT_NETWORK_IPV6_PROTOCOL: t.CDefine = 1 +QT_NETWORK_ANY_IP_PROTOCOL: t.CDefine = 2 + +# 主机地址特殊情况 +QT_HOST_ADDRESS_LOCAL_HOST: t.CDefine = 0x00000000 +QT_HOST_ADDRESS_LOCAL_HOST_IPV6: t.CDefine = 0x00000001 +QT_HOST_ADDRESS_BROADCAST: t.CDefine = 0x00000002 +QT_HOST_ADDRESS_ANY_IPV4: t.CDefine = 0x00000004 +QT_HOST_ADDRESS_ANY_IPV6: t.CDefine = 0x00000005 + + +# ============================================================ +# 已知端口常量 +# ============================================================ +QT_PORT_FTP: t.CDefine = 21 +QT_PORT_SSH: t.CDefine = 22 +QT_PORT_TELNET: t.CDefine = 23 +QT_PORT_SMTP: t.CDefine = 25 +QT_PORT_DNS: t.CDefine = 53 +QT_PORT_HTTP: t.CDefine = 80 +QT_PORT_POP3: t.CDefine = 110 +QT_PORT_IMAP: t.CDefine = 143 +QT_PORT_HTTPS: t.CDefine = 443 +QT_PORT_SMB: t.CDefine = 445 diff --git a/vqt6/_qtwidgets.vp b/vqt6/_qtwidgets.vp new file mode 100644 index 0000000..025d026 --- /dev/null +++ b/vqt6/_qtwidgets.vp @@ -0,0 +1,478 @@ +import t, c +from stdint import * +from vqt6._types import * + +# ============================================================ +# vqt6/_qtwidgets.py — QtWidgets 的 t.State FFI 声明 +# ============================================================ + +# ============================================================ +# QApplication — GUI 应用入口 +# ============================================================ +# argc/argv 通过单独的 buffer 数组传入(Viper 中 C 数组使用指针+长度) +def vqt6_qapplication_create(argc: t.CInt, argv: t.CPtr | t.CPtr) -> QtAppPtr | t.State: pass +def vqt6_qapplication_instance() -> QtAppPtr | t.State: pass +def vqt6_qapplication_exec(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_quit(app: QtAppPtr) -> t.State: pass +def vqt6_qapplication_exit(app: QtAppPtr, exit_code: t.CInt) -> t.State: pass +def vqt6_qapplication_process_events(app: QtAppPtr) -> t.State: pass +def vqt6_qapplication_desktop_width(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_desktop_height(app: QtAppPtr) -> t.CInt | t.State: pass +def vqt6_qapplication_set_quit_on_last_window_closed(app: QtAppPtr, quit: t.CInt) -> t.State: pass +def vqt6_qapplication_quit_on_last_window_closed(app: QtAppPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QWidget — 所有窗口的基类 +# ============================================================ +def vqt6_qwidget_create() -> QtWidgetPtr | t.State: pass +def vqt6_qwidget_create_with_parent(parent: QtWidgetPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qwidget_show(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_hide(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_close(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_is_visible(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_set_visible(widget: QtWidgetPtr, visible: t.CInt) -> t.State: pass + +# 几何 +def vqt6_qwidget_set_geometry(widget: QtWidgetPtr, x: t.CInt, y: t.CInt, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_geometry(widget: QtWidgetPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_resize(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_move(widget: QtWidgetPtr, x: t.CInt, y: t.CInt) -> t.State: pass +def vqt6_qwidget_pos(widget: QtWidgetPtr, x: t.CInt | t.CPtr, y: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_width(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_height(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_x(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_y(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 文本与标题 +def vqt6_qwidget_set_window_title(widget: QtWidgetPtr, title: QtStringPtr) -> t.State: pass +def vqt6_qwidget_window_title(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass +def vqt6_qwidget_set_text(widget: QtWidgetPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qwidget_text(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 启用 +def vqt6_qwidget_set_enabled(widget: QtWidgetPtr, enabled: t.CInt) -> t.State: pass +def vqt6_qwidget_is_enabled(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 父对象 +def vqt6_qwidget_set_parent(widget: QtWidgetPtr, parent: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_parent_widget(widget: QtWidgetPtr) -> QtWidgetPtr | t.State: pass + +# 焦点 +def vqt6_qwidget_set_focus(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_clear_focus(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_has_focus(widget: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qwidget_set_focus_policy(widget: QtWidgetPtr, policy: t.CInt) -> t.State: pass + +# 更新 +def vqt6_qwidget_update(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_repaint(widget: QtWidgetPtr) -> t.State: pass +def vqt6_qwidget_set_update_enabled(widget: QtWidgetPtr, enabled: t.CInt) -> t.State: pass + +# 窗口标志 +def vqt6_qwidget_set_window_flags(widget: QtWidgetPtr, flags: t.CInt) -> t.State: pass +def vqt6_qwidget_window_flags(widget: QtWidgetPtr) -> t.CInt | t.State: pass + +# 鼠标光标 +def vqt6_qwidget_set_cursor(widget: QtWidgetPtr, cursor: QtCursorPtr) -> t.State: pass +def vqt6_qwidget_cursor(widget: QtWidgetPtr) -> QtCursorPtr | t.State: pass +def vqt6_qwidget_unset_cursor(widget: QtWidgetPtr) -> t.State: pass + +# 工具提示 +def vqt6_qwidget_set_tool_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass +def vqt6_qwidget_tool_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 状态栏提示 +def vqt6_qwidget_set_status_tip(widget: QtWidgetPtr, tip: QtStringPtr) -> t.State: pass +def vqt6_qwidget_status_tip(widget: QtWidgetPtr) -> QtStringPtr | t.State: pass + +# 最小/最大尺寸 +def vqt6_qwidget_set_minimum_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_set_maximum_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_set_fixed_size(widget: QtWidgetPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qwidget_minimum_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass +def vqt6_qwidget_maximum_size(widget: QtWidgetPtr, w: t.CInt | t.CPtr, h: t.CInt | t.CPtr) -> t.State: pass + + +# ============================================================ +# QDialog — 对话框 +# ============================================================ +def vqt6_qdialog_create() -> QtDialogPtr | t.State: pass +def vqt6_qdialog_create_with_parent(parent: QtWidgetPtr) -> QtDialogPtr | t.State: pass +def vqt6_qdialog_exec(dialog: QtDialogPtr) -> t.CInt | t.State: pass +def vqt6_qdialog_done(dialog: QtDialogPtr, result: t.CInt) -> t.State: pass +def vqt6_qdialog_accept(dialog: QtDialogPtr) -> t.State: pass +def vqt6_qdialog_reject(dialog: QtDialogPtr) -> t.State: pass +def vqt6_qdialog_set_result(dialog: QtDialogPtr, result: t.CInt) -> t.State: pass +def vqt6_qdialog_result(dialog: QtDialogPtr) -> t.CInt | t.State: pass +def vqt6_qdialog_set_modal(dialog: QtDialogPtr, modal: t.CInt) -> t.State: pass +def vqt6_qdialog_is_modal(dialog: QtDialogPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMainWindow — 主窗口 +# ============================================================ +def vqt6_qmainwindow_create() -> QtMainWindowPtr | t.State: pass +def vqt6_qmainwindow_create_with_parent(parent: QtWidgetPtr) -> QtMainWindowPtr | t.State: pass +def vqt6_qmainwindow_set_central_widget(mw: QtMainWindowPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qmainwindow_central_widget(mw: QtMainWindowPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qmainwindow_menu_bar(mw: QtMainWindowPtr) -> QtMenuBarPtr | t.State: pass +def vqt6_qmainwindow_set_menu_bar(mw: QtMainWindowPtr, menubar: QtMenuBarPtr) -> t.State: pass +def vqt6_qmainwindow_status_bar(mw: QtMainWindowPtr) -> QtStatusBarPtr | t.State: pass +def vqt6_qmainwindow_set_status_bar(mw: QtMainWindowPtr, statusbar: QtStatusBarPtr) -> t.State: pass +def vqt6_qmainwindow_add_tool_bar(mw: QtMainWindowPtr, toolbar: QtToolBarPtr) -> t.State: pass +def vqt6_qmainwindow_add_tool_bar_break(mw: QtMainWindowPtr) -> t.State: pass + + +# ============================================================ +# QLabel — 标签 +# ============================================================ +def vqt6_qlabel_create() -> QtLabelPtr | t.State: pass +def vqt6_qlabel_create_with_text(text: QtStringPtr) -> QtLabelPtr | t.State: pass +def vqt6_qlabel_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLabelPtr | t.State: pass +def vqt6_qlabel_set_text(label: QtLabelPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlabel_text(label: QtLabelPtr) -> QtStringPtr | t.State: pass +def vqt6_qlabel_set_alignment(label: QtLabelPtr, alignment: t.CInt) -> t.State: pass +def vqt6_qlabel_alignment(label: QtLabelPtr) -> t.CInt | t.State: pass +def vqt6_qlabel_set_pixmap(label: QtLabelPtr, pixmap: QtPixmapPtr) -> t.State: pass +def vqt6_qlabel_pixmap(label: QtLabelPtr) -> QtPixmapPtr | t.State: pass +def vqt6_qlabel_set_indent(label: QtLabelPtr, indent: t.CInt) -> t.State: pass +def vqt6_qlabel_set_margin(label: QtLabelPtr, margin: t.CInt) -> t.State: pass +def vqt6_qlabel_set_word_wrap(label: QtLabelPtr, wrap: t.CInt) -> t.State: pass +def vqt6_qlabel_word_wrap(label: QtLabelPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QPushButton — 按钮 +# ============================================================ +def vqt6_qpushbutton_create() -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_create_with_text(text: QtStringPtr) -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtPushButtonPtr | t.State: pass +def vqt6_qpushbutton_set_text(btn: QtPushButtonPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qpushbutton_text(btn: QtPushButtonPtr) -> QtStringPtr | t.State: pass +def vqt6_qpushbutton_set_icon(btn: QtPushButtonPtr, icon: QtIconPtr) -> t.State: pass +def vqt6_qpushbutton_icon(btn: QtPushButtonPtr) -> QtIconPtr | t.State: pass +def vqt6_qpushbutton_set_default(btn: QtPushButtonPtr, is_default: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_default(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_flat(btn: QtPushButtonPtr, flat: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_flat(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_checkable(btn: QtPushButtonPtr, checkable: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_checkable(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_set_checked(btn: QtPushButtonPtr, checked: t.CInt) -> t.State: pass +def vqt6_qpushbutton_is_checked(btn: QtPushButtonPtr) -> t.CInt | t.State: pass +def vqt6_qpushbutton_click(btn: QtPushButtonPtr) -> t.State: pass + + +# ============================================================ +# QLineEdit — 单行输入框 +# ============================================================ +def vqt6_qlineedit_create() -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_create_with_text(text: QtStringPtr) -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtLineEditPtr | t.State: pass +def vqt6_qlineedit_text(le: QtLineEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qlineedit_set_text(le: QtLineEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlineedit_placeholder_text(le: QtLineEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qlineedit_set_placeholder_text(le: QtLineEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlineedit_set_max_length(le: QtLineEditPtr, max: t.CInt) -> t.State: pass +def vqt6_qlineedit_max_length(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_set_read_only(le: QtLineEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qlineedit_is_read_only(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_set_echo_mode(le: QtLineEditPtr, mode: t.CInt) -> t.State: pass +def vqt6_qlineedit_echo_mode(le: QtLineEditPtr) -> t.CInt | t.State: pass +def vqt6_qlineedit_select_all(le: QtLineEditPtr) -> t.State: pass +def vqt6_qlineedit_clear(le: QtLineEditPtr) -> t.State: pass + + +# ============================================================ +# QTextEdit / QPlainTextEdit — 多行文本编辑器 +# ============================================================ +def vqt6_qtextedit_create() -> QtTextEditPtr | t.State: pass +def vqt6_qtextedit_create_with_parent(parent: QtWidgetPtr) -> QtTextEditPtr | t.State: pass +def vqt6_qtextedit_to_plain_text(te: QtTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qtextedit_set_plain_text(te: QtTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_set_html(te: QtTextEditPtr, html: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_to_html(te: QtTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qtextedit_append(te: QtTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qtextedit_clear(te: QtTextEditPtr) -> t.State: pass +def vqt6_qtextedit_set_read_only(te: QtTextEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qtextedit_is_read_only(te: QtTextEditPtr) -> t.CInt | t.State: pass + +def vqt6_qplaintextedit_create() -> QtPlainTextEditPtr | t.State: pass +def vqt6_qplaintextedit_create_with_parent(parent: QtWidgetPtr) -> QtPlainTextEditPtr | t.State: pass +def vqt6_qplaintextedit_to_plain_text(pte: QtPlainTextEditPtr) -> QtStringPtr | t.State: pass +def vqt6_qplaintextedit_set_plain_text(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qplaintextedit_append(pte: QtPlainTextEditPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qplaintextedit_clear(pte: QtPlainTextEditPtr) -> t.State: pass +def vqt6_qplaintextedit_set_read_only(pte: QtPlainTextEditPtr, ro: t.CInt) -> t.State: pass +def vqt6_qplaintextedit_line_count(pte: QtPlainTextEditPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QCheckBox / QRadioButton — 复选/单选 +# ============================================================ +def vqt6_qcheckbox_create() -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_create_with_text(text: QtStringPtr) -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtCheckBoxPtr | t.State: pass +def vqt6_qcheckbox_set_checked(cb: QtCheckBoxPtr, checked: t.CInt) -> t.State: pass +def vqt6_qcheckbox_is_checked(cb: QtCheckBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcheckbox_set_text(cb: QtCheckBoxPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qcheckbox_text(cb: QtCheckBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qcheckbox_set_tristate(cb: QtCheckBoxPtr, tristate: t.CInt) -> t.State: pass +def vqt6_qcheckbox_is_tristate(cb: QtCheckBoxPtr) -> t.CInt | t.State: pass + +def vqt6_qradiobutton_create() -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_create_with_text(text: QtStringPtr) -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtRadioButtonPtr | t.State: pass +def vqt6_qradiobutton_set_checked(rb: QtRadioButtonPtr, checked: t.CInt) -> t.State: pass +def vqt6_qradiobutton_is_checked(rb: QtRadioButtonPtr) -> t.CInt | t.State: pass +def vqt6_qradiobutton_set_text(rb: QtRadioButtonPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qradiobutton_text(rb: QtRadioButtonPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# QComboBox — 下拉框 +# ============================================================ +def vqt6_qcombobox_create() -> QtComboBoxPtr | t.State: pass +def vqt6_qcombobox_create_with_parent(parent: QtWidgetPtr) -> QtComboBoxPtr | t.State: pass +def vqt6_qcombobox_add_item(cb: QtComboBoxPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qcombobox_add_items(cb: QtComboBoxPtr, items: QtStringListPtr) -> t.State: pass +def vqt6_qcombobox_insert_item(cb: QtComboBoxPtr, index: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qcombobox_remove_item(cb: QtComboBoxPtr, index: t.CInt) -> t.State: pass +def vqt6_qcombobox_clear(cb: QtComboBoxPtr) -> t.State: pass +def vqt6_qcombobox_count(cb: QtComboBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcombobox_current_index(cb: QtComboBoxPtr) -> t.CInt | t.State: pass +def vqt6_qcombobox_set_current_index(cb: QtComboBoxPtr, index: t.CInt) -> t.State: pass +def vqt6_qcombobox_current_text(cb: QtComboBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qcombobox_item_text(cb: QtComboBoxPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qcombobox_set_editable(cb: QtComboBoxPtr, editable: t.CInt) -> t.State: pass +def vqt6_qcombobox_is_editable(cb: QtComboBoxPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QListWidget — 列表控件 +# ============================================================ +def vqt6_qlistwidget_create() -> QtListWidgetPtr | t.State: pass +def vqt6_qlistwidget_create_with_parent(parent: QtWidgetPtr) -> QtListWidgetPtr | t.State: pass +def vqt6_qlistwidget_add_item(lw: QtListWidgetPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qlistwidget_add_items(lw: QtListWidgetPtr, items: QtStringListPtr) -> t.State: pass +def vqt6_qlistwidget_insert_item(lw: QtListWidgetPtr, row: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qlistwidget_remove_item_widget(lw: QtListWidgetPtr, row: t.CInt) -> t.State: pass +def vqt6_qlistwidget_take_item(lw: QtListWidgetPtr, row: t.CInt) -> QtListWidgetItemPtr | t.State: pass +def vqt6_qlistwidget_clear(lw: QtListWidgetPtr) -> t.State: pass +def vqt6_qlistwidget_count(lw: QtListWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qlistwidget_current_row(lw: QtListWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qlistwidget_set_current_row(lw: QtListWidgetPtr, row: t.CInt) -> t.State: pass +def vqt6_qlistwidget_current_item_text(lw: QtListWidgetPtr) -> QtStringPtr | t.State: pass +def vqt6_qlistwidget_item_text(lw: QtListWidgetPtr, row: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qlistwidget_set_item_text(lw: QtListWidgetPtr, row: t.CInt, text: QtStringPtr) -> t.State: pass + + +# ============================================================ +# QProgressBar — 进度条 +# ============================================================ +def vqt6_qprogressbar_create() -> QtProgressBarPtr | t.State: pass +def vqt6_qprogressbar_create_with_parent(parent: QtWidgetPtr) -> QtProgressBarPtr | t.State: pass +def vqt6_qprogressbar_set_value(pb: QtProgressBarPtr, value: t.CInt) -> t.State: pass +def vqt6_qprogressbar_value(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_set_minimum(pb: QtProgressBarPtr, min: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_maximum(pb: QtProgressBarPtr, max: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_range(pb: QtProgressBarPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qprogressbar_minimum(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_maximum(pb: QtProgressBarPtr) -> t.CInt | t.State: pass +def vqt6_qprogressbar_set_text_visible(pb: QtProgressBarPtr, visible: t.CInt) -> t.State: pass +def vqt6_qprogressbar_set_format(pb: QtProgressBarPtr, format: QtStringPtr) -> t.State: pass +def vqt6_qprogressbar_reset(pb: QtProgressBarPtr) -> t.State: pass + + +# ============================================================ +# QSlider — 滑块 +# ============================================================ +def vqt6_qslider_create() -> QtSliderPtr | t.State: pass +def vqt6_qslider_create_with_orientation(orientation: t.CInt) -> QtSliderPtr | t.State: pass +def vqt6_qslider_create_with_orientation_parent(orientation: t.CInt, parent: QtWidgetPtr) -> QtSliderPtr | t.State: pass +def vqt6_qslider_set_value(s: QtSliderPtr, value: t.CInt) -> t.State: pass +def vqt6_qslider_value(s: QtSliderPtr) -> t.CInt | t.State: pass +def vqt6_qslider_set_minimum(s: QtSliderPtr, min: t.CInt) -> t.State: pass +def vqt6_qslider_set_maximum(s: QtSliderPtr, max: t.CInt) -> t.State: pass +def vqt6_qslider_set_range(s: QtSliderPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qslider_set_orientation(s: QtSliderPtr, orientation: t.CInt) -> t.State: pass +def vqt6_qslider_orientation(s: QtSliderPtr) -> t.CInt | t.State: pass +def vqt6_qslider_set_single_step(s: QtSliderPtr, step: t.CInt) -> t.State: pass +def vqt6_qslider_set_page_step(s: QtSliderPtr, step: t.CInt) -> t.State: pass + + +# ============================================================ +# QSpinBox — 数字输入框 +# ============================================================ +def vqt6_qspinbox_create() -> QtSpinBoxPtr | t.State: pass +def vqt6_qspinbox_create_with_parent(parent: QtWidgetPtr) -> QtSpinBoxPtr | t.State: pass +def vqt6_qspinbox_value(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_set_value(sb: QtSpinBoxPtr, value: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_minimum(sb: QtSpinBoxPtr, min: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_maximum(sb: QtSpinBoxPtr, max: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_range(sb: QtSpinBoxPtr, min: t.CInt, max: t.CInt) -> t.State: pass +def vqt6_qspinbox_minimum(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_maximum(sb: QtSpinBoxPtr) -> t.CInt | t.State: pass +def vqt6_qspinbox_set_single_step(sb: QtSpinBoxPtr, step: t.CInt) -> t.State: pass +def vqt6_qspinbox_set_prefix(sb: QtSpinBoxPtr, prefix: QtStringPtr) -> t.State: pass +def vqt6_qspinbox_set_suffix(sb: QtSpinBoxPtr, suffix: QtStringPtr) -> t.State: pass +def vqt6_qspinbox_prefix(sb: QtSpinBoxPtr) -> QtStringPtr | t.State: pass +def vqt6_qspinbox_suffix(sb: QtSpinBoxPtr) -> QtStringPtr | t.State: pass + + +# ============================================================ +# 布局 - QLayout / QBoxLayout / QGridLayout / QFormLayout +# ============================================================ +def vqt6_qlayout_add_widget(layout: QtLayoutPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qlayout_remove_widget(layout: QtLayoutPtr, widget: QtWidgetPtr) -> t.State: pass +def vqt6_qlayout_count(layout: QtLayoutPtr) -> t.CInt | t.State: pass +def vqt6_qlayout_item_at(layout: QtLayoutPtr, index: t.CInt) -> QtWidgetPtr | t.State: pass +def vqt6_qlayout_set_contents_margins(layout: QtLayoutPtr, left: t.CInt, top: t.CInt, right: t.CInt, bottom: t.CInt) -> t.State: pass +def vqt6_qlayout_set_spacing(layout: QtLayoutPtr, spacing: t.CInt) -> t.State: pass +def vqt6_qlayout_spacing(layout: QtLayoutPtr) -> t.CInt | t.State: pass +def vqt6_qlayout_invalidate(layout: QtLayoutPtr) -> t.State: pass + +# QHBoxLayout +def vqt6_qhboxlayout_create() -> QtBoxLayoutPtr | t.State: pass +def vqt6_qhboxlayout_create_with_parent(parent: QtWidgetPtr) -> QtBoxLayoutPtr | t.State: pass +def vqt6_qhboxlayout_add_layout(layout: QtBoxLayoutPtr, child: QtLayoutPtr) -> t.State: pass +def vqt6_qhboxlayout_add_stretch(layout: QtBoxLayoutPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qhboxlayout_add_spacing(layout: QtBoxLayoutPtr, size: t.CInt) -> t.State: pass + +# QVBoxLayout +def vqt6_qvboxlayout_create() -> QtBoxLayoutPtr | t.State: pass +def vqt6_qvboxlayout_create_with_parent(parent: QtWidgetPtr) -> QtBoxLayoutPtr | t.State: pass +def vqt6_qvboxlayout_add_layout(layout: QtBoxLayoutPtr, child: QtLayoutPtr) -> t.State: pass +def vqt6_qvboxlayout_add_stretch(layout: QtBoxLayoutPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qvboxlayout_add_spacing(layout: QtBoxLayoutPtr, size: t.CInt) -> t.State: pass + +# QGridLayout +def vqt6_qgridlayout_create() -> QtGridLayoutPtr | t.State: pass +def vqt6_qgridlayout_create_with_parent(parent: QtWidgetPtr) -> QtGridLayoutPtr | t.State: pass +def vqt6_qgridlayout_add_widget(gl: QtGridLayoutPtr, w: QtWidgetPtr, row: t.CInt, col: t.CInt) -> t.State: pass +def vqt6_qgridlayout_add_widget_with_span(gl: QtGridLayoutPtr, w: QtWidgetPtr, row: t.CInt, col: t.CInt, row_span: t.CInt, col_span: t.CInt) -> t.State: pass + +# QFormLayout +def vqt6_qformlayout_create() -> QtFormLayoutPtr | t.State: pass +def vqt6_qformlayout_create_with_parent(parent: QtWidgetPtr) -> QtFormLayoutPtr | t.State: pass +def vqt6_qformlayout_add_row(fl: QtFormLayoutPtr, label: QtStringPtr, field: QtWidgetPtr) -> t.State: pass +def vqt6_qformlayout_add_row_widget_pair(fl: QtFormLayoutPtr, label: QtWidgetPtr, field: QtWidgetPtr) -> t.State: pass + + +# ============================================================ +# QStackedWidget / QTabWidget +# ============================================================ +def vqt6_qstackedwidget_create() -> QtStackedWidgetPtr | t.State: pass +def vqt6_qstackedwidget_create_with_parent(parent: QtWidgetPtr) -> QtStackedWidgetPtr | t.State: pass +def vqt6_qstackedwidget_add_widget(sw: QtStackedWidgetPtr, w: QtWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_remove_widget(sw: QtStackedWidgetPtr, w: QtWidgetPtr) -> t.State: pass +def vqt6_qstackedwidget_count(sw: QtStackedWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_current_index(sw: QtStackedWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qstackedwidget_set_current_index(sw: QtStackedWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qstackedwidget_current_widget(sw: QtStackedWidgetPtr) -> QtWidgetPtr | t.State: pass +def vqt6_qstackedwidget_widget(sw: QtStackedWidgetPtr, index: t.CInt) -> QtWidgetPtr | t.State: pass + +def vqt6_qtabwidget_create() -> QtTabWidgetPtr | t.State: pass +def vqt6_qtabwidget_create_with_parent(parent: QtWidgetPtr) -> QtTabWidgetPtr | t.State: pass +def vqt6_qtabwidget_add_tab(tw: QtTabWidgetPtr, w: QtWidgetPtr, label: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_insert_tab(tw: QtTabWidgetPtr, index: t.CInt, w: QtWidgetPtr, label: QtStringPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_remove_tab(tw: QtTabWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qtabwidget_count(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_current_index(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass +def vqt6_qtabwidget_set_current_index(tw: QtTabWidgetPtr, index: t.CInt) -> t.State: pass +def vqt6_qtabwidget_tab_text(tw: QtTabWidgetPtr, index: t.CInt) -> QtStringPtr | t.State: pass +def vqt6_qtabwidget_set_tab_text(tw: QtTabWidgetPtr, index: t.CInt, text: QtStringPtr) -> t.State: pass +def vqt6_qtabwidget_set_tabs_closable(tw: QtTabWidgetPtr, closable: t.CInt) -> t.State: pass +def vqt6_qtabwidget_tabs_closable(tw: QtTabWidgetPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMenuBar / QMenu / QAction +# ============================================================ +def vqt6_qmenubar_create() -> QtMenuBarPtr | t.State: pass +def vqt6_qmenubar_create_with_parent(parent: QtWidgetPtr) -> QtMenuBarPtr | t.State: pass +def vqt6_qmenubar_add_menu(mb: QtMenuBarPtr, title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenubar_add_menu_with_menu(mb: QtMenuBarPtr, menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenubar_add_action(mb: QtMenuBarPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qmenubar_clear(mb: QtMenuBarPtr) -> t.State: pass + +def vqt6_qmenu_create() -> QtMenuPtr | t.State: pass +def vqt6_qmenu_create_with_title(title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_create_with_title_parent(title: QtStringPtr, parent: QtWidgetPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_add_menu(menu: QtMenuPtr, title: QtStringPtr) -> QtMenuPtr | t.State: pass +def vqt6_qmenu_add_action(menu: QtMenuPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qmenu_add_separator(menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenu_clear(menu: QtMenuPtr) -> t.State: pass +def vqt6_qmenu_set_title(menu: QtMenuPtr, title: QtStringPtr) -> t.State: pass +def vqt6_qmenu_title(menu: QtMenuPtr) -> QtStringPtr | t.State: pass +def vqt6_qmenu_add_action_with_text(menu: QtMenuPtr, text: QtStringPtr) -> QtActionPtr | t.State: pass + +def vqt6_qaction_create() -> QtActionPtr | t.State: pass +def vqt6_qaction_create_with_text(text: QtStringPtr) -> QtActionPtr | t.State: pass +def vqt6_qaction_create_with_text_parent(text: QtStringPtr, parent: QtWidgetPtr) -> QtActionPtr | t.State: pass +def vqt6_qaction_set_text(action: QtActionPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qaction_text(action: QtActionPtr) -> QtStringPtr | t.State: pass +def vqt6_qaction_set_icon(action: QtActionPtr, icon: QtIconPtr) -> t.State: pass +def vqt6_qaction_icon(action: QtActionPtr) -> QtIconPtr | t.State: pass +def vqt6_qaction_set_shortcut(action: QtActionPtr, key_sequence: QtStringPtr) -> t.State: pass +def vqt6_qaction_shortcut(action: QtActionPtr) -> QtStringPtr | t.State: pass +def vqt6_qaction_set_checkable(action: QtActionPtr, checkable: t.CInt) -> t.State: pass +def vqt6_qaction_is_checkable(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_set_checked(action: QtActionPtr, checked: t.CInt) -> t.State: pass +def vqt6_qaction_is_checked(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_set_enabled(action: QtActionPtr, enabled: t.CInt) -> t.State: pass +def vqt6_qaction_is_enabled(action: QtActionPtr) -> t.CInt | t.State: pass +def vqt6_qaction_trigger(action: QtActionPtr) -> t.State: pass + + +# ============================================================ +# QStatusBar / QToolBar +# ============================================================ +def vqt6_qstatusbar_create() -> QtStatusBarPtr | t.State: pass +def vqt6_qstatusbar_create_with_parent(parent: QtWidgetPtr) -> QtStatusBarPtr | t.State: pass +def vqt6_qstatusbar_show_message(sb: QtStatusBarPtr, message: QtStringPtr, timeout_ms: t.CInt) -> t.State: pass +def vqt6_qstatusbar_clear_message(sb: QtStatusBarPtr) -> t.State: pass +def vqt6_qstatusbar_current_message(sb: QtStatusBarPtr) -> QtStringPtr | t.State: pass +def vqt6_qstatusbar_add_widget(sb: QtStatusBarPtr, w: QtWidgetPtr, stretch: t.CInt) -> t.State: pass +def vqt6_qstatusbar_add_permanent_widget(sb: QtStatusBarPtr, w: QtWidgetPtr, stretch: t.CInt) -> t.State: pass + +def vqt6_qtoolbar_create() -> QtToolBarPtr | t.State: pass +def vqt6_qtoolbar_create_with_parent(parent: QtWidgetPtr) -> QtToolBarPtr | t.State: pass +def vqt6_qtoolbar_add_widget(tb: QtToolBarPtr, w: QtWidgetPtr) -> QtActionPtr | t.State: pass +def vqt6_qtoolbar_add_action(tb: QtToolBarPtr, action: QtActionPtr) -> t.State: pass +def vqt6_qtoolbar_add_separator(tb: QtToolBarPtr) -> t.State: pass +def vqt6_qtoolbar_set_icon_size(tb: QtToolBarPtr, w: t.CInt, h: t.CInt) -> t.State: pass +def vqt6_qtoolbar_set_orientation(tb: QtToolBarPtr, orientation: t.CInt) -> t.State: pass +def vqt6_qtoolbar_orientation(tb: QtToolBarPtr) -> t.CInt | t.State: pass + + +# ============================================================ +# QMessageBox — 消息对话框(静态方法) +# ============================================================ +def vqt6_qmessagebox_information(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_warning(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_critical(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_question(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr, buttons: t.CInt) -> t.CInt | t.State: pass +def vqt6_qmessagebox_about(parent: QtWidgetPtr, title: QtStringPtr, text: QtStringPtr) -> t.State: pass +def vqt6_qmessagebox_about_qt(parent: QtWidgetPtr) -> t.State: pass + + +# ============================================================ +# QFileDialog — 文件选择对话框(静态方法) +# ============================================================ +def vqt6_qfiledialog_get_open_file_name(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_save_file_name(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_existing_directory(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr) -> QtStringPtr | t.State: pass +def vqt6_qfiledialog_get_open_file_names(parent: QtWidgetPtr, caption: QtStringPtr, dir: QtStringPtr, filter: QtStringPtr) -> QtStringListPtr | t.State: pass + + +# ============================================================ +# QColorDialog / QFontDialog / QInputDialog — 各种对话框 +# ============================================================ +def vqt6_qcolordialog_get_color(initial: QtColorPtr, parent: QtWidgetPtr, title: QtStringPtr) -> QtColorPtr | t.State: pass +def vqt6_qfontdialog_get_font(initial: QtFontPtr, parent: QtWidgetPtr, title: QtStringPtr) -> QtFontPtr | t.State: pass +def vqt6_qinputdialog_get_text(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, echo_mode: t.CInt, text: QtStringPtr, ok_pressed: t.CInt | t.CPtr) -> QtStringPtr | t.State: pass +def vqt6_qinputdialog_get_int(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, value: t.CInt, min_val: t.CInt, max_val: t.CInt, step: t.CInt, ok_pressed: t.CInt | t.CPtr) -> t.CInt | t.State: pass +def vqt6_qinputdialog_get_double(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, value: t.CDouble, min_val: t.CDouble, max_val: t.CDouble, decimals: t.CInt, ok_pressed: t.CInt | t.CPtr) -> t.CDouble | t.State: pass +def vqt6_qinputdialog_get_item(parent: QtWidgetPtr, title: QtStringPtr, label: QtStringPtr, items: QtStringListPtr, current: t.CInt, editable: t.CInt, ok_pressed: t.CInt | t.CPtr) -> QtStringPtr | t.State: pass diff --git a/vqt6/_types.vp b/vqt6/_types.vp new file mode 100644 index 0000000..86d1fe5 --- /dev/null +++ b/vqt6/_types.vp @@ -0,0 +1,186 @@ +import t +from stdint import * + +# ============================================================ +# vqt6/_types.py — 公共类型定义 +# +# Qt6 C++ 类在 Viper 端都是不透明指针 (void*) +# 不暴露 C++ 类的内部布局,只暴露指针 +# ============================================================ + +# 不透明指针 typedef(Qt6 C++ 类的 Viper 端表示) +QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # void* 通用不透明指针 +QtStringPtr: t.CTypedef = t.CVoid | t.CPtr # QString* +QtByteArrayPtr: t.CTypedef = t.CVoid | t.CPtr # QByteArray* +QtVariantPtr: t.CTypedef = t.CVoid | t.CPtr # QVariant* +QtObjectListPtr: t.CTypedef = t.CVoid | t.CPtr # QList* +QtStringListPtr: t.CTypedef = t.CVoid | t.CPtr # QStringList* +QtByteArrayListPtr: t.CTypedef = t.CVoid | t.CPtr # QList* +QtEventPtr: t.CTypedef = t.CVoid | t.CPtr # QEvent* + +# QtCore +QtCoreAppPtr: t.CTypedef = t.CVoid | t.CPtr # QCoreApplication* +QtTimerPtr: t.CTypedef = t.CVoid | t.CPtr # QTimer* +QtObjectPtr: t.CTypedef = t.CVoid | t.CPtr # QObject* +QtThreadPtr: t.CTypedef = t.CVoid | t.CPtr # QThread* +QtMutexPtr: t.CTypedef = t.CVoid | t.CPtr # QMutex* +QtWaitConditionPtr: t.CTypedef = t.CVoid | t.CPtr # QWaitCondition* + +# QtGui +QtColorPtr: t.CTypedef = t.CVoid | t.CPtr # QColor* +QtFontPtr: t.CTypedef = t.CVoid | t.CPtr # QFont* +QtFontMetricsPtr: t.CTypedef = t.CVoid | t.CPtr # QFontMetrics* +QtPixmapPtr: t.CTypedef = t.CVoid | t.CPtr # QPixmap* +QtImagePtr: t.CTypedef = t.CVoid | t.CPtr # QImage* +QtPainterPtr: t.CTypedef = t.CVoid | t.CPtr # QPainter* +QtPenPtr: t.CTypedef = t.CVoid | t.CPtr # QPen* +QtBrushPtr: t.CTypedef = t.CVoid | t.CPtr # QBrush* +QtIconPtr: t.CTypedef = t.CVoid | t.CPtr # QIcon* +QtKeyEventPtr: t.CTypedef = t.CVoid | t.CPtr # QKeyEvent* +QtMouseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QMouseEvent* +QtResizeEventPtr: t.CTypedef = t.CVoid | t.CPtr # QResizeEvent* +QtPaintEventPtr: t.CTypedef = t.CVoid | t.CPtr # QPaintEvent* +QtCloseEventPtr: t.CTypedef = t.CVoid | t.CPtr # QCloseEvent* +QtCursorPtr: t.CTypedef = t.CVoid | t.CPtr # QCursor* + +# QtWidgets +QtAppPtr: t.CTypedef = t.CVoid | t.CPtr # QApplication* +QtWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QWidget* +QtDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QDialog* +QtMainWindowPtr: t.CTypedef = t.CVoid | t.CPtr # QMainWindow* +QtLabelPtr: t.CTypedef = t.CVoid | t.CPtr # QLabel* +QtPushButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QPushButton* +QtLineEditPtr: t.CTypedef = t.CVoid | t.CPtr # QLineEdit* +QtTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QTextEdit* +QtPlainTextEditPtr: t.CTypedef = t.CVoid | t.CPtr # QPlainTextEdit* +QtCheckBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QCheckBox* +QtRadioButtonPtr: t.CTypedef = t.CVoid | t.CPtr # QRadioButton* +QtComboBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QComboBox* +QtListWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidget* +QtListWidgetItemPtr: t.CTypedef = t.CVoid | t.CPtr # QListWidgetItem* +QtProgressBarPtr: t.CTypedef = t.CVoid | t.CPtr # QProgressBar* +QtSliderPtr: t.CTypedef = t.CVoid | t.CPtr # QSlider* +QtSpinBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QSpinBox* +QtLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QLayout* +QtBoxLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QHBoxLayout / QVBoxLayout* +QtGridLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QGridLayout* +QtFormLayoutPtr: t.CTypedef = t.CVoid | t.CPtr # QFormLayout* +QtStackedWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QStackedWidget* +QtTabWidgetPtr: t.CTypedef = t.CVoid | t.CPtr # QTabWidget* +QtMenuBarPtr: t.CTypedef = t.CVoid | t.CPtr # QMenuBar* +QtMenuPtr: t.CTypedef = t.CVoid | t.CPtr # QMenu* +QtActionPtr: t.CTypedef = t.CVoid | t.CPtr # QAction* +QtStatusBarPtr: t.CTypedef = t.CVoid | t.CPtr # QStatusBar* +QtToolBarPtr: t.CTypedef = t.CVoid | t.CPtr # QToolBar* +QtMessageBoxPtr: t.CTypedef = t.CVoid | t.CPtr # QMessageBox* +QtFileDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFileDialog* +QtColorDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QColorDialog* +QtFontDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QFontDialog* +QtInputDialogPtr: t.CTypedef = t.CVoid | t.CPtr # QInputDialog* + +# QtNetwork +QtTcpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QTcpSocket* +QtUdpSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QUdpSocket* +QtHostAddressPtr: t.CTypedef = t.CVoid | t.CPtr # QHostAddress* +QtAbstractSocketPtr: t.CTypedef = t.CVoid | t.CPtr # QAbstractSocket* +QtNetworkAccessManagerPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkAccessManager* +QtNetworkReplyPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkReply* +QtNetworkRequestPtr: t.CTypedef = t.CVoid | t.CPtr # QNetworkRequest* + +# ============================================================ +# Qt 通用常量(C++ 枚举值的 C 兼容定义) +# ============================================================ + +# Qt 键盘按键 (Qt::Key) +QT_KEY_ESCAPE: t.CDefine = 0x01000000 +QT_KEY_TAB: t.CDefine = 0x01000001 +QT_KEY_BACKTAB: t.CDefine = 0x01000002 +QT_KEY_BACKSPACE: t.CDefine = 0x01000003 +QT_KEY_RETURN: t.CDefine = 0x01000004 +QT_KEY_ENTER: t.CDefine = 0x01000005 +QT_KEY_INSERT: t.CDefine = 0x01000006 +QT_KEY_DELETE: t.CDefine = 0x01000007 +QT_KEY_PAUSE: t.CDefine = 0x01000008 +QT_KEY_PRINT: t.CDefine = 0x01000009 +QT_KEY_HOME: t.CDefine = 0x01000010 +QT_KEY_END: t.CDefine = 0x01000011 +QT_KEY_LEFT: t.CDefine = 0x01000012 +QT_KEY_UP: t.CDefine = 0x01000013 +QT_KEY_RIGHT: t.CDefine = 0x01000014 +QT_KEY_DOWN: t.CDefine = 0x01000015 +QT_KEY_PAGEUP: t.CDefine = 0x01000016 +QT_KEY_PAGEDOWN: t.CDefine = 0x01000017 +QT_KEY_SHIFT: t.CDefine = 0x01000020 +QT_KEY_CONTROL: t.CDefine = 0x01000021 +QT_KEY_META: t.CDefine = 0x01000022 +QT_KEY_ALT: t.CDefine = 0x01000023 +QT_KEY_F1: t.CDefine = 0x01000030 +QT_KEY_F2: t.CDefine = 0x01000031 +QT_KEY_F12: t.CDefine = 0x0100003b +QT_KEY_SPACE: t.CDefine = 0x20 +QT_KEY_A: t.CDefine = 0x41 +QT_KEY_Z: t.CDefine = 0x5a +QT_KEY_0: t.CDefine = 0x30 +QT_KEY_9: t.CDefine = 0x39 + +# Qt 鼠标按键 (Qt::MouseButton) +QT_NO_BUTTON: t.CDefine = 0x00000000 +QT_LEFT_BUTTON: t.CDefine = 0x00000001 +QT_RIGHT_BUTTON: t.CDefine = 0x00000002 +QT_MID_BUTTON: t.CDefine = 0x00000004 + +# Qt::AlignmentFlag +QT_ALIGN_LEFT: t.CDefine = 0x0001 +QT_ALIGN_RIGHT: t.CDefine = 0x0002 +QT_ALIGN_HCENTER: t.CDefine = 0x0004 +QT_ALIGN_TOP: t.CDefine = 0x0020 +QT_ALIGN_BOTTOM: t.CDefine = 0x0040 +QT_ALIGN_VCENTER: t.CDefine = 0x0080 +QT_ALIGN_CENTER: t.CDefine = QT_ALIGN_HCENTER | QT_ALIGN_VCENTER + +# Qt::Orientation +QT_HORIZONTAL: t.CDefine = 0x1 +QT_VERTICAL: t.CDefine = 0x2 + +# Qt 焦点 +QT_NO_FOCUS: t.CDefine = 0x00 +QT_TAB_FOCUS: t.CDefine = 0x01 +QT_CLICK_FOCUS: t.CDefine = 0x02 +QT_STRONG_FOCUS: t.CDefine = QT_TAB_FOCUS | QT_CLICK_FOCUS +QT_WHEEL_FOCUS: t.CDefine = 0x04 +QT_ALL_FOCUS: t.CDefine = QT_STRONG_FOCUS | QT_WHEEL_FOCUS + +# Qt::WindowFlag +QT_WINDOW: t.CDefine = 0x00000001 +QT_DIALOG: t.CDefine = 0x00000002 | QT_WINDOW +QT_SHEET: t.CDefine = 0x00000004 | QT_WINDOW +QT_DRAWER: t.CDefine = QT_SHEET | 0x00000008 +QT_POPUP: t.CDefine = 0x00000008 | QT_WINDOW +QT_TOOL: t.CDefine = 0x0000000a | QT_WINDOW +QT_TOOLTIP: t.CDefine = 0x0000000c | QT_WINDOW +QT_SPLASH_SCREEN: t.CDefine = 0x0000000e | QT_WINDOW + +QT_WINDOW_TITLE: t.CDefine = 0x00000001 +QT_WINDOW_SYSTEM_MENU: t.CDefine = 0x00000002 +QT_WINDOW_MIN_MAX_BUTTONS: t.CDefine = 0x00000004 +QT_WINDOW_CLOSE_BUTTON: t.CDefine = 0x08000000 +QT_WINDOW_CONTEXT_HELP_BUTTON: t.CDefine = 0x00000008 + +# QMessageBox 标准按钮 +QT_OK: t.CDefine = 0x00000400 +QT_CANCEL: t.CDefine = 0x00400000 +QT_YES: t.CDefine = 0x00004000 +QT_NO: t.CDefine = 0x00010000 +QT_CLOSE: t.CDefine = 0x00200000 + +# 事件类型 +QT_EVENT_NONE: t.CDefine = 0 +QT_EVENT_KEY: t.CDefine = 6 +QT_EVENT_MOUSE_BUTTON_PRESS: t.CDefine = 2 +QT_EVENT_MOUSE_BUTTON_RELEASE: t.CDefine = 3 +QT_EVENT_MOUSE_MOVE: t.CDefine = 5 +QT_EVENT_PAINT: t.CDefine = 12 +QT_EVENT_RESIZE: t.CDefine = 14 +QT_EVENT_CLOSE: t.CDefine = 19 +QT_EVENT_SHOW: t.CDefine = 17 +QT_EVENT_HIDE: t.CDefine = 18 diff --git a/vrandom.vp b/vrandom.vp new file mode 100644 index 0000000..ecfa119 --- /dev/null +++ b/vrandom.vp @@ -0,0 +1,379 @@ +# vrandom - Hardware Random Number Generation Library +# Implemented using inline assembly based on x86 RDRAND / RDSEED instructions +import t, c +import vipermath + + +# Retry limit (RDRAND usually doesn't need retries, RDSEED might) +RDRAND_RETRY_LIMIT: t.CDefine = 10 +RDSEED_RETRY_LIMIT: t.CDefine = 100 + + +# ============================================================ +# RDRAND - Hardware random numbers (output from a pseudo-random number generator) +# ============================================================ + +def rdrand16() -> t.CUInt16T: + val: t.CUInt32T = 0 + c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return t.CUInt16T(val) + + +def rdrand32() -> t.CUInt32T: + val: t.CUInt32T = 0 + c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +def rdrand64() -> t.CUInt64T: + val: t.CUInt64T = 0 + c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +# ============================================================ +# RDSEED - Hardware random seeds (direct output from entropy source) +# ============================================================ + +def rdseed16() -> t.CUInt16T: + val: t.CUInt32T = 0 + c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return t.CUInt16T(val) + + +def rdseed32() -> t.CUInt32T: + val: t.CUInt32T = 0 + c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +def rdseed64() -> t.CUInt64T: + val: t.CUInt64T = 0 + c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC]) + return val + + +# ============================================================ +# Step version (with success flag, matching GCC builtin interface) +# Returns success flag: 1 on success, 0 on failure; random value written to *p +# ============================================================ + +def rdrand16_step(p: t.CUInt16T | t.CPtr) -> t.CInt: + val: t.CUInt32T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = t.CUInt16T(val) + return t.CInt(ok) + + +def rdrand32_step(p: t.CUInt32T | t.CPtr) -> t.CInt: + val: t.CUInt32T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = val + return t.CInt(ok) + + +def rdrand64_step(p: t.CUInt64T | t.CPtr) -> t.CInt: + val: t.CUInt64T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = val + return t.CInt(ok) + + +def rdseed16_step(p: t.CUInt16T | t.CPtr) -> t.CInt: + val: t.CUInt32T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = t.CUInt16T(val) + return t.CInt(ok) + + +def rdseed32_step(p: t.CUInt32T | t.CPtr) -> t.CInt: + val: t.CUInt32T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = val + return t.CInt(ok) + + +def rdseed64_step(p: t.CUInt64T | t.CPtr) -> t.CInt: + val: t.CUInt64T = 0 + ok: t.CUInt32T = 0 + c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)} + setc al + movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""", + out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)], + op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL]) + p[0] = val + return t.CInt(ok) + + +# ============================================================ +# Convenient interface with retry (automatically retries until it succeeds or reaches the limit) +# ============================================================ + +def random_u16() -> t.CUInt16T: + r: t.CUInt16T = 0 + i: t.CInt = 0 + while i < RDRAND_RETRY_LIMIT: + if rdrand16_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def random_u32() -> t.CUInt32T: + r: t.CUInt32T = 0 + i: t.CInt = 0 + while i < RDRAND_RETRY_LIMIT: + if rdrand32_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def random_u64() -> t.CUInt64T: + r: t.CUInt64T = 0 + i: t.CInt = 0 + while i < RDRAND_RETRY_LIMIT: + if rdrand64_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def seed_u16() -> t.CUInt16T: + r: t.CUInt16T = 0 + i: t.CInt = 0 + while i < RDSEED_RETRY_LIMIT: + if rdseed16_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def seed_u32() -> t.CUInt32T: + r: t.CUInt32T = 0 + i: t.CInt = 0 + while i < RDSEED_RETRY_LIMIT: + if rdseed32_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +def seed_u64() -> t.CUInt64T: + r: t.CUInt64T = 0 + i: t.CInt = 0 + while i < RDSEED_RETRY_LIMIT: + if rdseed64_step(c.Addr(r)) == 1: + return r + i += 1 + return 0 + + +# ============================================================ +# Python random standard library function implementations +# Default types: t.CUInt64T (u64), t.CDouble (f64), t.CInt (i32) +# ============================================================ + +# ---------- ONE, Random integers ---------- + +def randint(a: t.CInt, b: t.CInt) -> t.CInt: + return t.CInt(a + t.CInt(random_u64() % t.CUInt64T(b - a + 1))) + + +def randrange(start: t.CInt, stop: t.CInt, step: t.CInt = 1) -> t.CInt: + width: t.CInt = 0 + if step > 0: + width = (stop - start + step - 1) // step + else: + width = (start - stop - step - 1) // (-step) + return t.CInt(start + t.CInt(random_u64() % t.CUInt64T(width)) * step) + + +def getrandbits(k: t.CInt) -> t.CUInt64T: + r: t.CUInt64T = rdrand64() + if k >= 64: + return r + mask: t.CUInt64T = (t.CUInt64T(1) << k) - t.CUInt64T(1) + return r & mask + + +# ---------- TWO, Random floating-point numbers ---------- + +def random() -> t.CDouble: + return t.CDouble(rdrand64() >> 11) * (t.CDouble(1.0) / t.CDouble(9007199254740992.0)) + + +def uniform(a: t.CDouble, b: t.CDouble) -> t.CDouble: + return a + (b - a) * random() + + +def triangular(low: t.CDouble, high: t.CDouble, mode: t.CDouble) -> t.CDouble: + u: t.CDouble = random() + c: t.CDouble = (mode - low) / (high - low) + if u > c: + u = t.CDouble(1.0) - u + c = t.CDouble(1.0) - c + tmp: t.CDouble = low + low = high + high = tmp + return low + (high - low) * vipermath.sqrt(u * c) + + +def betavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: + y: t.CDouble = gammavariate(alpha, t.CDouble(1.0)) + if y != t.CDouble(0.0): + return y / (y + gammavariate(beta, t.CDouble(1.0))) + return t.CDouble(0.0) + + +def expovariate(lambd: t.CDouble) -> t.CDouble: + u: t.CDouble = random() + if u < t.CDouble(1e-300): + u = t.CDouble(1e-300) + return -vipermath.log(t.CDouble(1.0) - u) / lambd + + +def gammavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: + u: t.CDouble = t.CDouble(0.0) + d: t.CDouble = t.CDouble(0.0) + c: t.CDouble = t.CDouble(0.0) + x: t.CDouble = t.CDouble(0.0) + v: t.CDouble = t.CDouble(0.0) + if alpha <= t.CDouble(0.0) or beta <= t.CDouble(0.0): + return t.CDouble(0.0) + if alpha < t.CDouble(1.0): + u = random() + if u < t.CDouble(1e-300): + u = t.CDouble(1e-300) + return gammavariate(alpha + t.CDouble(1.0), beta) * vipermath.pow(u, t.CDouble(1.0) / alpha) + d = alpha - t.CDouble(1.0) / t.CDouble(3.0) + c = t.CDouble(1.0) / vipermath.sqrt(t.CDouble(9.0) * d) + while 1: + x = gauss(t.CDouble(0.0), t.CDouble(1.0)) + v = t.CDouble(1.0) + c * x + if v > t.CDouble(0.0): + v = v * v * v + u = random() + if u < t.CDouble(1.0) - t.CDouble(0.0331) * x * x * x * x: + return d * v * beta + if vipermath.log(u) < t.CDouble(0.5) * x * x + d * (t.CDouble(1.0) - v + vipermath.log(v)): + return d * v * beta + + +def gauss(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: + u1: t.CDouble = random() + u2: t.CDouble = random() + if u1 < t.CDouble(1e-300): + u1 = t.CDouble(1e-300) + z0: t.CDouble = vipermath.sqrt(t.CDouble(-2.0) * vipermath.log(u1)) * vipermath.cos(t.CDouble(2.0) * vipermath.U_M_PI * u2) + return mu + sigma * z0 + + +def normalvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: + NV_MAGICCONST: t.CDouble = t.CDouble(1.7155277699214135) + u1: t.CDouble = t.CDouble(0.0) + u2: t.CDouble = t.CDouble(0.0) + z: t.CDouble = t.CDouble(0.0) + zz: t.CDouble = t.CDouble(0.0) + while 1: + u1 = random() + u2 = random() + if u2 < t.CDouble(1e-300): + continue + z = NV_MAGICCONST * (u1 - t.CDouble(0.5)) / u2 + zz = z * z / t.CDouble(4.0) + if zz <= t.CDouble(0.0) - vipermath.log(u2): + break + return mu + z * sigma + + +def lognormvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble: + return vipermath.exp(gauss(mu, sigma)) + + +def vonmisesvariate(mu: t.CDouble, kappa: t.CDouble) -> t.CDouble: + if kappa <= t.CDouble(1e-6): + return vipermath.U_M_PI * t.CDouble(2.0) * random() + s: t.CDouble = t.CDouble(0.5) / kappa + r: t.CDouble = s + vipermath.sqrt(t.CDouble(1.0) + s * s) + u1: t.CDouble = t.CDouble(0.0) + u2: t.CDouble = t.CDouble(0.0) + u3: t.CDouble = t.CDouble(0.0) + z: t.CDouble = t.CDouble(0.0) + d: t.CDouble = t.CDouble(0.0) + q: t.CDouble = t.CDouble(0.0) + f: t.CDouble = t.CDouble(0.0) + theta: t.CDouble = t.CDouble(0.0) + two_pi: t.CDouble = vipermath.U_M_PI * t.CDouble(2.0) + while 1: + u1 = random() + z = vipermath.cos(vipermath.U_M_PI * u1) + d = t.CDouble(1.0) / (r + z) + u2 = random() + if u2 < t.CDouble(1.0) - d * d: + break + if u2 < (t.CDouble(1.0) - z) * vipermath.exp(kappa * (z - t.CDouble(1.0)) - d * kappa * r): + break + q = t.CDouble(1.0) / r + f = (q + z) / (t.CDouble(1.0) + q * z) + u3 = random() + if u3 > t.CDouble(0.5): + theta = mu + vipermath.acos(f) + else: + theta = mu - vipermath.acos(f) + while theta < t.CDouble(0.0): + theta += two_pi + while theta >= two_pi: + theta -= two_pi + return theta + + +def paretovariate(alpha: t.CDouble) -> t.CDouble: + u: t.CDouble = random() + if u < t.CDouble(1e-300): + u = t.CDouble(1e-300) + return t.CDouble(1.0) / vipermath.pow(t.CDouble(1.0) - u, t.CDouble(1.0) / alpha) + + +def weibullvariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble: + u: t.CDouble = random() + if u < t.CDouble(1e-300): + u = t.CDouble(1e-300) + return alpha * vipermath.pow(t.CDouble(-1.0) * vipermath.log(t.CDouble(1.0) - u), t.CDouble(1.0) / beta) diff --git a/vthreading.vp b/vthreading.vp new file mode 100644 index 0000000..12a1b4c --- /dev/null +++ b/vthreading.vp @@ -0,0 +1,102 @@ +import t, c +from stdint import * +from w32.win32base import * +from w32.win32process import CreateThread, GetExitCodeThread, GetCurrentThreadId, TlsAlloc, TlsFree, TlsGetValue, TlsSetValue +from w32.win32sync import WaitForSingleObject + +# All lock classes are imported, and users can also import them as needed. +from lock import Lock +from event import Event +from condition import Condition +from rwlock import RWLock + + +class Thread: + """Thread class, wraps Windows CreateThread. + + Thread callback signature: def thread_func(arg: t.CPtr) -> t.CPtr + Note: Windows API limits the return value to DWORD (32-bit), so 64-bit pointers will be truncated. + If you need to return a 64-bit result, pass it via the arg parameter struct. + + Usage: + def worker(arg: t.CPtr) -> t.CPtr: + # thread logic + return NULL + + t: Thread = Thread(worker, arg_ptr) + t.start() + t.join() + """ + handle: HANDLE + thread_id: ULONG + target: VOIDPTR + arg: VOIDPTR + started: BOOL + + def __init__(self, target: VOIDPTR, arg: VOIDPTR = NULL): + self.handle = NULL + self.thread_id = 0 + self.target = target + self.arg = arg + self.started = FALSE + + def start(self): + if self.started: + return + self.handle = CreateThread(NULL, 0, self.target, self.arg, 0, c.Addr(self.thread_id)) + self.started = TRUE + + def join(self, timeout_ms: ULONG = INFINITE) -> BOOL: + if not self.started: + return FALSE + result: ULONG = WaitForSingleObject(self.handle, timeout_ms) + return result == WAIT_OBJECT_0 + + def is_alive(self) -> BOOL: + if not self.started: + return FALSE + result: ULONG = WaitForSingleObject(self.handle, 0) + return result == WAIT_TIMEOUT + + def get_exit_code(self) -> ULONG: + code: ULONG = 0 + GetExitCodeThread(self.handle, c.Addr(code)) + return code + + def close(self): + if self.handle != NULL: + CloseHandle(self.handle) + self.handle = NULL + + +class local: + """TLS (Thread Local Storage) encapsulation. + + Usage: + tls: local = local() + tls.set(value_ptr) + val: t.CPtr = tls.get() + """ + index: ULONG + + def __init__(self): + self.index = TlsAlloc() + + def get(self) -> VOIDPTR: + return TlsGetValue(self.index) + + def set(self, value: VOIDPTR) -> BOOL: + return TlsSetValue(self.index, value) + + def free(self) -> BOOL: + return TlsFree(self.index) + + +def get_current_thread_id() -> ULONG: + """Get current thread ID""" + return GetCurrentThreadId() + + +def sleep_ms(ms: ULONG): + """Make the current thread sleep for a specified number of milliseconds""" + Sleep(ms) diff --git a/w32/fileio.vp b/w32/fileio.vp new file mode 100644 index 0000000..61b1ac9 --- /dev/null +++ b/w32/fileio.vp @@ -0,0 +1,389 @@ +import t, c +from stdint import * +import stdio +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, + None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None + ) + + 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)), None) + 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)), None) + 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, None, 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)), None) + 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() + if file_size < 0: return FRESULT.ERR_IO + 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)), None) + if result == 0: return FRESULT.ERR_IO + if bytes_read < max_count: + buf[bytes_read] = 0 + return LONG(bytes_read) + + +class FileW: + handle: w32.win32base.HANDLE + closed: bool + can_read: bool + can_write: bool + is_append: bool + _share_mode: ULONG + + def __init__(self, filename: w32.win32base.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, + None, disposition, w32.win32file.FILE_ATTRIBUTE_NORMAL, None + ) + + 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)), None) + 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)), None) + 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, None, 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)), None) + 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() + if file_size < 0: return FRESULT.ERR_IO + 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)), None) + 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: w32.win32base.LPCWSTR, mode: ULONG, share: ULONG = SHARE_READ) -> FileW | t.CPtr: + return FileW(filename, mode, share) diff --git a/w32/win32base.vp b/w32/win32base.vp new file mode 100644 index 0000000..aba48d3 --- /dev/null +++ b/w32/win32base.vp @@ -0,0 +1,80 @@ +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 = -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: DWORD + lpSecurityDescriptor: VOIDPTR + bInheritHandle: BOOL + +class OVERLAPPED(): + Internal: ULONGLONG + InternalHigh: ULONGLONG + Offset: DWORD + OffsetHigh: DWORD + 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 + +extern def GetLastError() -> ULONG +extern def SetLastError(dwErrCode: ULONG) +extern def CloseHandle(hObject: HANDLE) -> BOOL +extern def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR +extern def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE +extern def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE +extern def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE +extern def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE +extern def FreeLibrary(hLibModule: HANDLE) -> BOOL +extern def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) +extern def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) +extern def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL +extern def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL +extern def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL +extern def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL +extern def Sleep(dwMilliseconds: ULONG) +extern def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG +extern def GetTickCount() -> ULONG +extern def GetTickCount64() -> ULONGLONG +extern def GetCommandLineA() -> CHARPTR diff --git a/w32/win32console.vp b/w32/win32console.vp new file mode 100644 index 0000000..b7a7113 --- /dev/null +++ b/w32/win32console.vp @@ -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: DWORD + bVisible: BOOL + +class CHAR_INFO(): + UnicodeChar: WCHAR + Attributes: WORD + +class KEY_EVENT_RECORD(): + bKeyDown: BOOL + wRepeatCount: WORD + wVirtualKeyCode: WORD + wVirtualScanCode: WORD + uChar: WCHAR + dwControlKeyState: DWORD + +class MOUSE_EVENT_RECORD(): + dwMousePosition: COORD + dwButtonState: DWORD + dwControlKeyState: DWORD + dwEventFlags: DWORD + +class WINDOW_BUFFER_SIZE_RECORD(): + dwSize: COORD + +class INPUT_RECORD(): + EventType: WORD + Event: KEY_EVENT_RECORD + +extern def SetConsoleOutputCP(codepage: UINT) -> BOOL +extern def SetConsoleCP(codepage: UINT) -> BOOL +extern def GetConsoleCP() -> UINT +extern def GetConsoleOutputCP() -> UINT +extern def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL +extern def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL +extern def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL +extern def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL +extern def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL +extern def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL +extern def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL +extern def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL +extern def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL +extern def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL +extern def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL +extern def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL +extern def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL +extern def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL +extern def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL +extern def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL +extern def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL +extern def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL +extern def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL +extern def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL +extern def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL +extern def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG +extern def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG +extern def AllocConsole() -> BOOL +extern def FreeConsole() -> BOOL +extern def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL +extern def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL diff --git a/w32/win32file.vp b/w32/win32file.vp new file mode 100644 index 0000000..4fcbfb0 --- /dev/null +++ b/w32/win32file.vp @@ -0,0 +1,143 @@ +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: DWORD + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + dwVolumeSerialNumber: DWORD + nFileSizeHigh: DWORD + nFileSizeLow: DWORD + nNumberOfLinks: DWORD + nFileIndexHigh: DWORD + nFileIndexLow: DWORD + +class WIN32_FIND_DATAA(): + dwFileAttributes: DWORD + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: DWORD + nFileSizeLow: DWORD + dwReserved0: DWORD + dwReserved1: DWORD + cFileName: t.CArray[t.CChar, 260] + cAlternateFileName: t.CArray[t.CChar, 14] + +class WIN32_FIND_DATAW(): + dwFileAttributes: DWORD + ftCreationTime: FILETIME + ftLastAccessTime: FILETIME + ftLastWriteTime: FILETIME + nFileSizeHigh: DWORD + nFileSizeLow: DWORD + dwReserved0: DWORD + dwReserved1: DWORD + cFileName: t.CArray[t.CUInt16T, 260] + cAlternateFileName: t.CArray[t.CUInt16T, 14] + +extern def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE +extern def CreateFileW(lpFileName: LPCWSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE +extern def ReadFile(hFile: HANDLE, lpBuffer: VOIDPTR, nNumberOfBytesToRead: ULONG, lpNumberOfBytesRead: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL +extern def WriteFile(hFile: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfBytesToWrite: ULONG, lpNumberOfBytesWritten: ULONG | t.CPtr, lpOverlapped: OVERLAPPED | t.CPtr) -> BOOL +extern def SetFilePointer(hFile: HANDLE, lDistanceToMove: LONG, lpDistanceToMoveHigh: LONG | t.CPtr, dwMoveMethod: ULONG) -> LONG +extern def SetFilePointerEx(hFile: HANDLE, liDistanceToMove: LARGE_INTEGER | t.CPtr, lpNewFilePointer: LARGE_INTEGER | t.CPtr, dwMoveMethod: ULONG) -> BOOL +extern def GetFileSize(hFile: HANDLE, lpFileSizeHigh: ULONG | t.CPtr) -> ULONG +extern def GetFileSizeEx(hFile: HANDLE, lpFileSize: LARGE_INTEGER | t.CPtr) -> BOOL +extern def SetEndOfFile(hFile: HANDLE) -> BOOL +extern def FlushFileBuffers(hFile: HANDLE) -> BOOL +extern def GetFileType(hFile: HANDLE) -> ULONG +extern def GetFileAttributesA(lpFileName: LPCSTR) -> ULONG +extern def GetFileAttributesW(lpFileName: LPCWSTR) -> ULONG +extern def SetFileAttributesA(lpFileName: LPCSTR, dwFileAttributes: ULONG) -> BOOL +extern def SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: ULONG) -> BOOL +extern def DeleteFileA(lpFileName: LPCSTR) -> BOOL +extern def DeleteFileW(lpFileName: LPCWSTR) -> BOOL +extern def MoveFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR) -> BOOL +extern def MoveFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR) -> BOOL +extern def MoveFileExA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, dwFlags: ULONG) -> BOOL +extern def MoveFileExW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, dwFlags: ULONG) -> BOOL +extern def CopyFileA(lpExistingFileName: LPCSTR, lpNewFileName: LPCSTR, bFailIfExists: BOOL) -> BOOL +extern def CopyFileW(lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, bFailIfExists: BOOL) -> BOOL +extern def CreateDirectoryA(lpPathName: LPCSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL +extern def CreateDirectoryW(lpPathName: LPCWSTR, lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr) -> BOOL +extern def RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL +extern def RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL +extern def FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> HANDLE +extern def FindFirstFileW(lpFileName: LPCWSTR, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> HANDLE +extern def FindNextFileA(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAA | t.CPtr) -> BOOL +extern def FindNextFileW(hFindFile: HANDLE, lpFindFileData: WIN32_FIND_DATAW | t.CPtr) -> BOOL +extern def FindClose(hFindFile: HANDLE) -> BOOL +extern def GetStdHandle(nStdHandle: ULONG) -> HANDLE +extern def SetStdHandle(nStdHandle: ULONG, hHandle: HANDLE) -> BOOL +extern def GetFileInformationByHandle(hFile: HANDLE, lpFileInformation: BY_HANDLE_FILE_INFORMATION | t.CPtr) -> BOOL +extern def LockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToLockLow: ULONG, nNumberOfBytesToLockHigh: ULONG) -> BOOL +extern def UnlockFile(hFile: HANDLE, dwFileOffsetLow: ULONG, dwFileOffsetHigh: ULONG, nNumberOfBytesToUnlockLow: ULONG, nNumberOfBytesToUnlockHigh: ULONG) -> BOOL +extern def GetTempPathA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG +extern def GetTempPathW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG +extern def GetTempFileNameA(lpPathName: LPCSTR, lpPrefixString: LPCSTR, uUnique: UINT, lpTempFileName: CHARPTR) -> UINT +extern def GetTempFileNameW(lpPathName: LPCWSTR, lpPrefixString: LPCWSTR, uUnique: UINT, lpTempFileName: WCHARPTR) -> UINT +extern def GetCurrentDirectoryA(nBufferLength: ULONG, lpBuffer: CHARPTR) -> ULONG +extern def GetCurrentDirectoryW(nBufferLength: ULONG, lpBuffer: WCHARPTR) -> ULONG +extern def SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL +extern def SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL +extern def GetModuleFileNameA(hModule: HANDLE, lpFilename: CHARPTR, nSize: ULONG) -> ULONG +extern def GetModuleFileNameW(hModule: HANDLE, lpFilename: WCHARPTR, nSize: ULONG) -> ULONG + +HANDLE_FLAG_INHERIT: t.CDefine = 0x00000001 +HANDLE_FLAG_PROTECT_FROM_CLOSE: t.CDefine = 0x00000002 + +extern def CreatePipe(hReadPipe: HANDLE | t.CPtr, hWritePipe: HANDLE | t.CPtr, lpPipeAttributes: SECURITY_ATTRIBUTES | t.CPtr, nSize: ULONG) -> BOOL +extern def SetHandleInformation(hObject: HANDLE, dwMask: ULONG, dwFlags: ULONG) -> BOOL +extern def DuplicateHandle(hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, hTargetProcessHandle: HANDLE, lpTargetHandle: HANDLE | t.CPtr, dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwOptions: ULONG) -> BOOL + +DUPLICATE_SAME_ACCESS: t.CDefine = 0x00000002 diff --git a/w32/win32memory.vp b/w32/win32memory.vp new file mode 100644 index 0000000..ebeb811 --- /dev/null +++ b/w32/win32memory.vp @@ -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: DWORD + RegionSize: t.CSizeT + State: DWORD + Protect: DWORD + Type: DWORD + +extern def VirtualAlloc(lpAddress: VOIDPTR, dwSize: t.CSizeT, flAllocationType: ULONG, flProtect: ULONG) -> VOIDPTR +extern def VirtualFree(lpAddress: VOIDPTR, dwSize: t.CSizeT, dwFreeType: ULONG) -> BOOL +extern def VirtualProtect(lpAddress: VOIDPTR, dwSize: t.CSizeT, flNewProtect: ULONG, lpflOldProtect: ULONG | t.CPtr) -> BOOL +extern def VirtualQuery(lpAddress: t.CConst | VOIDPTR, lpBuffer: MEMORY_BASIC_INFORMATION | t.CPtr, dwLength: t.CSizeT) -> t.CSizeT +extern def VirtualLock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL +extern def VirtualUnlock(lpAddress: VOIDPTR, dwSize: t.CSizeT) -> BOOL +extern def GetProcessHeap() -> HANDLE +extern def HeapCreate(flOptions: ULONG, dwInitialSize: t.CSizeT, dwMaximumSize: t.CSizeT) -> HANDLE +extern def HeapDestroy(hHeap: HANDLE) -> BOOL +extern def HeapAlloc(hHeap: HANDLE, dwFlags: ULONG, dwBytes: t.CSizeT) -> VOIDPTR +extern def HeapReAlloc(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR, dwBytes: t.CSizeT) -> VOIDPTR +extern def HeapFree(hHeap: HANDLE, dwFlags: ULONG, lpMem: VOIDPTR) -> BOOL +extern def HeapSize(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> t.CSizeT +extern def HeapValidate(hHeap: HANDLE, dwFlags: ULONG, lpMem: t.CConst | VOIDPTR) -> BOOL +extern def HeapCompact(hHeap: HANDLE, dwFlags: ULONG) -> t.CSizeT +extern def GlobalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR +extern def GlobalFree(hMem: VOIDPTR) -> VOIDPTR +extern def GlobalLock(hMem: VOIDPTR) -> VOIDPTR +extern def GlobalUnlock(hMem: VOIDPTR) -> BOOL +extern def GlobalSize(hMem: VOIDPTR) -> t.CSizeT +extern def LocalAlloc(uFlags: UINT, dwBytes: t.CSizeT) -> VOIDPTR +extern def LocalFree(hMem: VOIDPTR) -> VOIDPTR diff --git a/w32/win32process.vp b/w32/win32process.vp new file mode 100644 index 0000000..89ed3e3 --- /dev/null +++ b/w32/win32process.vp @@ -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: DWORD + lpReserved: CHARPTR + lpDesktop: CHARPTR + lpTitle: CHARPTR + dwX: DWORD + dwY: DWORD + dwXSize: DWORD + dwYSize: DWORD + dwXCountChars: DWORD + dwYCountChars: DWORD + dwFillAttribute: DWORD + dwFlags: DWORD + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE + +class STARTUPINFOW(): + cb: DWORD + lpReserved: WCHARPTR + lpDesktop: WCHARPTR + lpTitle: WCHARPTR + dwX: DWORD + dwY: DWORD + dwXSize: DWORD + dwYSize: DWORD + dwXCountChars: DWORD + dwYCountChars: DWORD + dwFillAttribute: DWORD + dwFlags: DWORD + wShowWindow: WORD + cbReserved2: WORD + lpReserved2: VOIDPTR + hStdInput: HANDLE + hStdOutput: HANDLE + hStdError: HANDLE + +class PROCESS_INFORMATION(): + hProcess: HANDLE + hThread: HANDLE + dwProcessId: DWORD + dwThreadId: DWORD + +extern 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 +extern 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 +extern def TerminateProcess(hProcess: HANDLE, uExitCode: UINT) -> BOOL +extern def GetExitCodeProcess(hProcess: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL +extern def GetExitCodeThread(hThread: HANDLE, lpExitCode: ULONG | t.CPtr) -> BOOL +extern def OpenProcess(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwProcessId: ULONG) -> HANDLE +extern def GetCurrentProcess() -> HANDLE +extern def GetCurrentProcessId() -> ULONG +extern def CreateThread(lpThreadAttributes: SECURITY_ATTRIBUTES | t.CPtr, dwStackSize: t.CSizeT, lpStartAddress: VOIDPTR, lpParameter: VOIDPTR, dwCreationFlags: ULONG, lpThreadId: ULONG | t.CPtr) -> HANDLE +extern def OpenThread(dwDesiredAccess: ULONG, bInheritHandle: BOOL, dwThreadId: ULONG) -> HANDLE +extern def SuspendThread(hThread: HANDLE) -> ULONG +extern def ResumeThread(hThread: HANDLE) -> ULONG +extern def TerminateThread(hThread: HANDLE, dwExitCode: ULONG) -> BOOL +extern def GetCurrentThread() -> HANDLE +extern def GetCurrentThreadId() -> ULONG +extern def GetThreadId(hThread: HANDLE) -> ULONG +extern def GetProcessId(hProcess: HANDLE) -> ULONG +extern def SetThreadPriority(hThread: HANDLE, nPriority: INT) -> BOOL +extern def GetThreadPriority(hThread: HANDLE) -> INT +extern def ExitProcess(uExitCode: UINT) -> VOID +extern def ExitThread(dwExitCode: ULONG) -> VOID +extern def TlsAlloc() -> ULONG +extern def TlsFree(dwTlsIndex: ULONG) -> BOOL +extern def TlsGetValue(dwTlsIndex: ULONG) -> VOIDPTR +extern def TlsSetValue(dwTlsIndex: ULONG, lpTlsValue: VOIDPTR) -> BOOL diff --git a/w32/win32sync.vp b/w32/win32sync.vp new file mode 100644 index 0000000..a054423 --- /dev/null +++ b/w32/win32sync.vp @@ -0,0 +1,65 @@ +import t +from stdint import * +from w32.win32base import * + +class CRITICAL_SECTION(): + DebugInfo: VOIDPTR + LockCount: LONG + RecursionCount: LONG + OwningThread: HANDLE + LockSemaphore: HANDLE + SpinCount: QWORD + +extern def InitializeCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID +extern def EnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID +extern def LeaveCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID +extern def DeleteCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> VOID +extern def TryEnterCriticalSection(lpCriticalSection: CRITICAL_SECTION | t.CPtr) -> BOOL +extern def SetCriticalSectionSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> ULONG +extern def InitializeCriticalSectionAndSpinCount(lpCriticalSection: CRITICAL_SECTION | t.CPtr, dwSpinCount: ULONG) -> BOOL +extern def CreateMutexA(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCSTR) -> HANDLE +extern def CreateMutexW(lpMutexAttributes: SECURITY_ATTRIBUTES | t.CPtr, bInitialOwner: BOOL, lpName: LPCWSTR) -> HANDLE +extern def OpenMutexA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE +extern def OpenMutexW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE +extern def ReleaseMutex(hMutex: HANDLE) -> BOOL +extern def CreateEventA(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCSTR) -> HANDLE +extern def CreateEventW(lpEventAttributes: SECURITY_ATTRIBUTES | t.CPtr, bManualReset: BOOL, bInitialState: BOOL, lpName: LPCWSTR) -> HANDLE +extern def OpenEventA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE +extern def OpenEventW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE +extern def SetEvent(hEvent: HANDLE) -> BOOL +extern def ResetEvent(hEvent: HANDLE) -> BOOL +extern def PulseEvent(hEvent: HANDLE) -> BOOL +extern def CreateSemaphoreA(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCSTR) -> HANDLE +extern def CreateSemaphoreW(lpSemaphoreAttributes: SECURITY_ATTRIBUTES | t.CPtr, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE +extern def OpenSemaphoreA(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCSTR) -> HANDLE +extern def OpenSemaphoreW(dwDesiredAccess: ULONG, bInheritHandle: BOOL, lpName: LPCWSTR) -> HANDLE +extern def ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LONG | t.CPtr) -> BOOL +extern def WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: ULONG) -> ULONG +extern def WaitForSingleObjectEx(hHandle: HANDLE, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG +extern def WaitForMultipleObjects(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG) -> ULONG +extern def WaitForMultipleObjectsEx(nCount: ULONG, lpHandles: VOIDPTR, bWaitAll: BOOL, dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG +extern def InitializeSRWLock(SRWLock: VOIDPTR) -> VOID +extern def AcquireSRWLockExclusive(SRWLock: VOIDPTR) -> VOID +extern def AcquireSRWLockShared(SRWLock: VOIDPTR) -> VOID +extern def ReleaseSRWLockExclusive(SRWLock: VOIDPTR) -> VOID +extern def ReleaseSRWLockShared(SRWLock: VOIDPTR) -> VOID + +# 条件变量 (Condition Variables) - Vista+ +CONDITION_VARIABLE_LOCKMODE_SHARED: t.CDefine = 0x1 + +extern def InitializeConditionVariable(ConditionVariable: VOIDPTR) -> VOID +extern def SleepConditionVariableCS(ConditionVariable: VOIDPTR, CriticalSection: CRITICAL_SECTION | t.CPtr, dwMilliseconds: ULONG) -> BOOL +extern def SleepConditionVariableSRW(ConditionVariable: VOIDPTR, SRWLock: VOIDPTR, dwMilliseconds: ULONG, Flags: ULONG) -> BOOL +extern def WakeConditionVariable(ConditionVariable: VOIDPTR) -> VOID +extern def WakeAllConditionVariable(ConditionVariable: VOIDPTR) -> VOID + +# 一次性初始化 (One-Time Initialization) - Vista+ +INIT_ONCE_STATIC_INIT: t.CDefine = 0x00000001 +INIT_ONCE_CHECK_ONLY: t.CDefine = 0x00000002 +INIT_ONCE_ASYNC: t.CDefine = 0x00000004 +INIT_ONCE_INIT_FAILED: t.CDefine = 0x00000008 + +class INIT_ONCE: + Ptr: t.CPtr + +extern def InitOnceExecuteOnce(InitOnce: INIT_ONCE | t.CPtr, InitFn: VOIDPTR, Parameter: VOIDPTR, Context: VOIDPTR | t.CPtr) -> BOOL diff --git a/w32/winsock2.vp b/w32/winsock2.vp new file mode 100644 index 0000000..990b248 --- /dev/null +++ b/w32/winsock2.vp @@ -0,0 +1,104 @@ +import t, c +from stdint import * +from w32.win32base import * + + +# ============================================================ +# w32/winsock2.py — WinSock2 API 声明 (ws2_32.dll) +# ============================================================ + +# 版本常量 +WINSOCK_VERSION: t.CDefine = 0x0202 # 2.2 + +# 地址族 +AF_INET: t.CDefine = 2 +AF_INET6: t.CDefine = 23 + +# 套接字类型 +SOCK_STREAM: t.CDefine = 1 # TCP +SOCK_DGRAM: t.CDefine = 2 # UDP +SOCK_RAW: t.CDefine = 3 # 原始套接字 + +# 协议 +IPPROTO_TCP: t.CDefine = 6 +IPPROTO_UDP: t.CDefine = 17 + +# 选项级别 +SOL_SOCKET: t.CDefine = 0xFFFF # WinSock2 值 +SO_RCVTIMEO: t.CDefine = 0x1006 # WinSock2 值 +SO_SNDTIMEO: t.CDefine = 0x1005 # WinSock2 值 +SO_REUSEADDR: t.CDefine = 0x0004 # WinSock2 值 + +# 特殊值 +INADDR_ANY: t.CDefine = 0 +SOCKET_ERROR: t.CDefine = -1 +INVALID_SOCKET: t.CDefine = 0xFFFFFFFF # WinSock2: ~0 + +# 发送/接收标志 +MSG_NOSIGNAL: t.CDefine = 0 # Windows 不支持,设为 0 + +# 关闭方式 +SD_SEND: t.CDefine = 1 +SD_RECV: t.CDefine = 0 +SD_BOTH: t.CDefine = 2 + + +# ============================================================ +# 结构体 +# ============================================================ +# struct sockaddr_in — 16 字节 +class WSASocketAddr: + family: u16 # sin_family + port: u16 # sin_port + addr: u32 # sin_addr.s_addr + zero: u64 # sin_zero + + +# struct WSADATA — 400 字节 +class WSAData: + wVersion: WORD # @ 0 + wHighVersion: WORD # @ 2 + szDescription: BYTE # @ 4 (257 bytes + padding) + szSystemStatus: BYTE # @ 261 (129 bytes + padding) + iMaxSockets: u16 # @ 390 + iMaxUdpDg: u16 # @ 392 + lpVendorInfo: CHARPTR # @ 394 (实际上指针是 8 字节对齐) + + +# struct hostent — 自然对齐: h_name(8) + h_aliases(8) + h_addrtype(2) + h_length(2) + auto-pad(4) + h_addr_list(8) = 32 +class WSAHostEnt: + h_name: CHARPTR + h_aliases: CHARPTR + h_addrtype: SHORT + h_length: SHORT + h_addr_list: CHARPTR + + +# struct timeval +class WinTimeVal: + tv_sec: LONG # 秒 + tv_usec: LONG # 微秒 + + +# ============================================================ +# WinSock2 API 函数 +# ============================================================ + +extern def WSAStartup(wVersionRequested: WORD, lpWSAData: WSAData | t.CPtr) -> INT +extern def WSACleanup() -> INT +extern def WSAGetLastError() -> INT + +extern def socket(family: INT, type: INT, protocol: INT) -> u64 +extern def closesocket(s: u64) -> INT +extern def connect(s: u64, name: WSASocketAddr | t.CPtr, namelen: INT) -> INT +extern def send(s: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT +extern def recv(s: u64, buf: t.CVoid | t.CPtr, len: INT, flags: INT) -> INT +extern def bind(s: u64, name: WSASocketAddr | t.CPtr, namelen: INT) -> INT +extern def listen(s: u64, backlog: INT) -> INT +extern def accept(s: u64, addr: WSASocketAddr | t.CPtr, addrlen: INT | t.CPtr) -> u64 +extern def setsockopt(s: u64, level: INT, optname: INT, optval: t.CVoid | t.CPtr, optlen: INT) -> INT +extern def shutdown(s: u64, how: INT) -> INT +extern def gethostbyname(name: t.CChar | t.CConst | t.CPtr) -> WSAHostEnt | t.CPtr +extern def ntohs(netshort: u16) -> u16 +extern def htons(hostshort: u16) -> u16 +extern def inet_addr(cp: t.CChar | t.CConst | t.CPtr) -> u32 \ No newline at end of file diff --git a/zlib/__init__.vp b/zlib/__init__.vp new file mode 100644 index 0000000..829b69e --- /dev/null +++ b/zlib/__init__.vp @@ -0,0 +1 @@ +from .pyzlib import * diff --git a/zlib/pyzlib.vp b/zlib/pyzlib.vp new file mode 100644 index 0000000..6eb1ca9 --- /dev/null +++ b/zlib/pyzlib.vp @@ -0,0 +1,697 @@ +# from string import memset, memcpy +# from stdio import malloc, free, calloc, realloc +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 memhub +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: t.CArray[t.CChar, 512] = "" +pyzlib_error_code_val: t.CInt = 0 + +# ============================================================ +# Structures +# ============================================================ +@t.Object +class Compress: + pool: memhub.MemManager | 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(stdlib.calloc(1, 1)) + else: + p: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.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(stdlib.realloc(self.input_buf, self.input_buf_cap)) + else: + new_buf: BYTEPTR = BYTEPTR(self.pool.alloc(self.input_buf_cap)) + if new_buf: + string.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(stdlib.calloc(1, 1)) + else: + p2: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p2, 0, 1) + return p2 + self.input_buf = new_buf + string.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(stdlib.calloc(1, 1)) + else: + p3: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.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(stdlib.malloc(total)) + else: + result: BYTEPTR = BYTEPTR(self.pool.alloc(total)) + if result: string.memcpy(result, s.writer.buf, total) + c.Set(c.Deref(out_len), total) + if self.pool == None: + stdlib.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(stdlib.calloc(1, 1)) + else: + p4: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.memset(p4, 0, 1) + return p4 + + if self.pool == None: + result: BYTEPTR = BYTEPTR(stdlib.malloc(delta)) + else: + result: BYTEPTR = BYTEPTR(self.pool.alloc(delta)) + if result: string.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(stdlib.calloc(1, 1)) + else: + p5: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.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 = stdlib.calloc(1, Compress.__sizeof__()) + else: + copy_obj: Compress | t.CPtr = self.pool.alloc(Compress.__sizeof__()) + string.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: + stdlib.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(stdlib.calloc(1, self.input_buf_cap)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(self.input_buf_cap)) + string.memset(copy_obj.input_buf, 0, self.input_buf_cap) + if copy_obj.input_buf: + string.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(stdlib.calloc(1, 256)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(256)) + string.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: + stdlib.free(self.zdict) + stdlib.free(self.input_buf) + stdlib.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: memhub.MemManager | 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(stdlib.calloc(1, 1)) + else: + p6: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.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(stdlib.calloc(1, 1)) + else: + p7: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.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 + string.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(stdlib.calloc(1, 1)) + else: + p8: BYTEPTR = BYTEPTR(self.pool.alloc(1)) + string.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 = stdlib.calloc(1, Decompress.__sizeof__()) + else: + copy_obj: Decompress | t.CPtr = self.pool.alloc(Decompress.__sizeof__()) + string.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(stdlib.calloc(1, 256)) + else: + copy_obj.input_buf = BYTEPTR(self.pool.alloc(256)) + string.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: + stdlib.free(self.zdict) + stdlib.free(self._unused_data) + stdlib.free(self._unconsumed_tail) + stdlib.free(self.input_buf) + stdlib.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: + string.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: memhub.MemManager | t.CPtr, src: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if not src or length == 0: return None + if pool == None: + dst: BYTEPTR = BYTEPTR(stdlib.malloc(length)) + else: + dst: BYTEPTR = BYTEPTR(pool.alloc(length)) + if dst: string.memcpy(dst, src, length) + return dst + +def append_bytes(pool: memhub.MemManager | 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(stdlib.realloc(c.Deref(buf), new_cap)) + else: + new_buf: BYTEPTR = BYTEPTR(pool.alloc(new_cap)) + if new_buf: + string.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) + string.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: memhub.MemManager | t.CPtr, buf: BYTEPTR, length: t.CSizeT) -> BYTEPTR: + if length == 0: + if pool == None: + stdlib.free(buf) + return BYTEPTR(stdlib.calloc(1, 1)) + else: + pool.free(buf) + p: BYTEPTR = BYTEPTR(pool.alloc(1)) + string.memset(p, 0, 1) + return p + if pool == None: + result: BYTEPTR = BYTEPTR(stdlib.realloc(buf, length)) + return result if result else buf + else: + result: BYTEPTR = BYTEPTR(pool.alloc(length)) + if result: + string.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: memhub.MemManager | 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(stdlib.malloc(gzip_len)) + else: + gzip_buf: BYTEPTR = BYTEPTR(pool.alloc(gzip_len)) + if not gzip_buf: + if pool == None: + stdlib.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 + + string.memcpy(gzip_buf + pos, raw_result, c.Deref(out_len)) + pos += c.Deref(out_len) + if pool == None: + stdlib.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: memhub.MemManager | 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: memhub.MemManager | 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 = stdlib.calloc(1, Compress.__sizeof__()) + else: + obj: Compress | t.CPtr = pool.alloc(Compress.__sizeof__()) + string.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: + stdlib.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(stdlib.calloc(1, 256)) + else: + obj.input_buf = BYTEPTR(pool.alloc(256)) + string.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: memhub.MemManager | t.CPtr, wbits: t.CInt, zdict: BYTEPTR, zdict_len: t.CSizeT) -> Decompress | t.CPtr: + if pool == None: + obj: Decompress | t.CPtr = stdlib.calloc(1, Decompress.__sizeof__()) + else: + obj: Decompress | t.CPtr = pool.alloc(Decompress.__sizeof__()) + string.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(stdlib.calloc(1, 256)) + else: + obj.input_buf = BYTEPTR(pool.alloc(256)) + string.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/zlib/zchecksum.vp b/zlib/zchecksum.vp new file mode 100644 index 0000000..d46246f --- /dev/null +++ b/zlib/zchecksum.vp @@ -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: t.CArray[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/zlib/zdef.vp b/zlib/zdef.vp new file mode 100644 index 0000000..90c2b79 --- /dev/null +++ b/zlib/zdef.vp @@ -0,0 +1,287 @@ +from stdint import * +import string +import stdlib +import memhub +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: t.CArray[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: t.CArray[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: t.CArray[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: t.CArray[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: t.CArray[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: memhub.MemManager | t.CPtr + buf: BYTE | t.CPtr + cap: t.CSizeT + byte_pos: t.CSizeT + bit_pos: t.CInt + + def __init__(self, pool: memhub.MemManager | t.CPtr): + self.pool = pool + self.cap = 4096 + if pool == None: + self.buf = BYTEPTR(stdlib.malloc(self.cap)) + else: + self.buf = BYTEPTR(pool.alloc(self.cap)) + string.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(stdlib.realloc(self.buf, new_cap)) + else: + new_buf: BYTE | t.CPtr = BYTEPTR(self.pool.alloc(new_cap)) + if new_buf: + string.memcpy(new_buf, self.buf, self.byte_pos + (self.bit_pos + 7) / 8) + self.pool.free(self.buf) + if not new_buf: return + string.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: + stdlib.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: memhub.MemManager | t.CPtr, n: t.CSizeT) -> VOIDPTR: + if pool == None: return stdlib.malloc(n) + return pool.alloc(n) +def zdef_free(pool: memhub.MemManager | t.CPtr, p: VOIDPTR): + if pool == None: + stdlib.free(p) + return + pool.free(p) diff --git a/zlib/zdeflate.vp b/zlib/zdeflate.vp new file mode 100644 index 0000000..e79efda --- /dev/null +++ b/zlib/zdeflate.vp @@ -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 memhub +import t, c + + +@t.Object +class zdeflate_stream: + pool: memhub.MemManager | 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: t.CArray[t.CInt, 288] + dist_freqs: t.CArray[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: t.CArray[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: t.CArray[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) + string.memset(self.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + string.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 + string.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 + string.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 + string.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 + string.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 + string.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 + string.memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + string.memcpy(z.hash_head, self.hash_head, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + string.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): + string.memset(lit_freqs, 0, 288 * int.__sizeof__()) + string.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): + string.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: memhub.MemManager | t.CPtr, level: t.CInt, wbits: t.CInt, mem_level: t.CInt, strategy: t.CInt) -> zdeflate_stream | t.CPtr: + n: t.CSizeT = zdeflate_stream.__sizeof__() + s: zdeflate_stream | t.CPtr = zdef.zdef_alloc(pool, n) + if not s: return None + string.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 + string.memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + string.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: memhub.MemManager | 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 + + string.memset(s.hash_head, -1, zdef.ZDEFLATE_HASH_SIZE * int.__sizeof__()) + string.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: string.memcpy(result, s.writer.buf, c.Deref(out_len)) + s.destroy() + return result diff --git a/zlib/zhuff.vp b/zlib/zhuff.vp new file mode 100644 index 0000000..4707510 --- /dev/null +++ b/zlib/zhuff.vp @@ -0,0 +1,357 @@ +#include +from stdint import * +import zlib.zdef as zdef +import string +import memhub +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: memhub.MemManager | t.CPtr + codes: t.CArray[zhuff_code, ZHUFF_MAX_CODES] + count: t.CInt + max_bits: t.CInt + + def __init__(self): + self.pool = None + + def build_codes(self, freqs: INTPTR, count: t.CInt, max_bits: t.CInt): + lengths: t.CArray[t.CInt, ZHUFF_MAX_CODES] + bl_count: t.CArray[t.CInt, ZHUFF_MAX_BITS + 1] + next_code: t.CArray[UINT, ZHUFF_MAX_BITS + 1] + self.count = count + self.max_bits = max_bits + self.build_code_lengths(lengths, freqs, count, max_bits) + string.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: t.CArray[t.CInt, 288] + bl_count: t.CArray[t.CInt, 16] + next_code: t.CArray[t.CUnsignedInt, 16] + self.get_fixed_lit_lengths(lengths) + string.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: t.CArray[t.CInt, 32] + bl_count: t.CArray[t.CInt, 16] + next_code: t.CArray[t.CUnsignedInt, 16] + self.get_fixed_dist_lengths(lengths) + string.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: t.CArray[t.CInt, ZHUFF_MAX_BITS + 2] + sort_count: t.CInt = 0 + string.memset(bl_count, 0, bl_count.__sizeof__()) + string.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 + string.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: t.CArray[t.CInt, 16] + next_code: t.CArray[t.CUnsignedInt, 16] + + string.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: t.CArray[t.CInt, 2] + symbol: t.CInt + + +@t.Object +class zhuff_decode_tree: + pool: memhub.MemManager | t.CPtr + nodes: t.CArray[zhuff_decode_node, 2 * ZHUFF_MAX_CODES] + node_count: t.CInt + root: t.CInt + + def __init__(self): + self.pool = None + + 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/zlib/zinflate.vp b/zlib/zinflate.vp new file mode 100644 index 0000000..18cc5b4 --- /dev/null +++ b/zlib/zinflate.vp @@ -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 memhub +import t, c + + +@t.Object +class zinflate_stream: + pool: memhub.MemManager | 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 + string.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 + string.memset(lit_dt, 0, zhuff.zhuff_decode_tree.__sizeof__()) + string.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: t.CArray[t.CInt, 19] + string.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: t.CArray[t.CInt, 288] + string.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: t.CArray[t.CInt, 32] + string.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: + string.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 + string.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 + string.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 + string.memcpy(z.window, self.window, zdef.ZDEFLATE_WINDOW_SIZE) + string.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: memhub.MemManager | 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: memhub.MemManager | 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 + string.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