从 TransPyC 主项目中分离 VRTE
This commit is contained in:
commit
14ff9d109f
121 files changed
+41596
No files matched your search
@@ -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
|
||||||
@@ -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)
|
||||||
+320
@@ -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
|
||||||
@@ -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]
|
||||||
+64
@@ -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
|
||||||
@@ -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
|
||||||
+460
@@ -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))
|
||||||
@@ -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]
|
||||||
|
)
|
||||||
+115
@@ -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)
|
||||||
+337
@@ -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
|
||||||
+504
@@ -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'
|
||||||
+1239
File diff suppressed because it is too large.
Load diff
+773
@@ -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
|
||||||
+363
@@ -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
|
||||||
+2749
File diff suppressed because it is too large.
Load diff
+1157
File diff suppressed because it is too large.
Load diff
+404
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
+349
@@ -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
|
||||||
+13
@@ -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
|
||||||
@@ -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))
|
||||||
+19
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
+242
@@ -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
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import stdio
|
||||||
|
|
||||||
|
|
||||||
|
def helloworld():
|
||||||
|
stdio.printf("Hello, world!\n")
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
+479
@@ -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
|
||||||
@@ -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, <max_variant_payload> }`,小变体浪费内存。
|
||||||
|
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 而非胖节点)
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -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 <ret_ty> @<name>(<params>) {
|
||||||
|
# <block_name>:
|
||||||
|
# <instruction>
|
||||||
|
# <instruction>
|
||||||
|
# <block_name>:
|
||||||
|
# <instruction>
|
||||||
|
# }
|
||||||
|
# ============================================================
|
||||||
|
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 <ret_ty> @<name>(<params>)
|
||||||
|
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
|
||||||
@@ -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 <ret_ty> @<name>(<params>)
|
||||||
|
"""
|
||||||
|
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"<chars>" 其中 " 和 \ 及非打印字符用 \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:
|
||||||
|
@<name> = global i<bits> <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_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)
|
||||||
@@ -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):
|
||||||
|
"""打印单个全局变量: @<name> = [linkage] [unnamed_addr] [constant] <ty> <init>"""
|
||||||
|
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):
|
||||||
|
"""打印全局变量声明: @<name> = external global <ty>"""
|
||||||
|
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'
|
||||||
@@ -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, <max_variant_payload> }
|
||||||
|
# ============================================================
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
格式: <type> <name>
|
||||||
|
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'
|
||||||
@@ -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 名。
|
||||||
|
|
||||||
|
定义行格式: "%<name> = <instruction>"
|
||||||
|
返回分配的 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:
|
||||||
|
# 构造 "%<name>" 字符串
|
||||||
|
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 = "<unnamed>"
|
||||||
|
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
|
||||||
@@ -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))
|
||||||
@@ -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
|
||||||
|
|
||||||
+1163
File diff suppressed because it is too large.
Load diff
+134
@@ -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)
|
||||||
+190
@@ -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)
|
||||||
+234
@@ -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)
|
||||||
+316
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
+360
@@ -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))
|
||||||
@@ -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()
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
+16
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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 标准库 <stdint.h> 类型名(小写 _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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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"
|
||||||
+196
@@ -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)
|
||||||
@@ -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]
|
||||||
@@ -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
|
||||||
@@ -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")
|
||||||
@@ -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
|
||||||
+59
@@ -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
|
||||||
+1375
File diff suppressed because it is too large.
Load diff
+544
@@ -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
|
||||||
+492
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .string import *
|
||||||
@@ -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()
|
||||||
@@ -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 示例验证
|
||||||
@@ -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",
|
||||||
|
]
|
||||||
@@ -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 <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
// ============================================================
|
||||||
|
// vqt6/_bridge_core.cpp — QtCore C 桥接层实现
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
#include "_bridge.h"
|
||||||
|
#include <QString>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QList>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
// 全局回调表(线程安全)
|
||||||
|
namespace {
|
||||||
|
QMutex g_slot_mutex;
|
||||||
|
QHash<int, QPair<vqt6_slot_callback_t, void*>> 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<QString*>(qstr);
|
||||||
|
QByteArray ba = s->toUtf8();
|
||||||
|
size_t len = static_cast<size_t>(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<QString*>(qstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qstring_length(void* qstr) {
|
||||||
|
if (qstr == nullptr) return 0;
|
||||||
|
return static_cast<QString*>(qstr)->length();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qstring_is_empty(void* qstr) {
|
||||||
|
if (qstr == nullptr) return 1;
|
||||||
|
return static_cast<QString*>(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<QString*>(qstr) == *static_cast<QString*>(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<QString*>(qstr) + *static_cast<QString*>(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<const char*>(data), static_cast<int>(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size) {
|
||||||
|
if (qba == nullptr) return nullptr;
|
||||||
|
QByteArray* ba = static_cast<QByteArray*>(qba);
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(ba->size());
|
||||||
|
return ba->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API size_t vqt6_qbytearray_size(void* qba) {
|
||||||
|
if (qba == nullptr) return 0;
|
||||||
|
return static_cast<size_t>(static_cast<QByteArray*>(qba)->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbytearray_free(void* qba) {
|
||||||
|
delete static_cast<QByteArray*>(qba);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QObject
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_delete(void* obj) {
|
||||||
|
if (obj == nullptr) return;
|
||||||
|
delete static_cast<QObject*>(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_delete_later(void* obj) {
|
||||||
|
if (obj == nullptr) return;
|
||||||
|
static_cast<QObject*>(obj)->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name) {
|
||||||
|
if (obj == nullptr || name == nullptr) return;
|
||||||
|
static_cast<QObject*>(obj)->setObjectName(*static_cast<QString*>(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qobject_object_name(void* obj) {
|
||||||
|
if (obj == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QObject*>(obj)->objectName());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_set_parent(void* child, void* parent) {
|
||||||
|
if (child == nullptr) return;
|
||||||
|
static_cast<QObject*>(child)->setParent(static_cast<QObject*>(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qobject_parent(void* obj) {
|
||||||
|
if (obj == nullptr) return nullptr;
|
||||||
|
return static_cast<QObject*>(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<QObject*>(sender), signal_name,
|
||||||
|
static_cast<QObject*>(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<QObject*>(sender), signal_name,
|
||||||
|
static_cast<QObject*>(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<QObject*>(watched)->installEventFilter(static_cast<QObject*>(filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter) {
|
||||||
|
if (watched == nullptr || filter == nullptr) return;
|
||||||
|
static_cast<QObject*>(watched)->removeEventFilter(static_cast<QObject*>(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<QCoreApplication*>(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<QCoreApplication*>(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<QCoreApplication*>(app)->exit(exit_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags) {
|
||||||
|
if (app == nullptr) return;
|
||||||
|
static_cast<QCoreApplication*>(app)->processEvents(static_cast<QEventLoop::ProcessEventsFlag>(flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event) {
|
||||||
|
if (receiver == nullptr || event == nullptr) return;
|
||||||
|
QCoreApplication::postEvent(static_cast<QObject*>(receiver), static_cast<QEvent*>(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<QObject*>(receiver), static_cast<QEvent*>(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<QString*>(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<QString*>(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<QObject*>(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms) {
|
||||||
|
if (timer == nullptr) return;
|
||||||
|
static_cast<QTimer*>(timer)->start(interval_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qtimer_stop(void* timer) {
|
||||||
|
if (timer == nullptr) return;
|
||||||
|
static_cast<QTimer*>(timer)->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms) {
|
||||||
|
if (timer == nullptr) return;
|
||||||
|
static_cast<QTimer*>(timer)->setInterval(interval_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qtimer_interval(void* timer) {
|
||||||
|
if (timer == nullptr) return 0;
|
||||||
|
return static_cast<QTimer*>(timer)->interval();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qtimer_is_active(void* timer) {
|
||||||
|
if (timer == nullptr) return 0;
|
||||||
|
return static_cast<QTimer*>(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<QTimer*>(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<QTimer*>(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<QString*>(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<QVariant*>(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<QVariant*>(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<QVariant*>(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<QVariant*>(v)->toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qvariant_type_id(void* v) {
|
||||||
|
if (v == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QVariant*>(v)->typeId());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qvariant_is_valid(void* v) {
|
||||||
|
if (v == nullptr) return 0;
|
||||||
|
return static_cast<QVariant*>(v)->isValid() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qvariant_free(void* v) {
|
||||||
|
delete static_cast<QVariant*>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QEvent
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API int vqt6_qevent_type(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QEvent*>(event)->type());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qevent_accept(void* event) {
|
||||||
|
if (event == nullptr) return;
|
||||||
|
static_cast<QEvent*>(event)->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qevent_ignore(void* event) {
|
||||||
|
if (event == nullptr) return;
|
||||||
|
static_cast<QEvent*>(event)->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qevent_is_accepted(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<QEvent*>(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<QStringList*>(list)->append(*static_cast<QString*>(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qstringlist_size(void* list) {
|
||||||
|
if (list == nullptr) return 0;
|
||||||
|
return static_cast<QStringList*>(list)->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qstringlist_at(void* list, int index) {
|
||||||
|
if (list == nullptr) return nullptr;
|
||||||
|
QStringList* sl = static_cast<QStringList*>(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<QStringList*>(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QByteArrayList
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void* vqt6_qbytearraylist_create(void) {
|
||||||
|
return new QList<QByteArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba) {
|
||||||
|
if (list == nullptr || qba == nullptr) return;
|
||||||
|
static_cast<QList<QByteArray>*>(list)->append(*static_cast<QByteArray*>(qba));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qbytearraylist_size(void* list) {
|
||||||
|
if (list == nullptr) return 0;
|
||||||
|
return static_cast<QList<QByteArray>*>(list)->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qbytearraylist_at(void* list, int index) {
|
||||||
|
if (list == nullptr) return nullptr;
|
||||||
|
QList<QByteArray>* qbl = static_cast<QList<QByteArray>*>(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<QList<QByteArray>*>(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<vqt6_slot_callback_t, void*>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,868 @@
|
|||||||
|
// ============================================================
|
||||||
|
// vqt6/_bridge_gui.cpp — QtGui C 桥接层实现
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
#include "_bridge.h"
|
||||||
|
#include "_bridge_gui.h"
|
||||||
|
#include <QColor>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QFontMetrics>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPen>
|
||||||
|
#include <QBrush>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QPolygon>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QPointF>
|
||||||
|
#include <QRect>
|
||||||
|
#include <QRectF>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 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<QString*>(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<QString*>(hex_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_red(void* c) {
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
return static_cast<QColor*>(c)->red();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_green(void* c) {
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
return static_cast<QColor*>(c)->green();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_blue(void* c) {
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
return static_cast<QColor*>(c)->blue();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_alpha(void* c) {
|
||||||
|
if (c == nullptr) return 255;
|
||||||
|
return static_cast<QColor*>(c)->alpha();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_set_red(void* c, int r) {
|
||||||
|
if (c == nullptr) return;
|
||||||
|
static_cast<QColor*>(c)->setRed(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_set_green(void* c, int g) {
|
||||||
|
if (c == nullptr) return;
|
||||||
|
static_cast<QColor*>(c)->setGreen(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_set_blue(void* c, int b) {
|
||||||
|
if (c == nullptr) return;
|
||||||
|
static_cast<QColor*>(c)->setBlue(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_set_alpha(void* c, int a) {
|
||||||
|
if (c == nullptr) return;
|
||||||
|
static_cast<QColor*>(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<QColor*>(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<QColor*>(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<QColor*>(c)->name());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_is_valid(void* c) {
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
return static_cast<QColor*>(c)->isValid() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_free(void* c) {
|
||||||
|
delete static_cast<QColor*>(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<QString*>(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<QString*>(family), point_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_family(void* font, void* family) {
|
||||||
|
if (font == nullptr || family == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setFamily(*static_cast<QString*>(family));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qfont_family(void* font) {
|
||||||
|
if (font == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QFont*>(font)->family());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setPointSize(point_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_point_size(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->pointSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setPixelSize(pixel_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_pixel_size(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->pixelSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_bold(void* font, int bold) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setBold(bold != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_bold(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->bold() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_italic(void* font, int italic) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setItalic(italic != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_italic(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->italic() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_underline(void* font, int underline) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setUnderline(underline != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_underline(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(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<QFont*>(font)->setStrikeOut(strike_out != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_strike_out(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->strikeOut() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_weight(void* font, int weight) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setWeight(static_cast<QFont::Weight>(weight));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_weight(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QFont*>(font)->weight());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_free(void* font) {
|
||||||
|
delete static_cast<QFont*>(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QFontMetrics
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void* vqt6_qfontmetrics_create(void* font) {
|
||||||
|
if (font == nullptr) return nullptr;
|
||||||
|
return new QFontMetrics(*static_cast<QFont*>(font));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text) {
|
||||||
|
if (fm == nullptr || text == nullptr) return 0;
|
||||||
|
return static_cast<QFontMetrics*>(fm)->horizontalAdvance(*static_cast<QString*>(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfontmetrics_height(void* fm) {
|
||||||
|
if (fm == nullptr) return 0;
|
||||||
|
return static_cast<QFontMetrics*>(fm)->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfontmetrics_ascent(void* fm) {
|
||||||
|
if (fm == nullptr) return 0;
|
||||||
|
return static_cast<QFontMetrics*>(fm)->ascent();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfontmetrics_descent(void* fm) {
|
||||||
|
if (fm == nullptr) return 0;
|
||||||
|
return static_cast<QFontMetrics*>(fm)->descent();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfontmetrics_free(void* fm) {
|
||||||
|
delete static_cast<QFontMetrics*>(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<QPixmap*>(pm)->load(*static_cast<QString*>(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<QPixmap*>(pm)->loadFromData(static_cast<const uchar*>(data), static_cast<uint>(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<QPixmap*>(pm)->save(*static_cast<QString*>(file_name)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpixmap_width(void* pm) {
|
||||||
|
if (pm == nullptr) return 0;
|
||||||
|
return static_cast<QPixmap*>(pm)->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpixmap_height(void* pm) {
|
||||||
|
if (pm == nullptr) return 0;
|
||||||
|
return static_cast<QPixmap*>(pm)->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpixmap_is_null(void* pm) {
|
||||||
|
if (pm == nullptr) return 0;
|
||||||
|
return static_cast<QPixmap*>(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<QPixmap*>(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<QPixmap*>(pm)->fill(*static_cast<QColor*>(color));
|
||||||
|
} else {
|
||||||
|
static_cast<QPixmap*>(pm)->fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpixmap_free(void* pm) {
|
||||||
|
delete static_cast<QPixmap*>(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<QImage::Format>(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<QImage*>(img)->load(*static_cast<QString*>(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<QImage*>(img)->save(*static_cast<QString*>(file_name)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qimage_width(void* img) {
|
||||||
|
if (img == nullptr) return 0;
|
||||||
|
return static_cast<QImage*>(img)->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qimage_height(void* img) {
|
||||||
|
if (img == nullptr) return 0;
|
||||||
|
return static_cast<QImage*>(img)->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qimage_format(void* img) {
|
||||||
|
if (img == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QImage*>(img)->format());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qimage_is_null(void* img) {
|
||||||
|
if (img == nullptr) return 0;
|
||||||
|
return static_cast<QImage*>(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<QImage*>(img)->fill(*static_cast<QColor*>(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<QImage*>(img)->scaled(w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qimage_free(void* img) {
|
||||||
|
delete static_cast<QImage*>(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<QPainter*>(p)->begin(static_cast<QPixmap*>(device)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpainter_end(void* p) {
|
||||||
|
if (p == nullptr) return 0;
|
||||||
|
return static_cast<QPainter*>(p)->end() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpainter_is_active(void* p) {
|
||||||
|
if (p == nullptr) return 0;
|
||||||
|
return static_cast<QPainter*>(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<QPainter*>(p)->setPen(*static_cast<QPen*>(pen));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush) {
|
||||||
|
if (p == nullptr || brush == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->setBrush(*static_cast<QBrush*>(brush));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_set_font(void* p, void* font) {
|
||||||
|
if (p == nullptr || font == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->setFont(*static_cast<QFont*>(font));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qpainter_pen(void* p) {
|
||||||
|
if (p == nullptr) return nullptr;
|
||||||
|
return new QPen(static_cast<QPainter*>(p)->pen());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qpainter_brush(void* p) {
|
||||||
|
if (p == nullptr) return nullptr;
|
||||||
|
return new QBrush(static_cast<QPainter*>(p)->brush());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qpainter_font(void* p) {
|
||||||
|
if (p == nullptr) return nullptr;
|
||||||
|
return new QFont(static_cast<QPainter*>(p)->font());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->setOpacity(opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API double vqt6_qpainter_opacity(void* p) {
|
||||||
|
if (p == nullptr) return 1.0;
|
||||||
|
return static_cast<QPainter*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(p)->fillRect(x, y, w, h, *static_cast<QColor*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(p)->drawPolyline(polyline);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(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<QPainter*>(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<QPainter*>(p)->drawText(x, y, *static_cast<QString*>(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<QPainter*>(p)->drawText(x, y, w, h, flags, *static_cast<QString*>(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<QPainter*>(p)->drawPixmap(x, y, *static_cast<QPixmap*>(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<QPainter*>(p)->drawImage(x, y, *static_cast<QImage*>(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<QPainter*>(p)->drawTiledPixmap(x, y, w, h, *static_cast<QPixmap*>(pixmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->translate(dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_rotate(void* p, double angle) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->rotate(angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->scale(sx, sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_reset_transform(void* p) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->resetTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_save(void* p) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_restore(void* p) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_free(void* p) {
|
||||||
|
delete static_cast<QPainter*>(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<QColor*>(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<QColor*>(color), width);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpen_set_color(void* pen, void* color) {
|
||||||
|
if (pen == nullptr || color == nullptr) return;
|
||||||
|
static_cast<QPen*>(pen)->setColor(*static_cast<QColor*>(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qpen_color(void* pen) {
|
||||||
|
if (pen == nullptr) return nullptr;
|
||||||
|
return new QColor(static_cast<QPen*>(pen)->color());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpen_set_width(void* pen, int width) {
|
||||||
|
if (pen == nullptr) return;
|
||||||
|
static_cast<QPen*>(pen)->setWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpen_width(void* pen) {
|
||||||
|
if (pen == nullptr) return 0;
|
||||||
|
return static_cast<QPen*>(pen)->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpen_set_style(void* pen, int style) {
|
||||||
|
if (pen == nullptr) return;
|
||||||
|
static_cast<QPen*>(pen)->setStyle(static_cast<Qt::PenStyle>(style));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpen_style(void* pen) {
|
||||||
|
if (pen == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QPen*>(pen)->style());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpen_free(void* pen) {
|
||||||
|
delete static_cast<QPen*>(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<QColor*>(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qbrush_create_with_style(int style) {
|
||||||
|
return new QBrush(static_cast<Qt::BrushStyle>(style));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbrush_set_color(void* brush, void* color) {
|
||||||
|
if (brush == nullptr || color == nullptr) return;
|
||||||
|
static_cast<QBrush*>(brush)->setColor(*static_cast<QColor*>(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qbrush_color(void* brush) {
|
||||||
|
if (brush == nullptr) return nullptr;
|
||||||
|
return new QColor(static_cast<QBrush*>(brush)->color());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbrush_set_style(void* brush, int style) {
|
||||||
|
if (brush == nullptr) return;
|
||||||
|
static_cast<QBrush*>(brush)->setStyle(static_cast<Qt::BrushStyle>(style));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qbrush_style(void* brush) {
|
||||||
|
if (brush == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QBrush*>(brush)->style());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbrush_free(void* brush) {
|
||||||
|
delete static_cast<QBrush*>(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<QString*>(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<QIcon*>(icon)->addFile(*static_cast<QString*>(file_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap) {
|
||||||
|
if (icon == nullptr || pixmap == nullptr) return;
|
||||||
|
static_cast<QIcon*>(icon)->addPixmap(*static_cast<QPixmap*>(pixmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qicon_is_null(void* icon) {
|
||||||
|
if (icon == nullptr) return 0;
|
||||||
|
return static_cast<QIcon*>(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<QIcon*>(icon)->pixmap(w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qicon_free(void* icon) {
|
||||||
|
delete static_cast<QIcon*>(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<Qt::CursorShape>(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<QCursor*>(cursor)->setShape(static_cast<Qt::CursorShape>(shape));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcursor_shape(void* cursor) {
|
||||||
|
if (cursor == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QCursor*>(cursor)->shape());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcursor_free(void* cursor) {
|
||||||
|
delete static_cast<QCursor*>(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QKeyEvent
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text) {
|
||||||
|
QString* t = static_cast<QString*>(text);
|
||||||
|
return new QKeyEvent(static_cast<QEvent::Type>(type), key, static_cast<Qt::KeyboardModifiers>(modifiers),
|
||||||
|
t != nullptr ? *t : QString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qkeyevent_key(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<QKeyEvent*>(event)->key();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qkeyevent_text(void* event) {
|
||||||
|
if (event == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QKeyEvent*>(event)->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qkeyevent_modifiers(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QKeyEvent*>(event)->modifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<QKeyEvent*>(event)->isAutoRepeat() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qkeyevent_free(void* event) {
|
||||||
|
delete static_cast<QKeyEvent*>(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<QPointF*>(local_pos);
|
||||||
|
return new QMouseEvent(
|
||||||
|
static_cast<QEvent::Type>(type),
|
||||||
|
lp != nullptr ? *lp : QPointF(0, 0),
|
||||||
|
Qt::NoButton,
|
||||||
|
static_cast<Qt::MouseButton>(button),
|
||||||
|
static_cast<Qt::KeyboardModifiers>(modifiers)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_button(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->button());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_buttons(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->buttons());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_x(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->position().x());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_y(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->position().y());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_global_x(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->globalPosition().x());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_global_y(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->globalPosition().y());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_modifiers(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->modifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qmouseevent_free(void* event) {
|
||||||
|
delete static_cast<QMouseEvent*>(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<QResizeEvent*>(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<QResizeEvent*>(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<QResizeEvent*>(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<QPaintEvent*>(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<QPaintEvent*>(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<QCloseEvent*>(event)->isAccepted() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcloseevent_accept(void* event) {
|
||||||
|
if (event == nullptr) return;
|
||||||
|
static_cast<QCloseEvent*>(event)->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcloseevent_ignore(void* event) {
|
||||||
|
if (event == nullptr) return;
|
||||||
|
static_cast<QCloseEvent*>(event)->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcloseevent_free(void* event) {
|
||||||
|
delete static_cast<QCloseEvent*>(event);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,519 @@
|
|||||||
|
// ============================================================
|
||||||
|
// vqt6/_bridge_network.cpp — QtNetwork C 桥接层实现
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
#include "_bridge.h"
|
||||||
|
#include "_bridge_network.h"
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QUdpSocket>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QHttpHeaders>
|
||||||
|
#include <QHttp2Configuration>
|
||||||
|
#include <QNetworkCookieJar>
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 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<quint32>(ipv4));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_string(void* address) {
|
||||||
|
if (address == nullptr) return new QHostAddress();
|
||||||
|
return new QHostAddress(*static_cast<QString*>(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<QHostAddress*>(addr)->toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<uint32_t>(static_cast<QHostAddress*>(addr)->toIPv4Address());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qhostaddress_is_null(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<QHostAddress*>(addr)->isNull() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qhostaddress_is_loopback(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<QHostAddress*>(addr)->isLoopback() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<QHostAddress*>(addr)->isBroadcast() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qhostaddress_protocol(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QHostAddress*>(addr)->protocol());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qhostaddress_free(void* addr) {
|
||||||
|
delete static_cast<QHostAddress*>(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QAbstractSocket
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API int vqt6_qabstractsocket_state(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QAbstractSocket*>(socket)->state());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qabstractsocket_error(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QAbstractSocket*>(socket)->error());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qabstractsocket_error_string(void* socket) {
|
||||||
|
if (socket == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QAbstractSocket*>(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<QAbstractSocket*>(socket)->connectToHost(*static_cast<QString*>(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<QAbstractSocket*>(socket)->connectToHost(*static_cast<QHostAddress*>(address), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket) {
|
||||||
|
if (socket == nullptr) return;
|
||||||
|
static_cast<QAbstractSocket*>(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<QAbstractSocket*>(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<QAbstractSocket*>(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<QAbstractSocket*>(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<QAbstractSocket*>(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<QAbstractSocket*>(socket)->isValid() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qabstractsocket_is_open(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<QAbstractSocket*>(socket)->isOpen() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qabstractsocket_flush(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<QAbstractSocket*>(socket)->flush() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qabstractsocket_close(void* socket) {
|
||||||
|
if (socket == nullptr) return;
|
||||||
|
static_cast<QAbstractSocket*>(socket)->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qabstractsocket_abort(void* socket) {
|
||||||
|
if (socket == nullptr) return;
|
||||||
|
static_cast<QAbstractSocket*>(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<size_t>(static_cast<QAbstractSocket*>(socket)->read(static_cast<char*>(buf), static_cast<qint64>(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<QAbstractSocket*>(socket)->readAll();
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(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<size_t>(static_cast<QAbstractSocket*>(socket)->write(static_cast<const char*>(data), static_cast<qint64>(size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->bytesAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->bytesToWrite());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket) {
|
||||||
|
if (socket == nullptr) return nullptr;
|
||||||
|
return new QHostAddress(static_cast<QAbstractSocket*>(socket)->peerAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<uint16_t>(static_cast<QAbstractSocket*>(socket)->peerPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qabstractsocket_local_address(void* socket) {
|
||||||
|
if (socket == nullptr) return nullptr;
|
||||||
|
return new QHostAddress(static_cast<QAbstractSocket*>(socket)->localAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<uint16_t>(static_cast<QAbstractSocket*>(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<QObject*>(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<QTcpSocket*>(socket)->connectToHost(*static_cast<QString*>(host_name), port,
|
||||||
|
static_cast<QIODevice::OpenMode>(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<QTcpSocket*>(socket)->connectToHost(*static_cast<QHostAddress*>(address), port,
|
||||||
|
static_cast<QIODevice::OpenMode>(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<QTcpSocket*>(socket)->setSocketDescriptor(static_cast<qintptr>(socket_descriptor)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket) {
|
||||||
|
if (socket == nullptr) return -1;
|
||||||
|
return static_cast<intptr_t>(static_cast<QTcpSocket*>(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<QTcpSocket*>(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<QObject*>(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<QUdpSocket*>(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<QUdpSocket*>(socket)->bind(*static_cast<QHostAddress*>(address), port) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qudpsocket_close(void* socket) {
|
||||||
|
if (socket == nullptr) return;
|
||||||
|
static_cast<QUdpSocket*>(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<size_t>(static_cast<QUdpSocket*>(socket)->writeDatagram(
|
||||||
|
static_cast<const char*>(data), static_cast<qint64>(size),
|
||||||
|
*static_cast<QHostAddress*>(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<QUdpSocket*>(socket)->readDatagram(
|
||||||
|
static_cast<char*>(data), static_cast<qint64>(max_size), &sender, &sender_port);
|
||||||
|
if (host != nullptr) {
|
||||||
|
QHostAddress* dst = static_cast<QHostAddress*>(host);
|
||||||
|
*dst = sender;
|
||||||
|
}
|
||||||
|
if (port != nullptr) {
|
||||||
|
*port = sender_port;
|
||||||
|
}
|
||||||
|
return static_cast<size_t>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<QUdpSocket*>(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<size_t>(static_cast<QUdpSocket*>(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<QUdpSocket*>(socket)->joinMulticastGroup(*static_cast<QHostAddress*>(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<QUdpSocket*>(socket)->leaveMulticastGroup(*static_cast<QHostAddress*>(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<QString*>(url)));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url) {
|
||||||
|
if (req == nullptr || url == nullptr) return;
|
||||||
|
static_cast<QNetworkRequest*>(req)->setUrl(QUrl(*static_cast<QString*>(url)));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkrequest_url(void* req) {
|
||||||
|
if (req == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QNetworkRequest*>(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<QNetworkRequest*>(req)->setHeader(static_cast<QNetworkRequest::KnownHeaders>(header_type),
|
||||||
|
*static_cast<QVariant*>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type) {
|
||||||
|
if (req == nullptr) return nullptr;
|
||||||
|
return new QVariant(static_cast<QNetworkRequest*>(req)->header(static_cast<QNetworkRequest::KnownHeaders>(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<QNetworkRequest*>(req)->setRawHeader(QByteArray(header_name),
|
||||||
|
QByteArray(static_cast<const char*>(value), static_cast<int>(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<QNetworkRequest*>(req)->rawHeader(QByteArray(header_name));
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(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<QNetworkRequest*>(req)->setAttribute(static_cast<QNetworkRequest::Attribute>(attr_type),
|
||||||
|
*static_cast<QVariant*>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type) {
|
||||||
|
if (req == nullptr) return nullptr;
|
||||||
|
return new QVariant(static_cast<QNetworkRequest*>(req)->attribute(static_cast<QNetworkRequest::Attribute>(attr_type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qnetworkrequest_free(void* req) {
|
||||||
|
delete static_cast<QNetworkRequest*>(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<QObject*>(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req) {
|
||||||
|
if (nam == nullptr || req == nullptr) return nullptr;
|
||||||
|
return static_cast<QNetworkAccessManager*>(nam)->get(*static_cast<QNetworkRequest*>(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<const char*>(data), static_cast<int>(size));
|
||||||
|
}
|
||||||
|
return static_cast<QNetworkAccessManager*>(nam)->post(*static_cast<QNetworkRequest*>(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<const char*>(data), static_cast<int>(size));
|
||||||
|
}
|
||||||
|
return static_cast<QNetworkAccessManager*>(nam)->put(*static_cast<QNetworkRequest*>(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<QNetworkAccessManager*>(nam)->deleteResource(*static_cast<QNetworkRequest*>(req));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req) {
|
||||||
|
if (nam == nullptr || req == nullptr) return nullptr;
|
||||||
|
return static_cast<QNetworkAccessManager*>(nam)->head(*static_cast<QNetworkRequest*>(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<QNetworkCookieJar*>(static_cast<QObject*>(store));
|
||||||
|
if (jar != nullptr) {
|
||||||
|
static_cast<QNetworkAccessManager*>(nam)->setCookieJar(jar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QNetworkReply
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkreply_url(void* reply) {
|
||||||
|
if (reply == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QNetworkReply*>(reply)->url().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkreply_request(void* reply) {
|
||||||
|
if (reply == nullptr) return nullptr;
|
||||||
|
return new QNetworkRequest(static_cast<QNetworkReply*>(reply)->request());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qnetworkreply_error(void* reply) {
|
||||||
|
if (reply == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QNetworkReply*>(reply)->error());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkreply_error_string(void* reply) {
|
||||||
|
if (reply == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QNetworkReply*>(reply)->errorString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qnetworkreply_is_finished(void* reply) {
|
||||||
|
if (reply == nullptr) return 0;
|
||||||
|
return static_cast<QNetworkReply*>(reply)->isFinished() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qnetworkreply_is_running(void* reply) {
|
||||||
|
if (reply == nullptr) return 0;
|
||||||
|
return static_cast<QNetworkReply*>(reply)->isRunning() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qnetworkreply_abort(void* reply) {
|
||||||
|
if (reply == nullptr) return;
|
||||||
|
static_cast<QNetworkReply*>(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<size_t>(static_cast<QNetworkReply*>(reply)->read(static_cast<char*>(buf), static_cast<qint64>(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<QNetworkReply*>(reply)->readAll();
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(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<size_t>(static_cast<QNetworkReply*>(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<QNetworkReply*>(reply)->header(static_cast<QNetworkRequest::KnownHeaders>(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<QNetworkReply*>(reply)->rawHeader(QByteArray(header_name));
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(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<QNetworkReply*>(reply)->attribute(static_cast<QNetworkRequest::Attribute>(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<QNetworkReply*>(reply)->attribute(static_cast<QNetworkRequest::Attribute>(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<QNetworkReply*>(reply)->setRawHeader(QByteArray(header_name),
|
||||||
|
QByteArray(static_cast<const char*>(value), static_cast<int>(value_size)));
|
||||||
|
}
|
||||||
@@ -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
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||||
@@ -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_<class>_<action>
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 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<QString>)
|
||||||
|
# ============================================================
|
||||||
|
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<QByteArray>)
|
||||||
|
# ============================================================
|
||||||
|
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 # 测试用
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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<QObject*>*
|
||||||
|
QtStringListPtr: t.CTypedef = t.CVoid | t.CPtr # QStringList*
|
||||||
|
QtByteArrayListPtr: t.CTypedef = t.CVoid | t.CPtr # QList<QByteArray>*
|
||||||
|
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
|
||||||
@@ -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()
|
||||||
@@ -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 示例验证
|
||||||
@@ -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",
|
||||||
|
]
|
||||||
+151
@@ -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 <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
// ============================================================
|
||||||
|
// vqt6/_bridge_core.cpp — QtCore C 桥接层实现
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
#include "_bridge.h"
|
||||||
|
#include <QString>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QList>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
// 全局回调表(线程安全)
|
||||||
|
namespace {
|
||||||
|
QMutex g_slot_mutex;
|
||||||
|
QHash<int, QPair<vqt6_slot_callback_t, void*>> 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<QString*>(qstr);
|
||||||
|
QByteArray ba = s->toUtf8();
|
||||||
|
size_t len = static_cast<size_t>(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<QString*>(qstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qstring_length(void* qstr) {
|
||||||
|
if (qstr == nullptr) return 0;
|
||||||
|
return static_cast<QString*>(qstr)->length();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qstring_is_empty(void* qstr) {
|
||||||
|
if (qstr == nullptr) return 1;
|
||||||
|
return static_cast<QString*>(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<QString*>(qstr) == *static_cast<QString*>(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<QString*>(qstr) + *static_cast<QString*>(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<const char*>(data), static_cast<int>(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qbytearray_data(void* qba, size_t* out_size) {
|
||||||
|
if (qba == nullptr) return nullptr;
|
||||||
|
QByteArray* ba = static_cast<QByteArray*>(qba);
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(ba->size());
|
||||||
|
return ba->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API size_t vqt6_qbytearray_size(void* qba) {
|
||||||
|
if (qba == nullptr) return 0;
|
||||||
|
return static_cast<size_t>(static_cast<QByteArray*>(qba)->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbytearray_free(void* qba) {
|
||||||
|
delete static_cast<QByteArray*>(qba);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QObject
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_delete(void* obj) {
|
||||||
|
if (obj == nullptr) return;
|
||||||
|
delete static_cast<QObject*>(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_delete_later(void* obj) {
|
||||||
|
if (obj == nullptr) return;
|
||||||
|
static_cast<QObject*>(obj)->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_set_object_name(void* obj, void* name) {
|
||||||
|
if (obj == nullptr || name == nullptr) return;
|
||||||
|
static_cast<QObject*>(obj)->setObjectName(*static_cast<QString*>(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qobject_object_name(void* obj) {
|
||||||
|
if (obj == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QObject*>(obj)->objectName());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_set_parent(void* child, void* parent) {
|
||||||
|
if (child == nullptr) return;
|
||||||
|
static_cast<QObject*>(child)->setParent(static_cast<QObject*>(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qobject_parent(void* obj) {
|
||||||
|
if (obj == nullptr) return nullptr;
|
||||||
|
return static_cast<QObject*>(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<QObject*>(sender), signal_name,
|
||||||
|
static_cast<QObject*>(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<QObject*>(sender), signal_name,
|
||||||
|
static_cast<QObject*>(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<QObject*>(watched)->installEventFilter(static_cast<QObject*>(filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qobject_remove_event_filter(void* watched, void* filter) {
|
||||||
|
if (watched == nullptr || filter == nullptr) return;
|
||||||
|
static_cast<QObject*>(watched)->removeEventFilter(static_cast<QObject*>(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<QCoreApplication*>(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<QCoreApplication*>(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<QCoreApplication*>(app)->exit(exit_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcoreapp_process_events(void* app, int flags) {
|
||||||
|
if (app == nullptr) return;
|
||||||
|
static_cast<QCoreApplication*>(app)->processEvents(static_cast<QEventLoop::ProcessEventsFlag>(flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcoreapp_post_event(void* receiver, void* event) {
|
||||||
|
if (receiver == nullptr || event == nullptr) return;
|
||||||
|
QCoreApplication::postEvent(static_cast<QObject*>(receiver), static_cast<QEvent*>(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<QObject*>(receiver), static_cast<QEvent*>(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<QString*>(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<QString*>(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<QObject*>(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qtimer_start(void* timer, int interval_ms) {
|
||||||
|
if (timer == nullptr) return;
|
||||||
|
static_cast<QTimer*>(timer)->start(interval_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qtimer_stop(void* timer) {
|
||||||
|
if (timer == nullptr) return;
|
||||||
|
static_cast<QTimer*>(timer)->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qtimer_set_interval(void* timer, int interval_ms) {
|
||||||
|
if (timer == nullptr) return;
|
||||||
|
static_cast<QTimer*>(timer)->setInterval(interval_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qtimer_interval(void* timer) {
|
||||||
|
if (timer == nullptr) return 0;
|
||||||
|
return static_cast<QTimer*>(timer)->interval();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qtimer_is_active(void* timer) {
|
||||||
|
if (timer == nullptr) return 0;
|
||||||
|
return static_cast<QTimer*>(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<QTimer*>(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<QTimer*>(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<QString*>(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<QVariant*>(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<QVariant*>(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<QVariant*>(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<QVariant*>(v)->toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qvariant_type_id(void* v) {
|
||||||
|
if (v == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QVariant*>(v)->typeId());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qvariant_is_valid(void* v) {
|
||||||
|
if (v == nullptr) return 0;
|
||||||
|
return static_cast<QVariant*>(v)->isValid() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qvariant_free(void* v) {
|
||||||
|
delete static_cast<QVariant*>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QEvent
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API int vqt6_qevent_type(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QEvent*>(event)->type());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qevent_accept(void* event) {
|
||||||
|
if (event == nullptr) return;
|
||||||
|
static_cast<QEvent*>(event)->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qevent_ignore(void* event) {
|
||||||
|
if (event == nullptr) return;
|
||||||
|
static_cast<QEvent*>(event)->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qevent_is_accepted(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<QEvent*>(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<QStringList*>(list)->append(*static_cast<QString*>(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qstringlist_size(void* list) {
|
||||||
|
if (list == nullptr) return 0;
|
||||||
|
return static_cast<QStringList*>(list)->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qstringlist_at(void* list, int index) {
|
||||||
|
if (list == nullptr) return nullptr;
|
||||||
|
QStringList* sl = static_cast<QStringList*>(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<QStringList*>(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QByteArrayList
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void* vqt6_qbytearraylist_create(void) {
|
||||||
|
return new QList<QByteArray>();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbytearraylist_append(void* list, void* qba) {
|
||||||
|
if (list == nullptr || qba == nullptr) return;
|
||||||
|
static_cast<QList<QByteArray>*>(list)->append(*static_cast<QByteArray*>(qba));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qbytearraylist_size(void* list) {
|
||||||
|
if (list == nullptr) return 0;
|
||||||
|
return static_cast<QList<QByteArray>*>(list)->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qbytearraylist_at(void* list, int index) {
|
||||||
|
if (list == nullptr) return nullptr;
|
||||||
|
QList<QByteArray>* qbl = static_cast<QList<QByteArray>*>(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<QList<QByteArray>*>(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<vqt6_slot_callback_t, void*>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,868 @@
|
|||||||
|
// ============================================================
|
||||||
|
// vqt6/_bridge_gui.cpp — QtGui C 桥接层实现
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
#include "_bridge.h"
|
||||||
|
#include "_bridge_gui.h"
|
||||||
|
#include <QColor>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QFontMetrics>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPen>
|
||||||
|
#include <QBrush>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QPolygon>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QPointF>
|
||||||
|
#include <QRect>
|
||||||
|
#include <QRectF>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QStyle>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 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<QString*>(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<QString*>(hex_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_red(void* c) {
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
return static_cast<QColor*>(c)->red();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_green(void* c) {
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
return static_cast<QColor*>(c)->green();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_blue(void* c) {
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
return static_cast<QColor*>(c)->blue();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_alpha(void* c) {
|
||||||
|
if (c == nullptr) return 255;
|
||||||
|
return static_cast<QColor*>(c)->alpha();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_set_red(void* c, int r) {
|
||||||
|
if (c == nullptr) return;
|
||||||
|
static_cast<QColor*>(c)->setRed(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_set_green(void* c, int g) {
|
||||||
|
if (c == nullptr) return;
|
||||||
|
static_cast<QColor*>(c)->setGreen(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_set_blue(void* c, int b) {
|
||||||
|
if (c == nullptr) return;
|
||||||
|
static_cast<QColor*>(c)->setBlue(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_set_alpha(void* c, int a) {
|
||||||
|
if (c == nullptr) return;
|
||||||
|
static_cast<QColor*>(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<QColor*>(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<QColor*>(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<QColor*>(c)->name());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcolor_is_valid(void* c) {
|
||||||
|
if (c == nullptr) return 0;
|
||||||
|
return static_cast<QColor*>(c)->isValid() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcolor_free(void* c) {
|
||||||
|
delete static_cast<QColor*>(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<QString*>(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<QString*>(family), point_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_family(void* font, void* family) {
|
||||||
|
if (font == nullptr || family == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setFamily(*static_cast<QString*>(family));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qfont_family(void* font) {
|
||||||
|
if (font == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QFont*>(font)->family());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_point_size(void* font, int point_size) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setPointSize(point_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_point_size(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->pointSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_pixel_size(void* font, int pixel_size) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setPixelSize(pixel_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_pixel_size(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->pixelSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_bold(void* font, int bold) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setBold(bold != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_bold(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->bold() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_italic(void* font, int italic) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setItalic(italic != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_italic(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->italic() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_underline(void* font, int underline) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setUnderline(underline != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_underline(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(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<QFont*>(font)->setStrikeOut(strike_out != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_strike_out(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<QFont*>(font)->strikeOut() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_set_weight(void* font, int weight) {
|
||||||
|
if (font == nullptr) return;
|
||||||
|
static_cast<QFont*>(font)->setWeight(static_cast<QFont::Weight>(weight));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfont_weight(void* font) {
|
||||||
|
if (font == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QFont*>(font)->weight());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfont_free(void* font) {
|
||||||
|
delete static_cast<QFont*>(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QFontMetrics
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void* vqt6_qfontmetrics_create(void* font) {
|
||||||
|
if (font == nullptr) return nullptr;
|
||||||
|
return new QFontMetrics(*static_cast<QFont*>(font));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfontmetrics_width(void* fm, void* text) {
|
||||||
|
if (fm == nullptr || text == nullptr) return 0;
|
||||||
|
return static_cast<QFontMetrics*>(fm)->horizontalAdvance(*static_cast<QString*>(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfontmetrics_height(void* fm) {
|
||||||
|
if (fm == nullptr) return 0;
|
||||||
|
return static_cast<QFontMetrics*>(fm)->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfontmetrics_ascent(void* fm) {
|
||||||
|
if (fm == nullptr) return 0;
|
||||||
|
return static_cast<QFontMetrics*>(fm)->ascent();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qfontmetrics_descent(void* fm) {
|
||||||
|
if (fm == nullptr) return 0;
|
||||||
|
return static_cast<QFontMetrics*>(fm)->descent();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qfontmetrics_free(void* fm) {
|
||||||
|
delete static_cast<QFontMetrics*>(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<QPixmap*>(pm)->load(*static_cast<QString*>(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<QPixmap*>(pm)->loadFromData(static_cast<const uchar*>(data), static_cast<uint>(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<QPixmap*>(pm)->save(*static_cast<QString*>(file_name)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpixmap_width(void* pm) {
|
||||||
|
if (pm == nullptr) return 0;
|
||||||
|
return static_cast<QPixmap*>(pm)->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpixmap_height(void* pm) {
|
||||||
|
if (pm == nullptr) return 0;
|
||||||
|
return static_cast<QPixmap*>(pm)->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpixmap_is_null(void* pm) {
|
||||||
|
if (pm == nullptr) return 0;
|
||||||
|
return static_cast<QPixmap*>(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<QPixmap*>(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<QPixmap*>(pm)->fill(*static_cast<QColor*>(color));
|
||||||
|
} else {
|
||||||
|
static_cast<QPixmap*>(pm)->fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpixmap_free(void* pm) {
|
||||||
|
delete static_cast<QPixmap*>(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<QImage::Format>(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<QImage*>(img)->load(*static_cast<QString*>(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<QImage*>(img)->save(*static_cast<QString*>(file_name)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qimage_width(void* img) {
|
||||||
|
if (img == nullptr) return 0;
|
||||||
|
return static_cast<QImage*>(img)->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qimage_height(void* img) {
|
||||||
|
if (img == nullptr) return 0;
|
||||||
|
return static_cast<QImage*>(img)->height();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qimage_format(void* img) {
|
||||||
|
if (img == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QImage*>(img)->format());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qimage_is_null(void* img) {
|
||||||
|
if (img == nullptr) return 0;
|
||||||
|
return static_cast<QImage*>(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<QImage*>(img)->fill(*static_cast<QColor*>(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<QImage*>(img)->scaled(w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qimage_free(void* img) {
|
||||||
|
delete static_cast<QImage*>(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<QPainter*>(p)->begin(static_cast<QPixmap*>(device)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpainter_end(void* p) {
|
||||||
|
if (p == nullptr) return 0;
|
||||||
|
return static_cast<QPainter*>(p)->end() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpainter_is_active(void* p) {
|
||||||
|
if (p == nullptr) return 0;
|
||||||
|
return static_cast<QPainter*>(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<QPainter*>(p)->setPen(*static_cast<QPen*>(pen));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_set_brush(void* p, void* brush) {
|
||||||
|
if (p == nullptr || brush == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->setBrush(*static_cast<QBrush*>(brush));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_set_font(void* p, void* font) {
|
||||||
|
if (p == nullptr || font == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->setFont(*static_cast<QFont*>(font));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qpainter_pen(void* p) {
|
||||||
|
if (p == nullptr) return nullptr;
|
||||||
|
return new QPen(static_cast<QPainter*>(p)->pen());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qpainter_brush(void* p) {
|
||||||
|
if (p == nullptr) return nullptr;
|
||||||
|
return new QBrush(static_cast<QPainter*>(p)->brush());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qpainter_font(void* p) {
|
||||||
|
if (p == nullptr) return nullptr;
|
||||||
|
return new QFont(static_cast<QPainter*>(p)->font());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_set_opacity(void* p, double opacity) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->setOpacity(opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API double vqt6_qpainter_opacity(void* p) {
|
||||||
|
if (p == nullptr) return 1.0;
|
||||||
|
return static_cast<QPainter*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(p)->fillRect(x, y, w, h, *static_cast<QColor*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(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<QPainter*>(p)->drawPolyline(polyline);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_draw_point(void* p, int x, int y) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(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<QPainter*>(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<QPainter*>(p)->drawText(x, y, *static_cast<QString*>(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<QPainter*>(p)->drawText(x, y, w, h, flags, *static_cast<QString*>(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<QPainter*>(p)->drawPixmap(x, y, *static_cast<QPixmap*>(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<QPainter*>(p)->drawImage(x, y, *static_cast<QImage*>(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<QPainter*>(p)->drawTiledPixmap(x, y, w, h, *static_cast<QPixmap*>(pixmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_translate(void* p, int dx, int dy) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->translate(dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_rotate(void* p, double angle) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->rotate(angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_scale(void* p, double sx, double sy) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->scale(sx, sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_reset_transform(void* p) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->resetTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_save(void* p) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_restore(void* p) {
|
||||||
|
if (p == nullptr) return;
|
||||||
|
static_cast<QPainter*>(p)->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpainter_free(void* p) {
|
||||||
|
delete static_cast<QPainter*>(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<QColor*>(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<QColor*>(color), width);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpen_set_color(void* pen, void* color) {
|
||||||
|
if (pen == nullptr || color == nullptr) return;
|
||||||
|
static_cast<QPen*>(pen)->setColor(*static_cast<QColor*>(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qpen_color(void* pen) {
|
||||||
|
if (pen == nullptr) return nullptr;
|
||||||
|
return new QColor(static_cast<QPen*>(pen)->color());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpen_set_width(void* pen, int width) {
|
||||||
|
if (pen == nullptr) return;
|
||||||
|
static_cast<QPen*>(pen)->setWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpen_width(void* pen) {
|
||||||
|
if (pen == nullptr) return 0;
|
||||||
|
return static_cast<QPen*>(pen)->width();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpen_set_style(void* pen, int style) {
|
||||||
|
if (pen == nullptr) return;
|
||||||
|
static_cast<QPen*>(pen)->setStyle(static_cast<Qt::PenStyle>(style));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qpen_style(void* pen) {
|
||||||
|
if (pen == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QPen*>(pen)->style());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qpen_free(void* pen) {
|
||||||
|
delete static_cast<QPen*>(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<QColor*>(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qbrush_create_with_style(int style) {
|
||||||
|
return new QBrush(static_cast<Qt::BrushStyle>(style));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbrush_set_color(void* brush, void* color) {
|
||||||
|
if (brush == nullptr || color == nullptr) return;
|
||||||
|
static_cast<QBrush*>(brush)->setColor(*static_cast<QColor*>(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qbrush_color(void* brush) {
|
||||||
|
if (brush == nullptr) return nullptr;
|
||||||
|
return new QColor(static_cast<QBrush*>(brush)->color());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbrush_set_style(void* brush, int style) {
|
||||||
|
if (brush == nullptr) return;
|
||||||
|
static_cast<QBrush*>(brush)->setStyle(static_cast<Qt::BrushStyle>(style));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qbrush_style(void* brush) {
|
||||||
|
if (brush == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QBrush*>(brush)->style());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qbrush_free(void* brush) {
|
||||||
|
delete static_cast<QBrush*>(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<QString*>(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<QIcon*>(icon)->addFile(*static_cast<QString*>(file_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qicon_add_pixmap(void* icon, void* pixmap) {
|
||||||
|
if (icon == nullptr || pixmap == nullptr) return;
|
||||||
|
static_cast<QIcon*>(icon)->addPixmap(*static_cast<QPixmap*>(pixmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qicon_is_null(void* icon) {
|
||||||
|
if (icon == nullptr) return 0;
|
||||||
|
return static_cast<QIcon*>(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<QIcon*>(icon)->pixmap(w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qicon_free(void* icon) {
|
||||||
|
delete static_cast<QIcon*>(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<Qt::CursorShape>(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<QCursor*>(cursor)->setShape(static_cast<Qt::CursorShape>(shape));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qcursor_shape(void* cursor) {
|
||||||
|
if (cursor == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QCursor*>(cursor)->shape());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcursor_free(void* cursor) {
|
||||||
|
delete static_cast<QCursor*>(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QKeyEvent
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void* vqt6_qkeyevent_create(int type, int key, int modifiers, void* text) {
|
||||||
|
QString* t = static_cast<QString*>(text);
|
||||||
|
return new QKeyEvent(static_cast<QEvent::Type>(type), key, static_cast<Qt::KeyboardModifiers>(modifiers),
|
||||||
|
t != nullptr ? *t : QString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qkeyevent_key(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<QKeyEvent*>(event)->key();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qkeyevent_text(void* event) {
|
||||||
|
if (event == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QKeyEvent*>(event)->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qkeyevent_modifiers(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QKeyEvent*>(event)->modifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qkeyevent_is_auto_repeat(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<QKeyEvent*>(event)->isAutoRepeat() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qkeyevent_free(void* event) {
|
||||||
|
delete static_cast<QKeyEvent*>(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<QPointF*>(local_pos);
|
||||||
|
return new QMouseEvent(
|
||||||
|
static_cast<QEvent::Type>(type),
|
||||||
|
lp != nullptr ? *lp : QPointF(0, 0),
|
||||||
|
Qt::NoButton,
|
||||||
|
static_cast<Qt::MouseButton>(button),
|
||||||
|
static_cast<Qt::KeyboardModifiers>(modifiers)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_button(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->button());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_buttons(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->buttons());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_x(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->position().x());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_y(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->position().y());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_global_x(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->globalPosition().x());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_global_y(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->globalPosition().y());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qmouseevent_modifiers(void* event) {
|
||||||
|
if (event == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QMouseEvent*>(event)->modifiers());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qmouseevent_free(void* event) {
|
||||||
|
delete static_cast<QMouseEvent*>(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<QResizeEvent*>(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<QResizeEvent*>(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<QResizeEvent*>(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<QPaintEvent*>(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<QPaintEvent*>(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<QCloseEvent*>(event)->isAccepted() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcloseevent_accept(void* event) {
|
||||||
|
if (event == nullptr) return;
|
||||||
|
static_cast<QCloseEvent*>(event)->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcloseevent_ignore(void* event) {
|
||||||
|
if (event == nullptr) return;
|
||||||
|
static_cast<QCloseEvent*>(event)->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qcloseevent_free(void* event) {
|
||||||
|
delete static_cast<QCloseEvent*>(event);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,519 @@
|
|||||||
|
// ============================================================
|
||||||
|
// vqt6/_bridge_network.cpp — QtNetwork C 桥接层实现
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
#include "_bridge.h"
|
||||||
|
#include "_bridge_network.h"
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QAbstractSocket>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QUdpSocket>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QHttpHeaders>
|
||||||
|
#include <QHttp2Configuration>
|
||||||
|
#include <QNetworkCookieJar>
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// 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<quint32>(ipv4));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qhostaddress_create_with_string(void* address) {
|
||||||
|
if (address == nullptr) return new QHostAddress();
|
||||||
|
return new QHostAddress(*static_cast<QString*>(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<QHostAddress*>(addr)->toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API uint32_t vqt6_qhostaddress_to_ipv4(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<uint32_t>(static_cast<QHostAddress*>(addr)->toIPv4Address());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qhostaddress_is_null(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<QHostAddress*>(addr)->isNull() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qhostaddress_is_loopback(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<QHostAddress*>(addr)->isLoopback() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qhostaddress_is_broadcast(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<QHostAddress*>(addr)->isBroadcast() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qhostaddress_protocol(void* addr) {
|
||||||
|
if (addr == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QHostAddress*>(addr)->protocol());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qhostaddress_free(void* addr) {
|
||||||
|
delete static_cast<QHostAddress*>(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QAbstractSocket
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API int vqt6_qabstractsocket_state(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QAbstractSocket*>(socket)->state());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qabstractsocket_error(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QAbstractSocket*>(socket)->error());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qabstractsocket_error_string(void* socket) {
|
||||||
|
if (socket == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QAbstractSocket*>(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<QAbstractSocket*>(socket)->connectToHost(*static_cast<QString*>(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<QAbstractSocket*>(socket)->connectToHost(*static_cast<QHostAddress*>(address), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qabstractsocket_disconnect_from_host(void* socket) {
|
||||||
|
if (socket == nullptr) return;
|
||||||
|
static_cast<QAbstractSocket*>(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<QAbstractSocket*>(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<QAbstractSocket*>(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<QAbstractSocket*>(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<QAbstractSocket*>(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<QAbstractSocket*>(socket)->isValid() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qabstractsocket_is_open(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<QAbstractSocket*>(socket)->isOpen() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qabstractsocket_flush(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<QAbstractSocket*>(socket)->flush() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qabstractsocket_close(void* socket) {
|
||||||
|
if (socket == nullptr) return;
|
||||||
|
static_cast<QAbstractSocket*>(socket)->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qabstractsocket_abort(void* socket) {
|
||||||
|
if (socket == nullptr) return;
|
||||||
|
static_cast<QAbstractSocket*>(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<size_t>(static_cast<QAbstractSocket*>(socket)->read(static_cast<char*>(buf), static_cast<qint64>(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<QAbstractSocket*>(socket)->readAll();
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(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<size_t>(static_cast<QAbstractSocket*>(socket)->write(static_cast<const char*>(data), static_cast<qint64>(size)));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_available(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->bytesAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API size_t vqt6_qabstractsocket_bytes_to_write(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<size_t>(static_cast<QAbstractSocket*>(socket)->bytesToWrite());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qabstractsocket_peer_address(void* socket) {
|
||||||
|
if (socket == nullptr) return nullptr;
|
||||||
|
return new QHostAddress(static_cast<QAbstractSocket*>(socket)->peerAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API uint16_t vqt6_qabstractsocket_peer_port(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<uint16_t>(static_cast<QAbstractSocket*>(socket)->peerPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qabstractsocket_local_address(void* socket) {
|
||||||
|
if (socket == nullptr) return nullptr;
|
||||||
|
return new QHostAddress(static_cast<QAbstractSocket*>(socket)->localAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API uint16_t vqt6_qabstractsocket_local_port(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<uint16_t>(static_cast<QAbstractSocket*>(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<QObject*>(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<QTcpSocket*>(socket)->connectToHost(*static_cast<QString*>(host_name), port,
|
||||||
|
static_cast<QIODevice::OpenMode>(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<QTcpSocket*>(socket)->connectToHost(*static_cast<QHostAddress*>(address), port,
|
||||||
|
static_cast<QIODevice::OpenMode>(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<QTcpSocket*>(socket)->setSocketDescriptor(static_cast<qintptr>(socket_descriptor)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API intptr_t vqt6_qtcpsocket_socket_descriptor(void* socket) {
|
||||||
|
if (socket == nullptr) return -1;
|
||||||
|
return static_cast<intptr_t>(static_cast<QTcpSocket*>(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<QTcpSocket*>(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<QObject*>(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qudpsocket_bind(void* socket, uint16_t port) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<QUdpSocket*>(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<QUdpSocket*>(socket)->bind(*static_cast<QHostAddress*>(address), port) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qudpsocket_close(void* socket) {
|
||||||
|
if (socket == nullptr) return;
|
||||||
|
static_cast<QUdpSocket*>(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<size_t>(static_cast<QUdpSocket*>(socket)->writeDatagram(
|
||||||
|
static_cast<const char*>(data), static_cast<qint64>(size),
|
||||||
|
*static_cast<QHostAddress*>(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<QUdpSocket*>(socket)->readDatagram(
|
||||||
|
static_cast<char*>(data), static_cast<qint64>(max_size), &sender, &sender_port);
|
||||||
|
if (host != nullptr) {
|
||||||
|
QHostAddress* dst = static_cast<QHostAddress*>(host);
|
||||||
|
*dst = sender;
|
||||||
|
}
|
||||||
|
if (port != nullptr) {
|
||||||
|
*port = sender_port;
|
||||||
|
}
|
||||||
|
return static_cast<size_t>(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qudpsocket_has_pending_datagrams(void* socket) {
|
||||||
|
if (socket == nullptr) return 0;
|
||||||
|
return static_cast<QUdpSocket*>(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<size_t>(static_cast<QUdpSocket*>(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<QUdpSocket*>(socket)->joinMulticastGroup(*static_cast<QHostAddress*>(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<QUdpSocket*>(socket)->leaveMulticastGroup(*static_cast<QHostAddress*>(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<QString*>(url)));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qnetworkrequest_set_url(void* req, void* url) {
|
||||||
|
if (req == nullptr || url == nullptr) return;
|
||||||
|
static_cast<QNetworkRequest*>(req)->setUrl(QUrl(*static_cast<QString*>(url)));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkrequest_url(void* req) {
|
||||||
|
if (req == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QNetworkRequest*>(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<QNetworkRequest*>(req)->setHeader(static_cast<QNetworkRequest::KnownHeaders>(header_type),
|
||||||
|
*static_cast<QVariant*>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkrequest_header(void* req, int header_type) {
|
||||||
|
if (req == nullptr) return nullptr;
|
||||||
|
return new QVariant(static_cast<QNetworkRequest*>(req)->header(static_cast<QNetworkRequest::KnownHeaders>(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<QNetworkRequest*>(req)->setRawHeader(QByteArray(header_name),
|
||||||
|
QByteArray(static_cast<const char*>(value), static_cast<int>(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<QNetworkRequest*>(req)->rawHeader(QByteArray(header_name));
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(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<QNetworkRequest*>(req)->setAttribute(static_cast<QNetworkRequest::Attribute>(attr_type),
|
||||||
|
*static_cast<QVariant*>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkrequest_attribute(void* req, int attr_type) {
|
||||||
|
if (req == nullptr) return nullptr;
|
||||||
|
return new QVariant(static_cast<QNetworkRequest*>(req)->attribute(static_cast<QNetworkRequest::Attribute>(attr_type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qnetworkrequest_free(void* req) {
|
||||||
|
delete static_cast<QNetworkRequest*>(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<QObject*>(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_get(void* nam, void* req) {
|
||||||
|
if (nam == nullptr || req == nullptr) return nullptr;
|
||||||
|
return static_cast<QNetworkAccessManager*>(nam)->get(*static_cast<QNetworkRequest*>(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<const char*>(data), static_cast<int>(size));
|
||||||
|
}
|
||||||
|
return static_cast<QNetworkAccessManager*>(nam)->post(*static_cast<QNetworkRequest*>(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<const char*>(data), static_cast<int>(size));
|
||||||
|
}
|
||||||
|
return static_cast<QNetworkAccessManager*>(nam)->put(*static_cast<QNetworkRequest*>(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<QNetworkAccessManager*>(nam)->deleteResource(*static_cast<QNetworkRequest*>(req));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkaccessmanager_head(void* nam, void* req) {
|
||||||
|
if (nam == nullptr || req == nullptr) return nullptr;
|
||||||
|
return static_cast<QNetworkAccessManager*>(nam)->head(*static_cast<QNetworkRequest*>(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<QNetworkCookieJar*>(static_cast<QObject*>(store));
|
||||||
|
if (jar != nullptr) {
|
||||||
|
static_cast<QNetworkAccessManager*>(nam)->setCookieJar(jar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// QNetworkReply
|
||||||
|
// ============================================================
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkreply_url(void* reply) {
|
||||||
|
if (reply == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QNetworkReply*>(reply)->url().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkreply_request(void* reply) {
|
||||||
|
if (reply == nullptr) return nullptr;
|
||||||
|
return new QNetworkRequest(static_cast<QNetworkReply*>(reply)->request());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qnetworkreply_error(void* reply) {
|
||||||
|
if (reply == nullptr) return 0;
|
||||||
|
return static_cast<int>(static_cast<QNetworkReply*>(reply)->error());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void* vqt6_qnetworkreply_error_string(void* reply) {
|
||||||
|
if (reply == nullptr) return nullptr;
|
||||||
|
return new QString(static_cast<QNetworkReply*>(reply)->errorString());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qnetworkreply_is_finished(void* reply) {
|
||||||
|
if (reply == nullptr) return 0;
|
||||||
|
return static_cast<QNetworkReply*>(reply)->isFinished() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API int vqt6_qnetworkreply_is_running(void* reply) {
|
||||||
|
if (reply == nullptr) return 0;
|
||||||
|
return static_cast<QNetworkReply*>(reply)->isRunning() ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" VQT6_API void vqt6_qnetworkreply_abort(void* reply) {
|
||||||
|
if (reply == nullptr) return;
|
||||||
|
static_cast<QNetworkReply*>(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<size_t>(static_cast<QNetworkReply*>(reply)->read(static_cast<char*>(buf), static_cast<qint64>(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<QNetworkReply*>(reply)->readAll();
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(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<size_t>(static_cast<QNetworkReply*>(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<QNetworkReply*>(reply)->header(static_cast<QNetworkRequest::KnownHeaders>(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<QNetworkReply*>(reply)->rawHeader(QByteArray(header_name));
|
||||||
|
if (out_size != nullptr) *out_size = static_cast<size_t>(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<QNetworkReply*>(reply)->attribute(static_cast<QNetworkRequest::Attribute>(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<QNetworkReply*>(reply)->attribute(static_cast<QNetworkRequest::Attribute>(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<QNetworkReply*>(reply)->setRawHeader(QByteArray(header_name),
|
||||||
|
QByteArray(static_cast<const char*>(value), static_cast<int>(value_size)));
|
||||||
|
}
|
||||||
@@ -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
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||||
+157
@@ -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_<class>_<action>
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 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<QString>)
|
||||||
|
# ============================================================
|
||||||
|
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<QByteArray>)
|
||||||
|
# ============================================================
|
||||||
|
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 # 测试用
|
||||||
Loaded 100 of 121 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user